From 2b6eb39e5eb13f51ac859612f03f6060b2f02961 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Fri, 28 Mar 2025 15:58:02 +0800 Subject: [PATCH] New upstream version 7.1.1 Signed-off-by: nyanmisaka --- Changelog | 576 ++-- INSTALL.md | 8 + MAINTAINERS | 115 +- Makefile | 7 +- RELEASE | 2 +- RELEASE_NOTES | 10 +- VERSION | 2 +- compat/atomics/gcc/stdatomic.h | 173 - compat/atomics/pthread/stdatomic.h | 197 -- compat/atomics/suncc/stdatomic.h | 186 -- compat/stdbit/stdbit.h | 599 ++++ compat/w32dlfcn.h | 1 + configure | 352 ++- doc/APIchanges | 155 + doc/Doxyfile | 2 +- doc/Makefile | 2 +- doc/bitstream_filters.texi | 27 + doc/community.texi | 9 +- doc/decoders.texi | 47 +- doc/demuxers.texi | 46 +- doc/developer.texi | 23 +- doc/encoders.texi | 148 +- doc/examples/avio_read_callback.c | 1 + doc/examples/decode_filter_audio.c | 20 + doc/examples/decode_filter_video.c | 20 + doc/examples/filter_audio.c | 16 +- doc/examples/hw_decode.c | 1 + doc/examples/qsv_decode.c | 16 +- doc/examples/qsv_transcode.c | 1 + doc/examples/remux.c | 1 + doc/examples/transcode.c | 1 + doc/examples/transcode_aac.c | 21 +- doc/ffmpeg.texi | 165 +- doc/ffprobe.xsd | 1 + doc/fftools-common-opts.texi | 7 +- doc/filters.texi | 563 +++- doc/formats.texi | 19 +- doc/general_contents.texi | 26 +- doc/indevs.texi | 20 +- doc/infra.txt | 5 + doc/mailing-list-faq.texi | 3 - doc/mips.txt | 6 - doc/multithreading.txt | 15 +- doc/muxers.texi | 662 ++-- doc/protocols.texi | 143 +- doc/t2h.pm | 169 +- doc/texidep.pl | 2 +- doc/utils.texi | 72 +- ffbuild/arch.mak | 1 + ffbuild/libversion.sh | 1 + fftools/cmdutils.c | 421 ++- fftools/cmdutils.h | 92 +- fftools/ffmpeg.c | 96 +- fftools/ffmpeg.h | 197 +- fftools/ffmpeg_dec.c | 453 ++- fftools/ffmpeg_demux.c | 247 +- fftools/ffmpeg_enc.c | 78 +- fftools/ffmpeg_filter.c | 648 ++-- fftools/ffmpeg_hw.c | 4 +- fftools/ffmpeg_mux.c | 27 +- fftools/ffmpeg_mux.h | 8 + fftools/ffmpeg_mux_init.c | 780 +++-- fftools/ffmpeg_opt.c | 240 +- fftools/ffmpeg_sched.c | 205 +- fftools/ffmpeg_sched.h | 27 +- fftools/ffmpeg_utils.h | 5 +- fftools/ffplay.c | 39 +- fftools/ffplay_renderer.c | 1 + fftools/ffprobe.c | 30 +- fftools/fopen_utf8.h | 1 + fftools/opt_common.c | 90 +- libavcodec/012v.c | 3 - libavcodec/4xm.c | 1 + libavcodec/8svx.c | 1 + libavcodec/Makefile | 79 +- libavcodec/a64multienc.c | 2 +- libavcodec/aac.h | 35 +- libavcodec/aac/Makefile | 8 + .../{aacdec_template.c => aac/aacdec.c} | 1721 +++------- libavcodec/aac/aacdec.h | 562 ++++ libavcodec/aac/aacdec_ac.c | 208 ++ libavcodec/aac/aacdec_ac.h | 54 + libavcodec/aac/aacdec_dsp_template.c | 688 ++++ libavcodec/aac/aacdec_fixed.c | 105 + libavcodec/aac/aacdec_fixed_coupling.h | 137 + libavcodec/aac/aacdec_fixed_dequant.h | 174 + libavcodec/aac/aacdec_fixed_prediction.h | 151 + libavcodec/aac/aacdec_float.c | 182 ++ libavcodec/aac/aacdec_float_coupling.h | 90 + libavcodec/aac/aacdec_float_prediction.h | 100 + libavcodec/{aacdec.c => aac/aacdec_latm.h} | 279 +- libavcodec/aac/aacdec_lpd.c | 201 ++ libavcodec/aac/aacdec_lpd.h | 33 + libavcodec/aac/aacdec_proc_template.c | 448 +++ .../{aacdec_common.c => aac/aacdec_tab.c} | 11 +- libavcodec/{aacdectab.h => aac/aacdec_tab.h} | 8 +- libavcodec/aac/aacdec_usac.c | 1786 +++++++++++ libavcodec/aac/aacdec_usac.h | 37 + libavcodec/aac_ac3_parser.c | 14 +- libavcodec/aac_ac3_parser.h | 10 - libavcodec/aac_defines.h | 30 +- libavcodec/aac_parser.c | 16 +- libavcodec/aaccoder_twoloop.h | 6 +- libavcodec/aacdec.h | 279 -- libavcodec/aacdec_fixed.c | 515 --- libavcodec/aacenc.c | 13 +- libavcodec/aacenc.h | 16 +- libavcodec/aacenc_tns.c | 7 +- libavcodec/aacpsdsp.h | 1 - libavcodec/aacpsdsp_template.c | 2 - libavcodec/aacpsy.c | 5 +- libavcodec/aacsbr.c | 4 - libavcodec/aacsbr.h | 56 +- libavcodec/aacsbr_template.c | 285 +- libavcodec/aacsbrdata.h | 164 +- libavcodec/aactab.c | 570 +++- libavcodec/aactab.h | 25 + libavcodec/aarch64/Makefile | 12 +- libavcodec/aarch64/ac3dsp_init_aarch64.c | 50 + libavcodec/aarch64/ac3dsp_neon.S | 111 + .../{alpha/hpeldsp_alpha.h => aarch64/fdct.h} | 10 +- libavcodec/aarch64/fdctdsp_init_aarch64.c | 39 + libavcodec/aarch64/fdctdsp_neon.S | 368 +++ libavcodec/aarch64/h264pred_neon.S | 20 +- libavcodec/aarch64/h26x/dsp.h | 308 ++ .../{hevcdsp_epel_neon.S => h26x/epel_neon.S} | 404 ++- .../{hevcdsp_qpel_neon.S => h26x/qpel_neon.S} | 622 +++- .../{hevcdsp_sao_neon.S => h26x/sao_neon.S} | 46 +- libavcodec/aarch64/hevcdsp_init_aarch64.c | 240 +- libavcodec/aarch64/idctdsp_init_aarch64.c | 2 +- libavcodec/aarch64/me_cmp_init_aarch64.c | 14 + libavcodec/aarch64/me_cmp_neon.S | 114 + .../aarch64/mpegvideoencdsp_init.c | 55 +- libavcodec/aarch64/mpegvideoencdsp_neon.S | 93 + libavcodec/aarch64/opusdsp_init.c | 4 +- libavcodec/aarch64/opusdsp_neon.S | 28 +- libavcodec/aarch64/vp9mc_neon.S | 10 +- libavcodec/aarch64/vvc/Makefile | 10 + libavcodec/aarch64/vvc/alf.S | 293 ++ libavcodec/aarch64/vvc/alf_template.c | 157 + libavcodec/aarch64/vvc/dsp_init.c | 177 ++ libavcodec/aarch64/vvc/inter.S | 163 + libavcodec/aarch64/vvc/sad.S | 75 + libavcodec/ac3_parser.c | 16 +- libavcodec/ac3_parser_internal.h | 13 +- libavcodec/ac3dec.c | 21 +- libavcodec/ac3dsp.c | 4 +- libavcodec/ac3dsp.h | 3 +- libavcodec/ac3enc.c | 911 +++--- libavcodec/ac3enc.h | 68 +- libavcodec/ac3enc_fixed.c | 22 +- libavcodec/ac3enc_float.c | 20 +- libavcodec/ac3enc_template.c | 102 +- libavcodec/adpcm.c | 65 +- libavcodec/adpcmenc.c | 1 + libavcodec/adts_header.c | 17 +- libavcodec/adts_header.h | 30 +- libavcodec/adts_parser.c | 19 +- libavcodec/agm.c | 1 + libavcodec/aic.c | 6 +- libavcodec/alac.c | 1 + libavcodec/alacenc.c | 1 + libavcodec/aliaspixdec.c | 3 - libavcodec/allcodecs.c | 60 +- libavcodec/alpha/Makefile | 10 - libavcodec/alpha/asm.h | 153 - libavcodec/alpha/hpeldsp_alpha.c | 213 -- libavcodec/alpha/hpeldsp_alpha_asm.S | 125 - libavcodec/alpha/idctdsp_alpha.c | 127 - libavcodec/alpha/idctdsp_alpha.h | 34 - libavcodec/alpha/idctdsp_alpha_asm.S | 167 - libavcodec/alpha/me_cmp_alpha.c | 279 -- libavcodec/alpha/me_cmp_mvi_asm.S | 179 -- libavcodec/alpha/mpegvideo_alpha.c | 110 - libavcodec/alpha/pixblockdsp_alpha.c | 79 - libavcodec/alpha/regdef.h | 77 - libavcodec/alpha/simple_idct_alpha.c | 303 -- libavcodec/alsdec.c | 4 +- libavcodec/amfenc.c | 128 + libavcodec/amfenc.h | 5 + libavcodec/amfenc_av1.c | 225 +- libavcodec/amfenc_h264.c | 178 +- libavcodec/amfenc_hevc.c | 179 +- libavcodec/amrwbdec.c | 2 +- libavcodec/aom_film_grain.c | 49 +- libavcodec/aom_film_grain.h | 6 +- libavcodec/apac.c | 6 +- libavcodec/apedec.c | 1 + libavcodec/arm/ac3dsp_neon.S | 63 - libavcodec/arm/hevcdsp_arm.h | 2 +- libavcodec/arm/hevcdsp_init_arm.c | 2 +- libavcodec/arm/hevcdsp_init_neon.c | 2 +- libavcodec/arm/mlpdsp_armv5te.S | 6 +- libavcodec/arm/mpegvideo_arm.c | 20 +- libavcodec/arm/mpegvideoencdsp_init_arm.c | 4 +- libavcodec/arm/vp8.h | 3 +- libavcodec/arm/vp9mc_neon.S | 13 +- libavcodec/ass.c | 49 +- libavcodec/asvdec.c | 2 - libavcodec/asvenc.c | 2 + libavcodec/atrac1.c | 1 + libavcodec/atrac3.c | 1 + libavcodec/atrac3plus.c | 2 +- libavcodec/atrac3plusdec.c | 1 + libavcodec/atrac9dec.c | 1 + libavcodec/atsc_a53.c | 1 + libavcodec/audio_frame_queue.c | 2 +- libavcodec/audiodsp.c | 53 +- libavcodec/audiotoolboxdec.c | 3 + libavcodec/audiotoolboxenc.c | 2 + libavcodec/av1dec.c | 131 +- libavcodec/av1dec.h | 8 +- libavcodec/avcodec.c | 147 +- libavcodec/avcodec.h | 43 +- libavcodec/avcodec_internal.h | 51 +- libavcodec/avdct.c | 1 + libavcodec/avfft.c | 2 +- libavcodec/avr32/mathops.h | 101 - libavcodec/avrndec.c | 2 - libavcodec/avuidec.c | 3 - libavcodec/avuienc.c | 2 + libavcodec/bfi.c | 3 +- libavcodec/bgmc.c | 1 + libavcodec/bink.c | 2 +- libavcodec/bitpacked_dec.c | 3 - libavcodec/bitstream_filters.c | 3 +- libavcodec/bitstream_template.h | 2 +- libavcodec/blockdsp.c | 4 +- libavcodec/bmp.c | 2 - libavcodec/bmpenc.c | 2 +- libavcodec/bonk.c | 3 +- libavcodec/brenderpix.c | 2 - libavcodec/bsf/Makefile | 1 + libavcodec/bsf/aac_adtstoasc.c | 6 +- libavcodec/bsf/dovi_rpu.c | 285 ++ libavcodec/bsf/dts2pts.c | 22 +- libavcodec/bsf/evc_frame_merge.c | 1 + libavcodec/bsf/extract_extradata.c | 6 +- libavcodec/bsf/filter_units.c | 7 +- libavcodec/bsf/h264_metadata.c | 1 + libavcodec/bsf/h264_mp4toannexb.c | 15 + libavcodec/bsf/h265_metadata.c | 104 +- libavcodec/bsf/hevc_mp4toannexb.c | 3 +- libavcodec/bsf/media100_to_mjpegb.c | 1 + libavcodec/bsf/noise.c | 1 + libavcodec/bsf/remove_extradata.c | 3 +- libavcodec/bsf/showinfo.c | 6 +- libavcodec/cavs.c | 1 + libavcodec/cavsdec.c | 1 + libavcodec/cbs.c | 1 + libavcodec/cbs_av1.c | 10 +- libavcodec/cbs_av1.h | 5 + libavcodec/cbs_av1_syntax_template.c | 36 +- libavcodec/cbs_h264.h | 20 + libavcodec/cbs_h2645.c | 101 +- libavcodec/cbs_h264_syntax_template.c | 34 + libavcodec/cbs_h265.h | 74 +- libavcodec/cbs_h265_syntax_template.c | 416 ++- libavcodec/cbs_h266.h | 28 +- libavcodec/cbs_h266_syntax_template.c | 94 +- libavcodec/cbs_jpeg.c | 1 + libavcodec/cbs_sei.c | 5 +- libavcodec/cbs_sei.h | 30 + libavcodec/cbs_sei_syntax_template.c | 62 + libavcodec/cbs_vp9.c | 2 +- libavcodec/cdtoons.c | 1 + libavcodec/cdxl.c | 3 +- libavcodec/cfhd.c | 2 +- libavcodec/cfhdenc.c | 10 +- libavcodec/cinepakenc.c | 3 +- libavcodec/clearvideo.c | 1 + libavcodec/cljrdec.c | 2 - libavcodec/cljrenc.c | 1 + libavcodec/cllc.c | 4 +- libavcodec/cngdec.c | 2 +- libavcodec/cngenc.c | 1 + libavcodec/codec.h | 19 +- libavcodec/codec_desc.c | 26 +- libavcodec/codec_id.h | 2 + libavcodec/codec_internal.h | 50 +- libavcodec/container_fifo.c | 195 ++ libavcodec/container_fifo.h | 89 + libavcodec/cook.c | 1 + libavcodec/cri.c | 3 - libavcodec/cscd.c | 2 +- libavcodec/cuviddec.c | 24 +- libavcodec/d3d12va_av1.c | 1 + libavcodec/d3d12va_decode.c | 5 +- libavcodec/d3d12va_encode.c | 1557 +++++++++ libavcodec/d3d12va_encode.h | 335 ++ libavcodec/d3d12va_encode_hevc.c | 1007 ++++++ libavcodec/d3d12va_hevc.c | 14 +- libavcodec/d3d12va_mpeg2.c | 10 +- libavcodec/d3d12va_vc1.c | 10 +- libavcodec/dca_core.c | 1 + libavcodec/dca_lbr.c | 1 + libavcodec/dca_xll.c | 1 + libavcodec/dcaadpcm.c | 1 + libavcodec/dcadec.c | 1 + libavcodec/dcaenc.c | 2 +- libavcodec/dds.c | 2 - libavcodec/decode.c | 592 +++- libavcodec/decode.h | 26 +- libavcodec/defs.h | 2 + libavcodec/dirac.c | 1 + libavcodec/diracdec.c | 18 +- libavcodec/dnxhddec.c | 3 +- libavcodec/dnxhdenc.c | 48 +- libavcodec/dnxhdenc.h | 1 - libavcodec/dovi_rpu.c | 462 +-- libavcodec/dovi_rpu.h | 153 +- libavcodec/dovi_rpudec.c | 742 +++++ libavcodec/dovi_rpuenc.c | 937 ++++++ libavcodec/dsd.c | 12 +- libavcodec/dsddec.c | 6 +- libavcodec/dsicinvideo.c | 1 + libavcodec/dv.c | 4 +- libavcodec/dv_internal.h | 2 +- libavcodec/dvbsubdec.c | 1 + libavcodec/dvdec.c | 8 +- libavcodec/dvdsubdec.c | 1 + libavcodec/dvdsubenc.c | 1 + libavcodec/dvenc.c | 29 +- libavcodec/dxa.c | 2 +- libavcodec/dxtory.c | 2 - libavcodec/dxv.c | 4 +- libavcodec/dxva2.c | 11 +- libavcodec/dxva2_av1.c | 15 +- libavcodec/dxva2_hevc.c | 66 +- libavcodec/dxva2_mpeg2.c | 21 +- libavcodec/dxva2_vc1.c | 25 +- libavcodec/dxva2_vp9.c | 8 +- libavcodec/dxvenc.c | 1 + libavcodec/eac3dec.c | 6 +- libavcodec/eac3enc.c | 154 +- libavcodec/eac3enc.h | 10 - libavcodec/eacmv.c | 5 +- libavcodec/eamad.c | 1 + libavcodec/eatgq.c | 5 +- libavcodec/eatqi.c | 1 + libavcodec/elbg.c | 1 + libavcodec/encode.c | 119 +- libavcodec/error_resilience.c | 44 +- libavcodec/error_resilience.h | 1 + libavcodec/escape124.c | 1 + libavcodec/evc.h | 6 +- libavcodec/evc_ps.c | 1 + libavcodec/exr.c | 1 + libavcodec/exrenc.c | 3 +- libavcodec/fastaudio.c | 1 + libavcodec/faxcompr.c | 1 + libavcodec/fdctdsp.c | 4 +- libavcodec/fdctdsp.h | 2 + libavcodec/ffv1.c | 127 +- libavcodec/ffv1.h | 90 +- libavcodec/ffv1_template.c | 22 +- libavcodec/ffv1dec.c | 529 ++-- libavcodec/ffv1dec_template.c | 71 +- libavcodec/ffv1enc.c | 315 +- libavcodec/ffv1enc_template.c | 83 +- libavcodec/ffwavesynth.c | 1 + libavcodec/fic.c | 1 + libavcodec/fitsdec.c | 3 - libavcodec/flac_parser.c | 3 +- libavcodec/flacdec.c | 20 +- libavcodec/flacdsp.c | 31 + libavcodec/flacdsp.h | 5 + libavcodec/flacenc.c | 10 +- libavcodec/flashsv.c | 1 + libavcodec/flashsv2enc.c | 2 +- libavcodec/flvdec.c | 7 +- libavcodec/flvenc.c | 1 + libavcodec/fmvc.c | 1 + libavcodec/frame_thread_encoder.c | 53 +- libavcodec/fraps.c | 4 +- libavcodec/frwu.c | 3 - libavcodec/ftr_parser.c | 7 +- libavcodec/g2meet.c | 13 +- libavcodec/g722enc.c | 1 + libavcodec/g726.c | 2 +- libavcodec/g729dec.c | 3 +- libavcodec/gdv.c | 1 + libavcodec/gemdec.c | 1 + libavcodec/get_buffer.c | 25 +- libavcodec/gif.c | 2 + libavcodec/gifdec.c | 1 + libavcodec/h261.h | 9 +- libavcodec/h261data.c | 14 +- libavcodec/h261dec.c | 123 +- libavcodec/h261enc.c | 119 +- libavcodec/h263.c | 51 +- libavcodec/h263dec.c | 119 +- libavcodec/h263dec.h | 6 +- libavcodec/h263dsp.c | 4 +- libavcodec/h263dsp.h | 1 + libavcodec/h263enc.h | 32 +- libavcodec/h2645_parse.c | 24 +- libavcodec/h2645_parse.h | 17 +- libavcodec/h2645_sei.c | 304 +- libavcodec/h2645_sei.h | 11 +- libavcodec/h264_parse.c | 6 +- libavcodec/h264_parse.h | 2 +- libavcodec/h264_refs.c | 143 +- libavcodec/h264_sei.c | 1 - libavcodec/h264_slice.c | 13 +- libavcodec/h264dec.c | 55 +- libavcodec/h264dec.h | 9 +- libavcodec/h264dsp.c | 2 + libavcodec/h264dsp.h | 2 + libavcodec/hap.c | 1 + libavcodec/hapdec.c | 4 +- libavcodec/hapenc.c | 2 +- libavcodec/hcadec.c | 1 + libavcodec/hcom.c | 1 + libavcodec/hdrdec.c | 3 - libavcodec/hdrenc.c | 2 +- libavcodec/hevc/Makefile | 28 + libavcodec/{hevc_cabac.c => hevc/cabac.c} | 186 +- libavcodec/{hevc_data.c => hevc/data.c} | 2 +- libavcodec/{hevc_data.h => hevc/data.h} | 0 libavcodec/{hevcdsp.c => hevc/dsp.c} | 10 +- libavcodec/{hevcdsp.h => hevc/dsp.h} | 8 +- .../dsp_template.c} | 6 +- libavcodec/{hevc_filter.c => hevc/filter.c} | 486 +-- libavcodec/{ => hevc}/hevc.h | 15 +- libavcodec/{ => hevc}/hevcdec.c | 2809 ++++++++++------- libavcodec/{ => hevc}/hevcdec.h | 267 +- libavcodec/{hevc_mvs.c => hevc/mvs.c} | 158 +- libavcodec/{hevc_parse.c => hevc/parse.c} | 13 +- libavcodec/{hevc_parse.h => hevc/parse.h} | 4 +- libavcodec/{hevc_parser.c => hevc/parser.c} | 82 +- libavcodec/{hevcpred.c => hevc/pred.c} | 10 +- libavcodec/{hevcpred.h => hevc/pred.h} | 10 +- .../pred_template.c} | 82 +- libavcodec/{hevc_ps.c => hevc/ps.c} | 880 ++++-- libavcodec/{hevc_ps.h => hevc/ps.h} | 183 +- libavcodec/{hevc_ps_enc.c => hevc/ps_enc.c} | 2 +- libavcodec/hevc/refs.c | 588 ++++ libavcodec/{hevc_sei.c => hevc/sei.c} | 61 +- libavcodec/{hevc_sei.h => hevc/sei.h} | 24 +- libavcodec/hevc_refs.c | 558 ---- libavcodec/hpeldsp.c | 2 - libavcodec/hq_hqa.c | 3 - libavcodec/hqx.c | 3 - libavcodec/huffyuv.c | 29 +- libavcodec/huffyuv.h | 2 - libavcodec/huffyuvdec.c | 82 +- libavcodec/huffyuvenc.c | 225 +- libavcodec/huffyuvencdsp.c | 32 +- libavcodec/hw_base_encode.c | 817 +++++ libavcodec/hw_base_encode.h | 253 ++ libavcodec/hw_base_encode_h264.c | 265 ++ libavcodec/hw_base_encode_h264.h | 52 + libavcodec/hw_base_encode_h265.c | 351 ++ libavcodec/hw_base_encode_h265.h | 56 + libavcodec/idctdsp.c | 2 - libavcodec/iff.c | 13 +- libavcodec/iirfilter.c | 14 - libavcodec/iirfilter.h | 15 - libavcodec/ilbcdec.c | 2 +- libavcodec/imc.c | 1 + libavcodec/imm4.c | 5 + libavcodec/indeo3.c | 1 + libavcodec/intelh263dec.c | 7 +- libavcodec/internal.h | 15 +- libavcodec/interplayacm.c | 1 + libavcodec/intrax8.c | 3 +- libavcodec/intrax8.h | 2 +- libavcodec/ituh263dec.c | 77 +- libavcodec/ituh263enc.c | 47 +- libavcodec/itut35.h | 2 + libavcodec/ivi.c | 1 + libavcodec/j2kenc.c | 2 + libavcodec/jfdctint_template.c | 2 +- libavcodec/jni.c | 4 +- libavcodec/jpeg2000.h | 10 + libavcodec/jpeg2000dec.c | 511 ++- libavcodec/jpeg2000dec.h | 7 + libavcodec/jpeg2000htdec.c | 293 +- libavcodec/jpeg2000htdec.h | 2 +- libavcodec/jpeglsdec.c | 1 + libavcodec/jpeglsenc.c | 1 + libavcodec/jpegxl_parser.c | 9 +- libavcodec/jvdec.c | 2 - libavcodec/kgv1dec.c | 1 + libavcodec/lagarith.c | 3 - libavcodec/lcevcdec.c | 319 ++ libavcodec/lcevcdec.h | 42 + libavcodec/lcldec.c | 3 - libavcodec/leaddec.c | 4 +- libavcodec/libaomenc.c | 118 +- libavcodec/libaribb24.c | 1 + libavcodec/libaribcaption.c | 1 + libavcodec/libcodec2.c | 1 + libavcodec/libdav1d.c | 20 +- libavcodec/libfdk-aacdec.c | 8 +- libavcodec/libfdk-aacenc.c | 11 + libavcodec/libjxldec.c | 2 +- libavcodec/libjxlenc.c | 1 + libavcodec/libkvazaar.c | 5 +- libavcodec/liblc3dec.c | 146 + libavcodec/liblc3enc.c | 214 ++ libavcodec/libmp3lame.c | 1 + libavcodec/libopencore-amr.c | 1 + libavcodec/libopenh264enc.c | 3 +- libavcodec/libopenjpegenc.c | 1 + libavcodec/libopusenc.c | 1 + libavcodec/librav1e.c | 2 + libavcodec/libspeexenc.c | 1 + libavcodec/libsvtav1.c | 51 +- libavcodec/libtheoraenc.c | 2 + libavcodec/libvorbisenc.c | 1 + libavcodec/libvpxenc.c | 58 +- libavcodec/libvvenc.c | 491 +++ libavcodec/libwebpenc.c | 2 + libavcodec/libwebpenc_animencoder.c | 3 +- libavcodec/libwebpenc_common.c | 1 + libavcodec/libx264.c | 66 +- libavcodec/libx265.c | 128 +- libavcodec/libxavs.c | 1 + libavcodec/libxavs2.c | 1 + libavcodec/libxevd.c | 8 +- libavcodec/libxeve.c | 9 +- libavcodec/libxvid.c | 5 +- libavcodec/libzvbi-teletextdec.c | 2 +- libavcodec/ljpegenc.c | 1 + libavcodec/loco.c | 1 - libavcodec/loongarch/Makefile | 2 +- libavcodec/loongarch/hevcdsp_lasx.h | 2 +- libavcodec/loongarch/hevcdsp_lsx.h | 2 +- libavcodec/lpc.c | 6 +- libavcodec/lscrdec.c | 1 + libavcodec/m101.c | 2 - libavcodec/magicyuv.c | 4 +- libavcodec/magicyuvenc.c | 18 +- libavcodec/mathops.h | 2 - libavcodec/mdec.c | 3 +- libavcodec/me_cmp.c | 132 +- libavcodec/me_cmp.h | 16 +- libavcodec/mediacodec_wrapper.c | 165 +- libavcodec/mediacodecdec.c | 107 +- libavcodec/mediacodecdec_common.c | 346 +- libavcodec/mediacodecenc.c | 208 +- libavcodec/mf_utils.h | 5 + libavcodec/mfenc.c | 34 +- libavcodec/mimic.c | 62 +- libavcodec/mips/Makefile | 11 +- libavcodec/mips/aacdec_mips.c | 443 --- libavcodec/mips/aacdec_mips.h | 253 -- libavcodec/mips/aacpsdsp_mips.c | 465 --- libavcodec/mips/aacpsy_mips.h | 238 -- libavcodec/mips/aacsbr_mips.c | 624 ---- libavcodec/mips/aacsbr_mips.h | 496 --- libavcodec/mips/ac3dsp_mips.c | 2 + libavcodec/mips/h263dsp_mips.h | 2 +- libavcodec/mips/h264dsp_init_mips.c | 7 - libavcodec/mips/h264dsp_mips.h | 2 - libavcodec/mips/h264dsp_mmi.c | 47 - libavcodec/mips/hevcdsp_mips.h | 2 +- libavcodec/mips/hevcdsp_mmi.c | 2 +- libavcodec/mips/hevcpred_mips.h | 6 +- libavcodec/mips/hevcpred_msa.c | 361 ++- libavcodec/mips/mpegvideo_init_mips.c | 2 - libavcodec/mips/mpegvideo_mmi.c | 72 - .../mips/mpegvideoenc_init_mips.c | 33 +- libavcodec/mips/mpegvideoenc_mmi.c | 98 + libavcodec/mips/mpegvideoencdsp_msa.c | 2 +- libavcodec/mips/sbrdsp_mips.c | 912 ------ libavcodec/mjpegdec.c | 23 +- libavcodec/mjpegenc.c | 32 +- libavcodec/mjpegenc_common.c | 13 +- libavcodec/mlpdec.c | 1 + libavcodec/mlz.c | 1 + libavcodec/mmaldec.c | 1 + libavcodec/mobiclip.c | 1 + libavcodec/motion_est.c | 236 +- libavcodec/motion_est.h | 17 +- libavcodec/motion_est_template.c | 60 +- libavcodec/motionpixels.c | 1 + libavcodec/mpc7.c | 1 + libavcodec/mpeg12.c | 44 +- libavcodec/mpeg12dec.c | 308 +- libavcodec/mpeg12dec.h | 2 + libavcodec/mpeg12enc.c | 52 +- libavcodec/mpeg4audio.h | 83 +- libavcodec/mpeg4video.c | 14 +- libavcodec/mpeg4video_parser.c | 2 +- libavcodec/mpeg4videodec.c | 206 +- libavcodec/mpeg4videodec.h | 2 + libavcodec/mpeg4videoenc.c | 87 +- libavcodec/mpeg_er.c | 30 +- libavcodec/mpegaudiodec_template.c | 1 + libavcodec/mpegpicture.c | 451 +-- libavcodec/mpegpicture.h | 123 +- libavcodec/mpegutils.c | 59 +- libavcodec/mpegutils.h | 65 +- libavcodec/mpegvideo.c | 273 +- libavcodec/mpegvideo.h | 59 +- libavcodec/mpegvideo_dec.c | 461 ++- libavcodec/mpegvideo_enc.c | 884 +++--- libavcodec/mpegvideo_motion.c | 83 +- libavcodec/mpegvideodec.h | 14 +- libavcodec/mpegvideoenc.h | 25 +- libavcodec/mpegvideoencdsp.c | 63 +- libavcodec/mpegvideoencdsp.h | 14 +- libavcodec/mpv_reconstruct_mb_template.c | 78 +- libavcodec/mscc.c | 47 +- libavcodec/msmpeg4.c | 31 +- libavcodec/msmpeg4dec.c | 109 +- libavcodec/msmpeg4enc.c | 71 +- libavcodec/msp2dec.c | 3 - libavcodec/mss12.c | 1 + libavcodec/mss2.c | 6 +- libavcodec/mss3.c | 1 + libavcodec/mss4.c | 1 + libavcodec/msvideo1enc.c | 1 + libavcodec/mv30.c | 1 + libavcodec/mvcdec.c | 3 - libavcodec/mvha.c | 4 +- libavcodec/mwsc.c | 1 + libavcodec/mxpegdec.c | 1 + libavcodec/nellymoserdec.c | 1 + libavcodec/nellymoserenc.c | 1 + libavcodec/notchlc.c | 7 +- libavcodec/nuv.c | 1 + libavcodec/nvdec.c | 1 + libavcodec/nvdec_av1.c | 9 +- libavcodec/nvdec_h264.c | 1 + libavcodec/nvdec_hevc.c | 72 +- libavcodec/nvdec_mpeg12.c | 7 +- libavcodec/nvdec_mpeg4.c | 6 +- libavcodec/nvdec_vc1.c | 6 +- libavcodec/nvenc.c | 174 +- libavcodec/nvenc.h | 14 + libavcodec/nvenc_av1.c | 22 +- libavcodec/nvenc_h264.c | 10 + libavcodec/nvenc_hevc.c | 35 +- libavcodec/omx.c | 3 + libavcodec/on2avc.c | 1 + libavcodec/options.c | 3 +- libavcodec/options_table.h | 5 + libavcodec/opus/Makefile | 30 + libavcodec/{opus_celt.c => opus/celt.c} | 6 +- libavcodec/{opus_celt.h => opus/celt.h} | 7 +- libavcodec/{opusdec.c => opus/dec.c} | 11 +- .../{opusdec_celt.c => opus/dec_celt.c} | 13 +- libavcodec/{opusdsp.c => opus/dsp.c} | 8 +- libavcodec/{opusdsp.h => opus/dsp.h} | 10 +- libavcodec/{opusenc.c => opus/enc.c} | 14 +- libavcodec/{opusenc.h => opus/enc.h} | 6 +- libavcodec/{opusenc_psy.c => opus/enc_psy.c} | 9 +- libavcodec/{opusenc_psy.h => opus/enc_psy.h} | 12 +- .../{opusenc_utils.h => opus/enc_utils.h} | 6 +- libavcodec/{ => opus}/opus.h | 6 +- libavcodec/{opus_parse.c => opus/parse.c} | 2 +- libavcodec/{opus_parse.h => opus/parse.h} | 2 +- libavcodec/{opus_parser.c => opus/parser.c} | 3 +- libavcodec/{opus_pvq.c => opus/pvq.c} | 9 +- libavcodec/{opus_pvq.h => opus/pvq.h} | 2 +- libavcodec/{opus_rc.c => opus/rc.c} | 8 +- libavcodec/{opus_rc.h => opus/rc.h} | 4 +- libavcodec/{opus_silk.c => opus/silk.c} | 7 +- libavcodec/{opus_silk.h => opus/silk.h} | 2 +- libavcodec/{opustab.c => opus/tab.c} | 30 +- libavcodec/{opustab.h => opus/tab.h} | 8 +- libavcodec/osq.c | 11 +- libavcodec/{avpacket.c => packet.c} | 2 + libavcodec/packet.h | 25 +- libavcodec/pafvideo.c | 1 + libavcodec/parser.c | 1 + libavcodec/pcm.c | 1 + libavcodec/pcx.c | 1 + libavcodec/pcxenc.c | 2 +- libavcodec/pgssubdec.c | 1 + libavcodec/pgxdec.c | 2 - libavcodec/photocd.c | 3 - libavcodec/pictordec.c | 1 + libavcodec/pixblockdsp.c | 11 +- libavcodec/pixlet.c | 7 +- libavcodec/pngdec.c | 73 +- libavcodec/pngdsp.c | 25 +- libavcodec/pngenc.c | 1 + libavcodec/pnmdec.c | 2 - libavcodec/ppc/hevcdsp.c | 2 +- libavcodec/ppc/hpeldsp_altivec.c | 4 +- libavcodec/ppc/mpegvideoencdsp.c | 8 +- libavcodec/profiles.c | 5 +- libavcodec/profiles.h | 4 +- libavcodec/progressframe.h | 157 + libavcodec/{proresdec2.c => proresdec.c} | 3 +- libavcodec/proresenc_anatoliy.c | 5 +- libavcodec/proresenc_kostya.c | 6 +- libavcodec/prosumer.c | 2 - libavcodec/psd.c | 1 + libavcodec/pthread.c | 1 + libavcodec/pthread_frame.c | 348 +- libavcodec/pthread_slice.c | 102 - libavcodec/put_bits.h | 2 +- libavcodec/put_golomb.h | 2 +- libavcodec/qdrw.c | 3 - libavcodec/qoidec.c | 3 - libavcodec/qsv.c | 130 +- libavcodec/qsv_internal.h | 11 +- libavcodec/qsvdec.c | 154 +- libavcodec/qsvenc.c | 121 +- libavcodec/qsvenc.h | 11 +- libavcodec/qsvenc_av1.c | 76 +- libavcodec/qsvenc_h264.c | 1 + libavcodec/qsvenc_hevc.c | 11 +- libavcodec/qsvenc_jpeg.c | 1 + libavcodec/qsvenc_mpeg2.c | 1 + libavcodec/qsvenc_vp9.c | 1 + libavcodec/qtrleenc.c | 1 + libavcodec/r210dec.c | 2 - libavcodec/ra288.c | 1 + libavcodec/rangecoder.h | 5 +- libavcodec/rasc.c | 1 + libavcodec/ratecontrol.c | 115 +- libavcodec/ratecontrol.h | 13 +- libavcodec/rawdec.c | 6 +- libavcodec/riscv/Makefile | 26 +- libavcodec/riscv/aacencdsp_init.c | 5 +- libavcodec/riscv/aacencdsp_rvv.S | 35 +- libavcodec/riscv/aacpsdsp_init.c | 27 +- libavcodec/riscv/aacpsdsp_rvv.S | 15 +- libavcodec/riscv/ac3dsp_init.c | 38 +- libavcodec/riscv/ac3dsp_rvb.S | 23 + libavcodec/riscv/ac3dsp_rvv.S | 108 +- .../timer.h => libavcodec/riscv/ac3dsp_rvvb.S | 56 +- libavcodec/riscv/alacdsp_init.c | 2 +- libavcodec/riscv/alacdsp_rvv.S | 9 +- libavcodec/riscv/audiodsp_init.c | 17 +- libavcodec/riscv/audiodsp_rvv.S | 8 +- libavcodec/riscv/blockdsp_init.c | 8 +- libavcodec/riscv/blockdsp_rvv.S | 25 + libavcodec/riscv/bswapdsp_init.c | 17 +- libavcodec/riscv/bswapdsp_rvb.S | 2 + libavcodec/riscv/bswapdsp_rvv.S | 3 +- .../riscv/{audiodsp_rvf.S => bswapdsp_rvvb.S} | 49 +- libavcodec/riscv/cpu_common.c | 1 + libavcodec/riscv/exrdsp_init.c | 3 +- libavcodec/riscv/exrdsp_rvv.S | 3 +- libavcodec/riscv/fixed_vtype.S | 48 + libavcodec/riscv/flacdsp_init.c | 27 +- libavcodec/riscv/flacdsp_rvv.S | 142 +- libavcodec/riscv/fmtconvert_init.c | 2 +- libavcodec/riscv/fmtconvert_rvv.S | 6 +- libavcodec/riscv/g722dsp_init.c | 2 +- libavcodec/riscv/g722dsp_rvv.S | 1 + .../blockdsp_alpha.c => riscv/h263dsp_init.c} | 40 +- libavcodec/riscv/h263dsp_rvv.S | 101 + libavcodec/riscv/h264_chroma_init_riscv.c | 2 +- libavcodec/riscv/h264_mc_chroma.S | 12 +- libavcodec/riscv/h264addpx_rvv.S | 115 + libavcodec/riscv/h264dsp_init.c | 182 ++ libavcodec/riscv/h264dsp_rvv.S | 393 +++ libavcodec/riscv/h264idct_rvv.S | 805 +++++ libavcodec/riscv/huffyuvdsp_init.c | 2 +- libavcodec/riscv/huffyuvdsp_rvv.S | 10 +- libavcodec/riscv/idctdsp_init.c | 2 +- libavcodec/riscv/idctdsp_rvv.S | 3 + libavcodec/riscv/jpeg2000dsp_init.c | 2 +- libavcodec/riscv/jpeg2000dsp_rvv.S | 6 +- libavcodec/riscv/llauddsp_init.c | 2 +- libavcodec/riscv/llauddsp_rvv.S | 6 +- libavcodec/riscv/llviddsp_rvv.S | 1 + libavcodec/riscv/llvidencdsp_rvv.S | 1 + libavcodec/riscv/lpc_init.c | 2 +- libavcodec/riscv/lpc_rvv.S | 9 +- libavcodec/riscv/me_cmp_init.c | 2 +- libavcodec/riscv/me_cmp_rvv.S | 17 + libavcodec/riscv/mpegvideoencdsp_init.c | 51 + libavcodec/riscv/mpegvideoencdsp_rvv.S | 127 + libavcodec/riscv/opusdsp_init.c | 5 +- libavcodec/riscv/opusdsp_rvv.S | 3 +- libavcodec/riscv/pixblockdsp_init.c | 9 +- libavcodec/riscv/pixblockdsp_rvi.S | 2 + libavcodec/riscv/pixblockdsp_rvv.S | 4 + libavcodec/riscv/rv34dsp_init.c | 2 +- libavcodec/riscv/rv34dsp_rvv.S | 22 +- libavcodec/riscv/rv40dsp_init.c | 51 + libavcodec/riscv/rv40dsp_rvv.S | 375 +++ libavcodec/riscv/sbrdsp_init.c | 15 +- libavcodec/riscv/sbrdsp_rvv.S | 45 +- libavcodec/riscv/startcode_rvb.S | 84 + libavcodec/riscv/startcode_rvv.S | 47 + libavcodec/riscv/svqenc_init.c | 2 +- libavcodec/riscv/svqenc_rvv.S | 3 +- libavcodec/riscv/takdsp_init.c | 2 +- libavcodec/riscv/takdsp_rvv.S | 12 +- libavcodec/riscv/utvideodsp_init.c | 2 +- libavcodec/riscv/utvideodsp_rvv.S | 6 +- libavcodec/riscv/vc1dsp_init.c | 47 +- libavcodec/riscv/vc1dsp_rvi.S | 49 + libavcodec/riscv/vc1dsp_rvv.S | 502 ++- libavcodec/riscv/videodsp.S | 34 + .../riscv/videodsp_init.c | 38 +- libavcodec/riscv/vorbisdsp_init.c | 2 +- libavcodec/riscv/vorbisdsp_rvv.S | 3 +- libavcodec/riscv/vp7dsp_init.c | 59 + libavcodec/riscv/vp7dsp_rvv.S | 150 + libavcodec/riscv/vp8dsp.h | 75 + libavcodec/riscv/vp8dsp_init.c | 101 +- libavcodec/riscv/vp8dsp_rvi.S | 64 + libavcodec/riscv/vp8dsp_rvv.S | 544 +++- libavcodec/riscv/vp9_intra_rvv.S | 300 ++ libavcodec/riscv/vp9_mc_rvi.S | 110 + libavcodec/riscv/vp9_mc_rvv.S | 208 ++ libavcodec/riscv/vp9dsp.h | 188 ++ libavcodec/riscv/vp9dsp_init.c | 147 + libavcodec/rka.c | 1 + libavcodec/rkmppdec.c | 86 +- libavcodec/roqaudioenc.c | 1 + libavcodec/roqvideoenc.c | 2 + libavcodec/rpzaenc.c | 8 +- libavcodec/rscc.c | 1 + libavcodec/rtv1.c | 3 - libavcodec/rv10.c | 74 +- libavcodec/rv10enc.c | 1 + libavcodec/rv20enc.c | 1 + libavcodec/rv30.c | 20 +- libavcodec/rv34.c | 199 +- libavcodec/rv34dsp.h | 1 + libavcodec/rv40.c | 12 +- libavcodec/rv40dsp.c | 2 + libavcodec/samidec.c | 1 + libavcodec/sanm.c | 1 + libavcodec/sbr.h | 32 +- libavcodec/sbrdsp.h | 1 - libavcodec/sbrdsp_template.c | 10 +- libavcodec/scpr.c | 1 + libavcodec/sga.c | 9 +- libavcodec/sgidec.c | 2 - libavcodec/sgienc.c | 1 + libavcodec/sgirledec.c | 6 +- libavcodec/sh4/README | 6 - libavcodec/sheervideo.c | 3 - libavcodec/shorten.c | 9 +- libavcodec/sinewin_fixed_tablegen.c | 2 + libavcodec/sinewin_fixed_tablegen.h | 4 + libavcodec/siren.c | 1 + libavcodec/smacker.c | 1 + libavcodec/smcenc.c | 4 +- libavcodec/snow.c | 1 + libavcodec/snow_dwt.c | 1 + libavcodec/snowdec.c | 2 +- libavcodec/snowenc.c | 43 +- libavcodec/sonic.c | 1 + libavcodec/sp5xdec.c | 2 +- libavcodec/speedhqdec.c | 217 +- libavcodec/speedhqenc.c | 15 +- libavcodec/speexdec.c | 1 + libavcodec/sunrast.c | 1 + libavcodec/svq1dec.c | 1 + libavcodec/svq1enc.c | 42 +- libavcodec/svq3.c | 4 + libavcodec/takdec.c | 1 + libavcodec/targa_y216dec.c | 3 - libavcodec/tdsc.c | 1 + libavcodec/tests/aarch64/dct.c | 2 + libavcodec/tests/avcodec.c | 6 +- libavcodec/tests/avpacket.c | 1 + libavcodec/tests/iirfilter.c | 17 +- libavcodec/tests/motion.c | 2 - libavcodec/tests/snowenc.c | 1 + libavcodec/tests/x86/dct.c | 4 +- libavcodec/thread.h | 59 +- libavcodec/threadprogress.c | 79 + libavcodec/threadprogress.h | 92 + libavcodec/tiff.c | 12 +- libavcodec/tiff_common.c | 1 + libavcodec/tiffenc.c | 2 + libavcodec/tmv.c | 2 - libavcodec/truemotion2.c | 1 + libavcodec/truemotion2rt.c | 2 - libavcodec/tscc.c | 1 + libavcodec/tscc2.c | 1 + libavcodec/tta.c | 1 + libavcodec/ttaenc.c | 1 + libavcodec/ttmlenc.c | 1 + libavcodec/twinvq.c | 1 + libavcodec/utils.c | 29 +- libavcodec/utvideodec.c | 3 +- libavcodec/utvideoenc.c | 3 +- libavcodec/v210dec.c | 4 +- libavcodec/v210x.c | 2 - libavcodec/v308dec.c | 3 - libavcodec/v408dec.c | 7 - libavcodec/v408enc.c | 5 - libavcodec/v410dec.c | 3 - libavcodec/v4l2_buffers.c | 7 +- libavcodec/v4l2_buffers.h | 6 +- libavcodec/v4l2_context.c | 1 + libavcodec/v4l2_m2m.c | 26 +- libavcodec/v4l2_m2m.h | 5 +- libavcodec/v4l2_m2m_enc.c | 1 + libavcodec/vaapi_av1.c | 54 +- libavcodec/vaapi_decode.c | 50 +- libavcodec/vaapi_decode.h | 1 + libavcodec/vaapi_encode.c | 1062 +------ libavcodec/vaapi_encode.h | 192 +- libavcodec/vaapi_encode_av1.c | 178 +- libavcodec/vaapi_encode_h264.c | 427 +-- libavcodec/vaapi_encode_h265.c | 493 +-- libavcodec/vaapi_encode_mjpeg.c | 34 +- libavcodec/vaapi_encode_mpeg2.c | 64 +- libavcodec/vaapi_encode_vp8.c | 28 +- libavcodec/vaapi_encode_vp9.c | 56 +- libavcodec/vaapi_h264.c | 16 +- libavcodec/vaapi_hevc.c | 115 +- libavcodec/vaapi_mjpeg.c | 2 +- libavcodec/vaapi_mpeg2.c | 14 +- libavcodec/vaapi_mpeg4.c | 18 +- libavcodec/vaapi_vc1.c | 17 +- libavcodec/vaapi_vp8.c | 2 +- libavcodec/vaapi_vp9.c | 4 +- libavcodec/vb.c | 1 + libavcodec/vble.c | 14 +- libavcodec/vbndec.c | 4 +- libavcodec/vc1.c | 20 +- libavcodec/vc1.h | 1 + libavcodec/vc1_block.c | 264 +- libavcodec/vc1_loopfilter.c | 56 +- libavcodec/vc1_mc.c | 130 +- libavcodec/vc1_parser.c | 5 +- libavcodec/vc1_pred.c | 260 +- libavcodec/vc1dec.c | 100 +- libavcodec/vc2enc.c | 63 +- libavcodec/vcr1.c | 2 - libavcodec/vdpau.c | 6 +- libavcodec/vdpau_av1.c | 11 +- libavcodec/vdpau_hevc.c | 71 +- libavcodec/vdpau_mpeg12.c | 8 +- libavcodec/vdpau_mpeg4.c | 6 +- libavcodec/vdpau_vc1.c | 12 +- libavcodec/version.c | 16 +- libavcodec/version.h | 4 +- libavcodec/version_major.h | 1 + libavcodec/videodsp.c | 2 + libavcodec/videodsp.h | 1 + libavcodec/videotoolbox.c | 28 +- libavcodec/videotoolbox_vp9.c | 1 + libavcodec/videotoolboxenc.c | 150 +- libavcodec/vlc.c | 10 +- libavcodec/vlc.h | 5 +- libavcodec/vmdvideo.c | 1 + libavcodec/vmixdec.c | 5 +- libavcodec/vmnc.c | 1 + libavcodec/vorbis_parser.c | 2 +- libavcodec/vorbisdec.c | 7 +- libavcodec/vorbisenc.c | 1 + libavcodec/vp3.c | 149 +- libavcodec/vp56.c | 1 + libavcodec/vp8.c | 109 +- libavcodec/vp8.h | 5 +- libavcodec/vp8dsp.c | 6 + libavcodec/vp8dsp.h | 3 + libavcodec/vp9.c | 157 +- libavcodec/vp9_mc_template.c | 2 +- libavcodec/vp9block.c | 5 +- libavcodec/vp9dec.h | 6 +- libavcodec/vp9dsp.c | 2 + libavcodec/vp9dsp.h | 1 + libavcodec/vp9dsp_template.c | 52 +- libavcodec/vp9lpf.c | 1 + libavcodec/vp9mvs.c | 7 +- libavcodec/vp9recon.c | 27 +- libavcodec/vp9shared.h | 9 +- libavcodec/vqavideo.c | 1 + libavcodec/vqcdec.c | 1 + libavcodec/vulkan_av1.c | 7 +- libavcodec/vulkan_decode.c | 243 +- libavcodec/vulkan_decode.h | 11 +- libavcodec/vulkan_encode.c | 1059 +++++++ libavcodec/vulkan_encode.h | 259 ++ libavcodec/vulkan_encode_h264.c | 1666 ++++++++++ libavcodec/vulkan_encode_h265.c | 1793 +++++++++++ libavcodec/vulkan_h264.c | 3 +- libavcodec/vulkan_hevc.c | 157 +- libavcodec/vulkan_video.c | 229 +- libavcodec/vulkan_video.h | 39 +- libavcodec/vvc.h | 3 + libavcodec/vvc/Makefile | 28 +- libavcodec/vvc/{vvc_cabac.c => cabac.c} | 14 +- libavcodec/vvc/{vvc_cabac.h => cabac.h} | 8 +- libavcodec/vvc/{vvc_ctu.c => ctu.c} | 109 +- libavcodec/vvc/{vvc_ctu.h => ctu.h} | 40 +- libavcodec/vvc/{vvc_data.c => data.c} | 85 +- libavcodec/vvc/{vvc_data.h => data.h} | 16 +- libavcodec/vvc/{vvcdec.c => dec.c} | 183 +- libavcodec/vvc/{vvcdec.h => dec.h} | 55 +- libavcodec/vvc/{vvcdsp.c => dsp.c} | 43 +- libavcodec/vvc/{vvcdsp.h => dsp.h} | 52 +- .../vvc/{vvcdsp_template.c => dsp_template.c} | 12 +- libavcodec/vvc/{vvc_filter.c => filter.c} | 1078 +++---- libavcodec/vvc/{vvc_filter.h => filter.h} | 14 +- ...vc_filter_template.c => filter_template.c} | 14 +- libavcodec/vvc/inter.c | 1026 ++++++ libavcodec/vvc/{vvc_inter.h => inter.h} | 8 +- ...{vvc_inter_template.c => inter_template.c} | 253 +- libavcodec/vvc/{vvc_intra.c => intra.c} | 63 +- libavcodec/vvc/{vvc_intra.h => intra.h} | 8 +- ...{vvc_intra_template.c => intra_template.c} | 4 +- .../vvc/{vvc_intra_utils.c => intra_utils.c} | 12 +- libavcodec/vvc/{vvc_itx_1d.c => itx_1d.c} | 4 +- libavcodec/vvc/{vvc_itx_1d.h => itx_1d.h} | 6 +- libavcodec/vvc/{vvc_mvs.c => mvs.c} | 128 +- libavcodec/vvc/{vvc_mvs.h => mvs.h} | 12 +- libavcodec/vvc/{vvc_ps.c => ps.c} | 262 +- libavcodec/vvc/{vvc_ps.h => ps.h} | 29 +- libavcodec/vvc/{vvc_refs.c => refs.c} | 86 +- libavcodec/vvc/{vvc_refs.h => refs.h} | 8 +- libavcodec/vvc/{vvc_thread.c => thread.c} | 218 +- libavcodec/vvc/{vvc_thread.h => thread.h} | 11 +- libavcodec/vvc/vvc_inter.c | 926 ------ libavcodec/vvc_parser.c | 9 +- libavcodec/wavarc.c | 3 +- libavcodec/wavpack.c | 163 +- libavcodec/wavpack.h | 1 + libavcodec/wavpackenc.c | 1 + libavcodec/wbmpdec.c | 3 - libavcodec/webp.c | 7 +- libavcodec/webvttdec.c | 4 +- libavcodec/wma.c | 1 + libavcodec/wmaenc.c | 1 + libavcodec/wmalosslessdec.c | 1 + libavcodec/wmaprodec.c | 3 +- libavcodec/wmavoice.c | 8 +- libavcodec/wmv2.c | 3 +- libavcodec/wmv2.h | 3 +- libavcodec/wmv2dec.c | 34 +- libavcodec/wmv2enc.c | 2 + libavcodec/wnv1.c | 1 - libavcodec/wrapped_avframe.c | 3 +- libavcodec/x86/Makefile | 2 - libavcodec/x86/aacencdsp.asm | 42 +- libavcodec/x86/aacencdsp_init.c | 6 + libavcodec/x86/ac3dsp.asm | 7 +- libavcodec/x86/blockdsp.asm | 33 + libavcodec/x86/blockdsp_init.c | 13 + libavcodec/x86/celt_pvq_init.c | 2 +- libavcodec/x86/celt_pvq_search.asm | 1 - libavcodec/x86/flacdsp.asm | 72 +- libavcodec/x86/flacdsp_init.c | 8 + libavcodec/x86/h264_weight.asm | 4 +- libavcodec/x86/hevcdsp_init.c | 2 +- libavcodec/x86/me_cmp_init.c | 2 +- libavcodec/x86/mpegvideo.c | 6 +- libavcodec/x86/mpegvideoenc_template.c | 2 - libavcodec/x86/mpegvideoencdsp.asm | 6 +- libavcodec/x86/mpegvideoencdsp_init.c | 69 +- libavcodec/x86/opusdsp.asm | 9 +- libavcodec/x86/opusdsp_init.c | 4 +- libavcodec/x86/vvc/Makefile | 6 +- libavcodec/x86/vvc/vvc_alf.asm | 876 +++++ libavcodec/x86/vvc/vvc_dmvr.asm | 373 +++ libavcodec/x86/vvc/vvc_of.asm | 385 +++ libavcodec/x86/vvc/vvc_sad.asm | 134 + libavcodec/x86/vvc/vvcdsp_init.c | 280 +- libavcodec/xan.c | 3 + libavcodec/xbmdec.c | 3 - libavcodec/xl.c | 2 - libavcodec/xpmdec.c | 4 +- libavcodec/xsubdec.c | 1 + libavcodec/xwddec.c | 3 - libavcodec/xwdenc.c | 1 + libavcodec/y41pdec.c | 3 - libavcodec/ylc.c | 2 - libavcodec/yop.c | 1 + libavcodec/yuv4dec.c | 3 - libavcodec/zmbv.c | 1 + libavcodec/zmbvenc.c | 5 +- libavdevice/alsa.c | 1 + libavdevice/android_camera.c | 1 + libavdevice/audiotoolbox.m | 1 + libavdevice/avdevice.c | 1 + libavdevice/avfoundation.m | 1 + libavdevice/bktr.c | 1 + libavdevice/caca.c | 1 + libavdevice/decklink_common.h | 2 + libavdevice/decklink_common_c.h | 7 + libavdevice/decklink_dec.cpp | 45 +- libavdevice/decklink_dec_c.c | 6 +- libavdevice/dshow.c | 4 +- libavdevice/dshow_enummediatypes.c | 1 + libavdevice/dshow_pin.c | 1 + libavdevice/fbdev_common.c | 1 + libavdevice/gdigrab.c | 3 +- libavdevice/iec61883.c | 1 + libavdevice/jack.c | 5 +- libavdevice/kmsgrab.c | 1 + libavdevice/opengl_enc.c | 3 +- libavdevice/riscv/Makefile | 1 + libavdevice/riscv/cpu_common.c | 1 + libavdevice/sdl2.c | 7 +- libavdevice/sndio.c | 2 +- libavdevice/utils.c | 1 + libavdevice/v4l2-common.c | 6 + libavdevice/v4l2.c | 94 +- libavdevice/version.c | 5 +- libavdevice/version.h | 2 +- libavdevice/vfwcap.c | 1 + libavdevice/xcbgrab.c | 1 + libavdevice/xv.c | 1 + libavfilter/Makefile | 20 +- libavfilter/aap_template.c | 14 +- libavfilter/aeval.c | 40 +- libavfilter/af_aap.c | 18 +- libavfilter/af_acontrast.c | 1 + libavfilter/af_acopy.c | 2 +- libavfilter/af_acrossover.c | 19 +- libavfilter/af_acrusher.c | 3 +- libavfilter/af_adeclick.c | 2 +- libavfilter/af_adecorrelate.c | 2 + libavfilter/af_adelay.c | 3 +- libavfilter/af_adenorm.c | 2 +- libavfilter/af_aderivative.c | 2 +- libavfilter/af_adrc.c | 5 +- libavfilter/af_adynamicequalizer.c | 18 +- libavfilter/af_adynamicsmooth.c | 1 + libavfilter/af_aecho.c | 2 +- libavfilter/af_aemphasis.c | 2 +- libavfilter/af_aexciter.c | 3 +- libavfilter/af_afade.c | 5 +- libavfilter/af_afftdn.c | 4 +- libavfilter/af_afftfilt.c | 2 +- libavfilter/af_afir.c | 110 +- libavfilter/af_afir.h | 110 - libavfilter/af_aformat.c | 172 +- libavfilter/af_afreqshift.c | 1 + libavfilter/af_afwtdn.c | 1 + libavfilter/af_agate.c | 24 +- libavfilter/af_aiir.c | 39 +- libavfilter/af_alimiter.c | 3 +- libavfilter/af_amerge.c | 2 +- libavfilter/af_amix.c | 2 +- libavfilter/af_amultiply.c | 2 +- libavfilter/af_anequalizer.c | 35 +- libavfilter/af_anlmdndsp.h | 1 - libavfilter/af_anlms.c | 18 +- libavfilter/af_anull.c | 2 +- libavfilter/af_apad.c | 1 - libavfilter/af_aphaser.c | 3 +- libavfilter/af_apsyclip.c | 2 +- libavfilter/af_apulsator.c | 31 +- libavfilter/af_aresample.c | 24 +- libavfilter/af_arls.c | 18 +- libavfilter/af_arnndn.c | 15 +- libavfilter/af_asdr.c | 2 +- libavfilter/af_asetnsamples.c | 1 - libavfilter/af_asetrate.c | 20 +- libavfilter/af_ashowinfo.c | 8 +- libavfilter/af_asoftclip.c | 1 + libavfilter/af_aspectralstats.c | 2 +- libavfilter/af_asr.c | 36 +- libavfilter/af_astats.c | 3 +- libavfilter/af_asubboost.c | 2 + libavfilter/af_asupercut.c | 1 + libavfilter/af_atempo.c | 109 +- libavfilter/af_atilt.c | 1 + libavfilter/af_axcorrelate.c | 1 - libavfilter/af_biquads.c | 18 +- libavfilter/af_bs2b.c | 21 +- libavfilter/af_channelmap.c | 117 +- libavfilter/af_channelsplit.c | 64 +- libavfilter/af_chorus.c | 3 +- libavfilter/af_compand.c | 3 +- libavfilter/af_compensationdelay.c | 2 +- libavfilter/af_crossfeed.c | 29 +- libavfilter/af_crystalizer.c | 1 + libavfilter/af_dcshift.c | 2 +- libavfilter/af_deesser.c | 2 + libavfilter/af_dialoguenhance.c | 32 +- libavfilter/af_drmeter.c | 3 +- libavfilter/af_dynaudnorm.c | 5 +- libavfilter/af_earwax.c | 32 +- libavfilter/af_extrastereo.c | 30 +- libavfilter/af_firequalizer.c | 6 +- libavfilter/af_flanger.c | 4 +- libavfilter/af_haas.c | 30 +- libavfilter/af_hdcd.c | 31 +- libavfilter/af_headphone.c | 32 +- libavfilter/af_join.c | 17 +- libavfilter/af_ladspa.c | 34 +- libavfilter/af_loudnorm.c | 23 +- libavfilter/af_lv2.c | 33 +- libavfilter/af_mcompand.c | 3 +- libavfilter/af_pan.c | 72 +- libavfilter/af_replaygain.c | 42 +- libavfilter/af_rubberband.c | 1 - libavfilter/af_sidechaincompress.c | 24 +- libavfilter/af_silencedetect.c | 3 +- libavfilter/af_silenceremove.c | 2 +- libavfilter/af_sofalizer.c | 18 +- libavfilter/af_speechnorm.c | 2 +- libavfilter/af_stereotools.c | 32 +- libavfilter/af_stereowiden.c | 31 +- libavfilter/af_superequalizer.c | 2 +- libavfilter/af_surround.c | 52 +- libavfilter/af_tremolo.c | 3 +- libavfilter/af_vibrato.c | 3 +- libavfilter/af_virtualbass.c | 29 +- libavfilter/af_volume.c | 26 +- libavfilter/af_volumedetect.c | 2 +- libavfilter/afir_template.c | 1 - libavfilter/allfilters.c | 5 + libavfilter/anlms_template.c | 16 +- libavfilter/arls_template.c | 14 +- libavfilter/asink_anullsink.c | 2 +- libavfilter/asrc_afdelaysrc.c | 2 - libavfilter/asrc_afirsrc.c | 2 +- libavfilter/asrc_anoisesrc.c | 1 - libavfilter/asrc_anullsrc.c | 1 - libavfilter/asrc_flite.c | 2 +- libavfilter/asrc_hilbert.c | 2 +- libavfilter/asrc_sinc.c | 2 +- libavfilter/asrc_sine.c | 5 +- libavfilter/audio.c | 38 +- libavfilter/audio.h | 27 +- libavfilter/avf_a3dscope.c | 6 +- libavfilter/avf_abitscope.c | 7 +- libavfilter/avf_ahistogram.c | 9 +- libavfilter/avf_aphasemeter.c | 9 +- libavfilter/avf_avectorscope.c | 6 +- libavfilter/avf_concat.c | 13 +- libavfilter/avf_showcqt.c | 5 +- libavfilter/avf_showcqt.h | 1 - libavfilter/avf_showcwt.c | 9 +- libavfilter/avf_showfreqs.c | 12 +- libavfilter/avf_showspatial.c | 9 +- libavfilter/avf_showspectrum.c | 7 +- libavfilter/avf_showvolume.c | 10 +- libavfilter/avf_showwaves.c | 13 +- libavfilter/avfilter.c | 144 +- libavfilter/avfilter.h | 153 +- libavfilter/avfilter_internal.h | 66 +- libavfilter/avfiltergraph.c | 95 +- libavfilter/blend.h | 10 +- libavfilter/blend_modes.c | 3 +- libavfilter/boxblur.c | 1 + libavfilter/buffersink.c | 24 +- libavfilter/buffersrc.c | 39 +- libavfilter/convolution.h | 2 +- libavfilter/cuda/load_helper.c | 1 + libavfilter/dialoguenhance_template.c | 2 +- libavfilter/dnn/dnn_backend_common.c | 1 + libavfilter/dnn/dnn_backend_common.h | 13 +- libavfilter/dnn/dnn_backend_openvino.c | 214 +- libavfilter/dnn/dnn_backend_tf.c | 200 +- libavfilter/dnn/dnn_backend_torch.cpp | 130 +- libavfilter/dnn/dnn_interface.c | 122 +- libavfilter/dnn/dnn_io_proc.c | 5 +- libavfilter/dnn_filter_common.c | 45 +- libavfilter/dnn_filter_common.h | 40 +- libavfilter/dnn_interface.h | 80 +- libavfilter/edge_template.c | 1 - libavfilter/f_bench.c | 2 +- libavfilter/f_cue.c | 1 - libavfilter/f_drawgraph.c | 10 +- libavfilter/f_ebur128.c | 9 +- libavfilter/f_graphmonitor.c | 39 +- libavfilter/f_interleave.c | 4 +- libavfilter/f_latency.c | 7 +- libavfilter/f_loop.c | 86 +- libavfilter/f_metadata.c | 11 +- libavfilter/f_realtime.c | 2 +- libavfilter/f_reverse.c | 3 +- libavfilter/f_segment.c | 16 +- libavfilter/f_select.c | 26 +- libavfilter/f_sendcmd.c | 8 +- libavfilter/f_sidedata.c | 12 +- libavfilter/f_streamselect.c | 11 +- libavfilter/f_zmq.c | 6 +- libavfilter/filters.h | 377 ++- libavfilter/formats.c | 206 +- libavfilter/formats.h | 84 + libavfilter/framepool.c | 13 +- libavfilter/framequeue.c | 1 + libavfilter/framesync.c | 41 +- libavfilter/framesync.h | 1 + libavfilter/graphdump.c | 3 +- libavfilter/graphparser.c | 2 +- libavfilter/hflip.h | 3 +- libavfilter/internal.h | 389 --- libavfilter/median_template.c | 1 - libavfilter/opencl.c | 11 +- libavfilter/perlin.c | 224 ++ libavfilter/perlin.h | 101 + libavfilter/phase_template.c | 1 - libavfilter/qrencode.c | 11 +- libavfilter/qsvvpp.c | 117 +- libavfilter/qsvvpp.h | 2 +- libavfilter/riscv/Makefile | 6 +- libavfilter/riscv/af_afir_init.c | 2 +- libavfilter/riscv/af_afir_rvv.S | 3 +- libavfilter/riscv/cpu_common.c | 1 + libavfilter/setpts.c | 10 +- libavfilter/settb.c | 1 - libavfilter/signature.h | 1 - libavfilter/signature_lookup.c | 4 +- libavfilter/split.c | 1 - libavfilter/src_avsynctest.c | 4 +- libavfilter/src_movie.c | 8 +- libavfilter/stack_internal.c | 12 +- libavfilter/tests/filtfmts.c | 20 +- libavfilter/tests/formats.c | 1 + libavfilter/tests/integral.c | 1 + libavfilter/textutils.c | 9 +- libavfilter/textutils.h | 4 +- libavfilter/trim.c | 2 +- libavfilter/unsharp.h | 62 - libavfilter/vaapi_vpp.c | 32 +- libavfilter/vaf_spectrumsynth.c | 15 +- libavfilter/version.c | 5 +- libavfilter/version.h | 2 +- libavfilter/vf_addroi.c | 3 +- libavfilter/vf_alphamerge.c | 5 +- libavfilter/vf_amplify.c | 3 +- libavfilter/vf_aspect.c | 2 +- libavfilter/vf_atadenoise.c | 2 +- libavfilter/vf_avgblur.c | 3 +- libavfilter/vf_avgblur_opencl.c | 12 +- libavfilter/vf_avgblur_vulkan.c | 3 +- libavfilter/vf_backgroundkey.c | 3 +- libavfilter/vf_bbox.c | 5 +- libavfilter/vf_bilateral.c | 3 +- libavfilter/vf_bilateral_cuda.c | 26 +- libavfilter/vf_bitplanenoise.c | 2 +- libavfilter/vf_blackdetect.c | 6 +- libavfilter/vf_blackframe.c | 2 +- libavfilter/vf_blend.c | 50 +- libavfilter/vf_blend_init.h | 4 +- libavfilter/vf_blend_vulkan.c | 7 +- libavfilter/vf_blockdetect.c | 9 +- libavfilter/vf_blurdetect.c | 9 +- libavfilter/vf_bm3d.c | 6 +- libavfilter/vf_boxblur.c | 4 +- libavfilter/vf_bwdif.c | 2 +- libavfilter/vf_bwdif_cuda.c | 17 +- libavfilter/vf_bwdif_vulkan.c | 16 +- libavfilter/vf_cas.c | 2 +- libavfilter/vf_ccrepack.c | 5 +- libavfilter/vf_chromaber_vulkan.c | 3 +- libavfilter/vf_chromakey.c | 2 +- libavfilter/vf_chromakey_cuda.c | 27 +- libavfilter/vf_chromanr.c | 2 +- libavfilter/vf_chromashift.c | 2 +- libavfilter/vf_ciescope.c | 2 +- libavfilter/vf_codecview.c | 5 +- libavfilter/vf_colorbalance.c | 2 +- libavfilter/vf_colorchannelmixer.c | 3 +- libavfilter/vf_colorconstancy.c | 5 +- libavfilter/vf_colorcontrast.c | 2 +- libavfilter/vf_colorcorrect.c | 3 +- libavfilter/vf_colorize.c | 2 +- libavfilter/vf_colorkey.c | 2 +- libavfilter/vf_colorkey_opencl.c | 2 +- libavfilter/vf_colorlevels.c | 2 +- libavfilter/vf_colormap.c | 6 +- libavfilter/vf_colormatrix.c | 2 +- libavfilter/vf_colorspace.c | 65 +- libavfilter/vf_colorspace_cuda.c | 27 +- libavfilter/vf_colortemperature.c | 2 +- libavfilter/vf_convolution.c | 5 +- libavfilter/vf_convolution_opencl.c | 2 +- libavfilter/vf_convolve.c | 7 +- libavfilter/vf_copy.c | 2 +- libavfilter/vf_coreimage.m | 6 +- libavfilter/vf_corr.c | 7 +- libavfilter/vf_cover_rect.c | 3 +- libavfilter/vf_crop.c | 7 +- libavfilter/vf_cropdetect.c | 3 +- libavfilter/vf_curves.c | 9 +- libavfilter/vf_datascope.c | 7 +- libavfilter/vf_dblur.c | 3 +- libavfilter/vf_dctdnoiz.c | 4 +- libavfilter/vf_deband.c | 3 +- libavfilter/vf_deblock.c | 2 +- libavfilter/vf_decimate.c | 11 +- libavfilter/vf_dedot.c | 1 - libavfilter/vf_deflicker.c | 3 +- libavfilter/vf_deinterlace_vaapi.c | 8 +- libavfilter/vf_dejudder.c | 9 +- libavfilter/vf_delogo.c | 5 +- libavfilter/vf_derain.c | 8 +- libavfilter/vf_deshake.c | 8 +- libavfilter/vf_deshake_opencl.c | 17 +- libavfilter/vf_despill.c | 2 +- libavfilter/vf_detelecine.c | 13 +- libavfilter/vf_displace.c | 6 +- libavfilter/vf_dnn_classify.c | 6 +- libavfilter/vf_dnn_detect.c | 16 +- libavfilter/vf_dnn_processing.c | 5 +- libavfilter/vf_drawbox.c | 2 +- libavfilter/vf_drawbox_vaapi.c | 369 +++ libavfilter/vf_drawtext.c | 14 +- libavfilter/vf_edgedetect.c | 3 +- libavfilter/vf_elbg.c | 3 +- libavfilter/vf_entropy.c | 3 +- libavfilter/vf_epx.c | 3 +- libavfilter/vf_eq.c | 11 +- libavfilter/vf_estdif.c | 9 +- libavfilter/vf_exposure.c | 2 +- libavfilter/vf_extractplanes.c | 1 - libavfilter/vf_fade.c | 11 +- libavfilter/vf_feedback.c | 1 - libavfilter/vf_fftdnoiz.c | 4 +- libavfilter/vf_fftfilt.c | 11 +- libavfilter/vf_field.c | 2 +- libavfilter/vf_fieldhint.c | 18 +- libavfilter/vf_fieldmatch.c | 13 +- libavfilter/vf_fieldorder.c | 2 +- libavfilter/vf_fillborders.c | 2 +- libavfilter/vf_find_rect.c | 8 +- libavfilter/vf_flip_vulkan.c | 3 +- libavfilter/vf_floodfill.c | 2 +- libavfilter/vf_format.c | 19 +- libavfilter/vf_fps.c | 13 +- libavfilter/vf_framepack.c | 19 +- libavfilter/vf_framerate.c | 4 +- libavfilter/vf_framestep.c | 15 +- libavfilter/vf_freezedetect.c | 3 +- libavfilter/vf_freezeframes.c | 13 +- libavfilter/vf_frei0r.c | 5 +- libavfilter/vf_fspp.c | 4 +- libavfilter/vf_fsync.c | 4 +- libavfilter/vf_gblur.c | 3 +- libavfilter/vf_gblur_vulkan.c | 6 +- libavfilter/vf_geq.c | 27 +- libavfilter/vf_gradfun.c | 3 +- libavfilter/vf_grayworld.c | 18 +- libavfilter/vf_guided.c | 6 +- libavfilter/vf_hflip.c | 10 +- libavfilter/vf_hflip_init.h | 1 + libavfilter/vf_histeq.c | 2 +- libavfilter/vf_histogram.c | 2 +- libavfilter/vf_hqdn3d.c | 3 +- libavfilter/vf_hqx.c | 2 +- libavfilter/vf_hsvkey.c | 2 +- libavfilter/vf_hue.c | 11 +- libavfilter/vf_huesaturation.c | 2 +- libavfilter/vf_hwdownload.c | 7 +- libavfilter/vf_hwmap.c | 23 +- libavfilter/vf_hwupload.c | 18 +- libavfilter/vf_hwupload_cuda.c | 12 +- libavfilter/vf_hysteresis.c | 7 +- libavfilter/vf_iccdetect.c | 2 +- libavfilter/vf_iccgen.c | 2 +- libavfilter/vf_identity.c | 7 +- libavfilter/vf_idet.c | 2 +- libavfilter/vf_il.c | 2 +- libavfilter/vf_kerndeint.c | 3 +- libavfilter/vf_lagfun.c | 3 +- libavfilter/vf_lcevc.c | 430 +++ libavfilter/vf_lenscorrection.c | 4 +- libavfilter/vf_lensfun.c | 2 +- libavfilter/vf_libopencv.c | 3 +- libavfilter/vf_libplacebo.c | 28 +- libavfilter/vf_libvmaf.c | 13 +- libavfilter/vf_limitdiff.c | 6 +- libavfilter/vf_limiter.c | 2 +- libavfilter/vf_lumakey.c | 2 +- libavfilter/vf_lut.c | 3 +- libavfilter/vf_lut2.c | 8 +- libavfilter/vf_lut3d.c | 11 +- libavfilter/vf_maskedclamp.c | 6 +- libavfilter/vf_maskedmerge.c | 6 +- libavfilter/vf_maskedminmax.c | 6 +- libavfilter/vf_maskedthreshold.c | 6 +- libavfilter/vf_maskfun.c | 2 +- libavfilter/vf_mcdeint.c | 2 +- libavfilter/vf_median.c | 3 +- libavfilter/vf_mergeplanes.c | 6 +- libavfilter/vf_mestimate.c | 3 +- libavfilter/vf_midequalizer.c | 7 +- libavfilter/vf_minterpolate.c | 6 +- libavfilter/vf_misc_vaapi.c | 2 +- libavfilter/vf_mix.c | 9 +- libavfilter/vf_monochrome.c | 2 +- libavfilter/vf_morpho.c | 7 +- libavfilter/vf_mpdecimate.c | 2 +- libavfilter/vf_multiply.c | 6 +- libavfilter/vf_negate.c | 2 +- libavfilter/vf_neighbor.c | 2 +- libavfilter/vf_neighbor_opencl.c | 6 +- libavfilter/vf_nlmeans.c | 3 +- libavfilter/vf_nlmeans_opencl.c | 2 +- libavfilter/vf_nlmeans_vulkan.c | 58 +- libavfilter/vf_nnedi.c | 14 +- libavfilter/vf_noise.c | 4 +- libavfilter/vf_normalize.c | 3 +- libavfilter/vf_null.c | 2 +- libavfilter/vf_ocr.c | 2 +- libavfilter/vf_overlay.c | 5 +- libavfilter/vf_overlay_cuda.c | 15 +- libavfilter/vf_overlay_opencl.c | 2 +- libavfilter/vf_overlay_qsv.c | 29 +- libavfilter/vf_overlay_vaapi.c | 5 +- libavfilter/vf_overlay_vulkan.c | 3 +- libavfilter/vf_owdenoise.c | 3 +- libavfilter/vf_pad.c | 2 +- libavfilter/vf_pad_opencl.c | 2 +- libavfilter/vf_pad_vaapi.c | 283 ++ libavfilter/vf_palettegen.c | 3 +- libavfilter/vf_paletteuse.c | 2 +- libavfilter/vf_perspective.c | 9 +- libavfilter/vf_phase.c | 2 +- libavfilter/vf_photosensitivity.c | 1 - libavfilter/vf_pixdesctest.c | 3 +- libavfilter/vf_pixelize.c | 2 +- libavfilter/vf_pp.c | 3 +- libavfilter/vf_pp7.c | 4 +- libavfilter/vf_premultiply.c | 5 +- libavfilter/vf_procamp_vaapi.c | 2 +- libavfilter/vf_program_opencl.c | 2 +- libavfilter/vf_pseudocolor.c | 2 +- libavfilter/vf_psnr.c | 11 +- libavfilter/vf_pullup.c | 3 +- libavfilter/vf_qp.c | 2 +- libavfilter/vf_quirc.c | 4 +- libavfilter/vf_random.c | 2 +- libavfilter/vf_readeia608.c | 3 +- libavfilter/vf_readvitc.c | 2 +- libavfilter/vf_remap.c | 6 +- libavfilter/vf_remap_opencl.c | 6 +- libavfilter/vf_removegrain.c | 2 +- libavfilter/vf_removelogo.c | 3 +- libavfilter/vf_repeatfields.c | 5 +- libavfilter/vf_rotate.c | 5 +- libavfilter/vf_sab.c | 3 +- libavfilter/vf_scale.c | 371 ++- libavfilter/vf_scale_cuda.c | 28 +- libavfilter/vf_scale_npp.c | 34 +- libavfilter/vf_scale_vaapi.c | 2 +- libavfilter/vf_scale_vt.c | 16 +- libavfilter/vf_scale_vulkan.c | 2 +- libavfilter/vf_scdet.c | 4 +- libavfilter/vf_scroll.c | 2 +- libavfilter/vf_selectivecolor.c | 2 +- libavfilter/vf_separatefields.c | 7 +- libavfilter/vf_setparams.c | 134 +- libavfilter/vf_sharpen_npp.c | 20 +- libavfilter/vf_shear.c | 2 +- libavfilter/vf_showinfo.c | 61 +- libavfilter/vf_showpalette.c | 2 +- libavfilter/vf_shuffleframes.c | 3 +- libavfilter/vf_shufflepixels.c | 4 +- libavfilter/vf_shuffleplanes.c | 2 +- libavfilter/vf_signalstats.c | 420 +-- libavfilter/vf_signature.c | 15 +- libavfilter/vf_siti.c | 3 +- libavfilter/vf_smartblur.c | 45 +- libavfilter/vf_spp.c | 8 +- libavfilter/vf_sr.c | 8 +- libavfilter/vf_ssim.c | 26 +- libavfilter/vf_ssim360.c | 30 +- libavfilter/vf_stack.c | 17 +- libavfilter/vf_stack_qsv.c | 21 +- libavfilter/vf_stack_vaapi.c | 11 +- libavfilter/vf_stereo3d.c | 8 +- libavfilter/vf_subtitles.c | 7 +- libavfilter/vf_super2xsai.c | 2 +- libavfilter/vf_swaprect.c | 7 +- libavfilter/vf_swapuv.c | 15 +- libavfilter/vf_telecine.c | 14 +- libavfilter/vf_threshold.c | 6 +- libavfilter/vf_thumbnail.c | 3 +- libavfilter/vf_thumbnail_cuda.c | 13 +- libavfilter/vf_tile.c | 7 +- libavfilter/vf_tiltandshift.c | 6 +- libavfilter/vf_tinterlace.c | 23 +- libavfilter/vf_tmidequalizer.c | 3 +- libavfilter/vf_tonemap.c | 2 +- libavfilter/vf_tonemap_opencl.c | 6 +- libavfilter/vf_tonemap_vaapi.c | 192 +- libavfilter/vf_tpad.c | 13 +- libavfilter/vf_transpose.c | 2 +- libavfilter/vf_transpose_npp.c | 25 +- libavfilter/vf_transpose_opencl.c | 10 +- libavfilter/vf_transpose_vaapi.c | 8 +- libavfilter/vf_transpose_vt.c | 22 +- libavfilter/vf_transpose_vulkan.c | 9 +- libavfilter/vf_unsharp.c | 41 +- libavfilter/vf_unsharp_opencl.c | 4 +- libavfilter/vf_untile.c | 8 +- libavfilter/vf_uspp.c | 4 +- libavfilter/vf_v360.c | 12 +- libavfilter/vf_vaguedenoiser.c | 3 +- libavfilter/vf_varblur.c | 7 +- libavfilter/vf_vectorscope.c | 4 +- libavfilter/vf_vflip.c | 11 +- libavfilter/vf_vfrdet.c | 3 +- libavfilter/vf_vibrance.c | 2 +- libavfilter/vf_vidstabdetect.c | 1 - libavfilter/vf_vidstabtransform.c | 2 +- libavfilter/vf_vif.c | 7 +- libavfilter/vf_vignette.c | 11 +- libavfilter/vf_vmafmotion.c | 12 +- libavfilter/vf_vpp_qsv.c | 34 +- libavfilter/vf_w3fdif.c | 7 +- libavfilter/vf_waveform.c | 4 +- libavfilter/vf_weave.c | 11 +- libavfilter/vf_xbr.c | 3 +- libavfilter/vf_xfade.c | 26 +- libavfilter/vf_xfade_opencl.c | 19 +- libavfilter/vf_xfade_vulkan.c | 5 +- libavfilter/vf_xmedian.c | 19 +- libavfilter/vf_xpsnr.c | 759 +++++ libavfilter/vf_yadif.c | 2 +- libavfilter/vf_yadif_cuda.c | 17 +- libavfilter/vf_yadif_videotoolbox.m | 22 +- libavfilter/vf_yaepblur.c | 3 +- libavfilter/vf_zoompan.c | 13 +- libavfilter/vf_zscale.c | 48 +- libavfilter/video.c | 22 +- libavfilter/video.h | 13 +- libavfilter/vidstabutils.c | 1 + libavfilter/vsink_nullsink.c | 2 +- libavfilter/vsrc_cellauto.c | 6 +- libavfilter/vsrc_ddagrab.c | 10 +- libavfilter/vsrc_gradients.c | 4 +- libavfilter/vsrc_life.c | 7 +- libavfilter/vsrc_mandelbrot.c | 6 +- libavfilter/vsrc_mptestsrc.c | 10 +- libavfilter/vsrc_perlin.c | 170 + libavfilter/vsrc_sierpinski.c | 5 +- libavfilter/vsrc_testsrc.c | 29 +- libavfilter/vsrc_testsrc_vulkan.c | 8 +- libavfilter/vulkan_filter.c | 188 +- libavfilter/vulkan_shaderc.c | 4 + libavfilter/x86/Makefile | 5 + libavfilter/x86/vf_blend_init.c | 2 +- libavfilter/x86/vf_gblur_init.c | 1 + libavfilter/x86/vf_xpsnr_init.c | 43 + libavfilter/xpsnr.h | 48 + libavfilter/yadif_common.c | 10 +- libavformat/4xm.c | 1 + libavformat/Makefile | 21 +- libavformat/aacdec.c | 14 +- libavformat/aadec.c | 1 + libavformat/aaxdec.c | 1 + libavformat/aiffdec.c | 1 + libavformat/allformats.c | 7 +- libavformat/ape.c | 1 + libavformat/apetag.c | 4 +- libavformat/apngdec.c | 1 + libavformat/apngenc.c | 1 + libavformat/argo_brp.c | 4 +- libavformat/asf.c | 5 +- libavformat/asfdec_f.c | 1 + libavformat/asfdec_o.c | 1 + libavformat/asfenc.c | 1 + libavformat/assenc.c | 1 + libavformat/async.c | 22 +- libavformat/au.c | 1 + libavformat/av1.c | 1 + libavformat/av1dec.c | 1 + libavformat/avc.c | 166 +- libavformat/avc.h | 37 - libavformat/avformat.c | 7 + libavformat/avformat.h | 66 +- libavformat/avidec.c | 1 + libavformat/avienc.c | 2 +- libavformat/avio.c | 1 + libavformat/aviobuf.c | 1 + libavformat/avisynth.c | 203 +- libavformat/bethsoftvid.c | 1 + libavformat/bitstream.c | 1 - libavformat/bmv.c | 1 + libavformat/brstm.c | 1 + libavformat/cache.c | 19 +- libavformat/cafdec.c | 1 + libavformat/cafenc.c | 1 + libavformat/chromaprint.c | 12 +- libavformat/cinedec.c | 1 + libavformat/concatdec.c | 1 + libavformat/crypto.c | 5 +- libavformat/dashdec.c | 33 +- libavformat/dashenc.c | 5 +- libavformat/data_uri.c | 1 + libavformat/demux.c | 36 +- libavformat/demux_utils.c | 2 +- libavformat/dhav.c | 10 +- libavformat/dovi_isom.c | 20 +- libavformat/dss.c | 1 + libavformat/dtshddec.c | 1 + libavformat/dump.c | 78 +- libavformat/dv.c | 1 + libavformat/dvdvideodec.c | 540 ++-- libavformat/dxa.c | 2 + libavformat/electronicarts.c | 13 +- libavformat/evc.c | 23 +- libavformat/ffmetadec.c | 1 + libavformat/file.c | 24 +- libavformat/fitsenc.c | 2 +- libavformat/flac_picture.c | 4 +- libavformat/flacdec.c | 1 + libavformat/flvdec.c | 3 +- libavformat/flvenc.c | 4 +- libavformat/format.c | 3 +- libavformat/ftp.c | 1 + libavformat/gifdec.c | 5 +- libavformat/gxfenc.c | 1 + libavformat/hashenc.c | 1 + libavformat/hdsenc.c | 1 + libavformat/hevc.c | 550 ++-- libavformat/hevc.h | 20 +- libavformat/hevcdec.c | 2 +- libavformat/hls.c | 62 +- libavformat/hls_sample_encryption.c | 1 + libavformat/hlsenc.c | 95 +- libavformat/hlsplaylist.c | 3 + libavformat/hlsplaylist.h | 1 + libavformat/hlsproto.c | 1 + libavformat/http.c | 137 +- libavformat/httpauth.c | 1 + libavformat/iamf_parse.c | 127 +- libavformat/iamf_reader.c | 28 +- libavformat/iamf_writer.c | 36 +- libavformat/icecast.c | 2 +- libavformat/icodec.c | 3 +- libavformat/icoenc.c | 2 +- libavformat/id3v2.c | 1 + libavformat/iff.c | 4 + libavformat/ilbc.c | 3 +- libavformat/imf_cpl.c | 2 +- libavformat/imfdec.c | 2 +- libavformat/img2.c | 148 +- libavformat/img2.h | 2 +- libavformat/img2dec.c | 3 +- libavformat/img2enc.c | 8 +- libavformat/internal.h | 21 +- libavformat/ipfsgateway.c | 1 + libavformat/ipmovie.c | 3 +- libavformat/isom.c | 26 +- libavformat/isom.h | 13 +- libavformat/isom_tags.c | 2 + libavformat/ivfenc.c | 4 +- libavformat/jpegxl_anim_dec.c | 4 +- libavformat/jvdec.c | 1 + libavformat/lafdec.c | 1 + libavformat/lc3.c | 244 ++ libavformat/libamqp.c | 3 +- libavformat/libgme.c | 3 +- libavformat/libmodplug.c | 1 + libavformat/libopenmpt.c | 2 +- libavformat/libsmbclient.c | 1 + libavformat/libsrt.c | 1 + libavformat/libssh.c | 7 +- libavformat/libzmq.c | 2 +- libavformat/lmlm4.c | 8 +- libavformat/lrc.c | 2 +- libavformat/lrcdec.c | 2 +- libavformat/lrcenc.c | 2 +- libavformat/matroskadec.c | 97 +- libavformat/matroskaenc.c | 110 +- libavformat/mccdec.c | 4 +- libavformat/mlvdec.c | 21 +- libavformat/mms.c | 1 + libavformat/mmsh.c | 3 +- libavformat/mmst.c | 2 +- libavformat/mov.c | 1034 +++++- libavformat/mov_chan.c | 634 ++-- libavformat/mov_chan.h | 7 +- libavformat/movenc.c | 609 +++- libavformat/movenc.h | 4 +- libavformat/movenc_ttml.c | 1 + libavformat/movenccenc.c | 6 +- libavformat/movenchint.c | 1 + libavformat/mp3enc.c | 1 + libavformat/mpc.c | 3 +- libavformat/mpc8.c | 1 + libavformat/mpeg.c | 5 +- libavformat/mpegenc.c | 1 + libavformat/mpegts.c | 18 +- libavformat/mpegtsenc.c | 3 +- libavformat/mpjpegdec.c | 1 + libavformat/mtv.c | 2 +- libavformat/mux.c | 1 + libavformat/mvdec.c | 4 +- libavformat/mxfdec.c | 106 +- libavformat/mxfenc.c | 12 +- libavformat/mxg.c | 1 + libavformat/nal.c | 190 ++ libavformat/nal.h | 67 + libavformat/network.c | 30 +- libavformat/nistspheredec.c | 2 +- libavformat/nsvdec.c | 1 + libavformat/nut.c | 1 + libavformat/nutdec.c | 15 +- libavformat/nutenc.c | 1 + libavformat/nuv.c | 4 +- libavformat/oggdec.c | 5 +- libavformat/oggenc.c | 3 +- libavformat/oggparsecelt.c | 1 + libavformat/oggparsedirac.c | 1 + libavformat/oggparseopus.c | 1 + libavformat/oggparsespeex.c | 1 + libavformat/oggparsetheora.c | 2 +- libavformat/oggparsevorbis.c | 1 + libavformat/omadec.c | 1 + libavformat/options.c | 35 +- libavformat/options_table.h | 1 + libavformat/os_support.c | 1 + libavformat/os_support.h | 1 + libavformat/paf.c | 1 + libavformat/pcmdec.c | 1 + libavformat/pdvdec.c | 1 + libavformat/pmpdec.c | 1 + libavformat/pp_bnk.c | 1 + libavformat/prompeg.c | 3 +- libavformat/qcp.c | 3 +- libavformat/qoadec.c | 5 +- libavformat/rcwtdec.c | 122 + libavformat/rcwtenc.c | 6 - libavformat/rdt.c | 1 + libavformat/realtextdec.c | 2 +- libavformat/riff.c | 3 +- libavformat/riffdec.c | 1 + libavformat/riffenc.c | 2 +- libavformat/riscv/Makefile | 1 + libavformat/riscv/cpu_common.c | 1 + libavformat/rl2.c | 1 + libavformat/rmdec.c | 4 +- libavformat/rpl.c | 6 +- libavformat/rtmphttp.c | 3 +- libavformat/rtmppkt.c | 3 +- libavformat/rtmpproto.c | 5 +- libavformat/rtpdec.c | 1 + libavformat/rtpdec_asf.c | 1 + libavformat/rtpdec_h264.c | 1 + libavformat/rtpdec_hevc.c | 1 + libavformat/rtpdec_latm.c | 1 + libavformat/rtpdec_mpa_robust.c | 1 + libavformat/rtpdec_mpeg4.c | 1 + libavformat/rtpdec_qt.c | 1 + libavformat/rtpdec_rfc4175.c | 1 + libavformat/rtpdec_xiph.c | 1 + libavformat/rtpenc.c | 1 + libavformat/rtpenc_h264_hevc.c | 9 +- libavformat/rtpenc_mpegts.c | 1 + libavformat/rtpproto.c | 3 +- libavformat/rtsp.c | 6 +- libavformat/rtspdec.c | 1 + libavformat/rtspenc.c | 1 + libavformat/sapdec.c | 1 + libavformat/sapenc.c | 1 + libavformat/sauce.c | 2 +- libavformat/sbgdec.c | 1 + libavformat/scd.c | 6 +- libavformat/sdp.c | 6 +- libavformat/seek.c | 1 + libavformat/segafilm.c | 3 +- libavformat/segment.c | 1 + libavformat/sierravmd.c | 1 + libavformat/smacker.c | 1 + libavformat/smjpegdec.c | 2 +- libavformat/smoothstreamingenc.c | 5 +- libavformat/soxdec.c | 1 + libavformat/spdifdec.c | 2 + libavformat/spdifenc.c | 1 + libavformat/srtp.c | 1 + libavformat/srtpproto.c | 6 +- libavformat/subtitles.c | 24 +- libavformat/subtitles.h | 2 +- libavformat/swfdec.c | 1 + libavformat/takdec.c | 1 + libavformat/tcp.c | 2 +- libavformat/tee.c | 83 +- libavformat/tests/movenc.c | 67 +- libavformat/tiertexseq.c | 1 + libavformat/tls.c | 3 +- libavformat/tls_gnutls.c | 16 +- libavformat/tls_mbedtls.c | 55 +- libavformat/tls_openssl.c | 50 +- libavformat/tls_schannel.c | 16 +- libavformat/tls_securetransport.c | 1 + libavformat/ty.c | 1 + libavformat/udp.c | 2 +- libavformat/usmdec.c | 1 + libavformat/utils.c | 25 +- libavformat/vapoursynth.c | 139 +- libavformat/version.c | 5 +- libavformat/version.h | 2 +- libavformat/version_major.h | 1 + libavformat/vividas.c | 4 +- libavformat/vqf.c | 23 +- libavformat/vvc.c | 284 +- libavformat/wavdec.c | 8 +- libavformat/wavenc.c | 1 + libavformat/wc3movie.c | 1 + libavformat/webm_chunk.c | 1 + libavformat/webmdashenc.c | 1 + libavformat/westwood_vqa.c | 4 +- libavformat/wsddec.c | 2 +- libavformat/wtvdec.c | 8 +- libavformat/wtvenc.c | 1 + libavformat/wvdec.c | 2 +- libavformat/xmv.c | 1 + libavformat/xwma.c | 1 + libavutil/aarch64/cpu.c | 31 +- libavutil/aarch64/intreadwrite.h | 42 + libavutil/aarch64/timer.h | 17 +- libavutil/ambient_viewing_environment.c | 10 + libavutil/arm/bswap.h | 20 - libavutil/arm/cpu.c | 2 +- libavutil/arm/intreadwrite.h | 91 - libavutil/avr32/intreadwrite.h | 182 -- libavutil/avsscanf.c | 1 - libavutil/avstring.c | 6 +- libavutil/bswap.h | 8 +- libavutil/channel_layout.c | 22 +- libavutil/channel_layout.h | 18 + libavutil/common.h | 38 +- libavutil/cpu.c | 35 +- libavutil/cpu.h | 8 + libavutil/cpu_internal.h | 2 + libavutil/detection_bbox.c | 1 + libavutil/dovi_meta.c | 22 +- libavutil/dovi_meta.h | 160 + libavutil/downmix_info.c | 5 +- libavutil/error.c | 1 + libavutil/error.h | 1 + libavutil/eval.c | 3 +- libavutil/executor.c | 48 +- libavutil/executor.h | 2 +- libavutil/fifo.h | 4 - libavutil/file.c | 10 +- libavutil/file.h | 1 - libavutil/file_open.c | 8 +- libavutil/film_grain_params.c | 1 + libavutil/fixed_dsp.c | 1 + libavutil/float_dsp.c | 12 + libavutil/float_dsp.h | 31 +- libavutil/frame.c | 161 +- libavutil/frame.h | 114 +- libavutil/hwcontext_d3d11va.c | 1 + libavutil/hwcontext_d3d12va.c | 3 +- libavutil/hwcontext_d3d12va.h | 8 + libavutil/hwcontext_drm.c | 1 + libavutil/hwcontext_dxva2.c | 1 + libavutil/hwcontext_qsv.c | 366 ++- libavutil/hwcontext_qsv.h | 27 +- libavutil/hwcontext_vaapi.c | 41 + libavutil/hwcontext_videotoolbox.c | 130 +- libavutil/hwcontext_videotoolbox.h | 11 +- libavutil/hwcontext_vulkan.c | 1503 ++++++--- libavutil/hwcontext_vulkan.h | 43 +- libavutil/iamf.c | 20 +- libavutil/iamf.h | 12 +- libavutil/imgutils.c | 2 +- libavutil/imgutils_internal.h | 4 + libavutil/internal.h | 16 +- libavutil/intmath.h | 4 +- libavutil/intreadwrite.h | 45 +- libavutil/lls.c | 13 +- libavutil/lls.h | 1 + libavutil/loongarch/cpu.c | 2 +- libavutil/macos_kperf.c | 16 +- libavutil/mastering_display_metadata.c | 29 +- libavutil/mastering_display_metadata.h | 9 + libavutil/mem.c | 4 +- libavutil/mips/cpu.c | 2 +- libavutil/opt.c | 458 ++- libavutil/opt.h | 195 +- libavutil/pca.c | 1 + libavutil/pixdesc.c | 3 + libavutil/pixfmt.h | 3 + libavutil/ppc/cpu.c | 42 +- libavutil/random_seed.c | 6 +- libavutil/riscv/Makefile | 7 +- libavutil/riscv/asm.S | 227 +- libavutil/riscv/bswap.h | 44 +- libavutil/riscv/bswap_rvb.S | 10 +- libavutil/riscv/cpu.c | 97 +- libavutil/riscv/cpu.h | 35 + .../riscv/cpu_common.c | 28 +- libavutil/riscv/fixed_dsp_init.c | 2 +- libavutil/riscv/fixed_dsp_rvv.S | 20 +- libavutil/riscv/float_dsp_init.c | 5 +- libavutil/riscv/float_dsp_rvv.S | 55 +- libavutil/riscv/intmath.h | 197 +- libavutil/riscv/lls_init.c | 56 + libavutil/riscv/lls_rvv.S | 39 + libavutil/spherical.c | 5 + libavutil/spherical.h | 16 + libavutil/stereo3d.c | 77 +- libavutil/stereo3d.h | 96 + libavutil/tests/cpu.c | 8 +- libavutil/tests/dict.c | 2 + libavutil/tests/imgutils.c | 1 + libavutil/tests/lfg.c | 1 + libavutil/tests/opt.c | 183 +- libavutil/tests/side_data_array.c | 52 +- libavutil/tests/tea.c | 1 + libavutil/tests/tree.c | 1 + libavutil/timecode.c | 4 +- libavutil/timer.h | 17 +- libavutil/tx.c | 1 + libavutil/tx_template.c | 2 + libavutil/version.c | 12 +- libavutil/version.h | 5 +- libavutil/vulkan.c | 830 +++-- libavutil/vulkan.h | 124 +- libavutil/vulkan_functions.h | 31 +- libavutil/vulkan_loader.h | 7 + libavutil/wchar_filename.h | 2 +- libavutil/x86/bswap.h | 13 +- libavutil/x86/float_dsp.asm | 52 + libavutil/x86/float_dsp_init.c | 5 + libavutil/x86/intmath.h | 20 +- libavutil/x86/intreadwrite.h | 37 +- libavutil/x86/tx_float_init.c | 1 + libpostproc/postprocess.c | 17 +- libpostproc/postprocess_template.c | 5 +- libpostproc/version.c | 5 +- libpostproc/version.h | 2 +- libswresample/arm/resample.S | 8 +- libswresample/audioconvert.c | 2 +- libswresample/dither.c | 1 + libswresample/options.c | 1 + libswresample/rematrix.c | 1 + libswresample/resample.c | 2 +- libswresample/swresample.c | 1 + libswresample/swresample.h | 4 +- libswresample/version.c | 5 +- libswresample/version.h | 2 +- libswresample/x86/rematrix_init.c | 1 + libswscale/aarch64/Makefile | 3 + libswscale/aarch64/input.S | 315 ++ libswscale/aarch64/range_convert_neon.S | 99 + libswscale/aarch64/rgb2rgb.c | 29 + libswscale/aarch64/rgb2rgb_neon.S | 219 ++ libswscale/aarch64/swscale.c | 85 + libswscale/aarch64/swscale_unscaled.c | 88 + libswscale/aarch64/swscale_unscaled_neon.S | 70 + libswscale/aarch64/yuv2rgb_neon.S | 73 +- libswscale/arm/hscale.S | 3 +- libswscale/arm/output.S | 3 +- libswscale/arm/yuv2rgb_neon.S | 7 +- libswscale/gamma.c | 1 + libswscale/hscale.c | 1 + libswscale/loongarch/Makefile | 1 + libswscale/loongarch/input.S | 495 +++ libswscale/loongarch/input_lasx.c | 43 + libswscale/loongarch/input_lsx.c | 65 + libswscale/loongarch/output.S | 254 +- libswscale/loongarch/output_lasx.c | 23 +- libswscale/loongarch/output_lsx.c | 22 +- libswscale/loongarch/swscale.S | 368 +++ libswscale/loongarch/swscale_init_loongarch.c | 67 +- libswscale/loongarch/swscale_loongarch.h | 84 +- libswscale/options.c | 8 +- libswscale/output.c | 75 +- libswscale/ppc/swscale_altivec.c | 26 +- libswscale/ppc/swscale_ppc_template.c | 171 +- libswscale/rgb2rgb.h | 2 - libswscale/rgb2rgb_template.c | 83 +- libswscale/riscv/Makefile | 9 +- libswscale/riscv/cpu_common.c | 1 + libswscale/riscv/input_rvv.S | 321 ++ libswscale/riscv/range_rvv.S | 118 + libswscale/riscv/rgb2rgb.c | 14 +- libswscale/riscv/rgb2rgb_rvb.S | 2 +- libswscale/riscv/rgb2rgb_rvv.S | 19 +- libswscale/riscv/swscale.c | 126 + libswscale/slice.c | 3 +- libswscale/swscale.c | 5 +- libswscale/swscale.h | 28 +- libswscale/swscale_internal.h | 57 +- libswscale/swscale_unscaled.c | 85 +- libswscale/utils.c | 101 +- libswscale/version.c | 5 +- libswscale/version.h | 2 +- libswscale/vscale.c | 1 + libswscale/x86/Makefile | 1 + libswscale/x86/input.asm | 214 +- libswscale/x86/range_convert.asm | 136 + libswscale/x86/rgb2rgb.c | 2321 +++++++++++++- libswscale/x86/rgb2rgb_template.c | 2453 -------------- libswscale/x86/rgb_2_rgb.asm | 98 +- libswscale/x86/swscale.c | 52 +- libswscale/x86/swscale_template.c | 20 - libswscale/x86/yuv2rgb.c | 251 +- libswscale/x86/yuv2rgb_template.c | 196 -- libswscale/x86/yuv_2_rgb.asm | 123 +- libswscale/yuv2rgb.c | 1027 +++--- tests/Makefile | 1 + tests/api/api-band-test.c | 15 +- tests/api/api-flac-test.c | 1 + tests/api/api-h264-slice-test.c | 1 + tests/api/api-h264-test.c | 1 + tests/api/api-seek-test.c | 1 + tests/api/api-threadmessage-test.c | 1 + tests/audiogen.c | 2 +- tests/checkasm/Makefile | 9 +- tests/checkasm/aacencdsp.c | 37 + tests/checkasm/ac3dsp.c | 133 + tests/checkasm/av_tx.c | 1 + tests/checkasm/blockdsp.c | 25 + tests/checkasm/checkasm.c | 177 +- tests/checkasm/checkasm.h | 16 +- tests/checkasm/fdctdsp.c | 71 + tests/checkasm/flacdsp.c | 104 +- tests/checkasm/float_dsp.c | 20 + tests/checkasm/h263dsp.c | 62 + tests/checkasm/h264chroma.c | 34 +- tests/checkasm/h264dsp.c | 57 +- tests/checkasm/hevc_add_res.c | 4 +- tests/checkasm/hevc_deblock.c | 8 +- tests/checkasm/hevc_idct.c | 2 +- tests/checkasm/hevc_pel.c | 30 +- tests/checkasm/hevc_sao.c | 10 +- tests/checkasm/huffyuvdsp.c | 2 +- tests/checkasm/llauddsp.c | 4 +- tests/checkasm/lls.c | 105 + tests/checkasm/llviddsp.c | 22 +- tests/checkasm/lpc.c | 55 +- tests/checkasm/motion.c | 13 +- tests/checkasm/mpegvideoencdsp.c | 147 + tests/checkasm/opusdsp.c | 11 +- tests/checkasm/riscv/checkasm.S | 17 +- tests/checkasm/rv40dsp.c | 75 + tests/checkasm/svq1enc.c | 5 +- tests/checkasm/sw_gbrp.c | 40 +- tests/checkasm/sw_range_convert.c | 134 + tests/checkasm/sw_rgb.c | 303 +- tests/checkasm/sw_scale.c | 1 + tests/checkasm/sw_yuv2rgb.c | 239 ++ tests/checkasm/sw_yuv2yuv.c | 133 + tests/checkasm/vc1dsp.c | 38 + tests/checkasm/vf_blend.c | 3 +- tests/checkasm/vf_bwdif.c | 6 +- tests/checkasm/vf_colorspace.c | 8 +- tests/checkasm/vf_gblur.c | 1 + tests/checkasm/vf_nlmeans.c | 1 + tests/checkasm/vp8dsp.c | 116 +- tests/checkasm/vvc_alf.c | 199 ++ tests/checkasm/vvc_mc.c | 173 +- tests/fate-run.sh | 4 +- tests/fate.sh | 6 +- tests/fate/aac.mak | 8 + tests/fate/api.mak | 2 +- tests/fate/audio.mak | 7 +- tests/fate/cbs.mak | 8 +- tests/fate/checkasm.mak | 9 + tests/fate/demux.mak | 2 +- tests/fate/ffmpeg.mak | 8 +- tests/fate/ffprobe.mak | 40 +- tests/fate/filter-audio.mak | 10 + tests/fate/filter-video.mak | 22 +- tests/fate/fits.mak | 2 +- tests/fate/h264.mak | 6 +- tests/fate/hevc.mak | 43 +- tests/fate/iamf.mak | 19 +- tests/fate/image.mak | 156 +- tests/fate/jpeg2000.mak | 3 + tests/fate/lavf-container.mak | 11 +- tests/fate/libavcodec.mak | 2 +- tests/fate/libswscale.mak | 9 +- tests/fate/matroska.mak | 2 +- tests/fate/mov.mak | 43 +- tests/fate/seek.mak | 8 +- tests/fate/source-check.sh | 2 +- tests/fate/vcodec.mak | 5 +- tests/fate/video.mak | 2 +- tests/fate/vvc.mak | 5 +- tests/fate/wavpack.mak | 3 + tests/filtergraphs/crazychannels | 79 + tests/filtergraphs/scale2ref_keep_aspect | 3 +- tests/ref/fate/aic | 32 +- tests/ref/fate/cavs-demux | 2 +- .../ref/fate/concat-demuxer-extended-lavf-mxf | 2 +- .../fate/concat-demuxer-extended-lavf-mxf_d10 | 2 +- .../ref/fate/concat-demuxer-simple1-lavf-mxf | 4 +- .../fate/concat-demuxer-simple1-lavf-mxf_d10 | 4 +- tests/ref/fate/concat-demuxer-simple2-lavf-ts | 4 +- tests/ref/fate/copy-trac236 | 16 +- tests/ref/fate/copy-trac4914-avi | 4 +- tests/ref/fate/enhanced-flv-hevc | 4 +- tests/ref/fate/exif-image-tiff | 2 +- tests/ref/fate/ffmpeg-spec-disposition | 7 + tests/ref/fate/ffprobe_compact | 6 +- tests/ref/fate/ffprobe_csv | 6 +- tests/ref/fate/ffprobe_default | 3 + tests/ref/fate/ffprobe_flat | 3 + tests/ref/fate/ffprobe_ini | 3 + tests/ref/fate/ffprobe_json | 9 +- tests/ref/fate/ffprobe_xml | 6 +- tests/ref/fate/ffprobe_xsd | 6 +- tests/ref/fate/filter-atempo | 70 + tests/ref/fate/filter-crazychannels | 396 +++ tests/ref/fate/filter-pixfmts-copy | 4 +- tests/ref/fate/filter-pixfmts-crop | 4 +- tests/ref/fate/filter-pixfmts-field | 4 +- tests/ref/fate/filter-pixfmts-fieldorder | 4 +- tests/ref/fate/filter-pixfmts-hflip | 4 +- tests/ref/fate/filter-pixfmts-il | 4 +- tests/ref/fate/filter-pixfmts-null | 4 +- tests/ref/fate/filter-pixfmts-pad | 2 +- tests/ref/fate/filter-pixfmts-scale | 4 +- tests/ref/fate/filter-pixfmts-transpose | 4 +- tests/ref/fate/filter-pixfmts-vflip | 4 +- tests/ref/fate/filter-refcmp-xpsnr-rgb | 20 + tests/ref/fate/filter-refcmp-xpsnr-yuv | 20 + tests/ref/fate/filter-scalechroma | 50 +- tests/ref/fate/filter-tiltandshift-410 | 55 + tests/ref/fate/filter-tiltandshift-422 | 55 + tests/ref/fate/filter-tiltandshift-444 | 55 + tests/ref/fate/fitsdec-gbrap16be | 2 +- tests/ref/fate/flv-demux | 4 +- tests/ref/fate/gapless-mp3-side-data | 2 +- tests/ref/fate/h264-bsf-dts2pts | 58 + tests/ref/fate/h264-bsf-mp4toannexb | 2 +- tests/ref/fate/h264_mp4toannexb_ticket2991 | 18 +- ...hapqa-extract-nosnappy-to-hapalphaonly-mov | 1 + .../fate/hapqa-extract-nosnappy-to-hapq-mov | 1 + tests/ref/fate/hevc-afd-tc-sei | 36 + tests/ref/fate/hevc-conformance-MVHEVCS_A | 106 + tests/ref/fate/hevc-conformance-MVHEVCS_B | 138 + tests/ref/fate/hevc-conformance-MVHEVCS_E | 106 + tests/ref/fate/hevc-conformance-MVHEVCS_F | 106 + tests/ref/fate/hevc-mv-nuh-layer-id | 15 + tests/ref/fate/hevc-mv-position | 32 + tests/ref/fate/hevc-mv-switch | 172 + tests/ref/fate/hevc-pir | 15 + tests/ref/fate/iamf-5_1-copy | 313 ++ tests/ref/fate/iamf-5_1-demux | 313 ++ tests/ref/fate/iamf-5_1_4 | 12 + tests/ref/fate/iamf-7_1_4 | 14 + tests/ref/fate/iamf-ambisonic_1 | 8 + tests/ref/fate/iamf-stereo | 2 + tests/ref/fate/iamf-stereo-demux | 119 + tests/ref/fate/jpeg2000dec-ds0_ht_01_b11 | 2 +- tests/ref/fate/jpeg2000dec-p0_10 | 6 + tests/ref/fate/jpg-12bpp | 2 +- tests/ref/fate/jv-demux | 14 +- tests/ref/fate/matroska-alac-remux | 1 + tests/ref/fate/matroska-dovi-write-config7 | 1 + tests/ref/fate/matroska-dovi-write-config8 | 5 +- tests/ref/fate/matroska-mpegts-remux | 2 + tests/ref/fate/matroska-side-data-pref-codec | 1 + tests/ref/fate/matroska-side-data-pref-packet | 1 + tests/ref/fate/matroska-spherical-mono | 5 + tests/ref/fate/matroska-spherical-mono-remux | 10 + tests/ref/fate/matroska-stereo_mode | 20 + tests/ref/fate/matroska-vp8-alpha-remux | 6 + .../ref/fate/mov-heic-demux-still-image-grid | 5 + .../ref/fate/mov-heic-demux-still-image-iovl | 3 + .../fate/mov-heic-demux-still-image-iovl-2 | 2 + .../ref/fate/mov-mp4-disposition-mpegts-remux | 6 +- tests/ref/fate/mov-mp4-iamf-5_1_4 | 14 + tests/ref/fate/mov-mp4-iamf-7_1_4-video-first | 662 ++++ ...mf-7_1_4 => mov-mp4-iamf-7_1_4-video-last} | 191 +- tests/ref/fate/mov-mp4-iamf-ambisonic_1 | 10 + tests/ref/fate/mov-mp4-iamf-stereo | 4 + tests/ref/fate/mov-mp4-pcm | 2 +- tests/ref/fate/mov-spherical-mono | 5 + tests/ref/fate/mov-zombie | 2 +- tests/ref/fate/movenc | 10 +- tests/ref/fate/mxf-probe-applehdr10 | 3 + tests/ref/fate/mxf-probe-d10 | 2 + tests/ref/fate/mxf-probe-dnxhd | 4 + tests/ref/fate/mxf-probe-dv25 | 3 + tests/ref/fate/mxf-probe-j2k | 1 + tests/ref/fate/oggopus-demux | 2 +- tests/ref/fate/opt | 96 +- tests/ref/fate/png-mdcv | 22 + tests/ref/fate/prores-transparency | 4 +- tests/ref/fate/prores-transparency_skip | 4 +- tests/ref/fate/segment-mp4-to-ts | 12 +- tests/ref/fate/side_data_array | 22 +- tests/ref/fate/source | 10 +- tests/ref/fate/spdif-dca-core-remux | 14 +- tests/ref/fate/spdif-dca-master-core-remux | 2344 +++++++------- tests/ref/fate/sub-webvtt | 2 +- tests/ref/fate/sub-webvtt2 | 2 +- tests/ref/fate/time_base | 2 +- tests/ref/fate/ts-demux | 6 +- tests/ref/fate/ts-opus-demux | 2 +- tests/ref/fate/ts-small-demux | 2 +- tests/ref/fate/ts-timed-id3-demux | 2 +- .../ref/fate/vvc-conformance-IBC_B_Tencent_2 | 22 + tests/ref/fate/vvc-conformance-RPR_A_4 | 9 + .../fate/vvc-conformance-SUBPIC_C_ERICSSON_1 | 37 + tests/ref/fate/vvc-conformance-WRAP_A_4 | 16 +- tests/ref/fate/wavpack-lossless-dsd | 1 + tests/ref/fate/webm-webvtt-remux | 4 + tests/ref/lavf-fate/evc.mp4 | 2 +- tests/ref/lavf-fate/hevc.flv | 2 +- tests/ref/lavf-fate/hevc.mp4 | 3 + tests/ref/lavf-fate/mv_hevc.mov | 3 + tests/ref/lavf-fate/vvc.mp4 | 3 + tests/ref/lavf/mov_hybrid_frag | 3 + tests/ref/vsynth/vsynth1-ffv1-v2 | 4 + tests/ref/vsynth/vsynth1-h261-trellis | 8 +- tests/ref/vsynth/vsynth1-mpeg4-thread | 6 +- tests/ref/vsynth/vsynth1-prores_444_int | 2 +- tests/ref/vsynth/vsynth1-prores_int | 2 +- tests/ref/vsynth/vsynth2-ffv1-v2 | 4 + tests/ref/vsynth/vsynth2-h261-trellis | 8 +- tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd | 6 +- tests/ref/vsynth/vsynth2-mpeg4-adap | 8 +- tests/ref/vsynth/vsynth2-mpeg4-qprd | 6 +- tests/ref/vsynth/vsynth2-mpeg4-thread | 6 +- tests/ref/vsynth/vsynth2-prores_444_int | 2 +- tests/ref/vsynth/vsynth2-prores_int | 2 +- tests/ref/vsynth/vsynth3-ffv1-v2 | 4 + tests/ref/vsynth/vsynth3-prores_444_int | 2 +- tests/ref/vsynth/vsynth3-prores_int | 2 +- tests/ref/vsynth/vsynth_lena-ffv1-v2 | 4 + tests/ref/vsynth/vsynth_lena-h261-trellis | 8 +- tests/ref/vsynth/vsynth_lena-mpeg4-rc | 4 +- tests/ref/vsynth/vsynth_lena-prores_444_int | 2 +- tests/ref/vsynth/vsynth_lena-prores_int | 2 +- tests/streamgroups/audio_element-7_1_4-2 | 6 + tools/Makefile | 6 + tools/crypto_bench.c | 1 + tools/enc_recon_frame_test.c | 1 + tools/ismindex.c | 1 + tools/probetest.c | 1 + tools/sidxindex.c | 1 + tools/target_bsf_fuzzer.c | 1 + tools/target_dec_fuzzer.c | 17 +- tools/target_dem_fuzzer.c | 1 + tools/target_enc_fuzzer.c | 215 ++ tools/target_swr_fuzzer.c | 154 + tools/target_sws_fuzzer.c | 1 + tools/uncoded_frame.c | 1 + 2329 files changed, 88403 insertions(+), 41615 deletions(-) delete mode 100644 compat/atomics/gcc/stdatomic.h delete mode 100644 compat/atomics/pthread/stdatomic.h delete mode 100644 compat/atomics/suncc/stdatomic.h create mode 100644 compat/stdbit/stdbit.h create mode 100644 libavcodec/aac/Makefile rename libavcodec/{aacdec_template.c => aac/aacdec.c} (59%) create mode 100644 libavcodec/aac/aacdec.h create mode 100644 libavcodec/aac/aacdec_ac.c create mode 100644 libavcodec/aac/aacdec_ac.h create mode 100644 libavcodec/aac/aacdec_dsp_template.c create mode 100644 libavcodec/aac/aacdec_fixed.c create mode 100644 libavcodec/aac/aacdec_fixed_coupling.h create mode 100644 libavcodec/aac/aacdec_fixed_dequant.h create mode 100644 libavcodec/aac/aacdec_fixed_prediction.h create mode 100644 libavcodec/aac/aacdec_float.c create mode 100644 libavcodec/aac/aacdec_float_coupling.h create mode 100644 libavcodec/aac/aacdec_float_prediction.h rename libavcodec/{aacdec.c => aac/aacdec_latm.h} (60%) create mode 100644 libavcodec/aac/aacdec_lpd.c create mode 100644 libavcodec/aac/aacdec_lpd.h create mode 100644 libavcodec/aac/aacdec_proc_template.c rename libavcodec/{aacdec_common.c => aac/aacdec_tab.c} (99%) rename libavcodec/{aacdectab.h => aac/aacdec_tab.h} (91%) create mode 100644 libavcodec/aac/aacdec_usac.c create mode 100644 libavcodec/aac/aacdec_usac.h delete mode 100644 libavcodec/aacdec.h delete mode 100644 libavcodec/aacdec_fixed.c create mode 100644 libavcodec/aarch64/ac3dsp_init_aarch64.c create mode 100644 libavcodec/aarch64/ac3dsp_neon.S rename libavcodec/{alpha/hpeldsp_alpha.h => aarch64/fdct.h} (75%) create mode 100644 libavcodec/aarch64/fdctdsp_init_aarch64.c create mode 100644 libavcodec/aarch64/fdctdsp_neon.S create mode 100644 libavcodec/aarch64/h26x/dsp.h rename libavcodec/aarch64/{hevcdsp_epel_neon.S => h26x/epel_neon.S} (94%) rename libavcodec/aarch64/{hevcdsp_qpel_neon.S => h26x/qpel_neon.S} (91%) rename libavcodec/aarch64/{hevcdsp_sao_neon.S => h26x/sao_neon.S} (88%) rename libavutil/aarch64/bswap.h => libavcodec/aarch64/mpegvideoencdsp_init.c (53%) create mode 100644 libavcodec/aarch64/mpegvideoencdsp_neon.S create mode 100644 libavcodec/aarch64/vvc/Makefile create mode 100644 libavcodec/aarch64/vvc/alf.S create mode 100644 libavcodec/aarch64/vvc/alf_template.c create mode 100644 libavcodec/aarch64/vvc/dsp_init.c create mode 100644 libavcodec/aarch64/vvc/inter.S create mode 100644 libavcodec/aarch64/vvc/sad.S delete mode 100644 libavcodec/alpha/Makefile delete mode 100644 libavcodec/alpha/asm.h delete mode 100644 libavcodec/alpha/hpeldsp_alpha.c delete mode 100644 libavcodec/alpha/hpeldsp_alpha_asm.S delete mode 100644 libavcodec/alpha/idctdsp_alpha.c delete mode 100644 libavcodec/alpha/idctdsp_alpha.h delete mode 100644 libavcodec/alpha/idctdsp_alpha_asm.S delete mode 100644 libavcodec/alpha/me_cmp_alpha.c delete mode 100644 libavcodec/alpha/me_cmp_mvi_asm.S delete mode 100644 libavcodec/alpha/mpegvideo_alpha.c delete mode 100644 libavcodec/alpha/pixblockdsp_alpha.c delete mode 100644 libavcodec/alpha/regdef.h delete mode 100644 libavcodec/alpha/simple_idct_alpha.c delete mode 100644 libavcodec/avr32/mathops.h create mode 100644 libavcodec/bsf/dovi_rpu.c create mode 100644 libavcodec/container_fifo.c create mode 100644 libavcodec/container_fifo.h create mode 100644 libavcodec/d3d12va_encode.c create mode 100644 libavcodec/d3d12va_encode.h create mode 100644 libavcodec/d3d12va_encode_hevc.c create mode 100644 libavcodec/dovi_rpudec.c create mode 100644 libavcodec/dovi_rpuenc.c create mode 100644 libavcodec/hevc/Makefile rename libavcodec/{hevc_cabac.c => hevc/cabac.c} (88%) rename libavcodec/{hevc_data.c => hevc/data.c} (98%) rename libavcodec/{hevc_data.h => hevc/data.h} (100%) rename libavcodec/{hevcdsp.c => hevc/dsp.c} (99%) rename libavcodec/{hevcdsp.h => hevc/dsp.h} (98%) rename libavcodec/{hevcdsp_template.c => hevc/dsp_template.c} (99%) rename libavcodec/{hevc_filter.c => hevc/filter.c} (58%) rename libavcodec/{ => hevc}/hevc.h (94%) rename libavcodec/{ => hevc}/hevcdec.c (58%) rename libavcodec/{ => hevc}/hevcdec.h (71%) rename libavcodec/{hevc_mvs.c => hevc/mvs.c} (82%) rename libavcodec/{hevc_parse.c => hevc/parse.c} (94%) rename libavcodec/{hevc_parse.h => hevc/parse.h} (96%) rename libavcodec/{hevc_parser.c => hevc/parser.c} (84%) rename libavcodec/{hevcpred.c => hevc/pred.c} (93%) rename libavcodec/{hevcpred.h => hevc/pred.h} (86%) rename libavcodec/{hevcpred_template.c => hevc/pred_template.c} (87%) rename libavcodec/{hevc_ps.c => hevc/ps.c} (74%) rename libavcodec/{hevc_ps.h => hevc/ps.h} (77%) rename libavcodec/{hevc_ps_enc.c => hevc/ps_enc.c} (99%) create mode 100644 libavcodec/hevc/refs.c rename libavcodec/{hevc_sei.c => hevc/sei.c} (78%) rename libavcodec/{hevc_sei.h => hevc/sei.h} (81%) delete mode 100644 libavcodec/hevc_refs.c create mode 100644 libavcodec/hw_base_encode.c create mode 100644 libavcodec/hw_base_encode.h create mode 100644 libavcodec/hw_base_encode_h264.c create mode 100644 libavcodec/hw_base_encode_h264.h create mode 100644 libavcodec/hw_base_encode_h265.c create mode 100644 libavcodec/hw_base_encode_h265.h create mode 100644 libavcodec/lcevcdec.c create mode 100644 libavcodec/lcevcdec.h create mode 100644 libavcodec/liblc3dec.c create mode 100644 libavcodec/liblc3enc.c create mode 100644 libavcodec/libvvenc.c delete mode 100644 libavcodec/mips/aacdec_mips.c delete mode 100644 libavcodec/mips/aacdec_mips.h delete mode 100644 libavcodec/mips/aacpsdsp_mips.c delete mode 100644 libavcodec/mips/aacpsy_mips.h delete mode 100644 libavcodec/mips/aacsbr_mips.c delete mode 100644 libavcodec/mips/aacsbr_mips.h rename libavutil/avr32/bswap.h => libavcodec/mips/mpegvideoenc_init_mips.c (62%) create mode 100644 libavcodec/mips/mpegvideoenc_mmi.c delete mode 100644 libavcodec/mips/sbrdsp_mips.c create mode 100644 libavcodec/opus/Makefile rename libavcodec/{opus_celt.c => opus/celt.c} (99%) rename libavcodec/{opus_celt.h => opus/celt.h} (98%) rename libavcodec/{opusdec.c => opus/dec.c} (99%) rename libavcodec/{opusdec_celt.c => opus/dec_celt.c} (98%) rename libavcodec/{opusdsp.c => opus/dsp.c} (88%) rename libavcodec/{opusdsp.h => opus/dsp.h} (84%) rename libavcodec/{opusenc.c => opus/enc.c} (99%) rename libavcodec/{opusenc.h => opus/enc.h} (94%) rename libavcodec/{opusenc_psy.c => opus/enc_psy.c} (99%) rename libavcodec/{opusenc_psy.h => opus/enc_psy.h} (94%) rename libavcodec/{opusenc_utils.h => opus/enc_utils.h} (96%) rename libavcodec/{ => opus}/opus.h (94%) rename libavcodec/{opus_parse.c => opus/parse.c} (99%) rename libavcodec/{opus_parse.h => opus/parse.h} (98%) rename libavcodec/{opus_parser.c => opus/parser.c} (99%) rename libavcodec/{opus_pvq.c => opus/pvq.c} (99%) rename libavcodec/{opus_pvq.h => opus/pvq.h} (98%) rename libavcodec/{opus_rc.c => opus/rc.c} (98%) rename libavcodec/{opus_rc.h => opus/rc.h} (99%) rename libavcodec/{opus_silk.c => opus/silk.c} (99%) rename libavcodec/{opus_silk.h => opus/silk.h} (98%) rename libavcodec/{opustab.c => opus/tab.c} (98%) rename libavcodec/{opustab.h => opus/tab.h} (97%) rename libavcodec/{avpacket.c => packet.c} (99%) create mode 100644 libavcodec/progressframe.h rename libavcodec/{proresdec2.c => proresdec.c} (99%) rename libavutil/riscv/timer.h => libavcodec/riscv/ac3dsp_rvvb.S (54%) rename libavcodec/riscv/{audiodsp_rvf.S => bswapdsp_rvvb.S} (56%) create mode 100644 libavcodec/riscv/cpu_common.c create mode 100644 libavcodec/riscv/fixed_vtype.S rename libavcodec/{alpha/blockdsp_alpha.c => riscv/h263dsp_init.c} (57%) create mode 100644 libavcodec/riscv/h263dsp_rvv.S create mode 100644 libavcodec/riscv/h264addpx_rvv.S create mode 100644 libavcodec/riscv/h264dsp_init.c create mode 100644 libavcodec/riscv/h264dsp_rvv.S create mode 100644 libavcodec/riscv/h264idct_rvv.S create mode 100644 libavcodec/riscv/mpegvideoencdsp_init.c create mode 100644 libavcodec/riscv/mpegvideoencdsp_rvv.S create mode 100644 libavcodec/riscv/rv40dsp_init.c create mode 100644 libavcodec/riscv/rv40dsp_rvv.S create mode 100644 libavcodec/riscv/startcode_rvb.S create mode 100644 libavcodec/riscv/startcode_rvv.S create mode 100644 libavcodec/riscv/vc1dsp_rvi.S create mode 100644 libavcodec/riscv/videodsp.S rename libavutil/sh4/bswap.h => libavcodec/riscv/videodsp_init.c (59%) create mode 100644 libavcodec/riscv/vp7dsp_init.c create mode 100644 libavcodec/riscv/vp7dsp_rvv.S create mode 100644 libavcodec/riscv/vp8dsp.h create mode 100644 libavcodec/riscv/vp8dsp_rvi.S create mode 100644 libavcodec/riscv/vp9_intra_rvv.S create mode 100644 libavcodec/riscv/vp9_mc_rvi.S create mode 100644 libavcodec/riscv/vp9_mc_rvv.S create mode 100644 libavcodec/riscv/vp9dsp.h create mode 100644 libavcodec/riscv/vp9dsp_init.c delete mode 100644 libavcodec/sh4/README create mode 100644 libavcodec/threadprogress.c create mode 100644 libavcodec/threadprogress.h create mode 100644 libavcodec/vulkan_encode.c create mode 100644 libavcodec/vulkan_encode.h create mode 100644 libavcodec/vulkan_encode_h264.c create mode 100644 libavcodec/vulkan_encode_h265.c rename libavcodec/vvc/{vvc_cabac.c => cabac.c} (99%) rename libavcodec/vvc/{vvc_cabac.h => cabac.h} (98%) rename libavcodec/vvc/{vvc_ctu.c => ctu.c} (97%) rename libavcodec/vvc/{vvc_ctu.h => ctu.h} (93%) rename libavcodec/vvc/{vvc_data.c => data.c} (99%) rename libavcodec/vvc/{vvc_data.h => data.h} (87%) rename libavcodec/vvc/{vvcdec.c => dec.c} (89%) rename libavcodec/vvc/{vvcdec.h => dec.h} (80%) rename libavcodec/vvc/{vvcdsp.c => dsp.c} (75%) rename libavcodec/vvc/{vvcdsp.h => dsp.h} (84%) rename libavcodec/vvc/{vvcdsp_template.c => dsp_template.c} (94%) rename libavcodec/vvc/{vvc_filter.c => filter.c} (50%) rename libavcodec/vvc/{vvc_filter.h => filter.h} (90%) rename libavcodec/vvc/{vvc_filter_template.c => filter_template.c} (98%) create mode 100644 libavcodec/vvc/inter.c rename libavcodec/vvc/{vvc_inter.h => inter.h} (90%) rename libavcodec/vvc/{vvc_inter_template.c => inter_template.c} (62%) rename libavcodec/vvc/{vvc_intra.c => intra.c} (92%) rename libavcodec/vvc/{vvc_intra.h => intra.h} (93%) rename libavcodec/vvc/{vvc_intra_template.c => intra_template.c} (99%) rename libavcodec/vvc/{vvc_intra_utils.c => intra_utils.c} (96%) rename libavcodec/vvc/{vvc_itx_1d.c => itx_1d.c} (99%) rename libavcodec/vvc/{vvc_itx_1d.h => itx_1d.h} (94%) rename libavcodec/vvc/{vvc_mvs.c => mvs.c} (93%) rename libavcodec/vvc/{vvc_mvs.h => mvs.h} (88%) rename libavcodec/vvc/{vvc_ps.c => ps.c} (83%) rename libavcodec/vvc/{vvc_ps.h => ps.h} (91%) rename libavcodec/vvc/{vvc_refs.c => refs.c} (82%) rename libavcodec/vvc/{vvc_refs.h => refs.h} (94%) rename libavcodec/vvc/{vvc_thread.c => thread.c} (87%) rename libavcodec/vvc/{vvc_thread.h => thread.h} (83%) delete mode 100644 libavcodec/vvc/vvc_inter.c create mode 100644 libavcodec/x86/vvc/vvc_alf.asm create mode 100644 libavcodec/x86/vvc/vvc_dmvr.asm create mode 100644 libavcodec/x86/vvc/vvc_of.asm create mode 100644 libavcodec/x86/vvc/vvc_sad.asm create mode 100644 libavdevice/riscv/Makefile create mode 100644 libavdevice/riscv/cpu_common.c delete mode 100644 libavfilter/af_afir.h delete mode 100644 libavfilter/internal.h create mode 100644 libavfilter/perlin.c create mode 100644 libavfilter/perlin.h create mode 100644 libavfilter/riscv/cpu_common.c delete mode 100644 libavfilter/unsharp.h create mode 100644 libavfilter/vf_drawbox_vaapi.c create mode 100644 libavfilter/vf_lcevc.c create mode 100644 libavfilter/vf_pad_vaapi.c create mode 100644 libavfilter/vf_xpsnr.c create mode 100644 libavfilter/vsrc_perlin.c create mode 100644 libavfilter/x86/vf_xpsnr_init.c create mode 100644 libavfilter/xpsnr.h delete mode 100644 libavformat/bitstream.c create mode 100644 libavformat/lc3.c create mode 100644 libavformat/nal.c create mode 100644 libavformat/nal.h create mode 100644 libavformat/rcwtdec.c create mode 100644 libavformat/riscv/Makefile create mode 100644 libavformat/riscv/cpu_common.c create mode 100644 libavutil/aarch64/intreadwrite.h delete mode 100644 libavutil/arm/intreadwrite.h delete mode 100644 libavutil/avr32/intreadwrite.h rename compat/atomics/pthread/stdatomic.c => libavutil/riscv/cpu_common.c (68%) create mode 100644 libavutil/riscv/lls_init.c create mode 100644 libavutil/riscv/lls_rvv.S create mode 100644 libswscale/aarch64/input.S create mode 100644 libswscale/aarch64/range_convert_neon.S create mode 100644 libswscale/aarch64/swscale_unscaled_neon.S create mode 100644 libswscale/loongarch/input_lsx.c create mode 100644 libswscale/riscv/cpu_common.c create mode 100644 libswscale/riscv/input_rvv.S create mode 100644 libswscale/riscv/range_rvv.S create mode 100644 libswscale/riscv/swscale.c create mode 100644 libswscale/x86/range_convert.asm delete mode 100644 libswscale/x86/rgb2rgb_template.c delete mode 100644 libswscale/x86/yuv2rgb_template.c create mode 100644 tests/checkasm/fdctdsp.c create mode 100644 tests/checkasm/h263dsp.c create mode 100644 tests/checkasm/lls.c create mode 100644 tests/checkasm/mpegvideoencdsp.c create mode 100644 tests/checkasm/rv40dsp.c create mode 100644 tests/checkasm/sw_range_convert.c create mode 100644 tests/checkasm/sw_yuv2rgb.c create mode 100644 tests/checkasm/sw_yuv2yuv.c create mode 100644 tests/checkasm/vvc_alf.c create mode 100644 tests/filtergraphs/crazychannels create mode 100644 tests/ref/fate/ffmpeg-spec-disposition create mode 100644 tests/ref/fate/filter-atempo create mode 100644 tests/ref/fate/filter-crazychannels create mode 100644 tests/ref/fate/filter-refcmp-xpsnr-rgb create mode 100644 tests/ref/fate/filter-refcmp-xpsnr-yuv create mode 100644 tests/ref/fate/filter-tiltandshift-410 create mode 100644 tests/ref/fate/filter-tiltandshift-422 create mode 100644 tests/ref/fate/filter-tiltandshift-444 create mode 100644 tests/ref/fate/h264-bsf-dts2pts create mode 100644 tests/ref/fate/hevc-conformance-MVHEVCS_A create mode 100644 tests/ref/fate/hevc-conformance-MVHEVCS_B create mode 100644 tests/ref/fate/hevc-conformance-MVHEVCS_E create mode 100644 tests/ref/fate/hevc-conformance-MVHEVCS_F create mode 100644 tests/ref/fate/hevc-mv-nuh-layer-id create mode 100644 tests/ref/fate/hevc-mv-position create mode 100644 tests/ref/fate/hevc-mv-switch create mode 100644 tests/ref/fate/hevc-pir create mode 100644 tests/ref/fate/iamf-5_1-copy create mode 100644 tests/ref/fate/iamf-5_1-demux create mode 100644 tests/ref/fate/iamf-stereo-demux create mode 100644 tests/ref/fate/jpeg2000dec-p0_10 create mode 100644 tests/ref/fate/mov-mp4-iamf-7_1_4-video-first rename tests/ref/fate/{mov-mp4-iamf-7_1_4 => mov-mp4-iamf-7_1_4-video-last} (85%) create mode 100644 tests/ref/fate/png-mdcv create mode 100644 tests/ref/fate/vvc-conformance-IBC_B_Tencent_2 create mode 100644 tests/ref/fate/vvc-conformance-RPR_A_4 create mode 100644 tests/ref/fate/vvc-conformance-SUBPIC_C_ERICSSON_1 create mode 100644 tests/ref/fate/wavpack-lossless-dsd create mode 100644 tests/ref/lavf-fate/hevc.mp4 create mode 100644 tests/ref/lavf-fate/mv_hevc.mov create mode 100644 tests/ref/lavf-fate/vvc.mp4 create mode 100644 tests/ref/lavf/mov_hybrid_frag create mode 100644 tests/ref/vsynth/vsynth1-ffv1-v2 create mode 100644 tests/ref/vsynth/vsynth2-ffv1-v2 create mode 100644 tests/ref/vsynth/vsynth3-ffv1-v2 create mode 100644 tests/ref/vsynth/vsynth_lena-ffv1-v2 create mode 100644 tests/streamgroups/audio_element-7_1_4-2 create mode 100644 tools/target_enc_fuzzer.c create mode 100644 tools/target_swr_fuzzer.c diff --git a/Changelog b/Changelog index 2faa8f380..4b35e446c 100644 --- a/Changelog +++ b/Changelog @@ -1,331 +1,259 @@ Entries are sorted chronologically from oldest to youngest within each release, releases are sorted from youngest to oldest. -version 7.0.2: - avcodec/snow: Fix off by 1 error in run_buffer - avcodec/utils: apply the same alignment to YUV410 as we do to YUV420 for snow - avformat/iamf_parse: Check for 0 samples - swscale: [loongarch] Fix checkasm-sw_yuv2rgb failure. - avcodec/aacps_tablegen_template: don't redefine CONFIG_HARDCODED_TABLES - avutil/hwcontext_vaapi: use the correct type for VASurfaceAttribExternalBuffers.buffers - avcodec/pcm-bluray/dvd: Use correct pointer types on BE - avcodec/pngenc: fix sBIT writing for indexed-color PNGs - avcodec/pngdec: use 8-bit sBIT cap for indexed PNGs per spec - avformat/mov: check that child boxes of trak are only present inside it - avformat/mov: check that sample and chunk count is 1 for HEIF - avcodec/videotoolboxenc: Fix bitrate doesn't work as expected - avdevice/dshow: Don't skip audio devices if no video device is present - avcodec/hdrenc: Allocate more space - avcodec/cfhdenc: Height of 16 is not supported - avcodec/cfhdenc: Allocate more space - avcodec/osq: fix integer overflow when applying factor - avcodec/osq: avoid using too large numbers for shifts and integers in update_residue_parameter() - avcodec/vaapi_encode: Check hwctx - avcodec/proresdec: Consider negative bits left - avcodec/alsdec: Clear shift_value - avcodec/hevc/hevcdec: Do not allow slices to depend on failed slices - avformat/mov: add an EOF check in IPRP - avfilter/vf_xfade: Check ff_inlink_consume_frame() for failure - avutil/slicethread: Check pthread_*_init() for failure - avutil/frame: Check log2_crop_align - avutil/buffer: Check ff_mutex_init() for failure - avformat/xmv: Check this_packet_size - avformat/webpenc: Check filesize in trailer - avformat/ty: rec_size seems to only need 32bit - avformat/tty: Check avio_size() - avformat/siff: Basic pkt_size check - avformat/sauce: Check avio_size() for failure - avformat/sapdec: Check ffurl_get_file_handle() for error - avformat/nsvdec: Check asize for PCM - avformat/mp3dec: Check header_filesize - avformat/mp3dec; Check for avio_size() failure - avformat/mov: Use 64bit for str_size - avformat/mm: Check length - avformat/hnm: Check *chunk_size - avformat/hlsenc: Check ret - avformat/bintext: Check avio_size() return - avformat/asfdec_o: Check size of index object - avfilter/vf_scale: Check ff_scale_adjust_dimensions() for failure - avfilter/scale_eval: Use 64bit, check values in ff_scale_adjust_dimensions() - avfilter/vf_lut3d: Check av_scanf() - avfilter/vf_elbg: Use unsigned for shifting into the top bit - avfilter/vf_premultiply: Use AV_PIX_MAX_PLANES - avfilter/vf_deshake_opencl: Ensure that the first iteration initializes the best variables - avformat/iamf_parse: Check for negative sample sizes - swscale/output: Fix integer overflows in yuv2rgba64_X_c_template - avformat/mxfdec: Reorder elements of expression in bisect loop - avutil/timecode: Use a 64bit framenum internally - avcodec/pnmdec: Use 64bit for input size check - avformat/mov: Check extradata in mov_read_iacb() - avcodec/mpeg12enc: Use av_rescale() in vbv_buffer_size computation - avcodec/utvideoenc: Use unsigned shift to build flags - avcodec/j2kenc: Merge dwt_norm into lambda - avcodec/vc2enc: Fix overflows with storing large values - avcodec/mpegvideo_enc: Do not duplicate pictures on shifting - avdevice/dshow_capture: Fix error handling in ff_dshow_##prefix##_Create() - avcodec/tiff: Check value on positive signed targets - avfilter/vf_convolution_opencl: Assert that the filter name is one of the filters - avfilter/vf_bm3d: Dont round MSE2SSE to an integer - avdevice/dshow: Remove NULL check on pin - avdevice/dshow: check ff_dshow_pin_ConnectionMediaType() for failure - avdevice/dshow: Check device_filter_unique_name before use - avdevice/dshow: Cleanup also on av_log case - avdevice/dshow_filter: Use wcscpy_s() - avcodec/flac_parser: Assert that we do not overrun the link_penalty array - avcodec/osq: avoid signed overflow in downsample path - avcodec/pixlet: Simplify pfx computation - avcodec/motion_est: Fix score squaring overflow - avcodec/mlpenc: Use 64 for ml, mr - avcodec/loco: Check loco_get_rice() for failure - avcodec/loco: check get_ur_golomb_jpegls() for failure - avcodec/leaddec: Check init_get_bits8() for failure - avcodec/imm4: check cbphi for error - avcodec/iff: Use signed count - avcodec/golomb: Assert that k is in the supported range for get_ur/sr_golomb() - avcodec/golomb: Document return for get_ur_golomb_jpegls() and get_sr_golomb_flac() - avcodec/dxv: Fix type in get_opcodes() - avcodec/cri: Check length - avcodec/xsubdec: Check parse_timecode() - avutil/imgutils: av_image_check_size2() ensure width and height fit in 32bit - avfilter/vf_tiltandshift: Free dst on error - doc/examples/mux: remove nop - avcodec/proresenc_kostya: use unsigned alpha for rotation - avformat/rtpenc_rfc4175: Use 64bit in computation if copy_offset - avformat/rtmpproto: Use AV_DICT_MATCH_CASE instead of litteral number - avformat/rtmppkt: Simplify and deobfuscate amf_tag_skip() slightly - avformat/rmdec: use 64bit for audio_framesize checks - avutil/wchar_filename: Correct sizeof - avutil/hwcontext_d3d11va: correct sizeof IDirect3DSurface9 - avutil/hwcontext_d3d11va: Free AVD3D11FrameDescriptor on error - avutil/hwcontext_d3d11va: correct sizeof AVD3D11FrameDescriptor - avcodec/vvc/refs: Use unsigned mask - doc/examples/vaapi_encode: Try to check fwrite() for failure - avformat/usmdec: Initialize value - avformat/tls_schannel: Initialize ret - avformat/subfile: Assert that whence is a known case - avformat/subfile: Merge if into switch() - avformat/rtsp: Check that lower transport is handled in one of the if() - avformat/rtsp: initialize reply1 - avformat/rtsp: use < 0 for error check - avformat/rtpenc_vc2hq: Check sizes - avfilter/af_aderivative: Free out on error - swscale/swscale: Use ptrdiff_t for linesize computations - avfilter/af_amerge: Cleanup on av_channel_layout_copy() failure - avfilter/af_afir: Assert format - avfilter/af_afftdn: Assert format - avfilter/af_pan: check nb_output_channels before use - cbs_av1: Reject thirty-two zero bits in uvlc code - avfilter/af_mcompand: compute half frequency in double - avfilter/af_channelsplit: Assert that av_channel_layout_channel_from_index() succeeds - avfilter/af_aresample: Cleanup on av_channel_layout_copy() failure - tools/coverity: Phase 1 study of anti-halicogenic for coverity av_rescale() - avfilter/vf_avgblur: Check plane instead of AVFrame - avfilter/drawutils: Fix depthb computation - avfilter/avf_showcwt: Check av_parse_video_rate() for failure - avformat/rdt: Check pkt_len - avformat/mpeg: Check len in mpegps_probe() - avformat/mxfenc: resurrects the error print - avdevice/dshow: Check ICaptureGraphBuilder2_SetFiltergraph() for failure - avcodec/mfenc: check IMFSample_ConvertToContiguousBuffer() for failure - avcodec/vc1_loopfilter: Factor duplicate code in vc1_b_h_intfi_loop_filter() - avcodec/vvc/ctu: Remove dead ret check - avcodec/vvc/dec: Remove constant eos_at_start - avformat/img2dec: assert no pipe on ts_from_file - avcodec/cbs_jpeg: Try to move the read entity to one side in a test - fftools/ffplay: Check vulkan_params - fftools/ffmpeg_enc: Initialize Decoder - fftools/ffmpeg_enc: Initialize fd - fftools/ffmpeg_enc: simplify opaque_ref check - avformat/mov: Check edit list for overflow - fftools/ffmpeg: Check read() for failure - avcodec/vvc/dec: Check ff_init_cabac_decoder() for failure - MAINTAINERS: Add Timo Rothenpieler to server admins - swscale/output: Avoid undefined overflow in yuv2rgb_write_full() - swscale/output: alpha can become negative after scaling, use multiply - avcodec/targaenc: Allocate space for the palette - avcodec/r210enc: Use av_rescale for bitrate - avcodec/jfdctint_template: Fewer integer anomalies - avcodec/snowenc: MV limits due to mv_penalty table size - tools/target_dec_fuzzer: Adjust threshold for MV30 - tools/target_dec_fuzzer: Adjust threshold for jpeg2000 - avformat/mxfdec: Check container_ul->desc before use - avcodec/libvpxenc: Cleanup on error - MAINTAINERS: Update the entries for the release maintainer for FFmpeg - doc/developer: Provide information about git send-email and gmail - avfilter/vf_rotate: Check ff_draw_init2() return value - avformat/mov: Use int64_t in intermediate for corrected_dts - avformat/mov: Use 64bit in intermediate for current_dts - avformat/matroskadec: Assert that num_levels is non negative - avformat/libzmq: Check av_strstart() - avformat/img2dec: Little JFIF / Exif cleanup - avformat/img2dec: Move DQT after unrelated if() - avformat/imfdec: Simplify get_next_track_with_minimum_timestamp() - avdevice/xcbgrab: Check sscanf() return - fftools/cmdutils: Add protective () to FLAGS - avformat/sdp: Check before appending "," - avcodec/libx264: Check init_get_bits8() return code - avcodec/ilbcdec: Remove dead code - avcodec/vp8: Check cond init - avcodec/vp8: Check mutex init - avcodec/proresenc_anatoliy: Assert that AV_PROFILE_UNKNOWN is replaced - avcodec/pcm-dvdenc: 64bit pkt-size - avcodec/notchlc: Check init_get_bits8() for failure - avcodec/tests/dct: Use 64bit in intermediate for error computation - avcodec/scpr3: Check add_dec() for failure - avcodec/rv34: assert that size is not 0 in rv34_gen_vlc_ext() - avcodec/wavpackenc: Use unsigned for potential 31bit shift - avcodec/vvc/mvs: Initialize mvf - avcodec/tests/jpeg2000dwt: Use 64bit in comparission - avcodec/tests/jpeg2000dwt: Use 64bit in err2 computation - avformat/fwse: Remove always false expression - avcodec/sga: Make it clear that the return is intentionally not checked - avformat/asfdec_f: Use 64bit for preroll computation - avformat/argo_asf: Use 64bit in offset intermediate - avformat/ape: Use 64bit for final frame size - avformat/ac4dec: Check remaining space in ac4_probe() - avdevice/pulse_audio_enc: Use av_rescale() to avoid integer overflow - avcodec/vlc: Cleanup on multi table alloc failure in ff_vlc_init_multi_from_lengths() - avcodec/tiff: Assert init_get_bits8() success in unpack_gray() - avcodec/tiff: Assert init_get_bits8() success in horizontal_fill() - tools/decode_simple: Check avcodec_send_packet() for errors on flushing - swscale/yuv2rgb: Use 64bit for brightness computation - swscale/x86/swscale: use a clearer name for INPUT_PLANER_RGB_A_FUNC_CASE - avutil/tests/opt: Check av_set_options_string() for failure - avutil/tests/dict: Check av_dict_set() before get for failure - avdevice/dshow: fix badly indented line - avformat/demux: resurrect dead stores - avcodec/tests/bitstream_template: Assert bits_init8() return - tools/enc_recon_frame_test: Assert that av_image_get_linesize() succeeds - avformat/iamf_writer: disallow Opus extradata with mapping family other than 0 - avformat/iamf_parse: sanitize audio_roll_distance values - avformat/iamf: byteswap values in OpusHeader - avformat/iamf: rename Codec Config seek_preroll to audio_roll_distance - avformat/iamf_writer: fix coded audio_roll_distance values - avformat/iamf_writer: fix PCM endian-ness flag - avformat/movenc: fix channel count and samplerate fields for IAMF tracks - avformat/iamf_parse: keep substream count consistent - avformat/iamf_parse: add missing padding to AAC extradata - avformat/iamf_parse: 0 layers are not allowed - avformat/iamf_parse: consider nb_substreams when accessing substreams array - avformat/iamf_parse: Remove dead case - avcodec/png: more informative error message for invalid sBIT size - avcodec/pngdec: avoid erroring with sBIT on indexed-color images - avfilter/vf_tiltandshift: fix buffer offset for yuv422p input - avutil/timestamp: avoid possible FPE when 0 is passed to av_ts_make_time_string2() - avformat/mov: add more checks for infe atom size - avformat/mov: check for EOF inside the infe list parsing loop - avformat/mov: check extent_offset calculation for overflow - avformat/mov: check that iloc offset values fit on an int64_t - avcodec/pngenc: fix mDCv typo - avcodec/pngdec: fix mDCv typo - avcodec/nvenc: fix segfault in intra-only mode - avdevice/avfoundation: add external video devices - aarch64: Add OpenBSD runtime detection of dotprod and i8mm using sysctl - fftools/ffplay_renderer: use correct NULL value for Vulkan type - qsv: Initialize impl_value - avutil/hwcontext_qsv: fix GCC 14.1 warnings - avcodec/mediacodecenc: workaround the alignment requirement for H.265 - avcodec/mediacodecenc: workaround the alignment requirement only for H.264 - lavc/lpc: fix off-by-one in R-V V compute_autocorr - lavc/vp9: reset segmentation fields when segmentation isn't enabled - configure: enable ffnvcodec, nvenc, nvdec for FreeBSD - lavc/sbrdsp: fix potential overflow in noise table +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 7.1: +- Raw Captions with Time (RCWT) closed caption demuxer +- LC3/LC3plus decoding/encoding using external library liblc3 +- ffmpeg CLI filtergraph chaining +- LC3/LC3plus demuxer and muxer +- pad_vaapi, drawbox_vaapi filters +- vf_scale supports secondary ref input and framesync options +- vf_scale2ref deprecated +- qsv_params option added for QSV encoders +- VVC decoder compatible with DVB test content +- xHE-AAC decoder +- removed DEC Alpha DSP and support code +- VVC encoding support via libvvenc +- perlin video source +- D3D12VA HEVC encoder +- Cropping metadata parsing and writing in Matroska and MP4/MOV de/muxers +- Intel QSV-accelerated VVC decoding +- MediaCodec AAC/AMR-NB/AMR-WB/MP3 decoding +- YUV colorspace negotiation for codecs and filters, obsoleting the + YUVJ pixel format +- Vulkan H.264 encoder +- Vulkan H.265 encoder +- stream specifiers in fftools can now match by stream disposition +- LCEVC enhancement data exporting in H.26x and MP4/ISOBMFF +- LCEVC filter +- MV-HEVC decoding +- minor stream specifier syntax changes: + - when matching by metadata (:m::), the colon character + in keys or values now has to be backslash-escaped + - in optional maps (-map ....?) with a metadata-matching stream specifier, + the value has to be separated from the question mark by a colon, i.e. + -map ....:m:::? (otherwise it would be ambiguous whether the + 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 -version 7.0.1: - lavc/flacdsp: do not assume maximum R-V VL - avformat/flacdec: Reorder allocations to avoid leak on error - avcodec/adts_parser: Don't presume buffer to be padded - avformat/movenc: Check av_malloc() - avcodec/vp8: Return error on error - avformat/mov: store sample_sizes as unsigned ints - avformat/vvc: fix parsing sps_subpic_id - avformat/vvc: initialize some ptl flags - avcodec/mscc & mwsc: Check loop counts before use - avcodec/mpegvideo_enc: Fix potential overflow in RD - avcodec/mpeg4videodec: assert impossible wrap points - avcodec/mpeg12dec: Use 64bit in bit computation - avcodec/vqcdec: Check init_get_bits8() for failure - avcodec/vvc/dec: Check init_get_bits8() for failure - avcodec/vble: Check av_image_get_buffer_size() for failure - avcodec/vp3: Replace check by assert - avcodec/vp8: Forward return of ff_vpx_init_range_decoder() - avcodec/jpeg2000dec: remove ST=3 case - avcodec/qsvdec: Check av_image_get_buffer_size() for failure - avcodec/exr: Fix preview overflow - avcodec/decode: decode_simple_internal() only implements audio and video - avcodec/fmvc: remove dead assignment - avcodec/h2645_sei: Remove dead checks - avcodec/h264_slice: Remove dead sps check - avcodec/lpc: copy levenson coeffs only when they have been computed - avutil/tests/base64: Check with too short output array - libavutil/base64: Try not to write over the array end - avcodec/cbs_av1: Avoid shift overflow - fftools/ffplay: Check return of swr_alloc_set_opts2() - tools/opt_common: Check for malloc failure - doc/examples/demux_decode: Simplify loop - avformat/concatdec: Check file - avcodec/mpegvideo_enc: Fix 1 line and one column images - avcodec/amrwbdec: assert mode to be valid in decode_fixed_vector() - avcodec/wavarc: fix integer overflow in decode_5elp() block type 2 - swscale/output: Fix integer overflow in yuv2rgba64_full_1_c_template() - swscale/output: Fix integer overflow in yuv2rgba64_1_c_template - avcodec/av1dec: Change bit_depth to int - avcodec/av1dec: bit_depth cannot be another values than 8,10,12 - avcodec/avs3_parser: assert the return value of init_get_bits() - avcodec/avs2_parser: Assert init_get_bits8() success with const size 15 - avfilter/avfiltergraph: return value of ff_request_frame() is unused - avformat/mxfdec: Check body_offset - avformat/kvag: Check sample_rate - avcodec/atrac9dec: Check init_get_bits8() for failure - avcodec/ac3_parser: Check init_get_bits8() for failure - avcodec/pngdec: Check last AVFrame before deref - avcodec/hevcdec: Check ref frame - doc/examples/qsv_transcode: Initialize pointer before free - doc/examples/qsv_transcode: Simplify str_to_dict() loop - doc/examples/vaapi_transcode: Simplify loop - doc/examples/qsv_transcode: Simplify loop - avcodec/cbs_h2645: Check NAL space - avfilter/vf_thumbnail_cuda: Set ret before checking it - avfilter/signature_lookup: Dont copy uninitialized stuff around - avfilter/signature_lookup: Fix 2 differences to the refernce SW - avcodec/x86/vp3dsp_init: Set correct function pointer, fix crash - avformat/mp3dec: change bogus error message if read_header encounters EOF - avformat/mp3dec: simplify inner frame size check in mp3_read_header - avformat/mp3dec: only call ffio_ensure_seekback once - avcodec/cbs_h266: read vps_ptl_max_tid before using it - avcodec/cbs_h266: fix sh_collocated_from_l0_flag and sh_collocated_ref_idx infer - avformat/vvc: fix parsing some early VPS bitstream values - avformat/vvc: fix writing general_constraint_info bytes - avutil/ppc/cpu: Also use the machdep.altivec sysctl on NetBSD - lavd/v4l2: Use proper field type for second parameter of ioctl() with BSD's - vulkan_av1: Fix force_integer_mv value - vaapi_av1: Fix force_integer_mv value - av1dec: Add force_integer_mv derived field for decoder use - avutil/iamf: fix offsets for mix_gain options - avformat/iamfdec: check nb_streams in header read - avformat/mov: free the infe allocated item data on failure - avformat/iamf_writer: reject duplicated stream ids in a stream group - avformat/mov: don't read key_size bytes twice in the keys atom - avformat/mov: take into account the first eight bytes in the keys atom - avformat/mov: fix the check for the heif item parsing loop - avutil/iamf: fix mix_gain_class name - av1dec: Fix RefFrameSignBias calculation - avcodec/codec_par: always clear extradata_size in avcodec_parameters_to_context() - avcodec/mediacodecenc: Fix return empty packet when bsf is used - avcodec/hevcdec: Fix precedence, bogus film grain warning - avcodec/hevcdec: fix segfault on invalid film grain metadata - lavc/vvc: Skip enhancement layer NAL units - avformat/mov: ignore old infe box versions - vulkan_av1: add workaround for NVIDIA drivers tested on broken CTS - lavc/vulkan_av1: Use av1dec reference order hint information - lavc/av1: Record reference ordering information for each frame - doc/encoders: add missing libxvid option - doc/encoders: remove non-existent flag - fate/ffmpeg: Avoid dependency on samples - avcodec/wavpack: Remove always-false check - avcodec/wavpack: Fix leak and segfault on reallocation error - avcodec/lossless_videoencdsp: Don't presume alignment in diff_bytes - avcodec/ppc/h264dsp: Fix left shifts of negative numbers version 7.0: - DXV DXT1 encoder diff --git a/INSTALL.md b/INSTALL.md index 3b220bc6f..bdf581401 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -15,3 +15,11 @@ NOTICE ------ - Non system dependencies (e.g. libx264, libvpx) are disabled by default. + +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 + some of these 3rd party packages). This avoids circular dependencies during build. diff --git a/MAINTAINERS b/MAINTAINERS index a1599c7b0..8a2ee04ae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6,10 +6,26 @@ FFmpeg code. Please try to keep entries where you are the maintainer up to date! -Names in () mean that the maintainer currently has no time to maintain the code. +*Status*, one of the following: +[X] Old code. Something tagged obsolete generally means it has been replaced by a better system and you should be using that. +[0] No current maintainer [but maybe you could take the role as you write your new code]. +[1] It has a maintainer but they don't have time to do much other than throw the odd patch in. +[2] Someone actually looks after it. + A (CC
) after the name means that the maintainer prefers to be CC-ed on patches and related discussions. +(L
) *Mailing list* that is relevant to this area +(W
) *Web-page* with status/info +(B
) URI for where to file *bugs*. A web-page with detailed bug + filing info, a direct bug tracker link, or a mailto: URI. +(P
) *Subsystem Profile* document for more details submitting + patches to the given subsystem. This is either an in-tree file, + or a URI. See Documentation/maintainer/maintainer-entry-profile.rst + for details. +(T
) *SCM* tree type and location. + Type is one of: git, hg, quilt, stgit, topgit + Applications ============ @@ -18,10 +34,10 @@ ffmpeg: ffmpeg.c Michael Niedermayer, Anton Khirnov ffplay: - ffplay.c Marton Balint + ffplay.c [2] Marton Balint ffprobe: - ffprobe.c Stefano Sabatini + ffprobe.c [2] Stefano Sabatini Commandline utility code: cmdutils.c, cmdutils.h Michael Niedermayer @@ -34,25 +50,24 @@ Miscellaneous Areas =================== documentation Stefano Sabatini, Mike Melanson, Timothy Gu, Gyan Doshi -project server day to day operations Árpád Gereöffy, Michael Niedermayer, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler -project server emergencies Árpád Gereöffy, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov, Timo Rothenpieler -presets Robert Swain +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 +presets [0] metadata subsystem Aurelien Jacobs release management Michael Niedermayer -API tests Ludmila Glinskih +API tests [0] Communication ============= - -website Deby Barbara Lepage -fate.ffmpeg.org Timothy Gu -Trac bug tracker Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos -Patchwork Andriy Gelman -mailing lists Baptiste Coudurier +website (T: https://git.ffmpeg.org/ffmpeg-web) Deby Barbara Lepage +fate.ffmpeg.org (L: fate-admin@ffmpeg.org) (W: https://fate.ffmpeg.org) (P: https://ffmpeg.org/fate.html) (S: https://git.ffmpeg.org/fateserver) Timo Rothenpieler +Trac bug tracker (W: https://trac.ffmpeg.org) Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos +Patchwork [2] (W: https://patchwork.ffmpeg.org) Andriy Gelman +mailing lists (W: https://ffmpeg.org/contact.html#MailingLists) Baptiste Coudurier Twitter Reynaldo H. Verdejo Pinochet Launchpad Timothy Gu -ffmpeg-security Andreas Cadhalpun, Carl Eugen Hoyos, Clément Bœsch, Michael Niedermayer, Reimar Doeffinger, rcombs, wm4 +ffmpeg-security [2] (L: ffmpeg-security@ffmpeg.org) (W: https://ffmpeg.org/security.html) Michael Niedermayer, Reimar Doeffinger libavutil @@ -69,22 +84,22 @@ Other: bswap.h des Reimar Doeffinger dynarray.h Nicolas George - eval.c, eval.h Michael Niedermayer + eval.c, eval.h [2] Michael Niedermayer float_dsp Loren Merritt hash Reimar Doeffinger hwcontext_cuda* Timo Rothenpieler - hwcontext_vulkan* Lynne + hwcontext_vulkan* [2] Lynne intfloat* Michael Niedermayer integer.c, integer.h Michael Niedermayer lzo Reimar Doeffinger - mathematics.c, mathematics.h Michael Niedermayer - mem.c, mem.h Michael Niedermayer + mathematics.c, mathematics.h [2] Michael Niedermayer + mem.c, mem.h [2] Michael Niedermayer opencl.c, opencl.h Wei Gao opt.c, opt.h Michael Niedermayer - rational.c, rational.h Michael Niedermayer + rational.c, rational.h [2] Michael Niedermayer rc4 Reimar Doeffinger ripemd.c, ripemd.h James Almer - tx* Lynne + tx* [2] Lynne libavcodec @@ -106,20 +121,20 @@ Generic Parts: DSP utilities: dsputils.c, dsputils.h Michael Niedermayer entropy coding: - rangecoder.c, rangecoder.h Michael Niedermayer + rangecoder.c, rangecoder.h [2] Michael Niedermayer lzw.* Michael Niedermayer floating point AAN DCT: - faandct.c, faandct.h Michael Niedermayer + faandct.c, faandct.h [2] Michael Niedermayer Golomb coding: - golomb.c, golomb.h Michael Niedermayer + golomb.c, golomb.h [2] Michael Niedermayer motion estimation: motion* Michael Niedermayer rate control: - ratecontrol.c Michael Niedermayer + ratecontrol.c [2] Michael Niedermayer simple IDCT: - simple_idct.c, simple_idct.h Michael Niedermayer + simple_idct.c, simple_idct.h [2] Michael Niedermayer postprocessing: - libpostproc/* Michael Niedermayer + libpostproc/* [2] Michael Niedermayer table generation: tableprint.c, tableprint.h Reimar Doeffinger fixed point FFT: @@ -127,7 +142,7 @@ Generic Parts: Text Subtitles Clément Bœsch Codecs: - 4xm.c Michael Niedermayer + 4xm.c [2] Michael Niedermayer 8bps.c Roberto Togni 8svx.c Jaikrishnan Menon aacenc*, aaccoder.c Rostislav Pehlivanov @@ -163,7 +178,7 @@ Codecs: dvbsubdec.c Anshul Maheshwari eacmv*, eaidct*, eat* Peter Ross exif.c, exif.h Thilo Borgmann - ffv1* Michael Niedermayer + ffv1* [2] Michael Niedermayer ffwavesynth.c Nicolas George fifo.c Jan Sebechlebsky flicvideo.c Mike Melanson @@ -174,6 +189,7 @@ Codecs: h263* Michael Niedermayer h264* Loren Merritt, Michael Niedermayer hap* Tom Butterworth + hevc/* Anton Khirnov huffyuv* Michael Niedermayer idcinvideo.c Mike Melanson interplayvideo.c Mike Melanson @@ -250,7 +266,7 @@ Codecs: vp8 David Conrad, Ronald Bultje vp9 Ronald Bultje vqavideo.c Mike Melanson - vvc Nuo Mi + vvc [2] Nuo Mi wmaprodec.c Sascha Sommer wmavoice.c Ronald S. Bultje wmv2.c Michael Niedermayer @@ -260,6 +276,7 @@ Codecs: Hardware acceleration: dxva2* Hendrik Leppkes, Laurent Aimar, Steve Lhomme d3d11va* Steve Lhomme + d3d12va_encode* Tong Wu mediacodec* Matthieu Bouron, Aman Gupta, Zhao Zhili vaapi* Haihao Xiang vaapi_encode* Mark Thompson, Haihao Xiang @@ -324,12 +341,13 @@ Filters: vf_mestimate.c Davinder Singh vf_minterpolate.c Davinder Singh vf_readvitc.c Tobias Rapp (CC t.rapp at noa-archive dot com) - vf_scale.c Michael Niedermayer + vf_scale.c [2] Michael Niedermayer vf_tonemap_opencl.c Ruiling Song - vf_yadif.c Michael Niedermayer + vf_yadif.c [2] Michael Niedermayer + vf_xfade_vulkan.c [2] Marvin Scholz (CC ) Sources: - vsrc_mandelbrot.c Michael Niedermayer + vsrc_mandelbrot.c [2] Michael Niedermayer dnn Yejun Guo @@ -347,7 +365,7 @@ Generic parts: Muxers/Demuxers: 4xm.c Mike Melanson aadec.c Vesselin Bontchev (vesselin.bontchev at yandex dot com) - adtsenc.c Robert Swain + adtsenc.c [0] aiffdec.c Baptiste Coudurier, Matthieu Bouron aiffenc.c Baptiste Coudurier, Matthieu Bouron alp.c Zane van Iperen @@ -383,6 +401,7 @@ Muxers/Demuxers: gxf.c Reimar Doeffinger gxfenc.c Baptiste Coudurier hlsenc.c Christian Suloway, Steven Liu + iamf* [2] James Almer idcin.c Mike Melanson idroqdec.c Mike Melanson iff.c Jaikrishnan Menon @@ -397,9 +416,9 @@ Muxers/Demuxers: libopenmpt.c Josh de Kock lmlm4.c Ivo van Poorten lxfdec.c Tomas Härdin - matroska.c Aurelien Jacobs, Andreas Rheinhardt - matroskadec.c Aurelien Jacobs, Andreas Rheinhardt - matroskaenc.c David Conrad, Andreas Rheinhardt + matroska.c Andreas Rheinhardt + matroskadec.c Andreas Rheinhardt + matroskaenc.c Andreas Rheinhardt matroska subtitles (matroskaenc.c) John Peebles metadata* Aurelien Jacobs microdvd* Aurelien Jacobs @@ -468,33 +487,34 @@ Protocols: libzmq.c Andriy Gelman mms*.c Ronald S. Bultje udp.c Luca Abeni - icecast.c Marvin Scholz + icecast.c [2] Marvin Scholz (CC ) libswresample ============= Generic parts: - audioconvert.c Michael Niedermayer - dither.c Michael Niedermayer - rematrix*.c Michael Niedermayer - swresample*.c Michael Niedermayer + audioconvert.c [2] Michael Niedermayer + dither.c [2] Michael Niedermayer + rematrix*.c [2] Michael Niedermayer + swresample*.c [2] Michael Niedermayer Resamplers: - resample*.c Michael Niedermayer + resample*.c [2] Michael Niedermayer soxr_resample.c Rob Sykes Operating systems / CPU architectures ===================================== -Alpha Falk Hueffner +*BSD [2] Brad Smith +Alpha [0] MIPS Manojkumar Bhosale, Shiyou Yin -LoongArch Shiyou Yin -Mac OS X / PowerPC Romain Dolbeau, Guillaume Poirier +LoongArch [2] Shiyou Yin +Mac OS X / PowerPC [0] Amiga / PowerPC Colin Ward -Linux / PowerPC Lauri Kasanen -RISC-V Rémi Denis-Courmont +Linux / PowerPC [1] Lauri Kasanen +RISC-V [2] Rémi Denis-Courmont Windows MinGW Alex Beregszaszi, Ramiro Polla Windows Cygwin Victor Paesa Windows MSVC Hendrik Leppkes @@ -513,6 +533,7 @@ Benjamin Larsson Bobby Bingham Daniel Verkamp Derek Buitenhuis +Fei Wang Ganesh Ajjanagadde Henrik Gramner Ivan Uskov diff --git a/Makefile b/Makefile index b309dbc4d..b350d7748 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,9 @@ $(TOOLS): %$(EXESUF): %.o target_dec_%_fuzzer$(EXESUF): target_dec_%_fuzzer.o $(FF_DEP_LIBS) $(LD) $(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) + tools/target_bsf_%_fuzzer$(EXESUF): tools/target_bsf_%_fuzzer.o $(FF_DEP_LIBS) $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) @@ -67,6 +70,8 @@ tools/target_io_dem_fuzzer$(EXESUF): tools/target_io_dem_fuzzer.o $(FF_DEP_LIBS) tools/target_sws_fuzzer$(EXESUF): tools/target_sws_fuzzer.o $(FF_DEP_LIBS) $(LD) $(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) tools/enum_options$(EXESUF): ELIBS = $(FF_EXTRALIBS) tools/enum_options$(EXESUF): $(FF_DEP_LIBS) @@ -98,7 +103,7 @@ SUBDIR_VARS := CLEANFILES FFLIBS HOSTPROGS TESTPROGS TOOLS \ ARMV5TE-OBJS ARMV6-OBJS ARMV8-OBJS VFP-OBJS NEON-OBJS \ ALTIVEC-OBJS VSX-OBJS MMX-OBJS X86ASM-OBJS \ MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSP-OBJS MSA-OBJS \ - MMI-OBJS LSX-OBJS LASX-OBJS RV-OBJS RVV-OBJS \ + MMI-OBJS LSX-OBJS LASX-OBJS RV-OBJS RVV-OBJS RVVB-OBJS \ OBJS SLIBOBJS SHLIBOBJS STLIBOBJS HOSTOBJS TESTOBJS define RESET diff --git a/RELEASE b/RELEASE index a8907c025..21c8c7b46 100644 --- a/RELEASE +++ b/RELEASE @@ -1 +1 @@ -7.0.2 +7.1.1 diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 93bcf7d5b..851701a73 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,10 +1,10 @@ - ┌─────────────────────────────────────────┐ - │ RELEASE NOTES for FFmpeg 7.0 "Dijkstra" │ - └─────────────────────────────────────────┘ + ┌──────────────────────────────────────┐ + │ RELEASE NOTES for FFmpeg 7.1 "Péter" │ + └──────────────────────────────────────┘ - The FFmpeg Project proudly presents FFmpeg 7.0 "Dijkstra", about 6 - months after the release of FFmpeg 6.1. + The FFmpeg Project proudly presents FFmpeg 7.1 "Péter", about 6 + months after the release of FFmpeg 7.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 a8907c025..21c8c7b46 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.2 +7.1.1 diff --git a/compat/atomics/gcc/stdatomic.h b/compat/atomics/gcc/stdatomic.h deleted file mode 100644 index e13ed0e06..000000000 --- a/compat/atomics/gcc/stdatomic.h +++ /dev/null @@ -1,173 +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 - */ - -/* - * based on vlc_atomic.h from VLC - * Copyright (C) 2010 Rémi Denis-Courmont - */ - -#ifndef COMPAT_ATOMICS_GCC_STDATOMIC_H -#define COMPAT_ATOMICS_GCC_STDATOMIC_H - -#include -#include - -#define ATOMIC_FLAG_INIT 0 - -#define ATOMIC_VAR_INIT(value) (value) - -#define atomic_init(obj, value) \ -do { \ - *(obj) = (value); \ -} while(0) - -#define kill_dependency(y) ((void)0) - -#define atomic_thread_fence(order) \ - __sync_synchronize() - -#define atomic_signal_fence(order) \ - ((void)0) - -#define atomic_is_lock_free(obj) 0 - -typedef _Bool atomic_flag; -typedef _Bool atomic_bool; -typedef char atomic_char; -typedef signed char atomic_schar; -typedef unsigned char atomic_uchar; -typedef short atomic_short; -typedef unsigned short atomic_ushort; -typedef int atomic_int; -typedef unsigned int atomic_uint; -typedef long atomic_long; -typedef unsigned long atomic_ulong; -typedef long long atomic_llong; -typedef unsigned long long atomic_ullong; -typedef wchar_t atomic_wchar_t; -typedef int_least8_t atomic_int_least8_t; -typedef uint_least8_t atomic_uint_least8_t; -typedef int_least16_t atomic_int_least16_t; -typedef uint_least16_t atomic_uint_least16_t; -typedef int_least32_t atomic_int_least32_t; -typedef uint_least32_t atomic_uint_least32_t; -typedef int_least64_t atomic_int_least64_t; -typedef uint_least64_t atomic_uint_least64_t; -typedef int_fast8_t atomic_int_fast8_t; -typedef uint_fast8_t atomic_uint_fast8_t; -typedef int_fast16_t atomic_int_fast16_t; -typedef uint_fast16_t atomic_uint_fast16_t; -typedef int_fast32_t atomic_int_fast32_t; -typedef uint_fast32_t atomic_uint_fast32_t; -typedef int_fast64_t atomic_int_fast64_t; -typedef uint_fast64_t atomic_uint_fast64_t; -typedef intptr_t atomic_intptr_t; -typedef uintptr_t atomic_uintptr_t; -typedef size_t atomic_size_t; -typedef ptrdiff_t atomic_ptrdiff_t; -typedef intmax_t atomic_intmax_t; -typedef uintmax_t atomic_uintmax_t; - -#define atomic_store(object, desired) \ -do { \ - *(object) = (desired); \ - __sync_synchronize(); \ -} while (0) - -#define atomic_store_explicit(object, desired, order) \ - atomic_store(object, desired) - -#define atomic_load(object) \ - (__sync_synchronize(), *(object)) - -#define atomic_load_explicit(object, order) \ - atomic_load(object) - -#define atomic_exchange(object, desired) \ -({ \ - __typeof__(object) _obj = (object); \ - __typeof__(*object) _old; \ - do \ - _old = atomic_load(_obj); \ - while (!__sync_bool_compare_and_swap(_obj, _old, (desired))); \ - _old; \ -}) - -#define atomic_exchange_explicit(object, desired, order) \ - atomic_exchange(object, desired) - -#define atomic_compare_exchange_strong(object, expected, desired) \ -({ \ - __typeof__(object) _exp = (expected); \ - __typeof__(*object) _old = *_exp; \ - *_exp = __sync_val_compare_and_swap((object), _old, (desired)); \ - *_exp == _old; \ -}) - -#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_strong(object, expected, desired) - -#define atomic_compare_exchange_weak(object, expected, desired) \ - atomic_compare_exchange_strong(object, expected, desired) - -#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_weak(object, expected, desired) - -#define atomic_fetch_add(object, operand) \ - __sync_fetch_and_add(object, operand) - -#define atomic_fetch_add_explicit(object, operand, order) \ - atomic_fetch_add(object, operand) - -#define atomic_fetch_sub(object, operand) \ - __sync_fetch_and_sub(object, operand) - -#define atomic_fetch_sub_explicit(object, operand, order) \ - atomic_fetch_sub(object, operand) - -#define atomic_fetch_or(object, operand) \ - __sync_fetch_and_or(object, operand) - -#define atomic_fetch_or_explicit(object, operand, order) \ - atomic_fetch_or(object, operand) - -#define atomic_fetch_xor(object, operand) \ - __sync_fetch_and_xor(object, operand) - -#define atomic_fetch_xor_explicit(object, operand, order) \ - atomic_fetch_xor(object, operand) - -#define atomic_fetch_and(object, operand) \ - __sync_fetch_and_and(object, operand) - -#define atomic_fetch_and_explicit(object, operand, order) \ - atomic_fetch_and(object, operand) - -#define atomic_flag_test_and_set(object) \ - atomic_exchange(object, 1) - -#define atomic_flag_test_and_set_explicit(object, order) \ - atomic_flag_test_and_set(object) - -#define atomic_flag_clear(object) \ - atomic_store(object, 0) - -#define atomic_flag_clear_explicit(object, order) \ - atomic_flag_clear(object) - -#endif /* COMPAT_ATOMICS_GCC_STDATOMIC_H */ diff --git a/compat/atomics/pthread/stdatomic.h b/compat/atomics/pthread/stdatomic.h deleted file mode 100644 index 81a60f102..000000000 --- a/compat/atomics/pthread/stdatomic.h +++ /dev/null @@ -1,197 +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 - */ - -/* - * based on vlc_atomic.h from VLC - * Copyright (C) 2010 Rémi Denis-Courmont - */ - -#ifndef COMPAT_ATOMICS_PTHREAD_STDATOMIC_H -#define COMPAT_ATOMICS_PTHREAD_STDATOMIC_H - -#include - -#define ATOMIC_FLAG_INIT 0 - -#define ATOMIC_VAR_INIT(value) (value) - -#define atomic_init(obj, value) \ -do { \ - *(obj) = (value); \ -} while(0) - -#define kill_dependency(y) ((void)0) - -#define atomic_signal_fence(order) \ - ((void)0) - -#define atomic_is_lock_free(obj) 0 - -typedef intptr_t atomic_flag; -typedef intptr_t atomic_bool; -typedef intptr_t atomic_char; -typedef intptr_t atomic_schar; -typedef intptr_t atomic_uchar; -typedef intptr_t atomic_short; -typedef intptr_t atomic_ushort; -typedef intptr_t atomic_int; -typedef intptr_t atomic_uint; -typedef intptr_t atomic_long; -typedef intptr_t atomic_ulong; -typedef intptr_t atomic_llong; -typedef intptr_t atomic_ullong; -typedef intptr_t atomic_wchar_t; -typedef intptr_t atomic_int_least8_t; -typedef intptr_t atomic_uint_least8_t; -typedef intptr_t atomic_int_least16_t; -typedef intptr_t atomic_uint_least16_t; -typedef intptr_t atomic_int_least32_t; -typedef intptr_t atomic_uint_least32_t; -typedef intptr_t atomic_int_least64_t; -typedef intptr_t atomic_uint_least64_t; -typedef intptr_t atomic_int_fast8_t; -typedef intptr_t atomic_uint_fast8_t; -typedef intptr_t atomic_int_fast16_t; -typedef intptr_t atomic_uint_fast16_t; -typedef intptr_t atomic_int_fast32_t; -typedef intptr_t atomic_uint_fast32_t; -typedef intptr_t atomic_int_fast64_t; -typedef intptr_t atomic_uint_fast64_t; -typedef intptr_t atomic_intptr_t; -typedef intptr_t atomic_uintptr_t; -typedef intptr_t atomic_size_t; -typedef intptr_t atomic_ptrdiff_t; -typedef intptr_t atomic_intmax_t; -typedef intptr_t atomic_uintmax_t; - -void avpriv_atomic_lock(void); -void avpriv_atomic_unlock(void); - -static inline void atomic_thread_fence(int order) -{ - avpriv_atomic_lock(); - avpriv_atomic_unlock(); -} - -static inline void atomic_store(intptr_t *object, intptr_t desired) -{ - avpriv_atomic_lock(); - *object = desired; - avpriv_atomic_unlock(); -} - -#define atomic_store_explicit(object, desired, order) \ - atomic_store(object, desired) - -static inline intptr_t atomic_load(intptr_t *object) -{ - intptr_t ret; - avpriv_atomic_lock(); - ret = *object; - avpriv_atomic_unlock(); - return ret; -} - -#define atomic_load_explicit(object, order) \ - atomic_load(object) - -static inline intptr_t atomic_exchange(intptr_t *object, intptr_t desired) -{ - intptr_t ret; - avpriv_atomic_lock(); - ret = *object; - *object = desired; - avpriv_atomic_unlock(); - return ret; -} - -#define atomic_exchange_explicit(object, desired, order) \ - atomic_exchange(object, desired) - -static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected, - intptr_t desired) -{ - int ret; - avpriv_atomic_lock(); - if (*object == *expected) { - ret = 1; - *object = desired; - } else { - ret = 0; - *expected = *object; - } - avpriv_atomic_unlock(); - return ret; -} - -#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_strong(object, expected, desired) - -#define atomic_compare_exchange_weak(object, expected, desired) \ - atomic_compare_exchange_strong(object, expected, desired) - -#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_weak(object, expected, desired) - -#define FETCH_MODIFY(opname, op) \ -static inline intptr_t atomic_fetch_ ## opname(intptr_t *object, intptr_t operand) \ -{ \ - intptr_t ret; \ - avpriv_atomic_lock(); \ - ret = *object; \ - *object = *object op operand; \ - avpriv_atomic_unlock(); \ - return ret; \ -} - -FETCH_MODIFY(add, +) -FETCH_MODIFY(sub, -) -FETCH_MODIFY(or, |) -FETCH_MODIFY(xor, ^) -FETCH_MODIFY(and, &) - -#undef FETCH_MODIFY - -#define atomic_fetch_add_explicit(object, operand, order) \ - atomic_fetch_add(object, operand) - -#define atomic_fetch_sub_explicit(object, operand, order) \ - atomic_fetch_sub(object, operand) - -#define atomic_fetch_or_explicit(object, operand, order) \ - atomic_fetch_or(object, operand) - -#define atomic_fetch_xor_explicit(object, operand, order) \ - atomic_fetch_xor(object, operand) - -#define atomic_fetch_and_explicit(object, operand, order) \ - atomic_fetch_and(object, operand) - -#define atomic_flag_test_and_set(object) \ - atomic_exchange(object, 1) - -#define atomic_flag_test_and_set_explicit(object, order) \ - atomic_flag_test_and_set(object) - -#define atomic_flag_clear(object) \ - atomic_store(object, 0) - -#define atomic_flag_clear_explicit(object, order) \ - atomic_flag_clear(object) - -#endif /* COMPAT_ATOMICS_PTHREAD_STDATOMIC_H */ diff --git a/compat/atomics/suncc/stdatomic.h b/compat/atomics/suncc/stdatomic.h deleted file mode 100644 index 0cf89e0f7..000000000 --- a/compat/atomics/suncc/stdatomic.h +++ /dev/null @@ -1,186 +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 COMPAT_ATOMICS_SUNCC_STDATOMIC_H -#define COMPAT_ATOMICS_SUNCC_STDATOMIC_H - -#include -#include -#include -#include - -#define ATOMIC_FLAG_INIT 0 - -#define ATOMIC_VAR_INIT(value) (value) - -#define atomic_init(obj, value) \ -do { \ - *(obj) = (value); \ -} while(0) - -#define kill_dependency(y) ((void)0) - -#define atomic_thread_fence(order) \ - __machine_rw_barrier(); - -#define atomic_signal_fence(order) \ - ((void)0) - -#define atomic_is_lock_free(obj) 0 - -typedef intptr_t atomic_flag; -typedef intptr_t atomic_bool; -typedef intptr_t atomic_char; -typedef intptr_t atomic_schar; -typedef intptr_t atomic_uchar; -typedef intptr_t atomic_short; -typedef intptr_t atomic_ushort; -typedef intptr_t atomic_int; -typedef intptr_t atomic_uint; -typedef intptr_t atomic_long; -typedef intptr_t atomic_ulong; -typedef intptr_t atomic_llong; -typedef intptr_t atomic_ullong; -typedef intptr_t atomic_wchar_t; -typedef intptr_t atomic_int_least8_t; -typedef intptr_t atomic_uint_least8_t; -typedef intptr_t atomic_int_least16_t; -typedef intptr_t atomic_uint_least16_t; -typedef intptr_t atomic_int_least32_t; -typedef intptr_t atomic_uint_least32_t; -typedef intptr_t atomic_int_least64_t; -typedef intptr_t atomic_uint_least64_t; -typedef intptr_t atomic_int_fast8_t; -typedef intptr_t atomic_uint_fast8_t; -typedef intptr_t atomic_int_fast16_t; -typedef intptr_t atomic_uint_fast16_t; -typedef intptr_t atomic_int_fast32_t; -typedef intptr_t atomic_uint_fast32_t; -typedef intptr_t atomic_int_fast64_t; -typedef intptr_t atomic_uint_fast64_t; -typedef intptr_t atomic_intptr_t; -typedef intptr_t atomic_uintptr_t; -typedef intptr_t atomic_size_t; -typedef intptr_t atomic_ptrdiff_t; -typedef intptr_t atomic_intmax_t; -typedef intptr_t atomic_uintmax_t; - -static inline void atomic_store(intptr_t *object, intptr_t desired) -{ - *object = desired; - __machine_rw_barrier(); -} - -#define atomic_store_explicit(object, desired, order) \ - atomic_store(object, desired) - -static inline intptr_t atomic_load(intptr_t *object) -{ - __machine_rw_barrier(); - return *object; -} - -#define atomic_load_explicit(object, order) \ - atomic_load(object) - -#define atomic_exchange(object, desired) \ - atomic_swap_ptr(object, desired) - -#define atomic_exchange_explicit(object, desired, order) \ - atomic_exchange(object, desired) - -static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected, - intptr_t desired) -{ - intptr_t old = *expected; - *expected = (intptr_t)atomic_cas_ptr(object, (void *)old, (void *)desired); - return *expected == old; -} - -#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_strong(object, expected, desired) - -#define atomic_compare_exchange_weak(object, expected, desired) \ - atomic_compare_exchange_strong(object, expected, desired) - -#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_weak(object, expected, desired) - -static inline intptr_t atomic_fetch_add(intptr_t *object, intptr_t operand) -{ - return atomic_add_ptr_nv(object, operand) - operand; -} - -#define atomic_fetch_sub(object, operand) \ - atomic_fetch_add(object, -(operand)) - -static inline intptr_t atomic_fetch_or(intptr_t *object, intptr_t operand) -{ - intptr_t old; - do { - old = atomic_load(object); - } while (!atomic_compare_exchange_strong(object, old, old | operand)); - return old; -} - -static inline intptr_t atomic_fetch_xor(intptr_t *object, intptr_t operand) -{ - intptr_t old; - do { - old = atomic_load(object); - } while (!atomic_compare_exchange_strong(object, old, old ^ operand)); - return old; -} - -static inline intptr_t atomic_fetch_and(intptr_t *object, intptr_t operand) -{ - intptr_t old; - do { - old = atomic_load(object); - } while (!atomic_compare_exchange_strong(object, old, old & operand)); - return old; -} - -#define atomic_fetch_add_explicit(object, operand, order) \ - atomic_fetch_add(object, operand) - -#define atomic_fetch_sub_explicit(object, operand, order) \ - atomic_fetch_sub(object, operand) - -#define atomic_fetch_or_explicit(object, operand, order) \ - atomic_fetch_or(object, operand) - -#define atomic_fetch_xor_explicit(object, operand, order) \ - atomic_fetch_xor(object, operand) - -#define atomic_fetch_and_explicit(object, operand, order) \ - atomic_fetch_and(object, operand) - -#define atomic_flag_test_and_set(object) \ - atomic_exchange(object, 1) - -#define atomic_flag_test_and_set_explicit(object, order) \ - atomic_flag_test_and_set(object) - -#define atomic_flag_clear(object) \ - atomic_store(object, 0) - -#define atomic_flag_clear_explicit(object, order) \ - atomic_flag_clear(object) - -#endif /* COMPAT_ATOMICS_SUNCC_STDATOMIC_H */ diff --git a/compat/stdbit/stdbit.h b/compat/stdbit/stdbit.h new file mode 100644 index 000000000..53419cf9f --- /dev/null +++ b/compat/stdbit/stdbit.h @@ -0,0 +1,599 @@ +/* + * Copyright (C) 2023 Rémi Denis-Courmont + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + */ + +#ifndef __STDC_VERSION_STDBIT_H__ +#define __STDC_VERSION_STDBIT_H__ 202311L + +#include +#include /* CHAR_BIT */ + +#define __STDC_ENDIAN_LITTLE__ 1234 +#define __STDC_ENDIAN_BIG__ 4321 + +#ifdef __BYTE_ORDER__ +# if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_LITTLE__ +# elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_BIG__ +# else +# define __STDC_ENDIAN_NATIVE__ 3412 +# endif +#elif defined(_MSC_VER) +# define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_LITTLE__ +#else +# error Not implemented. +#endif + +#define __stdbit_generic_type_func(func, value) \ + _Generic (value, \ + unsigned long long: stdc_##func##_ull((unsigned long long)(value)), \ + unsigned long: stdc_##func##_ul((unsigned long)(value)), \ + unsigned int: stdc_##func##_ui((unsigned int)(value)), \ + unsigned short: stdc_##func##_us((unsigned short)(value)), \ + unsigned char: stdc_##func##_uc((unsigned char)(value))) + +#if defined (__GNUC__) || defined (__clang__) +static inline unsigned int stdc_leading_zeros_ull(unsigned long long value) +{ + return value ? __builtin_clzll(value) : (CHAR_BIT * sizeof (value)); +} + +static inline unsigned int stdc_leading_zeros_ul(unsigned long value) +{ + return value ? __builtin_clzl(value) : (CHAR_BIT * sizeof (value)); +} + +static inline unsigned int stdc_leading_zeros_ui(unsigned int value) +{ + return value ? __builtin_clz(value) : (CHAR_BIT * sizeof (value)); +} + +static inline unsigned int stdc_leading_zeros_us(unsigned short value) +{ + return stdc_leading_zeros_ui(value) + - CHAR_BIT * (sizeof (int) - sizeof (value)); +} + +static inline unsigned int stdc_leading_zeros_uc(unsigned char value) +{ + return stdc_leading_zeros_ui(value) - (CHAR_BIT * (sizeof (int) - 1)); +} +#else +static inline unsigned int __stdc_leading_zeros(unsigned long long value, + unsigned int size) +{ + unsigned int zeros = size * CHAR_BIT; + + while (value != 0) { + value >>= 1; + zeros--; + } + + return zeros; +} + +static inline unsigned int stdc_leading_zeros_ull(unsigned long long value) +{ + return __stdc_leading_zeros(value, sizeof (value)); +} + +static inline unsigned int stdc_leading_zeros_ul(unsigned long value) +{ + return __stdc_leading_zeros(value, sizeof (value)); +} + +static inline unsigned int stdc_leading_zeros_ui(unsigned int value) +{ + return __stdc_leading_zeros(value, sizeof (value)); +} + +static inline unsigned int stdc_leading_zeros_us(unsigned short value) +{ + return __stdc_leading_zeros(value, sizeof (value)); +} + +static inline unsigned int stdc_leading_zeros_uc(unsigned char value) +{ + return __stdc_leading_zeros(value, sizeof (value)); +} +#endif + +#define stdc_leading_zeros(value) \ + __stdbit_generic_type_func(leading_zeros, value) + +static inline unsigned int stdc_leading_ones_ull(unsigned long long value) +{ + return stdc_leading_zeros_ull(~value); +} + +static inline unsigned int stdc_leading_ones_ul(unsigned long value) +{ + return stdc_leading_zeros_ul(~value); +} + +static inline unsigned int stdc_leading_ones_ui(unsigned int value) +{ + return stdc_leading_zeros_ui(~value); +} + +static inline unsigned int stdc_leading_ones_us(unsigned short value) +{ + return stdc_leading_zeros_us(~value); +} + +static inline unsigned int stdc_leading_ones_uc(unsigned char value) +{ + return stdc_leading_zeros_uc(~value); +} + +#define stdc_leading_ones(value) \ + __stdbit_generic_type_func(leading_ones, value) + +#if defined (__GNUC__) || defined (__clang__) +static inline unsigned int stdc_trailing_zeros_ull(unsigned long long value) +{ + return value ? (unsigned int)__builtin_ctzll(value) + : (CHAR_BIT * sizeof (value)); +} + +static inline unsigned int stdc_trailing_zeros_ul(unsigned long value) +{ + return value ? (unsigned int)__builtin_ctzl(value) + : (CHAR_BIT * sizeof (value)); +} + +static inline unsigned int stdc_trailing_zeros_ui(unsigned int value) +{ + return value ? (unsigned int)__builtin_ctz(value) + : (CHAR_BIT * sizeof (value)); +} + +static inline unsigned int stdc_trailing_zeros_us(unsigned short value) +{ + return value ? (unsigned int)__builtin_ctz(value) + : (CHAR_BIT * sizeof (value)); +} + +static inline unsigned int stdc_trailing_zeros_uc(unsigned char value) +{ + return value ? (unsigned int)__builtin_ctz(value) + : (CHAR_BIT * sizeof (value)); +} +#else +static inline unsigned int __stdc_trailing_zeros(unsigned long long value, + unsigned int size) +{ + unsigned int zeros = 0; + + if (!value) + return size * CHAR_BIT; + + while ((value & 1) == 0) { + value >>= 1; + zeros++; + } + + return zeros; +} + +static inline unsigned int stdc_trailing_zeros_ull(unsigned long long value) +{ + return __stdc_trailing_zeros(value, sizeof (value)); +} + +static inline unsigned int stdc_trailing_zeros_ul(unsigned long value) +{ + return __stdc_trailing_zeros(value, sizeof (value)); +} + +static inline unsigned int stdc_trailing_zeros_ui(unsigned int value) +{ + return __stdc_trailing_zeros(value, sizeof (value)); +} + +static inline unsigned int stdc_trailing_zeros_us(unsigned short value) +{ + return __stdc_trailing_zeros(value, sizeof (value)); +} + +static inline unsigned int stdc_trailing_zeros_uc(unsigned char value) +{ + return __stdc_trailing_zeros(value, sizeof (value)); +} +#endif + +#define stdc_trailing_zeros(value) \ + __stdbit_generic_type_func(trailing_zeros, value) + +static inline unsigned int stdc_trailing_ones_ull(unsigned long long value) +{ + return stdc_trailing_zeros_ull(~value); +} + +static inline unsigned int stdc_trailing_ones_ul(unsigned long value) +{ + return stdc_trailing_zeros_ul(~value); +} + +static inline unsigned int stdc_trailing_ones_ui(unsigned int value) +{ + return stdc_trailing_zeros_ui(~value); +} + +static inline unsigned int stdc_trailing_ones_us(unsigned short value) +{ + return stdc_trailing_zeros_us(~value); +} + +static inline unsigned int stdc_trailing_ones_uc(unsigned char value) +{ + return stdc_trailing_zeros_uc(~value); +} + +#define stdc_trailing_ones(value) \ + __stdbit_generic_type_func(trailing_ones, value) + +static inline unsigned int stdc_first_leading_one_ull(unsigned long long value) +{ + return value ? (stdc_leading_zeros_ull(value) + 1) : 0; +} + +static inline unsigned int stdc_first_leading_one_ul(unsigned long value) +{ + return value ? (stdc_leading_zeros_ul(value) + 1) : 0; +} + +static inline unsigned int stdc_first_leading_one_ui(unsigned int value) +{ + return value ? (stdc_leading_zeros_ui(value) + 1) : 0; +} + +static inline unsigned int stdc_first_leading_one_us(unsigned short value) +{ + return value ? (stdc_leading_zeros_us(value) + 1) : 0; +} + +static inline unsigned int stdc_first_leading_one_uc(unsigned char value) +{ + return value ? (stdc_leading_zeros_uc(value) + 1) : 0; +} + +#define stdc_first_leading_one(value) \ + __stdbit_generic_type_func(first_leading_one, value) + +static inline unsigned int stdc_first_leading_zero_ull(unsigned long long value) +{ + return stdc_leading_ones_ull(~value); +} + +static inline unsigned int stdc_first_leading_zero_ul(unsigned long value) +{ + return stdc_leading_ones_ul(~value); +} + +static inline unsigned int stdc_first_leading_zero_ui(unsigned int value) +{ + return stdc_leading_ones_ui(~value); +} + +static inline unsigned int stdc_first_leading_zero_us(unsigned short value) +{ + return stdc_leading_ones_us(~value); +} + +static inline unsigned int stdc_first_leading_zero_uc(unsigned char value) +{ + return stdc_leading_ones_uc(~value); +} + +#define stdc_first_leading_zero(value) \ + __stdbit_generic_type_func(first_leading_zero, value) + +#if defined (__GNUC__) || defined (__clang__) +static inline unsigned int stdc_first_trailing_one_ull(unsigned long long value) +{ + return __builtin_ffsll(value); +} + +static inline unsigned int stdc_first_trailing_one_ul(unsigned long value) +{ + return __builtin_ffsl(value); +} + +static inline unsigned int stdc_first_trailing_one_ui(unsigned int value) +{ + return __builtin_ffs(value); +} + +static inline unsigned int stdc_first_trailing_one_us(unsigned short value) +{ + return __builtin_ffs(value); +} + +static inline unsigned int stdc_first_trailing_one_uc(unsigned char value) +{ + return __builtin_ffs(value); +} +#else +static inline unsigned int stdc_first_trailing_one_ull(unsigned long long value) +{ + return value ? (1 + stdc_trailing_zeros_ull(value)) : 0; +} + +static inline unsigned int stdc_first_trailing_one_ul(unsigned long value) +{ + return value ? (1 + stdc_trailing_zeros_ul(value)) : 0; +} + +static inline unsigned int stdc_first_trailing_one_ui(unsigned int value) +{ + return value ? (1 + stdc_trailing_zeros_ui(value)) : 0; +} + +static inline unsigned int stdc_first_trailing_one_us(unsigned short value) +{ + return value ? (1 + stdc_trailing_zeros_us(value)) : 0; +} + +static inline unsigned int stdc_first_trailing_one_uc(unsigned char value) +{ + return value ? (1 + stdc_trailing_zeros_uc(value)) : 0; +} +#endif + +#define stdc_first_trailing_one(value) \ + __stdbit_generic_type_func(first_trailing_one, value) + +static inline unsigned int stdc_first_trailing_zero_ull(unsigned long long value) +{ + return stdc_first_trailing_one_ull(~value); +} + +static inline unsigned int stdc_first_trailing_zero_ul(unsigned long value) +{ + return stdc_first_trailing_one_ul(~value); +} + +static inline unsigned int stdc_first_trailing_zero_ui(unsigned int value) +{ + return stdc_first_trailing_one_ui(~value); +} + +static inline unsigned int stdc_first_trailing_zero_us(unsigned short value) +{ + return stdc_first_trailing_one_us(~value); +} + +static inline unsigned int stdc_first_trailing_zero_uc(unsigned char value) +{ + return stdc_first_trailing_one_uc(~value); +} + +#define stdc_first_trailing_zero(value) \ + __stdbit_generic_type_func(first_trailing_zero, value) + +#if defined (__GNUC__) || defined (__clang__) +static inline unsigned int stdc_count_ones_ull(unsigned long long value) +{ + return __builtin_popcountll(value); +} + +static inline unsigned int stdc_count_ones_ul(unsigned long value) +{ + return __builtin_popcountl(value); +} + +static inline unsigned int stdc_count_ones_ui(unsigned int value) +{ + return __builtin_popcount(value); +} + +static inline unsigned int stdc_count_ones_us(unsigned short value) +{ + return __builtin_popcount(value); +} + +static inline unsigned int stdc_count_ones_uc(unsigned char value) +{ + return __builtin_popcount(value); +} +#else +static inline unsigned int __stdc_count_ones(unsigned long long value, + unsigned int size) +{ + unsigned int ones = 0; + + for (unsigned int c = 0; c < (size * CHAR_BIT); c++) { + ones += value & 1; + value >>= 1; + } + + return ones; +} + +static inline unsigned int stdc_count_ones_ull(unsigned long long value) +{ + return __stdc_count_ones(value, sizeof (value)); +} + +static inline unsigned int stdc_count_ones_ul(unsigned long value) +{ + return __stdc_count_ones(value, sizeof (value)); +} + +static inline unsigned int stdc_count_ones_ui(unsigned int value) +{ + return __stdc_count_ones(value, sizeof (value)); +} + +static inline unsigned int stdc_count_ones_us(unsigned short value) +{ + return __stdc_count_ones(value, sizeof (value)); +} + +static inline unsigned int stdc_count_ones_uc(unsigned char value) +{ + return __stdc_count_ones(value, sizeof (value)); +} +#endif + +#define stdc_count_ones(value) \ + __stdbit_generic_type_func(count_ones, value) + +static inline unsigned int stdc_count_zeros_ull(unsigned long long value) +{ + return stdc_count_ones_ull(~value); +} + +static inline unsigned int stdc_count_zeros_ul(unsigned long value) +{ + return stdc_count_ones_ul(~value); +} + +static inline unsigned int stdc_count_zeros_ui(unsigned int value) +{ + return stdc_count_ones_ui(~value); +} + +static inline unsigned int stdc_count_zeros_us(unsigned short value) +{ + return stdc_count_ones_us(~value); +} + +static inline unsigned int stdc_count_zeros_uc(unsigned char value) +{ + return stdc_count_ones_uc(~value); +} + +#define stdc_count_zeros(value) \ + __stdbit_generic_type_func(count_zeros, value) + +static inline bool stdc_has_single_bit_ull(unsigned long long value) +{ + return value && (value & (value - 1)) == 0; +} + +static inline bool stdc_has_single_bit_ul(unsigned long value) +{ + return value && (value & (value - 1)) == 0; +} + +static inline bool stdc_has_single_bit_ui(unsigned int value) +{ + return value && (value & (value - 1)) == 0; +} + +static inline bool stdc_has_single_bit_us(unsigned short value) +{ + return value && (value & (value - 1)) == 0; +} + +static inline bool stdc_has_single_bit_uc(unsigned char value) +{ + return value && (value & (value - 1)) == 0; +} + +#define stdc_has_single_bit(value) \ + __stdbit_generic_type_func(has_single_bit, value) + +static inline unsigned int stdc_bit_width_ull(unsigned long long value) +{ + return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_ull(value); +} + +static inline unsigned int stdc_bit_width_ul(unsigned long value) +{ + return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_ul(value); +} + +static inline unsigned int stdc_bit_width_ui(unsigned int value) +{ + return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_ui(value); +} + +static inline unsigned int stdc_bit_width_us(unsigned short value) +{ + return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_us(value); +} + +static inline unsigned int stdc_bit_width_uc(unsigned char value) +{ + return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_uc(value); +} + +#define stdc_bit_width(value) \ + __stdbit_generic_type_func(bit_width, value) + +static inline unsigned long long stdc_bit_floor_ull(unsigned long long value) +{ + return value ? (1ULL << (stdc_bit_width_ull(value) - 1)) : 0ULL; +} + +static inline unsigned long stdc_bit_floor_ul(unsigned long value) +{ + return value ? (1UL << (stdc_bit_width_ul(value) - 1)) : 0UL; +} + +static inline unsigned int stdc_bit_floor_ui(unsigned int value) +{ + return value ? (1U << (stdc_bit_width_ui(value) - 1)) : 0U; +} + +static inline unsigned short stdc_bit_floor_us(unsigned short value) +{ + return value ? (1U << (stdc_bit_width_us(value) - 1)) : 0U; +} + +static inline unsigned int stdc_bit_floor_uc(unsigned char value) +{ + return value ? (1U << (stdc_bit_width_uc(value) - 1)) : 0U; +} + +#define stdc_bit_floor(value) \ + __stdbit_generic_type_func(bit_floor, value) + +/* NOTE: Bit ceiling undefines overflow. */ +static inline unsigned long long stdc_bit_ceil_ull(unsigned long long value) +{ + return 1ULL << (value ? stdc_bit_width_ull(value - 1) : 0); +} + +static inline unsigned long stdc_bit_ceil_ul(unsigned long value) +{ + return 1UL << (value ? stdc_bit_width_ul(value - 1) : 0); +} + +static inline unsigned int stdc_bit_ceil_ui(unsigned int value) +{ + return 1U << (value ? stdc_bit_width_ui(value - 1) : 0); +} + +static inline unsigned short stdc_bit_ceil_us(unsigned short value) +{ + return 1U << (value ? stdc_bit_width_us(value - 1) : 0); +} + +static inline unsigned int stdc_bit_ceil_uc(unsigned char value) +{ + return 1U << (value ? stdc_bit_width_uc(value - 1) : 0); +} + +#define stdc_bit_ceil(value) \ + __stdbit_generic_type_func(bit_ceil, value) + +#endif /* __STDC_VERSION_STDBIT_H__ */ diff --git a/compat/w32dlfcn.h b/compat/w32dlfcn.h index fb1aa1b72..ac20e83a7 100644 --- a/compat/w32dlfcn.h +++ b/compat/w32dlfcn.h @@ -26,6 +26,7 @@ #include "config.h" #include "libavutil/macros.h" +#include "libavutil/mem.h" #include "libavutil/wchar_filename.h" static inline wchar_t *get_module_filename(HMODULE module) diff --git a/configure b/configure index 86425130b..ffa407d53 100755 --- a/configure +++ b/configure @@ -140,6 +140,7 @@ Component options: --disable-error-resilience disable error resilience code --disable-lsp disable LSP code --disable-faan disable floating point AAN (I)DCT code + --disable-iamf disable support for Immersive Audio Model --disable-pixelutils disable pixel utils in libavutil Individual component options: @@ -244,6 +245,8 @@ External library support: --enable-libjxl enable JPEG XL de/encoding via libjxl [no] --enable-libklvanc enable Kernel Labs VANC processing [no] --enable-libkvazaar enable HEVC encoding via libkvazaar [no] + --enable-liblc3 enable LC3 de/encoding via liblc3 [no] + --enable-liblcevc-dec enable LCEVC decoding via liblcevc-dec [no] --enable-liblensfun enable lensfun lens correction [no] --enable-libmodplug enable ModPlug via libmodplug [no] --enable-libmp3lame enable MP3 encoding via libmp3lame [no] @@ -251,7 +254,7 @@ External library support: --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 de/encoding via OpenJPEG [no] + --enable-libopenjpeg enable JPEG 2000 encoding via OpenJPEG [no] --enable-libopenmpt enable decoding tracked files via libopenmpt [no] --enable-libopenvino enable OpenVINO as a DNN module backend for DNN based filters like dnn_processing [no] @@ -291,6 +294,7 @@ External library support: --enable-libvorbis enable Vorbis en/decoding via libvorbis, native implementation exists [no] --enable-libvpx enable VP8 and VP9 de/encoding via libvpx [no] + --enable-libvvenc enable H.266/VVC encoding via vvenc [no] --enable-libwebp enable WebP encoding via libwebp [no] --enable-libx264 enable H.264 encoding via x264 [no] --enable-libx265 enable HEVC encoding via x265 [no] @@ -1926,6 +1930,8 @@ EXTERNAL_LIBRARY_LIST=" libjxl libklvanc libkvazaar + liblc3 + liblcevc_dec libmodplug libmp3lame libmysofa @@ -1963,6 +1969,7 @@ EXTERNAL_LIBRARY_LIST=" libvmaf libvorbis libvpx + libvvenc libwebp libxevd libxeve @@ -2070,6 +2077,7 @@ SUBSYSTEM_LIST=" error_resilience faan fast_unaligned + iamf lsp pixelutils network @@ -2111,8 +2119,6 @@ THREADS_LIST=" " ATOMICS_LIST=" - atomics_gcc - atomics_suncc atomics_win32 " @@ -2124,12 +2130,7 @@ AUTODETECT_LIBS=" ARCH_LIST=" aarch64 - alpha arm - avr32 - avr32_ap - avr32_uc - bfin ia64 loongarch loongarch32 @@ -2142,7 +2143,6 @@ ARCH_LIST=" ppc64 riscv s390 - sh4 sparc sparc64 tilegx @@ -2218,6 +2218,8 @@ ARCH_EXT_LIST_PPC=" ARCH_EXT_LIST_RISCV=" rv rvv + rv_zicbop + rv_zvbb " ARCH_EXT_LIST_X86=" @@ -2247,13 +2249,10 @@ ARCH_FEATURES=" " BUILTIN_LIST=" - atomic_cas_ptr - machine_rw_barrier MemoryBarrier mm_empty rdtsc sem_timedwait - sync_val_compare_and_swap " HAVE_LIST_CMDLINE=" inline_asm @@ -2268,6 +2267,7 @@ HAVE_LIST_PUB=" HEADERS_LIST=" arpa_inet_h + asm_hwprobe_h asm_types_h cdio_paranoia_h cdio_paranoia_paranoia_h @@ -2294,6 +2294,7 @@ HEADERS_LIST=" OpenGL_gl3_h poll_h pthread_np_h + sys_hwprobe_h sys_param_h sys_resource_h sys_select_h @@ -2311,6 +2312,7 @@ HEADERS_LIST=" INTRINSICS_LIST=" intrinsics_neon + intrinsics_sse2 " MATH_FUNCS=" @@ -2362,6 +2364,7 @@ SYSTEM_FUNCS=" clock_gettime closesocket CommandLineToArgvW + elf_aux_info fcntl getaddrinfo getauxval @@ -2410,6 +2413,7 @@ SYSTEM_FUNCS=" sysconf sysctl sysctlbyname + tempnam usleep UTGetOSTypeFromString VirtualAlloc @@ -2485,6 +2489,7 @@ TYPES_LIST=" struct_sockaddr_storage struct_stat_st_mtim_tv_nsec struct_v4l2_frmivalenum_discrete + struct_mfxConfigInterface " HAVE_LIST=" @@ -2517,6 +2522,7 @@ HAVE_LIST=" opencl_videotoolbox perl pod2man + posix_ioctl texi2html xmllint zlib_gzip @@ -2543,10 +2549,12 @@ CONFIG_EXTRA=" cbs_mpeg2 cbs_vp8 cbs_vp9 + d3d12va_encode deflate_wrapper dirac_parse dnn - dovi_rpu + dovi_rpudec + dovi_rpuenc dvprofile evcparse exif @@ -2578,6 +2586,7 @@ CONFIG_EXTRA=" inflate_wrapper intrax8 iso_media + iso_writer ividsp jpegtables lgplv3 @@ -2627,6 +2636,7 @@ CONFIG_EXTRA=" vp3dsp vp56dsp vp8dsp + vulkan_encode wma_freqs wmv2dsp " @@ -2736,6 +2746,7 @@ armv6t2_deps="arm" armv8_deps="aarch64" neon_deps_any="aarch64 arm" intrinsics_neon_deps="neon" +intrinsics_sse2_deps="sse2" vfp_deps="arm" vfpv3_deps="vfp" setend_deps="arm" @@ -2753,6 +2764,8 @@ power8_deps="vsx" rv_deps="riscv" rvv_deps="rv" +rv_zicbop="riscv" +rv_zvbb_deps="rvv" loongson2_deps="mips" loongson3_deps="mips" @@ -2805,8 +2818,8 @@ for ext in $(filter_out mmx $ARCH_EXT_LIST_X86_SIMD); do done aligned_stack_if_any="aarch64 ppc x86" -fast_64bit_if_any="aarch64 alpha ia64 mips64 parisc64 ppc64 riscv64 sparc64 x86_64" -fast_clz_if_any="aarch64 alpha avr32 mips ppc x86" +fast_64bit_if_any="aarch64 ia64 mips64 parisc64 ppc64 riscv64 sparc64 x86_64" +fast_clz_if_any="aarch64 mips ppc x86" fast_unaligned_if_any="aarch64 ppc x86" simd_align_16_if_any="altivec neon sse" simd_align_32_if_any="avx" @@ -2819,8 +2832,6 @@ valgrind_backtrace_conflict="optimizations" valgrind_backtrace_deps="valgrind_valgrind_h" # threading support -atomics_gcc_if="sync_val_compare_and_swap" -atomics_suncc_if="atomic_cas_ptr machine_rw_barrier" atomics_win32_if="MemoryBarrier" atomics_native_if_any="$ATOMICS_LIST" w32threads_deps="atomics_native" @@ -2837,9 +2848,10 @@ cbs_vp8_select="cbs" cbs_vp9_select="cbs" deflate_wrapper_deps="zlib" dirac_parse_select="golomb" -dovi_rpu_select="golomb" -dnn_suggest="libtensorflow libopenvino libtorch" +dovi_rpudec_select="golomb" +dovi_rpuenc_select="golomb" dnn_deps="avformat swscale" +dnn_deps_any="libtensorflow libopenvino libtorch" error_resilience_select="me_cmp" evcparse_select="golomb" faandct_deps="faan" @@ -2847,11 +2859,14 @@ faandct_select="fdctdsp" faanidct_deps="faan" faanidct_select="idctdsp" h264dsp_select="startcode" +h264parse_select="golomb" h264_sei_select="atsc_a53 golomb" hevcparse_select="golomb" hevc_sei_select="atsc_a53 golomb" frame_thread_encoder_deps="encoders threads" +iamfdec_deps="iamf" iamfdec_select="iso_media mpeg4audio" +iamfenc_deps="iamf" inflate_wrapper_deps="zlib" intrax8_select="blockdsp wmv2dsp" iso_media_select="mpeg4audio" @@ -2864,6 +2879,7 @@ mpegvideoenc_select="aandcttables fdctdsp me_cmp mpegvideo pixblockdsp" msmpeg4dec_select="h263_decoder" msmpeg4enc_select="h263_encoder" vc1dsp_select="h264chroma qpeldsp startcode" +wmv2dsp_select="qpeldsp" # decoders / encoders aac_decoder_select="adts_header mpeg4audio sinewin" @@ -2895,7 +2911,9 @@ asv1_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" asv2_decoder_select="blockdsp bswapdsp idctdsp" asv2_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" atrac1_decoder_select="sinewin" -av1_decoder_select="atsc_a53 cbs_av1 dovi_rpu" +atrac3p_decoder_select="sinewin" +atrac3pal_decoder_select="sinewin" +av1_decoder_select="atsc_a53 cbs_av1 dovi_rpudec" bink_decoder_select="blockdsp hpeldsp" binkaudio_dct_decoder_select="wma_freqs" binkaudio_rdft_decoder_select="wma_freqs" @@ -2907,7 +2925,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 videodsp mpegvideoenc" +dirac_decoder_select="dirac_parse dwt golomb mpegvideoenc qpeldsp videodsp" dnxhd_decoder_select="blockdsp idctdsp" dnxhd_encoder_select="blockdsp fdctdsp idctdsp mpegvideoenc pixblockdsp videodsp" dvvideo_decoder_select="dvprofile idctdsp" @@ -2936,6 +2954,7 @@ flv_decoder_select="h263_decoder" flv_encoder_select="h263_encoder" fourxm_decoder_select="blockdsp bswapdsp" fraps_decoder_select="bswapdsp huffman" +ftr_decoder_select="adts_header" g2m_decoder_deps="zlib" g2m_decoder_select="blockdsp idctdsp jpegtables" g729_decoder_select="audiodsp" @@ -2951,7 +2970,7 @@ h264_decoder_suggest="error_resilience" hap_decoder_select="snappy texturedsp" hap_encoder_deps="libsnappy" hap_encoder_select="texturedspenc" -hevc_decoder_select="bswapdsp cabac dovi_rpu golomb hevcparse hevc_sei videodsp" +hevc_decoder_select="bswapdsp cabac dovi_rpudec golomb hevcparse hevc_sei videodsp" huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp" huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp" hymt_decoder_select="huffyuv_decoder" @@ -3000,7 +3019,7 @@ mpeg1video_decoder_select="mpegvideodec" mpeg1video_encoder_select="mpegvideoenc" mpeg2video_decoder_select="mpegvideodec" mpeg2video_encoder_select="mpegvideoenc" -mpeg4_decoder_select="h263_decoder mpeg4video_parser" +mpeg4_decoder_select="h263_decoder" mpeg4_encoder_select="h263_encoder qpeldsp" msa1_decoder_select="mss34dsp" mscc_decoder_select="inflate_wrapper" @@ -3021,7 +3040,7 @@ notchlc_decoder_select="lzf" nuv_decoder_select="idctdsp" opus_decoder_deps="swresample" opus_encoder_select="audio_frame_queue" -pdv_decoder_deps="zlib" +pdv_decoder_select="inflate_wrapper" png_decoder_select="inflate_wrapper" png_encoder_select="deflate_wrapper llvidencdsp" prores_decoder_select="blockdsp idctdsp" @@ -3125,7 +3144,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" +mediacodec_deps="android mediandk" nvdec_deps="ffnvcodec" vaapi_x11_deps="xlib_x11" videotoolbox_hwaccel_deps="videotoolbox pthreads" @@ -3268,6 +3287,7 @@ wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" wmv3_vdpau_hwaccel_select="vc1_vdpau_hwaccel" # hardware-accelerated codecs +d3d12va_encode_deps="d3d12va ID3D12VideoEncoder d3d12_encoder_feature" mediafoundation_deps="mftransform_h MFCreateAlignedMemoryBuffer" omx_deps="libdl pthreads" omx_rpi_select="omx" @@ -3276,6 +3296,7 @@ qsvdec_select="qsv" qsvenc_select="qsv" qsvvpp_select="qsv" vaapi_encode_deps="vaapi" +vulkan_encode_deps="vulkan" v4l2_m2m_deps="linux_videodev2_h sem_timedwait" bilateral_cuda_filter_deps="ffnvcodec" @@ -3302,13 +3323,26 @@ amf_deps_any="libdl LoadLibrary" nvenc_deps="ffnvcodec" nvenc_deps_any="libdl LoadLibrary" +aac_mediacodec_decoder_deps="mediacodec" +aac_mediacodec_decoder_select="aac_adtstoasc_bsf aac_parser" aac_mf_encoder_deps="mediafoundation" ac3_mf_encoder_deps="mediafoundation" +amrnb_mediacodec_decoder_deps="mediacodec" +amrnb_mediacodec_decoder_select="amr_parser" +amrwb_mediacodec_decoder_deps="mediacodec" +amrwb_mediacodec_decoder_select="amr_parser" +av1_amf_encoder_deps="amf" av1_cuvid_decoder_deps="cuvid CUVIDAV1PICPARAMS" av1_mediacodec_decoder_deps="mediacodec" av1_mediacodec_encoder_deps="mediacodec" +av1_mediacodec_encoder_select="extract_extradata_bsf" av1_nvenc_encoder_deps="nvenc NV_ENC_PIC_PARAMS_AV1" av1_nvenc_encoder_select="atsc_a53" +av1_qsv_decoder_select="qsvdec" +av1_qsv_encoder_deps="libvpl" +av1_qsv_encoder_select="qsvenc" +av1_vaapi_encoder_deps="VAEncPictureParameterBufferAV1" +av1_vaapi_encoder_select="cbs_av1 vaapi_encode" h263_v4l2m2m_decoder_deps="v4l2_m2m h263_v4l2_m2m" h263_v4l2m2m_encoder_deps="v4l2_m2m h263_v4l2_m2m" h264_amf_encoder_deps="amf" @@ -3317,7 +3351,7 @@ h264_cuvid_decoder_select="h264_mp4toannexb_bsf" h264_mediacodec_decoder_deps="mediacodec" h264_mediacodec_decoder_select="h264_mp4toannexb_bsf h264_parser" h264_mediacodec_encoder_deps="mediacodec" -h264_mediacodec_encoder_select="h264_metadata" +h264_mediacodec_encoder_select="extract_extradata_bsf h264_metadata" h264_mf_encoder_deps="mediafoundation" h264_mmal_decoder_deps="mmal" h264_nvenc_encoder_deps="nvenc" @@ -3328,16 +3362,18 @@ h264_qsv_encoder_select="atsc_a53 qsvenc" h264_rkmpp_decoder_deps="rkmpp" h264_rkmpp_decoder_select="h264_mp4toannexb_bsf" h264_vaapi_encoder_select="atsc_a53 cbs_h264 vaapi_encode" +h264_vulkan_encoder_select="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_cuvid_decoder_deps="cuvid" hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf" +hevc_d3d12va_encoder_select="cbs_h265 d3d12va_encode" hevc_mediacodec_decoder_deps="mediacodec" hevc_mediacodec_decoder_select="hevc_mp4toannexb_bsf hevc_parser" hevc_mediacodec_encoder_deps="mediacodec" -hevc_mediacodec_encoder_select="hevc_metadata" +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" @@ -3347,6 +3383,7 @@ hevc_rkmpp_decoder_deps="rkmpp" hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf" 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" hevc_v4l2m2m_decoder_deps="v4l2_m2m hevc_v4l2_m2m" hevc_v4l2m2m_decoder_select="hevc_mp4toannexb_bsf" hevc_v4l2m2m_encoder_deps="v4l2_m2m hevc_v4l2_m2m" @@ -3357,6 +3394,8 @@ mjpeg_qsv_encoder_select="qsvenc" mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG" mjpeg_vaapi_encoder_select="cbs_jpeg jpegtables vaapi_encode" mp3_mf_encoder_deps="mediafoundation" +mp3_mediacodec_decoder_deps="mediacodec" +mp3_mediacodec_decoder_select="mpegaudioheader" mpeg1_cuvid_decoder_deps="cuvid" mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m" mpeg2_cuvid_decoder_deps="cuvid" @@ -3369,6 +3408,7 @@ mpeg2_v4l2m2m_decoder_deps="v4l2_m2m mpeg2_v4l2_m2m" mpeg4_cuvid_decoder_deps="cuvid" mpeg4_mediacodec_decoder_deps="mediacodec" mpeg4_mediacodec_encoder_deps="mediacodec" +mpeg4_mediacodec_encoder_select="extract_extradata_bsf" mpeg4_mmal_decoder_deps="mmal" mpeg4_omx_encoder_deps="omx" mpeg4_v4l2m2m_decoder_deps="v4l2_m2m mpeg4_v4l2_m2m" @@ -3396,17 +3436,13 @@ 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" -av1_qsv_decoder_select="qsvdec" -av1_qsv_encoder_select="qsvenc" -av1_qsv_encoder_deps="libvpl" -av1_amf_encoder_deps="amf" -av1_vaapi_encoder_deps="VAEncPictureParameterBufferAV1" -av1_vaapi_encoder_select="cbs_av1 vaapi_encode" +vvc_qsv_decoder_select="vvc_mp4toannexb_bsf qsvdec" # parsers aac_parser_select="adts_header mpeg4audio" av1_parser_select="cbs_av1" evc_parser_select="evcparse" +ftr_parser_select="adts_header mpeg4audio" h264_parser_select="golomb h264dsp h264parse h264_sei" hevc_parser_select="hevcparse hevc_sei" mpegaudio_parser_select="mpegaudioheader" @@ -3419,6 +3455,7 @@ aac_adtstoasc_bsf_select="adts_header mpeg4audio" 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" eac3_core_bsf_select="ac3_parser" evc_frame_merge_bsf_select="evcparse" @@ -3477,14 +3514,14 @@ prores_videotoolbox_encoder_deps="pthreads" prores_videotoolbox_encoder_select="videotoolbox_encoder" libaom_av1_decoder_deps="libaom" libaom_av1_encoder_deps="libaom" -libaom_av1_encoder_select="extract_extradata_bsf" +libaom_av1_encoder_select="extract_extradata_bsf dovi_rpuenc" libaribb24_decoder_deps="libaribb24" libaribcaption_decoder_deps="libaribcaption" libcelt_decoder_deps="libcelt" libcodec2_decoder_deps="libcodec2" libcodec2_encoder_deps="libcodec2" libdav1d_decoder_deps="libdav1d" -libdav1d_decoder_select="atsc_a53 dovi_rpu" +libdav1d_decoder_select="atsc_a53 dovi_rpudec" libdavs2_decoder_deps="libdavs2" libdavs2_decoder_select="avs2_parser" libfdk_aac_decoder_deps="libfdk_aac" @@ -3500,6 +3537,9 @@ libilbc_encoder_deps="libilbc" libjxl_decoder_deps="libjxl libjxl_threads" libjxl_encoder_deps="libjxl libjxl_threads" libkvazaar_encoder_deps="libkvazaar" +liblc3_decoder_deps="liblc3" +liblc3_encoder_deps="liblc3" +liblc3_encoder_select="audio_frame_queue" libmodplug_demuxer_deps="libmodplug" libmp3lame_encoder_deps="libmp3lame" libmp3lame_encoder_select="audio_frame_queue mpegaudioheader" @@ -3523,6 +3563,7 @@ libspeex_decoder_deps="libspeex" libspeex_encoder_deps="libspeex" libspeex_encoder_select="audio_frame_queue" libsvtav1_encoder_deps="libsvtav1" +libsvtav1_encoder_select="dovi_rpuenc" libtheora_encoder_deps="libtheora" libtwolame_encoder_deps="libtwolame" libuavs3d_decoder_deps="libuavs3d" @@ -3534,6 +3575,7 @@ libvpx_vp8_decoder_deps="libvpx" libvpx_vp8_encoder_deps="libvpx" libvpx_vp9_decoder_deps="libvpx" libvpx_vp9_encoder_deps="libvpx" +libvvenc_encoder_deps="libvvenc" libwebp_encoder_deps="libwebp" libwebp_anim_encoder_deps="libwebp" libx262_encoder_deps="libx262" @@ -3542,7 +3584,7 @@ libx264_encoder_select="atsc_a53 golomb" libx264rgb_encoder_deps="libx264" libx264rgb_encoder_select="libx264_encoder" libx265_encoder_deps="libx265" -libx265_encoder_select="atsc_a53" +libx265_encoder_select="atsc_a53 dovi_rpuenc" libxavs_encoder_deps="libxavs" libxavs2_encoder_deps="libxavs2" libxevd_decoder_deps="libxevd" @@ -3586,7 +3628,7 @@ evc_demuxer_select="evc_frame_merge_bsf evc_parser" f4v_muxer_select="mov_muxer" fifo_muxer_deps="threads" flac_demuxer_select="flac_parser" -flv_muxer_select="aac_adtstoasc_bsf" +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" @@ -3604,19 +3646,20 @@ latm_muxer_select="aac_adtstoasc_bsf mpeg4audio" matroska_audio_muxer_select="matroska_muxer" matroska_demuxer_select="riffdec" matroska_demuxer_suggest="bzlib zlib" -matroska_muxer_select="mpeg4audio riffenc aac_adtstoasc_bsf pgs_frame_merge_bsf vp9_superframe_bsf" +matroska_muxer_select="iso_writer mpeg4audio riffenc aac_adtstoasc_bsf pgs_frame_merge_bsf vp9_superframe_bsf" mlp_demuxer_select="mlp_parser" mmf_muxer_select="riffenc" -mov_demuxer_select="iso_media riffdec iamfdec" -mov_demuxer_suggest="zlib" -mov_muxer_select="iso_media riffenc rtpenc_chain vp9_superframe_bsf aac_adtstoasc_bsf ac3_parser iamfenc" +mov_demuxer_select="iso_media riffdec" +mov_demuxer_suggest="iamfdec zlib" +mov_muxer_select="iso_media iso_writer riffenc rtpenc_chain vp9_superframe_bsf aac_adtstoasc_bsf ac3_parser" +mov_muxer_suggest="iamfenc" mp3_demuxer_select="mpegaudio_parser" mp3_muxer_select="mpegaudioheader" mp4_muxer_select="mov_muxer" 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="pcm_rechunk_bsf rangecoder" +mxf_muxer_select="iso_writer pcm_rechunk_bsf rangecoder" mxf_d10_muxer_select="mxf_muxer" mxf_opatom_muxer_select="mxf_muxer" nut_muxer_select="riffenc" @@ -3629,6 +3672,7 @@ ogv_muxer_select="ogg_muxer" opus_muxer_select="ogg_muxer" psp_muxer_select="mov_muxer" rtp_demuxer_select="sdp_demuxer" +rtp_muxer_select="iso_writer" rtp_mpegts_muxer_select="mpegts_muxer rtp_muxer" rtpdec_select="asf_demuxer mov_demuxer mpegts_demuxer rm_demuxer rtp_protocol srtp" rtsp_demuxer_select="http_protocol rtpdec" @@ -3840,9 +3884,11 @@ 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" kerndeint_filter_deps="gpl" ladspa_filter_deps="ladspa libdl" +lcevc_filter_deps="liblcevc_dec" lensfun_filter_deps="liblensfun version3" libplacebo_filter_deps="libplacebo vulkan" lv2_filter_deps="lv2" @@ -3946,6 +3992,8 @@ vstack_qsv_filter_deps="libmfx" vstack_qsv_filter_select="qsvvpp" xstack_qsv_filter_deps="libmfx" xstack_qsv_filter_select="qsvvpp" +pad_vaapi_filter_deps="vaapi_1" +drawbox_vaapi_filter_deps="vaapi_1" # examples avio_http_serve_files_deps="avformat avutil fork" @@ -3979,7 +4027,7 @@ cws2fws_extralibs="zlib_extralibs" # libraries, in any order avcodec_deps="avutil" -avcodec_suggest="libm stdatomic" +avcodec_suggest="libm stdatomic liblcevc_dec" avdevice_deps="avformat avcodec avutil" avdevice_suggest="libm stdatomic" avfilter_deps="avutil" @@ -4000,8 +4048,8 @@ avutil_extralibs="d3d11va_extralibs d3d12va_extralibs mediacodec_extralibs nanos # programs ffmpeg_deps="avcodec avfilter avformat threads" -ffmpeg_select="aformat_filter anull_filter atrim_filter format_filter - hflip_filter null_filter +ffmpeg_select="aformat_filter anull_filter atrim_filter crop_filter + format_filter hflip_filter null_filter rotate_filter transpose_filter trim_filter vflip_filter" ffmpeg_suggest="ole32 psapi shell32" ffplay_deps="avcodec avformat avfilter swscale swresample sdl2" @@ -4080,6 +4128,7 @@ enable asm enable debug enable doc enable faan faandct faanidct +enable iamf enable large_tests enable optimizations enable ptx_compression @@ -4500,37 +4549,49 @@ enabled ossfuzz && ! echo $CFLAGS | grep -q -- "-fsanitize=" && ! echo $CFLAGS add_ldflags -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard,trace-cmp } +add_sanitizer_flags(){ + case "$1" in + asan) + add_cflags -fsanitize=address + add_ldflags -fsanitize=address + ;; + lsan) + add_cflags -fsanitize=leak + add_ldflags -fsanitize=leak + ;; + msan) + add_cflags -fsanitize=memory -fsanitize-memory-track-origins + add_ldflags -fsanitize=memory + ;; + tsan) + add_cflags -fsanitize=thread + add_ldflags -fsanitize=thread + ;; + usan) + add_cflags -fsanitize=undefined + add_ldflags -fsanitize=undefined + ;; + ?*) + die "Unknown sanitizer $1" + ;; + esac +} + case "$toolchain" in - *-asan) - cc_default="${toolchain%-asan}" - add_cflags -fsanitize=address - add_ldflags -fsanitize=address + clang-*) + add_sanitizer_flags "${toolchain#clang-}" + cc_default="clang" + cxx_default="clang++" ;; - *-lsan) - cc_default="${toolchain%-lsan}" - add_cflags -fsanitize=leak - add_ldflags -fsanitize=leak - ;; - *-msan) - cc_default="${toolchain%-msan}" - add_cflags -fsanitize=memory -fsanitize-memory-track-origins - add_ldflags -fsanitize=memory - ;; - *-tsan) - cc_default="${toolchain%-tsan}" - add_cflags -fsanitize=thread - add_ldflags -fsanitize=thread - case "$toolchain" in - gcc-tsan) - add_cflags -fPIC - add_ldflags -fPIC - ;; - esac - ;; - *-usan) - cc_default="${toolchain%-usan}" - add_cflags -fsanitize=undefined - add_ldflags -fsanitize=undefined + gcc-*) + add_sanitizer_flags "${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_ldflags -fPIC + fi ;; valgrind-*) target_exec_default="valgrind" @@ -4726,7 +4787,7 @@ chmod +x $TMPE # make sure we can execute files in $TMPDIR cat > $TMPSH 2>> $logfile <> $logfile 2>&1 if ! $TMPSH >> $logfile 2>&1; then @@ -5018,7 +5079,12 @@ probe_cc(){ else _ident=$($_cc --version 2>/dev/null | head -n1 | tr -d '\r') fi - _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); gsub(/\\/, "/"); if (!match($$0, / /)) print "$@:", $$0 }'\'' > $(@:.o=.d)' + if [ -x "$(command -v wslpath)" ]; then + _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); if (!match($$0, / /)) { print $$0 } }'\'' | xargs -r -d\\n -n1 wslpath -u | awk '\''BEGIN { printf "%s:", "$@" }; { sub(/\r/,""); printf " %s", $$0 }; END { print "" }'\'' > $(@:.o=.d)' + + 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' _cflags_speed="-O2" _cflags_size="-O1" @@ -5212,9 +5278,6 @@ case "$arch" in s390|s390x) arch="s390" ;; - sh4|sh) - arch="sh4" - ;; sun4*|sparc*) arch="sparc" ;; @@ -5241,10 +5304,6 @@ if enabled aarch64; then ;; esac -elif enabled alpha; then - - cpuflags="-mcpu=$cpu" - elif enabled arm; then check_arm_arch() { @@ -5311,31 +5370,6 @@ elif enabled arm; then test_cflags -mfp16-format=ieee && add_cflags -mfp16-format=ieee -elif enabled avr32; then - - case $cpu in - ap7[02]0[0-2]) - subarch="avr32_ap" - cpuflags="-mpart=$cpu" - ;; - ap) - subarch="avr32_ap" - cpuflags="-march=$cpu" - ;; - uc3[ab]*) - subarch="avr32_uc" - cpuflags="-mcpu=$cpu" - ;; - uc) - subarch="avr32_uc" - cpuflags="-march=$cpu" - ;; - esac - -elif enabled bfin; then - - cpuflags="-mcpu=$cpu" - elif enabled loongarch; then enable local_aligned @@ -5514,6 +5548,9 @@ elif enabled ppc; then elif enabled riscv; then + check_headers asm/hwprobe.h + check_headers sys/hwprobe.h + if test_cpp_condition stddef.h "__riscv_zbb"; then enable fast_clz fi @@ -5559,6 +5596,12 @@ elif enabled x86; then ;; esac +else + + if test_cpp_condition inttypes.h "UINTPTR_MAX >= UINT64_MAX"; then + enable fast_64bit + fi + fi if [ "$cpu" != generic ]; then @@ -5623,7 +5666,7 @@ check_64bit(){ } case "$arch" in - aarch64|alpha|ia64) + aarch64|ia64) enabled shared && enable_weak pic ;; loongarch) @@ -6102,18 +6145,16 @@ enabled pic && enable_weak_pic test_cc <= 2.13" lcms2.h cmsCreateContext -enabled libaom && require_pkg_config libaom "aom >= 1.0.0" aom/aom_codec.h aom_codec_version +enabled libaom && require_pkg_config libaom "aom >= 2.0.0" aom/aom_codec.h aom_codec_version 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."; } @@ -6870,7 +6912,9 @@ enabled libjxl && require_pkg_config libjxl "libjxl >= 0.7.0" jxl/dec require_pkg_config libjxl_threads "libjxl_threads >= 0.7.0" jxl/thread_parallel_runner.h JxlThreadParallelRunner enabled libklvanc && require libklvanc libklvanc/vanc.h klvanc_context_create -lklvanc 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 if enabled libmfx && enabled libvpl; then die "ERROR: can not use libmfx and libvpl together" @@ -6898,6 +6942,7 @@ elif enabled libvpl; then check_pkg_config libmfx "vpl >= 2.6" "mfxvideo.h mfxdispatcher.h" MFXLoad || \ die "ERROR: libvpl >= 2.6 not found" add_cflags -DMFX_DEPRECATED_OFF + check_type "vpl/mfxdefs.h vpl/mfxvideo.h" "struct mfxConfigInterface" fi if enabled libmfx; then @@ -6991,11 +7036,12 @@ enabled libvpx && { fi } +enabled libvvenc && require_pkg_config libvvenc "libvvenc >= 1.6.1" "vvenc/vvenc.h" vvenc_get_version enabled libwebp && { enabled libwebp_encoder && require_pkg_config libwebp "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion enabled libwebp_anim_encoder && check_pkg_config libwebp_anim_encoder "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit; } enabled libx264 && require_pkg_config libx264 x264 "stdint.h x264.h" x264_encoder_encode && - require_cpp_condition libx264 x264.h "X264_BUILD >= 122" && { + require_cpp_condition libx264 x264.h "X264_BUILD >= 155" && { [ "$toolchain" != "msvc" ] || require_cpp_condition libx264 x264.h "X264_BUILD >= 158"; } && check_cpp_condition libx264_hdr10 x264.h "X264_BUILD >= 163" && @@ -7005,7 +7051,7 @@ 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 libxeve && require_pkg_config libxeve "xeve >= 0.4.3" "xeve.h" xeve_encode +enabled libxeve && require_pkg_config libxeve "xeve >= 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 @@ -7032,7 +7078,7 @@ enabled openal && { check_pkg_config openal "openal >= 1.1" "AL/al.h" { test_cpp_condition "AL/al.h" "defined(AL_VERSION_1_1)" || die "ERROR: openal must be installed and version must be 1.1 or compatible"; } enabled opencl && { check_pkg_config opencl OpenCL CL/cl.h clEnqueueNDRangeKernel || - check_lib opencl OpenCL/cl.h clEnqueueNDRangeKernel -Wl,-framework,OpenCL || + check_lib opencl OpenCL/cl.h clEnqueueNDRangeKernel "-framework OpenCL" || check_lib opencl CL/cl.h clEnqueueNDRangeKernel -lOpenCL || die "ERROR: opencl not found"; } && { test_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" || @@ -7040,8 +7086,8 @@ enabled opencl && { check_pkg_config opencl OpenCL CL/cl.h clEnqueueN die "ERROR: opencl must be installed and version must be 1.2 or compatible"; } enabled opengl && { check_lib opengl GL/glx.h glXGetProcAddress "-lGL" || check_lib opengl windows.h wglGetProcAddress "-lopengl32 -lgdi32" || - check_lib opengl OpenGL/gl3.h glGetError "-Wl,-framework,OpenGL" || - check_lib opengl ES2/gl.h glGetError "-isysroot=${sysroot} -Wl,-framework,OpenGLES" || + check_lib opengl OpenGL/gl3.h glGetError "-framework OpenGL" || + check_lib opengl ES2/gl.h glGetError "-isysroot=${sysroot} -framework OpenGLES" || die "ERROR: opengl not found." } enabled omx_rpi && { test_code cc OMX_Core.h OMX_IndexConfigBrcmVideoRequestIFrame || @@ -7067,7 +7113,7 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } -enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init +enabled vapoursynth && require_headers "vapoursynth/VSScript4.h vapoursynth/VapourSynth4.h" if enabled gcrypt; then @@ -7109,12 +7155,12 @@ if enabled decklink; then fi enabled securetransport && - check_func SecIdentityCreate "-Wl,-framework,CoreFoundation -Wl,-framework,Security" && - check_lib securetransport "Security/SecureTransport.h Security/Security.h" "SSLCreateContext" "-Wl,-framework,CoreFoundation -Wl,-framework,Security" || + check_func SecIdentityCreate "-framework CoreFoundation -framework Security" && + check_lib securetransport "Security/SecureTransport.h Security/Security.h" "SSLCreateContext" "-framework CoreFoundation -framework Security" || disable securetransport enabled securetransport && - check_func SecItemImport "-Wl,-framework,CoreFoundation -Wl,-framework,Security" + check_func SecItemImport "-framework CoreFoundation -framework Security" enabled schannel && check_func_headers "windows.h security.h" InitializeSecurityContext -DSECURITY_WIN32 -lsecur32 && @@ -7129,14 +7175,16 @@ enabled makeinfo \ disabled makeinfo_html && texi2html --help 2> /dev/null | grep -q 'init-file' && enable texi2html || disable texi2html perl -v > /dev/null 2>&1 && enable perl || disable perl pod2man --help > /dev/null 2>&1 && enable pod2man || disable pod2man -rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout +rsync --help 2> /dev/null | grep -q 'contimeout=' && enable rsync_contimeout || disable rsync_contimeout 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 + # check V4L2 codecs available in the API if enabled v4l2_m2m; then - 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 check_cc v4l2_m2m linux/videodev2.h "int i = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_M2M | V4L2_BUF_FLAG_LAST;" check_cc vc1_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VC1_ANNEX_G;" check_cc mpeg1_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG1;" @@ -7349,7 +7397,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) >= 0x00010004001d0000" + "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x0001000400210000" # Funny iconv installations are not unusual, so check it after all flags have been set if enabled libc_iconv; then @@ -7732,21 +7780,18 @@ for thread in $THREADS_LIST; do done if disabled stdatomic; then - if enabled atomics_gcc; then - add_cppflags '-I\$(SRC_PATH)/compat/atomics/gcc' - elif enabled atomics_win32; then + if enabled atomics_win32; then add_cppflags '-I\$(SRC_PATH)/compat/atomics/win32' - elif enabled atomics_suncc; then - add_cppflags '-I\$(SRC_PATH)/compat/atomics/suncc' - elif enabled pthreads; then - add_compat atomics/pthread/stdatomic.o - add_cppflags '-I\$(SRC_PATH)/compat/atomics/pthread' else enabled threads && die "Threading is enabled, but no atomics are available" add_cppflags '-I\$(SRC_PATH)/compat/atomics/dummy' fi fi +check_builtin stdbit "stdbit.h assert.h" \ + 'static_assert(__STDC_VERSION_STDBIT_H__ >= 202311L, "Compiler lacks stdbit.h")' || \ + add_cppflags '-I\$(SRC_PATH)/compat/stdbit' + # Check if requested libraries were found. for lib in $AUTODETECT_LIBS; do requested $lib && ! enabled $lib && die "ERROR: $lib requested but not found"; @@ -7763,14 +7808,14 @@ enabled elbg_filter && prepend avfilter_deps "avcodec" enabled find_rect_filter && prepend avfilter_deps "avformat avcodec" enabled fsync_filter && prepend avfilter_deps "avformat" enabled mcdeint_filter && prepend avfilter_deps "avcodec" -enabled movie_filter && prepend avfilter_deps "avformat 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 qrencode_filter && prepend avfilter_deps "swscale" +enabled qrencodesrc_filter && prepend avfilter_deps "swscale" enabled removelogo_filter && prepend avfilter_deps "avformat avcodec swscale" enabled sab_filter && prepend avfilter_deps "swscale" -enabled scale_filter && prepend avfilter_deps "swscale" +enabled scale_filter && prepend avfilter_deps "swscale" enabled scale2ref_filter && prepend avfilter_deps "swscale" enabled showcqt_filter && prepend avfilter_deps "avformat swscale" enabled signature_filter && prepend avfilter_deps "avcodec avformat" @@ -7902,6 +7947,7 @@ if enabled loongarch; then echo "LASX enabled ${lasx-no}" fi if enabled riscv; then + echo "RISC-V CBO Prefetch ${rv_zicbop-no}" echo "RISC-V Vector enabled ${rvv-no}" fi echo "debug symbols ${debug-no}" @@ -8145,7 +8191,7 @@ cat > $TMPH < $@ + $(M)doc/print_options$(HOSTEXESUF) $* > $@ doc/%.html: TAG = HTML doc/%-all.html: TAG = HTML diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index 3d4dda04f..e1cb87a52 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -101,6 +101,29 @@ Remove zero padding at the end of a packet. Extract the core from a DCA/DTS stream, dropping extensions such as DTS-HD. +@section dovi_rpu + +Manipulate Dolby Vision metadata in a HEVC/AV1 bitstream, optionally enabling +metadata compression. + +@table @option +@item strip +If enabled, strip all Dolby Vision metadata (configuration record + RPU data +blocks) from the stream. +@item compression +Which compression level to enable. +@table @samp +@item none +No metadata compression. +@item limited +Limited metadata compression scheme. Should be compatible with most devices. +This is the default. +@item extended +Extended metadata compression. Devices are not required to support this. Note +that this level currently behaves the same as @samp{limited} in libavcodec. +@end table +@end table + @section dump_extra Add extradata to the beginning of the filtered packets except when @@ -456,6 +479,10 @@ will replace the current ones if the stream is already cropped. These fields are set in pixels. Note that some sizes may not be representable if the chroma is subsampled (H.265 section 7.4.3.2.1). +@item width +@item height +Set width and height after crop. + @item level Set the level in the VPS and SPS. See H.265 section A.4 and tables A.6 and A.7. diff --git a/doc/community.texi b/doc/community.texi index 90d2b6f36..97a49f15e 100644 --- a/doc/community.texi +++ b/doc/community.texi @@ -82,8 +82,6 @@ The TC has 2 modes of operation: a RFC one and an internal one. If the TC thinks it needs the input from the larger community, the TC can call for a RFC. Else, it can decide by itself. -If the disagreement involves a member of the TC, that member should recuse themselves from the decision. - The decision to use a RFC process or an internal discussion is a discretionary decision of the TC. The TC can also reject a seizure for a few reasons such as: the matter was not discussed enough previously; it lacks expertise to reach a beneficial decision on the matter; or the matter is too trivial. @@ -123,6 +121,13 @@ The decisions from the TC will be sent on the mailing list, with the [TC] tag. Internally, the TC should take decisions with a majority, or using ranked-choice voting. +Each TC member must vote on such decision according to what is, in their view, best for the project. + +If a TC member feels they are affected by a conflict of interest with regards to the case, they should announce it and recuse themselves from the TC +discussion and vote. + +A conflict of interest is presumed to occur when a TC member has a personal interest (e.g. financial) in a specific outcome of the case. + The decision from the TC should be published with a summary of the reasons that lead to this decision. The decisions from the TC are final, until the matters are reopened after no less than one year. diff --git a/doc/decoders.texi b/doc/decoders.texi index 293c82c2b..17bb361ff 100644 --- a/doc/decoders.texi +++ b/doc/decoders.texi @@ -38,6 +38,51 @@ Select an operating point of a scalable AV1 bitstream (0 - 31). Default is 0. @end table +@section hevc +HEVC (AKA ITU-T H.265 or ISO/IEC 23008-2) decoder. + +The decoder supports MV-HEVC multiview streams with at most two views. Views to +be output are selected by supplying a list of view IDs to the decoder (the +@option{view_ids} option). This option may be set either statically before +decoder init, or from the @code{get_format()} callback - useful for the case +when the view count or IDs change dynamically during decoding. + +Only the base layer is decoded by default. + +Note that if you are using the @code{ffmpeg} CLI tool, you should be using view +specifiers as documented in its manual, rather than the options documented here. + +@subsection Options + +@table @option + +@item view_ids (MV-HEVC) +Specify a list of view IDs that should be output. This option can also be set to +a single '-1', which will cause all views defined in the VPS to be decoded and +output. + +@item view_ids_available (MV-HEVC) +This option may be read by the caller to retrieve an array of view IDs available +in the active VPS. The array is empty for single-layer video. + +The value of this option is guaranteed to be accurate when read from the +@code{get_format()} callback. It may also be set at other times (e.g. after +opening the decoder), but the value is informational only and may be incorrect +(e.g. when the stream contains multiple distinct VPS NALUs). + +@item view_pos_available (MV-HEVC) +This option may be read by the caller to retrieve an array of view positions +(left, right, or unspecified) available in the active VPS, as +@code{AVStereo3DView} values. When the array is available, its elements apply to +the corresponding elements of @option{view_ids_available}, i.e. +@code{view_pos_available[i]} contains the position of view with ID +@code{view_ids_available[i]}. + +Same validity restrictions as for @option{view_ids_available} apply to +this option. + +@end table + @section rawvideo Raw video decoder. @@ -157,7 +202,7 @@ Force to use a specific number of threads @section QSV Decoders The family of Intel QuickSync Video decoders (VC1, MPEG-2, H.264, HEVC, -JPEG/MJPEG, VP8, VP9, AV1). +JPEG/MJPEG, VP8, VP9, AV1, VVC). @subsection Common Options diff --git a/doc/demuxers.texi b/doc/demuxers.texi index b70f3a38d..2324b3b46 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -292,7 +292,6 @@ DVD-Video demuxer, powered by libdvdnav and libdvdread. Can directly ingest DVD titles, specifically sequential PGCs, into a conversion pipeline. Menu assets, such as background video or audio, can also be demuxed given the menu's coordinates (at best effort). -Seeking is not supported at this time. Block devices (DVD drives), ISO files, and directory structures are accepted. Activate with @code{-f dvdvideo} in front of one of these inputs. @@ -380,11 +379,11 @@ Default is false. @item menu_lu @var{int} The menu language to demux. In DVD, menus are grouped by language. -Default is 0, the first language unit. +Default is 1, the first language unit. @item menu_vts @var{int} The VTS where the menu lives, or 0 if it is a VMG menu (root-level). -Default is 0, VMG menu. +Default is 1, menu of the first VTS. @item pgc @var{int} The entry PGC to start playback, in conjunction with @option{pg}. @@ -397,8 +396,7 @@ Default is 0, automatically resolve from value of @option{title}. The entry PG to start playback, in conjunction with @option{pgc}. Alternative to setting @option{title}. Chapter markers are not supported at this time. -Default is 0, automatically resolve from value of @option{title}, or -start from the beginning (PG 1) of the menu. +Default is 1, the first PG of the PGC. @item preindex @var{bool} Enable this to have accurate chapter (PTT) markers and duration measurement, @@ -406,7 +404,6 @@ which requires a slow second pass read in order to index the chapter marker timestamps from NAV packets. This is non-ideal extra work for real optical drives. It is recommended and faster to use this option with a backup of the DVD structure stored on a hard drive. Not compatible with @option{pgc} and @option{pg}. -Not applicable to menus. Default is 0, false. @item trim @var{bool} @@ -567,6 +564,13 @@ prefer to use #EXT-X-START if it's in playlist instead of live_start_index. @item allowed_extensions ',' separated list of file extensions that hls is allowed to access. +@item extension_picky +This blocks disallowed extensions from probing +It also requires all available segments to have matching extensions to the format +except mpegts, which is always allowed. +It is recommended to set the whitelists correctly instead of depending on extensions +Enabled by default. + @item max_reload Maximum number of times a insufficient list is attempted to be reloaded. Default value is 1000. @@ -1038,6 +1042,36 @@ the command: ffplay -f rawvideo -pixel_format rgb24 -video_size 320x240 -framerate 10 input.raw @end example +@anchor{rcwtdec} +@section rcwt + +RCWT (Raw Captions With Time) is a format native to ccextractor, a commonly +used open source tool for processing 608/708 Closed Captions (CC) sources. +For more information on the format, see @ref{rcwtenc,,,ffmpeg-formats}. + +This demuxer implements the specification as of March 2024, which has +been stable and unchanged since April 2014. + +@subsection Examples + +@itemize +@item +Render CC to ASS using the built-in decoder: +@example +ffmpeg -i CC.rcwt.bin CC.ass +@end example +Note that if your output appears to be empty, you may have to manually +set the decoder's @option{data_field} option to pick the desired CC substream. + +@item +Convert an RCWT backup to Scenarist (SCC) format: +@example +ffmpeg -i CC.rcwt.bin -c:s copy CC.scc +@end example +Note that the SCC format does not support all of the possible CC extensions +that can be stored in RCWT (such as EIA-708). +@end itemize + @section sbg SBaGen script demuxer. diff --git a/doc/developer.texi b/doc/developer.texi index ed998adec..dcfb64e07 100644 --- a/doc/developer.texi +++ b/doc/developer.texi @@ -687,7 +687,7 @@ number) in @file{libavcodec/version.h} or @file{libavformat/version.h}? Did you register it in @file{allcodecs.c} or @file{allformats.c}? @item -Did you add the AVCodecID to @file{avcodec.h}? +Did you add the AVCodecID to @file{codec_id.h}? When adding new codec IDs, also add an entry to the codec descriptor list in @file{libavcodec/codec_desc.c}. @@ -702,7 +702,7 @@ already being compiled by some other rule, like a raw demuxer. @item Did you add an entry to the table of supported formats or codecs in -@file{doc/general.texi}? +@file{doc/general_contents.texi}? @item Did you add an entry in the Changelog? @@ -927,6 +927,25 @@ In case you need finer control over how valgrind is invoked, use the @code{--target-exec='valgrind } option in your configure line instead. +@anchor{Maintenance} +@chapter Maintenance process + +@anchor{MAINTAINERS} +@section MAINTAINERS + +The developers maintaining each part of the codebase are listed in @file{MAINTAINERS}. +Being listed in @file{MAINTAINERS}, gives one the right to have git write access to +the specific repository. + +@anchor{Becoming a maintainer} +@section Becoming a maintainer + +People add themselves to @file{MAINTAINERS} by sending a patch like any other code +change. These get reviewed by the community like any other patch. It is expected +that, if someone has an objection to a new maintainer, she is willing to object +in public with her full name and is willing to take over maintainership for the area. + + @anchor{Release process} @chapter Release process diff --git a/doc/encoders.texi b/doc/encoders.texi index 840382a25..0749417db 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -144,8 +144,7 @@ If this option is unspecified it is set to @samp{aac_low}. AC-3 audio encoders. -These encoders implement part of ATSC A/52:2010 and ETSI TS 102 366, as well as -the undocumented RealAudio 3 (a.k.a. dnet). +These encoders implement part of ATSC A/52:2010 and ETSI TS 102 366. The @var{ac3} encoder uses floating-point math, while the @var{ac3_fixed} encoder only uses fixed-point integer math. This does not mean that one is @@ -814,6 +813,63 @@ ffmpeg -i input.wav -c:a libfdk_aac -profile:a aac_he -b:a 64k output.m4a @end example @end itemize +@anchor{liblc3-enc} +@section liblc3 + +liblc3 LC3 (Low Complexity Communication Codec) encoder wrapper. + +Requires the presence of the liblc3 headers and library during configuration. +You need to explicitly configure the build with @code{--enable-liblc3}. + +This encoder has support for the Bluetooth SIG LC3 codec for the LE Audio +protocol, and the following features of LC3plus: +@itemize +@item +Frame duration of 2.5 and 5ms. +@item +High-Resolution mode, 48 KHz, and 96 kHz sampling rates. +@end itemize + +For more information see the liblc3 project at +@url{https://github.com/google/liblc3}. + +@subsection Options + +The following options are mapped on the shared FFmpeg codec options. + +@table @option +@item b @var{bitrate} +Set the bit rate in bits/s. This will determine the fixed size of the encoded +frames, for a selected frame duration. + +@item ar @var{frequency} +Set the audio sampling rate (in Hz). + +@item channels +Set the number of audio channels. + +@item frame_duration +Set the audio frame duration in milliseconds. Default value is 10ms. +Allowed frame durations are 2.5ms, 5ms, 7.5ms and 10ms. +LC3 (Bluetooth LE Audio), allows 7.5ms and 10ms; and LC3plus 2.5ms, 5ms +and 10ms. + +The 10ms frame duration is available in LC3 and LC3 plus standard. +In this mode, the produced bitstream can be referenced either as LC3 or LC3plus. + +@item high_resolution @var{boolean} +Enable the high-resolution mode if set to 1. The high-resolution mode is +available with all LC3plus frame durations and for a sampling rate of 48 KHz, +and 96 KHz. + +The encoder automatically turns off this mode at lower sampling rates and +activates it at 96 KHz. + +This mode should be preferred at high bitrates. In this mode, the audio +bandwidth is always up to the Nyquist frequency, compared to LC3 at 48 KHz, +which limits the bandwidth to 20 KHz. +@end table + @anchor{libmp3lame} @section libmp3lame @@ -2322,6 +2378,70 @@ Indicates frame duration For more information about libvpx see: @url{http://www.webmproject.org/} +@section libvvenc + +VVenC H.266/VVC encoder wrapper. + +This encoder requires the presence of the libvvenc headers and library +during configuration. You need to explicitly configure the build with +@option{--enable-libvvenc}. + +The VVenC project website is at +@url{https://github.com/fraunhoferhhi/vvenc}. + +@subsection Supported Pixel Formats + +VVenC supports only 10-bit color spaces as input. But the internal (encoded) +bit depth can be set to 8-bit or 10-bit at runtime. + +@subsection Options + +@table @option +@item b +Sets target video bitrate. + +@item g +Set the GOP size. Currently support for g=1 (Intra only) or default. + +@item preset +Set the VVenC preset. + +@item levelidc +Set level idc. + +@item tier +Set vvc tier. + +@item qp +Set constant quantization parameter. + +@item subopt @var{boolean} +Set subjective (perceptually motivated) optimization. Default is 1 (on). + +@item bitdepth8 @var{boolean} +Set 8bit coding mode instead of using 10bit. Default is 0 (off). + +@item period +set (intra) refresh period in seconds. + +@item vvenc-params +Set vvenc options using a list of @var{key}=@var{value} couples separated +by ":". See @command{vvencapp --fullhelp} or @command{vvencFFapp --fullhelp} for a list of options. + +For example, the options might be provided as: + +@example +intraperiod=64:decodingrefreshtype=idr:poc0idr=1:internalbitdepth=8 +@end example + +For example the encoding options might be provided with @option{-vvenc-params}: + +@example +ffmpeg -i input -c:v libvvenc -b 1M -vvenc-params intraperiod=64:decodingrefreshtype=idr:poc0idr=1:internalbitdepth=8 output.mp4 +@end example + +@end table + @section libwebp libwebp WebP Image encoder wrapper @@ -3490,6 +3610,20 @@ Change these value to reset qsv codec's bitrate control configuration. @item @var{pic_timing_sei} Supported in h264_qsv and hevc_qsv. Change this value to reset qsv codec's pic_timing_sei configuration. + +@item @var{qsv_params} +Set QSV encoder parameters as a colon-separated list of key-value pairs. + +The @option{qsv_params} should be formatted as @code{key1=value1:key2=value2:...}. + +These parameters are passed directly to the underlying Intel Quick Sync Video (QSV) encoder using the MFXSetParameter function. + +Example: +@example +ffmpeg -i input.mp4 -c:v h264_qsv -qsv_params "CodingOption1=1:CodingOption2=2" output.mp4 +@end example + +This option allows fine-grained control over various encoder-specific settings provided by the QSV encoder. @end table @subsection H264 options @@ -3971,10 +4105,18 @@ Setting this flag turns on or off LowDelayBRC feautre in qsv plugin, which provi more accurate bitrate control to minimize the variance of bitstream size frame by frame. Value: -1-default 0-off 1-on -@item max_frame_size +@item @var{max_frame_size} Set the allowed max size in bytes for each frame. If the frame size exceeds the limitation, encoder will adjust the QP value to control the frame size. Invalid in CQP rate control mode. + +@item @var{max_frame_size_i} +Maximum encoded frame size for I frames in bytes. If this value is set as larger +than zero, then for I frames the value set by max_frame_size is ignored. + +@item @var{max_frame_size_p} +Maximum encoded frame size for P frames in bytes. If this value is set as larger +than zero, then for P frames the value set by max_frame_size is ignored. @end table @section snow diff --git a/doc/examples/avio_read_callback.c b/doc/examples/avio_read_callback.c index 4cf81ad72..dffc061d9 100644 --- a/doc/examples/avio_read_callback.c +++ b/doc/examples/avio_read_callback.c @@ -32,6 +32,7 @@ #include #include #include +#include struct buffer_data { uint8_t *ptr; diff --git a/doc/examples/decode_filter_audio.c b/doc/examples/decode_filter_audio.c index 204641981..d637ca172 100644 --- a/doc/examples/decode_filter_audio.c +++ b/doc/examples/decode_filter_audio.c @@ -37,6 +37,7 @@ #include #include #include +#include #include static const char *filter_descr = "aresample=8000,aformat=sample_fmts=s16:channel_layouts=mono"; @@ -279,6 +280,25 @@ int main(int argc, char **argv) } av_packet_unref(packet); } + if (ret == AVERROR_EOF) { + /* signal EOF to the filtergraph */ + if (av_buffersrc_add_frame_flags(buffersrc_ctx, NULL, 0) < 0) { + av_log(NULL, AV_LOG_ERROR, "Error while closing the filtergraph\n"); + goto end; + } + + /* pull remaining frames from the filtergraph */ + while (1) { + ret = av_buffersink_get_frame(buffersink_ctx, filt_frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + break; + if (ret < 0) + goto end; + print_frame(filt_frame); + av_frame_unref(filt_frame); + } + } + end: avfilter_graph_free(&filter_graph); avcodec_free_context(&dec_ctx); diff --git a/doc/examples/decode_filter_video.c b/doc/examples/decode_filter_video.c index 454c19222..b91ca56d4 100644 --- a/doc/examples/decode_filter_video.c +++ b/doc/examples/decode_filter_video.c @@ -36,6 +36,7 @@ #include #include #include +#include #include const char *filter_descr = "scale=78:24,transpose=cclock"; @@ -276,6 +277,25 @@ int main(int argc, char **argv) } av_packet_unref(packet); } + if (ret == AVERROR_EOF) { + /* signal EOF to the filtergraph */ + if (av_buffersrc_add_frame_flags(buffersrc_ctx, NULL, 0) < 0) { + av_log(NULL, AV_LOG_ERROR, "Error while closing the filtergraph\n"); + goto end; + } + + /* pull remaining frames from the filtergraph */ + while (1) { + ret = av_buffersink_get_frame(buffersink_ctx, filt_frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + break; + if (ret < 0) + goto end; + display_frame(filt_frame, buffersink_ctx->inputs[0]->time_base); + av_frame_unref(filt_frame); + } + } + end: avfilter_graph_free(&filter_graph); avcodec_free_context(&dec_ctx); diff --git a/doc/examples/filter_audio.c b/doc/examples/filter_audio.c index 9e4039b90..8b237e2ad 100644 --- a/doc/examples/filter_audio.c +++ b/doc/examples/filter_audio.c @@ -41,15 +41,15 @@ #include #include -#include "libavutil/channel_layout.h" -#include "libavutil/md5.h" -#include "libavutil/mem.h" -#include "libavutil/opt.h" -#include "libavutil/samplefmt.h" +#include +#include +#include +#include +#include -#include "libavfilter/avfilter.h" -#include "libavfilter/buffersink.h" -#include "libavfilter/buffersrc.h" +#include +#include +#include #define INPUT_SAMPLERATE 48000 #define INPUT_FORMAT AV_SAMPLE_FMT_FLTP diff --git a/doc/examples/hw_decode.c b/doc/examples/hw_decode.c index 6a4a4fb83..ac4e44550 100644 --- a/doc/examples/hw_decode.c +++ b/doc/examples/hw_decode.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include diff --git a/doc/examples/qsv_decode.c b/doc/examples/qsv_decode.c index 901eac3b2..5a6f3625a 100644 --- a/doc/examples/qsv_decode.c +++ b/doc/examples/qsv_decode.c @@ -30,16 +30,16 @@ #include -#include "libavformat/avformat.h" -#include "libavformat/avio.h" +#include +#include -#include "libavcodec/avcodec.h" +#include -#include "libavutil/buffer.h" -#include "libavutil/error.h" -#include "libavutil/hwcontext.h" -#include "libavutil/hwcontext_qsv.h" -#include "libavutil/mem.h" +#include +#include +#include +#include +#include static int get_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts) { diff --git a/doc/examples/qsv_transcode.c b/doc/examples/qsv_transcode.c index ff115f366..665a76af2 100644 --- a/doc/examples/qsv_transcode.c +++ b/doc/examples/qsv_transcode.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include diff --git a/doc/examples/remux.c b/doc/examples/remux.c index ecf30489f..1f002987c 100644 --- a/doc/examples/remux.c +++ b/doc/examples/remux.c @@ -28,6 +28,7 @@ * input to the output without transcoding. */ +#include #include #include diff --git a/doc/examples/transcode.c b/doc/examples/transcode.c index a544ec034..cbe5088ef 100644 --- a/doc/examples/transcode.c +++ b/doc/examples/transcode.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/doc/examples/transcode_aac.c b/doc/examples/transcode_aac.c index cf6edc989..20de08d93 100644 --- a/doc/examples/transcode_aac.c +++ b/doc/examples/transcode_aac.c @@ -29,19 +29,20 @@ #include -#include "libavformat/avformat.h" -#include "libavformat/avio.h" +#include +#include +#include -#include "libavcodec/avcodec.h" +#include -#include "libavutil/audio_fifo.h" -#include "libavutil/avassert.h" -#include "libavutil/avstring.h" -#include "libavutil/channel_layout.h" -#include "libavutil/frame.h" -#include "libavutil/opt.h" +#include +#include +#include +#include +#include +#include -#include "libswresample/swresample.h" +#include /* The output bit rate in bit/s */ #define OUTPUT_BIT_RATE 96000 diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index a38ef834e..013f5f4da 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -229,12 +229,16 @@ successive integers starting at zero. These indices should then be used to refer to loopback decoders in complex filtergraph link labels, as described in the documentation for @option{-filter_complex}. +Decoding AVOptions can be passed to loopback decoders by placing them before +@code{-dec}, analogously to input/output options. + E.g. the following example: @example ffmpeg -i INPUT \ -map 0:v:0 -c:v libx264 -crf 45 -f null - \ - -dec 0:0 -filter_complex '[0:v][dec:0]hstack[stack]' \ + -threads 3 -dec 0:0 \ + -filter_complex '[0:v][dec:0]hstack[stack]' \ -map '[stack]' -c:v ffv1 OUTPUT @end example @@ -244,11 +248,13 @@ reads an input video and (line 2) encodes it with @code{libx264} at low quality; @item -(line 3) decodes this encoded stream and places it side by side with the -original input video; +(line 3) decodes this encoded stream using 3 threads; @item -(line 4) combined video is then losslessly encoded and written into +(line 4) places decoded video side by side with the original input video; + +@item +(line 5) combined video is then losslessly encoded and written into @file{OUTPUT}. @end itemize @@ -657,10 +663,11 @@ Not all muxers support embedded thumbnails, and those who do, only support a few Creates a program with the specified @var{title}, @var{program_num} and adds the specified @var{stream}(s) to it. -@item -stream_group type=@var{type}:st=@var{stream}[:st=@var{stream}][:stg=@var{stream_group}][:id=@var{stream_group_id}...] (@emph{output}) +@item -stream_group [map=@var{input_file_id}=@var{stream_group}][type=@var{type}:]st=@var{stream}[:st=@var{stream}][:stg=@var{stream_group}][:id=@var{stream_group_id}...] (@emph{output}) -Creates a stream group of the specified @var{type}, @var{stream_group_id} and adds the specified -@var{stream}(s) and/or previously defined @var{stream_group}(s) to it. +Creates a stream group of the specified @var{type} and @var{stream_group_id}, or by +@var{map}ping an input group, adding the specified @var{stream}(s) and/or previously +defined @var{stream_group}(s) to it. @var{type} can be one of the following: @table @option @@ -857,6 +864,27 @@ all sub-mix element's @var{annotations}s @end table +E.g. to create an scalable 5.1 IAMF file from several WAV input files +@example +ffmpeg -i front.wav -i back.wav -i center.wav -i lfe.wav +-map 0:0 -map 1:0 -map 2:0 -map 3:0 -c:a opus +-stream_group type=iamf_audio_element:id=1:st=0:st=1:st=2:st=3, +demixing=parameter_id=998, +recon_gain=parameter_id=101, +layer=ch_layout=stereo, +layer=ch_layout=5.1, +-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 +-streamid 0:0 -streamid 1:1 -streamid 2:2 -streamid 3:3 output.iamf +@end example + +To copy the two stream groups (Audio Element and Mix Presentation) from an input IAMF file with four +streams into an mp4 output +@example +ffmpeg -i input.iamf -c:a copy -stream_group map=0=0:st=0:st=1:st=2:st=3 -stream_group map=0=1:stg=0 +-streamid 0:0 -streamid 1:1 -streamid 2:2 -streamid 3:3 output.mp4 +@end example + @item -target @var{type} (@emph{output}) Specify target file type (@code{vcd}, @code{svcd}, @code{dvd}, @code{dv}, @code{dv50}). @var{type} may be prefixed with @code{pal-}, @code{ntsc-} or @@ -1351,6 +1379,21 @@ Note that forcing too many keyframes is very harmful for the lookahead algorithms of certain encoders: using fixed-GOP options or similar would be more efficient. +@item -apply_cropping[:@var{stream_specifier}] @var{source} (@emph{input,per-stream}) +Automatically crop the video after decoding according to file metadata. +Default is @emph{all}. + +@table @option +@item none (0) +Don't apply any cropping metadata. +@item all (1) +Apply both codec and container level croppping. This is the default mode. +@item codec (2) +Apply codec level croppping. +@item container (3) +Apply container level croppping. +@end table + @item -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream}) When doing stream copy, copy also non-key frames found at the beginning. @@ -1415,6 +1458,11 @@ The following options are recognized: When @var{device} is not specified, use this option to specify the name of the kernel driver associated with the desired device. This option is available only when the hardware acceleration method @emph{drm} and @emph{vaapi} are enabled. +@item vendor_id +When @var{device} and @var{kernel_driver} are not specified, use this option to specify +the vendor id associated with the desired device. This option is available only when the +hardware acceleration method @emph{drm} and @emph{vaapi} are enabled and @emph{kernel_driver} +is not specified. @end table Examples: @@ -1430,6 +1478,9 @@ Create a vaapi device on DirectX adapter 1. @item -init_hw_device vaapi:,kernel_driver=i915 Create a vaapi device on a device associated with kernel driver @samp{i915}. + +@item -init_hw_device vaapi:,vendor_id=0x8086 +Create a vaapi device on a device associated with vendor id @samp{0x8086}. @end table @item vdpau @@ -1691,12 +1742,21 @@ This is an alias for @code{-filter:a}, see the @ref{filter_option,,-filter optio @table @option @item -atag @var{fourcc/tag} (@emph{output}) Force audio tag/fourcc. This is an alias for @code{-tag:a}. +@item -ch_layout[:@var{stream_specifier}] @var{layout} (@emph{input/output,per-stream}) +Alias for @code{-channel_layout}. +@item -channel_layout[:@var{stream_specifier}] @var{layout} (@emph{input/output,per-stream}) +Set the audio channel layout. For output streams it is set by default to the +input channel layout. For input streams it overrides the channel layout of the +input. Not all decoders respect the overridden channel layout. This option +also sets the channel layout for audio grabbing devices and raw demuxers +and is mapped to the corresponding demuxer option. @item -guess_layout_max @var{channels} (@emph{input,per-stream}) If some input channel layout is not known, try to guess only if it corresponds to at most the specified number of channels. For example, 2 tells to @command{ffmpeg} to recognize 1 channel as mono and 2 channels as stereo but not 6 channels as 5.1. The default is to always try to guess. Use -0 to disable all guessing. +0 to disable all guessing. Using the @code{-channel_layout} option to +explicitly specify an input layout also disables guessing. @end table @section Subtitle options @@ -1739,7 +1799,7 @@ Set the size of the canvas used to render subtitles. @section Advanced options @table @option -@item -map [-]@var{input_file_id}[:@var{stream_specifier}][?] | @var{[linklabel]} (@emph{output}) +@item -map [-]@var{input_file_id}[:@var{stream_specifier}][:@var{view_specifier}][:?] | @var{[linklabel]} (@emph{output}) Create one or more streams in the output file. This option has two forms for specifying the data source(s): the first selects one or more streams from some @@ -1754,6 +1814,26 @@ only those streams that match the specifier are used (see the A @code{-} character before the stream identifier creates a "negative" mapping. It disables matching streams from already created mappings. +An optional @var{view_specifier} may be given after the stream specifier, which +for multiview video specifies the view to be used. The view specifier may have +one of the following formats: +@table @option +@item view:@var{view_id} +select a view by its ID; @var{view_id} may be set to 'all' to use all the views +interleaved into one stream; + +@item vidx:@var{view_idx} +select a view by its index; i.e. 0 is the base view, 1 is the first non-base +view, etc. + +@item vpos:@var{position} +select a view by its display position; @var{position} may be @code{left} or +@code{right} +@end table +The default for transcoding is to only use the base view, i.e. the equivalent of +@code{vidx:0}. For streamcopy, view specifiers are not supported and all views +are always copied. + A trailing @code{?} after the stream index will allow the map to be optional: if the map matches no streams the map will be ignored instead of failing. Note the map will still fail if an invalid input file index @@ -2137,15 +2217,68 @@ Define a complex filtergraph, i.e. one with arbitrary number of inputs and/or outputs. For simple graphs -- those with one input and one output of the same type -- see the @option{-filter} options. @var{filtergraph} is a description of the filtergraph, as described in the ``Filtergraph syntax'' section of the -ffmpeg-filters manual. +ffmpeg-filters manual. This option may be specified multiple times - each use +creates a new complex filtergraph. -Input link labels must refer to either input streams or loopback decoders. For -input streams, use the @code{[file_index:stream_specifier]} syntax (i.e. the -same as @option{-map} uses). If @var{stream_specifier} matches multiple streams, -the first one will be used. +Inputs to a complex filtergraph may come from different source types, +distinguished by the format of the corresponding link label: +@itemize +@item +To connect an input stream, use @code{[file_index:stream_specifier]} (i.e. the +same syntax as @option{-map}). If @var{stream_specifier} matches multiple +streams, the first one will be used. For multiview video, the stream specifier +may be followed by the view specifier, see documentation for the @option{-map} +option for its syntax. -For decoders, the link label must be [dec:@var{dec_idx}], where @var{dec_idx} is -the index of the loopback decoder to be connected to given input. +@item +To connect a loopback decoder use [dec:@var{dec_idx}], where @var{dec_idx} is +the index of the loopback decoder to be connected to given input. For multiview +video, the decoder index may be followed by the view specifier, see +documentation for the @option{-map} option for its syntax. + +@item +To connect an output from another complex filtergraph, use its link label. E.g +the following example: + +@example +ffmpeg -i input.mkv \ + -filter_complex '[0:v]scale=size=hd1080,split=outputs=2[for_enc][orig_scaled]' \ + -c:v libx264 -map '[for_enc]' output.mkv \ + -dec 0:0 \ + -filter_complex '[dec:0][orig_scaled]hstack[stacked]' \ + -map '[stacked]' -c:v ffv1 comparison.mkv +@end example + +reads an input video and +@itemize +@item +(line 2) uses a complex filtergraph with one input and two outputs +to scale the video to 1920x1080 and duplicate the result to both +outputs; + +@item +(line 3) encodes one scaled output with @code{libx264} and writes the result to +@file{output.mkv}; + +@item +(line 4) decodes this encoded stream with a loopback decoder; + +@item +(line 5) places the output of the loopback decoder (i.e. the +@code{libx264}-encoded video) side by side with the scaled original input; + +@item +(line 6) combined video is then losslessly encoded and written into +@file{comparison.mkv}. + +@end itemize + +Note that the two filtergraphs cannot be combined into one, because then there +would be a cycle in the transcoding pipeline (filtergraph output goes to +encoding, from there to decoding, then back to the same graph), and such cycles +are not allowed. + +@end itemize An unlabeled input will be connected to the first unused input stream of the matching type. diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd index 6d5d094d9..64e2d8857 100644 --- a/doc/ffprobe.xsd +++ b/doc/ffprobe.xsd @@ -255,6 +255,7 @@ + diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi index 1974d79a4..8b0931a86 100644 --- a/doc/fftools-common-opts.texi +++ b/doc/fftools-common-opts.texi @@ -78,7 +78,12 @@ Match the stream by stream id (e.g. PID in MPEG-TS container). @item m:@var{key}[:@var{value}] Matches streams with the metadata tag @var{key} having the specified value. If @var{value} is not given, matches streams that contain the given tag with any -value. +value. The colon character ':' in @var{key} or @var{value} needs to be +backslash-escaped. +@item disp:@var{dispositions}[:@var{additional_stream_specifier}] +Matches streams with the given disposition(s). @var{dispositions} is a list of +one or more dispositions (as printed by the @option{-dispositions} option) +joined with '+'. @item u Matches streams with usable configuration, the codec must be defined and the essential information such as video dimension or audio sample rate must be present. diff --git a/doc/filters.texi b/doc/filters.texi index bfa8ccec8..428986a1e 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -11092,8 +11092,8 @@ By default, a component curve is defined by the two points @var{(0;0)} and "adjusted" to its own value, which means no change to the image. The filter allows you to redefine these two points and add some more. A new -curve will be define to pass smoothly through all these new coordinates. The -new defined points needs to be strictly increasing over the x-axis, and their +curve will be defined to pass smoothly through all these new coordinates. The +new defined points need to be strictly increasing over the x-axis, and their @var{x} and @var{y} values must be in the @var{[0;1]} interval. The curve is formed by using a natural or monotonic cubic spline interpolation, depending on the @var{interp} option (default: @code{natural}). The @code{natural} @@ -17071,8 +17071,8 @@ ffmpeg \ -hwaccel cuda -hwaccel_output_format cuda -codec:v av1_cuvid -i dis.obu \ -hwaccel cuda -hwaccel_output_format cuda -codec:v av1_cuvid -i ref.obu \ -filter_complex " - [0:v]scale_cuda=format=yuv420p[ref]; \ - [1:v]scale_cuda=format=yuv420p[dis]; \ + [0:v]scale_cuda=format=yuv420p[dis]; \ + [1:v]scale_cuda=format=yuv420p[ref]; \ [dis][ref]libvmaf_cuda=log_fmt=json:log_path=output.json " \ -f null - @@ -17290,6 +17290,9 @@ The command accepts the same syntax of the corresponding option. If the specified expression is not valid, it is kept at its current value. +@anchor{lutrgb} +@anchor{lutyuv} +@anchor{lut} @section lut, lutrgb, lutyuv Compute a look-up table for binding each pixel component input value @@ -19941,6 +19944,7 @@ pseudocolor="'if(between(val,ymax,amax),lerp(ymin,ymax,(val-ymax)/(amax-ymax)),- @end example @end itemize +@anchor{psnr} @section psnr Obtain the average, maximum and minimum PSNR (Peak Signal to Noise @@ -20989,8 +20993,8 @@ the next filter, the scale filter will convert the input to the requested format. @subsection Options -The filter accepts the following options, or any of the options -supported by the libswscale scaler. +The filter accepts the following options, any of the options supported +by the libswscale scaler, as well as any of the @ref{framesync} options. See @ref{scaler_options,,the ffmpeg-scaler manual,ffmpeg-scaler} for the complete list of scaler options. @@ -21134,6 +21138,21 @@ Set full range (0-255 in case of 8-bit luma). Set "MPEG" range (16-235 in case of 8-bit luma). @end table +@item in_chroma_loc +@item out_chroma_loc +Set in/output chroma sample location. If not specified, center-sited chroma +is used by default. Possible values: + +@table @samp +@item auto, unknown +@item left +@item center +@item topleft +@item top +@item bottomleft +@item bottom +@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: @@ -21228,6 +21247,16 @@ 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. + +@item ref_w, rw +@item ref_h, rh +@item ref_a +@item ref_dar, rdar +@item ref_n +@item ref_t +@item ref_pos +Eqvuialent to the above, but for a second reference input. If any of these +variables are present, this filter accepts two inputs. @end table @subsection Examples @@ -21329,6 +21358,20 @@ 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 @end example + +@item +Scale a subtitle stream (sub) to match the main video (main) in size before +overlaying. ("scale2ref") +@example +'[main]split[a][b]; [ref][a]scale=rw:rh[c]; [b][c]overlay' +@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]scale=w=oh*dar:h=rh/10[logo-out] +@end example @end itemize @subsection Commands @@ -21564,79 +21607,6 @@ Only available with @code{eval=frame}. Deprecated, do not use. @end table -@section scale2ref - -Scale (resize) the input video, based on a reference video. - -See the scale filter for available options, scale2ref supports the same but -uses the reference video instead of the main input as basis. scale2ref 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_hsub -@item main_vsub -The main input video's horizontal and vertical chroma subsample values. -For example for the pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} -is 1. - -@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[b][a];[a][b]overlay' -@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=w=oh*mdar:h=ih/10[logo-out][video-out] -@end example -@end itemize - -@subsection Commands - -This filter supports the following commands: -@table @option -@item width, w -@item height, h -Set the output video dimension expression. -The command accepts the same syntax of the corresponding option. - -If the specified expression is not valid, it is kept at its current -value. -@end table - @section scale2ref_npp Use the NVIDIA Performance Primitives (libnpp) to scale (resize) the input @@ -22119,6 +22089,23 @@ Keep the same colorspace property (default). @item chroma-derived-c @item ictcp @end table + +@item chroma_location +Set the chroma sample location. +Available values are: + +@table @samp +@item auto +Keep the same chroma location (default). + +@item unspecified, unknown +@item left +@item center +@item topleft +@item top +@item bottomleft +@item bottom +@end table @end table @section sharpen_npp @@ -22702,9 +22689,27 @@ whether a pixel should be blurred or not. The option value must be an integer in the range [-30,30]. A value of 0 will filter all the image, a value included in [0,30] will filter flat areas and a value included in [-30,0] will filter edges. Default value is @option{luma_threshold}. + +@item alpha_radius, ar +Set the alpha radius. The option value must be a float number in +the range [0.1,5.0] that specifies the variance of the gaussian filter +used to blur the image (slower if larger). Default value is @option{luma_radius}. + +@item alpha_strength, as +Set the alpha strength. The option value must be a float number +in the range [-1.0,1.0] that configures the blurring. A value included +in [0.0,1.0] will blur the image whereas a value included in +[-1.0,0.0] will sharpen the image. Default value is @option{luma_strength}. + +@item alpha_threshold, at +Set the alpha threshold used as a coefficient to determine +whether a pixel should be blurred or not. The option value must be an +integer in the range [-30,30]. A value of 0 will filter all the image, +a value included in [0,30] will filter flat areas and a value included +in [-30,0] will filter edges. Default value is @option{luma_threshold}. @end table -If a chroma option is not explicitly set, the corresponding luma value +If a chroma or alpha option is not explicitly set, the corresponding luma value is set. @section sobel @@ -23574,12 +23579,13 @@ tile=3x2:nb_frames=5:padding=7:margin=2 @end itemize @section tiltandshift +Apply tilt-and-shift effect. What happens when you invert time and space? Normally a video is composed of several frames that represent a different -instant of time and shows a scence that evolves in the space captured by the -frame. This filter is the antipode of that concept, taking inspiration by +instant of time and shows a scene that evolves in the space captured by the +frame. This filter is the antipode of that concept, taking inspiration from tilt and shift photography. A filtered frame contains the whole timeline of events composing the sequence, @@ -23587,13 +23593,13 @@ and this is obtained by placing a slice of pixels from each frame into a single one. However, since there are no infinite-width frames, this is done up the width of the input frame, and a video is recomposed by shifting away one column for each subsequent frame. In order to map space to time, the filter -tilts each input frame as well, so that motion is preseved. This is accomplished +tilts each input frame as well, so that motion is preserved. This is accomplished by progressively selecting a different column from each input frame. -The end result is a sort of inverted parralax, so that far away objects move +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, -or when there is a lot of motion and a very wide depth of field (eg. wide +or when there is a lot of motion and a very wide depth of field (e.g. wide panorama, while moving on a train). The filter accepts the following parameters: @@ -23618,7 +23624,7 @@ How many columns should be inserted before end of filtering. @end table -Normally the filter shifts and tils from the very first frame, and stops when +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, the last video frame may be reconstructed at the end. Alternatively it is @@ -23626,7 +23632,7 @@ possible to just start and end with black. @table @samp @item none -Filtering is starts immediately and ends when the last frame is received. +Filtering starts immediately and ends when the last frame is received. @item frame The first frames or the very last frame are kept intact during processing. @@ -24458,7 +24464,7 @@ The way this differs from the behavior of spp is that uspp actually encodes & decodes each case with libavcodec Snow, whereas spp uses a simplified intra only 8x8 DCT similar to MJPEG. -This filter is only available in ffmpeg version 4.4 or earlier. +This filter is not available in ffmpeg versions between 5.0 and 6.0. The filter accepts the following options: @@ -26059,6 +26065,73 @@ minimum values, and @code{1} maximum values. This filter supports all above options as @ref{commands}, excluding option @code{inputs}. +@anchor{xpsnr} +@section xpsnr + +Obtain the average (across all input frames) and minimum (across all color plane averages) +eXtended Perceptually weighted peak Signal-to-Noise Ratio (XPSNR) between two input videos. + +The XPSNR is a low-complexity psychovisually motivated distortion measurement algorithm for +assessing the difference between two video streams or images. This is especially useful for +objectively quantifying the distortions caused by video and image codecs, as an alternative +to a formal subjective test. The logarithmic XPSNR output values are in a similar range as +those of traditional @ref{psnr} assessments but better reflect human impressions of visual +coding quality. More details on the XPSNR measure, which essentially represents a blockwise +weighted variant of the PSNR measure, can be found in the following freely available papers: + +@itemize +@item +C. R. Helmrich, M. Siekmann, S. Becker, S. Bosse, D. Marpe, and T. Wiegand, "XPSNR: A +Low-Complexity Extension of the Perceptually Weighted Peak Signal-to-Noise Ratio for +High-Resolution Video Quality Assessment," in Proc. IEEE Int. Conf. Acoustics, Speech, +Sig. Process. (ICASSP), virt./online, May 2020. @url{www.ecodis.de/xpsnr.htm} + +@item +C. R. Helmrich, S. Bosse, H. Schwarz, D. Marpe, and T. Wiegand, "A Study of the +Extended Perceptually Weighted Peak Signal-to-Noise Ratio (XPSNR) for Video Compression +with Different Resolutions and Bit Depths," ITU Journal: ICT Discoveries, vol. 3, no. +1, pp. 65 - 72, May 2020. @url{http://handle.itu.int/11.1002/pub/8153d78b-en} +@end itemize + +When publishing the results of XPSNR assessments obtained using, e.g., this FFmpeg filter, a +reference to the above papers as a means of documentation is strongly encouraged. The filter +requires two input videos. The first input is considered a (usually not distorted) reference +source and is passed unchanged to the output, whereas the second input is a (distorted) test +signal. Except for the bit depth, these two video inputs must have the same pixel format. In +addition, for best performance, both compared input videos should be in YCbCr color format. + +The obtained overall XPSNR values mentioned above are printed through the logging system. In +case of input with multiple color planes, we suggest reporting of the minimum XPSNR average. + +The following parameter, which behaves like the one for the @ref{psnr} filter, is accepted: + +@table @option +@item stats_file, f +If specified, the filter will use the named file to save the XPSNR value of each individual +frame and color plane. When the file name equals "-", that data is sent to standard output. +@end table + +This filter also supports the @ref{framesync} options. + +@subsection Examples +@itemize +@item +XPSNR analysis of two 1080p HD videos, ref_source.yuv and test_video.yuv, both at 24 frames +per second, with color format 4:2:0, bit depth 8, and output of a logfile named "xpsnr.log": +@example +ffmpeg -s 1920x1080 -framerate 24 -pix_fmt yuv420p -i ref_source.yuv -s 1920x1080 -framerate +24 -pix_fmt yuv420p -i test_video.yuv -lavfi xpsnr="stats_file=xpsnr.log" -f null - +@end example + +@item +XPSNR analysis of two 2160p UHD videos, ref_source.yuv with bit depth 8 and test_video.yuv +with bit depth 10, both at 60 frames per second with color format 4:2:0, no logfile output: +@example +ffmpeg -s 3840x2160 -framerate 60 -pix_fmt yuv420p -i ref_source.yuv -s 3840x2160 -framerate +60 -pix_fmt yuv420p10le -i test_video.yuv -lavfi xpsnr="stats_file=-" -f null - +@end example +@end itemize + @anchor{xstack} @section xstack Stack video inputs into custom layout. @@ -27832,8 +27905,7 @@ The inputs have same memory layout for color channels, the overlay has additiona @section tonemap_vaapi -Perform HDR(High Dynamic Range) to SDR(Standard Dynamic Range) conversion with tone-mapping. -It maps the dynamic range of HDR10 content to the SDR content. +Perform HDR-to-SDR or HDR-to-HDR tone-mapping. It currently only accepts HDR10 as input. It accepts the following parameters: @@ -27842,28 +27914,42 @@ It accepts the following parameters: @item format Specify the output pixel format. -Currently supported formats are: -@table @var -@item p010 -@item nv12 -@end table - -Default is nv12. +Default is nv12 for HDR-to-SDR tone-mapping and p010 for HDR-to-HDR +tone-mapping. @item primaries, p Set the output color primaries. -Default is same as input. +Default is bt709 for HDR-to-SDR tone-mapping and same as input for HDR-to-HDR +tone-mapping. @item transfer, t Set the output transfer characteristics. -Default is bt709. +Default is bt709 for HDR-to-SDR tone-mapping and same as input for HDR-to-HDR +tone-mapping. @item matrix, m Set the output colorspace matrix. -Default is same as input. +Default is bt709 for HDR-to-SDR tone-mapping and same as input for HDR-to-HDR +tone-mapping. + +@item display +Set the output mastering display colour volume. It is given by a '|'-separated +list of two values, two values are space separated. It set display primaries +x & y in G, B, R order, then white point x & y, the nominal minimum & maximum +display luminances. + +HDR-to-HDR tone-mapping will be performed when this option is set. + +@item light +Set the output content light level information. It accepts 2 space-separated +values, the first input is the maximum light level and the second input is +the maximum average light level. + +It is ignored for HDR-to-SDR tone-mapping, and optional for HDR-to-HDR +tone-mapping. @end table @@ -27875,6 +27961,11 @@ Convert HDR(HDR10) video to bt2020-transfer-characteristic p010 format @example tonemap_vaapi=format=p010:t=bt2020-10 @end example +@item +Convert HDR video to HDR video +@example +tonemap_vaapi=display=7500\ 3000|34000\ 16000|13250\ 34500|15635\ 16450|500\ 10000000 +@end example @end itemize @section hstack_vaapi @@ -27955,6 +28046,168 @@ first input stream. For the syntax of this option, check the See @ref{xstack}. @end table +@section pad_vaapi + +Add paddings to the input image, and place the original input at the +provided @var{x}, @var{y} coordinates. + +It accepts the following options: + +@table @option +@item width, w +@item height, h +Specify an expression for the size of the output image with the +paddings added. If the value for @var{width} or @var{height} is 0, the +corresponding input size is used for the output. + +The @var{width} expression can reference the value set by the +@var{height} expression, and vice versa. + +The default value of @var{width} and @var{height} is 0. + +@item x +@item y +Specify the offsets to place the input image at within the padded area, +with respect to the top/left border of the output image. + +The @var{x} expression can reference the value set by the @var{y} +expression, and vice versa. + +The default value of @var{x} and @var{y} is 0. + +If @var{x} or @var{y} evaluate to a negative number, they'll be changed +so the input image is centered on the padded area. + +@item color +Specify the color of the padded area. For the syntax of this option, +check the @ref{color syntax,,"Color" section in the ffmpeg-utils +manual,ffmpeg-utils}. + +@item aspect +Pad to an aspect instead to a resolution. +@end table + +The value for the @var{width}, @var{height}, @var{x}, and @var{y} +options are expressions containing the following constants: + +@table @option +@item in_w +@item in_h +The input video 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 width and height (the size of the padded area), as +specified by the @var{width} and @var{height} expressions. + +@item ow +@item oh +These are the same as @var{out_w} and @var{out_h}. + +@item x +@item y +The x and y offsets as specified by the @var{x} and @var{y} +expressions, or NAN if not yet specified. + +@item a +same as @var{iw} / @var{ih} + +@item sar +input sample aspect ratio + +@item dar +input display aspect ratio, it is the same as (@var{iw} / @var{ih}) * @var{sar} +@end table + +@section drawbox_vaapi + +Draw a colored box on the input image. + +It accepts the following parameters: + +@table @option +@item x +@item y +The expressions which specify the top left corner coordinates of the box. It defaults to 0. + +@item width, w +@item height, h +The expressions which specify the width and height of the box; if 0 they are interpreted as +the input width and height. It defaults to 0. + +@item color, c +Specify the color of the box to write. For the general syntax of this option, +check the @ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}. + +@item thickness, t +The expression which sets the thickness of the box edge. +A value of @code{fill} will create a filled box. Default value is @code{3}. + +See below for the list of accepted constants. + +@item replace +With value @code{1}, the pixels of the painted box will overwrite the video's color and alpha pixels. +Default is @code{0}, which composites the box onto the input video. +@end table + +The parameters for @var{x}, @var{y}, @var{w} and @var{h} and @var{t} are expressions containing the +following constants: + +@table @option +@item in_h, ih +@item in_w, iw +The input width and height. + +@item x +@item y +The x and y offset coordinates where the box is drawn. + +@item w +@item h +The width and height of the drawn box. + +@item t +The thickness of the drawn box. + +@end table + +@subsection Examples + +@itemize +@item +Draw a black box around the edge of the input image: +@example +drawbox +@end example + +@item +Draw a box with color red and an opacity of 50%: +@example +drawbox=10:20:200:60:red@@0.5 +@end example + +The previous example can be specified as: +@example +drawbox=x=10:y=20:w=200:h=60:color=red@@0.5 +@end example + +@item +Fill the box with pink color: +@example +drawbox=x=10:y=10:w=100:h=100:color=pink@@0.5:t=fill +@end example + +@item +Draw a 2-pixel red 2.40:1 mask: +@example +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 +@end example +@end itemize + @c man end VAAPI VIDEO FILTERS @chapter Vulkan Video Filters @@ -29131,6 +29384,107 @@ ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_c @end example @end itemize +@section perlin +Generate Perlin noise. + +Perlin noise is a kind of noise with local continuity in space. This +can be used to generate patterns with continuity in space and time, +e.g. to simulate smoke, fluids, or terrain. + +In case more than one octave is specified through the @option{octaves} +option, Perlin noise is generated as a sum of components, each one +with doubled frequency. In this case the @option{persistence} option +specify the ratio of the amplitude with respect to the previous +component. More octave components enable to specify more high +frequency details in the generated noise (e.g. small size variations +due to boulders in a generated terrain). + +@subsection Options +@table @option + +@item size, s +Specify the size (width and height) of the buffered video frames. For the +syntax of this option, check the +@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}. +Default value is @code{320x240}. + +@item rate, r +Specify the frame rate expected for the video stream, expressed as a +number of frames per second. Default value is @code{25}. + +@item octaves +Specify the total number of components making up the noise, each one +with doubled frequency. Default value is @code{1}. + +@item persistence +Set the ratio used to compute the amplitude of the next octave +component with respect to the previous component amplitude. Default +value is @code{1}. + +@item xscale +@item yscale +Define a scale factor used to multiple the x, y coordinates. This can +be useful to define an effect with a pattern stretched along the x or +y axis. Default value is @code{1}. + +@item tscale +Define a scale factor used to multiple the time coordinate. This can +be useful to change the time variation speed. Default value is @code{1}. + +@item random_mode +Set random mode used to compute initial pattern. + +Supported values are: +@table @option +@item random +Compute and use random seed. + +@item ken +Use the predefined initial pattern defined by Ken Perlin in the +original article, can be useful to compare the output with other +sources. + +@item seed +Use the value specified by @option{random_seed} option. +@end table + +Default value is @code{random}. + +@item random_seed, seed +When @option{random_mode} is set to @var{random_seed}, use this value +to compute the initial pattern. Default value is @code{0}. +@end table + +@subsection Examples +@itemize +@item +Generate single component: +@example +perlin +@end example + +@item +Use Perlin noise with 7 components, each one with a halved contribution +to total amplitude: +@example +perlin=octaves=7:persistence=0.5 +@end example + +@item +Chain Perlin noise with the @ref{lutyuv} to generate a black&white +effect: +@example +perlin=octaves=3:tscale=0.3,lutyuv=y='if(lt(val\,128)\,255\,0)' +@end example + +@item +Stretch noise along the y axis, and convert gray level to red-only +signal: +@example +perlin=octaves=7:tscale=0.4:yscale=0.3,lutrgb=r=val:b=0:g=0 +@end example +@end itemize + @section qrencodesrc Generate a QR code using the libqrencode library (see @@ -30751,6 +31105,15 @@ missing. That basically means that an input frame is selected if its pts is within the interval set by the concat demuxer. +@item iw @emph{(video only)} +Represents the width of the input video frame. + +@item ih @emph{(video only)} +Represents the height of the input video frame. + +@item view @emph{(video only)} +View ID for multi-view video. + @end table The default value of the select expression is "1". diff --git a/doc/formats.texi b/doc/formats.texi index 69fc1457a..876a9e92b 100644 --- a/doc/formats.texi +++ b/doc/formats.texi @@ -225,9 +225,26 @@ Specifies the maximum number of streams. This can be used to reject files that would require too many resources due to a large number of streams. @item skip_estimate_duration_from_pts @var{bool} (@emph{input}) -Skip estimation of input duration when calculated using PTS. +Skip estimation of input duration if it requires an additional probing for PTS at end of file. At present, applicable for MPEG-PS and MPEG-TS. +@item duration_probesize @var{integer} (@emph{input}) +Set probing size, in bytes, for input duration estimation when it actually requires +an additional probing for PTS at end of file (at present: MPEG-PS and MPEG-TS). +It is aimed at users interested in better durations probing for itself, or indirectly +because using the concat demuxer, for example. +The typical use case is an MPEG-TS CBR with a high bitrate, high video buffering and +ending cleaning with similar PTS for video and audio: in such a scenario, the large +physical gap between the last video packet and the last audio packet makes it necessary +to read many bytes in order to get the video stream duration. +Another use case is where the default probing behaviour only reaches a single video frame which is +not the last one of the stream due to frame reordering, so the duration is not accurate. +Setting this option has a performance impact even for small files because the probing +size is fixed. +Default behaviour is a general purpose trade-off, largely adaptive, but the probing size +will not be extended to get streams durations at all costs. +Must be an integer not lesser than 1, or 0 for default behaviour. + @item strict, f_strict @var{integer} (@emph{input/output}) Specify how strictly to follow the standards. @code{f_strict} is deprecated and should be used only via the @command{ffmpeg} tool. diff --git a/doc/general_contents.texi b/doc/general_contents.texi index f269cbd1a..5980ac6f0 100644 --- a/doc/general_contents.texi +++ b/doc/general_contents.texi @@ -160,6 +160,19 @@ Go to @url{http://lame.sourceforge.net/} and follow the instructions for installing the library. 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 +decoding on supported bitstreams. + +Go to @url{https://github.com/v-novaltd/LCEVCdec} and follow the instructions +for installing the library. Then pass @code{--enable-liblcevc-dec} to configure to +enable it. + +@float NOTE +LCEVCdec is under the BSD-3-Clause-Clear License. +@end float + @section libilbc iLBC is a narrowband speech codec that has been made freely available @@ -237,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 LC3 library + +FFmpeg can make use of the Google LC3 library for LC3 decoding & encoding. + +Go to @url{https://github.com/google/liblc3/} and follow the instructions for +installing the library. +Then pass @code{--enable-liblc3} to configure to enable it. + @section OpenH264 FFmpeg can make use of the OpenH264 library for H.264 decoding and encoding. @@ -1015,6 +1036,8 @@ following image formats are supported: @item Kega Game Video (KGV1) @tab @tab X @tab Kega emulator screen capture codec. @item Lagarith @tab @tab X +@item LCEVC / MPEG-5 LCEVC / MPEG-5 Part 2 @tab @tab E + @tab decoding supported through external library liblcevc-dec @item LCL (LossLess Codec Library) MSZH @tab @tab X @item LCL (LossLess Codec Library) ZLIB @tab E @tab E @item LEAD MCMP @tab @tab X @@ -1300,7 +1323,8 @@ following image formats are supported: @tab encoding and decoding supported through external library libilbc @item IMC (Intel Music Coder) @tab @tab X @item Interplay ACM @tab @tab X -@item MACE (Macintosh Audio Compression/Expansion) 3:1 @tab @tab X +@item LC3 @tab E @tab E + @tab supported through external library liblc3 @item MACE (Macintosh Audio Compression/Expansion) 6:1 @tab @tab X @item Marian's A-pac audio @tab @tab X @item MI-SC4 (Micronas SC-4 Audio) @tab @tab X diff --git a/doc/indevs.texi b/doc/indevs.texi index d1b2bacf8..cdf44a663 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -396,6 +396,22 @@ Defaults to @samp{audio}. @item draw_bars If set to @samp{true}, color bars are drawn in the event of a signal loss. Defaults to @samp{true}. +This option is deprecated, please use the @code{signal_loss_action} option. + +@item signal_loss_action +Sets the action to take in the event of a signal loss. Accepts one of the +following values: + +@table @option +@item 1, none +Do nothing on signal loss. This usually results in black frames. +@item 2, bars +Draw color bars on signal loss. Only supported for 8-bit input signals. +@item 3, repeat +Repeat the last video frame on signal loss. +@end table + +Defaults to @samp{bars}. @item queue_size Sets maximum input buffer size in bytes. If the buffering reaches this value, @@ -1069,9 +1085,9 @@ ffplay -f lavfi "movie=test.avi[out0];amovie=test.wav[out1]" @end example @item -Dump decoded frames to images and closed captions to a file (experimental): +Dump decoded frames to images and Closed Captions to an RCWT backup: @example -ffmpeg -f lavfi -i "movie=test.ts[out0+subcc]" -map v frame%08d.png -map s -c copy -f rawvideo subcc.bin +ffmpeg -f lavfi -i "movie=test.ts[out0+subcc]" -map v frame%08d.png -map s -c copy -f rcwt subcc.bin @end example @end itemize diff --git a/doc/infra.txt b/doc/infra.txt index 30a85dd5c..79d4e5671 100644 --- a/doc/infra.txt +++ b/doc/infra.txt @@ -23,6 +23,8 @@ Web, mail, and public facing git, also website git fftrac VM: ---------- trac.ffmpeg.org Issue tracking +gpg encrypted backups of the trac repositories are created once a day +and can be downloaded by any of the admins. ffaux VM: @@ -65,6 +67,9 @@ Github mirrors are redundantly synced by multiple people You need a new git repository related to FFmpeg ? contact root at ffmpeg.org +git repositories are managed by gitolite, every change to permissions is +logged, including when, what and by whom + Fate: ~~~~~ diff --git a/doc/mailing-list-faq.texi b/doc/mailing-list-faq.texi index b2028eeee..e10d92a5f 100644 --- a/doc/mailing-list-faq.texi +++ b/doc/mailing-list-faq.texi @@ -157,9 +157,6 @@ Perform a site search using your favorite search engine. Example: You can ask for help in the official @t{#ffmpeg} IRC channel on Libera Chat. -Some users prefer the third-party @url{http://www.ffmpeg-archive.org/, Nabble} -interface which presents the mailing lists in a typical forum layout. - There are also numerous third-party help sites such as @url{https://superuser.com/tags/ffmpeg, Super User} and @url{https://www.reddit.com/r/ffmpeg/, r/ffmpeg on reddit}. diff --git a/doc/mips.txt b/doc/mips.txt index d66ce3b44..a42546f0c 100644 --- a/doc/mips.txt +++ b/doc/mips.txt @@ -49,11 +49,6 @@ Files that have MIPS copyright notice in them: libm_mips.h softfloat_tables.h * libavcodec/mips/ - aacdec_fixed.c - aacsbr_fixed.c - aacsbr_template.c - aaccoder_mips.c - aacpsy_mips.h ac3dsp_mips.c acelp_filters_mips.c acelp_vectors_mips.c @@ -64,7 +59,6 @@ Files that have MIPS copyright notice in them: compute_antialias_fixed.h compute_antialias_float.h lsp_mips.h - dsputil_mips.c fmtconvert_mips.c iirfilter_mips.c mpegaudiodsp_mips_fixed.c diff --git a/doc/multithreading.txt b/doc/multithreading.txt index 6c65ca965..842d331e4 100644 --- a/doc/multithreading.txt +++ b/doc/multithreading.txt @@ -36,9 +36,9 @@ Frame threading - * Codecs similar to ffv1, whose streams don't reset across frames, will not work because their bitstreams cannot be decoded in parallel. -* The contents of buffers must not be read before ff_thread_await_progress() +* The contents of buffers must not be read before ff_progress_frame_await() has been called on them. reget_buffer() and buffer age optimizations no longer work. -* The contents of buffers must not be written to after ff_thread_report_progress() +* The contents of buffers must not be written to after ff_progress_frame_report() has been called on them. This includes draw_edges(). Porting codecs to frame threading @@ -53,14 +53,13 @@ thread. Add AV_CODEC_CAP_FRAME_THREADS to the codec capabilities. There will be very little speed gain at this point but it should work. -If there are inter-frame dependencies, so the codec calls -ff_thread_report/await_progress(), set FF_CODEC_CAP_ALLOCATE_PROGRESS in -FFCodec.caps_internal and use ff_thread_get_buffer() to allocate frames. -Otherwise decode directly into the user-supplied frames. +Use ff_thread_get_buffer() (or ff_progress_frame_get_buffer() +in case you have inter-frame dependencies and use the ProgressFrame API) +to allocate frame buffers. -Call ff_thread_report_progress() after some part of the current picture has decoded. +Call ff_progress_frame_report() after some part of the current picture has decoded. A good place to put this is where draw_horiz_band() is called - add this if it isn't called anywhere, as it's useful too and the implementation is trivial when you're doing this. Note that draw_edges() needs to be called before reporting progress. -Before accessing a reference frame or its MVs, call ff_thread_await_progress(). +Before accessing a reference frame or its MVs, call ff_progress_frame_await(). diff --git a/doc/muxers.texi b/doc/muxers.texi index a10a8e216..ce93ba148 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -569,6 +569,17 @@ experimental, may be renamed or changed, do not use from scripts. @item write_gama write deprecated gama atom + +@item hybrid_fragmented +For recoverability - write the output file as a fragmented file. +This allows the intermediate file to be read while being written +(in particular, if the writing process is aborted uncleanly). When +writing is finished, the file is converted to a regular, non-fragmented +file, which is more compatible and allows easier and quicker seeking. + +If writing is aborted, the intermediate file can manually be +remuxed to get a regular, non-fragmented file of what had been +written into the unfinished file. @end table @item movie_timescale @var{scale} @@ -1900,9 +1911,6 @@ flexible implementation of a segmenter, and can be used to perform HLS segmentation. @subsection Options - -This muxer supports the following options: - @table @option @item hls_init_time @var{duration} Set the initial target segment length. Default value is @var{0}. @@ -1910,9 +1918,9 @@ Set the initial target segment length. Default value is @var{0}. @var{duration} must be a time duration specification, see @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}. -Segment will be cut on the next key frame after this time has passed on the first m3u8 list. -After the initial playlist is filled @command{ffmpeg} will cut segments -at duration equal to @code{hls_time} +Segment will be cut on the next key frame after this time has passed on the +first m3u8 list. After the initial playlist is filled, @command{ffmpeg} will cut +segments at duration equal to @option{hls_time}. @item hls_time @var{duration} Set the target segment length. Default value is 2. @@ -1929,12 +1937,12 @@ will contain all the segments. Default value is 5. Set the number of unreferenced segments to keep on disk before @code{hls_flags delete_segments} deletes them. Increase this to allow continue clients to download segments which were recently referenced in the playlist. Default value is 1, meaning segments older than -@code{hls_list_size+1} will be deleted. +@option{hls_list_size+1} will be deleted. -@item hls_start_number_source +@item hls_start_number_source @var{source} Start the playlist sequence number (@code{#EXT-X-MEDIA-SEQUENCE}) according to the specified source. -Unless @code{hls_flags single_file} is set, it also specifies source of starting sequence numbers of -segment and subtitle filenames. In any case, if @code{hls_flags append_list} +Unless @option{hls_flags single_file} is set, it also specifies source of starting sequence numbers of +segment and subtitle filenames. In any case, if @option{hls_flags append_list} is set and read playlist sequence number is greater than the specified start sequence number, then that value will be used as start value. @@ -1943,26 +1951,25 @@ It accepts the following values: @table @option @item generic (default) -Set the starting sequence numbers according to @var{start_number} option value. +Set the start numbers according to the @option{start_number} option value. @item epoch -The start number will be the seconds since epoch (1970-01-01 00:00:00) +Set the start number as the seconds since epoch (1970-01-01 00:00:00). @item epoch_us -The start number will be the microseconds since epoch (1970-01-01 00:00:00) +Set the start number as the microseconds since epoch (1970-01-01 00:00:00). @item datetime -The start number will be based on the current date/time as YYYYmmddHHMMSS. e.g. 20161231235759. - +Set the start number based on the current date/time as YYYYmmddHHMMSS. e.g. 20161231235759. @end table @item start_number @var{number} Start the playlist sequence number (@code{#EXT-X-MEDIA-SEQUENCE}) from the specified @var{number} -when @var{hls_start_number_source} value is @var{generic}. (This is the default case.) -Unless @code{hls_flags single_file} is set, it also specifies starting sequence numbers of segment and subtitle filenames. +when @option{hls_start_number_source} value is @var{generic}. (This is the default case.) +Unless @option{hls_flags single_file} is set, it also specifies starting sequence numbers of segment and subtitle filenames. Default value is 0. -@item hls_allow_cache @var{allowcache} +@item hls_allow_cache @var{bool} Explicitly set whether the client MAY (1) or MUST NOT (0) cache media segments. @item hls_base_url @var{baseurl} @@ -1975,29 +1982,37 @@ which can be cyclic, for example if the @option{wrap} option is specified. @item hls_segment_filename @var{filename} -Set the segment filename. Unless @code{hls_flags single_file} is set, -@var{filename} is used as a string format with the segment number: +Set the segment filename. Unless the @option{hls_flags} option is set with +@samp{single_file}, @var{filename} is used as a string format with the +segment number appended. + +For example: @example ffmpeg -i in.nut -hls_segment_filename 'file%03d.ts' out.m3u8 @end example -This example will produce the playlist, @file{out.m3u8}, and segment files: + +will produce the playlist, @file{out.m3u8}, and segment files: @file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc. -@var{filename} may contain full path or relative path specification, -but only the file name part without any path info will be contained in the m3u8 segment list. +@var{filename} may contain a full path or relative path specification, +but only the file name part without any path will be contained in the m3u8 segment list. Should a relative path be specified, the path of the created segment files will be relative to the current working directory. -When strftime_mkdir is set, the whole expanded value of @var{filename} will be written into the m3u8 segment list. +When @option{strftime_mkdir} is set, the whole expanded value of @var{filename} will be written into the m3u8 segment list. -When @code{var_stream_map} is set with two or more variant streams, the -@var{filename} pattern must contain the string "%v", this string specifies -the position of variant stream index in the generated segment file names. +When @option{var_stream_map} is set with two or more variant streams, the +@var{filename} pattern must contain the string "%v", and this string will be +expanded to the position of variant stream index in the generated segment file +names. + +For example: @example ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ -hls_segment_filename 'file_%v_%03d.ts' out_%v.m3u8 @end example -This example will produce the playlists segment file sets: + +will produce the playlists segment file sets: @file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and @file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc. @@ -2007,48 +2022,60 @@ sub-directory or filename.) If the string %v is present in the directory name, t sub-directories are created after expanding the directory name pattern. This enables creation of segments corresponding to different variant streams in subdirectories. + +For example: @example ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ -hls_segment_filename 'vs%v/file_%03d.ts' vs%v/out.m3u8 @end example -This example will produce the playlists segment file sets: +will produce the playlists segment file sets: @file{vs0/file_000.ts}, @file{vs0/file_001.ts}, @file{vs0/file_002.ts}, etc. and @file{vs1/file_000.ts}, @file{vs1/file_001.ts}, @file{vs1/file_002.ts}, etc. -@item strftime -Use strftime() on @var{filename} to expand the segment filename with localtime. -The segment number is also available in this mode, but to use it, you need to specify second_level_segment_index -hls_flag and %%d will be the specifier. +@item strftime @var{bool} +Use @code{strftime()} on @var{filename} to expand the segment filename with +localtime. The segment number is also available in this mode, but to use it, +you need to set @samp{second_level_segment_index} in the @option{hls_flag} and +%%d will be the specifier. + +For example: @example ffmpeg -i in.nut -strftime 1 -hls_segment_filename 'file-%Y%m%d-%s.ts' out.m3u8 @end example -This example will produce the playlist, @file{out.m3u8}, and segment files: +will produce the playlist, @file{out.m3u8}, and segment files: @file{file-20160215-1455569023.ts}, @file{file-20160215-1455569024.ts}, etc. -Note: On some systems/environments, the @code{%s} specifier is not available. See - @code{strftime()} documentation. +Note: On some systems/environments, the @code{%s} specifier is not +available. See @code{strftime()} documentation. + +For example: @example ffmpeg -i in.nut -strftime 1 -hls_flags second_level_segment_index -hls_segment_filename 'file-%Y%m%d-%%04d.ts' out.m3u8 @end example -This example will produce the playlist, @file{out.m3u8}, and segment files: +will produce the playlist, @file{out.m3u8}, and segment files: @file{file-20160215-0001.ts}, @file{file-20160215-0002.ts}, etc. -@item strftime_mkdir -Used together with -strftime_mkdir, it will create all subdirectories which -is expanded in @var{filename}. +@item strftime_mkdir @var{bool} +Used together with @option{strftime}, it will create all subdirectories which +are present in the expanded values of option @option{hls_segment_filename}. + +For example: @example ffmpeg -i in.nut -strftime 1 -strftime_mkdir 1 -hls_segment_filename '%Y%m%d/file-%Y%m%d-%s.ts' out.m3u8 @end example -This example will create a directory 201560215 (if it does not exist), and then +will create a directory @file{201560215} (if it does not exist), and then produce the playlist, @file{out.m3u8}, and segment files: -@file{20160215/file-20160215-1455569023.ts}, @file{20160215/file-20160215-1455569024.ts}, etc. +@file{20160215/file-20160215-1455569023.ts}, +@file{20160215/file-20160215-1455569024.ts}, etc. +For example: @example ffmpeg -i in.nut -strftime 1 -strftime_mkdir 1 -hls_segment_filename '%Y/%m/%d/file-%Y%m%d-%s.ts' out.m3u8 @end example -This example will create a directory hierarchy 2016/02/15 (if any of them do not exist), and then -produce the playlist, @file{out.m3u8}, and segment files: -@file{2016/02/15/file-20160215-1455569023.ts}, @file{2016/02/15/file-20160215-1455569024.ts}, etc. +will create a directory hierarchy @file{2016/02/15} (if any of them do not +exist), and then produce the playlist, @file{out.m3u8}, and segment files: +@file{2016/02/15/file-20160215-1455569023.ts}, +@file{2016/02/15/file-20160215-1455569024.ts}, etc. @item hls_segment_options @var{options_list} Set output format options using a :-separated list of key=value @@ -2065,7 +2092,7 @@ format. The optional third line specifies the initialization vector (IV) as a hexadecimal string to be used instead of the segment sequence number (default) for encryption. Changes to @var{key_info_file} will result in segment encryption with the new key/IV and an entry in the playlist for the new key -URI/IV if @code{hls_flags periodic_rekey} is enabled. +URI/IV if @option{hls_flags periodic_rekey} is enabled. Key info file format: @example @@ -2111,22 +2138,22 @@ ffmpeg -f lavfi -re -i testsrc -c:v h264 -hls_flags delete_segments \ -hls_key_info_file file.keyinfo out.m3u8 @end example -@item -hls_enc @var{enc} +@item hls_enc @var{bool} Enable (1) or disable (0) the AES128 encryption. When enabled every segment generated is encrypted and the encryption key is saved as @var{playlist name}.key. -@item -hls_enc_key @var{key} -16-octet key to encrypt the segments, by default it -is randomly generated. +@item hls_enc_key @var{key} +Specify a 16-octet key to encrypt the segments, by default it is randomly +generated. -@item -hls_enc_key_url @var{keyurl} +@item hls_enc_key_url @var{keyurl} If set, @var{keyurl} is prepended instead of @var{baseurl} to the key filename in the playlist. -@item -hls_enc_iv @var{iv} -16-octet initialization vector for every segment instead -of the autogenerated ones. +@item hls_enc_iv @var{iv} +Specify the 16-octet initialization vector for every segment instead of the +autogenerated ones. @item hls_segment_type @var{flags} Possible values: @@ -2139,23 +2166,23 @@ compatible with all HLS versions. @item fmp4 Output segment files in fragmented MP4 format, similar to MPEG-DASH. fmp4 files may be used in HLS version 7 and above. - @end table @item hls_fmp4_init_filename @var{filename} -Set filename to the fragment files header file, default filename is @file{init.mp4}. +Set filename for the fragment files header file, default filename is @file{init.mp4}. -Use @code{-strftime 1} on @var{filename} to expand the segment filename with localtime. +When @option{strftime} is enabled, @var{filename} is expanded to the segment filename with localtime. + +For example: @example -ffmpeg -i in.nut -hls_segment_type fmp4 -strftime 1 -hls_fmp4_init_filename "%s_init.mp4" out.m3u8 +ffmpeg -i in.nut -hls_segment_type fmp4 -strftime 1 -hls_fmp4_init_filename "%s_init.mp4" out.m3u8 @end example -This will produce init like this -@file{1602678741_init.mp4} +will produce init like this @file{1602678741_init.mp4}. -@item hls_fmp4_init_resend +@item hls_fmp4_init_resend @var{bool} Resend init file after m3u8 file refresh every time, default is @var{0}. -When @code{var_stream_map} is set with two or more variant streams, the +When @option{var_stream_map} is set with two or more variant streams, the @var{filename} pattern must contain the string "%v", this string specifies the position of variant stream index in the generated init file names. The string "%v" may be present in the filename or in the last directory name @@ -2172,11 +2199,12 @@ Possible values: If this flag is set, the muxer will store all segments in a single MPEG-TS file, and will use byte ranges in the playlist. HLS playlists generated with this way will have the version number 4. + For example: @example ffmpeg -i in.nut -hls_flags single_file out.m3u8 @end example -Will produce the playlist, @file{out.m3u8}, and a single segment file, +will produce the playlist, @file{out.m3u8}, and a single segment file, @file{out.ts}. @item delete_segments @@ -2191,7 +2219,7 @@ and remove the @code{#EXT-X-ENDLIST} from the old segment list. Round the duration info in the playlist file segment info to integer values, instead of using floating point. If there are no other features requiring higher HLS versions be used, -then this will allow ffmpeg to output a HLS version 2 m3u8. +then this will allow @command{ffmpeg} to output a HLS version 2 m3u8. @item discont_start Add the @code{#EXT-X-DISCONTINUITY} tag to the playlist, before the @@ -2206,137 +2234,165 @@ detect updates to the encryption info. Be sure to replace this file atomically, including the file containing the AES encryption key. @item independent_segments -Add the @code{#EXT-X-INDEPENDENT-SEGMENTS} to playlists that has video segments -and when all the segments of that playlist are guaranteed to start with a Key frame. +Add the @code{#EXT-X-INDEPENDENT-SEGMENTS} tag to playlists that has video segments +and when all the segments of that playlist are guaranteed to start with a key frame. @item iframes_only -Add the @code{#EXT-X-I-FRAMES-ONLY} to playlists that has video segments +Add the @code{#EXT-X-I-FRAMES-ONLY} tag to playlists that has video segments and can play only I-frames in the @code{#EXT-X-BYTERANGE} mode. @item split_by_time -Allow segments to start on frames other than keyframes. This improves -behavior on some players when the time between keyframes is inconsistent, +Allow segments to start on frames other than key frames. This improves +behavior on some players when the time between key frames is inconsistent, but may make things worse on others, and can cause some oddities during -seeking. This flag should be used with the @code{hls_time} option. +seeking. This flag should be used with the @option{hls_time} option. @item program_date_time Generate @code{EXT-X-PROGRAM-DATE-TIME} tags. @item second_level_segment_index -Makes it possible to use segment indexes as %%d in hls_segment_filename expression -besides date/time values when strftime is on. -To get fixed width numbers with trailing zeroes, %%0xd format is available where x is the required width. +Make it possible to use segment indexes as %%d in the +@option{hls_segment_filename} option expression besides date/time values when +@option{strftime} option is on. To get fixed width numbers with trailing zeroes, %%0xd format +is available where x is the required width. @item second_level_segment_size -Makes it possible to use segment sizes (counted in bytes) as %%s in hls_segment_filename -expression besides date/time values when strftime is on. -To get fixed width numbers with trailing zeroes, %%0xs format is available where x is the required width. +Make it possible to use segment sizes (counted in bytes) as %%s in +@option{hls_segment_filename} option expression besides date/time values when +strftime is on. To get fixed width numbers with trailing zeroes, %%0xs format +is available where x is the required width. @item second_level_segment_duration -Makes it possible to use segment duration (calculated in microseconds) as %%t in hls_segment_filename -expression besides date/time values when strftime is on. -To get fixed width numbers with trailing zeroes, %%0xt format is available where x is the required width. +Make it possible to use segment duration (calculated in microseconds) as %%t in +@option{hls_segment_filename} option expression besides date/time values when +strftime is on. To get fixed width numbers with trailing zeroes, %%0xt format +is available where x is the required width. +For example: @example ffmpeg -i sample.mpeg \ -f hls -hls_time 3 -hls_list_size 5 \ -hls_flags second_level_segment_index+second_level_segment_size+second_level_segment_duration \ -strftime 1 -strftime_mkdir 1 -hls_segment_filename "segment_%Y%m%d%H%M%S_%%04d_%%08s_%%013t.ts" stream.m3u8 @end example -This will produce segments like this: +will produce segments like this: @file{segment_20170102194334_0003_00122200_0000003000000.ts}, @file{segment_20170102194334_0004_00120072_0000003000000.ts} etc. @item temp_file -Write segment data to filename.tmp and rename to filename only once the segment is complete. A webserver -serving up segments can be configured to reject requests to *.tmp to prevent access to in-progress segments -before they have been added to the m3u8 playlist. This flag also affects how m3u8 playlist files are created. -If this flag is set, all playlist files will written into temporary file and renamed after they are complete, similarly as segments are handled. -But playlists with @code{file} protocol and with type (@code{hls_playlist_type}) other than @code{vod} -are always written into temporary file regardless of this flag. Master playlist files (@code{master_pl_name}), if any, with @code{file} protocol, -are always written into temporary file regardless of this flag if @code{master_pl_publish_rate} value is other than zero. +Write segment data to @file{filename.tmp} and rename to filename only once the +segment is complete. +A webserver serving up segments can be configured to reject requests to *.tmp to +prevent access to in-progress segments before they have been added to the m3u8 +playlist. + +This flag also affects how m3u8 playlist files are created. If this flag is set, +all playlist files will be written into a temporary file and renamed after they +are complete, similarly as segments are handled. But playlists with @code{file} +protocol and with @option{hls_playlist_type} type other than @samp{vod} are +always written into a temporary file regardless of this flag. + +Master playlist files specified with @option{master_pl_name}, if any, with +@code{file} protocol, are always written into temporary file regardless of this +flag if @option{master_pl_publish_rate} value is other than zero. @end table -@item hls_playlist_type event -Emit @code{#EXT-X-PLAYLIST-TYPE:EVENT} in the m3u8 header. Forces -@option{hls_list_size} to 0; the playlist can only be appended to. +@item hls_playlist_type @var{type} +If type is @samp{event}, emit @code{#EXT-X-PLAYLIST-TYPE:EVENT} in the m3u8 +header. This forces @option{hls_list_size} to 0; the playlist can only be +appended to. -@item hls_playlist_type vod -Emit @code{#EXT-X-PLAYLIST-TYPE:VOD} in the m3u8 header. Forces -@option{hls_list_size} to 0; the playlist must not change. +If type is @samp{vod}, emit @code{#EXT-X-PLAYLIST-TYPE:VOD} in the m3u8 +header. This forces @option{hls_list_size} to 0; the playlist must not change. -@item method +@item method @var{method} Use the given HTTP method to create the hls files. + +For example: @example ffmpeg -re -i in.ts -f hls -method PUT http://example.com/live/out.m3u8 @end example -This example will upload all the mpegts segment files to the HTTP -server using the HTTP PUT method, and update the m3u8 files every -@code{refresh} times using the same method. -Note that the HTTP server must support the given method for uploading +will upload all the mpegts segment files to the HTTP server using the HTTP PUT +method, and update the m3u8 files every @code{refresh} times using the same +method. Note that the HTTP server must support the given method for uploading files. -@item http_user_agent +@item http_user_agent @var{agent} Override User-Agent field in HTTP header. Applicable only for HTTP output. -@item var_stream_map -Map string which specifies how to group the audio, video and subtitle streams -into different variant streams. The variant stream groups are separated -by space. +@item var_stream_map @var{stream_map} +Specify a map string defining how to group the audio, video and subtitle streams +into different variant streams. The variant stream groups are separated by +space. + Expected string format is like this "a:0,v:0 a:1,v:1 ....". Here a:, v:, s: are the keys to specify audio, video and subtitle streams respectively. Allowed values are 0 to 9 (limited just based on practical usage). When there are two or more variant streams, the output filename pattern must -contain the string "%v", this string specifies the position of variant stream +contain the string "%v": this string specifies the position of variant stream index in the output media playlist filenames. The string "%v" may be present in the filename or in the last directory name containing the file. If the string is present in the directory name, then sub-directories are created after expanding the directory name pattern. This enables creation of variant streams in subdirectories. +A few examples follow. + +@itemize +@item +Create two hls variant streams. The first variant stream will contain video +stream of bitrate 1000k and audio stream of bitrate 64k and the second variant +stream will contain video stream of bitrate 256k and audio stream of bitrate +32k. Here, two media playlist with file names @file{out_0.m3u8} and +@file{out_1.m3u8} will be created. @example ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ http://example.com/live/out_%v.m3u8 @end example -This example creates two hls variant streams. The first variant stream will -contain video stream of bitrate 1000k and audio stream of bitrate 64k and the -second variant stream will contain video stream of bitrate 256k and audio -stream of bitrate 32k. Here, two media playlist with file names out_0.m3u8 and -out_1.m3u8 will be created. If you want something meaningful text instead of indexes -in result names, you may specify names for each or some of the variants -as in the following example. - +@item +If you want something meaningful text instead of indexes in result names, you +may specify names for each or some of the variants. The following example will +create two hls variant streams as in the previous one. But here, the two media +playlist with file names @file{out_my_hd.m3u8} and @file{out_my_sd.m3u8} will be +created. @example ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0,name:my_hd v:1,a:1,name:my_sd" \ http://example.com/live/out_%v.m3u8 @end example -This example creates two hls variant streams as in the previous one. -But here, the two media playlist with file names out_my_hd.m3u8 and -out_my_sd.m3u8 will be created. - +@item +Create three hls variant streams. The first variant stream will be a video only +stream with video bitrate 1000k, the second variant stream will be an audio only +stream with bitrate 64k and the third variant stream will be a video only stream +with bitrate 256k. Here, three media playlist with file names @file{out_0.m3u8}, +@file{out_1.m3u8} and @file{out_2.m3u8} will be created. @example ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k \ -map 0:v -map 0:a -map 0:v -f hls -var_stream_map "v:0 a:0 v:1" \ http://example.com/live/out_%v.m3u8 @end example -This example creates three hls variant streams. The first variant stream will -be a video only stream with video bitrate 1000k, the second variant stream will -be an audio only stream with bitrate 64k and the third variant stream will be a -video only stream with bitrate 256k. Here, three media playlist with file names -out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created. + +@item +Create the variant streams in subdirectories. Here, the first media playlist is +created at @file{http://example.com/live/vs_0/out.m3u8} and the second one at +@file{http://example.com/live/vs_1/out.m3u8}. @example ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ http://example.com/live/vs_%v/out.m3u8 @end example -This example creates the variant streams in subdirectories. Here, the first -media playlist is created at @file{http://example.com/live/vs_0/out.m3u8} and -the second one at @file{http://example.com/live/vs_1/out.m3u8}. + +@item +Create two audio only and two video only variant streams. In addition to the +@code{#EXT-X-STREAM-INF} tag for each variant stream in the master playlist, the +@code{#EXT-X-MEDIA} tag is also added for the two audio only variant streams and +they are mapped to the two video only variant streams with audio group names +'aud_low' and 'aud_high'. +By default, a single hls variant containing all the encoded streams is created. @example ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k \ -map 0:a -map 0:a -map 0:v -map 0:v -f hls \ @@ -2344,14 +2400,15 @@ ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k \ -master_pl_name master.m3u8 \ http://example.com/live/out_%v.m3u8 @end example -This example creates two audio only and two video only variant streams. In -addition to the #EXT-X-STREAM-INF tag for each variant stream in the master -playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams -and they are mapped to the two video only variant streams with audio group names -'aud_low' and 'aud_high'. +@item + +Create two audio only and one video only variant streams. In addition to the +@code{#EXT-X-STREAM-INF} tag for each variant stream in the master playlist, the +@code{#EXT-X-MEDIA} tag is also added for the two audio only variant streams and +they are mapped to the one video only variant streams with audio group name +'aud_low', and the audio group have default stat is NO or YES. By default, a single hls variant containing all the encoded streams is created. - @example ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \ -map 0:a -map 0:a -map 0:v -f hls \ @@ -2359,14 +2416,15 @@ ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \ -master_pl_name master.m3u8 \ http://example.com/live/out_%v.m3u8 @end example -This example creates two audio only and one video only variant streams. In -addition to the #EXT-X-STREAM-INF tag for each variant stream in the master -playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams -and they are mapped to the one video only variant streams with audio group name -'aud_low', and the audio group have default stat is NO or YES. - -By default, a single hls variant containing all the encoded streams is created. +@item +Create two audio only and one video only variant streams. In addition to the +@code{#EXT-X-STREAM-INF} tag for each variant stream in the master playlist, the +@code{#EXT-X-MEDIA} tag is also added for the two audio only variant streams and +they are mapped to the one video only variant streams with audio group name +'aud_low', and the audio group have default stat is NO or YES, and one audio +have and language is named ENG, the other audio language is named CHN. By +default, a single hls variant containing all the encoded streams is created. @example ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \ -map 0:a -map 0:a -map 0:v -f hls \ @@ -2374,15 +2432,11 @@ ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \ -master_pl_name master.m3u8 \ http://example.com/live/out_%v.m3u8 @end example -This example creates two audio only and one video only variant streams. In -addition to the #EXT-X-STREAM-INF tag for each variant stream in the master -playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams -and they are mapped to the one video only variant streams with audio group name -'aud_low', and the audio group have default stat is NO or YES, and one audio -have and language is named ENG, the other audio language is named CHN. - -By default, a single hls variant containing all the encoded streams is created. +@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. @example ffmpeg -y -i input_with_subtitle.mkv \ -b:v:0 5250k -c:v h264 -pix_fmt yuv420p -profile:v main -level 4.1 \ @@ -2390,85 +2444,103 @@ ffmpeg -y -i input_with_subtitle.mkv \ -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" \ -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 \ + 10 -master_pl_publish_rate 10 -hls_flags \ delete_segments+discont_start+split_by_time ./tmp/video.m3u8 @end example +@end itemize -This example adds @code{#EXT-X-MEDIA} tag with @code{TYPE=SUBTITLES} in -the master playlist with webvtt subtitle group name 'subtitle'. Please make sure -the input file has one text subtitle stream at least. - -@item cc_stream_map +@item cc_stream_map @var{cc_stream_map} Map string which specifies different closed captions groups and their attributes. The closed captions stream groups are separated by space. + Expected string format is like this "ccgroup:,instreamid:,language: ....". 'ccgroup' and 'instreamid' are mandatory attributes. 'language' is an optional attribute. + The closed captions groups configured using this option are mapped to different variant streams by providing the same 'ccgroup' name in the -@code{var_stream_map} string. If @code{var_stream_map} is not set, then the -first available ccgroup in @code{cc_stream_map} is mapped to the output variant -stream. The examples for these two use cases are given below. +@option{var_stream_map} string. -@example -ffmpeg -re -i in.ts -b:v 1000k -b:a 64k -a53cc 1 -f hls \ - -cc_stream_map "ccgroup:cc,instreamid:CC1,language:en" \ - -master_pl_name master.m3u8 \ - http://example.com/live/out.m3u8 -@end example -This example adds @code{#EXT-X-MEDIA} tag with @code{TYPE=CLOSED-CAPTIONS} in -the master playlist with group name 'cc', language 'en' (english) and -INSTREAM-ID 'CC1'. Also, it adds @code{CLOSED-CAPTIONS} attribute with group -name 'cc' for the output variant stream. +For example: @example ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ - -a53cc:0 1 -a53cc:1 1\ + -a53cc:0 1 -a53cc:1 1 \ -map 0:v -map 0:a -map 0:v -map 0:a -f hls \ -cc_stream_map "ccgroup:cc,instreamid:CC1,language:en ccgroup:cc,instreamid:CC2,language:sp" \ -var_stream_map "v:0,a:0,ccgroup:cc v:1,a:1,ccgroup:cc" \ -master_pl_name master.m3u8 \ http://example.com/live/out_%v.m3u8 @end example -This example adds two @code{#EXT-X-MEDIA} tags with @code{TYPE=CLOSED-CAPTIONS} in -the master playlist for the INSTREAM-IDs 'CC1' and 'CC2'. Also, it adds +will add two @code{#EXT-X-MEDIA} tags with @code{TYPE=CLOSED-CAPTIONS} in the +master playlist for the INSTREAM-IDs 'CC1' and 'CC2'. Also, it will add @code{CLOSED-CAPTIONS} attribute with group name 'cc' for the two output variant streams. -@item master_pl_name +If @option{var_stream_map} is not set, then the first available ccgroup in +@option{cc_stream_map} is mapped to the output variant stream. + +For example: +@example +ffmpeg -re -i in.ts -b:v 1000k -b:a 64k -a53cc 1 -f hls \ + -cc_stream_map "ccgroup:cc,instreamid:CC1,language:en" \ + -master_pl_name master.m3u8 \ + http://example.com/live/out.m3u8 +@end example +this will add @code{#EXT-X-MEDIA} tag with @code{TYPE=CLOSED-CAPTIONS} in the +master playlist with group name 'cc', language 'en' (english) and INSTREAM-ID +'CC1'. Also, it will add @code{CLOSED-CAPTIONS} attribute with group name 'cc' +for the output variant stream. + +@item master_pl_name @var{name} Create HLS master playlist with the given name. +For example: @example ffmpeg -re -i in.ts -f hls -master_pl_name master.m3u8 http://example.com/live/out.m3u8 @end example -This example creates HLS master playlist with name master.m3u8 and it is -published at http://example.com/live/ +creates an HLS master playlist with name @file{master.m3u8} which is published +at @url{http://example.com/live/}. -@item master_pl_publish_rate +@item master_pl_publish_rate @var{count} Publish master play list repeatedly every after specified number of segment intervals. +For example: @example ffmpeg -re -i in.ts -f hls -master_pl_name master.m3u8 \ -hls_time 2 -master_pl_publish_rate 30 http://example.com/live/out.m3u8 @end example - -This example creates HLS master playlist with name master.m3u8 and keep +creates an HLS master playlist with name @file{master.m3u8} and keeps publishing it repeatedly every after 30 segments i.e. every after 60s. -@item http_persistent +@item http_persistent @var{bool} Use persistent HTTP connections. Applicable only for HTTP output. -@item timeout +@item timeout @var{timeout} Set timeout for socket I/O operations. Applicable only for HTTP output. -@item ignore_io_errors +@item ignore_io_errors @var{bool} Ignore IO errors during open, write and delete. Useful for long-duration runs with network output. -@item headers +@item headers @var{headers} Set custom HTTP headers, can override built in default headers. Applicable only for HTTP output. - @end table +@section iamf +Immersive Audio Model and Formats (IAMF) muxer. + +IAMF is used to provide immersive audio content for presentation on a wide range +of devices in both streaming and offline applications. These applications +include internet audio streaming, multicasting/broadcasting services, file +download, gaming, communication, virtual and augmented reality, and others. In +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. + +For more information about this format, see @url{https://aomedia.org/iamf/}. + @anchor{ico} @section ico @@ -2502,11 +2574,16 @@ If a BMP image is used, it must use the BITMAPINFOHEADER DIB header If a PNG image is used, it must use the rgba pixel format @end itemize +@section ilbc +Internet Low Bitrate Codec (iLBC) raw muxer. + +It accepts a single @samp{ilbc} audio stream. + @anchor{image2} -@section image2 +@section image2, image2pipe Image file muxer. -The image file muxer writes video frames to image files. +The @samp{image2} muxer writes video frames to image files. The output filenames are specified by a pattern, which can be used to produce sequentially numbered series of files. @@ -2537,40 +2614,42 @@ each of the YUV420P components. To read or write this image file format, specify the name of the '.Y' file. The muxer will automatically open the '.U' and '.V' files as required. -@subsection Options +The @samp{image2pipe} muxer accepts the same options as the @samp{image2} muxer, +but ignores the pattern verification and expansion, as it is supposed to write +to the command output rather than to an actual stored file. +@subsection Options @table @option -@item frame_pts -If set to 1, expand the filename with pts from pkt->pts. +@item frame_pts @var{bool} +If set to 1, expand the filename with the packet PTS (presentation time stamp). Default value is 0. -@item start_number +@item start_number @var{count} Start the sequence from the specified number. Default value is 1. -@item update +@item update @var{bool} If set to 1, the filename will always be interpreted as just a filename, not a pattern, and the corresponding file will be continuously overwritten with new images. Default value is 0. -@item strftime +@item strftime @var{bool} If set to 1, expand the filename with date and time information from @code{strftime()}. Default value is 0. -@item atomic_writing +@item atomic_writing @var{bool} Write output to a temporary file, which is renamed to target filename once writing is completed. Default is disabled. @item protocol_opts @var{options_list} Set protocol options as a :-separated list of key=value parameters. Values containing the @code{:} special character must be escaped. - @end table @subsection Examples - -The following example shows how to use @command{ffmpeg} for creating a -sequence of files @file{img-001.jpeg}, @file{img-002.jpeg}, ..., -taking one image every second from the input video: +@itemize +@item +Use @command{ffmpeg} for creating a sequence of files @file{img-001.jpeg}, +@file{img-002.jpeg}, ..., taking one image every second from the input video: @example ffmpeg -i in.avi -vsync cfr -r 1 -f image2 'img-%03d.jpeg' @end example @@ -2590,36 +2669,110 @@ Note also that the pattern must not necessarily contain "%d" or ffmpeg -i in.avi -f image2 -frames:v 1 img.jpeg @end example +@item The @option{strftime} option allows you to expand the filename with date and time information. Check the documentation of the @code{strftime()} function for the syntax. -For example to generate image files from the @code{strftime()} -"%Y-%m-%d_%H-%M-%S" pattern, the following @command{ffmpeg} command -can be used: +To generate image files from the @code{strftime()} "%Y-%m-%d_%H-%M-%S" pattern, +the following @command{ffmpeg} command can be used: @example ffmpeg -f v4l2 -r 1 -i /dev/video0 -f image2 -strftime 1 "%Y-%m-%d_%H-%M-%S.jpg" @end example -You can set the file name with current frame's PTS: +@item +Set the file name with current frame's PTS: @example ffmpeg -f v4l2 -r 1 -i /dev/video0 -copyts -f image2 -frame_pts true %d.jpg @end example -A more complex example is to publish contents of your desktop directly to a -WebDAV server every second: +@item +Publish contents of your desktop directly to a WebDAV server every second: @example ffmpeg -f x11grab -framerate 1 -i :0.0 -q:v 6 -update 1 -protocol_opts method=PUT http://example.com/desktop.jpg @end example +@end itemize + +@section ircam +Berkeley / IRCAM / CARL Sound Filesystem (BICSF) format muxer. + +The Berkeley/IRCAM/CARL Sound Format, developed in the 1980s, is a result of the +merging of several different earlier sound file formats and systems including +the csound system developed by Dr Gareth Loy at the Computer Audio Research Lab +(CARL) at UC San Diego, the IRCAM sound file system developed by Rob Gross and +Dan Timis at the Institut de Recherche et Coordination Acoustique / Musique in +Paris and the Berkeley Fast Filesystem. + +It was developed initially as part of the Berkeley/IRCAM/CARL Sound Filesystem, +a suite of programs designed to implement a filesystem for audio applications +running under Berkeley UNIX. It was particularly popular in academic music +research centres, and was used a number of times in the creation of early +computer-generated compositions. + +This muxer accepts a single audio stream containing PCM data. + +@section ivf +On2 IVF muxer. + +IVF was developed by On2 Technologies (formerly known as Duck +Corporation), to store internally developed codecs. + +This muxer accepts a single @samp{vp8}, @samp{vp9}, or @samp{av1} +video stream. + +@section jacosub +JACOsub subtitle format muxer. + +This muxer accepts a single @samp{jacosub} subtitles stream. + +For more information about the format, see +@url{http://unicorn.us.com/jacosub/jscripts.html}. + +@section kvag +Simon & Schuster Interactive VAG muxer. + +This custom VAG container is used by some Simon & Schuster Interactive +games such as "Real War", and "Real War: Rogue States". + +This muxer accepts a single @samp{adpcm_ima_ssi} audio stream. + +@section lc3 +Bluetooth SIG Low Complexity Communication Codec audio (LC3), or +ETSI TS 103 634 Low Complexity Communication Codec plus (LC3plus). + +This muxer accepts a single @samp{lc3} audio stream. + +@section lrc +LRC lyrics file format muxer. + +LRC (short for LyRiCs) is a computer file format that synchronizes +song lyrics with an audio file, such as MP3, Vorbis, or MIDI. + +This muxer accepts a single @samp{subrip} or @samp{text} subtitles stream. + +@subsection Metadata +The following metadata tags are converted to the format corresponding +metadata: + +@table @option +@item title +@item album +@item artist +@item author +@item creator +@item encoder +@item encoder_version +@end table + +If @samp{encoder_version} is not explicitly set, it is automatically +set to the libavformat version. @section matroska - Matroska container muxer. This muxer implements the matroska and webm container specs. @subsection Metadata - The recognized metadata settings in this muxer are: @table @option @@ -2679,18 +2832,15 @@ ffmpeg -i sample_left_right_clip.mpg -an -c:v libvpx -metadata stereo_mode=left_ @end example @subsection Options - -This muxer supports the following options: - @table @option -@item reserve_index_space +@item reserve_index_space @var{size} By default, this muxer writes the index for seeking (called cues in Matroska terms) at the end of the file, because it cannot know in advance how much space to leave for the index at the beginning of the file. However for some use cases -- e.g. streaming where seeking is possible but slow -- it is useful to put the index at the beginning of the file. -If this option is set to a non-zero value, the muxer will reserve a given amount +If this option is set to a non-zero value, the muxer will reserve @var{size} bytes of space in the file header and then try to write the cues there when the muxing finishes. If the reserved space does not suffice, no Cues will be written, the file will be finalized and writing the trailer will return an error. @@ -2699,7 +2849,7 @@ A safe size for most use cases should be about 50kB per hour of video. Note that cues are only written if the output is seekable and this option will have no effect if it is not. -@item cues_to_front +@item cues_to_front @var{bool} If set, the muxer will write the index at the beginning of the file by shifting the main data if necessary. This can be combined with reserve_index_space in which case the data is only shifted if @@ -2707,8 +2857,44 @@ the initially reserved space turns out to be insufficient. This option is ignored if the output is unseekable. -@item default_mode -This option controls how the FlagDefault of the output tracks will be set. +@item cluster_size_limit @var{size} +Store at most the provided amount of bytes in a cluster. + +If not specified, the limit is set automatically to a sensible +hardcoded fixed value. + +@item cluster_time_limit @var{duration} +Store at most the provided number of milliseconds in a cluster. + +If not specified, the limit is set automatically to a sensible +hardcoded fixed value. + +@item dash @var{bool} +Create a WebM file conforming to WebM DASH specification. By default +it is set to @code{false}. + +@item dash_track_number @var{index} +Track number for the DASH stream. By default it is set to @code{1}. + +@item live @var{bool} +Write files assuming it is a live stream. By default it is set to +@code{false}. + +@item allow_raw_vfw @var{bool} +Allow raw VFW mode. By default it is set to @code{false}. + +@item flipped_raw_rgb @var{bool} +If set to @code{true}, store positive height for raw RGB bitmaps, which indicates +bitmap is stored bottom-up. Note that this option does not flip the bitmap +which has to be done manually beforehand, e.g. by using the @samp{vflip} filter. +Default is @code{false} and indicates bitmap is stored top down. + +@item write_crc32 @var{bool} +Write a CRC32 element inside every Level 1 element. By default it is +set to @code{true}. This option is ignored for WebM. + +@item default_mode @var{mode} +Control how the FlagDefault of the output tracks will be set. It influences which tracks players should play by default. The default mode is @samp{passthrough}. @table @samp @@ -2726,37 +2912,46 @@ disposition default exists, no subtitle track will be marked as default. In this mode the FlagDefault is set if and only if the AV_DISPOSITION_DEFAULT flag is set in the disposition of the corresponding stream. @end table - -@item flipped_raw_rgb -If set to true, store positive height for raw RGB bitmaps, which indicates -bitmap is stored bottom-up. Note that this option does not flip the bitmap -which has to be done manually beforehand, e.g. by using the vflip filter. -Default is @var{false} and indicates bitmap is stored top down. - @end table @anchor{md5} @section md5 - MD5 testing format. This is a variant of the @ref{hash} muxer. Unlike that muxer, it defaults to using the MD5 hash function. -@subsection Examples +See also the @ref{hash} and @ref{framemd5} muxers. +@subsection Examples +@itemize +@item To compute the MD5 hash of the input converted to raw audio and video, and store it in the file @file{out.md5}: @example ffmpeg -i INPUT -f md5 out.md5 @end example -You can print the MD5 to stdout with the command: +@item +To print the MD5 hash to stdout: @example ffmpeg -i INPUT -f md5 - @end example +@end itemize -See also the @ref{hash} and @ref{framemd5} muxers. +@section microdvd +MicroDVD subtitle format muxer. + +This muxer accepts a single @samp{microdvd} subtitles stream. + +@section mmf +Synthetic music Mobile Application Format (SMAF) format muxer. + +SMAF is a music data format specified by Yamaha for portable +electronic devices, such as mobile phones and personal digital +assistants. + +This muxer accepts a single @samp{adpcm_yamaha} audio stream. @section mp3 @@ -3038,19 +3233,18 @@ ogg files can be safely chained. @end table -@anchor{rcwt} +@anchor{rcwtenc} @section rcwt -Raw Captions With Time (RCWT) is a format native to ccextractor, a commonly -used open source tool for processing 608/708 closed caption (CC) sources. -It can be used to archive the original, raw CC bitstream and to produce -a source file for later CC processing or conversion. As a result, -it also allows for interopability with ccextractor for processing CC data -extracted via ffmpeg. The format is simple to parse and can be used -to retain all lines and variants of CC. +RCWT (Raw Captions With Time) is a format native to ccextractor, a commonly +used open source tool for processing 608/708 Closed Captions (CC) sources. +It can be used to archive the original extracted CC bitstream and to produce +a source file for later processing or conversion. The format allows +for interoperability between ccextractor and FFmpeg, is simple to parse, +and can be used to create a backup of the CC presentation. -This muxer implements the specification as of 2024-01-05, which has -been stable and unchanged for 10 years as of this writing. +This muxer implements the specification as of March 2024, which has +been stable and unchanged since April 2014. This muxer will have some nuances from the way that ccextractor muxes RCWT. No compatibility issues when processing the output with ccextractor @@ -3060,6 +3254,16 @@ and outputs will not be a bit-exact match. A free specification of RCWT can be found here: @url{https://github.com/CCExtractor/ccextractor/blob/master/docs/BINARY_FILE_FORMAT.TXT} +@subsection Examples + +@itemize +@item +Extract Closed Captions to RCWT using lavfi: +@example +ffmpeg -f lavfi -i "movie=INPUT.mkv[out+subcc]" -map 0:s:0 -c:s copy -f rcwt CC.rcwt.bin +@end example +@end itemize + @anchor{segment} @section segment, stream_segment, ssegment diff --git a/doc/protocols.texi b/doc/protocols.texi index f54600b84..ed70af4b3 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -442,9 +442,6 @@ value is -1. @item chunked_post If set to 1 use chunked Transfer-Encoding for posts, default is 1. -@item content_type -Set a specific content type for the POST messages or for listen mode. - @item http_proxy set HTTP proxy to tunnel through e.g. http://example.com:1234 @@ -452,42 +449,33 @@ set HTTP proxy to tunnel through e.g. http://example.com:1234 Set custom HTTP headers, can override built in default headers. The value must be a string encoding the headers. +@item content_type +Set a specific content type for the POST messages or for listen mode. + +@item user_agent +Override the User-Agent header. If not specified the protocol will use a +string describing the libavformat build. ("Lavf/") + +@item referer +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 post_data Set custom HTTP post data. -@item referer -Set the Referer header. Include 'Referer: URL' header in HTTP request. - -@item user_agent -Override the User-Agent header. If not specified the protocol will use a -string describing the libavformat build. ("Lavf/") - -@item reconnect_at_eof -If set then eof is treated like an error and causes reconnection, this is useful -for live / endless streams. - -@item reconnect_streamed -If set then even streamed/non seekable streams will be reconnected on errors. - -@item reconnect_on_network_error -Reconnect automatically in case of TCP/TLS errors during connect. - -@item reconnect_on_http_error -A comma separated list of HTTP status codes to reconnect on. The list can -include specific status codes (e.g. '503') or the strings '4xx' / '5xx'. - -@item reconnect_delay_max -Sets the maximum delay in seconds after which to give up reconnecting - @item mime_type Export the MIME type. @item http_version Exports the HTTP response version number. Usually "1.0" or "1.1". +@item cookies +Set the cookies to be sent in future requests. The format of each cookie is the +same as the value of a Set-Cookie HTTP response field. Multiple cookies can be +delimited by a newline character. + @item icy If set to 1 request ICY (SHOUTcast) metadata from the server. If the server supports this, the metadata has to be retrieved by the application by reading @@ -504,10 +492,40 @@ contains the last non-empty metadata packet sent by the server. It should be polled in regular intervals by applications interested in mid-stream metadata updates. -@item cookies -Set the cookies to be sent in future requests. The format of each cookie is the -same as the value of a Set-Cookie HTTP response field. Multiple cookies can be -delimited by a newline character. +@item metadata +Set an exported dictionary containing Icecast metadata from the bitstream, if present. +Only useful with the C API. + +@item auth_type + +Set HTTP authentication type. No option for Digest, since this method requires +getting nonce parameters from the server first and can't be used straight away like +Basic. + +@table @option +@item none +Choose the HTTP authentication type automatically. This is the default. +@item basic + +Choose the HTTP basic authentication. + +Basic authentication sends a Base64-encoded string that contains a user name and password +for the client. Base64 is not a form of encryption and should be considered the same as +sending the user name and password in clear text (Base64 is a reversible encoding). +If a resource needs to be protected, strongly consider using an authentication scheme +other than basic authentication. HTTPS/TLS should be used with basic authentication. +Without these additional security enhancements, basic authentication should not be used +to protect sensitive or valuable information. +@end table + +@item send_expect_100 +Send an Expect: 100-continue header for POST. If set to 1 it will send, if set +to 0 it won't, if set to -1 it will try to send if it is applicable. Default +value is -1. + +@item location +An exported dictionary containing the content location. Only useful with the C +API. @item offset Set initial byte offset. @@ -525,6 +543,37 @@ be given a Bad Request response. When unset the HTTP method is not checked for now. This will be replaced by autodetection in the future. +@item reconnect +Reconnect automatically when disconnected before EOF is hit. + +@item reconnect_at_eof +If set then eof is treated like an error and causes reconnection, this is useful +for live / endless streams. + +@item reconnect_on_network_error +Reconnect automatically in case of TCP/TLS errors during connect. + +@item reconnect_on_http_error +A comma separated list of HTTP status codes to reconnect on. The list can +include specific status codes (e.g. '503') or the strings '4xx' / '5xx'. + +@item reconnect_streamed +If set then even streamed/non seekable streams will be reconnected on errors. + +@item reconnect_delay_max +Set the maximum delay in seconds after which to give up reconnecting. + +@item reconnect_max_retries +Set the maximum number of times to retry a connection. Default unset. + +@item reconnect_delay_total_max +Set the maximum total delay in seconds after which to give up reconnecting. + +@item respect_retry_after +If enabled, and a Retry-After header is encountered, its requested reconnection +delay will be honored, rather than using exponential backoff. Useful for 429 and +503 errors. Default enabled. + @item listen If set to 1 enables experimental HTTP server. This can be used to send data when used as an output option, or read data from a client with HTTP POST when used as @@ -551,32 +600,16 @@ ffmpeg -i somefile.ogg -chunked_post 0 -c copy -f ogg http://@var{server}:@var{p wget --post-file=somefile.ogg http://@var{server}:@var{port} @end example -@item send_expect_100 -Send an Expect: 100-continue header for POST. If set to 1 it will send, if set -to 0 it won't, if set to -1 it will try to send if it is applicable. Default -value is -1. +@item resource +The resource requested by a client, when the experimental HTTP server is in use. -@item auth_type +@item reply_code +The HTTP code returned to the client, when the experimental HTTP server is in use. -Set HTTP authentication type. No option for Digest, since this method requires -getting nonce parameters from the server first and can't be used straight away like -Basic. - -@table @option -@item none -Choose the HTTP authentication type automatically. This is the default. -@item basic - -Choose the HTTP basic authentication. - -Basic authentication sends a Base64-encoded string that contains a user name and password -for the client. Base64 is not a form of encryption and should be considered the same as -sending the user name and password in clear text (Base64 is a reversible encoding). -If a resource needs to be protected, strongly consider using an authentication scheme -other than basic authentication. HTTPS/TLS should be used with basic authentication. -Without these additional security enhancements, basic authentication should not be used -to protect sensitive or valuable information. -@end table +@item short_seek_size +Set the threshold, in bytes, for when a readahead should be prefered 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. @end table diff --git a/doc/t2h.pm b/doc/t2h.pm index b7485e1f1..4875d6630 100644 --- a/doc/t2h.pm +++ b/doc/t2h.pm @@ -54,12 +54,24 @@ sub get_formatting_function($$) { } # determine texinfo version -my $program_version_num = version->declare(ff_get_conf('PACKAGE_VERSION'))->numify; +my $package_version = ff_get_conf('PACKAGE_VERSION'); +$package_version =~ s/\+dev$//; +my $program_version_num = version->declare($package_version)->numify; my $program_version_6_8 = $program_version_num >= 6.008000; # no navigation elements ff_set_from_init_file('HEADERS', 0); +my %sectioning_commands = %Texinfo::Common::sectioning_commands; +if (scalar(keys(%sectioning_commands)) == 0) { + %sectioning_commands = %Texinfo::Commands::sectioning_heading_commands; +} + +my %root_commands = %Texinfo::Common::root_commands; +if (scalar(keys(%root_commands)) == 0) { + %root_commands = %Texinfo::Commands::root_commands; +} + sub ffmpeg_heading_command($$$$$) { my $self = shift; @@ -77,6 +89,9 @@ sub ffmpeg_heading_command($$$$$) return $result; } + # no need to set it as the $element_id is output unconditionally + my $heading_id; + my $element_id = $self->command_id($command); $result .= "\n" if (defined($element_id) and $element_id ne ''); @@ -84,24 +99,40 @@ sub ffmpeg_heading_command($$$$$) print STDERR "Process $command " .Texinfo::Structuring::_print_root_command_texi($command)."\n" if ($self->get_conf('DEBUG')); - my $element; - if ($Texinfo::Common::root_commands{$command->{'cmdname'}} - and $command->{'parent'} - and $command->{'parent'}->{'type'} - and $command->{'parent'}->{'type'} eq 'element') { - $element = $command->{'parent'}; + my $output_unit; + if ($root_commands{$command->{'cmdname'}}) { + if ($command->{'associated_unit'}) { + $output_unit = $command->{'associated_unit'}; + } elsif ($command->{'structure'} + and $command->{'structure'}->{'associated_unit'}) { + $output_unit = $command->{'structure'}->{'associated_unit'}; + } elsif ($command->{'parent'} + and $command->{'parent'}->{'type'} + and $command->{'parent'}->{'type'} eq 'element') { + $output_unit = $command->{'parent'}; + } } - if ($element) { + + if ($output_unit) { $result .= &{get_formatting_function($self, 'format_element_header')}($self, $cmdname, - $command, $element); + $command, $output_unit); } my $heading_level; # node is used as heading if there is nothing else. if ($cmdname eq 'node') { - if (!$element or (!$element->{'extra'}->{'section'} - and $element->{'extra'}->{'node'} - and $element->{'extra'}->{'node'} eq $command + if (!$output_unit or + (((!$output_unit->{'extra'}->{'section'} + and $output_unit->{'extra'}->{'node'} + and $output_unit->{'extra'}->{'node'} eq $command) + or + ((($output_unit->{'extra'}->{'unit_command'} + and $output_unit->{'extra'}->{'unit_command'} eq $command) + or + ($output_unit->{'unit_command'} + and $output_unit->{'unit_command'} eq $command)) + and $command->{'extra'} + and not $command->{'extra'}->{'associated_section'})) # bogus node may not have been normalized and defined($command->{'extra'}->{'normalized'}))) { if ($command->{'extra'}->{'normalized'} eq 'Top') { @@ -111,7 +142,15 @@ sub ffmpeg_heading_command($$$$$) } } } else { - $heading_level = $command->{'level'}; + if (defined($command->{'extra'}) + and defined($command->{'extra'}->{'section_level'})) { + $heading_level = $command->{'extra'}->{'section_level'}; + } elsif ($command->{'structure'} + and defined($command->{'structure'}->{'section_level'})) { + $heading_level = $command->{'structure'}->{'section_level'}; + } else { + $heading_level = $command->{'level'}; + } } my $heading = $self->command_text($command); @@ -119,8 +158,8 @@ sub ffmpeg_heading_command($$$$$) # if there is an error in the node. if (defined($heading) and $heading ne '' and defined($heading_level)) { - if ($Texinfo::Common::root_commands{$cmdname} - and $Texinfo::Common::sectioning_commands{$cmdname}) { + if ($root_commands{$cmdname} + and $sectioning_commands{$cmdname}) { my $content_href = $self->command_contents_href($command, 'contents', $self->{'current_filename'}); if ($content_href) { @@ -140,7 +179,13 @@ sub ffmpeg_heading_command($$$$$) } } - if ($self->in_preformatted()) { + my $in_preformatted; + if ($program_version_num >= 7.001090) { + $in_preformatted = $self->in_preformatted_context(); + } else { + $in_preformatted = $self->in_preformatted(); + } + if ($in_preformatted) { $result .= $heading."\n"; } else { # if the level was changed, set the command name right @@ -149,21 +194,25 @@ sub ffmpeg_heading_command($$$$$) $cmdname = $Texinfo::Common::level_to_structuring_command{$cmdname}->[$heading_level]; } - # format_heading_text expects an array of headings for texinfo >= 7.0 if ($program_version_num >= 7.000000) { - $heading = [$heading]; - } - $result .= &{get_formatting_function($self,'format_heading_text')}( + $result .= &{get_formatting_function($self,'format_heading_text')}($self, + $cmdname, [$cmdname], $heading, + $heading_level +$self->get_conf('CHAPTER_HEADER_LEVEL') -1, + $heading_id, $command); + + } else { + $result .= &{get_formatting_function($self,'format_heading_text')}( $self, $cmdname, $heading, $heading_level + $self->get_conf('CHAPTER_HEADER_LEVEL') - 1, $command); + } } } $result .= $content if (defined($content)); return $result; } -foreach my $command (keys(%Texinfo::Common::sectioning_commands), 'node') { +foreach my $command (keys(%sectioning_commands), 'node') { texinfo_register_command_formatting($command, \&ffmpeg_heading_command); } @@ -188,28 +237,56 @@ sub ffmpeg_begin_file($$$) my $filename = shift; my $element = shift; - my $command; - if ($element and $self->get_conf('SPLIT')) { - $command = $self->element_command($element); + my ($element_command, $node_command, $command_for_title); + if ($element) { + if ($element->{'unit_command'}) { + $element_command = $element->{'unit_command'}; + } elsif ($self->can('tree_unit_element_command')) { + $element_command = $self->tree_unit_element_command($element); + } elsif ($self->can('tree_unit_element_command')) { + $element_command = $self->element_command($element); + } + + $node_command = $element_command; + if ($element_command and $element_command->{'cmdname'} + and $element_command->{'cmdname'} ne 'node' + and $element_command->{'extra'} + and $element_command->{'extra'}->{'associated_node'}) { + $node_command = $element_command->{'extra'}->{'associated_node'}; + } + + $command_for_title = $element_command if ($self->get_conf('SPLIT')); } - my ($title, $description, $encoding, $date, $css_lines, - $doctype, $bodytext, $copying_comment, $after_body_open, - $extra_head, $program_and_version, $program_homepage, + my ($title, $description, $keywords, $encoding, $date, $css_lines, $doctype, + $root_html_element_attributes, $body_attributes, $copying_comment, + $after_body_open, $extra_head, $program_and_version, $program_homepage, $program, $generator); - if ($program_version_num >= 7.000000) { - ($title, $description, $encoding, $date, $css_lines, - $doctype, $bodytext, $copying_comment, $after_body_open, + if ($program_version_num >= 7.001090) { + ($title, $description, $keywords, $encoding, $date, $css_lines, $doctype, + $root_html_element_attributes, $body_attributes, $copying_comment, + $after_body_open, $extra_head, $program_and_version, $program_homepage, + $program, $generator) = $self->_file_header_information($command_for_title, + $filename); + } elsif ($program_version_num >= 7.000000) { + ($title, $description, $encoding, $date, $css_lines, $doctype, + $root_html_element_attributes, $copying_comment, $after_body_open, $extra_head, $program_and_version, $program_homepage, - $program, $generator) = $self->_file_header_information($command); + $program, $generator) = $self->_file_header_information($command_for_title, + $filename); } else { ($title, $description, $encoding, $date, $css_lines, - $doctype, $bodytext, $copying_comment, $after_body_open, - $extra_head, $program_and_version, $program_homepage, - $program, $generator) = $self->_file_header_informations($command); + $doctype, $root_html_element_attributes, $copying_comment, + $after_body_open, $extra_head, $program_and_version, $program_homepage, + $program, $generator) = $self->_file_header_informations($command_for_title); } - my $links = $self->_get_links ($filename, $element); + my $links; + if ($program_version_num >= 7.000000) { + $links = $self->_get_links($filename, $element, $node_command); + } else { + $links = $self->_get_links ($filename, $element); + } my $head1 = $ENV{"FFMPEG_HEADER1"} || < @@ -252,13 +329,25 @@ sub ffmpeg_program_string($) if (defined($self->get_conf('PROGRAM')) and $self->get_conf('PROGRAM') ne '' and defined($self->get_conf('PACKAGE_URL'))) { - return $self->convert_tree( + if ($program_version_num >= 7.001090) { + return $self->convert_tree( + $self->cdt('This document was generated using @uref{{program_homepage}, @emph{{program}}}.', + { 'program_homepage' => {'text' => $self->get_conf('PACKAGE_URL')}, + 'program' => {'text' => $self->get_conf('PROGRAM') }})); + } else { + return $self->convert_tree( $self->gdt('This document was generated using @uref{{program_homepage}, @emph{{program}}}.', - { 'program_homepage' => $self->get_conf('PACKAGE_URL'), - 'program' => $self->get_conf('PROGRAM') })); + { 'program_homepage' => {'text' => $self->get_conf('PACKAGE_URL')}, + 'program' => {'text' => $self->get_conf('PROGRAM') }})); + } } else { - return $self->convert_tree( - $self->gdt('This document was generated automatically.')); + if ($program_version_num >= 7.001090) { + return $self->convert_tree( + $self->cdt('This document was generated automatically.')); + } else { + return $self->convert_tree( + $self->gdt('This document was generated automatically.')); + } } } if ($program_version_6_8) { diff --git a/doc/texidep.pl b/doc/texidep.pl index 099690378..33e6c7c53 100644 --- a/doc/texidep.pl +++ b/doc/texidep.pl @@ -1,4 +1,4 @@ -#! /usr/bin/env perl +#!/usr/bin/env perl # This script will print the dependency of a Texinfo file to stdout. # texidep.pl diff --git a/doc/utils.texi b/doc/utils.texi index 76e704fc3..9968725d2 100644 --- a/doc/utils.texi +++ b/doc/utils.texi @@ -801,6 +801,11 @@ The following binary operators are available: @code{+}, @code{-}, The following unary operators are available: @code{+}, @code{-}. +Some internal variables can be used to store and load intermediary +results. They can be accessed using the @code{ld} and @code{st} +functions with an index argument varying from 0 to 9 to specify which +internal variable to access. + The following functions are available: @table @option @item abs(x) @@ -898,9 +903,9 @@ Return 1.0 if @var{x} is +/-INFINITY, 0.0 otherwise. @item isnan(x) Return 1.0 if @var{x} is NAN, 0.0 otherwise. -@item ld(var) -Load the value of the internal variable with number -@var{var}, which was previously stored with st(@var{var}, @var{expr}). +@item ld(idx) +Load the value of the internal variable with index @var{idx}, which was +previously stored with st(@var{idx}, @var{expr}). The function returns the loaded value. @item lerp(x, y, z) @@ -933,21 +938,31 @@ Compute the power of @var{x} elevated @var{y}, it is equivalent to @item print(t) @item print(t, l) -Print the value of expression @var{t} with loglevel @var{l}. If -@var{l} is not specified then a default log level is used. -Returns the value of the expression printed. - -Prints t with loglevel l +Print the value of expression @var{t} with loglevel @var{l}. If @var{l} is not +specified then a default log level is used. +Return the value of the expression printed. @item random(idx) Return a pseudo random value between 0.0 and 1.0. @var{idx} is the -index of the internal variable which will be used to save the -seed/state. +index of the internal variable used to save the seed/state, which can be +previously stored with @code{st(idx)}. + +To initialize the seed, you need to store the seed value as a 64-bit +unsigned integer in the internal variable with index @var{idx}. + +For example, to store the seed with value @code{42} in the internal +variable with index @code{0} and print a few random values: +@example +st(0,42); print(random(0)); print(random(0)); print(random(0)) +@end example @item randomi(idx, min, max) Return a pseudo random value in the interval between @var{min} and -@var{max}. @var{idx} is the index of the internal variable which will -be used to save the seed/state. +@var{max}. @var{idx} is the index of the internal variable which will be used to +save the seed/state, which can be previously stored with @code{st(idx)}. + +To initialize the seed, you need to store the seed value as a 64-bit +unsigned integer in the internal variable with index @var{idx}. @item root(expr, max) Find an input value for which the function represented by @var{expr} @@ -956,14 +971,14 @@ with argument @var{ld(0)} is 0 in the interval 0..@var{max}. The expression in @var{expr} must denote a continuous function or the result is undefined. -@var{ld(0)} is used to represent the function input value, which means -that the given expression will be evaluated multiple times with -various input values that the expression can access through -@code{ld(0)}. When the expression evaluates to 0 then the -corresponding input value will be returned. +@var{ld(0)} is used to represent the function input value, which means that the +given expression will be evaluated multiple times with various input values that +the expression can access through @code{ld(0)}. When the expression evaluates to +0 then the corresponding input value will be returned. @item round(expr) -Round the value of expression @var{expr} to the nearest integer. For example, "round(1.5)" is "2.0". +Round the value of expression @var{expr} to the nearest integer. For example, +"round(1.5)" is "2.0". @item sgn(x) Compute sign of @var{x}. @@ -981,12 +996,15 @@ Compute the square root of @var{expr}. This is equivalent to @item squish(x) Compute expression @code{1/(1 + exp(4*x))}. -@item st(var, expr) +@item st(idx, expr) Store the value of the expression @var{expr} in an internal -variable. @var{var} specifies the number of the variable where to -store the value, and it is a value ranging from 0 to 9. The function -returns the value stored in the internal variable. -Note, Variables are currently not shared between expressions. +variable. @var{idx} specifies the index of the variable where to store +the value, and it is a value ranging from 0 to 9. The function returns +the value stored in the internal variable. + +The stored value can be retrieved with @code{ld(var)}. + +Note: variables are currently not shared between expressions. @item tan(x) Compute tangent of @var{x}. @@ -995,16 +1013,16 @@ Compute tangent of @var{x}. Compute hyperbolic tangent of @var{x}. @item taylor(expr, x) -@item taylor(expr, x, id) +@item taylor(expr, x, idx) Evaluate a Taylor series at @var{x}, given an expression representing -the @code{ld(id)}-th derivative of a function at 0. +the @code{ld(idx)}-th derivative of a function at 0. When the series does not converge the result is undefined. -@var{ld(id)} is used to represent the derivative order in @var{expr}, +@var{ld(idx)} is used to represent the derivative order in @var{expr}, which means that the given expression will be evaluated multiple times with various input values that the expression can access through -@code{ld(id)}. If @var{id} is not specified then 0 is assumed. +@code{ld(idx)}. If @var{idx} is not specified then 0 is assumed. Note, when you have the derivatives at y instead of 0, @code{taylor(expr, x-y)} can be used. diff --git a/ffbuild/arch.mak b/ffbuild/arch.mak index 23a3feb09..3fc40e5e5 100644 --- a/ffbuild/arch.mak +++ b/ffbuild/arch.mak @@ -17,6 +17,7 @@ OBJS-$(HAVE_VSX) += $(VSX-OBJS) $(VSX-OBJS-yes) 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_X86ASM) += $(X86ASM-OBJS) $(X86ASM-OBJS-yes) diff --git a/ffbuild/libversion.sh b/ffbuild/libversion.sh index a94ab5805..ecaa90cde 100755 --- a/ffbuild/libversion.sh +++ b/ffbuild/libversion.sh @@ -1,3 +1,4 @@ +#!/bin/sh toupper(){ echo "$@" | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ } diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index 309ec4d32..9beed94ea 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -33,17 +33,14 @@ #include "compat/va_copy.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" -#include "libswscale/version.h" #include "libswresample/swresample.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" -#include "libavutil/channel_layout.h" #include "libavutil/display.h" #include "libavutil/getenv_utf8.h" -#include "libavutil/mathematics.h" -#include "libavutil/imgutils.h" #include "libavutil/libm.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "libavutil/eval.h" #include "libavutil/dict.h" @@ -249,6 +246,8 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, (uint8_t *)optctx + po->u.off : po->u.dst_ptr; char *arg_allocated = NULL; + enum OptionType so_type = po->type; + SpecifierOptList *sol = NULL; double num; int ret = 0; @@ -289,6 +288,14 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, goto finish; } sol->opt[sol->nb_opt - 1].specifier = str; + + if (po->flags & OPT_FLAG_PERSTREAM) { + ret = stream_specifier_parse(&sol->opt[sol->nb_opt - 1].stream_spec, + str, 0, NULL); + if (ret < 0) + goto finish; + } + dst = &sol->opt[sol->nb_opt - 1].u; } @@ -313,8 +320,9 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, goto finish; *(int *)dst = num; + so_type = OPT_TYPE_INT; } else if (po->type == OPT_TYPE_INT64) { - ret = parse_number(opt, arg, OPT_TYPE_INT64, INT64_MIN, INT64_MAX, &num); + ret = parse_number(opt, arg, OPT_TYPE_INT64, INT64_MIN, (double)INT64_MAX, &num); if (ret < 0) goto finish; @@ -326,6 +334,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, opt, arg); goto finish; } + so_type = OPT_TYPE_INT64; } else if (po->type == OPT_TYPE_FLOAT) { ret = parse_number(opt, arg, OPT_TYPE_FLOAT, -INFINITY, INFINITY, &num); if (ret < 0) @@ -355,7 +364,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt, } if (sol) { - sol->type = po->type; + sol->type = so_type; sol->opt_canon = (po->flags & OPT_HAS_CANON) ? find_option(defs, po->u1.name_canon) : po; } @@ -793,7 +802,7 @@ int split_commandline(OptionParseContext *octx, int argc, char *argv[], while (optindex < argc) { const char *opt = argv[optindex++], *arg; const OptionDef *po; - int ret, group_idx; + int group_idx; av_log(NULL, AV_LOG_DEBUG, "Reading option '%s' ...", opt); @@ -979,17 +988,366 @@ FILE *get_preset_file(char *filename, size_t filename_size, return f; } +int cmdutils_isalnum(char c) +{ + return (c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z'); +} + +void stream_specifier_uninit(StreamSpecifier *ss) +{ + av_freep(&ss->meta_key); + av_freep(&ss->meta_val); + av_freep(&ss->remainder); + + memset(ss, 0, sizeof(*ss)); +} + +int stream_specifier_parse(StreamSpecifier *ss, const char *spec, + int allow_remainder, void *logctx) +{ + char *endptr; + int ret; + + memset(ss, 0, sizeof(*ss)); + + ss->idx = -1; + ss->media_type = AVMEDIA_TYPE_UNKNOWN; + ss->stream_list = STREAM_LIST_ALL; + + av_log(logctx, AV_LOG_TRACE, "Parsing stream specifier: %s\n", spec); + + while (*spec) { + if (*spec <= '9' && *spec >= '0') { /* opt:index */ + ss->idx = strtol(spec, &endptr, 0); + + av_assert0(endptr > spec); + spec = endptr; + + av_log(logctx, AV_LOG_TRACE, + "Parsed index: %d; remainder: %s\n", ss->idx, spec); + + // this terminates the specifier + break; + } else if ((*spec == 'v' || *spec == 'a' || *spec == 's' || + *spec == 'd' || *spec == 't' || *spec == 'V') && + !cmdutils_isalnum(*(spec + 1))) { /* opt:[vasdtV] */ + if (ss->media_type != AVMEDIA_TYPE_UNKNOWN) { + av_log(logctx, AV_LOG_ERROR, "Stream type specified multiple times\n"); + ret = AVERROR(EINVAL); + goto fail; + } + + switch (*spec++) { + case 'v': ss->media_type = AVMEDIA_TYPE_VIDEO; break; + case 'a': ss->media_type = AVMEDIA_TYPE_AUDIO; break; + case 's': ss->media_type = AVMEDIA_TYPE_SUBTITLE; break; + case 'd': ss->media_type = AVMEDIA_TYPE_DATA; break; + case 't': ss->media_type = AVMEDIA_TYPE_ATTACHMENT; break; + case 'V': ss->media_type = AVMEDIA_TYPE_VIDEO; + ss->no_apic = 1; break; + default: av_assert0(0); + } + + av_log(logctx, AV_LOG_TRACE, "Parsed media type: %s; remainder: %s\n", + av_get_media_type_string(ss->media_type), spec); + } else if (*spec == 'g' && *(spec + 1) == ':') { + if (ss->stream_list != STREAM_LIST_ALL) + goto multiple_stream_lists; + + spec += 2; + if (*spec == '#' || (*spec == 'i' && *(spec + 1) == ':')) { + ss->stream_list = STREAM_LIST_GROUP_ID; + + spec += 1 + (*spec == 'i'); + } else + ss->stream_list = STREAM_LIST_GROUP_IDX; + + ss->list_id = strtol(spec, &endptr, 0); + if (spec == endptr) { + av_log(logctx, AV_LOG_ERROR, "Expected stream group idx/ID, got: %s\n", spec); + ret = AVERROR(EINVAL); + goto fail; + } + spec = endptr; + + av_log(logctx, AV_LOG_TRACE, "Parsed stream group %s: %"PRId64"; remainder: %s\n", + ss->stream_list == STREAM_LIST_GROUP_ID ? "ID" : "index", ss->list_id, spec); + } else if (*spec == 'p' && *(spec + 1) == ':') { + if (ss->stream_list != STREAM_LIST_ALL) + goto multiple_stream_lists; + + ss->stream_list = STREAM_LIST_PROGRAM; + + spec += 2; + ss->list_id = strtol(spec, &endptr, 0); + if (spec == endptr) { + av_log(logctx, AV_LOG_ERROR, "Expected program ID, got: %s\n", spec); + ret = AVERROR(EINVAL); + goto fail; + } + spec = endptr; + + av_log(logctx, AV_LOG_TRACE, + "Parsed program ID: %"PRId64"; remainder: %s\n", ss->list_id, spec); + } else if (!strncmp(spec, "disp:", 5)) { + const AVClass *st_class = av_stream_get_class(); + const AVOption *o = av_opt_find(&st_class, "disposition", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ); + char *disp = NULL; + size_t len; + + av_assert0(o); + + if (ss->disposition) { + av_log(logctx, AV_LOG_ERROR, "Multiple disposition specifiers\n"); + ret = AVERROR(EINVAL); + goto fail; + } + + spec += 5; + + for (len = 0; cmdutils_isalnum(spec[len]) || + spec[len] == '_' || spec[len] == '+'; len++) + continue; + + disp = av_strndup(spec, len); + if (!disp) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = av_opt_eval_flags(&st_class, o, disp, &ss->disposition); + av_freep(&disp); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "Invalid disposition specifier\n"); + goto fail; + } + + spec += len; + + av_log(logctx, AV_LOG_TRACE, + "Parsed disposition: 0x%x; remainder: %s\n", ss->disposition, spec); + } else if (*spec == '#' || + (*spec == 'i' && *(spec + 1) == ':')) { + if (ss->stream_list != STREAM_LIST_ALL) + goto multiple_stream_lists; + + ss->stream_list = STREAM_LIST_STREAM_ID; + + spec += 1 + (*spec == 'i'); + ss->list_id = strtol(spec, &endptr, 0); + if (spec == endptr) { + av_log(logctx, AV_LOG_ERROR, "Expected stream ID, got: %s\n", spec); + ret = AVERROR(EINVAL); + goto fail; + } + spec = endptr; + + av_log(logctx, AV_LOG_TRACE, + "Parsed stream ID: %"PRId64"; remainder: %s\n", ss->list_id, spec); + + // this terminates the specifier + break; + } else if (*spec == 'm' && *(spec + 1) == ':') { + av_assert0(!ss->meta_key && !ss->meta_val); + + spec += 2; + ss->meta_key = av_get_token(&spec, ":"); + if (!ss->meta_key) { + ret = AVERROR(ENOMEM); + goto fail; + } + if (*spec == ':') { + spec++; + ss->meta_val = av_get_token(&spec, ":"); + if (!ss->meta_val) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + av_log(logctx, AV_LOG_TRACE, + "Parsed metadata: %s:%s; remainder: %s", ss->meta_key, + ss->meta_val ? ss->meta_val : "", spec); + + // this terminates the specifier + break; + } else if (*spec == 'u' && (*(spec + 1) == '\0' || *(spec + 1) == ':')) { + ss->usable_only = 1; + spec++; + av_log(logctx, AV_LOG_ERROR, "Parsed 'usable only'\n"); + + // this terminates the specifier + break; + } else + break; + + if (*spec == ':') + spec++; + } + + if (*spec) { + if (!allow_remainder) { + av_log(logctx, AV_LOG_ERROR, + "Trailing garbage at the end of a stream specifier: %s\n", + spec); + ret = AVERROR(EINVAL); + goto fail; + } + + if (*spec == ':') + spec++; + + ss->remainder = av_strdup(spec); + if (!ss->remainder) { + ret = AVERROR(EINVAL); + goto fail; + } + } + + return 0; + +multiple_stream_lists: + av_log(logctx, AV_LOG_ERROR, + "Cannot combine multiple program/group designators in a " + "single stream specifier"); + ret = AVERROR(EINVAL); + +fail: + stream_specifier_uninit(ss); + return ret; +} + +unsigned stream_specifier_match(const StreamSpecifier *ss, + const AVFormatContext *s, const AVStream *st, + void *logctx) +{ + const AVStreamGroup *g = NULL; + const AVProgram *p = NULL; + int start_stream = 0, nb_streams; + int nb_matched = 0; + + switch (ss->stream_list) { + case STREAM_LIST_STREAM_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 (st->id != ss->list_id) + return 0; + start_stream = st->index; + nb_streams = st->index + 1; + break; + case STREAM_LIST_ALL: + start_stream = ss->idx >= 0 ? 0 : st->index; + nb_streams = st->index + 1; + break; + case STREAM_LIST_PROGRAM: + for (unsigned i = 0; i < s->nb_programs; i++) { + if (s->programs[i]->id == ss->list_id) { + p = s->programs[i]; + break; + } + } + if (!p) { + av_log(logctx, AV_LOG_WARNING, "No program with ID %"PRId64" exists," + " stream specifier can never match\n", ss->list_id); + return 0; + } + nb_streams = p->nb_stream_indexes; + break; + case STREAM_LIST_GROUP_ID: + for (unsigned i = 0; i < s->nb_stream_groups; i++) { + if (ss->list_id == s->stream_groups[i]->id) { + g = s->stream_groups[i]; + break; + } + } + // fall-through + case STREAM_LIST_GROUP_IDX: + if (ss->stream_list == STREAM_LIST_GROUP_IDX && + ss->list_id >= 0 && ss->list_id < s->nb_stream_groups) + g = s->stream_groups[ss->list_id]; + + if (!g) { + av_log(logctx, AV_LOG_WARNING, "No stream group with group %s %" + PRId64" exists, stream specifier can never match\n", + ss->stream_list == STREAM_LIST_GROUP_ID ? "ID" : "index", + ss->list_id); + return 0; + } + nb_streams = g->nb_streams; + break; + default: av_assert0(0); + } + + for (int i = start_stream; i < nb_streams; i++) { + const AVStream *candidate = s->streams[g ? g->streams[i]->index : + p ? p->stream_index[i] : i]; + + if (ss->media_type != AVMEDIA_TYPE_UNKNOWN && + (ss->media_type != candidate->codecpar->codec_type || + (ss->no_apic && (candidate->disposition & AV_DISPOSITION_ATTACHED_PIC)))) + continue; + + 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) { + const AVCodecParameters *par = candidate->codecpar; + + switch (par->codec_type) { + case AVMEDIA_TYPE_AUDIO: + if (!par->sample_rate || !par->ch_layout.nb_channels || + par->format == AV_SAMPLE_FMT_NONE) + continue; + break; + case AVMEDIA_TYPE_VIDEO: + if (!par->width || !par->height || par->format == AV_PIX_FMT_NONE) + continue; + break; + case AVMEDIA_TYPE_UNKNOWN: + continue; + } + } + + if (ss->disposition && + (candidate->disposition & ss->disposition) != ss->disposition) + continue; + + if (st == candidate) + return ss->idx < 0 || ss->idx == nb_matched; + + nb_matched++; + } + + return 0; +} + int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec) { - int ret = avformat_match_stream_specifier(s, st, spec); + StreamSpecifier ss; + int ret; + + ret = stream_specifier_parse(&ss, spec, 0, NULL); if (ret < 0) - av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); + return ret; + + ret = stream_specifier_match(&ss, s, st, NULL); + stream_specifier_uninit(&ss); return ret; } int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, AVFormatContext *s, AVStream *st, const AVCodec *codec, - AVDictionary **dst) + AVDictionary **dst, AVDictionary **opts_used) { AVDictionary *ret = NULL; const AVDictionaryEntry *t = NULL; @@ -998,10 +1356,6 @@ int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, char prefix = 0; const AVClass *cc = avcodec_get_class(); - if (!codec) - codec = s->oformat ? avcodec_find_encoder(codec_id) - : avcodec_find_decoder(codec_id); - switch (st->codecpar->codec_type) { case AVMEDIA_TYPE_VIDEO: prefix = 'v'; @@ -1020,6 +1374,7 @@ int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, while (t = av_dict_iterate(opts, t)) { const AVClass *priv_class; char *p = strchr(t->key, ':'); + int used = 0; /* check stream specification in opt name */ if (p) { @@ -1037,15 +1392,21 @@ int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, !codec || ((priv_class = codec->priv_class) && av_opt_find(&priv_class, t->key, NULL, flags, - AV_OPT_SEARCH_FAKE_OBJ))) + AV_OPT_SEARCH_FAKE_OBJ))) { av_dict_set(&ret, t->key, t->value, 0); - else if (t->key[0] == prefix && + used = 1; + } else if (t->key[0] == prefix && av_opt_find(&cc, t->key + 1, NULL, flags, - AV_OPT_SEARCH_FAKE_OBJ)) + AV_OPT_SEARCH_FAKE_OBJ)) { av_dict_set(&ret, t->key + 1, t->value, 0); + used = 1; + } if (p) *p = ':'; + + if (used && opts_used) + av_dict_set(opts_used, t->key, "", 0); } *dst = ret; @@ -1053,7 +1414,7 @@ int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, } int setup_find_stream_info_opts(AVFormatContext *s, - AVDictionary *codec_opts, + AVDictionary *local_codec_opts, AVDictionary ***dst) { int ret; @@ -1069,8 +1430,8 @@ int setup_find_stream_info_opts(AVFormatContext *s, return AVERROR(ENOMEM); for (int i = 0; i < s->nb_streams; i++) { - ret = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id, - s, s->streams[i], NULL, &opts[i]); + ret = filter_codec_opts(local_codec_opts, s->streams[i]->codecpar->codec_id, + s, s->streams[i], NULL, &opts[i], NULL); if (ret < 0) goto fail; } @@ -1153,3 +1514,23 @@ char *file_read(const char *filename) return NULL; return str; } + +void remove_avoptions(AVDictionary **a, AVDictionary *b) +{ + const AVDictionaryEntry *t = NULL; + + while ((t = av_dict_iterate(b, t))) { + av_dict_set(a, t->key, NULL, AV_DICT_MATCH_CASE); + } +} + +int check_avoptions(AVDictionary *m) +{ + const AVDictionaryEntry *t = av_dict_iterate(m, NULL); + if (t) { + av_log(NULL, AV_LOG_FATAL, "Option %s not found.\n", t->key); + return AVERROR_OPTION_NOT_FOUND; + } + + return 0; +} diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h index d0c773663..316b6a8c6 100644 --- a/fftools/cmdutils.h +++ b/fftools/cmdutils.h @@ -102,8 +102,70 @@ enum OptionType { int parse_number(const char *context, const char *numstr, enum OptionType type, double min, double max, double *dst); +enum StreamList { + STREAM_LIST_ALL, + STREAM_LIST_STREAM_ID, + STREAM_LIST_PROGRAM, + STREAM_LIST_GROUP_ID, + STREAM_LIST_GROUP_IDX, +}; + +typedef struct StreamSpecifier { + // trailing stream index - pick idx-th stream that matches + // all the other constraints; -1 when not present + int idx; + + // which stream list to consider + enum StreamList stream_list; + + // STREAM_LIST_STREAM_ID: stream ID + // STREAM_LIST_GROUP_IDX: group index + // STREAM_LIST_GROUP_ID: group ID + // STREAM_LIST_PROGRAM: program ID + int64_t list_id; + + // when not AVMEDIA_TYPE_UNKNOWN, consider only streams of this type + enum AVMediaType media_type; + uint8_t no_apic; + + uint8_t usable_only; + + int disposition; + + char *meta_key; + char *meta_val; + + char *remainder; +} StreamSpecifier; + +/** + * Parse a stream specifier string into a form suitable for matching. + * + * @param ss Parsed specifier will be stored here; must be uninitialized + * with stream_specifier_uninit() when no longer needed. + * @param spec String containing the stream specifier to be parsed. + * @param allow_remainder When 1, the part of spec that is left after parsing + * the stream specifier is stored into ss->remainder. + * When 0, any remainder will cause parsing to fail. + */ +int stream_specifier_parse(StreamSpecifier *ss, const char *spec, + int allow_remainder, void *logctx); + +/** + * @return 1 if st matches the parsed specifier, 0 if it does not + */ +unsigned stream_specifier_match(const StreamSpecifier *ss, + const AVFormatContext *s, const AVStream *st, + void *logctx); + +void stream_specifier_uninit(StreamSpecifier *ss); + typedef struct SpecifierOpt { - char *specifier; /**< stream/chapter/program/... specifier */ + // original specifier or empty string + char *specifier; + // parsed specifier for OPT_FLAG_PERSTREAM options + StreamSpecifier stream_spec; + union { uint8_t *str; int i; @@ -120,6 +182,9 @@ typedef struct SpecifierOptList { /* Canonical option definition that was parsed into this list. */ const struct OptionDef *opt_canon; + /* Type corresponding to the field that should be used from SpecifierOpt.u. + * May not match the option type, e.g. OPT_TYPE_BOOL options are stored as + * int, so this field would be OPT_TYPE_INT for them */ enum OptionType type; } SpecifierOptList; @@ -371,11 +436,13 @@ int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec); * @param codec The particular codec for which the options should be filtered. * If null, the default one is looked up according to the codec id. * @param dst a pointer to the created dictionary + * @param opts_used if non-NULL, every option stored in dst is also stored here, + * with specifiers preserved * @return a non-negative number on success, a negative error code on failure */ int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, AVFormatContext *s, AVStream *st, const AVCodec *codec, - AVDictionary **dst); + AVDictionary **dst, AVDictionary **opts_used); /** * Setup AVCodecContext options for avformat_find_stream_info(). @@ -465,22 +532,17 @@ void *allocate_array_elem(void *array, size_t elem_size, int *nb_elems); #define GROW_ARRAY(array, nb_elems)\ grow_array((void**)&array, sizeof(*array), &nb_elems, nb_elems + 1) -#define GET_PIX_FMT_NAME(pix_fmt)\ - const char *name = av_get_pix_fmt_name(pix_fmt); - -#define GET_CODEC_NAME(id)\ - const char *name = avcodec_descriptor_get(id)->name; - -#define GET_SAMPLE_FMT_NAME(sample_fmt)\ - const char *name = av_get_sample_fmt_name(sample_fmt) - -#define GET_SAMPLE_RATE_NAME(rate)\ - char name[16];\ - snprintf(name, sizeof(name), "%d", rate); - double get_rotation(const int32_t *displaymatrix); /* read file contents into a string */ char *file_read(const char *filename); +/* Remove keys in dictionary b from dictionary a */ +void remove_avoptions(AVDictionary **a, AVDictionary *b); + +/* Check if any keys exist in dictionary m */ +int check_avoptions(AVDictionary *m); + +int cmdutils_isalnum(char c); + #endif /* FFTOOLS_CMDUTILS_H */ diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 4a0c7d5c4..420ba3c6e 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -68,40 +68,19 @@ #include #endif -#include "libavutil/avassert.h" -#include "libavutil/avstring.h" #include "libavutil/bprint.h" -#include "libavutil/channel_layout.h" #include "libavutil/dict.h" -#include "libavutil/display.h" -#include "libavutil/fifo.h" -#include "libavutil/hwcontext.h" -#include "libavutil/imgutils.h" -#include "libavutil/intreadwrite.h" -#include "libavutil/libm.h" -#include "libavutil/mathematics.h" -#include "libavutil/opt.h" -#include "libavutil/parseutils.h" -#include "libavutil/pixdesc.h" -#include "libavutil/samplefmt.h" -#include "libavutil/thread.h" -#include "libavutil/threadmessage.h" +#include "libavutil/mem.h" #include "libavutil/time.h" -#include "libavutil/timestamp.h" - -#include "libavcodec/version.h" #include "libavformat/avformat.h" #include "libavdevice/avdevice.h" -#include "libswresample/swresample.h" - #include "cmdutils.h" #include "ffmpeg.h" #include "ffmpeg_sched.h" #include "ffmpeg_utils.h" -#include "sync_queue.h" const char program_name[] = "ffmpeg"; const int program_birth_year = 2000; @@ -157,7 +136,7 @@ void term_exit(void) static volatile int received_sigterm = 0; static volatile int received_nb_signals = 0; -static atomic_int transcode_init_done = ATOMIC_VAR_INIT(0); +static atomic_int transcode_init_done = 0; static volatile int ffmpeg_exited = 0; static int64_t copy_ts_first_pts = AV_NOPTS_VALUE; @@ -330,8 +309,8 @@ const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL }; static void ffmpeg_cleanup(int ret) { if (do_benchmark) { - int maxrss = getmaxrss() / 1024; - av_log(NULL, AV_LOG_INFO, "bench: maxrss=%iKiB\n", maxrss); + int64_t maxrss = getmaxrss() / 1024; + av_log(NULL, AV_LOG_INFO, "bench: maxrss=%"PRId64"KiB\n", maxrss); } for (int i = 0; i < nb_filtergraphs; i++) @@ -495,21 +474,51 @@ const FrameData *packet_data_c(AVPacket *pkt) return ret < 0 ? NULL : (const FrameData*)pkt->opaque_ref->data; } -void remove_avoptions(AVDictionary **a, AVDictionary *b) +int check_avoptions_used(const AVDictionary *opts, const AVDictionary *opts_used, + void *logctx, int decode) { - const AVDictionaryEntry *t = NULL; + const AVClass *class = avcodec_get_class(); + const AVClass *fclass = avformat_get_class(); - while ((t = av_dict_iterate(b, t))) { - av_dict_set(a, t->key, NULL, AV_DICT_MATCH_CASE); - } -} + const int flag = decode ? AV_OPT_FLAG_DECODING_PARAM : + AV_OPT_FLAG_ENCODING_PARAM; + const AVDictionaryEntry *e = NULL; -int check_avoptions(AVDictionary *m) -{ - const AVDictionaryEntry *t; - if ((t = av_dict_get(m, "", NULL, AV_DICT_IGNORE_SUFFIX))) { - av_log(NULL, AV_LOG_FATAL, "Option %s not found.\n", t->key); - return AVERROR_OPTION_NOT_FOUND; + while ((e = av_dict_iterate(opts, e))) { + const AVOption *option, *foption; + char *optname, *p; + + if (av_dict_get(opts_used, e->key, NULL, 0)) + continue; + + optname = av_strdup(e->key); + if (!optname) + return AVERROR(ENOMEM); + + p = strchr(optname, ':'); + if (p) + *p = 0; + + option = av_opt_find(&class, optname, NULL, 0, + AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); + foption = av_opt_find(&fclass, optname, NULL, 0, + AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); + av_freep(&optname); + if (!option || foption) + continue; + + if (!(option->flags & flag)) { + av_log(logctx, AV_LOG_ERROR, "Codec AVOption %s (%s) is not a %s " + "option.\n", e->key, option->help ? option->help : "", + decode ? "decoding" : "encoding"); + return AVERROR(EINVAL); + } + + av_log(logctx, AV_LOG_WARNING, "Codec AVOption %s (%s) has not been used " + "for any stream. The most likely reason is either wrong type " + "(e.g. a video option with no video streams) or that it is a " + "private option of some decoder which was not actually used " + "for any stream.\n", e->key, option->help ? option->help : ""); } return 0; @@ -578,7 +587,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti av_bprintf(&buf_script, "stream_%d_%d_q=%.1f\n", ost->file->index, ost->index, q); } - if (!vid && ost->type == AVMEDIA_TYPE_VIDEO && ost->filter) { + if (!vid && ost->type == AVMEDIA_TYPE_VIDEO) { float fps; uint64_t frame_number = atomic_load(&ost->packets_written); @@ -592,8 +601,10 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti if (is_last_report) av_bprintf(&buf, "L"); - nb_frames_dup = atomic_load(&ost->filter->nb_frames_dup); - nb_frames_drop = atomic_load(&ost->filter->nb_frames_drop); + if (ost->filter) { + nb_frames_dup = atomic_load(&ost->filter->nb_frames_dup); + nb_frames_drop = atomic_load(&ost->filter->nb_frames_drop); + } vid = 1; } @@ -809,6 +820,11 @@ static int check_keyboard_interaction(int64_t cur_time) (n = sscanf(buf, "%63[^ ] %lf %255[^ ] %255[^\n]", target, &time, command, arg)) >= 3) { av_log(NULL, AV_LOG_DEBUG, "Processing command target:%s time:%f command:%s arg:%s", target, time, command, arg); + for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) { + if (ost->fg_simple) + fg_send_command(ost->fg_simple, time, target, command, arg, + key == 'C'); + } for (i = 0; i < nb_filtergraphs; i++) fg_send_command(filtergraphs[i], time, target, command, arg, key == 'C'); diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 6394cca1e..733d551fa 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -112,12 +112,32 @@ typedef struct HWDevice { AVBufferRef *device_ref; } HWDevice; +enum ViewSpecifierType { + // no specifier given + VIEW_SPECIFIER_TYPE_NONE = 0, + // val is view index + VIEW_SPECIFIER_TYPE_IDX, + // val is view ID + VIEW_SPECIFIER_TYPE_ID, + // specify view by its position, val is AV_STEREO3D_VIEW_LEFT/RIGHT + VIEW_SPECIFIER_TYPE_POS, + // use all views, val is ignored + VIEW_SPECIFIER_TYPE_ALL, +}; + +typedef struct ViewSpecifier { + enum ViewSpecifierType type; + unsigned val; +} ViewSpecifier; + /* select an input stream for an output stream */ typedef struct StreamMap { int disabled; /* 1 is this mapping is disabled by a negative map */ int file_index; int stream_index; char *linklabel; /* name of an output link, for mapping lavfi outputs */ + + ViewSpecifier vs; } StreamMap; typedef struct OptionsContext { @@ -155,6 +175,7 @@ typedef struct OptionsContext { SpecifierOptList hwaccel_devices; SpecifierOptList hwaccel_output_formats; SpecifierOptList autorotate; + SpecifierOptList apply_cropping; /* output options */ StreamMap *stream_maps; @@ -239,6 +260,7 @@ enum IFilterFlags { IFILTER_FLAG_AUTOROTATE = (1 << 0), IFILTER_FLAG_REINIT = (1 << 1), IFILTER_FLAG_CFR = (1 << 2), + IFILTER_FLAG_CROP = (1 << 3), }; typedef struct InputFilterOptions { @@ -254,6 +276,11 @@ typedef struct InputFilterOptions { * accurate */ AVRational framerate; + unsigned crop_top; + unsigned crop_bottom; + unsigned crop_left; + unsigned crop_right; + int sub2video_width; int sub2video_height; @@ -263,20 +290,78 @@ typedef struct InputFilterOptions { AVFrame *fallback; } InputFilterOptions; +enum OFilterFlags { + OFILTER_FLAG_DISABLE_CONVERT = (1 << 0), + // produce 24-bit audio + OFILTER_FLAG_AUDIO_24BIT = (1 << 1), + OFILTER_FLAG_AUTOSCALE = (1 << 2), +}; + +typedef struct OutputFilterOptions { + // Caller-provided name for this output + char *name; + + // Codec used for encoding, may be NULL + const AVCodec *enc; + + int64_t trim_start_us; + int64_t trim_duration_us; + int64_t ts_offset; + + /* Desired output timebase. + * Numerator can be one of EncTimeBase values, or 0 when no preference. + */ + AVRational output_tb; + + AVDictionary *sws_opts; + AVDictionary *swr_opts; + + const char *nb_threads; + + // A combination of OFilterFlags. + unsigned flags; + + int format; + int width; + int height; + enum AVColorSpace color_space; + enum AVColorRange color_range; + + enum VideoSyncMethod vsync_method; + + int sample_rate; + AVChannelLayout ch_layout; + + const int *formats; + const int *sample_rates; + const AVChannelLayout *ch_layouts; + const AVRational *frame_rates; + const enum AVColorSpace *color_spaces; + const enum AVColorRange *color_ranges; + + // for simple filtergraphs only, view specifier passed + // along to the decoder + const ViewSpecifier *vs; +} OutputFilterOptions; + typedef struct InputFilter { struct FilterGraph *graph; uint8_t *name; } InputFilter; typedef struct OutputFilter { - struct OutputStream *ost; + const AVClass *class; + struct FilterGraph *graph; uint8_t *name; /* for filters that are not yet bound to an output stream, * this stores the output linklabel, if any */ + int bound; uint8_t *linklabel; + char *apad; + enum AVMediaType type; atomic_uint_least64_t nb_frames_dup; @@ -304,6 +389,8 @@ enum DecoderFlags { DECODER_FLAG_TOP_FIELD_FIRST = (1 << 3), #endif DECODER_FLAG_SEND_END_TS = (1 << 4), + // force bitexact decoding + DECODER_FLAG_BITEXACT = (1 << 5), }; typedef struct DecoderOpts { @@ -368,8 +455,6 @@ typedef struct InputStream { int top_field_first; #endif - int autorotate; - int fix_sub_duration; /* decoded data from this stream goes into all those filters @@ -492,6 +577,13 @@ typedef struct KeyframeForceCtx { typedef struct Encoder Encoder; +enum CroppingType { + CROP_DISABLED = 0, + CROP_ALL, + CROP_CODEC, + CROP_CONTAINER, +}; + typedef struct OutputStream { const AVClass *class; @@ -515,21 +607,16 @@ typedef struct OutputStream { AVStream *st; /* stream in the output file */ - AVRational enc_timebase; - Encoder *enc; AVCodecContext *enc_ctx; /* video only */ AVRational frame_rate; AVRational max_frame_rate; - enum VideoSyncMethod vsync_method; - int is_cfr; int force_fps; #if FFMPEG_OPT_TOP int top_field_first; #endif - int autoscale; int bitexact; int bits_per_raw_sample; @@ -537,20 +624,15 @@ typedef struct OutputStream { KeyframeForceCtx kf; - char *logfile_prefix; + const char *logfile_prefix; FILE *logfile; + // simple filtergraph feeding this stream, if any + FilterGraph *fg_simple; OutputFilter *filter; - AVDictionary *encoder_opts; - AVDictionary *sws_dict; - AVDictionary *swr_opts; - char *apad; - char *attachment_filename; - int keep_pix_fmt; - /* stats */ // number of packets send to the muxer atomic_uint_least64_t packets_written; @@ -576,7 +658,6 @@ typedef struct OutputFile { int index; - const AVOutputFormat *format; const char *url; OutputStream **streams; @@ -585,7 +666,6 @@ typedef struct OutputFile { int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units - int shortest; int bitexact; } OutputFile; @@ -618,6 +698,7 @@ extern int nb_input_files; extern OutputFile **output_files; extern int nb_output_files; +// complex filtergraphs extern FilterGraph **filtergraphs; extern int nb_filtergraphs; @@ -672,11 +753,10 @@ void term_exit(void); void show_usage(void); -void remove_avoptions(AVDictionary **a, AVDictionary *b); -int check_avoptions(AVDictionary *m); +int check_avoptions_used(const AVDictionary *opts, const AVDictionary *opts_used, + void *logctx, int decode); int assert_file_overwrite(const char *filename); -AVDictionary *strip_specifiers(const AVDictionary *dict); 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); @@ -684,8 +764,9 @@ int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_id int filtergraph_is_simple(const FilterGraph *fg); int init_simple_filtergraph(InputStream *ist, OutputStream *ost, char *graph_desc, - Scheduler *sch, unsigned sch_idx_enc); -int fg_finalise_bindings(FilterGraph *fg); + Scheduler *sch, unsigned sch_idx_enc, + const OutputFilterOptions *opts); +int fg_finalise_bindings(void); /** * Get our axiliary frame data attached to the frame, allocating it @@ -699,7 +780,8 @@ FrameData *packet_data (AVPacket *pkt); const FrameData *packet_data_c(AVPacket *pkt); int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, - unsigned sched_idx_enc); + unsigned sched_idx_enc, + const OutputFilterOptions *opts); /** * Create a new filtergraph in the global filtergraph list. @@ -759,7 +841,21 @@ void dec_free(Decoder **pdec); * * @param opts filtergraph input options, to be filled by this function */ -int dec_filter_add(Decoder *dec, InputFilter *ifilter, InputFilterOptions *opts); +int dec_filter_add(Decoder *dec, InputFilter *ifilter, InputFilterOptions *opts, + const ViewSpecifier *vs, SchedulerNode *src); + +/* + * For multiview video, request output of the view(s) determined by vs. + * May be called multiple times. + * + * If this function is never called, only the base view is output. If it is + * called at least once, only the views requested are output. + * + * @param src scheduler node from which the frames corresponding vs + * will originate + */ +int dec_request_view(Decoder *dec, const ViewSpecifier *vs, + SchedulerNode *src); int enc_alloc(Encoder **penc, const AVCodec *codec, Scheduler *sch, unsigned sch_idx); @@ -789,7 +885,8 @@ void ifile_close(InputFile **f); int ist_output_add(InputStream *ist, OutputStream *ost); int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, - InputFilterOptions *opts); + const ViewSpecifier *vs, InputFilterOptions *opts, + SchedulerNode *src); /** * Find an unused input stream of given type. @@ -806,46 +903,18 @@ OutputStream *ost_iter(OutputStream *prev); void update_benchmark(const char *fmt, ...); -#define SPECIFIER_OPT_FMT_str "%s" -#define SPECIFIER_OPT_FMT_i "%i" -#define SPECIFIER_OPT_FMT_i64 "%"PRId64 -#define SPECIFIER_OPT_FMT_ui64 "%"PRIu64 -#define SPECIFIER_OPT_FMT_f "%f" -#define SPECIFIER_OPT_FMT_dbl "%lf" - -#define WARN_MULTIPLE_OPT_USAGE(optname, type, idx, st)\ -{\ - char namestr[128] = "";\ - const SpecifierOpt *so = &o->optname.opt[idx];\ - const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";\ - snprintf(namestr, sizeof(namestr), "-%s", o->optname.opt_canon->name);\ - if (o->optname.opt_canon->flags & OPT_HAS_ALT) {\ - const char * const *names_alt = o->optname.opt_canon->u1.names_alt;\ - for (int _i = 0; names_alt[_i]; _i++)\ - av_strlcatf(namestr, sizeof(namestr), "/-%s", names_alt[_i]);\ - }\ - av_log(NULL, AV_LOG_WARNING, "Multiple %s options specified for stream %d, only the last option '-%s%s%s "SPECIFIER_OPT_FMT_##type"' will be used.\n",\ - namestr, st->index, o->optname.opt_canon->name, spec[0] ? ":" : "", spec, so->u.type);\ -} - -#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\ -{\ - int _ret, _matches = 0, _match_idx;\ - for (int _i = 0; _i < o->name.nb_opt; _i++) {\ - char *spec = o->name.opt[_i].specifier;\ - if ((_ret = check_stream_specifier(fmtctx, st, spec)) > 0) {\ - outvar = o->name.opt[_i].u.type;\ - _match_idx = _i;\ - _matches++;\ - } else if (_ret < 0)\ - return _ret;\ - }\ - if (_matches > 1 && o->name.opt_canon)\ - WARN_MULTIPLE_OPT_USAGE(name, type, _match_idx, st);\ -} - const char *opt_match_per_type_str(const SpecifierOptList *sol, char mediatype); +void opt_match_per_stream_str(void *logctx, const SpecifierOptList *sol, + AVFormatContext *fc, AVStream *st, const char **out); +void opt_match_per_stream_int(void *logctx, const SpecifierOptList *sol, + AVFormatContext *fc, AVStream *st, int *out); +void opt_match_per_stream_int64(void *logctx, const SpecifierOptList *sol, + AVFormatContext *fc, AVStream *st, int64_t *out); +void opt_match_per_stream_dbl(void *logctx, const SpecifierOptList *sol, + AVFormatContext *fc, AVStream *st, double *out); + +int view_specifier_parse(const char **pspec, ViewSpecifier *vs); int muxer_thread(void *arg); int encoder_thread(void *arg); diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c index ed411b6bf..2723a0312 100644 --- a/fftools/ffmpeg_dec.c +++ b/fftools/ffmpeg_dec.c @@ -16,24 +16,25 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/dict.h" #include "libavutil/error.h" #include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" +#include "libavutil/stereo3d.h" #include "libavutil/time.h" #include "libavutil/timestamp.h" #include "libavcodec/avcodec.h" #include "libavcodec/codec.h" -#include "libavfilter/buffersrc.h" - #include "ffmpeg.h" -#include "ffmpeg_utils.h" -#include "thread_queue.h" typedef struct DecoderPriv { Decoder dec; @@ -41,6 +42,7 @@ typedef struct DecoderPriv { AVCodecContext *dec_ctx; AVFrame *frame; + AVFrame *frame_tmp_ref; AVPacket *pkt; // override output video sample aspect ratio with this value @@ -50,6 +52,7 @@ typedef struct DecoderPriv { // a combination of DECODER_FLAG_*, provided to dec_open() int flags; + int apply_cropping; enum AVPixelFormat hwaccel_pix_fmt; enum HWAccelID hwaccel_id; @@ -78,6 +81,23 @@ typedef struct DecoderPriv { char log_name[32]; char *parent_name; + // user specified decoder multiview options manually + int multiview_user_config; + + struct { + ViewSpecifier vs; + unsigned out_idx; + } *views_requested; + int nb_views_requested; + + /* A map of view ID to decoder outputs. + * MUST NOT be accessed outside of get_format()/get_buffer() */ + struct { + unsigned id; + uintptr_t out_mask; + } *view_map; + int nb_view_map; + struct { AVDictionary *opts; const AVCodec *codec; @@ -107,6 +127,7 @@ void dec_free(Decoder **pdec) avcodec_free_context(&dp->dec_ctx); av_frame_free(&dp->frame); + av_frame_free(&dp->frame_tmp_ref); av_packet_free(&dp->pkt); av_dict_free(&dp->standalone_init.opts); @@ -117,6 +138,9 @@ void dec_free(Decoder **pdec) av_freep(&dp->parent_name); + av_freep(&dp->views_requested); + av_freep(&dp->view_map); + av_freep(pdec); } @@ -261,6 +285,10 @@ static int64_t video_duration_estimate(const DecoderPriv *dp, const AVFrame *fra const int ts_unreliable = dp->flags & DECODER_FLAG_TS_UNRELIABLE; const int fr_forced = dp->flags & DECODER_FLAG_FRAMERATE_FORCED; int64_t codec_duration = 0; + // difference between this and last frame's timestamps + const int64_t ts_diff = + (frame->pts != AV_NOPTS_VALUE && dp->last_frame_pts != AV_NOPTS_VALUE) ? + frame->pts - dp->last_frame_pts : -1; // XXX lavf currently makes up frame durations when they are not provided by // the container. As there is no way to reliably distinguish real container @@ -268,8 +296,13 @@ static int64_t video_duration_estimate(const DecoderPriv *dp, const AVFrame *fra // the container has timestamps. Eventually lavf should stop making up // durations, then this should be simplified. + // frame duration is unreliable (typically guessed by lavf) when it is equal + // to 1 and the actual duration of the last frame is more than 2x larger + const int duration_unreliable = frame->duration == 1 && ts_diff > 2 * frame->duration; + // prefer frame duration for containers with timestamps - if (frame->duration > 0 && (!ts_unreliable || fr_forced)) + if (fr_forced || + (frame->duration > 0 && !ts_unreliable && !duration_unreliable)) return frame->duration; if (dp->dec_ctx->framerate.den && dp->dec_ctx->framerate.num) { @@ -286,9 +319,8 @@ static int64_t video_duration_estimate(const DecoderPriv *dp, const AVFrame *fra // when timestamps are available, repeat last frame's actual duration // (i.e. pts difference between this and last frame) - if (frame->pts != AV_NOPTS_VALUE && dp->last_frame_pts != AV_NOPTS_VALUE && - frame->pts > dp->last_frame_pts) - return frame->pts - dp->last_frame_pts; + if (ts_diff > 0) + return ts_diff; // try frame/codec duration if (frame->duration > 0) @@ -350,7 +382,8 @@ fail: return err; } -static int video_frame_process(DecoderPriv *dp, AVFrame *frame) +static int video_frame_process(DecoderPriv *dp, AVFrame *frame, + unsigned *outputs_mask) { #if FFMPEG_OPT_TOP if (dp->flags & DECODER_FLAG_TOP_FIELD_FIRST) { @@ -403,6 +436,18 @@ static int video_frame_process(DecoderPriv *dp, AVFrame *frame) if (dp->sar_override.num) frame->sample_aspect_ratio = dp->sar_override; + if (dp->apply_cropping) { + // lavfi does not require aligned frame data + int ret = av_frame_apply_cropping(frame, AV_FRAME_CROP_UNALIGNED); + if (ret < 0) { + av_log(dp, AV_LOG_ERROR, "Error applying decoder cropping\n"); + return ret; + } + } + + if (frame->opaque) + *outputs_mask = (uintptr_t)frame->opaque; + return 0; } @@ -562,7 +607,7 @@ static int process_subtitle(DecoderPriv *dp, AVFrame *frame) if (!subtitle) return 0; - ret = sch_dec_send(dp->sch, dp->sch_idx, frame); + ret = sch_dec_send(dp->sch, dp->sch_idx, 0, frame); if (ret < 0) av_frame_unref(frame); @@ -604,7 +649,7 @@ static int transcode_subtitles(DecoderPriv *dp, const AVPacket *pkt, frame->time_base = pkt->time_base; frame->opaque = (void*)(intptr_t)FRAME_OPAQUE_SUB_HEARTBEAT; - ret = sch_dec_send(dp->sch, dp->sch_idx, frame); + ret = sch_dec_send(dp->sch, dp->sch_idx, 0, frame); return ret == AVERROR_EOF ? AVERROR_EXIT : ret; } else if (pkt && (intptr_t)pkt->opaque == PKT_OPAQUE_FIX_SUB_DURATION) { return fix_sub_duration_heartbeat(dp, av_rescale_q(pkt->pts, pkt->time_base, @@ -699,6 +744,7 @@ static int packet_decode(DecoderPriv *dp, AVPacket *pkt, AVFrame *frame) while (1) { FrameData *fd; + unsigned outputs_mask = 1; av_frame_unref(frame); @@ -747,7 +793,7 @@ static int packet_decode(DecoderPriv *dp, AVPacket *pkt, AVFrame *frame) audio_ts_process(dp, frame); } else { - ret = video_frame_process(dp, frame); + ret = video_frame_process(dp, frame, &outputs_mask); if (ret < 0) { av_log(dp, AV_LOG_FATAL, "Error while processing the decoded data\n"); @@ -757,10 +803,28 @@ static int packet_decode(DecoderPriv *dp, AVPacket *pkt, AVFrame *frame) dp->dec.frames_decoded++; - ret = sch_dec_send(dp->sch, dp->sch_idx, frame); - if (ret < 0) { - av_frame_unref(frame); - return ret == AVERROR_EOF ? AVERROR_EXIT : ret; + for (int i = 0; i < stdc_count_ones(outputs_mask); i++) { + AVFrame *to_send = frame; + int pos; + + av_assert0(outputs_mask); + pos = stdc_trailing_zeros(outputs_mask); + outputs_mask &= ~(1U << pos); + + // this is not the last output and sch_dec_send() consumes the frame + // given to it, so make a temporary reference + if (outputs_mask) { + to_send = dp->frame_tmp_ref; + ret = av_frame_ref(to_send, frame); + if (ret < 0) + return ret; + } + + ret = sch_dec_send(dp->sch, dp->sch_idx, pos, to_send); + if (ret < 0) { + av_frame_unref(to_send); + return ret == AVERROR_EOF ? AVERROR_EXIT : ret; + } } } } @@ -935,7 +999,7 @@ static int decoder_thread(void *arg) dp->last_frame_pts + dp->last_frame_duration_est; dt.frame->time_base = dp->last_frame_tb; - ret = sch_dec_send(dp->sch, dp->sch_idx, dt.frame); + ret = sch_dec_send(dp->sch, dp->sch_idx, 0, dt.frame); if (ret < 0 && ret != AVERROR_EOF) { av_log(dp, AV_LOG_FATAL, "Error signalling EOF timestamp: %s\n", av_err2str(ret)); @@ -959,10 +1023,307 @@ finish: return ret; } +int dec_request_view(Decoder *d, const ViewSpecifier *vs, + SchedulerNode *src) +{ + DecoderPriv *dp = dp_from_dec(d); + unsigned out_idx = 0; + int ret; + + if (dp->multiview_user_config) { + if (!vs || vs->type == VIEW_SPECIFIER_TYPE_NONE) { + *src = SCH_DEC_OUT(dp->sch_idx, 0); + return 0; + } + + av_log(dp, AV_LOG_ERROR, + "Manually selecting views with -view_ids cannot be combined " + "with view selection via stream specifiers. It is strongly " + "recommended you always use stream specifiers only.\n"); + return AVERROR(EINVAL); + } + + // when multiview_user_config is not set, NONE specifier is treated + // as requesting the base view + vs = (vs && vs->type != VIEW_SPECIFIER_TYPE_NONE) ? vs : + &(ViewSpecifier){ .type = VIEW_SPECIFIER_TYPE_IDX, .val = 0 }; + + // check if the specifier matches an already-existing one + for (int i = 0; i < dp->nb_views_requested; i++) { + const ViewSpecifier *vs1 = &dp->views_requested[i].vs; + + if (vs->type == vs1->type && + (vs->type == VIEW_SPECIFIER_TYPE_ALL || vs->val == vs1->val)) { + *src = SCH_DEC_OUT(dp->sch_idx, dp->views_requested[i].out_idx); + return 0; + } + } + + // we use a bitmask to map view IDs to decoder outputs, which + // limits the number of outputs allowed + if (dp->nb_views_requested >= sizeof(dp->view_map[0].out_mask) * 8) { + av_log(dp, AV_LOG_ERROR, "Too many view specifiers\n"); + return AVERROR(ENOSYS); + } + + ret = GROW_ARRAY(dp->views_requested, dp->nb_views_requested); + if (ret < 0) + return ret; + + if (dp->nb_views_requested > 1) { + ret = sch_add_dec_output(dp->sch, dp->sch_idx); + if (ret < 0) + return ret; + out_idx = ret; + } + + dp->views_requested[dp->nb_views_requested - 1].out_idx = out_idx; + dp->views_requested[dp->nb_views_requested - 1].vs = *vs; + + *src = SCH_DEC_OUT(dp->sch_idx, + dp->views_requested[dp->nb_views_requested - 1].out_idx); + + return 0; +} + +static int multiview_setup(DecoderPriv *dp, AVCodecContext *dec_ctx) +{ + unsigned views_wanted = 0; + + unsigned nb_view_ids_av, nb_view_ids; + unsigned *view_ids_av = NULL, *view_pos_av = NULL; + int *view_ids = NULL; + int ret; + + // no views/only base view were requested - do nothing + if (!dp->nb_views_requested || + (dp->nb_views_requested == 1 && + dp->views_requested[0].vs.type == VIEW_SPECIFIER_TYPE_IDX && + dp->views_requested[0].vs.val == 0)) + return 0; + + av_freep(&dp->view_map); + dp->nb_view_map = 0; + + // retrieve views available in current CVS + ret = av_opt_get_array_size(dec_ctx, "view_ids_available", + AV_OPT_SEARCH_CHILDREN, &nb_view_ids_av); + if (ret < 0) { + av_log(dp, AV_LOG_ERROR, + "Multiview decoding requested, but decoder '%s' does not " + "support it\n", dec_ctx->codec->name); + return AVERROR(ENOSYS); + } + + if (nb_view_ids_av) { + unsigned nb_view_pos_av; + + if (nb_view_ids_av >= sizeof(views_wanted) * 8) { + av_log(dp, AV_LOG_ERROR, "Too many views in video: %u\n", nb_view_ids_av); + ret = AVERROR(ENOSYS); + goto fail; + } + + view_ids_av = av_calloc(nb_view_ids_av, sizeof(*view_ids_av)); + if (!view_ids_av) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = av_opt_get_array(dec_ctx, "view_ids_available", + AV_OPT_SEARCH_CHILDREN, 0, nb_view_ids_av, + AV_OPT_TYPE_UINT, view_ids_av); + if (ret < 0) + goto fail; + + ret = av_opt_get_array_size(dec_ctx, "view_pos_available", + AV_OPT_SEARCH_CHILDREN, &nb_view_pos_av); + if (ret >= 0 && nb_view_pos_av == nb_view_ids_av) { + view_pos_av = av_calloc(nb_view_ids_av, sizeof(*view_pos_av)); + if (!view_pos_av) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = av_opt_get_array(dec_ctx, "view_pos_available", + AV_OPT_SEARCH_CHILDREN, 0, nb_view_ids_av, + AV_OPT_TYPE_UINT, view_pos_av); + if (ret < 0) + goto fail; + } + } else { + // assume there is a single view with ID=0 + nb_view_ids_av = 1; + view_ids_av = av_calloc(nb_view_ids_av, sizeof(*view_ids_av)); + view_pos_av = av_calloc(nb_view_ids_av, sizeof(*view_pos_av)); + if (!view_ids_av || !view_pos_av) { + ret = AVERROR(ENOMEM); + goto fail; + } + view_pos_av[0] = AV_STEREO3D_VIEW_UNSPEC; + } + + dp->view_map = av_calloc(nb_view_ids_av, sizeof(*dp->view_map)); + if (!dp->view_map) { + ret = AVERROR(ENOMEM); + goto fail; + } + dp->nb_view_map = nb_view_ids_av; + + for (int i = 0; i < dp->nb_view_map; i++) + dp->view_map[i].id = view_ids_av[i]; + + // figure out which views should go to which output + for (int i = 0; i < dp->nb_views_requested; i++) { + const ViewSpecifier *vs = &dp->views_requested[i].vs; + + switch (vs->type) { + case VIEW_SPECIFIER_TYPE_IDX: + if (vs->val >= nb_view_ids_av) { + av_log(dp, exit_on_error ? AV_LOG_ERROR : AV_LOG_WARNING, + "View with index %u requested, but only %u views available " + "in current video sequence (more views may or may not be " + "available in later sequences).\n", + vs->val, nb_view_ids_av); + if (exit_on_error) { + ret = AVERROR(EINVAL); + goto fail; + } + + continue; + } + views_wanted |= 1U << vs->val; + dp->view_map[vs->val].out_mask |= 1ULL << i; + + break; + case VIEW_SPECIFIER_TYPE_ID: { + int view_idx = -1; + + for (unsigned j = 0; j < nb_view_ids_av; j++) { + if (view_ids_av[j] == vs->val) { + view_idx = j; + break; + } + } + if (view_idx < 0) { + av_log(dp, exit_on_error ? AV_LOG_ERROR : AV_LOG_WARNING, + "View with ID %u requested, but is not available " + "in the video sequence\n", vs->val); + if (exit_on_error) { + ret = AVERROR(EINVAL); + goto fail; + } + + continue; + } + views_wanted |= 1U << view_idx; + dp->view_map[view_idx].out_mask |= 1ULL << i; + + break; + } + case VIEW_SPECIFIER_TYPE_POS: { + int view_idx = -1; + + for (unsigned j = 0; view_pos_av && j < nb_view_ids_av; j++) { + if (view_pos_av[j] == vs->val) { + view_idx = j; + break; + } + } + if (view_idx < 0) { + av_log(dp, exit_on_error ? AV_LOG_ERROR : AV_LOG_WARNING, + "View position '%s' requested, but is not available " + "in the video sequence\n", av_stereo3d_view_name(vs->val)); + if (exit_on_error) { + ret = AVERROR(EINVAL); + goto fail; + } + + continue; + } + views_wanted |= 1U << view_idx; + dp->view_map[view_idx].out_mask |= 1ULL << i; + + break; + } + case VIEW_SPECIFIER_TYPE_ALL: + views_wanted |= (1U << nb_view_ids_av) - 1; + + for (int j = 0; j < dp->nb_view_map; j++) + dp->view_map[j].out_mask |= 1ULL << i; + + break; + } + } + if (!views_wanted) { + av_log(dp, AV_LOG_ERROR, "No views were selected for decoding\n"); + ret = AVERROR(EINVAL); + goto fail; + } + + // signal to decoder which views we want + nb_view_ids = stdc_count_ones(views_wanted); + view_ids = av_malloc_array(nb_view_ids, sizeof(*view_ids)); + if (!view_ids) { + ret = AVERROR(ENOMEM); + goto fail; + } + + for (unsigned i = 0; i < nb_view_ids; i++) { + int pos; + + av_assert0(views_wanted); + pos = stdc_trailing_zeros(views_wanted); + views_wanted &= ~(1U << pos); + + view_ids[i] = view_ids_av[pos]; + } + + // unset view_ids in case we set it earlier + av_opt_set(dec_ctx, "view_ids", NULL, AV_OPT_SEARCH_CHILDREN); + + ret = av_opt_set_array(dec_ctx, "view_ids", AV_OPT_SEARCH_CHILDREN, + 0, nb_view_ids, AV_OPT_TYPE_INT, view_ids); + if (ret < 0) + goto fail; + + if (!dp->frame_tmp_ref) { + dp->frame_tmp_ref = av_frame_alloc(); + if (!dp->frame_tmp_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + +fail: + av_freep(&view_ids_av); + av_freep(&view_pos_av); + av_freep(&view_ids); + + return ret; +} + +static void multiview_check_manual(DecoderPriv *dp, const AVDictionary *dec_opts) +{ + if (av_dict_get(dec_opts, "view_ids", NULL, 0)) { + av_log(dp, AV_LOG_WARNING, "Manually selecting views with -view_ids " + "is not recommended, use view specifiers instead\n"); + dp->multiview_user_config = 1; + } +} + static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts) { DecoderPriv *dp = s->opaque; const enum AVPixelFormat *p; + int ret; + + ret = multiview_setup(dp, s); + if (ret < 0) { + av_log(dp, AV_LOG_ERROR, "Error setting up multiview decoding: %s\n", + av_err2str(ret)); + return AV_PIX_FMT_NONE; + } for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p); @@ -993,6 +1354,26 @@ static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat return *p; } +static int get_buffer(AVCodecContext *dec_ctx, AVFrame *frame, int flags) +{ + DecoderPriv *dp = dec_ctx->opaque; + + // for multiview video, store the output mask in frame opaque + if (dp->nb_view_map) { + const AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_VIEW_ID); + int view_id = sd ? *(int*)sd->data : 0; + + for (int i = 0; i < dp->nb_view_map; i++) { + if (dp->view_map[i].id == view_id) { + frame->opaque = (void*)dp->view_map[i].out_mask; + break; + } + } + } + + return avcodec_default_get_buffer2(dec_ctx, frame, flags); +} + static HWDevice *hw_device_match_by_codec(const AVCodec *codec) { const AVCodecHWConfig *config; @@ -1186,13 +1567,12 @@ static int dec_open(DecoderPriv *dp, AVDictionary **dec_opts, dp->dec_ctx->opaque = dp; dp->dec_ctx->get_format = get_format; + dp->dec_ctx->get_buffer2 = get_buffer; dp->dec_ctx->pkt_timebase = o->time_base; if (!av_dict_get(*dec_opts, "threads", NULL, 0)) av_dict_set(dec_opts, "threads", "auto", 0); - av_dict_set(dec_opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY); - ret = hw_device_setup_for_decode(dp, codec, o->hwaccel_device); if (ret < 0) { av_log(dp, AV_LOG_ERROR, @@ -1201,7 +1581,25 @@ static int dec_open(DecoderPriv *dp, AVDictionary **dec_opts, return ret; } - if ((ret = avcodec_open2(dp->dec_ctx, codec, dec_opts)) < 0) { + ret = av_opt_set_dict2(dp->dec_ctx, dec_opts, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) { + av_log(dp, AV_LOG_ERROR, "Error applying decoder options: %s\n", + av_err2str(ret)); + return ret; + } + ret = check_avoptions(*dec_opts); + if (ret < 0) + return ret; + + dp->dec_ctx->flags |= AV_CODEC_FLAG_COPY_OPAQUE; + if (o->flags & DECODER_FLAG_BITEXACT) + dp->dec_ctx->flags |= AV_CODEC_FLAG_BITEXACT; + + // we apply cropping outselves + dp->apply_cropping = dp->dec_ctx->apply_cropping; + dp->dec_ctx->apply_cropping = 0; + + if ((ret = avcodec_open2(dp->dec_ctx, codec, NULL)) < 0) { av_log(dp, AV_LOG_ERROR, "Error while opening decoder: %s\n", av_err2str(ret)); return ret; @@ -1220,10 +1618,6 @@ static int dec_open(DecoderPriv *dp, AVDictionary **dec_opts, dp->dec_ctx->extra_hw_frames = extra_frames; } - ret = check_avoptions(*dec_opts); - if (ret < 0) - return ret; - dp->dec.subtitle_header = dp->dec_ctx->subtitle_header; dp->dec.subtitle_header_size = dp->dec_ctx->subtitle_header_size; @@ -1263,6 +1657,8 @@ int dec_init(Decoder **pdec, Scheduler *sch, if (ret < 0) return ret; + multiview_check_manual(dp, *dec_opts); + ret = dec_open(dp, dec_opts, o, param_out); if (ret < 0) goto fail; @@ -1327,7 +1723,7 @@ int dec_create(const OptionsContext *o, const char *arg, Scheduler *sch) return ret; enc_idx = ret; - ret = sch_connect(sch, SCH_ENC(enc_idx), SCH_DEC(dp->sch_idx)); + ret = sch_connect(sch, SCH_ENC(enc_idx), SCH_DEC_IN(dp->sch_idx)); if (ret < 0) return ret; @@ -1335,6 +1731,8 @@ int dec_create(const OptionsContext *o, const char *arg, Scheduler *sch) if (ret < 0) return ret; + multiview_check_manual(dp, dp->standalone_init.opts); + if (o->codec_names.nb_opt) { const char *name = o->codec_names.opt[o->codec_names.nb_opt - 1].u.str; dp->standalone_init.codec = avcodec_find_decoder_by_name(name); @@ -1347,7 +1745,8 @@ int dec_create(const OptionsContext *o, const char *arg, Scheduler *sch) return 0; } -int dec_filter_add(Decoder *d, InputFilter *ifilter, InputFilterOptions *opts) +int dec_filter_add(Decoder *d, InputFilter *ifilter, InputFilterOptions *opts, + const ViewSpecifier *vs, SchedulerNode *src) { DecoderPriv *dp = dp_from_dec(d); char name[16]; @@ -1357,5 +1756,5 @@ int dec_filter_add(Decoder *d, InputFilter *ifilter, InputFilterOptions *opts) if (!opts->name) return AVERROR(ENOMEM); - return dp->sch_idx; + return dec_request_view(d, vs, src); } diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c index 47312c9fe..13aef15ea 100644 --- a/fftools/ffmpeg_demux.c +++ b/fftools/ffmpeg_demux.c @@ -28,6 +28,7 @@ #include "libavutil/display.h" #include "libavutil/error.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" @@ -64,6 +65,9 @@ typedef struct DemuxStream { int streamcopy_needed; int have_sub2video; int reinit_filters; + int autorotate; + int apply_cropping; + int wrap_correction_done; int saw_first_ts; @@ -870,7 +874,8 @@ void ifile_close(InputFile **pf) av_freep(pf); } -static int ist_use(InputStream *ist, int decoding_needed) +static 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); @@ -908,11 +913,11 @@ static int ist_use(InputStream *ist, int decoding_needed) if (decoding_needed && ds->sch_idx_dec < 0) { int is_audio = ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO; - ds->dec_opts.flags = (!!ist->fix_sub_duration * DECODER_FLAG_FIX_SUB_DURATION) | - (!!(d->f.ctx->iformat->flags & AVFMT_NOTIMESTAMPS) * DECODER_FLAG_TS_UNRELIABLE) | - (!!(d->loop && is_audio) * DECODER_FLAG_SEND_END_TS) + ds->dec_opts.flags |= (!!ist->fix_sub_duration * DECODER_FLAG_FIX_SUB_DURATION) | + (!!(d->f.ctx->iformat->flags & AVFMT_NOTIMESTAMPS) * DECODER_FLAG_TS_UNRELIABLE) | + (!!(d->loop && is_audio) * DECODER_FLAG_SEND_END_TS) #if FFMPEG_OPT_TOP - | ((ist->top_field_first >= 0) * DECODER_FLAG_TOP_FIELD_FIRST) + | ((ist->top_field_first >= 0) * DECODER_FLAG_TOP_FIELD_FIRST) #endif ; @@ -950,22 +955,33 @@ static int ist_use(InputStream *ist, int decoding_needed) ds->sch_idx_dec = ret; ret = sch_connect(d->sch, SCH_DSTREAM(d->f.index, ds->sch_idx_stream), - SCH_DEC(ds->sch_idx_dec)); + SCH_DEC_IN(ds->sch_idx_dec)); if (ret < 0) return ret; d->have_audio_dec |= is_audio; } + if (decoding_needed && ist->par->codec_type == AVMEDIA_TYPE_VIDEO) { + ret = dec_request_view(ist->decoder, vs, src); + if (ret < 0) + return ret; + } else { + *src = decoding_needed ? + SCH_DEC_OUT(ds->sch_idx_dec, 0) : + SCH_DSTREAM(d->f.index, ds->sch_idx_stream); + } + 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); + ret = ist_use(ist, ost->enc ? DECODING_FOR_OST : 0, NULL, &src); if (ret < 0) return ret; @@ -979,14 +995,16 @@ int ist_output_add(InputStream *ist, OutputStream *ost) } int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, - InputFilterOptions *opts) + const ViewSpecifier *vs, InputFilterOptions *opts, + SchedulerNode *src) { Demuxer *d = demuxer_from_ifile(ist->file); DemuxStream *ds = ds_from_ist(ist); int64_t tsoffset = 0; int ret; - ret = ist_use(ist, is_simple ? DECODING_FOR_OST : DECODING_FOR_FILTER); + ret = ist_use(ist, is_simple ? DECODING_FOR_OST : DECODING_FOR_FILTER, + vs, src); if (ret < 0) return ret; @@ -997,11 +1015,23 @@ int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, ist->filters[ist->nb_filters - 1] = ifilter; if (ist->par->codec_type == AVMEDIA_TYPE_VIDEO) { + const AVPacketSideData *sd = av_packet_side_data_get(ist->par->coded_side_data, + ist->par->nb_coded_side_data, + AV_PKT_DATA_FRAME_CROPPING); if (ist->framerate.num > 0 && ist->framerate.den > 0) { opts->framerate = ist->framerate; opts->flags |= IFILTER_FLAG_CFR; } else opts->framerate = av_guess_frame_rate(d->f.ctx, ist->st, NULL); + if (sd && sd->size >= sizeof(uint32_t) * 4) { + opts->crop_top = AV_RL32(sd->data + 0); + opts->crop_bottom = AV_RL32(sd->data + 4); + opts->crop_left = AV_RL32(sd->data + 8); + opts->crop_right = AV_RL32(sd->data + 12); + if (ds->apply_cropping && ds->apply_cropping != CROP_CODEC && + (opts->crop_top | opts->crop_bottom | opts->crop_left | opts->crop_right)) + opts->flags |= IFILTER_FLAG_CROP; + } } else if (ist->par->codec_type == AVMEDIA_TYPE_SUBTITLE) { /* Compute the size of the canvas for the subtitles stream. If the subtitles codecpar has set a size, use it. Otherwise use the @@ -1055,20 +1085,21 @@ int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple, if (!opts->name) return AVERROR(ENOMEM); - opts->flags |= IFILTER_FLAG_AUTOROTATE * !!(ist->autorotate) | + opts->flags |= IFILTER_FLAG_AUTOROTATE * !!(ds->autorotate) | IFILTER_FLAG_REINIT * !!(ds->reinit_filters); - return ds->sch_idx_dec; + return 0; } -static int choose_decoder(const OptionsContext *o, AVFormatContext *s, AVStream *st, +static int choose_decoder(const OptionsContext *o, void *logctx, + AVFormatContext *s, AVStream *st, enum HWAccelID hwaccel_id, enum AVHWDeviceType hwaccel_device_type, const AVCodec **pcodec) { - char *codec_name = NULL; + const char *codec_name = NULL; - MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st); + opt_match_per_stream_str(logctx, &o->codec_names, s, st, &codec_name); if (codec_name) { int ret = find_codec(NULL, codec_name, st->codecpar->codec_type, 0, pcodec); if (ret < 0) @@ -1134,9 +1165,9 @@ static int add_display_matrix_to_stream(const OptionsContext *o, int hflip_set = 0, vflip_set = 0, rotation_set = 0; int32_t *buf; - MATCH_PER_STREAM_OPT(display_rotations, dbl, rotation, ctx, st); - MATCH_PER_STREAM_OPT(display_hflips, i, hflip, ctx, st); - MATCH_PER_STREAM_OPT(display_vflips, i, vflip, ctx, st); + opt_match_per_stream_dbl(ist, &o->display_rotations, ctx, st, &rotation); + opt_match_per_stream_int(ist, &o->display_hflips, ctx, st, &hflip); + opt_match_per_stream_int(ist, &o->display_vflips, ctx, st, &vflip); rotation_set = rotation != DBL_MAX; hflip_set = hflip != -1; @@ -1204,19 +1235,20 @@ static DemuxStream *demux_stream_alloc(Demuxer *d, AVStream *st) return ds; } -static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) +static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictionary **opts_used) { AVFormatContext *ic = d->f.ctx; AVCodecParameters *par = st->codecpar; DemuxStream *ds; InputStream *ist; - char *framerate = NULL, *hwaccel_device = NULL; + const char *framerate = NULL, *hwaccel_device = NULL; const char *hwaccel = NULL; - char *hwaccel_output_format = NULL; - char *codec_tag = NULL; - char *bsfs = NULL; + const char *apply_cropping = NULL; + const char *hwaccel_output_format = NULL; + const char *codec_tag = NULL; + const char *bsfs = NULL; char *next; - char *discard_str = NULL; + const char *discard_str = NULL; int ret; ds = demux_stream_alloc(d, st); @@ -1233,12 +1265,39 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) ds->dec_opts.time_base = st->time_base; ds->ts_scale = 1.0; - MATCH_PER_STREAM_OPT(ts_scale, dbl, ds->ts_scale, ic, st); + opt_match_per_stream_dbl(ist, &o->ts_scale, ic, st, &ds->ts_scale); - ist->autorotate = 1; - MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st); + ds->autorotate = 1; + opt_match_per_stream_int(ist, &o->autorotate, ic, st, &ds->autorotate); - MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st); + ds->apply_cropping = CROP_ALL; + opt_match_per_stream_str(ist, &o->apply_cropping, ic, st, &apply_cropping); + if (apply_cropping) { + const AVOption opts[] = { + { "apply_cropping", NULL, 0, AV_OPT_TYPE_INT, + { .i64 = CROP_ALL }, CROP_DISABLED, CROP_CONTAINER, AV_OPT_FLAG_DECODING_PARAM, .unit = "apply_cropping" }, + { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CROP_DISABLED }, .unit = "apply_cropping" }, + { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CROP_ALL }, .unit = "apply_cropping" }, + { "codec", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CROP_CODEC }, .unit = "apply_cropping" }, + { "container", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CROP_CONTAINER }, .unit = "apply_cropping" }, + { NULL }, + }; + const AVClass class = { + .class_name = "apply_cropping", + .item_name = av_default_item_name, + .option = opts, + .version = LIBAVUTIL_VERSION_INT, + }; + const AVClass *pclass = &class; + + ret = av_opt_eval_int(&pclass, opts, apply_cropping, &ds->apply_cropping); + if (ret < 0) { + av_log(ist, AV_LOG_ERROR, "Invalid apply_cropping value '%s'.\n", apply_cropping); + return ret; + } + } + + opt_match_per_stream_str(ist, &o->codec_tags, ic, st, &codec_tag); if (codec_tag) { uint32_t tag = strtol(codec_tag, &next, 0); if (*next) { @@ -1255,10 +1314,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) if (ret < 0) return ret; - MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st); - MATCH_PER_STREAM_OPT(hwaccel_output_formats, str, - hwaccel_output_format, ic, st); - + opt_match_per_stream_str(ist, &o->hwaccels, ic, st, &hwaccel); + opt_match_per_stream_str(ist, &o->hwaccel_output_formats, ic, st, + &hwaccel_output_format); if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, "cuvid")) { av_log(ist, AV_LOG_WARNING, "WARNING: defaulting hwaccel_output_format to cuda for compatibility " @@ -1316,7 +1374,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) } } - MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st); + opt_match_per_stream_str(ist, &o->hwaccel_devices, ic, st, &hwaccel_device); if (hwaccel_device) { ds->dec_opts.hwaccel_device = av_strdup(hwaccel_device); if (!ds->dec_opts.hwaccel_device) @@ -1324,18 +1382,20 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) } } - ret = choose_decoder(o, ic, st, ds->dec_opts.hwaccel_id, + ret = choose_decoder(o, ist, ic, st, ds->dec_opts.hwaccel_id, ds->dec_opts.hwaccel_device_type, &ist->dec); if (ret < 0) return ret; - ret = filter_codec_opts(o->g->codec_opts, ist->st->codecpar->codec_id, - ic, st, ist->dec, &ds->decoder_opts); - if (ret < 0) - return ret; + if (ist->dec) { + ret = filter_codec_opts(o->g->codec_opts, ist->st->codecpar->codec_id, + ic, st, ist->dec, &ds->decoder_opts, opts_used); + if (ret < 0) + return ret; + } ds->reinit_filters = -1; - MATCH_PER_STREAM_OPT(reinit_filters, i, ds->reinit_filters, ic, st); + opt_match_per_stream_int(ist, &o->reinit_filters, ic, st, &ds->reinit_filters); ist->user_set_discard = AVDISCARD_NONE; @@ -1345,7 +1405,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) (o->data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA)) ist->user_set_discard = AVDISCARD_ALL; - MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st); + opt_match_per_stream_str(ist, &o->discard, ic, st, &discard_str); if (discard_str) { ret = av_opt_set(ist->st, "discard", discard_str, 0); if (ret < 0) { @@ -1355,8 +1415,10 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) ist->user_set_discard = ist->st->discard; } - if (o->bitexact) - av_dict_set(&ds->decoder_opts, "flags", "+bitexact", AV_DICT_MULTIKEY); + ds->dec_opts.flags |= DECODER_FLAG_BITEXACT * !!o->bitexact; + + av_dict_set_int(&ds->decoder_opts, "apply_cropping", + ds->apply_cropping && ds->apply_cropping != CROP_CONTAINER, 0); /* Attached pics are sparse, therefore we would not want to delay their decoding * till EOF. */ @@ -1365,7 +1427,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: - MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st); + opt_match_per_stream_str(ist, &o->frame_rates, ic, st, &framerate); if (framerate) { ret = av_parse_video_rate(&ist->framerate, framerate); if (ret < 0) { @@ -1377,21 +1439,44 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) #if FFMPEG_OPT_TOP ist->top_field_first = -1; - MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st); + opt_match_per_stream_int(ist, &o->top_field_first, ic, st, &ist->top_field_first); #endif break; case AVMEDIA_TYPE_AUDIO: { - int guess_layout_max = INT_MAX; - MATCH_PER_STREAM_OPT(guess_layout_max, i, guess_layout_max, ic, st); - guess_input_channel_layout(ist, par, guess_layout_max); + const char *ch_layout_str = NULL; + + opt_match_per_stream_str(ist, &o->audio_ch_layouts, ic, st, &ch_layout_str); + if (ch_layout_str) { + AVChannelLayout ch_layout; + ret = av_channel_layout_from_string(&ch_layout, ch_layout_str); + if (ret < 0) { + av_log(ist, AV_LOG_ERROR, "Error parsing channel layout %s.\n", ch_layout_str); + return ret; + } + if (par->ch_layout.nb_channels <= 0 || par->ch_layout.nb_channels == ch_layout.nb_channels) { + av_channel_layout_uninit(&par->ch_layout); + par->ch_layout = ch_layout; + } else { + av_log(ist, AV_LOG_ERROR, + "Specified channel layout '%s' has %d channels, but input has %d channels.\n", + ch_layout_str, ch_layout.nb_channels, par->ch_layout.nb_channels); + av_channel_layout_uninit(&ch_layout); + return AVERROR(EINVAL); + } + } else { + int guess_layout_max = INT_MAX; + opt_match_per_stream_int(ist, &o->guess_layout_max, ic, st, &guess_layout_max); + guess_input_channel_layout(ist, par, guess_layout_max); + } break; } case AVMEDIA_TYPE_DATA: case AVMEDIA_TYPE_SUBTITLE: { - char *canvas_size = NULL; - MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st); - MATCH_PER_STREAM_OPT(canvas_sizes, str, canvas_size, ic, st); + const char *canvas_size = NULL; + + opt_match_per_stream_int(ist, &o->fix_sub_duration, ic, st, &ist->fix_sub_duration); + opt_match_per_stream_str(ist, &o->canvas_sizes, ic, st, &canvas_size); if (canvas_size) { ret = av_parse_video_size(&par->width, &par->height, canvas_size); @@ -1421,7 +1506,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) if (ist->st->sample_aspect_ratio.num) ist->par->sample_aspect_ratio = ist->st->sample_aspect_ratio; - MATCH_PER_STREAM_OPT(bitstream_filters, str, bsfs, ic, st); + opt_match_per_stream_str(ist, &o->bitstream_filters, ic, st, &bsfs); if (bsfs) { ret = av_bsf_list_parse_str(bsfs, &ds->bsf); if (ret < 0) { @@ -1526,10 +1611,9 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) InputFile *f; AVFormatContext *ic; const AVInputFormat *file_iformat = NULL; - int err, i, ret = 0; + int err, ret = 0; int64_t timestamp; - AVDictionary *unused_opts = NULL; - const AVDictionaryEntry *e = NULL; + AVDictionary *opts_used = NULL; const char* video_codec_name = NULL; const char* audio_codec_name = NULL; const char* subtitle_codec_name = NULL; @@ -1682,9 +1766,9 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) return ret; /* apply forced codec ids */ - for (i = 0; i < ic->nb_streams; i++) { + for (int i = 0; i < ic->nb_streams; i++) { const AVCodec *dummy; - ret = choose_decoder(o, ic, ic->streams[i], HWACCEL_NONE, AV_HWDEVICE_TYPE_NONE, + ret = choose_decoder(o, f, ic, ic->streams[i], HWACCEL_NONE, AV_HWDEVICE_TYPE_NONE, &dummy); if (ret < 0) return ret; @@ -1702,7 +1786,7 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) first frames to get it. (used in mpeg case for example) */ ret = avformat_find_stream_info(ic, opts); - for (i = 0; i < orig_nb_streams; i++) + for (int i = 0; i < orig_nb_streams; i++) av_dict_free(&opts[i]); av_freep(&opts); @@ -1743,7 +1827,7 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) if (!(ic->iformat->flags & AVFMT_SEEK_TO_PTS)) { int dts_heuristic = 0; - for (i=0; inb_streams; i++) { + for (int i = 0; i < ic->nb_streams; i++) { const AVCodecParameters *par = ic->streams[i]->codecpar; if (par->video_delay) { dts_heuristic = 1; @@ -1801,53 +1885,24 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) /* Add all the streams from the given input file to the demuxer */ for (int i = 0; i < ic->nb_streams; i++) { - ret = ist_add(o, d, ic->streams[i]); - if (ret < 0) + ret = ist_add(o, d, ic->streams[i], &opts_used); + if (ret < 0) { + av_dict_free(&opts_used); return ret; + } } /* dump the file content */ av_dump_format(ic, f->index, filename, 0); /* check if all codec options have been used */ - unused_opts = strip_specifiers(o->g->codec_opts); - for (i = 0; i < f->nb_streams; i++) { - DemuxStream *ds = ds_from_ist(f->streams[i]); - e = NULL; - while ((e = av_dict_iterate(ds->decoder_opts, e))) - av_dict_set(&unused_opts, e->key, NULL, 0); - } + ret = check_avoptions_used(o->g->codec_opts, opts_used, d, 1); + av_dict_free(&opts_used); + if (ret < 0) + return ret; - e = NULL; - while ((e = av_dict_iterate(unused_opts, e))) { - const AVClass *class = avcodec_get_class(); - const AVOption *option = av_opt_find(&class, e->key, NULL, 0, - AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); - const AVClass *fclass = avformat_get_class(); - const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0, - AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); - if (!option || foption) - continue; - - - if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) { - av_log(d, AV_LOG_ERROR, "Codec AVOption %s (%s) is not a decoding " - "option.\n", e->key, option->help ? option->help : ""); - return AVERROR(EINVAL); - } - - av_log(d, AV_LOG_WARNING, "Codec AVOption %s (%s) has not been used " - "for any stream. The most likely reason is either wrong type " - "(e.g. a video option with no video streams) or that it is a " - "private option of some decoder which was not actually used " - "for any stream.\n", e->key, option->help ? option->help : ""); - } - av_dict_free(&unused_opts); - - for (i = 0; i < o->dump_attachment.nb_opt; i++) { - int j; - - for (j = 0; j < f->nb_streams; j++) { + for (int i = 0; i < o->dump_attachment.nb_opt; i++) { + for (int j = 0; j < f->nb_streams; j++) { InputStream *ist = f->streams[j]; if (check_stream_specifier(ic, ist->st, o->dump_attachment.opt[i].specifier) == 1) { diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c index 447f13313..c1c8aa0e7 100644 --- a/fftools/ffmpeg_enc.c +++ b/fftools/ffmpeg_enc.c @@ -20,8 +20,6 @@ #include #include "ffmpeg.h" -#include "ffmpeg_utils.h" -#include "thread_queue.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -32,6 +30,7 @@ #include "libavutil/frame.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/rational.h" #include "libavutil/time.h" @@ -39,8 +38,6 @@ #include "libavcodec/avcodec.h" -#include "libavformat/avformat.h" - struct Encoder { // combined size of all the packets received from the encoder uint64_t data_size; @@ -187,6 +184,20 @@ int enc_open(void *opaque, const AVFrame *frame) if (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 = set_encoder_id(of, ost); @@ -246,21 +257,6 @@ int enc_open(void *opaque, const AVFrame *frame) enc_ctx->colorspace = frame->colorspace; enc_ctx->chroma_sample_location = frame->chroma_location; - for (int i = 0; i < frame->nb_side_data; i++) { - 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) { - av_frame_side_data_free( - &enc_ctx->decoded_side_data, - &enc_ctx->nb_decoded_side_data); - av_log(NULL, AV_LOG_ERROR, - "failed to configure video encoder: %s!\n", - av_err2str(ret)); - return ret; - } - } - if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) || (frame->flags & AV_FRAME_FLAG_INTERLACED) #if FFMPEG_OPT_TOP @@ -284,9 +280,6 @@ int enc_open(void *opaque, const AVFrame *frame) break; } case AVMEDIA_TYPE_SUBTITLE: - if (ost->enc_timebase.num) - av_log(ost, AV_LOG_WARNING, - "-enc_time_base not supported for subtitles, ignoring\n"); enc_ctx->time_base = AV_TIME_BASE_Q; if (!enc_ctx->width) { @@ -314,16 +307,10 @@ int enc_open(void *opaque, const AVFrame *frame) if (ost->bitexact) enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT; - if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0)) - av_dict_set(&ost->encoder_opts, "threads", "auto", 0); + if (enc->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE) + enc_ctx->flags |= AV_CODEC_FLAG_COPY_OPAQUE; - if (enc->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE) { - ret = av_dict_set(&ost->encoder_opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY); - if (ret < 0) - return ret; - } - - av_dict_set(&ost->encoder_opts, "flags", "+frame_duration", AV_DICT_MULTIKEY); + enc_ctx->flags |= AV_CODEC_FLAG_FRAME_DURATION; ret = hw_device_setup_for_encode(ost, frame ? frame->hw_frames_ctx : NULL); if (ret < 0) { @@ -332,7 +319,7 @@ int enc_open(void *opaque, const AVFrame *frame) return ret; } - if ((ret = avcodec_open2(ost->enc_ctx, enc, &ost->encoder_opts)) < 0) { + if ((ret = avcodec_open2(ost->enc_ctx, enc, NULL)) < 0) { if (ret != AVERROR_EXPERIMENTAL) av_log(ost, AV_LOG_ERROR, "Error while opening encoder - maybe " "incorrect parameters such as bit_rate, rate, width or height.\n"); @@ -344,10 +331,6 @@ int enc_open(void *opaque, const AVFrame *frame) if (ost->enc_ctx->frame_size) frame_samples = ost->enc_ctx->frame_size; - ret = check_avoptions(ost->encoder_opts); - if (ret < 0) - return ret; - 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." @@ -360,29 +343,6 @@ int enc_open(void *opaque, const AVFrame *frame) return ret; } - /* - * Add global input side data. For now this is naive, and copies it - * from the input stream's global side data. All side data should - * really be funneled over AVFrame and libavfilter, then added back to - * packet side data, and then potentially using the first packet for - * global side data. - */ - if (ist) { - for (int i = 0; i < ist->st->codecpar->nb_coded_side_data; i++) { - AVPacketSideData *sd_src = &ist->st->codecpar->coded_side_data[i]; - if (sd_src->type != AV_PKT_DATA_CPB_PROPERTIES) { - AVPacketSideData *sd_dst = av_packet_side_data_new(&ost->par_in->coded_side_data, - &ost->par_in->nb_coded_side_data, - sd_src->type, sd_src->size, 0); - if (!sd_dst) - return AVERROR(ENOMEM); - memcpy(sd_dst->data, sd_src->data, sd_src->size); - if (ist->autorotate && sd_src->type == AV_PKT_DATA_DISPLAYMATRIX) - av_display_rotation_set((int32_t *)sd_dst->data, 0); - } - } - } - // 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}); diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 171e47be9..38c7676a7 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -30,11 +30,10 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" -#include "libavutil/display.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" -#include "libavutil/imgutils.h" #include "libavutil/samplefmt.h" #include "libavutil/time.h" #include "libavutil/timestamp.h" @@ -60,6 +59,8 @@ typedef struct FilterGraphPriv { const char *graph_desc; + char *nb_threads; + // frame for temporarily holding output from the filtergraph AVFrame *frame; // frame for sending output to the encoder @@ -143,6 +144,7 @@ typedef struct InputFilterPriv { AVBufferRef *hw_frames_ctx; int displaymatrix_present; + int displaymatrix_applied; int32_t displaymatrix[9]; struct { @@ -175,6 +177,8 @@ typedef struct FPSConvContext { int last_dropped; int dropped_keyframe; + enum VideoSyncMethod vsync_method; + AVRational framerate; AVRational framerate_max; const AVRational *framerate_supported; @@ -186,6 +190,11 @@ typedef struct OutputFilterPriv { int index; + void *log_parent; + char log_name[32]; + + char *name; + AVFilterContext *filter; /* desired output stream properties */ @@ -193,6 +202,8 @@ typedef struct OutputFilterPriv { int width, height; int sample_rate; AVChannelLayout ch_layout; + enum AVColorSpace color_space; + enum AVColorRange color_range; // time base in which the output is sent to our downstream // does not need to match the filtersink's timebase @@ -203,17 +214,26 @@ typedef struct OutputFilterPriv { AVRational sample_aspect_ratio; + AVDictionary *sws_opts; + AVDictionary *swr_opts; + // 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; const AVChannelLayout *ch_layouts; const int *sample_rates; + const enum AVColorSpace *color_spaces; + const enum AVColorRange *color_ranges; AVRational enc_timebase; + int64_t trim_start_us; + int64_t trim_duration_us; // offset for output timestamps, in AV_TIME_BASE_Q int64_t ts_offset; int64_t next_pts; FPSConvContext fps; + + unsigned flags; } OutputFilterPriv; static OutputFilterPriv *ofp_from_ofilter(OutputFilter *ofilter) @@ -348,36 +368,6 @@ static void sub2video_update(InputFilterPriv *ifp, int64_t heartbeat_pts, ifp->sub2video.initialize = 0; } -/* *dst may return be set to NULL (no pixel format found), a static string or a - * string backed by the bprint. Nothing has been written to the AVBPrint in case - * NULL is returned. The AVBPrint provided should be clean. */ -static int choose_pix_fmts(OutputFilter *ofilter, AVBPrint *bprint, - const char **dst) -{ - OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); - OutputStream *ost = ofilter->ost; - - *dst = NULL; - - if (ost->keep_pix_fmt || ofp->format != AV_PIX_FMT_NONE) { - *dst = ofp->format == AV_PIX_FMT_NONE ? NULL : - av_get_pix_fmt_name(ofp->format); - } else if (ofp->formats) { - const enum AVPixelFormat *p = ofp->formats; - - for (; *p != AV_PIX_FMT_NONE; p++) { - const char *name = av_get_pix_fmt_name(*p); - av_bprintf(bprint, "%s%c", name, p[1] == AV_PIX_FMT_NONE ? '\0' : '|'); - } - if (!av_bprint_is_complete(bprint)) - return AVERROR(ENOMEM); - - *dst = bprint->str; - } - - return 0; -} - /* Define a function for appending a list of allowed formats * to an AVBPrint. If nonempty, the list will have a header. */ #define DEF_CHOOSE_FORMAT(name, type, var, supported_list, none, printf_format, get_name) \ @@ -400,8 +390,8 @@ static void choose_ ## name (OutputFilterPriv *ofp, AVBPrint *bprint) \ av_bprint_chars(bprint, ':', 1); \ } -//DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, AV_PIX_FMT_NONE, -// GET_PIX_FMT_NAME) +DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, + AV_PIX_FMT_NONE, "%s", av_get_pix_fmt_name) DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats, AV_SAMPLE_FMT_NONE, "%s", av_get_sample_fmt_name) @@ -409,6 +399,12 @@ DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats, DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0, "%d", ) +DEF_CHOOSE_FORMAT(color_spaces, enum AVColorSpace, color_space, color_spaces, + AVCOL_SPC_UNSPECIFIED, "%s", av_color_space_name); + +DEF_CHOOSE_FORMAT(color_ranges, enum AVColorRange, color_range, color_ranges, + AVCOL_RANGE_UNSPECIFIED, "%s", av_color_range_name); + static void choose_channel_layouts(OutputFilterPriv *ofp, AVBPrint *bprint) { if (av_channel_layout_check(&ofp->ch_layout)) { @@ -624,7 +620,21 @@ static char *describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in) avfilter_pad_get_name(pads, inout->pad_idx)); } -static OutputFilter *ofilter_alloc(FilterGraph *fg) +static const char *ofilter_item_name(void *obj) +{ + OutputFilterPriv *ofp = obj; + return ofp->log_name; +} + +static const AVClass ofilter_class = { + .class_name = "OutputFilter", + .version = LIBAVUTIL_VERSION_INT, + .item_name = ofilter_item_name, + .parent_log_context_offset = offsetof(OutputFilterPriv, log_parent), + .category = AV_CLASS_CATEGORY_FILTER, +}; + +static OutputFilter *ofilter_alloc(FilterGraph *fg, enum AVMediaType type) { OutputFilterPriv *ofp; OutputFilter *ofilter; @@ -634,18 +644,28 @@ static OutputFilter *ofilter_alloc(FilterGraph *fg) return NULL; ofilter = &ofp->ofilter; + ofilter->class = &ofilter_class; + ofp->log_parent = fg; ofilter->graph = fg; + ofilter->type = type; ofp->format = -1; + ofp->color_space = AVCOL_SPC_UNSPECIFIED; + ofp->color_range = AVCOL_RANGE_UNSPECIFIED; ofp->index = fg->nb_outputs - 1; + snprintf(ofp->log_name, sizeof(ofp->log_name), "%co%d", + av_get_media_type_string(type)[0], ofp->index); + return ofilter; } -static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist) +static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist, + const ViewSpecifier *vs) { InputFilterPriv *ifp = ifp_from_ifilter(ifilter); FilterGraphPriv *fgp = fgp_from_fg(ifilter->graph); - int ret, dec_idx; + SchedulerNode src; + int ret; av_assert0(!ifp->bound); ifp->bound = 1; @@ -663,13 +683,13 @@ static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist) if (!ifp->opts.fallback) return AVERROR(ENOMEM); - dec_idx = ist_filter_add(ist, ifilter, filtergraph_is_simple(ifilter->graph), - &ifp->opts); - if (dec_idx < 0) - return dec_idx; + ret = ist_filter_add(ist, ifilter, filtergraph_is_simple(ifilter->graph), + vs, &ifp->opts, &src); + if (ret < 0) + return ret; - ret = sch_connect(fgp->sch, SCH_DEC(dec_idx), - SCH_FILTER_IN(fgp->sch_idx, ifp->index)); + ret = sch_connect(fgp->sch, + src, SCH_FILTER_IN(fgp->sch_idx, ifp->index)); if (ret < 0) return ret; @@ -694,10 +714,12 @@ static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist) return 0; } -static int ifilter_bind_dec(InputFilterPriv *ifp, Decoder *dec) +static int ifilter_bind_dec(InputFilterPriv *ifp, Decoder *dec, + const ViewSpecifier *vs) { FilterGraphPriv *fgp = fgp_from_fg(ifp->ifilter.graph); - int ret, dec_idx; + SchedulerNode src; + int ret; av_assert0(!ifp->bound); ifp->bound = 1; @@ -710,145 +732,156 @@ static int ifilter_bind_dec(InputFilterPriv *ifp, Decoder *dec) ifp->type_src = ifp->type; - dec_idx = dec_filter_add(dec, &ifp->ifilter, &ifp->opts); - if (dec_idx < 0) - return dec_idx; + ret = dec_filter_add(dec, &ifp->ifilter, &ifp->opts, vs, &src); + if (ret < 0) + return ret; - ret = sch_connect(fgp->sch, SCH_DEC(dec_idx), - SCH_FILTER_IN(fgp->sch_idx, ifp->index)); + ret = sch_connect(fgp->sch, src, SCH_FILTER_IN(fgp->sch_idx, ifp->index)); if (ret < 0) return ret; return 0; } -static int set_channel_layout(OutputFilterPriv *f, OutputStream *ost) +static int set_channel_layout(OutputFilterPriv *f, const AVChannelLayout *layouts_allowed, + const AVChannelLayout *layout_requested) { - const AVCodec *c = ost->enc_ctx->codec; int i, err; - if (ost->enc_ctx->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) { + if (layout_requested->order != AV_CHANNEL_ORDER_UNSPEC) { /* Pass the layout through for all orders but UNSPEC */ - err = av_channel_layout_copy(&f->ch_layout, &ost->enc_ctx->ch_layout); + err = av_channel_layout_copy(&f->ch_layout, layout_requested); if (err < 0) return err; return 0; } /* Requested layout is of order UNSPEC */ - if (!c->ch_layouts) { + if (!layouts_allowed) { /* Use the default native layout for the requested amount of channels when the encoder doesn't have a list of supported layouts */ - av_channel_layout_default(&f->ch_layout, ost->enc_ctx->ch_layout.nb_channels); + av_channel_layout_default(&f->ch_layout, layout_requested->nb_channels); return 0; } /* Encoder has a list of supported layouts. Pick the first layout in it with the same amount of channels as the requested layout */ - for (i = 0; c->ch_layouts[i].nb_channels; i++) { - if (c->ch_layouts[i].nb_channels == ost->enc_ctx->ch_layout.nb_channels) + for (i = 0; layouts_allowed[i].nb_channels; i++) { + if (layouts_allowed[i].nb_channels == layout_requested->nb_channels) break; } - if (c->ch_layouts[i].nb_channels) { + if (layouts_allowed[i].nb_channels) { /* Use it if one is found */ - err = av_channel_layout_copy(&f->ch_layout, &c->ch_layouts[i]); + err = av_channel_layout_copy(&f->ch_layout, &layouts_allowed[i]); if (err < 0) return err; return 0; } /* If no layout for the amount of channels requested was found, use the default native layout for it. */ - av_channel_layout_default(&f->ch_layout, ost->enc_ctx->ch_layout.nb_channels); + av_channel_layout_default(&f->ch_layout, layout_requested->nb_channels); return 0; } int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, - unsigned sched_idx_enc) + unsigned sched_idx_enc, + const OutputFilterOptions *opts) { - const OutputFile *of = ost->file; OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); FilterGraph *fg = ofilter->graph; FilterGraphPriv *fgp = fgp_from_fg(fg); - const AVCodec *c = ost->enc_ctx->codec; int ret; - av_assert0(!ofilter->ost); + av_assert0(!ofilter->bound); + av_assert0(ofilter->type == ost->type); - ofilter->ost = ost; + ofilter->bound = 1; av_freep(&ofilter->linklabel); - ofp->ts_offset = of->start_time == AV_NOPTS_VALUE ? 0 : of->start_time; - ofp->enc_timebase = ost->enc_timebase; + ofp->flags = opts->flags; + ofp->ts_offset = opts->ts_offset; + ofp->enc_timebase = opts->output_tb; - switch (ost->enc_ctx->codec_type) { + 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) + return AVERROR(EINVAL); + + ret = av_dict_copy(&ofp->sws_opts, opts->sws_opts, 0); + if (ret < 0) + return ret; + + ret = av_dict_copy(&ofp->swr_opts, opts->swr_opts, 0); + if (ret < 0) + return ret; + + if (opts->flags & OFILTER_FLAG_AUDIO_24BIT) + av_dict_set(&ofp->swr_opts, "output_sample_bits", "24", 0); + + if (fgp->is_simple) { + // for simple filtergraph there is just one output, + // so use only graph-level information for logging + 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); + + switch (ofilter->type) { case AVMEDIA_TYPE_VIDEO: - ofp->width = ost->enc_ctx->width; - ofp->height = ost->enc_ctx->height; - if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) { - ofp->format = ost->enc_ctx->pix_fmt; - } else { - ofp->formats = c->pix_fmts; + ofp->width = opts->width; + ofp->height = opts->height; + if (opts->format != AV_PIX_FMT_NONE) { + ofp->format = opts->format; + } else + ofp->formats = opts->formats; - // MJPEG encoder exports a full list of supported pixel formats, - // but the full-range ones are experimental-only. - // Restrict the auto-conversion list unless -strict experimental - // has been specified. - if (!strcmp(c->name, "mjpeg")) { - // FIXME: YUV420P etc. are actually supported with full color range, - // yet the latter information isn't available here. - static const enum AVPixelFormat mjpeg_formats[] = - { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, - AV_PIX_FMT_NONE }; + if (opts->color_space != AVCOL_SPC_UNSPECIFIED) + ofp->color_space = opts->color_space; + else + ofp->color_spaces = opts->color_spaces; - const AVDictionaryEntry *strict = av_dict_get(ost->encoder_opts, "strict", NULL, 0); - int strict_val = ost->enc_ctx->strict_std_compliance; + if (opts->color_range != AVCOL_RANGE_UNSPECIFIED) + ofp->color_range = opts->color_range; + else + ofp->color_ranges = opts->color_ranges; - if (strict) { - const AVOption *o = av_opt_find(ost->enc_ctx, strict->key, NULL, 0, 0); - av_assert0(o); - av_opt_eval_int(ost->enc_ctx, o, strict->value, &strict_val); - } - - if (strict_val > FF_COMPLIANCE_UNOFFICIAL) - ofp->formats = mjpeg_formats; - } - } - - fgp->disable_conversions |= ost->keep_pix_fmt; + fgp->disable_conversions |= !!(ofp->flags & OFILTER_FLAG_DISABLE_CONVERT); ofp->fps.last_frame = av_frame_alloc(); if (!ofp->fps.last_frame) 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 ? - NULL : c->supported_framerates; + ofp->fps.framerate_supported = ost->force_fps || !opts->enc ? + NULL : opts->frame_rates; // reduce frame rate for mpeg4 to be within the spec limits - if (c->id == AV_CODEC_ID_MPEG4) + if (opts->enc && opts->enc->id == AV_CODEC_ID_MPEG4) ofp->fps.framerate_clip = 65535; ofp->fps.dup_warning = 1000; break; case AVMEDIA_TYPE_AUDIO: - if (ost->enc_ctx->sample_fmt != AV_SAMPLE_FMT_NONE) { - ofp->format = ost->enc_ctx->sample_fmt; + if (opts->format != AV_SAMPLE_FMT_NONE) { + ofp->format = opts->format; } else { - ofp->formats = c->sample_fmts; + ofp->formats = opts->formats; } - if (ost->enc_ctx->sample_rate) { - ofp->sample_rate = ost->enc_ctx->sample_rate; - } else { - ofp->sample_rates = c->supported_samplerates; - } - if (ost->enc_ctx->ch_layout.nb_channels) { - int ret = set_channel_layout(ofp, ost); + if (opts->sample_rate) { + ofp->sample_rate = opts->sample_rate; + } else + ofp->sample_rates = opts->sample_rates; + if (opts->ch_layout.nb_channels) { + int ret = set_channel_layout(ofp, opts->ch_layouts, &opts->ch_layout); if (ret < 0) return ret; - } else if (c->ch_layouts) { - ofp->ch_layouts = c->ch_layouts; + } else { + ofp->ch_layouts = opts->ch_layouts; } break; } @@ -861,6 +894,63 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost, return 0; } +static int ofilter_bind_ifilter(OutputFilter *ofilter, InputFilterPriv *ifp, + const OutputFilterOptions *opts) +{ + OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); + + av_assert0(!ofilter->bound); + av_assert0(ofilter->type == ifp->type); + + ofilter->bound = 1; + av_freep(&ofilter->linklabel); + + ofp->name = av_strdup(opts->name); + if (!ofp->name) + return AVERROR(EINVAL); + + av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofp->name); + + return 0; +} + +static int ifilter_bind_fg(InputFilterPriv *ifp, FilterGraph *fg_src, int out_idx) +{ + FilterGraphPriv *fgp = fgp_from_fg(ifp->ifilter.graph); + OutputFilter *ofilter_src = fg_src->outputs[out_idx]; + OutputFilterOptions opts; + char name[32]; + int ret; + + av_assert0(!ifp->bound); + ifp->bound = 1; + + if (ifp->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)); + return AVERROR(EINVAL); + } + + ifp->type_src = ifp->type; + + memset(&opts, 0, sizeof(opts)); + + snprintf(name, sizeof(name), "fg:%d:%d", fgp->fg.index, ifp->index); + opts.name = name; + + ret = ofilter_bind_ifilter(ofilter_src, ifp, &opts); + if (ret < 0) + return ret; + + ret = sch_connect(fgp->sch, SCH_FILTER_OUT(fg_src->index, out_idx), + SCH_FILTER_IN(fgp->sch_idx, ifp->index)); + if (ret < 0) + return ret; + + return 0; +} + static InputFilter *ifilter_alloc(FilterGraph *fg) { InputFilterPriv *ifp; @@ -925,14 +1015,19 @@ void fg_free(FilterGraph **pfg) OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); av_frame_free(&ofp->fps.last_frame); + av_dict_free(&ofp->sws_opts); + av_dict_free(&ofp->swr_opts); av_freep(&ofilter->linklabel); av_freep(&ofilter->name); + av_freep(&ofilter->apad); + av_freep(&ofp->name); av_channel_layout_uninit(&ofp->ch_layout); av_freep(&fg->outputs[j]); } av_freep(&fg->outputs); av_freep(&fgp->graph_desc); + av_freep(&fgp->nb_threads); av_frame_free(&fgp->frame); av_frame_free(&fgp->frame_enc); @@ -963,16 +1058,25 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) AVFilterGraph *graph; int ret = 0; - fgp = allocate_array_elem(&filtergraphs, sizeof(*fgp), &nb_filtergraphs); + fgp = av_mallocz(sizeof(*fgp)); if (!fgp) return AVERROR(ENOMEM); fg = &fgp->fg; - if (pfg) + if (pfg) { *pfg = fg; + fg->index = -1; + } else { + ret = av_dynarray_add_nofree(&filtergraphs, &nb_filtergraphs, fgp); + if (ret < 0) { + av_freep(&fgp); + return ret; + } + + fg->index = nb_filtergraphs - 1; + } fg->class = &fg_class; - fg->index = nb_filtergraphs - 1; fgp->graph_desc = graph_desc; fgp->disable_conversions = !auto_conversion_filters; fgp->sch = sch; @@ -997,8 +1101,9 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) for (unsigned i = 0; i < graph->nb_filters; i++) { const AVFilter *f = graph->filters[i]->filter; - if (!avfilter_filter_pad_count(f, 0) && - !(f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) { + if ((!avfilter_filter_pad_count(f, 0) && + !(f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) || + !strcmp(f->name, "apad")) { fgp->have_sources = 1; break; } @@ -1035,7 +1140,9 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) } for (AVFilterInOut *cur = outputs; cur; cur = cur->next) { - OutputFilter *const ofilter = ofilter_alloc(fg); + const enum AVMediaType type = avfilter_pad_get_type(cur->filter_ctx->output_pads, + cur->pad_idx); + OutputFilter *const ofilter = ofilter_alloc(fg, type); if (!ofilter) { ret = AVERROR(ENOMEM); @@ -1045,8 +1152,6 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch) ofilter->linklabel = cur->name; cur->name = NULL; - ofilter->type = avfilter_pad_get_type(cur->filter_ctx->output_pads, - cur->pad_idx); ofilter->name = describe_filter_link(fg, cur, 0); if (!ofilter->name) { ret = AVERROR(ENOMEM); @@ -1079,22 +1184,23 @@ fail: int init_simple_filtergraph(InputStream *ist, OutputStream *ost, char *graph_desc, - Scheduler *sch, unsigned sched_idx_enc) + Scheduler *sch, unsigned sched_idx_enc, + const OutputFilterOptions *opts) { FilterGraph *fg; FilterGraphPriv *fgp; int ret; - ret = fg_create(&fg, graph_desc, sch); + ret = fg_create(&ost->fg_simple, graph_desc, sch); if (ret < 0) return ret; + fg = ost->fg_simple; fgp = fgp_from_fg(fg); fgp->is_simple = 1; - snprintf(fgp->log_name, sizeof(fgp->log_name), "%cf#%d:%d", - av_get_media_type_string(ost->type)[0], - ost->file->index, ost->index); + snprintf(fgp->log_name, sizeof(fgp->log_name), "%cf%s", + av_get_media_type_string(ost->type)[0], opts->name); if (fg->nb_inputs != 1 || fg->nb_outputs != 1) { av_log(fg, AV_LOG_ERROR, "Simple filtergraph '%s' was expected " @@ -1104,17 +1210,31 @@ int init_simple_filtergraph(InputStream *ist, OutputStream *ost, graph_desc, fg->nb_inputs, fg->nb_outputs); return AVERROR(EINVAL); } + if (fg->outputs[0]->type != ost->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)); + return AVERROR(EINVAL); + } ost->filter = fg->outputs[0]; - ret = ifilter_bind_ist(fg->inputs[0], ist); + 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); + ret = ofilter_bind_ost(fg->outputs[0], ost, 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); + } + return 0; } @@ -1124,31 +1244,67 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) InputFilterPriv *ifp = ifp_from_ifilter(ifilter); InputStream *ist = NULL; enum AVMediaType type = ifp->type; + ViewSpecifier vs = { .type = VIEW_SPECIFIER_TYPE_NONE }; + const char *spec; + char *p; int i, ret; if (ifp->linklabel && !strncmp(ifp->linklabel, "dec:", 4)) { // bind to a standalone decoder int dec_idx; - dec_idx = strtol(ifp->linklabel + 4, NULL, 0); + dec_idx = strtol(ifp->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); return AVERROR(EINVAL); } - ret = ifilter_bind_dec(ifp, decoders[dec_idx]); + if (type == AVMEDIA_TYPE_VIDEO) { + spec = *p == ':' ? p + 1 : p; + ret = view_specifier_parse(&spec, &vs); + if (ret < 0) + return ret; + } + + ret = ifilter_bind_dec(ifp, decoders[dec_idx], &vs); if (ret < 0) av_log(fg, AV_LOG_ERROR, "Error binding a decoder to filtergraph input %s\n", ifilter->name); return ret; } else if (ifp->linklabel) { - // bind to an explicitly specified demuxer stream + StreamSpecifier ss; AVFormatContext *s; AVStream *st = NULL; - char *p; - int file_idx = strtol(ifp->linklabel, &p, 0); + int file_idx; + // try finding an unbound filtergraph output with this label + 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 && 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); + + 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; + } + } + } + + // bind to an explicitly specified demuxer stream + file_idx = strtol(ifp->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); @@ -1156,17 +1312,33 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) } s = input_files[file_idx]->ctx; + ret = stream_specifier_parse(&ss, *p == ':' ? p + 1 : p, 1, fg); + if (ret < 0) { + av_log(fg, AV_LOG_ERROR, "Invalid stream specifier: %s\n", p); + return ret; + } + + if (type == AVMEDIA_TYPE_VIDEO) { + spec = ss.remainder ? ss.remainder : ""; + ret = view_specifier_parse(&spec, &vs); + if (ret < 0) { + stream_specifier_uninit(&ss); + return ret; + } + } + for (i = 0; i < s->nb_streams; i++) { enum AVMediaType stream_type = s->streams[i]->codecpar->codec_type; if (stream_type != type && !(stream_type == AVMEDIA_TYPE_SUBTITLE && type == AVMEDIA_TYPE_VIDEO /* sub2video hack */)) continue; - if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) { + if (stream_specifier_match(&ss, s, s->streams[i], fg)) { st = s->streams[i]; break; } } + 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); @@ -1191,7 +1363,7 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) } av_assert0(ist); - ret = ifilter_bind_ist(ifilter, 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", @@ -1202,9 +1374,9 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) return 0; } -int fg_finalise_bindings(FilterGraph *fg) +static int bind_inputs(FilterGraph *fg) { - // bind filtergraph inputs to input streams + // bind filtergraph inputs to input streams or other filtergraphs for (int i = 0; i < fg->nb_inputs; i++) { InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]); int ret; @@ -1217,14 +1389,35 @@ int fg_finalise_bindings(FilterGraph *fg) return ret; } - for (int i = 0; i < fg->nb_outputs; i++) { - OutputFilter *output = fg->outputs[i]; - if (!output->ost) { - av_log(filtergraphs[i], AV_LOG_FATAL, - "Filter %s has an unconnected output\n", output->name); - return AVERROR(EINVAL); + return 0; +} + +int fg_finalise_bindings(void) +{ + int ret; + + for (int i = 0; i < nb_filtergraphs; i++) { + ret = bind_inputs(filtergraphs[i]); + if (ret < 0) + return ret; + } + + // check that all outputs were bound + for (int i = 0; i < nb_filtergraphs; i++) { + FilterGraph *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", + output->name, j, + output->linklabel ? (const char *)output->linklabel : "unlabeled"); + return AVERROR(EINVAL); + } } } + return 0; } @@ -1283,11 +1476,15 @@ static int insert_filter(AVFilterContext **last_filter, int *pad_idx, const char *filter_name, const char *args) { AVFilterGraph *graph = (*last_filter)->graph; + const AVFilter *filter = avfilter_get_by_name(filter_name); AVFilterContext *ctx; int ret; + if (!filter) + return AVERROR_BUG; + ret = avfilter_graph_create_filter(&ctx, - avfilter_get_by_name(filter_name), + filter, filter_name, args, NULL, graph); if (ret < 0) return ret; @@ -1301,20 +1498,17 @@ static int insert_filter(AVFilterContext **last_filter, int *pad_idx, return 0; } -static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, +static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *graph, OutputFilter *ofilter, AVFilterInOut *out) { OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); - OutputStream *ost = ofilter->ost; - OutputFile *of = ost->file; AVFilterContext *last_filter = out->filter_ctx; AVBPrint bprint; int pad_idx = out->pad_idx; int ret; - const char *pix_fmts; char name[255]; - snprintf(name, sizeof(name), "out_%d_%d", ost->file->index, ost->index); + snprintf(name, sizeof(name), "out_%s", ofp->name); ret = avfilter_graph_create_filter(&ofp->filter, avfilter_get_by_name("buffersink"), name, NULL, NULL, graph); @@ -1322,7 +1516,7 @@ static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, if (ret < 0) return ret; - if ((ofp->width || ofp->height) && ofilter->ost->autoscale) { + if ((ofp->width || ofp->height) && (ofp->flags & OFILTER_FLAG_AUTOSCALE)) { char args[255]; AVFilterContext *filter; const AVDictionaryEntry *e = NULL; @@ -1330,12 +1524,11 @@ static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, snprintf(args, sizeof(args), "%d:%d", ofp->width, ofp->height); - while ((e = av_dict_iterate(ost->sws_dict, e))) { + while ((e = av_dict_iterate(ofp->sws_opts, e))) { av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value); } - snprintf(name, sizeof(name), "scaler_out_%d_%d", - ost->file->index, ost->index); + snprintf(name, sizeof(name), "scaler_out_%s", ofp->name); if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), name, args, NULL, graph)) < 0) return ret; @@ -1346,17 +1539,21 @@ static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, pad_idx = 0; } + av_assert0(!(ofp->flags & OFILTER_FLAG_DISABLE_CONVERT) || + ofp->format != AV_PIX_FMT_NONE || !ofp->formats); av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); - ret = choose_pix_fmts(ofilter, &bprint, &pix_fmts); - if (ret < 0) - return ret; + choose_pix_fmts(ofp, &bprint); + choose_color_spaces(ofp, &bprint); + choose_color_ranges(ofp, &bprint); + if (!av_bprint_is_complete(&bprint)) + return AVERROR(ENOMEM); - if (pix_fmts) { + if (bprint.len) { AVFilterContext *filter; ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("format"), - "format", pix_fmts, NULL, graph); + "format", bprint.str, NULL, graph); av_bprint_finalize(&bprint, NULL); if (ret < 0) return ret; @@ -1367,9 +1564,8 @@ static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, pad_idx = 0; } - snprintf(name, sizeof(name), "trim_out_%d_%d", - ost->file->index, ost->index); - ret = insert_trim(of->start_time, of->recording_time, + snprintf(name, sizeof(name), "trim_out_%s", ofp->name); + ret = insert_trim(ofp->trim_start_us, ofp->trim_duration_us, &last_filter, &pad_idx, name); if (ret < 0) return ret; @@ -1381,19 +1577,17 @@ static int configure_output_video_filter(FilterGraph *fg, AVFilterGraph *graph, return 0; } -static int configure_output_audio_filter(FilterGraph *fg, AVFilterGraph *graph, +static int configure_output_audio_filter(FilterGraphPriv *fgp, AVFilterGraph *graph, OutputFilter *ofilter, AVFilterInOut *out) { OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); - OutputStream *ost = ofilter->ost; - OutputFile *of = ost->file; AVFilterContext *last_filter = out->filter_ctx; int pad_idx = out->pad_idx; AVBPrint args; char name[255]; int ret; - snprintf(name, sizeof(name), "out_%d_%d", ost->file->index, ost->index); + snprintf(name, sizeof(name), "out_%s", ofp->name); ret = avfilter_graph_create_filter(&ofp->filter, avfilter_get_by_name("abuffersink"), name, NULL, NULL, graph); @@ -1405,7 +1599,7 @@ static int configure_output_audio_filter(FilterGraph *fg, AVFilterGraph *graph, #define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do { \ AVFilterContext *filt_ctx; \ \ - av_log(fg, AV_LOG_INFO, opt_name " is forwarded to lavfi " \ + av_log(ofilter, AV_LOG_INFO, opt_name " is forwarded to lavfi " \ "similarly to -af " filter_name "=%s.\n", arg); \ \ ret = avfilter_graph_create_filter(&filt_ctx, \ @@ -1433,8 +1627,7 @@ static int configure_output_audio_filter(FilterGraph *fg, AVFilterGraph *graph, if (args.len) { AVFilterContext *format; - snprintf(name, sizeof(name), "format_out_%d_%d", - ost->file->index, ost->index); + snprintf(name, sizeof(name), "format_out_%s", ofp->name); ret = avfilter_graph_create_filter(&format, avfilter_get_by_name("aformat"), name, args.str, NULL, graph); @@ -1449,21 +1642,13 @@ static int configure_output_audio_filter(FilterGraph *fg, AVFilterGraph *graph, pad_idx = 0; } - if (ost->apad && of->shortest) { - int i; - - for (i = 0; i < of->nb_streams; i++) - if (of->streams[i]->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - break; - - if (i < of->nb_streams) { - AUTO_INSERT_FILTER("-apad", "apad", ost->apad); - } + if (ofilter->apad) { + AUTO_INSERT_FILTER("-apad", "apad", ofilter->apad); + fgp->have_sources = 1; } - snprintf(name, sizeof(name), "trim for output stream %d:%d", - ost->file->index, ost->index); - ret = insert_trim(of->start_time, of->recording_time, + snprintf(name, sizeof(name), "trim for output %s", ofp->name); + ret = insert_trim(ofp->trim_start_us, ofp->trim_duration_us, &last_filter, &pad_idx, name); if (ret < 0) goto fail; @@ -1476,17 +1661,12 @@ fail: return ret; } -static int configure_output_filter(FilterGraph *fg, AVFilterGraph *graph, +static int configure_output_filter(FilterGraphPriv *fgp, AVFilterGraph *graph, OutputFilter *ofilter, AVFilterInOut *out) { - if (!ofilter->ost) { - av_log(fg, AV_LOG_FATAL, "Filter %s has an unconnected output\n", ofilter->name); - return AVERROR(EINVAL); - } - - switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) { - case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, graph, ofilter, out); - case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, graph, ofilter, out); + switch (ofilter->type) { + case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fgp, graph, ofilter, out); + case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fgp, graph, ofilter, out); default: av_assert0(0); return 0; } } @@ -1551,7 +1731,19 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph, desc = av_pix_fmt_desc_get(ifp->format); av_assert0(desc); + if ((ifp->opts.flags & IFILTER_FLAG_CROP)) { + char crop_buf[64]; + snprintf(crop_buf, sizeof(crop_buf), "w=iw-%u-%u:h=ih-%u-%u:x=%u:y=%u", + ifp->opts.crop_left, ifp->opts.crop_right, + ifp->opts.crop_top, ifp->opts.crop_bottom, + ifp->opts.crop_left, ifp->opts.crop_top); + ret = insert_filter(&last_filter, &pad_idx, "crop", crop_buf); + if (ret < 0) + return ret; + } + // TODO: insert hwaccel enabled filters like transpose_vaapi into the graph + ifp->displaymatrix_applied = 0; if ((ifp->opts.flags & IFILTER_FLAG_AUTOROTATE) && !(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) { int32_t *displaymatrix = ifp->displaymatrix; @@ -1585,6 +1777,8 @@ static int configure_input_video_filter(FilterGraph *fg, AVFilterGraph *graph, } if (ret < 0) return ret; + + ifp->displaymatrix_applied = 1; } snprintf(name, sizeof(name), "trim_in_%s", ifp->opts.name); @@ -1703,30 +1897,29 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) return AVERROR(ENOMEM); if (simple) { - OutputStream *ost = fg->outputs[0]->ost; + OutputFilterPriv *ofp = ofp_from_ofilter(fg->outputs[0]); if (filter_nbthreads) { ret = av_opt_set(fgt->graph, "threads", filter_nbthreads, 0); if (ret < 0) goto fail; - } else { - const AVDictionaryEntry *e = NULL; - e = av_dict_get(ost->encoder_opts, "threads", NULL, 0); - if (e) - av_opt_set(fgt->graph, "threads", e->value, 0); + } else if (fgp->nb_threads) { + ret = av_opt_set(fgt->graph, "threads", fgp->nb_threads, 0); + if (ret < 0) + return ret; } - if (av_dict_count(ost->sws_dict)) { - ret = av_dict_get_string(ost->sws_dict, + if (av_dict_count(ofp->sws_opts)) { + ret = av_dict_get_string(ofp->sws_opts, &fgt->graph->scale_sws_opts, '=', ':'); if (ret < 0) goto fail; } - if (av_dict_count(ost->swr_opts)) { + if (av_dict_count(ofp->swr_opts)) { char *args; - ret = av_dict_get_string(ost->swr_opts, &args, '=', ':'); + ret = av_dict_get_string(ofp->swr_opts, &args, '=', ':'); if (ret < 0) goto fail; av_opt_set(fgt->graph, "aresample_swr_opts", args, 0); @@ -1750,7 +1943,7 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) avfilter_inout_free(&inputs); for (cur = outputs, i = 0; cur; cur = cur->next, i++) { - ret = configure_output_filter(fg, fgt->graph, fg->outputs[i], cur); + ret = configure_output_filter(fgp, fgt->graph, fg->outputs[i], cur); if (ret < 0) { avfilter_inout_free(&outputs); goto fail; @@ -1776,6 +1969,8 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt) ofp->width = av_buffersink_get_w(sink); ofp->height = av_buffersink_get_h(sink); + ofp->color_space = av_buffersink_get_colorspace(sink); + ofp->color_range = av_buffersink_get_color_range(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 @@ -1938,7 +2133,7 @@ static int choose_out_timebase(OutputFilterPriv *ofp, AVFrame *frame) // apply -enc_time_base if (ofp->enc_timebase.num == ENC_TIME_BASE_DEMUX && (fd->dec.tb.num <= 0 || fd->dec.tb.den <= 0)) { - av_log(ofilter->ost, AV_LOG_ERROR, + av_log(ofp, AV_LOG_ERROR, "Demuxing timebase not available - cannot use it for encoding\n"); return AVERROR(EINVAL); } @@ -1962,10 +2157,10 @@ static int choose_out_timebase(OutputFilterPriv *ofp, AVFrame *frame) fr = fr_sink; } - if (ofilter->ost->is_cfr) { + if (fps->vsync_method == VSYNC_CFR || fps->vsync_method == VSYNC_VSCFR) { if (!fr.num && !fps->framerate_max.num) { fr = (AVRational){25, 1}; - av_log(ofilter->ost, AV_LOG_WARNING, + av_log(ofp, AV_LOG_WARNING, "No information " "about the input framerate is available. Falling " "back to a default value of 25fps. Use the -r option " @@ -2048,7 +2243,6 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame, int64_t *nb_frames, int64_t *nb_frames_prev) { OutputFilter *ofilter = &ofp->ofilter; - OutputStream *ost = ofilter->ost; FPSConvContext *fps = &ofp->fps; double delta0, delta, sync_ipts, duration; @@ -2081,24 +2275,24 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame, if (delta0 < 0 && delta > 0 && - ost->vsync_method != VSYNC_PASSTHROUGH + fps->vsync_method != VSYNC_PASSTHROUGH #if FFMPEG_OPT_VSYNC_DROP - && ost->vsync_method != VSYNC_DROP + && fps->vsync_method != VSYNC_DROP #endif ) { if (delta0 < -0.6) { - av_log(ost, AV_LOG_VERBOSE, "Past duration %f too large\n", -delta0); + av_log(ofp, AV_LOG_VERBOSE, "Past duration %f too large\n", -delta0); } else - av_log(ost, AV_LOG_DEBUG, "Clipping frame in rate conversion by %f\n", -delta0); + av_log(ofp, AV_LOG_DEBUG, "Clipping frame in rate conversion by %f\n", -delta0); sync_ipts = ofp->next_pts; duration += delta0; delta0 = 0; } - switch (ost->vsync_method) { + switch (fps->vsync_method) { case VSYNC_VSCFR: if (fps->frame_number == 0 && delta0 >= 0.5) { - av_log(ost, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0)); + av_log(ofp, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0)); delta = duration; delta0 = 0; ofp->next_pts = llrint(sync_ipts); @@ -2142,23 +2336,23 @@ finish: if (*nb_frames_prev == 0 && fps->last_dropped) { atomic_fetch_add(&ofilter->nb_frames_drop, 1); - av_log(ost, AV_LOG_VERBOSE, + av_log(ofp, AV_LOG_VERBOSE, "*** dropping frame %"PRId64" at ts %"PRId64"\n", fps->frame_number, fps->last_frame->pts); } if (*nb_frames > (*nb_frames_prev && fps->last_dropped) + (*nb_frames > *nb_frames_prev)) { uint64_t nb_frames_dup; if (*nb_frames > dts_error_threshold * 30) { - av_log(ost, AV_LOG_ERROR, "%"PRId64" frame duplication too large, skipping\n", *nb_frames - 1); + av_log(ofp, AV_LOG_ERROR, "%"PRId64" frame duplication too large, skipping\n", *nb_frames - 1); atomic_fetch_add(&ofilter->nb_frames_drop, 1); *nb_frames = 0; return; } nb_frames_dup = atomic_fetch_add(&ofilter->nb_frames_dup, *nb_frames - (*nb_frames_prev && fps->last_dropped) - (*nb_frames > *nb_frames_prev)); - av_log(ost, AV_LOG_VERBOSE, "*** %"PRId64" dup!\n", *nb_frames - 1); + av_log(ofp, AV_LOG_VERBOSE, "*** %"PRId64" dup!\n", *nb_frames - 1); if (nb_frames_dup > fps->dup_warning) { - av_log(ost, AV_LOG_WARNING, "More than %"PRIu64" frames duplicated\n", fps->dup_warning); + av_log(ofp, AV_LOG_WARNING, "More than %"PRIu64" frames duplicated\n", fps->dup_warning); fps->dup_warning *= 10; } } @@ -2200,7 +2394,7 @@ static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt) av_assert0(!frame->buf[0]); - av_log(ofp->ofilter.ost, AV_LOG_WARNING, + av_log(ofp, AV_LOG_WARNING, "No filtered frames for output stream, trying to " "initialize anyway.\n"); @@ -2304,7 +2498,6 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, AVFrame *frame) { FilterGraphPriv *fgp = fgp_from_fg(ofp->ofilter.graph); - OutputStream *ost = ofp->ofilter.ost; AVFilterContext *filter = ofp->filter; FrameData *fd; int ret; @@ -2317,7 +2510,7 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { return 1; } else if (ret < 0) { - av_log(fgp, AV_LOG_WARNING, + av_log(ofp, AV_LOG_WARNING, "Error in retrieving a frame from the filtergraph: %s\n", av_err2str(ret)); return ret; @@ -2331,7 +2524,7 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, frame->time_base = av_buffersink_get_time_base(filter); if (debug_ts) - av_log(fgp, AV_LOG_INFO, "filter_raw -> pts:%s pts_time:%s time_base:%d/%d\n", + av_log(ofp, AV_LOG_INFO, "filter_raw -> pts:%s pts_time:%s time_base:%d/%d\n", av_ts2str(frame->pts), av_ts2timestr(frame->pts, &frame->time_base), frame->time_base.num, frame->time_base.den); @@ -2339,7 +2532,7 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, if (!ofp->tb_out_locked) { ret = choose_out_timebase(ofp, frame); if (ret < 0) { - av_log(ost, AV_LOG_ERROR, "Could not choose an output time base\n"); + av_log(ofp, AV_LOG_ERROR, "Could not choose an output time base\n"); av_frame_unref(frame); return ret; } @@ -2358,7 +2551,7 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt, if (!fgp->is_meta) fd->bits_per_raw_sample = 0; - if (ost->type == AVMEDIA_TYPE_VIDEO) { + if (ofp->ofilter.type == AVMEDIA_TYPE_VIDEO) { if (!frame->duration) { AVRational fr = av_buffersink_get_frame_rate(filter); if (fr.num > 0 && fr.den > 0) @@ -2681,6 +2874,9 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, frame->duration = av_rescale_q(frame->duration, frame->time_base, ifp->time_base); frame->time_base = ifp->time_base; + if (ifp->displaymatrix_applied) + av_frame_remove_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX); + fd = frame_data(frame); if (!fd) return AVERROR(ENOMEM); @@ -2702,10 +2898,10 @@ static void fg_thread_set_name(const FilterGraph *fg) { char name[16]; if (filtergraph_is_simple(fg)) { - OutputStream *ost = fg->outputs[0]->ost; - snprintf(name, sizeof(name), "%cf#%d:%d", - av_get_media_type_string(ost->type)[0], - ost->file->index, ost->index); + 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); } else { snprintf(name, sizeof(name), "fc%d", fg->index); } diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c index 8608d2451..5d4c06c28 100644 --- a/fftools/ffmpeg_hw.c +++ b/fftools/ffmpeg_hw.c @@ -18,9 +18,7 @@ #include -#include "libavutil/avstring.h" -#include "libavutil/pixdesc.h" -#include "libavfilter/buffersink.h" +#include "libavutil/mem.h" #include "ffmpeg.h" diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index e8e5c677b..71ff9b45a 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -140,7 +140,7 @@ static int mux_fixup_ts(Muxer *mux, MuxStream *ms, AVPacket *pkt) OutputStream *ost = &ms->ost; #if FFMPEG_OPT_VSYNC_DROP - if (ost->type == AVMEDIA_TYPE_VIDEO && ost->vsync_method == VSYNC_DROP) + if (ost->type == AVMEDIA_TYPE_VIDEO && ms->ts_drop) pkt->pts = pkt->dts = AV_NOPTS_VALUE; #endif @@ -290,7 +290,7 @@ static int mux_packet_filter(Muxer *mux, MuxThreadContext *mt, { MuxStream *ms = ms_from_ost(ost); const char *err_msg; - int ret = 0; + int ret; if (pkt && !ost->enc) { ret = of_streamcopy(&mux->of, ost, pkt); @@ -299,7 +299,6 @@ static int mux_packet_filter(Muxer *mux, MuxThreadContext *mt, else if (ret == AVERROR_EOF) { av_packet_unref(pkt); pkt = NULL; - ret = 0; *stream_eof = 1; } else if (ret < 0) goto fail; @@ -370,10 +369,11 @@ fail: return ret; } -static void thread_set_name(OutputFile *of) +static void thread_set_name(Muxer *mux) { char name[16]; - snprintf(name, sizeof(name), "mux%d:%s", of->index, of->format->name); + snprintf(name, sizeof(name), "mux%d:%s", + mux->of.index, mux->fc->oformat->name); ff_thread_setname(name); } @@ -417,7 +417,7 @@ int muxer_thread(void *arg) if (ret < 0) goto finish; - thread_set_name(of); + thread_set_name(mux); while (1) { OutputStream *ost; @@ -515,8 +515,10 @@ int print_sdp(const char *filename) if (!avc) return AVERROR(ENOMEM); for (int i = 0; i < nb_output_files; i++) { - if (!strcmp(output_files[i]->format->name, "rtp")) { - avc[j] = mux_from_of(output_files[i])->fc; + Muxer *mux = mux_from_of(output_files[i]); + + if (!strcmp(mux->fc->oformat->name, "rtp")) { + avc[j] = mux->fc; j++; } } @@ -756,7 +758,7 @@ int of_write_trailer(OutputFile *of) mux->last_filesize = filesize(fc->pb); - if (!(of->format->flags & AVFMT_NOFILE)) { + if (!(fc->oformat->flags & AVFMT_NOFILE)) { ret = avio_closep(&fc->pb); if (ret < 0) { av_log(mux, AV_LOG_ERROR, "Error closing file: %s\n", av_err2str(ret)); @@ -794,6 +796,7 @@ static void ost_free(OutputStream **post) ms = ms_from_ost(ost); enc_free(&ost->enc); + fg_free(&ost->fg_simple); if (ost->logfile) { if (fclose(ost->logfile)) @@ -809,19 +812,14 @@ static void ost_free(OutputStream **post) av_packet_free(&ms->bsf_pkt); av_packet_free(&ms->pkt); - av_dict_free(&ost->encoder_opts); av_freep(&ost->kf.pts); av_expr_free(ost->kf.pexpr); av_freep(&ost->logfile_prefix); - av_freep(&ost->apad); av_freep(&ost->attachment_filename); - av_dict_free(&ost->sws_dict); - av_dict_free(&ost->swr_opts); - if (ost->enc_ctx) av_freep(&ost->enc_ctx->stats_in); avcodec_free_context(&ost->enc_ctx); @@ -865,6 +863,7 @@ void of_free(OutputFile **pof) av_freep(&mux->sch_stream_idx); av_dict_free(&mux->opts); + av_dict_free(&mux->enc_opts_used); av_packet_free(&mux->sq_pkt); diff --git a/fftools/ffmpeg_mux.h b/fftools/ffmpeg_mux.h index 16af6d38b..22d728a91 100644 --- a/fftools/ffmpeg_mux.h +++ b/fftools/ffmpeg_mux.h @@ -75,6 +75,11 @@ typedef struct MuxStream { int copy_initial_nonkeyframes; int copy_prior_start; int streamcopy_started; +#if FFMPEG_OPT_VSYNC_DROP + int ts_drop; +#endif + + const char *apad; } MuxStream; typedef struct Muxer { @@ -94,6 +99,9 @@ typedef struct Muxer { AVDictionary *opts; + // used to validate that all encoder avoptions have been actually used + AVDictionary *enc_opts_used; + /* filesize limit expressed in bytes */ int64_t limit_filesize; atomic_int_least64_t last_filesize; diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index d3d7d022f..8afb018de 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -70,11 +70,11 @@ static int choose_encoder(const OptionsContext *o, AVFormatContext *s, OutputStream *ost, const AVCodec **enc) { enum AVMediaType type = ost->type; - char *codec_name = NULL; + const char *codec_name = NULL; *enc = NULL; - MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st); + opt_match_per_stream_str(ost, &o->codec_names, s, ost->st, &codec_name); if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO && @@ -419,9 +419,9 @@ static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc, #if FFMPEG_OPT_FILTER_SCRIPT const char *filters_script = NULL; - MATCH_PER_STREAM_OPT(filter_scripts, str, filters_script, oc, ost->st); + opt_match_per_stream_str(ost, &o->filter_scripts, oc, ost->st, &filters_script); #endif - MATCH_PER_STREAM_OPT(filters, str, filters, oc, ost->st); + opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters); if (!ost->enc) { if ( @@ -511,13 +511,19 @@ static int fmt_in_list(const int *formats, int format) } static enum AVPixelFormat -choose_pixel_fmt(const AVCodec *codec, enum AVPixelFormat target) +choose_pixel_fmt(const AVCodecContext *avctx, enum AVPixelFormat target) { - const enum AVPixelFormat *p = codec->pix_fmts; + const enum AVPixelFormat *p; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target); //FIXME: This should check for AV_PIX_FMT_FLAG_ALPHA after PAL8 pixel format without alpha is implemented int has_alpha = desc ? desc->nb_components % 2 == 0 : 0; enum AVPixelFormat best= AV_PIX_FMT_NONE; + int ret; + + ret = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, + 0, (const void **) &p, NULL); + if (ret < 0) + return AV_PIX_FMT_NONE; for (; *p != AV_PIX_FMT_NONE; p++) { best = av_find_best_pix_fmt_of_2(best, *p, target, has_alpha, NULL); @@ -529,7 +535,7 @@ choose_pixel_fmt(const AVCodec *codec, enum AVPixelFormat target) av_log(NULL, AV_LOG_WARNING, "Incompatible pixel format '%s' for codec '%s', auto-selecting format '%s'\n", av_get_pix_fmt_name(target), - codec->name, + avctx->codec->name, av_get_pix_fmt_name(best)); return best; } @@ -538,8 +544,9 @@ choose_pixel_fmt(const AVCodec *codec, enum AVPixelFormat target) static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name) { - const enum AVPixelFormat *fmts = ost->enc_ctx->codec->pix_fmts; + const enum AVPixelFormat *fmts; enum AVPixelFormat fmt; + int ret; fmt = av_get_pix_fmt(name); if (fmt == AV_PIX_FMT_NONE) { @@ -547,6 +554,11 @@ 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, + 0, (const void **) &fmts, NULL); + if (ret < 0) + return AV_PIX_FMT_NONE; + /* when the user specified-format is an alias for an endianness-specific * one (e.g. rgb48 -> rgb48be/le), it gets translated into the native * endianness by av_get_pix_fmt(); @@ -574,28 +586,30 @@ 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->codec, fmt); + fmt = choose_pixel_fmt(ost->enc_ctx, fmt); return fmt; } static int new_stream_video(Muxer *mux, const OptionsContext *o, - OutputStream *ost) + OutputStream *ost, int *keep_pix_fmt, + enum VideoSyncMethod *vsync_method) { + MuxStream *ms = ms_from_ost(ost); AVFormatContext *oc = mux->fc; AVStream *st; - char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL; + const char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL; int ret = 0; st = ost->st; - MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, 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) { av_log(ost, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate); return AVERROR(EINVAL); } - MATCH_PER_STREAM_OPT(max_frame_rates, str, max_frame_rate, oc, st); + 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) { av_log(ost, AV_LOG_FATAL, "Invalid maximum framerate value: %s\n", max_frame_rate); return AVERROR(EINVAL); @@ -606,7 +620,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, return AVERROR(EINVAL); } - MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st); + opt_match_per_stream_str(ost, &o->frame_aspect_ratios, oc, st, &frame_aspect_ratio); if (frame_aspect_ratio) { AVRational q; if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 || @@ -620,14 +634,14 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, if (ost->enc_ctx) { AVCodecContext *video_enc = ost->enc_ctx; const char *p = NULL, *fps_mode = NULL; - char *frame_size = NULL; - char *frame_pix_fmt = NULL; - char *intra_matrix = NULL, *inter_matrix = NULL; - char *chroma_intra_matrix = NULL; + const char *frame_size = NULL; + const char *frame_pix_fmt = NULL; + const char *intra_matrix = NULL, *inter_matrix = NULL; + const char *chroma_intra_matrix = NULL; int do_pass = 0; int i; - MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st); + opt_match_per_stream_str(ost, &o->frame_sizes, oc, st, &frame_size); if (frame_size) { ret = av_parse_video_size(&video_enc->width, &video_enc->height, frame_size); if (ret < 0) { @@ -636,9 +650,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, } } - MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st); + opt_match_per_stream_str(ost, &o->frame_pix_fmts, oc, st, &frame_pix_fmt); if (frame_pix_fmt && *frame_pix_fmt == '+') { - ost->keep_pix_fmt = 1; + *keep_pix_fmt = 1; if (!*++frame_pix_fmt) frame_pix_fmt = NULL; } @@ -648,7 +662,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, return AVERROR(EINVAL); } - MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st); + opt_match_per_stream_str(ost, &o->intra_matrices, oc, st, &intra_matrix); if (intra_matrix) { if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) return AVERROR(ENOMEM); @@ -657,17 +671,15 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, if (ret < 0) return ret; } - MATCH_PER_STREAM_OPT(chroma_intra_matrices, str, chroma_intra_matrix, oc, st); + opt_match_per_stream_str(ost, &o->chroma_intra_matrices, oc, st, &chroma_intra_matrix); if (chroma_intra_matrix) { - uint16_t *p = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64); - if (!p) + if (!(video_enc->chroma_intra_matrix = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64))) return AVERROR(ENOMEM); - video_enc->chroma_intra_matrix = p; - ret = parse_matrix_coeffs(ost, p, chroma_intra_matrix); + ret = parse_matrix_coeffs(ost, video_enc->chroma_intra_matrix, chroma_intra_matrix); if (ret < 0) return ret; } - MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st); + opt_match_per_stream_str(ost, &o->inter_matrices, oc, st, &inter_matrix); if (inter_matrix) { if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) return AVERROR(ENOMEM); @@ -676,7 +688,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, return ret; } - MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st); + opt_match_per_stream_str(ost, &o->rc_overrides, oc, st, &p); for (i = 0; p; i++) { int start, end, q; int e = sscanf(p, "%d,%d,%d", &start, &end, &q); @@ -707,19 +719,15 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, video_enc->rc_override_count = i; /* two pass mode */ - MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st); + opt_match_per_stream_int(ost, &o->pass, oc, st, &do_pass); if (do_pass) { - if (do_pass & 1) { + if (do_pass & 1) video_enc->flags |= AV_CODEC_FLAG_PASS1; - av_dict_set(&ost->encoder_opts, "flags", "+pass1", AV_DICT_APPEND); - } - if (do_pass & 2) { + if (do_pass & 2) video_enc->flags |= AV_CODEC_FLAG_PASS2; - av_dict_set(&ost->encoder_opts, "flags", "+pass2", AV_DICT_APPEND); - } } - MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st); + opt_match_per_stream_str(ost, &o->passlogfiles, oc, st, &ost->logfile_prefix); if (ost->logfile_prefix && !(ost->logfile_prefix = av_strdup(ost->logfile_prefix))) return AVERROR(ENOMEM); @@ -730,15 +738,18 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, FILE *f; /* compute this stream's global index */ - for (int i = 0; i <= ost->file->index; i++) - ost_idx += output_files[i]->nb_streams; + for (int idx = 0; idx <= ost->file->index; idx++) + ost_idx += output_files[idx]->nb_streams; snprintf(logfilename, sizeof(logfilename), "%s-%d.log", ost->logfile_prefix ? ost->logfile_prefix : DEFAULT_PASS_LOGFILENAME_PREFIX, ost_idx); - if (!strcmp(ost->enc_ctx->codec->name, "libx264")) { - av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE); + 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", + AV_OPT_SEARCH_CHILDREN) > 0) + av_opt_set(ost->enc_ctx, "stats", logfilename, + AV_OPT_SEARCH_CHILDREN); } else { if (video_enc->flags & AV_CODEC_FLAG_PASS2) { char *logbuffer = file_read(logfilename); @@ -763,59 +774,61 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, } } - MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st); + opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ost->force_fps); #if FFMPEG_OPT_TOP ost->top_field_first = -1; - MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st); + opt_match_per_stream_int(ost, &o->top_field_first, oc, st, &ost->top_field_first); if (ost->top_field_first >= 0) av_log(ost, AV_LOG_WARNING, "-top is deprecated, use the setfield filter instead\n"); #endif #if FFMPEG_OPT_VSYNC - ost->vsync_method = video_sync_method; + *vsync_method = video_sync_method; #else - ost->vsync_method = VSYNC_AUTO; + *vsync_method = VSYNC_AUTO; #endif - MATCH_PER_STREAM_OPT(fps_mode, str, fps_mode, oc, st); + opt_match_per_stream_str(ost, &o->fps_mode, oc, st, &fps_mode); if (fps_mode) { - ret = parse_and_set_vsync(fps_mode, &ost->vsync_method, ost->file->index, ost->index, 0); + ret = parse_and_set_vsync(fps_mode, vsync_method, ost->file->index, ost->index, 0); if (ret < 0) return ret; } if ((ost->frame_rate.num || ost->max_frame_rate.num) && - !(ost->vsync_method == VSYNC_AUTO || - ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR)) { + !(*vsync_method == VSYNC_AUTO || + *vsync_method == VSYNC_CFR || *vsync_method == VSYNC_VSCFR)) { av_log(ost, AV_LOG_FATAL, "One of -r/-fpsmax was specified " "together a non-CFR -vsync/-fps_mode. This is contradictory.\n"); return AVERROR(EINVAL); } - if (ost->vsync_method == VSYNC_AUTO) { + if (*vsync_method == VSYNC_AUTO) { if (ost->frame_rate.num || ost->max_frame_rate.num) { - ost->vsync_method = VSYNC_CFR; + *vsync_method = VSYNC_CFR; } else if (!strcmp(oc->oformat->name, "avi")) { - ost->vsync_method = VSYNC_VFR; + *vsync_method = VSYNC_VFR; } else { - ost->vsync_method = (oc->oformat->flags & AVFMT_VARIABLE_FPS) ? - ((oc->oformat->flags & AVFMT_NOTIMESTAMPS) ? - VSYNC_PASSTHROUGH : VSYNC_VFR) : - VSYNC_CFR; + *vsync_method = (oc->oformat->flags & AVFMT_VARIABLE_FPS) ? + ((oc->oformat->flags & AVFMT_NOTIMESTAMPS) ? + VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR; } - if (ost->ist && ost->vsync_method == VSYNC_CFR) { + if (ost->ist && *vsync_method == VSYNC_CFR) { const InputFile *ifile = ost->ist->file; if (ifile->nb_streams == 1 && ifile->input_ts_offset == 0) - ost->vsync_method = VSYNC_VSCFR; + *vsync_method = VSYNC_VSCFR; } - if (ost->vsync_method == VSYNC_CFR && copy_ts) { - ost->vsync_method = VSYNC_VSCFR; + if (*vsync_method == VSYNC_CFR && copy_ts) { + *vsync_method = VSYNC_VSCFR; } } - ost->is_cfr = (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR); +#if FFMPEG_OPT_VSYNC_DROP + if (*vsync_method == VSYNC_DROP) + ms->ts_drop = 1; +#endif } return 0; @@ -824,43 +837,37 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, static int new_stream_audio(Muxer *mux, const OptionsContext *o, OutputStream *ost) { + MuxStream *ms = ms_from_ost(ost); AVFormatContext *oc = mux->fc; AVStream *st = ost->st; if (ost->enc_ctx) { AVCodecContext *audio_enc = ost->enc_ctx; int channels = 0; - char *layout = NULL; - char *sample_fmt = NULL; - const char *apad = NULL; + const char *layout = NULL; + const char *sample_fmt = NULL; - MATCH_PER_STREAM_OPT(audio_channels, i, channels, oc, st); + opt_match_per_stream_int(ost, &o->audio_channels, oc, st, &channels); if (channels) { audio_enc->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; audio_enc->ch_layout.nb_channels = channels; } - MATCH_PER_STREAM_OPT(audio_ch_layouts, str, layout, oc, st); + opt_match_per_stream_str(ost, &o->audio_ch_layouts, oc, st, &layout); if (layout && av_channel_layout_from_string(&audio_enc->ch_layout, layout) < 0) { av_log(ost, AV_LOG_FATAL, "Unknown channel layout: %s\n", layout); return AVERROR(EINVAL); } - MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st); + opt_match_per_stream_str(ost, &o->sample_fmts, oc, st, &sample_fmt); if (sample_fmt && (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) { av_log(ost, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt); return AVERROR(EINVAL); } - MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st); - - MATCH_PER_STREAM_OPT(apad, str, apad, oc, st); - if (apad) { - ost->apad = av_strdup(apad); - if (!ost->apad) - return AVERROR(ENOMEM); - } + opt_match_per_stream_int(ost, &o->audio_sample_rate, oc, st, &audio_enc->sample_rate); + opt_match_per_stream_str(ost, &o->apad, oc, st, &ms->apad); } return 0; @@ -882,9 +889,9 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o, avcodec_descriptor_get(subtitle_enc->codec_id); int input_props = 0, output_props = 0; - char *frame_size = NULL; + const char *frame_size = NULL; - MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, mux->fc, st); + opt_match_per_stream_str(ost, &o->frame_sizes, mux->fc, st, &frame_size); if (frame_size) { int ret = av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size); if (ret < 0) { @@ -907,7 +914,115 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o, return 0; } -static int streamcopy_init(const Muxer *mux, OutputStream *ost) +static int +ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, + const OptionsContext *o, char *filters, + AVRational enc_tb, enum VideoSyncMethod vsync_method, + int keep_pix_fmt, int autoscale, int threads_manual, + const ViewSpecifier *vs) +{ + OutputStream *ost = &ms->ost; + AVCodecContext *enc_ctx = ost->enc_ctx; + char name[16]; + int ret; + + OutputFilterOptions opts = { + .enc = enc_ctx->codec, + .name = name, + .format = (ost->type == AVMEDIA_TYPE_VIDEO) ? + enc_ctx->pix_fmt : enc_ctx->sample_fmt, + .width = enc_ctx->width, + .height = enc_ctx->height, + .color_space = enc_ctx->colorspace, + .color_range = enc_ctx->color_range, + .vsync_method = vsync_method, + .sample_rate = enc_ctx->sample_rate, + .ch_layout = enc_ctx->ch_layout, + .sws_opts = o->g->sws_dict, + .swr_opts = o->g->swr_opts, + .output_tb = enc_tb, + .trim_start_us = mux->of.start_time, + .trim_duration_us = mux->of.recording_time, + .ts_offset = mux->of.start_time == AV_NOPTS_VALUE ? + 0 : mux->of.start_time, + .vs = vs, + + .flags = OFILTER_FLAG_DISABLE_CONVERT * !!keep_pix_fmt | + OFILTER_FLAG_AUTOSCALE * !!autoscale | + OFILTER_FLAG_AUDIO_24BIT * !!(av_get_exact_bits_per_sample(enc_ctx->codec_id) == 24), + }; + + snprintf(name, sizeof(name), "#%d:%d", mux->of.index, ost->index); + + if (ost->type == AVMEDIA_TYPE_VIDEO) { + if (!keep_pix_fmt) { + ret = avcodec_get_supported_config(enc_ctx, NULL, + AV_CODEC_CONFIG_PIX_FORMAT, 0, + (const void **) &opts.formats, NULL); + if (ret < 0) + return ret; + } + if (!ost->force_fps) { + ret = avcodec_get_supported_config(enc_ctx, NULL, + AV_CODEC_CONFIG_FRAME_RATE, 0, + (const void **) &opts.frame_rates, NULL); + if (ret < 0) + return ret; + } + ret = avcodec_get_supported_config(enc_ctx, NULL, + AV_CODEC_CONFIG_COLOR_SPACE, 0, + (const void **) &opts.color_spaces, NULL); + if (ret < 0) + return ret; + ret = avcodec_get_supported_config(enc_ctx, NULL, + AV_CODEC_CONFIG_COLOR_RANGE, 0, + (const void **) &opts.color_ranges, 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); + if (ret < 0) + return ret; + ret = avcodec_get_supported_config(enc_ctx, NULL, + AV_CODEC_CONFIG_SAMPLE_RATE, 0, + (const void **) &opts.sample_rates, NULL); + if (ret < 0) + return ret; + ret = avcodec_get_supported_config(enc_ctx, NULL, + AV_CODEC_CONFIG_CHANNEL_LAYOUT, 0, + (const void **) &opts.ch_layouts, NULL); + if (ret < 0) + return ret; + } + + if (threads_manual) { + ret = av_opt_get(enc_ctx, "threads", 0, (uint8_t**)&opts.nb_threads); + if (ret < 0) + return ret; + } + + if (ofilter) { + ost->filter = ofilter; + ret = ofilter_bind_ost(ofilter, ost, ms->sch_idx_enc, &opts); + } else { + ret = init_simple_filtergraph(ost->ist, ost, filters, + mux->sch, ms->sch_idx_enc, &opts); + } + 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; + + return ret; +} + +static int streamcopy_init(const Muxer *mux, OutputStream *ost, AVDictionary **encoder_opts) { MuxStream *ms = ms_from_ost(ost); @@ -918,7 +1033,6 @@ static int streamcopy_init(const Muxer *mux, OutputStream *ost) uint32_t codec_tag = par->codec_tag; AVCodecContext *codec_ctx = NULL; - AVDictionary *codec_opts = NULL; AVRational fr = ost->frame_rate; @@ -930,7 +1044,7 @@ static int streamcopy_init(const Muxer *mux, OutputStream *ost) ret = avcodec_parameters_to_context(codec_ctx, ist->par); if (ret >= 0) - ret = av_opt_set_dict(codec_ctx, &ost->encoder_opts); + ret = av_opt_set_dict(codec_ctx, encoder_opts); if (ret < 0) { av_log(ost, AV_LOG_FATAL, "Error setting up codec context options.\n"); @@ -962,17 +1076,12 @@ static int streamcopy_init(const Muxer *mux, OutputStream *ost) else ost->st->avg_frame_rate = ist->st->avg_frame_rate; - ret = avformat_transfer_internal_stream_timing_info(mux->fc->oformat, - ost->st, ist->st, copy_tb); - if (ret < 0) - goto fail; - // copy timebase while removing common factors if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) { if (fr.num) ost->st->time_base = av_inv_q(fr); else - ost->st->time_base = av_add_q(av_stream_get_codec_timebase(ost->st), (AVRational){0, 1}); + ost->st->time_base = av_add_q(ist->st->time_base, (AVRational){0, 1}); } if (!ms->copy_prior_start) { @@ -1020,7 +1129,6 @@ static int streamcopy_init(const Muxer *mux, OutputStream *ost) else sar = par->sample_aspect_ratio; ost->st->sample_aspect_ratio = par->sample_aspect_ratio = sar; - ost->st->avg_frame_rate = ist->st->avg_frame_rate; ost->st->r_frame_rate = ist->st->r_frame_rate; break; } @@ -1028,12 +1136,11 @@ static int streamcopy_init(const Muxer *mux, OutputStream *ost) fail: avcodec_free_context(&codec_ctx); - av_dict_free(&codec_opts); return ret; } static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, - InputStream *ist, OutputFilter *ofilter, + InputStream *ist, OutputFilter *ofilter, const ViewSpecifier *vs, OutputStream **post) { AVFormatContext *oc = mux->fc; @@ -1041,9 +1148,13 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, OutputStream *ost; const AVCodec *enc; AVStream *st; - int ret = 0; - const char *bsfs = NULL, *time_base = NULL; - char *filters = NULL, *next, *codec_tag = NULL; + 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; double qscale = -1; st = avformat_new_stream(oc, NULL); @@ -1152,21 +1263,20 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, return AVERROR(ENOMEM); if (ost->enc_ctx) { - AVCodecContext *enc = ost->enc_ctx; AVIOContext *s = NULL; - char *buf = NULL, *arg = NULL, *preset = 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; + const char *enc_time_base = NULL, *preset = NULL; - ret = filter_codec_opts(o->g->codec_opts, enc->codec_id, - oc, st, enc->codec, &ost->encoder_opts); + ret = filter_codec_opts(o->g->codec_opts, ost->enc_ctx->codec_id, + oc, st, ost->enc_ctx->codec, &encoder_opts, + &mux->enc_opts_used); if (ret < 0) - return ret; + goto fail; - MATCH_PER_STREAM_OPT(presets, str, preset, oc, st); - ost->autoscale = 1; - MATCH_PER_STREAM_OPT(autoscale, i, ost->autoscale, oc, st); - if (preset && (!(ret = get_preset_file_2(preset, enc->codec->name, &s)))) { + 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)))) { AVBPrint bprint; av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); do { @@ -1185,7 +1295,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, break; } *arg++ = 0; - av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE); + av_dict_set(&encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE); } while (!s->eof_reached); av_bprint_finalize(&bprint, NULL); avio_closep(&s); @@ -1193,48 +1303,52 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (ret) { av_log(ost, AV_LOG_FATAL, "Preset %s specified, but could not be opened.\n", preset); - return ret; + goto fail; } - MATCH_PER_STREAM_OPT(enc_stats_pre, str, enc_stats_pre, oc, st); + opt_match_per_stream_str(ost, &o->enc_stats_pre, oc, st, &enc_stats_pre); if (enc_stats_pre && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { const char *format = "{fidx} {sidx} {n} {t}"; - MATCH_PER_STREAM_OPT(enc_stats_pre_fmt, str, format, oc, st); + opt_match_per_stream_str(ost, &o->enc_stats_pre_fmt, oc, st, &format); ret = enc_stats_init(ost, &ost->enc_stats_pre, 1, enc_stats_pre, format); if (ret < 0) - return ret; + goto fail; } - MATCH_PER_STREAM_OPT(enc_stats_post, str, enc_stats_post, oc, st); + opt_match_per_stream_str(ost, &o->enc_stats_post, oc, st, &enc_stats_post); if (enc_stats_post && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { const char *format = "{fidx} {sidx} {n} {t}"; - MATCH_PER_STREAM_OPT(enc_stats_post_fmt, str, format, oc, st); + opt_match_per_stream_str(ost, &o->enc_stats_post_fmt, oc, st, &format); ret = enc_stats_init(ost, &ost->enc_stats_post, 0, enc_stats_post, format); if (ret < 0) - return ret; + goto fail; } - MATCH_PER_STREAM_OPT(mux_stats, str, mux_stats, oc, st); + opt_match_per_stream_str(ost, &o->mux_stats, oc, st, &mux_stats); if (mux_stats && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { const char *format = "{fidx} {sidx} {n} {t}"; - MATCH_PER_STREAM_OPT(mux_stats_fmt, str, format, oc, st); + opt_match_per_stream_str(ost, &o->mux_stats_fmt, oc, st, &format); ret = enc_stats_init(ost, &ms->stats, 0, mux_stats, format); if (ret < 0) - return ret; + goto fail; } - MATCH_PER_STREAM_OPT(enc_time_bases, str, enc_time_base, oc, st); - if (enc_time_base) { + opt_match_per_stream_str(ost, &o->enc_time_bases, oc, st, &enc_time_base); + if (enc_time_base && type == AVMEDIA_TYPE_SUBTITLE) + av_log(ost, AV_LOG_WARNING, + "-enc_time_base not supported for subtitles, ignoring\n"); + else if (enc_time_base) { AVRational q; + if (!strcmp(enc_time_base, "demux")) { q = (AVRational){ ENC_TIME_BASE_DEMUX, 0 }; } else if (!strcmp(enc_time_base, "filter")) { @@ -1247,45 +1361,64 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, #endif ) { av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", enc_time_base); - return ret < 0 ? ret : AVERROR(EINVAL); + ret = ret < 0 ? ret : AVERROR(EINVAL); + goto fail; } #if FFMPEG_OPT_ENC_TIME_BASE_NUM if (q.num < 0) av_log(ost, AV_LOG_WARNING, "-enc_time_base -1 is deprecated," - " use -enc_timebase demux\n"); + " use -enc_time_base demux\n"); #endif } - ost->enc_timebase = q; + enc_tb = q; } + + threads_manual = !!av_dict_get(encoder_opts, "threads", NULL, 0); + + ret = av_opt_set_dict2(ost->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)); + goto fail; + } + + ret = check_avoptions(encoder_opts); + if (ret < 0) + goto fail; + + // default to automatic thread count + if (!threads_manual) + ost->enc_ctx->thread_count = 0; } else { ret = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, - NULL, &ost->encoder_opts); + NULL, &encoder_opts, + &mux->enc_opts_used); if (ret < 0) - return ret; + goto fail; } if (o->bitexact) { ost->bitexact = 1; } else if (ost->enc_ctx) { - ost->bitexact = check_opt_bitexact(ost->enc_ctx, ost->encoder_opts, "flags", - AV_CODEC_FLAG_BITEXACT); + ost->bitexact = !!(ost->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT); } - MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st); + opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base); if (time_base) { AVRational q; if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 || q.num <= 0 || q.den <= 0) { av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", time_base); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto fail; } st->time_base = q; } ms->max_frames = INT64_MAX; - MATCH_PER_STREAM_OPT(max_frames, i64, ms->max_frames, oc, st); + opt_match_per_stream_int64(ost, &o->max_frames, oc, st, &ms->max_frames); for (int i = 0; i < o->max_frames.nb_opt; i++) { char *p = o->max_frames.opt[i].specifier; if (!*p && type != AVMEDIA_TYPE_VIDEO) { @@ -1295,18 +1428,17 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, } ms->copy_prior_start = -1; - MATCH_PER_STREAM_OPT(copy_prior_start, i, ms->copy_prior_start, oc ,st); - - MATCH_PER_STREAM_OPT(bitstream_filters, str, bsfs, oc, st); + opt_match_per_stream_int(ost, &o->copy_prior_start, oc, st, &ms->copy_prior_start); + opt_match_per_stream_str(ost, &o->bitstream_filters, oc, st, &bsfs); if (bsfs && *bsfs) { ret = av_bsf_list_parse_str(bsfs, &ms->bsf_ctx); if (ret < 0) { av_log(ost, AV_LOG_ERROR, "Error parsing bitstream filter sequence '%s': %s\n", bsfs, av_err2str(ret)); - return ret; + goto fail; } } - MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st); + opt_match_per_stream_str(ost, &o->codec_tags, oc, st, &codec_tag); if (codec_tag) { uint32_t tag = strtol(codec_tag, &next, 0); if (*next) { @@ -1320,7 +1452,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, ost->enc_ctx->codec_tag = tag; } - MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st); + 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; @@ -1330,97 +1462,78 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, int max_muxing_queue_size = 128; int muxing_queue_data_threshold = 50 * 1024 * 1024; - MATCH_PER_STREAM_OPT(max_muxing_queue_size, i, max_muxing_queue_size, oc, st); - MATCH_PER_STREAM_OPT(muxing_queue_data_threshold, i, muxing_queue_data_threshold, oc, st); + opt_match_per_stream_int(ost, &o->max_muxing_queue_size, oc, st, + &max_muxing_queue_size); + opt_match_per_stream_int(ost, &o->muxing_queue_data_threshold, + oc, st, &muxing_queue_data_threshold); sch_mux_stream_buffering(mux->sch, mux->sch_idx, ms->sch_idx, max_muxing_queue_size, muxing_queue_data_threshold); } - MATCH_PER_STREAM_OPT(bits_per_raw_sample, i, ost->bits_per_raw_sample, - oc, st); + opt_match_per_stream_int(ost, &o->bits_per_raw_sample, oc, st, + &ost->bits_per_raw_sample); - MATCH_PER_STREAM_OPT(fix_sub_duration_heartbeat, i, ost->fix_sub_duration_heartbeat, - oc, st); + 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; - av_dict_copy(&ost->sws_dict, o->g->sws_dict, 0); - - av_dict_copy(&ost->swr_opts, o->g->swr_opts, 0); - if (ost->enc_ctx && av_get_exact_bits_per_sample(ost->enc_ctx->codec_id) == 24) - av_dict_set(&ost->swr_opts, "output_sample_bits", "24", 0); - - MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, - ms->copy_initial_nonkeyframes, oc, st); - + opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes, + oc, st, &ms->copy_initial_nonkeyframes); switch (type) { - case AVMEDIA_TYPE_VIDEO: ret = new_stream_video (mux, o, ost); break; + case AVMEDIA_TYPE_VIDEO: ret = new_stream_video (mux, o, ost, &keep_pix_fmt, &vsync_method); break; case AVMEDIA_TYPE_AUDIO: ret = new_stream_audio (mux, o, ost); break; case AVMEDIA_TYPE_SUBTITLE: ret = new_stream_subtitle (mux, o, ost); break; } if (ret < 0) - return ret; + goto fail; if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO) { ret = ost_get_filters(o, oc, ost, &filters); if (ret < 0) - return ret; + goto fail; } if (ost->enc && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { - if (ofilter) { - ost->filter = ofilter; - ret = ofilter_bind_ost(ofilter, ost, ms->sch_idx_enc); - if (ret < 0) - return ret; - } else { - ret = init_simple_filtergraph(ost->ist, ost, filters, - mux->sch, ms->sch_idx_enc); - if (ret < 0) { - av_log(ost, AV_LOG_ERROR, - "Error initializing a simple filtergraph\n"); - return ret; - } - } - - ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc), - SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); + ret = ost_bind_filter(mux, ms, ofilter, o, filters, enc_tb, vsync_method, + keep_pix_fmt, autoscale, threads_manual, vs); if (ret < 0) - return ret; + goto fail; } else if (ost->ist) { int sched_idx = ist_output_add(ost->ist, ost); if (sched_idx < 0) { av_log(ost, AV_LOG_ERROR, "Error binding an input stream\n"); - return sched_idx; + ret = sched_idx; + goto fail; } ms->sch_idx_src = sched_idx; if (ost->enc) { - ret = sch_connect(mux->sch, SCH_DEC(sched_idx), + ret = sch_connect(mux->sch, SCH_DEC_OUT(sched_idx, 0), SCH_ENC(ms->sch_idx_enc)); if (ret < 0) - return ret; + goto fail; ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc), SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); if (ret < 0) - return ret; + goto fail; } else { ret = sch_connect(mux->sch, SCH_DSTREAM(ost->ist->file->index, sched_idx), SCH_MSTREAM(ost->file->index, ms->sch_idx)); if (ret < 0) - return ret; + goto fail; } } if (ost->ist && !ost->enc) { - ret = streamcopy_init(mux, ost); + ret = streamcopy_init(mux, ost, &encoder_opts); if (ret < 0) - return ret; + goto fail; } // copy estimated duration as a hint to the muxer @@ -1432,7 +1545,12 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (post) *post = ost; - return 0; + ret = 0; + +fail: + av_dict_free(&encoder_opts); + + return ret; } static int map_auto_video(Muxer *mux, const OptionsContext *o) @@ -1483,7 +1601,7 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o) } } if (best_ist) - return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, best_ist, NULL, NULL); + return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, best_ist, NULL, NULL, NULL); return 0; } @@ -1527,7 +1645,7 @@ static int map_auto_audio(Muxer *mux, const OptionsContext *o) } } if (best_ist) - return ost_add(mux, o, AVMEDIA_TYPE_AUDIO, best_ist, NULL, NULL); + return ost_add(mux, o, AVMEDIA_TYPE_AUDIO, best_ist, NULL, NULL, NULL); return 0; } @@ -1564,7 +1682,7 @@ static int map_auto_subtitle(Muxer *mux, const OptionsContext *o) input_descriptor && output_descriptor && (!input_descriptor->props || !output_descriptor->props)) { - return ost_add(mux, o, AVMEDIA_TYPE_SUBTITLE, ist, NULL, NULL); + return ost_add(mux, o, AVMEDIA_TYPE_SUBTITLE, ist, NULL, NULL, NULL); } } @@ -1585,7 +1703,7 @@ static int map_auto_data(Muxer *mux, const OptionsContext *o) continue; if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA && ist->st->codecpar->codec_id == codec_id) { - int ret = ost_add(mux, o, AVMEDIA_TYPE_DATA, ist, NULL, NULL); + int ret = ost_add(mux, o, AVMEDIA_TYPE_DATA, ist, NULL, NULL, NULL); if (ret < 0) return ret; } @@ -1627,10 +1745,13 @@ loop_end: av_log(mux, AV_LOG_VERBOSE, "Creating output stream from an explicitly " "mapped complex filtergraph %d, output [%s]\n", fg->index, map->linklabel); - ret = ost_add(mux, o, ofilter->type, NULL, ofilter, NULL); + ret = ost_add(mux, o, ofilter->type, NULL, ofilter, NULL, NULL); if (ret < 0) return ret; } else { + const ViewSpecifier *vs = map->vs.type == VIEW_SPECIFIER_TYPE_NONE ? + NULL : &map->vs; + ist = input_files[map->file_index]->streams[map->stream_index]; if (ist->user_set_discard == AVDISCARD_ALL) { av_log(mux, AV_LOG_FATAL, "Stream #%d:%d is disabled and cannot be mapped.\n", @@ -1661,7 +1782,14 @@ loop_end: return 0; } - ret = ost_add(mux, o, ist->st->codecpar->codec_type, ist, NULL, NULL); + if (vs && ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { + av_log(mux, AV_LOG_ERROR, + "View specifier given for mapping a %s input stream\n", + av_get_media_type_string(ist->st->codecpar->codec_type)); + return AVERROR(EINVAL); + } + + ret = ost_add(mux, o, ist->st->codecpar->codec_type, ist, NULL, vs, NULL); if (ret < 0) return ret; } @@ -1731,7 +1859,7 @@ read_fail: return AVERROR(ENOMEM); } - err = ost_add(mux, o, AVMEDIA_TYPE_ATTACHMENT, NULL, NULL, &ost); + err = ost_add(mux, o, AVMEDIA_TYPE_ATTACHMENT, NULL, NULL, NULL, &ost); if (err < 0) { av_free(attachment_filename); av_freep(&attachment); @@ -1774,7 +1902,7 @@ static int create_streams(Muxer *mux, const OptionsContext *o) for (int j = 0; j < fg->nb_outputs; j++) { OutputFilter *ofilter = fg->outputs[j]; - if (ofilter->linklabel || ofilter->ost) + if (ofilter->linklabel || ofilter->bound) continue; auto_disable |= 1 << ofilter->type; @@ -1786,7 +1914,7 @@ static int create_streams(Muxer *mux, const OptionsContext *o) av_get_media_type_string(ofilter->type)); av_log(mux, AV_LOG_VERBOSE, "\n"); - ret = ost_add(mux, o, ofilter->type, NULL, ofilter, NULL); + ret = ost_add(mux, o, ofilter->type, NULL, ofilter, NULL, NULL); if (ret < 0) return ret; } @@ -1837,6 +1965,33 @@ static int create_streams(Muxer *mux, const OptionsContext *o) } } + // handle -apad + if (o->shortest) { + int have_video = 0; + + for (unsigned i = 0; i < mux->of.nb_streams; i++) + if (mux->of.streams[i]->type == AVMEDIA_TYPE_VIDEO) { + have_video = 1; + break; + } + + for (unsigned i = 0; have_video && i < mux->of.nb_streams; i++) { + MuxStream *ms = ms_from_ost(mux->of.streams[i]); + OutputFilter *ofilter = ms->ost.filter; + + if (ms->ost.type != AVMEDIA_TYPE_AUDIO || !ms->apad || !ofilter) + continue; + + ofilter->apad = av_strdup(ms->apad); + if (!ofilter->apad) + return AVERROR(ENOMEM); + } + } + for (unsigned i = 0; i < mux->of.nb_streams; i++) { + MuxStream *ms = ms_from_ost(mux->of.streams[i]); + ms->apad = NULL; + } + if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) { av_dump_format(oc, nb_output_files - 1, oc->url, 1); av_log(mux, AV_LOG_ERROR, "Output file does not contain any stream\n"); @@ -1846,7 +2001,8 @@ static int create_streams(Muxer *mux, const OptionsContext *o) return 0; } -static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_us) +static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, + int64_t buf_size_us, int shortest) { OutputFile *of = &mux->of; int nb_av_enc = 0, nb_audio_fs = 0, nb_interleaved = 0; @@ -1872,7 +2028,7 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u limit_frames_av_enc |= (ms->max_frames < INT64_MAX) && IS_AV_ENC(ost, type); } - if (!((nb_interleaved > 1 && of->shortest) || + if (!((nb_interleaved > 1 && shortest) || (nb_interleaved > 0 && limit_frames) || nb_audio_fs)) return 0; @@ -1888,7 +2044,7 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u * different encoders run in different threads and need external * synchronization, while muxer sync queues can be handled inside the muxer */ - if ((of->shortest && nb_av_enc > 1) || limit_frames_av_enc || nb_audio_fs) { + if ((shortest && nb_av_enc > 1) || limit_frames_av_enc || nb_audio_fs) { int sq_idx, ret; sq_idx = sch_add_sq_enc(mux->sch, buf_size_us, mux); @@ -1904,7 +2060,7 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u continue; ret = sch_sq_add_enc(mux->sch, sq_idx, ms->sch_idx_enc, - of->shortest || ms->max_frames < INT64_MAX, + shortest || ms->max_frames < INT64_MAX, ms->max_frames); if (ret < 0) return ret; @@ -1931,7 +2087,7 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, int64_t buf_size_u continue; ms->sq_idx_mux = sq_add_stream(mux->sq_mux, - of->shortest || ms->max_frames < INT64_MAX); + shortest || ms->max_frames < INT64_MAX); if (ms->sq_idx_mux < 0) return ms->sq_idx_mux; @@ -2151,11 +2307,160 @@ fail: return ret; } +static int of_serialize_options(Muxer *mux, void *obj, AVBPrint *bp) +{ + char *ptr; + int ret; + + ret = av_opt_serialize(obj, 0, AV_OPT_SERIALIZE_SKIP_DEFAULTS | AV_OPT_SERIALIZE_SEARCH_CHILDREN, + &ptr, '=', ':'); + if (ret < 0) { + av_log(mux, AV_LOG_ERROR, "Failed to serialize group\n"); + return ret; + } + + av_bprintf(bp, "%s", ptr); + ret = strlen(ptr); + av_free(ptr); + + return ret; +} + +#define SERIALIZE(parent, child) do { \ + ret = of_serialize_options(mux, parent->child, bp); \ + if (ret < 0) \ + return ret; \ +} while (0) + +#define SERIALIZE_LOOP_SUBBLOCK(obj) do { \ + for (int k = 0; k < obj->nb_subblocks; k++) { \ + ret = of_serialize_options(mux, \ + av_iamf_param_definition_get_subblock(obj, k), bp); \ + if (ret < 0) \ + return ret; \ + } \ +} while (0) + +#define SERIALIZE_LOOP(parent, child, suffix, separator) do { \ + for (int j = 0; j < parent->nb_## child ## suffix; j++) { \ + av_bprintf(bp, separator#child "="); \ + SERIALIZE(parent, child ## suffix[j]); \ + } \ +} while (0) + +static int64_t get_stream_group_index_from_id(Muxer *mux, int64_t id) +{ + AVFormatContext *oc = mux->fc; + + for (unsigned i = 0; i < oc->nb_stream_groups; i++) + if (oc->stream_groups[i]->id == id) + return oc->stream_groups[i]->index; + + return AVERROR(EINVAL); +} + +static int of_map_group(Muxer *mux, AVDictionary **dict, AVBPrint *bp, const char *map) +{ + AVStreamGroup *stg; + int ret, file_idx, stream_idx; + char *ptr; + + file_idx = strtol(map, &ptr, 0); + if (file_idx >= nb_input_files || file_idx < 0 || map == ptr) { + av_log(mux, AV_LOG_ERROR, "Invalid input file index: %d.\n", file_idx); + return AVERROR(EINVAL); + } + + stream_idx = strtol(*ptr == '=' ? ptr + 1 : ptr, &ptr, 0); + if (*ptr || stream_idx >= input_files[file_idx]->ctx->nb_stream_groups || stream_idx < 0) { + av_log(mux, AV_LOG_ERROR, "Invalid input stream group index: %d.\n", stream_idx); + return AVERROR(EINVAL); + } + + stg = input_files[file_idx]->ctx->stream_groups[stream_idx]; + ret = of_serialize_options(mux, stg, bp); + if (ret < 0) + return ret; + + ret = av_dict_parse_string(dict, bp->str, "=", ":", 0); + if (ret < 0) + av_log(mux, AV_LOG_ERROR, "Error parsing mapped group specification %s\n", ptr); + av_dict_set_int(dict, "type", stg->type, 0); + + av_bprint_clear(bp); + switch(stg->type) { + case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: { + AVIAMFAudioElement *audio_element = stg->params.iamf_audio_element; + + if (audio_element->demixing_info) { + AVIAMFParamDefinition *demixing_info = audio_element->demixing_info; + av_bprintf(bp, ",demixing="); + SERIALIZE(audio_element, demixing_info); + if (ret && demixing_info->nb_subblocks) + av_bprintf(bp, ":"); + SERIALIZE_LOOP_SUBBLOCK(demixing_info); + } + if (audio_element->recon_gain_info) { + AVIAMFParamDefinition *recon_gain_info = audio_element->recon_gain_info; + av_bprintf(bp, ",recon_gain="); + SERIALIZE(audio_element, recon_gain_info); + if (ret && recon_gain_info->nb_subblocks) + av_bprintf(bp, ":"); + SERIALIZE_LOOP_SUBBLOCK(recon_gain_info); + } + SERIALIZE_LOOP(audio_element, layer, s, ","); + break; + } + case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: { + AVIAMFMixPresentation *mix = stg->params.iamf_mix_presentation; + + for (int i = 0; i < mix->nb_submixes; i++) { + AVIAMFSubmix *submix = mix->submixes[i]; + AVIAMFParamDefinition *output_mix_config = submix->output_mix_config; + + av_bprintf(bp, ",submix="); + SERIALIZE(mix, submixes[i]); + if (ret && output_mix_config->nb_subblocks) + av_bprintf(bp, ":"); + SERIALIZE_LOOP_SUBBLOCK(output_mix_config); + for (int j = 0; j < submix->nb_elements; j++) { + AVIAMFSubmixElement *element = submix->elements[j]; + AVIAMFParamDefinition *element_mix_config = element->element_mix_config; + int64_t id = get_stream_group_index_from_id(mux, element->audio_element_id); + + if (id < 0) { + av_log(mux, AV_LOG_ERROR, "Invalid or missing stream group index in" + "submix element"); + return id; + } + + av_bprintf(bp, "|element="); + SERIALIZE(submix, elements[j]); + if (ret && element_mix_config->nb_subblocks) + av_bprintf(bp, ":"); + SERIALIZE_LOOP_SUBBLOCK(element_mix_config); + if (ret) + av_bprintf(bp, ":"); + av_bprintf(bp, "stg=%"PRId64, id); + } + SERIALIZE_LOOP(submix, layout, s, "|"); + } + break; + } + default: + av_log(mux, AV_LOG_ERROR, "Unsupported mapped group type %d.\n", stg->type); + ret = AVERROR(EINVAL); + break; + } + return 0; +} + static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) { AVFormatContext *oc = mux->fc; AVStreamGroup *stg; AVDictionary *dict = NULL, *tmp = NULL; + char *mapped_string = NULL; const AVDictionaryEntry *e; const AVOption opts[] = { { "type", "Set group type", offsetof(AVStreamGroup, type), AV_OPT_TYPE_INT, @@ -2181,8 +2486,31 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) return ret; } + av_dict_copy(&tmp, dict, 0); + e = av_dict_get(dict, "map", NULL, 0); + if (e) { + AVBPrint bp; + + if (ptr) { + av_log(mux, AV_LOG_ERROR, "Unexpected extra parameters when mapping a" + " stream group\n"); + ret = AVERROR(EINVAL); + goto end; + } + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); + ret = of_map_group(mux, &tmp, &bp, e->value); + if (ret < 0) { + av_bprint_finalize(&bp, NULL); + goto end; + } + + av_bprint_finalize(&bp, &mapped_string); + ptr = mapped_string; + } + // "type" is not a user settable AVOption in AVStreamGroup, so handle it here - e = av_dict_get(dict, "type", NULL, 0); + e = av_dict_get(tmp, "type", NULL, 0); if (!e) { av_log(mux, AV_LOG_ERROR, "No type specified for Stream Group in \"%s\"\n", token); ret = AVERROR(EINVAL); @@ -2197,7 +2525,6 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) goto end; } - av_dict_copy(&tmp, dict, 0); stg = avformat_stream_group_create(oc, type, &tmp); if (!stg) { ret = AVERROR(ENOMEM); @@ -2250,6 +2577,7 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) // make sure that nothing but "st" and "stg" entries are left in the dict e = NULL; + av_dict_set(&tmp, "map", NULL, 0); av_dict_set(&tmp, "type", NULL, 0); while (e = av_dict_iterate(tmp, e)) { if (!strcmp(e->key, "st") || !strcmp(e->key, "stg")) @@ -2262,6 +2590,7 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) ret = 0; end: + av_free(mapped_string); av_dict_free(&dict); av_dict_free(&tmp); @@ -2679,7 +3008,7 @@ static int set_dispositions(Muxer *mux, const OptionsContext *o) nb_streams[ost->type + 1]++; - MATCH_PER_STREAM_OPT(disposition, str, dispositions[i], ctx, ost->st); + opt_match_per_stream_str(ost, &o->disposition, ctx, ost->st, &dispositions[i]); have_manual |= !!dispositions[i]; @@ -2768,9 +3097,13 @@ static int parse_forced_key_frames(void *log, KeyframeForceCtx *kf, unsigned int nb_ch = mux->fc->nb_chapters; int j; - if (nb_ch > INT_MAX - size || - !(pts = av_realloc_f(pts, size += nb_ch - 1, - sizeof(*pts)))) + if (nb_ch > INT_MAX - size) { + ret = AVERROR(ERANGE); + goto fail; + } + size += nb_ch - 1; + pts = av_realloc_f(pts, size, sizeof(*pts)); + if (!pts) return AVERROR(ENOMEM); if (p[8]) { @@ -2821,7 +3154,8 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o) OutputStream *ost = mux->of.streams[i]; const char *forced_keyframes = NULL; - MATCH_PER_STREAM_OPT(forced_key_frames, str, forced_keyframes, mux->fc, ost->st); + opt_match_per_stream_str(ost, &o->forced_key_frames, + mux->fc, ost->st, &forced_keyframes); if (!(ost->type == AVMEDIA_TYPE_VIDEO && ost->enc_ctx && forced_keyframes)) @@ -2860,52 +3194,6 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o) return 0; } -static int validate_enc_avopt(Muxer *mux, const AVDictionary *codec_avopt) -{ - const AVClass *class = avcodec_get_class(); - const AVClass *fclass = avformat_get_class(); - const OutputFile *of = &mux->of; - - AVDictionary *unused_opts; - const AVDictionaryEntry *e; - - unused_opts = strip_specifiers(codec_avopt); - for (int i = 0; i < of->nb_streams; i++) { - e = NULL; - while ((e = av_dict_iterate(of->streams[i]->encoder_opts, e))) - av_dict_set(&unused_opts, e->key, NULL, 0); - } - - e = NULL; - while ((e = av_dict_iterate(unused_opts, e))) { - const AVOption *option = av_opt_find(&class, e->key, NULL, 0, - AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); - const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0, - AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); - if (!option || foption) - continue; - - if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) { - av_log(mux, AV_LOG_ERROR, "Codec AVOption %s (%s) is not an " - "encoding option.\n", e->key, option->help ? option->help : ""); - return AVERROR(EINVAL); - } - - // gop_timecode is injected by generic code but not always used - if (!strcmp(e->key, "gop_timecode")) - continue; - - av_log(mux, AV_LOG_WARNING, "Codec AVOption %s (%s) has not been used " - "for any stream. The most likely reason is either wrong type " - "(e.g. a video option with no video streams) or that it is a " - "private option of some encoder which was not actually used for " - "any stream.\n", e->key, option->help ? option->help : ""); - } - av_dict_free(&unused_opts); - - return 0; -} - static const char *output_file_item_name(void *obj) { const Muxer *mux = obj; @@ -2968,7 +3256,6 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch) of->recording_time = recording_time; of->start_time = o->start_time; - of->shortest = o->shortest; mux->limit_filesize = o->limit_filesize; av_dict_copy(&mux->opts, o->g->format_opts, 0); @@ -2988,7 +3275,6 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch) av_strlcat(mux->log_name, oc->oformat->name, sizeof(mux->log_name)); - of->format = oc->oformat; if (recording_time != INT64_MAX) oc->duration = recording_time; @@ -3015,7 +3301,8 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch) return err; /* check if all codec options have been used */ - err = validate_enc_avopt(mux, o->g->codec_opts); + err = check_avoptions_used(o->g->codec_opts, mux->enc_opts_used, mux, 0); + av_dict_free(&mux->enc_opts_used); if (err < 0) return err; @@ -3084,7 +3371,8 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch) return err; } - err = setup_sync_queues(mux, oc, o->shortest_buf_duration * AV_TIME_BASE); + err = setup_sync_queues(mux, oc, o->shortest_buf_duration * AV_TIME_BASE, + o->shortest); if (err < 0) { av_log(mux, AV_LOG_FATAL, "Error setting up output sync queues\n"); return err; diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 4b3f9789b..f639a1cf0 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -31,7 +31,6 @@ #include "ffmpeg_sched.h" #include "cmdutils.h" #include "opt_common.h" -#include "sync_queue.h" #include "libavformat/avformat.h" @@ -43,16 +42,11 @@ #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/intreadwrite.h" -#include "libavutil/fifo.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" -#include "libavutil/pixdesc.h" -#include "libavutil/pixfmt.h" +#include "libavutil/stereo3d.h" HWDevice *filter_hw_device; @@ -94,8 +88,6 @@ int recast_media = 0; static void uninit_options(OptionsContext *o) { - int i; - /* all OPT_SPEC and OPT_TYPE_STRING can be freed in generic way */ for (const OptionDef *po = options; po->name; po++) { void *dst; @@ -108,6 +100,8 @@ static void uninit_options(OptionsContext *o) SpecifierOptList *so = dst; for (int i = 0; i < so->nb_opt; i++) { av_freep(&so->opt[i].specifier); + if (po->flags & OPT_FLAG_PERSTREAM) + stream_specifier_uninit(&so->opt[i].stream_spec); if (po->type == OPT_TYPE_STRING) av_freep(&so->opt[i].u.str); } @@ -117,11 +111,11 @@ static void uninit_options(OptionsContext *o) av_freep(dst); } - for (i = 0; i < o->nb_stream_maps; i++) + for (int i = 0; i < o->nb_stream_maps; i++) av_freep(&o->stream_maps[i].linklabel); av_freep(&o->stream_maps); - for (i = 0; i < o->nb_attachments; i++) + for (int i = 0; i < o->nb_attachments; i++) av_freep(&o->attachments[i]); av_freep(&o->attachments); @@ -158,24 +152,6 @@ static int show_hwaccels(void *optctx, const char *opt, const char *arg) return 0; } -/* return a copy of the input with the stream specifiers removed from the keys */ -AVDictionary *strip_specifiers(const AVDictionary *dict) -{ - const AVDictionaryEntry *e = NULL; - AVDictionary *ret = NULL; - - while ((e = av_dict_iterate(dict, e))) { - char *p = strchr(e->key, ':'); - - if (p) - *p = 0; - av_dict_set(&ret, e->key, e->value, 0); - if (p) - *p = ':'; - } - return ret; -} - const char *opt_match_per_type_str(const SpecifierOptList *sol, char mediatype) { @@ -189,6 +165,123 @@ const char *opt_match_per_type_str(const SpecifierOptList *sol, return NULL; } +static unsigned opt_match_per_stream(void *logctx, enum OptionType type, + const SpecifierOptList *sol, + AVFormatContext *fc, AVStream *st) +{ + 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_specifier_match(ss, fc, st, 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 %d, only the last option '-%s%s%s %s' will be used.\n", + namestr, st->index, sol->opt_canon->name, spec[0] ? ":" : "", + spec, optval); + } + + return match_idx + 1; +} + +#define OPT_MATCH_PER_STREAM(name, type, opt_type, m) \ +void opt_match_per_stream_ ## name(void *logctx, const SpecifierOptList *sol, \ + AVFormatContext *fc, AVStream *st, type *out) \ +{ \ + unsigned ret = opt_match_per_stream(logctx, opt_type, sol, fc, st); \ + if (ret > 0) \ + *out = sol->opt[ret - 1].u.m; \ +} + +OPT_MATCH_PER_STREAM(str, const char *, OPT_TYPE_STRING, str); +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); + +int view_specifier_parse(const char **pspec, ViewSpecifier *vs) +{ + const char *spec = *pspec; + char *endptr; + + vs->type = VIEW_SPECIFIER_TYPE_NONE; + + if (!strncmp(spec, "view:", 5)) { + spec += 5; + + if (!strncmp(spec, "all", 3)) { + spec += 3; + vs->type = VIEW_SPECIFIER_TYPE_ALL; + } else { + vs->type = VIEW_SPECIFIER_TYPE_ID; + vs->val = strtoul(spec, &endptr, 0); + if (endptr == spec) { + av_log(NULL, AV_LOG_ERROR, "Invalid view ID: %s\n", spec); + return AVERROR(EINVAL); + } + spec = endptr; + } + } else if (!strncmp(spec, "vidx:", 5)) { + spec += 5; + vs->type = VIEW_SPECIFIER_TYPE_IDX; + vs->val = strtoul(spec, &endptr, 0); + if (endptr == spec) { + av_log(NULL, AV_LOG_ERROR, "Invalid view index: %s\n", spec); + return AVERROR(EINVAL); + } + spec = endptr; + } else if (!strncmp(spec, "vpos:", 5)) { + spec += 5; + vs->type = VIEW_SPECIFIER_TYPE_POS; + + if (!strncmp(spec, "left", 4) && !cmdutils_isalnum(spec[4])) { + spec += 4; + vs->val = AV_STEREO3D_VIEW_LEFT; + } else if (!strncmp(spec, "right", 5) && !cmdutils_isalnum(spec[5])) { + spec += 5; + vs->val = AV_STEREO3D_VIEW_RIGHT; + } else { + av_log(NULL, AV_LOG_ERROR, "Invalid view position: %s\n", spec); + return AVERROR(EINVAL); + } + } else + return 0; + + *pspec = spec; + + return 0; +} + int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global) { if (!av_strcasecmp(arg, "cfr")) *vsync_var = VSYNC_CFR; @@ -324,7 +417,7 @@ static int opt_filter_threads(void *optctx, const char *opt, const char *arg) static int opt_abort_on(void *optctx, const char *opt, const char *arg) { static const AVOption opts[] = { - { "abort_on" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" }, + { "abort_on" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, (double)INT64_MAX, .unit = "flags" }, { "empty_output" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT }, .unit = "flags" }, { "empty_output_stream", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM }, .unit = "flags" }, { NULL }, @@ -386,22 +479,20 @@ static int opt_map(void *optctx, const char *opt, const char *arg) { OptionsContext *o = optctx; StreamMap *m = NULL; + StreamSpecifier ss; int i, negative = 0, file_idx, disabled = 0; - int ret; - char *map, *p; - char *allow_unused; + int ret, allow_unused = 0; + + memset(&ss, 0, sizeof(ss)); if (*arg == '-') { negative = 1; arg++; } - map = av_strdup(arg); - if (!map) - return AVERROR(ENOMEM); - if (map[0] == '[') { + if (arg[0] == '[') { /* this mapping refers to lavfi output */ - const char *c = map + 1; + const char *c = arg + 1; ret = GROW_ARRAY(o->stream_maps, o->nb_stream_maps); if (ret < 0) @@ -410,33 +501,62 @@ static int opt_map(void *optctx, const char *opt, const char *arg) m = &o->stream_maps[o->nb_stream_maps - 1]; m->linklabel = av_get_token(&c, "]"); if (!m->linklabel) { - av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", map); + av_log(NULL, AV_LOG_ERROR, "Invalid output link label: %s.\n", arg); ret = AVERROR(EINVAL); goto fail; } } else { - if (allow_unused = strchr(map, '?')) - *allow_unused = 0; - file_idx = strtol(map, &p, 0); + ViewSpecifier vs; + char *endptr; + + file_idx = strtol(arg, &endptr, 0); if (file_idx >= nb_input_files || file_idx < 0) { av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx); ret = AVERROR(EINVAL); goto fail; } + arg = endptr; + + ret = stream_specifier_parse(&ss, *arg == ':' ? arg + 1 : arg, 1, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Invalid stream specifier: %s\n", arg); + goto fail; + } + + arg = ss.remainder ? ss.remainder : ""; + + ret = view_specifier_parse(&arg, &vs); + if (ret < 0) + goto fail; + + if (*arg) { + if (!strcmp(arg, "?")) + allow_unused = 1; + else { + av_log(NULL, AV_LOG_ERROR, + "Trailing garbage after stream specifier: %s\n", arg); + ret = AVERROR(EINVAL); + goto fail; + } + } + if (negative) /* disable some already defined maps */ for (i = 0; i < o->nb_stream_maps; i++) { m = &o->stream_maps[i]; if (file_idx == m->file_index && - check_stream_specifier(input_files[m->file_index]->ctx, + stream_specifier_match(&ss, + input_files[m->file_index]->ctx, input_files[m->file_index]->ctx->streams[m->stream_index], - *p == ':' ? p + 1 : p) > 0) + NULL)) m->disabled = 1; } else for (i = 0; i < input_files[file_idx]->nb_streams; i++) { - if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i], - *p == ':' ? p + 1 : p) <= 0) + if (!stream_specifier_match(&ss, + input_files[file_idx]->ctx, + input_files[file_idx]->ctx->streams[i], + NULL)) continue; if (input_files[file_idx]->streams[i]->user_set_discard == AVDISCARD_ALL) { disabled = 1; @@ -450,6 +570,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg) m->file_index = file_idx; m->stream_index = i; + m->vs = vs; } } @@ -470,7 +591,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg) } ret = 0; fail: - av_freep(&map); + stream_specifier_uninit(&ss); return ret; } @@ -1271,12 +1392,10 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch) } // bind unbound filtegraph inputs/outputs and check consistency - for (int i = 0; i < nb_filtergraphs; i++) { - ret = fg_finalise_bindings(filtergraphs[i]); - if (ret < 0) { - errmsg = "binding filtergraph inputs/outputs"; - goto fail; - } + ret = fg_finalise_bindings(); + if (ret < 0) { + errmsg = "binding filtergraph inputs/outputs"; + goto fail; } correct_input_start_times(); @@ -1504,9 +1623,6 @@ const OptionDef options[] = { { "bitexact", OPT_TYPE_BOOL, OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT | OPT_INPUT, { .off = OFFSET(bitexact) }, "bitexact mode" }, - { "apad", OPT_TYPE_STRING, OPT_PERSTREAM | OPT_EXPERT | OPT_OUTPUT, - { .off = OFFSET(apad) }, - "audio pad", "" }, { "dts_delta_threshold", OPT_TYPE_FLOAT, OPT_EXPERT, { &dts_delta_threshold }, "timestamp discontinuity delta threshold", "threshold" }, @@ -1735,12 +1851,15 @@ const OptionDef options[] = { { "hwaccels", OPT_TYPE_FUNC, OPT_EXIT | OPT_EXPERT, { .func_arg = show_hwaccels }, "show available HW acceleration methods" }, - { "autorotate", OPT_TYPE_BOOL, OPT_PERSTREAM | OPT_EXPERT | OPT_INPUT, + { "autorotate", OPT_TYPE_BOOL, OPT_VIDEO | OPT_PERSTREAM | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(autorotate) }, "automatically insert correct rotate filters" }, - { "autoscale", OPT_TYPE_BOOL, OPT_PERSTREAM | OPT_EXPERT | OPT_OUTPUT, + { "autoscale", OPT_TYPE_BOOL, OPT_VIDEO | OPT_PERSTREAM | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(autoscale) }, "automatically insert a scale filter at the end of the filter graph" }, + { "apply_cropping", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_EXPERT | OPT_INPUT, + { .off = OFFSET(apply_cropping) }, + "select the cropping to apply" }, { "fix_sub_duration_heartbeat", OPT_TYPE_BOOL, OPT_VIDEO | OPT_EXPERT | OPT_PERSTREAM | OPT_OUTPUT, { .off = OFFSET(fix_sub_duration_heartbeat) }, "set this video output stream to be a heartbeat stream for " @@ -1771,6 +1890,9 @@ const OptionDef options[] = { { "ab", OPT_TYPE_FUNC, OPT_AUDIO | OPT_FUNC_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_bitrate }, "alias for -b:a (select bitrate for audio streams)", "bitrate" }, + { "apad", OPT_TYPE_STRING, OPT_AUDIO | OPT_PERSTREAM | OPT_EXPERT | OPT_OUTPUT, + { .off = OFFSET(apad) }, + "audio pad", "" }, { "atag", OPT_TYPE_FUNC, OPT_AUDIO | OPT_FUNC_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT | OPT_HAS_CANON, { .func_arg = opt_old2new }, "force audio tag/fourcc", "fourcc/tag", diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c index ee3af4590..ef0b6e289 100644 --- a/fftools/ffmpeg_sched.c +++ b/fftools/ffmpeg_sched.c @@ -71,13 +71,19 @@ typedef struct SchTask { int thread_running; } SchTask; +typedef struct SchDecOutput { + SchedulerNode *dst; + uint8_t *dst_finished; + unsigned nb_dst; +} SchDecOutput; + typedef struct SchDec { const AVClass *class; SchedulerNode src; - SchedulerNode *dst; - uint8_t *dst_finished; - unsigned nb_dst; + + SchDecOutput *outputs; + unsigned nb_outputs; SchTask task; // Queue for receiving input packets, one stream. @@ -513,8 +519,14 @@ void sch_free(Scheduler **psch) av_thread_message_queue_free(&dec->queue_end_ts); - av_freep(&dec->dst); - av_freep(&dec->dst_finished); + for (unsigned j = 0; j < dec->nb_outputs; j++) { + SchDecOutput *o = &dec->outputs[j]; + + av_freep(&o->dst); + av_freep(&o->dst_finished); + } + + av_freep(&dec->outputs); av_frame_free(&dec->send_frame); } @@ -712,14 +724,28 @@ int sch_add_demux_stream(Scheduler *sch, unsigned demux_idx) return ret < 0 ? ret : d->nb_streams - 1; } +int sch_add_dec_output(Scheduler *sch, unsigned dec_idx) +{ + SchDec *dec; + int ret; + + av_assert0(dec_idx < sch->nb_dec); + dec = &sch->dec[dec_idx]; + + ret = GROW_ARRAY(dec->outputs, dec->nb_outputs); + if (ret < 0) + return ret; + + return dec->nb_outputs - 1; +} + static const AVClass sch_dec_class = { .class_name = "SchDec", .version = LIBAVUTIL_VERSION_INT, .parent_log_context_offset = offsetof(SchDec, task.func_arg), }; -int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, - int send_end_ts) +int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, int send_end_ts) { const unsigned idx = sch->nb_dec; @@ -739,6 +765,10 @@ int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, if (!dec->send_frame) return AVERROR(ENOMEM); + ret = sch_add_dec_output(sch, idx); + if (ret < 0) + return ret; + ret = queue_alloc(&dec->queue, 1, 0, QUEUE_PACKETS); if (ret < 0) return ret; @@ -943,15 +973,19 @@ int sch_connect(Scheduler *sch, SchedulerNode src, SchedulerNode dst) } case SCH_NODE_TYPE_DEC: { SchDec *dec; + SchDecOutput *o; av_assert0(src.idx < sch->nb_dec); dec = &sch->dec[src.idx]; - ret = GROW_ARRAY(dec->dst, dec->nb_dst); + av_assert0(src.idx_stream < dec->nb_outputs); + o = &dec->outputs[src.idx_stream]; + + ret = GROW_ARRAY(o->dst, o->nb_dst); if (ret < 0) return ret; - dec->dst[dec->nb_dst - 1] = dst; + o->dst[o->nb_dst - 1] = dst; // decoded frames go to filters or encoding switch (dst.type) { @@ -983,20 +1017,40 @@ int sch_connect(Scheduler *sch, SchedulerNode src, SchedulerNode dst) } case SCH_NODE_TYPE_FILTER_OUT: { SchFilterOut *fo; - SchEnc *enc; av_assert0(src.idx < sch->nb_filters && src.idx_stream < sch->filters[src.idx].nb_outputs); - // filtered frames go to encoding - av_assert0(dst.type == SCH_NODE_TYPE_ENC && - dst.idx < sch->nb_enc); + fo = &sch->filters[src.idx].outputs[src.idx_stream]; - fo = &sch->filters[src.idx].outputs[src.idx_stream]; - enc = &sch->enc[dst.idx]; + av_assert0(!fo->dst.type); + fo->dst = dst; + + // filtered frames go to encoding or another filtergraph + switch (dst.type) { + case SCH_NODE_TYPE_ENC: { + SchEnc *enc; + + av_assert0(dst.idx < sch->nb_enc); + enc = &sch->enc[dst.idx]; + + av_assert0(!enc->src.type); + enc->src = src; + break; + } + case SCH_NODE_TYPE_FILTER_IN: { + SchFilterIn *fi; + + av_assert0(dst.idx < sch->nb_filters && + dst.idx_stream < sch->filters[dst.idx].nb_inputs); + fi = &sch->filters[dst.idx].inputs[dst.idx_stream]; + + av_assert0(!fi->src.type); + fi->src = src; + break; + } + default: av_assert0(0); + } - av_assert0(!fo->dst.type && !enc->src.type); - fo->dst = dst; - enc->src = src; break; } @@ -1351,24 +1405,13 @@ static int check_acyclic(Scheduler *sch) goto fail; } - // trace the transcoding graph upstream from every output stream - // fed by a filtergraph - for (unsigned i = 0; i < sch->nb_mux; i++) { - SchMux *mux = &sch->mux[i]; - - for (unsigned j = 0; j < mux->nb_streams; j++) { - SchMuxStream *ms = &mux->streams[j]; - SchedulerNode src = ms->src_sched; - - if (src.type != SCH_NODE_TYPE_FILTER_OUT) - continue; - src.idx_stream = 0; - - ret = check_acyclic_for_output(sch, src, filters_visited, filters_stack); - if (ret < 0) { - av_log(mux, AV_LOG_ERROR, "Transcoding graph has a cycle\n"); - goto fail; - } + // trace the transcoding graph upstream from every filtegraph + for (unsigned i = 0; i < sch->nb_filters; i++) { + ret = check_acyclic_for_output(sch, (SchedulerNode){ .idx = i }, + filters_visited, filters_stack); + if (ret < 0) { + av_log(&sch->filters[i], AV_LOG_ERROR, "Transcoding graph has a cycle\n"); + goto fail; } } @@ -1408,15 +1451,20 @@ static int start_prepare(Scheduler *sch) "Decoder not connected to a source\n"); return AVERROR(EINVAL); } - if (!dec->nb_dst) { - av_log(dec, AV_LOG_ERROR, - "Decoder not connected to any sink\n"); - return AVERROR(EINVAL); - } - dec->dst_finished = av_calloc(dec->nb_dst, sizeof(*dec->dst_finished)); - if (!dec->dst_finished) - return AVERROR(ENOMEM); + for (unsigned j = 0; j < dec->nb_outputs; j++) { + SchDecOutput *o = &dec->outputs[j]; + + if (!o->nb_dst) { + av_log(dec, AV_LOG_ERROR, + "Decoder output %u not connected to any sink\n", j); + return AVERROR(EINVAL); + } + + o->dst_finished = av_calloc(o->nb_dst, sizeof(*o->dst_finished)); + if (!o->dst_finished) + return AVERROR(ENOMEM); + } } for (unsigned i = 0; i < sch->nb_enc; i++) { @@ -1484,13 +1532,18 @@ static int start_prepare(Scheduler *sch) "Filtergraph input %u not connected to a source\n", j); return AVERROR(EINVAL); } - 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); + 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); + } } } @@ -2157,21 +2210,26 @@ finish: return AVERROR_EOF; } -int sch_dec_send(Scheduler *sch, unsigned dec_idx, AVFrame *frame) +int sch_dec_send(Scheduler *sch, unsigned dec_idx, + unsigned out_idx, AVFrame *frame) { SchDec *dec; - int ret = 0; + SchDecOutput *o; + int ret; unsigned nb_done = 0; av_assert0(dec_idx < sch->nb_dec); dec = &sch->dec[dec_idx]; - for (unsigned i = 0; i < dec->nb_dst; i++) { - uint8_t *finished = &dec->dst_finished[i]; + av_assert0(out_idx < dec->nb_outputs); + o = &dec->outputs[out_idx]; + + for (unsigned i = 0; i < o->nb_dst; i++) { + uint8_t *finished = &o->dst_finished[i]; AVFrame *to_send = frame; // sending a frame consumes it, so make a temporary reference if needed - if (i < dec->nb_dst - 1) { + if (i < o->nb_dst - 1) { to_send = dec->send_frame; // frame may sometimes contain props only, @@ -2182,19 +2240,18 @@ int sch_dec_send(Scheduler *sch, unsigned dec_idx, AVFrame *frame) return ret; } - ret = dec_send_to_dst(sch, dec->dst[i], finished, to_send); + ret = dec_send_to_dst(sch, o->dst[i], finished, to_send); if (ret < 0) { av_frame_unref(to_send); if (ret == AVERROR_EOF) { nb_done++; - ret = 0; continue; } return ret; } } - return (nb_done == dec->nb_dst) ? AVERROR_EOF : 0; + return (nb_done == o->nb_dst) ? AVERROR_EOF : 0; } static int dec_done(Scheduler *sch, unsigned dec_idx) @@ -2209,10 +2266,14 @@ static int dec_done(Scheduler *sch, unsigned dec_idx) if (dec->queue_end_ts) av_thread_message_queue_set_err_recv(dec->queue_end_ts, AVERROR_EOF); - for (unsigned i = 0; i < dec->nb_dst; i++) { - int err = dec_send_to_dst(sch, dec->dst[i], &dec->dst_finished[i], NULL); - if (err < 0 && err != AVERROR_EOF) - ret = err_merge(ret, err); + for (unsigned i = 0; i < dec->nb_outputs; i++) { + SchDecOutput *o = &dec->outputs[i]; + + for (unsigned j = 0; j < o->nb_dst; j++) { + int err = dec_send_to_dst(sch, o->dst[j], &o->dst_finished[j], NULL); + if (err < 0 && err != AVERROR_EOF) + ret = err_merge(ret, err); + } } return ret; @@ -2286,15 +2347,13 @@ int sch_enc_send(Scheduler *sch, unsigned enc_idx, AVPacket *pkt) ret = enc_send_to_dst(sch, enc->dst[i], finished, to_send); if (ret < 0) { av_packet_unref(to_send); - if (ret == AVERROR_EOF) { - ret = 0; + if (ret == AVERROR_EOF) continue; - } return ret; } } - return ret; + return 0; } static int enc_done(Scheduler *sch, unsigned enc_idx) @@ -2381,12 +2440,17 @@ void sch_filter_receive_finish(Scheduler *sch, unsigned fg_idx, unsigned in_idx) int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, AVFrame *frame) { SchFilterGraph *fg; + SchedulerNode dst; av_assert0(fg_idx < sch->nb_filters); fg = &sch->filters[fg_idx]; av_assert0(out_idx < fg->nb_outputs); - return send_to_enc(sch, &sch->enc[fg->outputs[out_idx].dst.idx], frame); + 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); } static int filter_done(Scheduler *sch, unsigned fg_idx) @@ -2398,8 +2462,11 @@ static int filter_done(Scheduler *sch, unsigned fg_idx) tq_receive_finish(fg->queue, i); for (unsigned i = 0; i < fg->nb_outputs; i++) { - SchEnc *enc = &sch->enc[fg->outputs[i].dst.idx]; - int err = send_to_enc(sch, enc, NULL); + SchedulerNode dst = fg->outputs[i].dst; + int err = (dst.type == SCH_NODE_TYPE_ENC) ? + send_to_enc (sch, &sch->enc[dst.idx], NULL) : + send_to_filter(sch, &sch->filters[dst.idx], dst.idx_stream, NULL); + if (err < 0 && err != AVERROR_EOF) ret = err_merge(ret, err); } diff --git a/fftools/ffmpeg_sched.h b/fftools/ffmpeg_sched.h index e51c26cec..3062c4a6e 100644 --- a/fftools/ffmpeg_sched.h +++ b/fftools/ffmpeg_sched.h @@ -41,7 +41,8 @@ * - filtergraphs, each containing zero or more inputs (0 in case the * filtergraph contains a lavfi source filter), and one or more outputs; the * inputs and outputs need not have matching media types; - * each filtergraph input receives decoded frames from some decoder; + * each filtergraph input receives decoded frames from some decoder or another + * filtergraph output; * filtered frames from each output are sent to some encoder; * - encoders, which receive decoded frames from some decoder (subtitles) or * some filtergraph output (audio/video), encode them, and send encoded @@ -51,6 +52,9 @@ * encoder (transcoding); those packets are interleaved and written out by the * muxer. * + * The structure formed by the above components is a directed acyclic graph + * (absence of cycles is checked at startup). + * * There must be at least one muxer instance, otherwise the transcode produces * no output and is meaningless. Otherwise, in a generic transcoding scenario * there may be arbitrary number of instances of any of the above components, @@ -110,9 +114,12 @@ typedef int (*SchThreadFunc)(void *arg); #define SCH_MSTREAM(file, stream) \ (SchedulerNode){ .type = SCH_NODE_TYPE_MUX, \ .idx = file, .idx_stream = stream } -#define SCH_DEC(decoder) \ +#define SCH_DEC_IN(decoder) \ (SchedulerNode){ .type = SCH_NODE_TYPE_DEC, \ - .idx = decoder } + .idx = decoder } +#define SCH_DEC_OUT(decoder, out_idx) \ + (SchedulerNode){ .type = SCH_NODE_TYPE_DEC, \ + .idx = decoder, .idx_stream = out_idx } #define SCH_ENC(encoder) \ (SchedulerNode){ .type = SCH_NODE_TYPE_ENC, \ .idx = encoder } @@ -174,8 +181,15 @@ int sch_add_demux_stream(Scheduler *sch, unsigned demux_idx); * @retval ">=0" Index of the newly-created decoder. * @retval "<0" Error code. */ -int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, - int send_end_ts); +int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, int send_end_ts); + +/** + * Add another output to decoder (e.g. for multiview video). + * + * @retval ">=0" Index of the newly-added decoder output. + * @retval "<0" Error code. + */ +int sch_add_dec_output(Scheduler *sch, unsigned dec_idx); /** * Add a filtergraph to the scheduler. @@ -375,7 +389,8 @@ int sch_dec_receive(Scheduler *sch, unsigned dec_idx, struct AVPacket *pkt); * @retval AVERROR_EOF all consumers are done, should terminate decoding * @retval "another negative error code" other failure */ -int sch_dec_send(Scheduler *sch, unsigned dec_idx, struct AVFrame *frame); +int sch_dec_send(Scheduler *sch, unsigned dec_idx, + unsigned out_idx, struct AVFrame *frame); /** * Called by filtergraph tasks to obtain frames for filtering. Will wait for a diff --git a/fftools/ffmpeg_utils.h b/fftools/ffmpeg_utils.h index bd225abc3..7939e44cd 100644 --- a/fftools/ffmpeg_utils.h +++ b/fftools/ffmpeg_utils.h @@ -35,11 +35,12 @@ typedef struct Timestamp { /** * Merge two return codes - return one of the error codes if at least one of * them was negative, 0 otherwise. - * Currently just picks the first one, eventually we might want to do something - * more sophisticated, like sorting them by priority. */ static inline int err_merge(int err0, int err1) { + // prefer "real" errors over EOF + if ((err0 >= 0 || err0 == AVERROR_EOF) && err1 < 0) + return err1; return (err0 < 0) ? err0 : FFMIN(err1, 0); } diff --git a/fftools/ffplay.c b/fftools/ffplay.c index 048a4a870..96b0b614b 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -25,7 +25,6 @@ #include "config.h" #include "config_components.h" -#include #include #include #include @@ -33,13 +32,11 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" -#include "libavutil/eval.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" -#include "libavutil/imgutils.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" @@ -1966,16 +1963,21 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c theta = get_rotation(displaymatrix); if (fabs(theta - 90) < 1.0) { - INSERT_FILT("transpose", "clock"); + INSERT_FILT("transpose", displaymatrix[3] > 0 ? "cclock_flip" : "clock"); } else if (fabs(theta - 180) < 1.0) { - INSERT_FILT("hflip", NULL); - INSERT_FILT("vflip", NULL); + if (displaymatrix[0] < 0) + INSERT_FILT("hflip", NULL); + if (displaymatrix[4] < 0) + INSERT_FILT("vflip", NULL); } else if (fabs(theta - 270) < 1.0) { - INSERT_FILT("transpose", "cclock"); + INSERT_FILT("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); INSERT_FILT("rotate", rotate_buf); + } else { + if (displaymatrix && displaymatrix[4] < 0) + INSERT_FILT("vflip", NULL); } } @@ -2605,6 +2607,11 @@ static int create_hwaccel(AVBufferRef **device_ctx) if (type == AV_HWDEVICE_TYPE_NONE) return AVERROR(ENOTSUP); + if (!vk_renderer) { + av_log(NULL, AV_LOG_ERROR, "Vulkan renderer is not available\n"); + return AVERROR(ENOTSUP); + } + ret = vk_renderer_get_hw_dev(vk_renderer, &vk_dev); if (ret < 0) return ret; @@ -2629,7 +2636,6 @@ static int stream_component_open(VideoState *is, int stream_index) const AVCodec *codec; const char *forced_codec_name = NULL; AVDictionary *opts = NULL; - const AVDictionaryEntry *t = NULL; int sample_rate; AVChannelLayout ch_layout = { 0 }; int ret = 0; @@ -2677,7 +2683,7 @@ static int stream_component_open(VideoState *is, int stream_index) avctx->flags2 |= AV_CODEC_FLAG2_FAST; ret = filter_codec_opts(codec_opts, avctx->codec_id, ic, - ic->streams[stream_index], codec, &opts); + ic->streams[stream_index], codec, &opts, NULL); if (ret < 0) goto fail; @@ -2697,11 +2703,9 @@ static int stream_component_open(VideoState *is, int stream_index) if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) { goto fail; } - if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { - av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); - ret = AVERROR_OPTION_NOT_FOUND; + ret = check_avoptions(opts); + if (ret < 0) goto fail; - } is->eof = 0; ic->streams[stream_index]->discard = AVDISCARD_DEFAULT; @@ -2864,12 +2868,11 @@ static int read_thread(void *arg) } if (scan_all_pmts_set) av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE); + remove_avoptions(&format_opts, codec_opts); - if ((t = av_dict_get(format_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { - av_log(NULL, AV_LOG_ERROR, "Option %s not found.\n", t->key); - ret = AVERROR_OPTION_NOT_FOUND; + ret = check_avoptions(format_opts); + if (ret < 0) goto fail; - } is->ic = ic; if (genpts) diff --git a/fftools/ffplay_renderer.c b/fftools/ffplay_renderer.c index fbb68b237..f272cb46f 100644 --- a/fftools/ffplay_renderer.c +++ b/fftools/ffplay_renderer.c @@ -42,6 +42,7 @@ #include #include "libavutil/bprint.h" +#include "libavutil/mem.h" #endif diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index 7d9998b42..14b98d22a 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -46,6 +46,7 @@ #include "libavutil/mastering_display_metadata.h" #include "libavutil/hdr_dynamic_vivid_metadata.h" #include "libavutil/dovi_meta.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/spherical.h" @@ -2543,6 +2544,11 @@ static void print_pkt_side_data(WriterContext *w, 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)); @@ -2597,6 +2603,7 @@ static void print_pkt_side_data(WriterContext *w, 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); @@ -2605,6 +2612,14 @@ static void print_pkt_side_data(WriterContext *w, 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); @@ -2622,6 +2637,11 @@ static void print_pkt_side_data(WriterContext *w, 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); } @@ -2900,6 +2920,8 @@ static void print_frame_side_data(WriterContext *w, } else if (sd->type == AV_FRAME_DATA_FILM_GRAIN_PARAMS) { AVFilmGrainParams *fgp = (AVFilmGrainParams *)sd->data; print_film_grain_params(w, fgp); + } else if (sd->type == AV_FRAME_DATA_VIEW_ID) { + print_int("view_id", *(int*)sd->data); } writer_print_section_footer(w); } @@ -3323,8 +3345,8 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id if (sar.num) { print_q("sample_aspect_ratio", sar, ':'); av_reduce(&dar.num, &dar.den, - par->width * sar.num, - par->height * sar.den, + (int64_t) par->width * sar.num, + (int64_t) par->height * sar.den, 1024*1024); print_q("display_aspect_ratio", dar, ':'); } else { @@ -3921,7 +3943,7 @@ static int open_input_file(InputFile *ifile, const char *filename, AVDictionary *opts; err = filter_codec_opts(codec_opts, stream->codecpar->codec_id, - fmt_ctx, stream, codec, &opts); + fmt_ctx, stream, codec, &opts, NULL); if (err < 0) exit(1); @@ -3950,7 +3972,7 @@ static int open_input_file(InputFile *ifile, const char *filename, exit(1); } - if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { + if ((t = av_dict_iterate(opts, NULL))) { av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n", t->key, stream->index); return AVERROR_OPTION_NOT_FOUND; diff --git a/fftools/fopen_utf8.h b/fftools/fopen_utf8.h index e5be84179..1cfd15818 100644 --- a/fftools/fopen_utf8.h +++ b/fftools/fopen_utf8.h @@ -27,6 +27,7 @@ * CRT, and FILE* handles can't be shared across them.) */ #ifdef _WIN32 +#include "libavutil/mem.h" #include "libavutil/wchar_filename.h" static inline FILE *fopen_utf8(const char *path_utf8, const char *mode) diff --git a/fftools/opt_common.c b/fftools/opt_common.c index 9d2d5184a..021ed7527 100644 --- a/fftools/opt_common.c +++ b/fftools/opt_common.c @@ -262,22 +262,36 @@ int show_buildconf(void *optctx, const char *opt, const char *arg) return 0; } -#define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \ - if (codec->field) { \ - const type *p = codec->field; \ - \ - printf(" Supported " list_name ":"); \ - while (*p != term) { \ - get_name(*p); \ - printf(" %s", name); \ - p++; \ - } \ - printf("\n"); \ - } \ +#define PRINT_CODEC_SUPPORTED(codec, config, type, name, elem, fmt, ...) \ + do { \ + int num = 0; \ + const type *elem = NULL; \ + avcodec_get_supported_config(NULL, codec, config, 0, \ + (const void **) &elem, &num); \ + if (elem) { \ + printf(" Supported " name ":"); \ + for (int i = 0; i < num; i++) { \ + printf(" " fmt, __VA_ARGS__); \ + elem++; \ + } \ + printf("\n"); \ + } \ + } while (0) + +static const char *get_channel_layout_desc(const AVChannelLayout *layout, AVBPrint *bp) +{ + int ret; + av_bprint_clear(bp); + ret = av_channel_layout_describe_bprint(layout, bp); + if (!av_bprint_is_complete(bp) || ret < 0) + return "unknown/invalid"; + return bp->str; +} static void print_codec(const AVCodec *c) { int encoder = av_codec_is_encoder(c); + AVBPrint desc; printf("%s %s [%s]:\n", encoder ? "Encoder" : "Decoder", c->name, c->long_name ? c->long_name : ""); @@ -343,35 +357,20 @@ static void print_codec(const AVCodec *c) printf("\n"); } - if (c->supported_framerates) { - const AVRational *fps = c->supported_framerates; + PRINT_CODEC_SUPPORTED(c, AV_CODEC_CONFIG_FRAME_RATE, AVRational, "framerates", + fps, "%d/%d", fps->num, fps->den); + PRINT_CODEC_SUPPORTED(c, AV_CODEC_CONFIG_PIX_FORMAT, enum AVPixelFormat, + "pixel formats", fmt, "%s", av_get_pix_fmt_name(*fmt)); + PRINT_CODEC_SUPPORTED(c, AV_CODEC_CONFIG_SAMPLE_RATE, int, "sample rates", + rate, "%d", *rate); + PRINT_CODEC_SUPPORTED(c, AV_CODEC_CONFIG_SAMPLE_FORMAT, enum AVSampleFormat, + "sample formats", fmt, "%s", av_get_sample_fmt_name(*fmt)); - printf(" Supported framerates:"); - while (fps->num) { - printf(" %d/%d", fps->num, fps->den); - fps++; - } - printf("\n"); - } - PRINT_CODEC_SUPPORTED(c, pix_fmts, enum AVPixelFormat, "pixel formats", - AV_PIX_FMT_NONE, GET_PIX_FMT_NAME); - PRINT_CODEC_SUPPORTED(c, supported_samplerates, int, "sample rates", 0, - GET_SAMPLE_RATE_NAME); - PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, "sample formats", - AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME); - - if (c->ch_layouts) { - const AVChannelLayout *p = c->ch_layouts; - - printf(" Supported channel layouts:"); - while (p->nb_channels) { - char name[128]; - av_channel_layout_describe(p, name, sizeof(name)); - printf(" %s", name); - p++; - } - printf("\n"); - } + av_bprint_init(&desc, 0, AV_BPRINT_SIZE_AUTOMATIC); + PRINT_CODEC_SUPPORTED(c, AV_CODEC_CONFIG_CHANNEL_LAYOUT, AVChannelLayout, + "channel layouts", layout, "%s", + get_channel_layout_desc(layout, &desc)); + av_bprint_finalize(&desc, NULL); if (c->priv_class) { show_help_children(c->priv_class, @@ -566,8 +565,15 @@ static void show_help_bsf(const char *name) } printf("Bit stream filter %s\n", bsf->name); - PRINT_CODEC_SUPPORTED(bsf, codec_ids, enum AVCodecID, "codecs", - AV_CODEC_ID_NONE, GET_CODEC_NAME); + if (bsf->codec_ids) { + const enum AVCodecID *id = bsf->codec_ids; + printf(" Supported codecs:"); + while (*id != AV_CODEC_ID_NONE) { + printf(" %s", avcodec_descriptor_get(*id)->name); + id++; + } + printf("\n"); + } if (bsf->priv_class) show_help_children(bsf->priv_class, AV_OPT_FLAG_BSF_PARAM); } diff --git a/libavcodec/012v.c b/libavcodec/012v.c index fa5eb0f95..7bb60219c 100644 --- a/libavcodec/012v.c +++ b/libavcodec/012v.c @@ -64,9 +64,6 @@ static int zero12v_decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->pict_type = AV_PICTURE_TYPE_I; - pic->flags |= AV_FRAME_FLAG_KEY; - line_end = avpkt->data + stride; for (line = 0; line < avctx->height; line++) { uint16_t y_temp[6] = {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000}; diff --git a/libavcodec/4xm.c b/libavcodec/4xm.c index cfe65c178..fd3a45f09 100644 --- a/libavcodec/4xm.c +++ b/libavcodec/4xm.c @@ -30,6 +30,7 @@ #include "libavutil/frame.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" #include "avcodec.h" diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c index 0a6d311cf..43567df3d 100644 --- a/libavcodec/8svx.c +++ b/libavcodec/8svx.c @@ -40,6 +40,7 @@ #include "config_components.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 113adb22d..a4fcce3b4 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -32,7 +32,7 @@ OBJS = ac3_parser.o \ avcodec.o \ avdct.o \ avfft.o \ - avpacket.o \ + packet.o \ bitstream.o \ bitstream_filters.o \ bsf.o \ @@ -46,6 +46,7 @@ OBJS = ac3_parser.o \ get_buffer.o \ imgconvert.o \ jni.o \ + lcevcdec.o \ mathtables.o \ mediacodec.o \ mpeg12framerate.o \ @@ -56,6 +57,7 @@ OBJS = ac3_parser.o \ qsv_api.o \ raw.o \ refstruct.o \ + threadprogress.o \ utils.o \ version.o \ vlc.o \ @@ -63,6 +65,9 @@ OBJS = ac3_parser.o \ xiph.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/$(ARCH)/vvc/Makefile OBJS-$(CONFIG_AANDCTTABLES) += aandcttab.o @@ -84,8 +89,10 @@ 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_D3D12VA_ENCODE) += d3d12va_encode.o hw_base_encode.o OBJS-$(CONFIG_DEFLATE_WRAPPER) += zlib_wrapper.o -OBJS-$(CONFIG_DOVI_RPU) += dovi_rpu.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 @@ -97,15 +104,14 @@ OBJS-$(CONFIG_GOLOMB) += golomb.o OBJS-$(CONFIG_H263DSP) += h263dsp.o OBJS-$(CONFIG_H264CHROMA) += h264chroma.o OBJS-$(CONFIG_H264DSP) += h264dsp.o h264idct.o -OBJS-$(CONFIG_H264PARSE) += h264_parse.o h264_ps.o h2645data.o \ - h2645_parse.o h2645_vui.o +OBJS-$(CONFIG_H264PARSE) += h264_parse.o h264_ps.o h264data.o \ + h2645data.o h2645_parse.o h2645_vui.o OBJS-$(CONFIG_H264PRED) += h264pred.o OBJS-$(CONFIG_H264QPEL) += h264qpel.o OBJS-$(CONFIG_H264_SEI) += h264_sei.o h2645_sei.o -OBJS-$(CONFIG_HEVCPARSE) += hevc_parse.o hevc_ps.o hevc_data.o \ - h2645data.o h2645_parse.o h2645_vui.o -OBJS-$(CONFIG_HEVC_SEI) += hevc_sei.o h2645_sei.o \ - dynamic_hdr_vivid.o aom_film_grain.o +OBJS-$(CONFIG_HEVCPARSE) += h2645data.o h2645_parse.o h2645_vui.o +OBJS-$(CONFIG_HEVC_SEI) += h2645_sei.o aom_film_grain.o \ + dynamic_hdr_vivid.o OBJS-$(CONFIG_HPELDSP) += hpeldsp.o OBJS-$(CONFIG_HUFFMAN) += huffman.o OBJS-$(CONFIG_HUFFYUVDSP) += huffyuvdsp.o @@ -113,7 +119,7 @@ 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 msmpeg4data.o +OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.o msmpeg4_vc1_data.o OBJS-$(CONFIG_IVIDSP) += ivi_dsp.o OBJS-$(CONFIG_JNI) += ffjni.o jni.o OBJS-$(CONFIG_JPEGTABLES) += jpegtables.o @@ -162,7 +168,7 @@ OBJS-$(CONFIG_STARTCODE) += startcode.o OBJS-$(CONFIG_TEXTUREDSP) += texturedsp.o OBJS-$(CONFIG_TEXTUREDSPENC) += texturedspenc.o OBJS-$(CONFIG_TPELDSP) += tpeldsp.o -OBJS-$(CONFIG_VAAPI_ENCODE) += vaapi_encode.o +OBJS-$(CONFIG_VAAPI_ENCODE) += vaapi_encode.o hw_base_encode.o OBJS-$(CONFIG_AV1_AMF_ENCODER) += amfenc_av1.o OBJS-$(CONFIG_VC1DSP) += vc1dsp.o OBJS-$(CONFIG_VIDEODSP) += videodsp.o @@ -177,11 +183,11 @@ OBJS-$(CONFIG_WMV2DSP) += wmv2dsp.o OBJS-$(CONFIG_ZERO12V_DECODER) += 012v.o OBJS-$(CONFIG_A64MULTI_ENCODER) += a64multienc.o elbg.o OBJS-$(CONFIG_A64MULTI5_ENCODER) += a64multienc.o elbg.o -OBJS-$(CONFIG_AAC_DECODER) += aacdec.o aacdec_common.o aactab.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 -OBJS-$(CONFIG_AAC_FIXED_DECODER) += aacdec_fixed.o aacdec_common.o aactab.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 @@ -193,6 +199,7 @@ OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \ aacenc_pred.o \ psymodel.o kbdwin.o \ mpeg4audio_sample_rates.o +OBJS-$(CONFIG_AAC_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_AAC_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_AASC_DECODER) += aasc.o msrledec.o OBJS-$(CONFIG_AC3_DECODER) += ac3dec_float.o ac3dec_data.o ac3.o \ @@ -219,6 +226,8 @@ OBJS-$(CONFIG_AMRWB_DECODER) += amrwbdec.o celp_filters.o \ celp_math.o acelp_filters.o \ acelp_vectors.o \ acelp_pitch_delay.o +OBJS-$(CONFIG_AMRNB_MEDIACODEC_DECODER) += mediacodecdec.o +OBJS-$(CONFIG_AMRWB_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_AMV_ENCODER) += mjpegenc.o mjpegenc_common.o OBJS-$(CONFIG_ANM_DECODER) += anm.o OBJS-$(CONFIG_ANULL_DECODER) += null.o @@ -265,8 +274,6 @@ OBJS-$(CONFIG_AVRP_ENCODER) += r210enc.o OBJS-$(CONFIG_AVS_DECODER) += avs.o OBJS-$(CONFIG_AVUI_DECODER) += avuidec.o OBJS-$(CONFIG_AVUI_ENCODER) += avuienc.o -OBJS-$(CONFIG_AYUV_DECODER) += v408dec.o -OBJS-$(CONFIG_AYUV_ENCODER) += v408enc.o OBJS-$(CONFIG_BETHSOFTVID_DECODER) += bethsoftvideo.o OBJS-$(CONFIG_BFI_DECODER) += bfi.o OBJS-$(CONFIG_BINK_DECODER) += bink.o binkdsp.o @@ -284,7 +291,7 @@ OBJS-$(CONFIG_BRENDER_PIX_DECODER) += brenderpix.o OBJS-$(CONFIG_C93_DECODER) += c93.o OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o \ cavsdata.o -OBJS-$(CONFIG_CBD2_DECODER) += dpcm.o +OBJS-$(CONFIG_CBD2_DPCM_DECODER) += dpcm.o OBJS-$(CONFIG_CCAPTION_DECODER) += ccaption_dec.o ass.o OBJS-$(CONFIG_CDGRAPHICS_DECODER) += cdgraphics.o OBJS-$(CONFIG_CDTOONS_DECODER) += cdtoons.o @@ -419,7 +426,10 @@ 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_VAAPI_ENCODER) += vaapi_encode_h264.o h264_levels.o \ - h2645data.o + h2645data.o hw_base_encode_h264.o +OBJS-$(CONFIG_H264_VULKAN_ENCODER) += vulkan_encode.o vulkan_encode_h264.o \ + hw_base_encode.o hw_base_encode_h264.o \ + h264_levels.o h2645data.o OBJS-$(CONFIG_H264_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o OBJS-$(CONFIG_H264_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_H264_V4L2M2M_ENCODER) += v4l2_m2m_enc.o @@ -429,22 +439,23 @@ 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) += hevcdec.o hevc_mvs.o \ - hevc_cabac.o hevc_refs.o hevcpred.o \ - hevcdsp.o hevc_filter.o hevc_data.o \ - h274.o aom_film_grain.o +OBJS-$(CONFIG_HEVC_DECODER) += aom_film_grain.o h274.o container_fifo.o OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_HEVC_D3D12VA_ENCODER) += d3d12va_encode_hevc.o h265_profile_level.o \ + h2645data.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_QSV_DECODER) += qsvdec.o -OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o \ - hevc_data.o +OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc/ps_enc.o OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o h265_profile_level.o \ - h2645data.o + h2645data.o hw_base_encode_h265.o +OBJS-$(CONFIG_HEVC_VULKAN_ENCODER) += vulkan_encode.o vulkan_encode_h265.o \ + hw_base_encode.o hw_base_encode_h265.o \ + h265_profile_level.o h2645data.o 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 @@ -521,6 +532,7 @@ OBJS-$(CONFIG_MP2FIXED_ENCODER) += mpegaudioenc_fixed.o mpegaudio.o \ mpegaudiotabs.o OBJS-$(CONFIG_MP2FLOAT_DECODER) += mpegaudiodec_float.o OBJS-$(CONFIG_MP3_DECODER) += mpegaudiodec_fixed.o +OBJS-$(CONFIG_MP3_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_MP3_MF_ENCODER) += mfenc.o mf_utils.o OBJS-$(CONFIG_MP3ADU_DECODER) += mpegaudiodec_fixed.o OBJS-$(CONFIG_MP3ADUFLOAT_DECODER) += mpegaudiodec_float.o @@ -576,11 +588,7 @@ OBJS-$(CONFIG_NELLYMOSER_ENCODER) += nellymoserenc.o nellymoser.o OBJS-$(CONFIG_NOTCHLC_DECODER) += notchlc.o OBJS-$(CONFIG_NUV_DECODER) += nuv.o rtjpeg.o jpegquanttables.o OBJS-$(CONFIG_ON2AVC_DECODER) += on2avc.o on2avcdata.o -OBJS-$(CONFIG_OPUS_DECODER) += opusdec.o opusdec_celt.o opus_celt.o \ - opus_pvq.o opus_silk.o opustab.o vorbis_data.o \ - opusdsp.o opus_parse.o opus_rc.o -OBJS-$(CONFIG_OPUS_ENCODER) += opusenc.o opusenc_psy.o opus_celt.o \ - opus_pvq.o opus_rc.o opustab.o +OBJS-$(CONFIG_OPUS_DECODER) += vorbis_data.o OBJS-$(CONFIG_OSQ_DECODER) += osq.o OBJS-$(CONFIG_PAF_AUDIO_DECODER) += pafaudio.o OBJS-$(CONFIG_PAF_VIDEO_DECODER) += pafvideo.o @@ -609,7 +617,7 @@ OBJS-$(CONFIG_PNG_DECODER) += png.o pngdec.o pngdsp.o OBJS-$(CONFIG_PNG_ENCODER) += png.o pngenc.o OBJS-$(CONFIG_PPM_DECODER) += pnmdec.o pnm.o OBJS-$(CONFIG_PPM_ENCODER) += pnmenc.o -OBJS-$(CONFIG_PRORES_DECODER) += proresdec2.o proresdsp.o proresdata.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 @@ -1124,6 +1132,8 @@ OBJS-$(CONFIG_LIBILBC_ENCODER) += libilbc.o OBJS-$(CONFIG_LIBJXL_DECODER) += libjxldec.o libjxl.o OBJS-$(CONFIG_LIBJXL_ENCODER) += libjxlenc.o libjxl.o 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_LIBOPENCORE_AMRNB_DECODER) += libopencore-amr.o OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER) += libopencore-amr.o @@ -1151,6 +1161,7 @@ OBJS-$(CONFIG_LIBVPX_VP8_DECODER) += libvpxdec.o OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o OBJS-$(CONFIG_LIBVPX_VP9_ENCODER) += libvpxenc.o +OBJS-$(CONFIG_LIBVVENC_ENCODER) += libvvenc.o OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.o libwebpenc.o OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_animencoder.o OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o @@ -1197,7 +1208,6 @@ OBJS-$(CONFIG_GSM_PARSER) += gsm_parser.o OBJS-$(CONFIG_H261_PARSER) += h261_parser.o OBJS-$(CONFIG_H263_PARSER) += h263_parser.o OBJS-$(CONFIG_H264_PARSER) += h264_parser.o h264data.o -OBJS-$(CONFIG_HEVC_PARSER) += hevc_parser.o hevc_data.o OBJS-$(CONFIG_HDR_PARSER) += hdr_parser.o OBJS-$(CONFIG_IPU_PARSER) += ipu_parser.o OBJS-$(CONFIG_JPEG2000_PARSER) += jpeg2000_parser.o @@ -1211,8 +1221,7 @@ OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \ OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ mpeg12.o mpeg12data.o -OBJS-$(CONFIG_OPUS_PARSER) += opus_parser.o opus_parse.o \ - vorbis_data.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_QOI_PARSER) += qoi_parser.o @@ -1263,7 +1272,7 @@ SKIPHEADERS += %_tablegen.h \ SKIPHEADERS-$(CONFIG_AMF) += amfenc.h SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h -SKIPHEADERS-$(CONFIG_D3D12VA) += d3d12va_decode.h +SKIPHEADERS-$(CONFIG_D3D12VA) += d3d12va_decode.h d3d12va_encode.h SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h SKIPHEADERS-$(CONFIG_JNI) += ffjni.h SKIPHEADERS-$(CONFIG_LCMS2) += fflcms2.h @@ -1280,7 +1289,7 @@ 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_decode.h +SKIPHEADERS-$(CONFIG_VULKAN) += 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 @@ -1348,7 +1357,7 @@ $(GEN_HEADERS): $(SUBDIR)%_tables.h: $(SUBDIR)%_tablegen$(HOSTEXESUF) ifdef CONFIG_HARDCODED_TABLES $(SUBDIR)cbrt_data.o: $(SUBDIR)cbrt_tables.h $(SUBDIR)cbrt_data_fixed.o: $(SUBDIR)cbrt_fixed_tables.h -$(SUBDIR)aacdec_fixed.o: $(SUBDIR)sinewin_fixed_tables.h +$(SUBDIR)aac/aacdec_fixed.o: $(SUBDIR)sinewin_fixed_tables.h $(SUBDIR)aacps_float.o: $(SUBDIR)aacps_tables.h $(SUBDIR)aacps_fixed.o: $(SUBDIR)aacps_fixed_tables.h $(SUBDIR)dvenc.o: $(SUBDIR)dv_tables.h diff --git a/libavcodec/a64multienc.c b/libavcodec/a64multienc.c index 26a9debc2..38edbe3a7 100644 --- a/libavcodec/a64multienc.c +++ b/libavcodec/a64multienc.c @@ -32,8 +32,8 @@ #include "elbg.h" #include "encode.h" #include "libavutil/avassert.h" -#include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #define DITHERSTEPS 8 #define CHARSET_CHARS 256 diff --git a/libavcodec/aac.h b/libavcodec/aac.h index 89f838eab..78026a588 100644 --- a/libavcodec/aac.h +++ b/libavcodec/aac.h @@ -30,11 +30,8 @@ #ifndef AVCODEC_AAC_H #define AVCODEC_AAC_H - -#include "aac_defines.h" - #define MAX_CHANNELS 64 -#define MAX_ELEM_ID 16 +#define MAX_ELEM_ID 64 #define TNS_MAX_ORDER 20 #define MAX_LTP_LONG_SFB 40 @@ -85,20 +82,6 @@ enum ChannelPosition { AAC_CHANNEL_CC = 5, }; -/** - * Predictor State - */ -typedef struct PredictorState { - AAC_FLOAT cor0; - AAC_FLOAT cor1; - AAC_FLOAT var0; - AAC_FLOAT var1; - AAC_FLOAT r0; - AAC_FLOAT r1; - AAC_FLOAT k1; - AAC_FLOAT x_est; -} PredictorState; - #define MAX_PREDICTORS 672 #define SCALE_DIV_512 36 ///< scalefactor difference that corresponds to scale difference in 512 times @@ -120,4 +103,20 @@ typedef struct Pulse { int amp[4]; } Pulse; +static inline int ff_aac_sample_rate_idx(int rate) +{ + if (92017 <= rate) return 0; + else if (75132 <= rate) return 1; + else if (55426 <= rate) return 2; + else if (46009 <= rate) return 3; + else if (37566 <= rate) return 4; + else if (27713 <= rate) return 5; + else if (23004 <= rate) return 6; + else if (18783 <= rate) return 7; + else if (13856 <= rate) return 8; + else if (11502 <= rate) return 9; + else if (9391 <= rate) return 10; + else return 11; +} + #endif /* AVCODEC_AAC_H */ diff --git a/libavcodec/aac/Makefile b/libavcodec/aac/Makefile new file mode 100644 index 000000000..70b1dca27 --- /dev/null +++ b/libavcodec/aac/Makefile @@ -0,0 +1,8 @@ +clean:: + $(RM) $(CLEANSUFFIXES:%=libavcodec/aac/%) + +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 +OBJS-$(CONFIG_AAC_FIXED_DECODER) += aac/aacdec.o aac/aacdec_tab.o \ + aac/aacdec_fixed.o diff --git a/libavcodec/aacdec_template.c b/libavcodec/aac/aacdec.c similarity index 59% rename from libavcodec/aacdec_template.c rename to libavcodec/aac/aacdec.c index aa856d7fe..39edf73fb 100644 --- a/libavcodec/aacdec_template.c +++ b/libavcodec/aac/aacdec.c @@ -1,5 +1,5 @@ /* - * AAC decoder + * Common parts of the AAC decoders * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) * Copyright (c) 2008-2013 Alex Converse @@ -29,16 +29,39 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file - * AAC decoder - * @author Oded Shimon ( ods15 ods15 dyndns org ) - * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) - * - * AAC decoder fixed-point implementation - * @author Stanislav Ocovaj ( stanislav.ocovaj imgtec com ) - * @author Nedeljko Babic ( nedeljko.babic imgtec com ) - */ +/* We use several quantization functions here (Q31, Q30), + * for which we need this to be defined for them to work as expected. */ +#define USE_FIXED 1 + +#include "config_components.h" + +#include +#include + +#include "aacdec.h" +#include "aacdec_tab.h" +#include "aacdec_usac.h" + +#include "libavcodec/aac.h" +#include "libavcodec/aac_defines.h" +#include "libavcodec/aacsbr.h" +#include "libavcodec/aactab.h" +#include "libavcodec/adts_header.h" + +#include "libavcodec/avcodec.h" +#include "libavcodec/internal.h" +#include "libavcodec/codec_internal.h" +#include "libavcodec/decode.h" +#include "libavcodec/profiles.h" + +#include "libavutil/attributes.h" +#include "libavutil/error.h" +#include "libavutil/log.h" +#include "libavutil/macros.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/tx.h" +#include "libavutil/version.h" /* * supported tools @@ -89,16 +112,6 @@ Parametric Stereo. */ -#include "libavutil/channel_layout.h" -#include "libavutil/thread.h" -#include "decode.h" -#include "internal.h" -#include "lpc_functions.h" - -static int output_configure(AACDecContext *ac, - uint8_t layout_map[MAX_ELEM_ID*4][3], int tags, - enum OCStatus oc_type, int get_new_frame); - #define overread_err "Input buffer exhausted before END element found\n" static int count_channels(uint8_t (*layout)[3], int tags) @@ -133,10 +146,7 @@ static av_cold int che_configure(AACDecContext *ac, return AVERROR_INVALIDDATA; if (che_pos) { if (!ac->che[type][id]) { - int ret; - if (!(ac->che[type][id] = av_mallocz(sizeof(ChannelElement)))) - return AVERROR(ENOMEM); - ret = AAC_RENAME(ff_aac_sbr_ctx_init)(ac, &ac->che[type][id]->sbr, type); + int ret = ac->proc.sbr_ctx_alloc_init(ac, &ac->che[type][id], type); if (ret < 0) return ret; } @@ -152,9 +162,11 @@ static av_cold int che_configure(AACDecContext *ac, } } } else { - if (ac->che[type][id]) - AAC_RENAME(ff_aac_sbr_ctx_close)(&ac->che[type][id]->sbr); + if (ac->che[type][id]) { + ac->proc.sbr_ctx_close(ac->che[type][id]); + } av_freep(&ac->che[type][id]); + memset(ac->output_element, 0, sizeof(ac->output_element)); } return 0; } @@ -169,8 +181,8 @@ static int frame_configure_elements(AVCodecContext *avctx) for (id = 0; id < MAX_ELEM_ID; id++) { ChannelElement *che = ac->che[type][id]; if (che) { - che->ch[0].ret = che->ch[0].ret_buf; - che->ch[1].ret = che->ch[1].ret_buf; + che->ch[0].output = che->ch[0].ret_buf; + che->ch[1].output = che->ch[1].ret_buf; } } } @@ -187,7 +199,7 @@ static int frame_configure_elements(AVCodecContext *avctx) /* map output channel pointers to AVFrame data */ for (ch = 0; ch < avctx->ch_layout.nb_channels; ch++) { if (ac->output_element[ch]) - ac->output_element[ch]->ret = (INTFLOAT *)ac->frame->extended_data[ch]; + ac->output_element[ch]->output = (void *)ac->frame->extended_data[ch]; } return 0; @@ -433,8 +445,8 @@ static void pop_output_configuration(AACDecContext *ac) if (ac->oc[1].status != OC_LOCKED && ac->oc[0].status != OC_NONE) { ac->oc[1] = ac->oc[0]; ac->avctx->ch_layout = ac->oc[1].ch_layout; - output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, - ac->oc[1].status, 0); + ff_aac_output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, + ac->oc[1].status, 0); } } @@ -444,7 +456,7 @@ static void pop_output_configuration(AACDecContext *ac) * * @return Returns error status. 0 - OK, !0 - error */ -static int output_configure(AACDecContext *ac, +int ff_aac_output_configure(AACDecContext *ac, uint8_t layout_map[MAX_ELEM_ID * 4][3], int tags, enum OCStatus oc_type, int get_new_frame) { @@ -510,7 +522,7 @@ static int output_configure(AACDecContext *ac, return 0; } -static void flush(AVCodecContext *avctx) +static av_cold void flush(AVCodecContext *avctx) { AACDecContext *ac= avctx->priv_data; int type, i, j; @@ -525,6 +537,8 @@ static void flush(AVCodecContext *avctx) } } } + + ff_aac_usac_reset_state(ac, &ac->oc[1]); } /** @@ -533,7 +547,7 @@ static void flush(AVCodecContext *avctx) * * @return Returns error status. 0 - OK, !0 - error */ -static int set_default_channel_config(AACDecContext *ac, AVCodecContext *avctx, +int ff_aac_set_default_channel_config(AACDecContext *ac, AVCodecContext *avctx, uint8_t (*layout_map)[3], int *tags, int channel_config) @@ -573,7 +587,7 @@ static int set_default_channel_config(AACDecContext *ac, AVCodecContext *avctx, return 0; } -static ChannelElement *get_che(AACDecContext *ac, int type, int elem_id) +ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id) { /* For PCE based channel configurations map the channels solely based * on tags. */ @@ -589,11 +603,11 @@ static ChannelElement *get_che(AACDecContext *ac, int type, int elem_id) av_log(ac->avctx, AV_LOG_DEBUG, "mono with CPE\n"); - if (set_default_channel_config(ac, ac->avctx, layout_map, - &layout_map_tags, 2) < 0) + if (ff_aac_set_default_channel_config(ac, ac->avctx, layout_map, + &layout_map_tags, 2) < 0) return NULL; - if (output_configure(ac, layout_map, layout_map_tags, - OC_TRIAL_FRAME, 1) < 0) + if (ff_aac_output_configure(ac, layout_map, layout_map_tags, + OC_TRIAL_FRAME, 1) < 0) return NULL; ac->oc[1].m4ac.chan_config = 2; @@ -613,8 +627,8 @@ static ChannelElement *get_che(AACDecContext *ac, int type, int elem_id) layout_map[0][2] = layout_map[1][2] = AAC_CHANNEL_FRONT; layout_map[0][1] = 0; layout_map[1][1] = 1; - if (output_configure(ac, layout_map, layout_map_tags, - OC_TRIAL_FRAME, 1) < 0) + if (ff_aac_output_configure(ac, layout_map, layout_map_tags, + OC_TRIAL_FRAME, 1) < 0) return NULL; if (ac->oc[1].m4ac.sbr) @@ -863,8 +877,8 @@ static int decode_ga_specific_config(AACDecContext *ac, AVCodecContext *avctx, if (tags < 0) return tags; } else { - if ((ret = set_default_channel_config(ac, avctx, layout_map, - &tags, channel_config))) + if ((ret = ff_aac_set_default_channel_config(ac, avctx, layout_map, + &tags, channel_config))) return ret; } @@ -873,7 +887,7 @@ static int decode_ga_specific_config(AACDecContext *ac, AVCodecContext *avctx, } else if (m4ac->sbr == 1 && m4ac->ps == -1) m4ac->ps = 1; - if (ac && (ret = output_configure(ac, layout_map, tags, OC_GLOBAL_HDR, 0))) + if (ac && (ret = ff_aac_output_configure(ac, layout_map, tags, OC_GLOBAL_HDR, 0))) return ret; if (extension_flag) { @@ -953,11 +967,11 @@ static int decode_eld_specific_config(AACDecContext *ac, AVCodecContext *avctx, skip_bits_long(gb, 8 * len); } - if ((ret = set_default_channel_config(ac, avctx, layout_map, - &tags, channel_config))) + if ((ret = ff_aac_set_default_channel_config(ac, avctx, layout_map, + &tags, channel_config))) return ret; - if (ac && (ret = output_configure(ac, layout_map, tags, OC_GLOBAL_HDR, 0))) + if (ac && (ret = ff_aac_output_configure(ac, layout_map, tags, OC_GLOBAL_HDR, 0))) return ret; ep_config = get_bits(gb, 2); @@ -983,13 +997,14 @@ static int decode_eld_specific_config(AACDecContext *ac, AVCodecContext *avctx, */ static int decode_audio_specific_config_gb(AACDecContext *ac, AVCodecContext *avctx, - MPEG4AudioConfig *m4ac, + OutputConfiguration *oc, GetBitContext *gb, int get_bit_alignment, int sync_extension) { int i, ret; GetBitContext gbc = *gb; + MPEG4AudioConfig *m4ac = &oc->m4ac; MPEG4AudioConfig m4ac_bak = *m4ac; if ((i = ff_mpeg4audio_get_config_gb(m4ac, &gbc, sync_extension, avctx)) < 0) { @@ -1023,14 +1038,21 @@ static int decode_audio_specific_config_gb(AACDecContext *ac, case AOT_ER_AAC_LC: case AOT_ER_AAC_LD: if ((ret = decode_ga_specific_config(ac, avctx, gb, get_bit_alignment, - m4ac, m4ac->chan_config)) < 0) + &oc->m4ac, m4ac->chan_config)) < 0) return ret; break; case AOT_ER_AAC_ELD: if ((ret = decode_eld_specific_config(ac, avctx, gb, - m4ac, m4ac->chan_config)) < 0) + &oc->m4ac, m4ac->chan_config)) < 0) return ret; break; +#if CONFIG_AAC_DECODER + case AOT_USAC: + if ((ret = ff_aac_usac_config_decode(ac, avctx, gb, + oc, m4ac->chan_config)) < 0) + return ret; + break; +#endif default: avpriv_report_missing_feature(avctx, "Audio object type %s%d", @@ -1050,7 +1072,7 @@ static int decode_audio_specific_config_gb(AACDecContext *ac, static int decode_audio_specific_config(AACDecContext *ac, AVCodecContext *avctx, - MPEG4AudioConfig *m4ac, + OutputConfiguration *oc, const uint8_t *data, int64_t bit_size, int sync_extension) { @@ -1070,106 +1092,103 @@ static int decode_audio_specific_config(AACDecContext *ac, if ((ret = init_get_bits(&gb, data, bit_size)) < 0) return ret; - return decode_audio_specific_config_gb(ac, avctx, m4ac, &gb, 0, + return decode_audio_specific_config_gb(ac, avctx, oc, &gb, 0, sync_extension); } -/** - * linear congruential pseudorandom number generator - * - * @param previous_val pointer to the current state of the generator - * - * @return Returns a 32-bit pseudorandom integer - */ -static av_always_inline int lcg_random(unsigned previous_val) +static av_cold int decode_close(AVCodecContext *avctx) { - union { unsigned u; int s; } v = { previous_val * 1664525u + 1013904223 }; - return v.s; + AACDecContext *ac = avctx->priv_data; + + 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]; + av_freep(&ec->ext.pl_data); + } + } + + for (int type = 0; type < FF_ARRAY_ELEMS(ac->che); type++) { + for (int i = 0; i < MAX_ELEM_ID; i++) { + if (ac->che[type][i]) { + ac->proc.sbr_ctx_close(ac->che[type][i]); + av_freep(&ac->che[type][i]); + } + } + } + + av_tx_uninit(&ac->mdct96); + av_tx_uninit(&ac->mdct120); + av_tx_uninit(&ac->mdct128); + av_tx_uninit(&ac->mdct480); + av_tx_uninit(&ac->mdct512); + av_tx_uninit(&ac->mdct768); + av_tx_uninit(&ac->mdct960); + av_tx_uninit(&ac->mdct1024); + av_tx_uninit(&ac->mdct_ltp); + + // Compiler will optimize this branch away. + if (ac->is_fixed) + av_freep(&ac->RENAME_FIXED(fdsp)); + else + av_freep(&ac->fdsp); + + return 0; } -static void reset_all_predictors(PredictorState *ps) +static av_cold int init_dsp(AVCodecContext *avctx) { - int i; - for (i = 0; i < MAX_PREDICTORS; i++) - reset_predict_state(&ps[i]); + AACDecContext *ac = avctx->priv_data; + int is_fixed = ac->is_fixed, ret; + float scale_fixed, scale_float; + const float *const scalep = is_fixed ? &scale_fixed : &scale_float; + enum AVTXType tx_type = is_fixed ? AV_TX_INT32_MDCT : AV_TX_FLOAT_MDCT; + +#define MDCT_INIT(s, fn, len, sval) \ + scale_fixed = (sval) * 128.0f; \ + scale_float = (sval) / 32768.0f; \ + ret = av_tx_init(&s, &fn, tx_type, 1, len, scalep, 0); \ + if (ret < 0) \ + return ret + + MDCT_INIT(ac->mdct96, ac->mdct96_fn, 96, 1.0/96); + MDCT_INIT(ac->mdct120, ac->mdct120_fn, 120, 1.0/120); + MDCT_INIT(ac->mdct128, ac->mdct128_fn, 128, 1.0/128); + MDCT_INIT(ac->mdct480, ac->mdct480_fn, 480, 1.0/480); + MDCT_INIT(ac->mdct512, ac->mdct512_fn, 512, 1.0/512); + MDCT_INIT(ac->mdct768, ac->mdct768_fn, 768, 1.0/768); + MDCT_INIT(ac->mdct960, ac->mdct960_fn, 960, 1.0/960); + MDCT_INIT(ac->mdct1024, ac->mdct1024_fn, 1024, 1.0/1024); +#undef MDCT_INIT + + /* LTP forward MDCT */ + scale_fixed = -1.0; + scale_float = -32786.0*2 + 36; + ret = av_tx_init(&ac->mdct_ltp, &ac->mdct_ltp_fn, tx_type, 0, 1024, scalep, 0); + if (ret < 0) + return ret; + + return 0; } -static int sample_rate_idx (int rate) +av_cold int ff_aac_decode_init(AVCodecContext *avctx) { - if (92017 <= rate) return 0; - else if (75132 <= rate) return 1; - else if (55426 <= rate) return 2; - else if (46009 <= rate) return 3; - else if (37566 <= rate) return 4; - else if (27713 <= rate) return 5; - else if (23004 <= rate) return 6; - else if (18783 <= rate) return 7; - else if (13856 <= rate) return 8; - else if (11502 <= rate) return 9; - else if (9391 <= rate) return 10; - else return 11; -} - -static void reset_predictor_group(PredictorState *ps, int group_num) -{ - int i; - for (i = group_num - 1; i < MAX_PREDICTORS; i += 30) - reset_predict_state(&ps[i]); -} - -static void aacdec_init(AACDecContext *ac); - -static av_cold void aac_static_table_init(void) -{ - AAC_RENAME(ff_aac_sbr_init)(); - - ff_aacdec_common_init_once(); - - // window initialization - AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(aac_kbd_long_960), 4.0, 960); - AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(aac_kbd_short_120), 6.0, 120); - -#if !USE_FIXED - AAC_RENAME(ff_sine_window_init)(AAC_RENAME(sine_960), 960); - AAC_RENAME(ff_sine_window_init)(AAC_RENAME(sine_120), 120); - AAC_RENAME(ff_init_ff_sine_windows)(9); - ff_aac_float_common_init(); -#else - AAC_RENAME(ff_kbd_window_init)(AAC_RENAME2(aac_kbd_long_1024), 4.0, 1024); - AAC_RENAME(ff_kbd_window_init)(AAC_RENAME2(aac_kbd_short_128), 6.0, 128); - init_sine_windows_fixed(); -#endif - - AAC_RENAME(ff_cbrt_tableinit)(); -} - -static AVOnce aac_table_init = AV_ONCE_INIT; - -static av_cold int aac_decode_init(AVCodecContext *avctx) -{ - float scale; AACDecContext *ac = avctx->priv_data; int ret; if (avctx->sample_rate > 96000) return AVERROR_INVALIDDATA; - ret = ff_thread_once(&aac_table_init, &aac_static_table_init); - if (ret != 0) - return AVERROR_UNKNOWN; + ff_aacdec_common_init_once(); ac->avctx = avctx; ac->oc[1].m4ac.sample_rate = avctx->sample_rate; - aacdec_init(ac); -#if USE_FIXED - avctx->sample_fmt = AV_SAMPLE_FMT_S32P; -#else - avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; -#endif /* USE_FIXED */ - if (avctx->extradata_size > 0) { - if ((ret = decode_audio_specific_config(ac, ac->avctx, &ac->oc[1].m4ac, + if ((ret = decode_audio_specific_config(ac, ac->avctx, &ac->oc[1], avctx->extradata, avctx->extradata_size * 8LL, 1)) < 0) @@ -1179,7 +1198,7 @@ static av_cold int aac_decode_init(AVCodecContext *avctx) uint8_t layout_map[MAX_ELEM_ID*4][3]; int layout_map_tags; - sr = sample_rate_idx(avctx->sample_rate); + sr = ff_aac_sample_rate_idx(avctx->sample_rate); ac->oc[1].m4ac.sampling_index = sr; ac->oc[1].m4ac.channels = avctx->ch_layout.nb_channels; ac->oc[1].m4ac.sbr = -1; @@ -1194,11 +1213,12 @@ static av_cold int aac_decode_init(AVCodecContext *avctx) ac->oc[1].m4ac.chan_config = i; if (ac->oc[1].m4ac.chan_config) { - int ret = set_default_channel_config(ac, avctx, layout_map, - &layout_map_tags, ac->oc[1].m4ac.chan_config); + int ret = ff_aac_set_default_channel_config(ac, avctx, layout_map, + &layout_map_tags, + ac->oc[1].m4ac.chan_config); if (!ret) - output_configure(ac, layout_map, layout_map_tags, - OC_GLOBAL_HDR, 0); + ff_aac_output_configure(ac, layout_map, layout_map_tags, + OC_GLOBAL_HDR, 0); else if (avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_INVALIDDATA; } @@ -1209,38 +1229,9 @@ static av_cold int aac_decode_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } -#if USE_FIXED - ac->fdsp = avpriv_alloc_fixed_dsp(avctx->flags & AV_CODEC_FLAG_BITEXACT); -#else - ac->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); -#endif /* USE_FIXED */ - if (!ac->fdsp) { - return AVERROR(ENOMEM); - } - ac->random_state = 0x1f2e3d4c; -#define MDCT_INIT(s, fn, len, sval) \ - scale = sval; \ - ret = av_tx_init(&s, &fn, TX_TYPE, 1, len, &scale, 0); \ - if (ret < 0) \ - return ret; - - MDCT_INIT(ac->mdct120, ac->mdct120_fn, 120, TX_SCALE(1.0/120)) - MDCT_INIT(ac->mdct128, ac->mdct128_fn, 128, TX_SCALE(1.0/128)) - MDCT_INIT(ac->mdct480, ac->mdct480_fn, 480, TX_SCALE(1.0/480)) - MDCT_INIT(ac->mdct512, ac->mdct512_fn, 512, TX_SCALE(1.0/512)) - MDCT_INIT(ac->mdct960, ac->mdct960_fn, 960, TX_SCALE(1.0/960)) - MDCT_INIT(ac->mdct1024, ac->mdct1024_fn, 1024, TX_SCALE(1.0/1024)) -#undef MDCT_INIT - - /* LTP forward MDCT */ - scale = USE_FIXED ? -1.0 : -32786.0*2 + 36; - ret = av_tx_init(&ac->mdct_ltp, &ac->mdct_ltp_fn, TX_TYPE, 0, 1024, &scale, 0); - if (ret < 0) - return ret; - - return 0; + return init_dsp(avctx); } /** @@ -1285,13 +1276,17 @@ static int decode_prediction(AACDecContext *ac, IndividualChannelStream *ics, /** * Decode Long Term Prediction data; reference: table 4.xx. */ -static void decode_ltp(LongTermPrediction *ltp, +static void decode_ltp(AACDecContext *ac, LongTermPrediction *ltp, GetBitContext *gb, uint8_t max_sfb) { int sfb; ltp->lag = get_bits(gb, 11); - ltp->coef = AAC_RENAME2(ltp_coef)[get_bits(gb, 3)]; + if (CONFIG_AAC_FIXED_DECODER && ac->is_fixed) + ltp->coef_fixed = Q30(ff_ltp_coef[get_bits(gb, 3)]); + else if (CONFIG_AAC_DECODER) + ltp->coef = ff_ltp_coef[get_bits(gb, 3)]; + for (sfb = 0; sfb < FFMIN(max_sfb, MAX_LTP_LONG_SFB); sfb++) ltp->used[sfb] = get_bits1(gb); } @@ -1326,6 +1321,7 @@ static int decode_ics_info(AACDecContext *ac, IndividualChannelStream *ics, ics->use_kb_window[1] = ics->use_kb_window[0]; ics->use_kb_window[0] = get_bits1(gb); } + ics->prev_num_window_groups = FFMAX(ics->num_window_groups, 1); ics->num_window_groups = 1; ics->group_len[0] = 1; if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { @@ -1398,7 +1394,7 @@ static int decode_ics_info(AACDecContext *ac, IndividualChannelStream *ics, goto fail; } if ((ics->ltp.present = get_bits(gb, 1))) - decode_ltp(&ics->ltp, gb, ics->max_sfb); + decode_ltp(ac, &ics->ltp, gb, ics->max_sfb); } } } @@ -1425,13 +1421,13 @@ fail: * * @return Returns error status. 0 - OK, !0 - error */ -static int decode_band_types(AACDecContext *ac, enum BandType band_type[120], - int band_type_run_end[120], GetBitContext *gb, - IndividualChannelStream *ics) +static int decode_band_types(AACDecContext *ac, SingleChannelElement *sce, + GetBitContext *gb) { - int g, idx = 0; + IndividualChannelStream *ics = &sce->ics; const int bits = (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) ? 3 : 5; - for (g = 0; g < ics->num_window_groups; g++) { + + for (int g = 0; g < ics->num_window_groups; g++) { int k = 0; while (k < ics->max_sfb) { uint8_t sect_end = k; @@ -1455,10 +1451,8 @@ static int decode_band_types(AACDecContext *ac, enum BandType band_type[120], return AVERROR_INVALIDDATA; } } while (sect_len_incr == (1 << bits) - 1); - for (; k < sect_end; k++) { - band_type [idx] = sect_band_type; - band_type_run_end[idx++] = sect_end; - } + for (; k < sect_end; k++) + sce->band_type[g*ics->max_sfb + k] = sect_band_type; } } return 0; @@ -1474,75 +1468,59 @@ static int decode_band_types(AACDecContext *ac, enum BandType band_type[120], * * @return Returns error status. 0 - OK, !0 - error */ -static int decode_scalefactors(AACDecContext *ac, INTFLOAT sf[120], GetBitContext *gb, - unsigned int global_gain, - IndividualChannelStream *ics, - enum BandType band_type[120], - int band_type_run_end[120]) +static int decode_scalefactors(AACDecContext *ac, SingleChannelElement *sce, + GetBitContext *gb, unsigned int global_gain) { - int g, i, idx = 0; + IndividualChannelStream *ics = &sce->ics; int offset[3] = { global_gain, global_gain - NOISE_OFFSET, 0 }; int clipped_offset; int noise_flag = 1; - for (g = 0; g < ics->num_window_groups; g++) { - for (i = 0; i < ics->max_sfb;) { - int run_end = band_type_run_end[idx]; - if (band_type[idx] == ZERO_BT) { - for (; i < run_end; i++, idx++) - sf[idx] = FIXR(0.); - } else if ((band_type[idx] == INTENSITY_BT) || - (band_type[idx] == INTENSITY_BT2)) { - for (; i < run_end; i++, idx++) { - offset[2] += get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - SCALE_DIFF_ZERO; - clipped_offset = av_clip(offset[2], -155, 100); - if (offset[2] != clipped_offset) { - avpriv_request_sample(ac->avctx, - "If you heard an audible artifact, there may be a bug in the decoder. " - "Clipped intensity stereo position (%d -> %d)", - offset[2], clipped_offset); - } -#if USE_FIXED - sf[idx] = 100 - clipped_offset; -#else - sf[idx] = ff_aac_pow2sf_tab[-clipped_offset + POW_SF2_ZERO]; -#endif /* USE_FIXED */ + + for (int g = 0; g < ics->num_window_groups; g++) { + for (int sfb = 0; sfb < ics->max_sfb; sfb++) { + switch (sce->band_type[g*ics->max_sfb + sfb]) { + case ZERO_BT: + sce->sfo[g*ics->max_sfb + sfb] = 0; + break; + case INTENSITY_BT: /* fallthrough */ + case INTENSITY_BT2: + offset[2] += get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - SCALE_DIFF_ZERO; + clipped_offset = av_clip(offset[2], -155, 100); + if (offset[2] != clipped_offset) { + avpriv_request_sample(ac->avctx, + "If you heard an audible artifact, there may be a bug in the decoder. " + "Clipped intensity stereo position (%d -> %d)", + offset[2], clipped_offset); } - } else if (band_type[idx] == NOISE_BT) { - for (; i < run_end; i++, idx++) { - if (noise_flag-- > 0) - offset[1] += get_bits(gb, NOISE_PRE_BITS) - NOISE_PRE; - else - offset[1] += get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - SCALE_DIFF_ZERO; - clipped_offset = av_clip(offset[1], -100, 155); - if (offset[1] != clipped_offset) { - avpriv_request_sample(ac->avctx, - "If you heard an audible artifact, there may be a bug in the decoder. " - "Clipped noise gain (%d -> %d)", - offset[1], clipped_offset); - } -#if USE_FIXED - sf[idx] = -(100 + clipped_offset); -#else - sf[idx] = -ff_aac_pow2sf_tab[clipped_offset + POW_SF2_ZERO]; -#endif /* USE_FIXED */ + sce->sfo[g*ics->max_sfb + sfb] = clipped_offset - 100; + break; + case NOISE_BT: + if (noise_flag-- > 0) + offset[1] += get_bits(gb, NOISE_PRE_BITS) - NOISE_PRE; + else + offset[1] += get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - SCALE_DIFF_ZERO; + clipped_offset = av_clip(offset[1], -100, 155); + if (offset[1] != clipped_offset) { + avpriv_request_sample(ac->avctx, + "If you heard an audible artifact, there may be a bug in the decoder. " + "Clipped noise gain (%d -> %d)", + offset[1], clipped_offset); } - } else { - for (; i < run_end; i++, idx++) { - offset[0] += get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - SCALE_DIFF_ZERO; - if (offset[0] > 255U) { - av_log(ac->avctx, AV_LOG_ERROR, - "Scalefactor (%d) out of range.\n", offset[0]); - return AVERROR_INVALIDDATA; - } -#if USE_FIXED - sf[idx] = -offset[0]; -#else - sf[idx] = -ff_aac_pow2sf_tab[offset[0] - 100 + POW_SF2_ZERO]; -#endif /* USE_FIXED */ + sce->sfo[g*ics->max_sfb + sfb] = clipped_offset; + break; + default: + offset[0] += get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - SCALE_DIFF_ZERO; + if (offset[0] > 255U) { + av_log(ac->avctx, AV_LOG_ERROR, + "Scalefactor (%d) out of range.\n", offset[0]); + return AVERROR_INVALIDDATA; } + sce->sfo[g*ics->max_sfb + sfb] = offset[0] - 100; + break; } } } + return 0; } @@ -1576,12 +1554,18 @@ static int decode_pulses(Pulse *pulse, GetBitContext *gb, * * @return Returns error status. 0 - OK, !0 - error */ -static int decode_tns(AACDecContext *ac, TemporalNoiseShaping *tns, +int ff_aac_decode_tns(AACDecContext *ac, TemporalNoiseShaping *tns, GetBitContext *gb, const IndividualChannelStream *ics) { + int tns_max_order = INT32_MAX; + const int is_usac = ac->oc[1].m4ac.object_type == AOT_USAC; int w, filt, i, coef_len, coef_res, coef_compress; const int is8 = ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE; - const int tns_max_order = is8 ? 7 : ac->oc[1].m4ac.object_type == AOT_AAC_MAIN ? 20 : 12; + + /* USAC doesn't seem to have a limit */ + if (!is_usac) + tns_max_order = is8 ? 7 : ac->oc[1].m4ac.object_type == AOT_AAC_MAIN ? 20 : 12; + for (w = 0; w < ics->num_windows; w++) { if ((tns->n_filt[w] = get_bits(gb, 2 - is8))) { coef_res = get_bits1(gb); @@ -1590,7 +1574,12 @@ static int decode_tns(AACDecContext *ac, TemporalNoiseShaping *tns, int tmp2_idx; tns->length[w][filt] = get_bits(gb, 6 - 2 * is8); - if ((tns->order[w][filt] = get_bits(gb, 5 - 2 * is8)) > tns_max_order) { + if (is_usac) + tns->order[w][filt] = get_bits(gb, 4 - is8); + else + tns->order[w][filt] = get_bits(gb, 5 - (2 * is8)); + + if (tns->order[w][filt] > tns_max_order) { av_log(ac->avctx, AV_LOG_ERROR, "TNS filter order %d is greater than maximum %d.\n", tns->order[w][filt], tns_max_order); @@ -1603,8 +1592,12 @@ static int decode_tns(AACDecContext *ac, TemporalNoiseShaping *tns, coef_len = coef_res + 3 - coef_compress; tmp2_idx = 2 * coef_compress + coef_res; - for (i = 0; i < tns->order[w][filt]; i++) - tns->coef[w][filt][i] = AAC_RENAME2(tns_tmp2_map)[tmp2_idx][get_bits(gb, coef_len)]; + for (i = 0; i < tns->order[w][filt]; i++) { + if (CONFIG_AAC_FIXED_DECODER && ac->is_fixed) + tns->coef_fixed[w][filt][i] = Q31(ff_tns_tmp2_map[tmp2_idx][get_bits(gb, coef_len)]); + else if (CONFIG_AAC_DECODER) + tns->coef[w][filt][i] = ff_tns_tmp2_map[tmp2_idx][get_bits(gb, coef_len)]; + } } } } @@ -1624,6 +1617,7 @@ static void decode_mid_side_stereo(ChannelElement *cpe, GetBitContext *gb, { int idx; int max_idx = cpe->ch[0].ics.num_window_groups * cpe->ch[0].ics.max_sfb; + cpe->max_sfb_ste = cpe->ch[0].ics.max_sfb; if (ms_present == 1) { for (idx = 0; idx < max_idx; idx++) cpe->ms_mask[idx] = get_bits1(gb); @@ -1632,341 +1626,6 @@ static void decode_mid_side_stereo(ChannelElement *cpe, GetBitContext *gb, } } -/** - * Decode spectral data; reference: table 4.50. - * Dequantize and scale spectral data; reference: 4.6.3.3. - * - * @param coef array of dequantized, scaled spectral data - * @param sf array of scalefactors or intensity stereo positions - * @param pulse_present set if pulses are present - * @param pulse pointer to pulse data struct - * @param band_type array of the used band type - * - * @return Returns error status. 0 - OK, !0 - error - */ -static int decode_spectrum_and_dequant(AACDecContext *ac, INTFLOAT coef[1024], - GetBitContext *gb, const INTFLOAT sf[120], - int pulse_present, const Pulse *pulse, - const IndividualChannelStream *ics, - enum BandType band_type[120]) -{ - int i, k, g, idx = 0; - const int c = 1024 / ics->num_windows; - const uint16_t *offsets = ics->swb_offset; - INTFLOAT *coef_base = coef; - - for (g = 0; g < ics->num_windows; g++) - memset(coef + g * 128 + offsets[ics->max_sfb], 0, - sizeof(INTFLOAT) * (c - offsets[ics->max_sfb])); - - for (g = 0; g < ics->num_window_groups; g++) { - unsigned g_len = ics->group_len[g]; - - for (i = 0; i < ics->max_sfb; i++, idx++) { - const unsigned cbt_m1 = band_type[idx] - 1; - INTFLOAT *cfo = coef + offsets[i]; - int off_len = offsets[i + 1] - offsets[i]; - int group; - - if (cbt_m1 >= INTENSITY_BT2 - 1) { - for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { - memset(cfo, 0, off_len * sizeof(*cfo)); - } - } else if (cbt_m1 == NOISE_BT - 1) { - for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { - INTFLOAT band_energy; -#if USE_FIXED - for (k = 0; k < off_len; k++) { - ac->random_state = lcg_random(ac->random_state); - cfo[k] = ac->random_state >> 3; - } - - band_energy = ac->fdsp->scalarproduct_fixed(cfo, cfo, off_len); - band_energy = fixed_sqrt(band_energy, 31); - noise_scale(cfo, sf[idx], band_energy, off_len); -#else - float scale; - - for (k = 0; k < off_len; k++) { - ac->random_state = lcg_random(ac->random_state); - cfo[k] = ac->random_state; - } - - band_energy = ac->fdsp->scalarproduct_float(cfo, cfo, off_len); - scale = sf[idx] / sqrtf(band_energy); - ac->fdsp->vector_fmul_scalar(cfo, cfo, scale, off_len); -#endif /* USE_FIXED */ - } - } else { -#if !USE_FIXED - const float *vq = ff_aac_codebook_vector_vals[cbt_m1]; -#endif /* !USE_FIXED */ - const VLCElem *vlc_tab = ff_vlc_spectral[cbt_m1]; - OPEN_READER(re, gb); - - switch (cbt_m1 >> 1) { - case 0: - for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { - INTFLOAT *cf = cfo; - int len = off_len; - - do { - int code; - unsigned cb_idx; - - UPDATE_CACHE(re, gb); - GET_VLC(code, re, gb, vlc_tab, 8, 2); - cb_idx = code; -#if USE_FIXED - cf = DEC_SQUAD(cf, cb_idx); -#else - cf = VMUL4(cf, vq, cb_idx, sf + idx); -#endif /* USE_FIXED */ - } while (len -= 4); - } - break; - - case 1: - for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { - INTFLOAT *cf = cfo; - int len = off_len; - - do { - int code; - unsigned nnz; - unsigned cb_idx; - uint32_t bits; - - UPDATE_CACHE(re, gb); - GET_VLC(code, re, gb, vlc_tab, 8, 2); - cb_idx = code; - nnz = cb_idx >> 8 & 15; - bits = nnz ? GET_CACHE(re, gb) : 0; - LAST_SKIP_BITS(re, gb, nnz); -#if USE_FIXED - cf = DEC_UQUAD(cf, cb_idx, bits); -#else - cf = VMUL4S(cf, vq, cb_idx, bits, sf + idx); -#endif /* USE_FIXED */ - } while (len -= 4); - } - break; - - case 2: - for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { - INTFLOAT *cf = cfo; - int len = off_len; - - do { - int code; - unsigned cb_idx; - - UPDATE_CACHE(re, gb); - GET_VLC(code, re, gb, vlc_tab, 8, 2); - cb_idx = code; -#if USE_FIXED - cf = DEC_SPAIR(cf, cb_idx); -#else - cf = VMUL2(cf, vq, cb_idx, sf + idx); -#endif /* USE_FIXED */ - } while (len -= 2); - } - break; - - case 3: - case 4: - for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { - INTFLOAT *cf = cfo; - int len = off_len; - - do { - int code; - unsigned nnz; - unsigned cb_idx; - unsigned sign; - - UPDATE_CACHE(re, gb); - GET_VLC(code, re, gb, vlc_tab, 8, 2); - cb_idx = code; - nnz = cb_idx >> 8 & 15; - sign = nnz ? SHOW_UBITS(re, gb, nnz) << (cb_idx >> 12) : 0; - LAST_SKIP_BITS(re, gb, nnz); -#if USE_FIXED - cf = DEC_UPAIR(cf, cb_idx, sign); -#else - cf = VMUL2S(cf, vq, cb_idx, sign, sf + idx); -#endif /* USE_FIXED */ - } while (len -= 2); - } - break; - - default: - for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { -#if USE_FIXED - int *icf = cfo; - int v; -#else - float *cf = cfo; - uint32_t *icf = (uint32_t *) cf; -#endif /* USE_FIXED */ - int len = off_len; - - do { - int code; - unsigned nzt, nnz; - unsigned cb_idx; - uint32_t bits; - int j; - - UPDATE_CACHE(re, gb); - GET_VLC(code, re, gb, vlc_tab, 8, 2); - cb_idx = code; - - if (cb_idx == 0x0000) { - *icf++ = 0; - *icf++ = 0; - continue; - } - - nnz = cb_idx >> 12; - nzt = cb_idx >> 8; - bits = SHOW_UBITS(re, gb, nnz) << (32-nnz); - LAST_SKIP_BITS(re, gb, nnz); - - for (j = 0; j < 2; j++) { - if (nzt & 1< 8) { - av_log(ac->avctx, AV_LOG_ERROR, "error in spectral data, ESC overflow\n"); - return AVERROR_INVALIDDATA; - } - - SKIP_BITS(re, gb, b + 1); - b += 4; - n = (1 << b) + SHOW_UBITS(re, gb, b); - LAST_SKIP_BITS(re, gb, b); -#if USE_FIXED - v = n; - if (bits & 1U<<31) - v = -v; - *icf++ = v; -#else - *icf++ = ff_cbrt_tab[n] | (bits & 1U<<31); -#endif /* USE_FIXED */ - bits <<= 1; - } else { -#if USE_FIXED - v = cb_idx & 15; - if (bits & 1U<<31) - v = -v; - *icf++ = v; -#else - unsigned v = ((const uint32_t*)vq)[cb_idx & 15]; - *icf++ = (bits & 1U<<31) | v; -#endif /* USE_FIXED */ - bits <<= !!v; - } - cb_idx >>= 4; - } - } while (len -= 2); -#if !USE_FIXED - ac->fdsp->vector_fmul_scalar(cfo, cfo, sf[idx], off_len); -#endif /* !USE_FIXED */ - } - } - - CLOSE_READER(re, gb); - } - } - coef += g_len << 7; - } - - if (pulse_present) { - idx = 0; - for (i = 0; i < pulse->num_pulse; i++) { - INTFLOAT co = coef_base[ pulse->pos[i] ]; - while (offsets[idx + 1] <= pulse->pos[i]) - idx++; - if (band_type[idx] != NOISE_BT && sf[idx]) { - INTFLOAT ico = -pulse->amp[i]; -#if USE_FIXED - if (co) { - ico = co + (co > 0 ? -ico : ico); - } - coef_base[ pulse->pos[i] ] = ico; -#else - if (co) { - co /= sf[idx]; - ico = co / sqrtf(sqrtf(fabsf(co))) + (co > 0 ? -ico : ico); - } - coef_base[ pulse->pos[i] ] = cbrtf(fabsf(ico)) * ico * sf[idx]; -#endif /* USE_FIXED */ - } - } - } -#if USE_FIXED - coef = coef_base; - idx = 0; - for (g = 0; g < ics->num_window_groups; g++) { - unsigned g_len = ics->group_len[g]; - - for (i = 0; i < ics->max_sfb; i++, idx++) { - const unsigned cbt_m1 = band_type[idx] - 1; - int *cfo = coef + offsets[i]; - int off_len = offsets[i + 1] - offsets[i]; - int group; - - if (cbt_m1 < NOISE_BT - 1) { - for (group = 0; group < (int)g_len; group++, cfo+=128) { - ac->vector_pow43(cfo, off_len); - ac->subband_scale(cfo, cfo, sf[idx], 34, off_len, ac->avctx); - } - } - } - coef += g_len << 7; - } -#endif /* USE_FIXED */ - return 0; -} - -/** - * Apply AAC-Main style frequency domain prediction. - */ -static void apply_prediction(AACDecContext *ac, SingleChannelElement *sce) -{ - int sfb, k; - - if (!sce->ics.predictor_initialized) { - reset_all_predictors(sce->predictor_state); - sce->ics.predictor_initialized = 1; - } - - if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { - for (sfb = 0; - sfb < ff_aac_pred_sfb_max[ac->oc[1].m4ac.sampling_index]; - 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->ics.predictor_present && - sce->ics.prediction_used[sfb]); - } - } - if (sce->ics.predictor_reset_group) - reset_predictor_group(sce->predictor_state, - sce->ics.predictor_reset_group); - } else - reset_all_predictors(sce->predictor_state); -} - static void decode_gain_control(SingleChannelElement * sce, GetBitContext * gb) { // wd_num, wd_test, aloc_size @@ -2002,13 +1661,12 @@ static void decode_gain_control(SingleChannelElement * sce, GetBitContext * gb) * * @return Returns error status. 0 - OK, !0 - error */ -static int decode_ics(AACDecContext *ac, SingleChannelElement *sce, +int ff_aac_decode_ics(AACDecContext *ac, SingleChannelElement *sce, GetBitContext *gb, int common_window, int scale_flag) { Pulse pulse; TemporalNoiseShaping *tns = &sce->tns; IndividualChannelStream *ics = &sce->ics; - INTFLOAT *out = sce->coeffs; int global_gain, eld_syntax, er_syntax, pulse_present = 0; int ret; @@ -2031,13 +1689,13 @@ static int decode_ics(AACDecContext *ac, SingleChannelElement *sce, goto fail; } - if ((ret = decode_band_types(ac, sce->band_type, - sce->band_type_run_end, gb, ics)) < 0) + if ((ret = decode_band_types(ac, sce, gb)) < 0) goto fail; - if ((ret = decode_scalefactors(ac, sce->sf, gb, global_gain, ics, - sce->band_type, sce->band_type_run_end)) < 0) + if ((ret = decode_scalefactors(ac, sce, gb, global_gain)) < 0) goto fail; + ac->dsp.dequant_scalefactors(sce); + pulse_present = 0; if (!scale_flag) { if (!eld_syntax && (pulse_present = get_bits1(gb))) { @@ -2056,7 +1714,7 @@ static int decode_ics(AACDecContext *ac, SingleChannelElement *sce, } tns->present = get_bits1(gb); if (tns->present && !er_syntax) { - ret = decode_tns(ac, tns, gb, ics); + ret = ff_aac_decode_tns(ac, tns, gb, ics); if (ret < 0) goto fail; } @@ -2070,112 +1728,28 @@ static int 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 if (tns->present && er_syntax) { - ret = decode_tns(ac, tns, gb, ics); + ret = ff_aac_decode_tns(ac, tns, gb, ics); if (ret < 0) goto fail; } } - ret = decode_spectrum_and_dequant(ac, out, gb, sce->sf, pulse_present, - &pulse, ics, sce->band_type); + ret = ac->proc.decode_spectrum_and_dequant(ac, gb, + pulse_present ? &pulse : NULL, + sce); if (ret < 0) goto fail; if (ac->oc[1].m4ac.object_type == AOT_AAC_MAIN && !common_window) - apply_prediction(ac, sce); + ac->dsp.apply_prediction(ac, sce); return 0; fail: + memset(sce->sfo, 0, sizeof(sce->sfo)); tns->present = 0; return ret; } -/** - * Mid/Side stereo decoding; reference: 4.6.8.1.3. - */ -static void apply_mid_side_stereo(AACDecContext *ac, ChannelElement *cpe) -{ - const IndividualChannelStream *ics = &cpe->ch[0].ics; - INTFLOAT *ch0 = cpe->ch[0].coeffs; - INTFLOAT *ch1 = cpe->ch[1].coeffs; - int g, i, group, idx = 0; - const uint16_t *offsets = ics->swb_offset; - for (g = 0; g < ics->num_window_groups; g++) { - for (i = 0; i < ics->max_sfb; i++, idx++) { - if (cpe->ms_mask[idx] && - cpe->ch[0].band_type[idx] < NOISE_BT && - cpe->ch[1].band_type[idx] < NOISE_BT) { -#if USE_FIXED - for (group = 0; group < ics->group_len[g]; group++) { - ac->fdsp->butterflies_fixed(ch0 + group * 128 + offsets[i], - ch1 + group * 128 + offsets[i], - offsets[i+1] - offsets[i]); -#else - for (group = 0; group < ics->group_len[g]; group++) { - ac->fdsp->butterflies_float(ch0 + group * 128 + offsets[i], - ch1 + group * 128 + offsets[i], - offsets[i+1] - offsets[i]); -#endif /* USE_FIXED */ - } - } - } - ch0 += ics->group_len[g] * 128; - ch1 += ics->group_len[g] * 128; - } -} - -/** - * intensity stereo decoding; reference: 4.6.8.2.3 - * - * @param ms_present Indicates mid/side stereo presence. [0] mask is all 0s; - * [1] mask is decoded from bitstream; [2] mask is all 1s; - * [3] reserved for scalable AAC - */ -static void apply_intensity_stereo(AACDecContext *ac, - ChannelElement *cpe, int ms_present) -{ - const IndividualChannelStream *ics = &cpe->ch[1].ics; - SingleChannelElement *sce1 = &cpe->ch[1]; - INTFLOAT *coef0 = cpe->ch[0].coeffs, *coef1 = cpe->ch[1].coeffs; - const uint16_t *offsets = ics->swb_offset; - int g, group, i, idx = 0; - int c; - INTFLOAT scale; - for (g = 0; g < ics->num_window_groups; g++) { - for (i = 0; i < ics->max_sfb;) { - if (sce1->band_type[idx] == INTENSITY_BT || - sce1->band_type[idx] == INTENSITY_BT2) { - const int bt_run_end = sce1->band_type_run_end[idx]; - for (; i < bt_run_end; i++, idx++) { - c = -1 + 2 * (sce1->band_type[idx] - 14); - if (ms_present) - c *= 1 - 2 * cpe->ms_mask[idx]; - scale = c * sce1->sf[idx]; - for (group = 0; group < ics->group_len[g]; group++) -#if USE_FIXED - ac->subband_scale(coef1 + group * 128 + offsets[i], - coef0 + group * 128 + offsets[i], - scale, - 23, - offsets[i + 1] - offsets[i] ,ac->avctx); -#else - ac->fdsp->vector_fmul_scalar(coef1 + group * 128 + offsets[i], - coef0 + group * 128 + offsets[i], - scale, - offsets[i + 1] - offsets[i]); -#endif /* USE_FIXED */ - } - } else { - int bt_run_end = sce1->band_type_run_end[idx]; - idx += bt_run_end - i; - i = bt_run_end; - } - } - coef0 += ics->group_len[g] * 128; - coef1 += ics->group_len[g] * 128; - } -} - /** * Decode a channel_pair_element; reference: table 4.4. * @@ -2196,7 +1770,7 @@ static int decode_cpe(AACDecContext *ac, GetBitContext *gb, ChannelElement *cpe) if (cpe->ch[1].ics.predictor_present && (ac->oc[1].m4ac.object_type != AOT_AAC_MAIN)) if ((cpe->ch[1].ics.ltp.present = get_bits(gb, 1))) - decode_ltp(&cpe->ch[1].ics.ltp, gb, cpe->ch[1].ics.max_sfb); + decode_ltp(ac, &cpe->ch[1].ics.ltp, gb, cpe->ch[1].ics.max_sfb); ms_present = get_bits(gb, 2); if (ms_present == 3) { av_log(ac->avctx, AV_LOG_ERROR, "ms_present = 3 is reserved.\n"); @@ -2204,112 +1778,21 @@ static int decode_cpe(AACDecContext *ac, GetBitContext *gb, ChannelElement *cpe) } else if (ms_present) decode_mid_side_stereo(cpe, gb, ms_present); } - if ((ret = decode_ics(ac, &cpe->ch[0], gb, common_window, 0))) + if ((ret = ff_aac_decode_ics(ac, &cpe->ch[0], gb, common_window, 0))) return ret; - if ((ret = decode_ics(ac, &cpe->ch[1], gb, common_window, 0))) + if ((ret = ff_aac_decode_ics(ac, &cpe->ch[1], gb, common_window, 0))) return ret; if (common_window) { if (ms_present) - apply_mid_side_stereo(ac, cpe); + ac->dsp.apply_mid_side_stereo(ac, cpe); if (ac->oc[1].m4ac.object_type == AOT_AAC_MAIN) { - apply_prediction(ac, &cpe->ch[0]); - apply_prediction(ac, &cpe->ch[1]); + ac->dsp.apply_prediction(ac, &cpe->ch[0]); + ac->dsp.apply_prediction(ac, &cpe->ch[1]); } } - apply_intensity_stereo(ac, cpe, ms_present); - return 0; -} - -static const float cce_scale[] = { - 1.09050773266525765921, //2^(1/8) - 1.18920711500272106672, //2^(1/4) - M_SQRT2, - 2, -}; - -/** - * Decode coupling_channel_element; reference: table 4.8. - * - * @return Returns error status. 0 - OK, !0 - error - */ -static int decode_cce(AACDecContext *ac, GetBitContext *gb, ChannelElement *che) -{ - int num_gain = 0; - int c, g, sfb, ret; - int sign; - INTFLOAT scale; - SingleChannelElement *sce = &che->ch[0]; - ChannelCoupling *coup = &che->coup; - - coup->coupling_point = 2 * get_bits1(gb); - coup->num_coupled = get_bits(gb, 3); - for (c = 0; c <= coup->num_coupled; c++) { - num_gain++; - coup->type[c] = get_bits1(gb) ? TYPE_CPE : TYPE_SCE; - coup->id_select[c] = get_bits(gb, 4); - if (coup->type[c] == TYPE_CPE) { - coup->ch_select[c] = get_bits(gb, 2); - if (coup->ch_select[c] == 3) - num_gain++; - } else - coup->ch_select[c] = 2; - } - coup->coupling_point += get_bits1(gb) || (coup->coupling_point >> 1); - - sign = get_bits(gb, 1); -#if USE_FIXED - scale = get_bits(gb, 2); -#else - scale = cce_scale[get_bits(gb, 2)]; -#endif - - if ((ret = decode_ics(ac, sce, gb, 0, 0))) - return ret; - - for (c = 0; c < num_gain; c++) { - int idx = 0; - int cge = 1; - int gain = 0; - INTFLOAT gain_cache = FIXR10(1.); - if (c) { - cge = coup->coupling_point == AFTER_IMDCT ? 1 : get_bits1(gb); - gain = cge ? get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - 60: 0; - gain_cache = GET_GAIN(scale, gain); -#if USE_FIXED - if ((abs(gain_cache)-1024) >> 3 > 30) - return AVERROR(ERANGE); -#endif - } - if (coup->coupling_point == AFTER_IMDCT) { - coup->gain[c][0] = gain_cache; - } else { - for (g = 0; g < sce->ics.num_window_groups; g++) { - for (sfb = 0; sfb < sce->ics.max_sfb; sfb++, idx++) { - if (sce->band_type[idx] != ZERO_BT) { - if (!cge) { - int t = get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - 60; - if (t) { - int s = 1; - t = gain += t; - if (sign) { - s -= 2 * (t & 0x1); - t >>= 1; - } - gain_cache = GET_GAIN(scale, t) * s; -#if USE_FIXED - if ((abs(gain_cache)-1024) >> 3 > 30) - return AVERROR(ERANGE); -#endif - } - } - coup->gain[c][idx] = gain_cache; - } - } - } - } - } + ac->dsp.apply_intensity_stereo(ac, cpe, ms_present); return 0; } @@ -2454,13 +1937,15 @@ static int decode_extension_payload(AACDecContext *ac, GetBitContext *gb, int cn ac->oc[1].m4ac.sbr = 1; ac->oc[1].m4ac.ps = 1; ac->avctx->profile = AV_PROFILE_AAC_HE_V2; - output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, - ac->oc[1].status, 1); + ff_aac_output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, + ac->oc[1].status, 1); } else { ac->oc[1].m4ac.sbr = 1; ac->avctx->profile = AV_PROFILE_AAC_HE; } - res = AAC_RENAME(ff_decode_sbr_extension)(ac, &che->sbr, gb, crc_flag, cnt, elem_type); + + ac->proc.sbr_decode_extension(ac, che, gb, crc_flag, cnt, elem_type); + if (ac->oc[1].m4ac.ps == 1 && !ac->warned_he_aac_mono) { av_log(ac->avctx, AV_LOG_VERBOSE, "Treating HE-AAC mono as stereo.\n"); ac->warned_he_aac_mono = 1; @@ -2481,381 +1966,6 @@ static int decode_extension_payload(AACDecContext *ac, GetBitContext *gb, int cn return res; } -/** - * Decode Temporal Noise Shaping filter coefficients and apply all-pole filters; reference: 4.6.9.3. - * - * @param decode 1 if tool is used normally, 0 if tool is used in LTP. - * @param coef spectral coefficients - */ -static void apply_tns(INTFLOAT coef_param[1024], TemporalNoiseShaping *tns, - IndividualChannelStream *ics, int decode) -{ - const int mmm = FFMIN(ics->tns_max_bands, ics->max_sfb); - int w, filt, m, i; - int bottom, top, order, start, end, size, inc; - INTFLOAT lpc[TNS_MAX_ORDER]; - INTFLOAT tmp[TNS_MAX_ORDER+1]; - UINTFLOAT *coef = coef_param; - - if(!mmm) - return; - - for (w = 0; w < ics->num_windows; w++) { - bottom = ics->num_swb; - for (filt = 0; filt < tns->n_filt[w]; filt++) { - top = bottom; - bottom = FFMAX(0, top - tns->length[w][filt]); - order = tns->order[w][filt]; - if (order == 0) - continue; - - // tns_decode_coef - compute_lpc_coefs(tns->coef[w][filt], order, lpc, 0, 0, 0); - - start = ics->swb_offset[FFMIN(bottom, mmm)]; - end = ics->swb_offset[FFMIN( top, mmm)]; - if ((size = end - start) <= 0) - continue; - if (tns->direction[w][filt]) { - inc = -1; - start = end - 1; - } else { - inc = 1; - } - start += w * 128; - - if (decode) { - // ar filter - for (m = 0; m < size; m++, start += inc) - for (i = 1; i <= FFMIN(m, order); i++) - coef[start] -= AAC_MUL26((INTFLOAT)coef[start - i * inc], lpc[i - 1]); - } else { - // ma filter - for (m = 0; m < size; m++, start += inc) { - tmp[0] = coef[start]; - for (i = 1; i <= FFMIN(m, order); i++) - coef[start] += AAC_MUL26(tmp[i], lpc[i - 1]); - for (i = order; i > 0; i--) - tmp[i] = tmp[i - 1]; - } - } - } - } -} - -/** - * Apply windowing and MDCT to obtain the spectral - * coefficient from the predicted sample by LTP. - */ -static void windowing_and_mdct_ltp(AACDecContext *ac, INTFLOAT *out, - INTFLOAT *in, IndividualChannelStream *ics) -{ - const INTFLOAT *lwindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024); - const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); - const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024); - const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); - - if (ics->window_sequence[0] != LONG_STOP_SEQUENCE) { - ac->fdsp->vector_fmul(in, in, lwindow_prev, 1024); - } else { - memset(in, 0, 448 * sizeof(*in)); - ac->fdsp->vector_fmul(in + 448, in + 448, swindow_prev, 128); - } - if (ics->window_sequence[0] != LONG_START_SEQUENCE) { - ac->fdsp->vector_fmul_reverse(in + 1024, in + 1024, lwindow, 1024); - } else { - ac->fdsp->vector_fmul_reverse(in + 1024 + 448, in + 1024 + 448, swindow, 128); - memset(in + 1024 + 576, 0, 448 * sizeof(*in)); - } - ac->mdct_ltp_fn(ac->mdct_ltp, out, in, sizeof(INTFLOAT)); -} - -/** - * Apply the long term prediction - */ -static void apply_ltp(AACDecContext *ac, SingleChannelElement *sce) -{ - const LongTermPrediction *ltp = &sce->ics.ltp; - const uint16_t *offsets = sce->ics.swb_offset; - int i, sfb; - - if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { - INTFLOAT *predTime = sce->ret; - INTFLOAT *predFreq = ac->buf_mdct; - int16_t num_samples = 2048; - - if (ltp->lag < 1024) - num_samples = ltp->lag + 1024; - for (i = 0; i < num_samples; i++) - predTime[i] = AAC_MUL30(sce->ltp_state[i + 2048 - ltp->lag], ltp->coef); - memset(&predTime[i], 0, (2048 - i) * sizeof(*predTime)); - - ac->windowing_and_mdct_ltp(ac, predFreq, predTime, &sce->ics); - - if (sce->tns.present) - ac->apply_tns(predFreq, &sce->tns, &sce->ics, 0); - - for (sfb = 0; sfb < FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) - if (ltp->used[sfb]) - for (i = offsets[sfb]; i < offsets[sfb + 1]; i++) - sce->coeffs[i] += (UINTFLOAT)predFreq[i]; - } -} - -/** - * Update the LTP buffer for next frame - */ -static void update_ltp(AACDecContext *ac, SingleChannelElement *sce) -{ - IndividualChannelStream *ics = &sce->ics; - INTFLOAT *saved = sce->saved; - INTFLOAT *saved_ltp = sce->coeffs; - const INTFLOAT *lwindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024); - const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); - int i; - - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - memcpy(saved_ltp, saved, 512 * sizeof(*saved_ltp)); - memset(saved_ltp + 576, 0, 448 * sizeof(*saved_ltp)); - ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64); - - for (i = 0; i < 64; i++) - saved_ltp[i + 512] = AAC_MUL31(ac->buf_mdct[1023 - i], swindow[63 - i]); - } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { - memcpy(saved_ltp, ac->buf_mdct + 512, 448 * sizeof(*saved_ltp)); - memset(saved_ltp + 576, 0, 448 * sizeof(*saved_ltp)); - ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64); - - for (i = 0; i < 64; i++) - saved_ltp[i + 512] = AAC_MUL31(ac->buf_mdct[1023 - i], swindow[63 - i]); - } else { // LONG_STOP or ONLY_LONG - ac->fdsp->vector_fmul_reverse(saved_ltp, ac->buf_mdct + 512, &lwindow[512], 512); - - for (i = 0; i < 512; i++) - saved_ltp[i + 512] = AAC_MUL31(ac->buf_mdct[1023 - i], lwindow[511 - i]); - } - - memcpy(sce->ltp_state, sce->ltp_state+1024, 1024 * sizeof(*sce->ltp_state)); - memcpy(sce->ltp_state+1024, sce->ret, 1024 * sizeof(*sce->ltp_state)); - memcpy(sce->ltp_state+2048, saved_ltp, 1024 * sizeof(*sce->ltp_state)); -} - -/** - * Conduct IMDCT and windowing. - */ -static void imdct_and_windowing(AACDecContext *ac, SingleChannelElement *sce) -{ - IndividualChannelStream *ics = &sce->ics; - INTFLOAT *in = sce->coeffs; - INTFLOAT *out = sce->ret; - INTFLOAT *saved = sce->saved; - const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); - const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024); - const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); - INTFLOAT *buf = ac->buf_mdct; - INTFLOAT *temp = ac->temp; - int i; - - // imdct - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - for (i = 0; i < 1024; i += 128) - ac->mdct128_fn(ac->mdct128, buf + i, in + i, sizeof(INTFLOAT)); - } else { - ac->mdct1024_fn(ac->mdct1024, buf, in, sizeof(INTFLOAT)); - } - - /* window overlapping - * NOTE: To simplify the overlapping code, all 'meaningless' short to long - * and long to short transitions are considered to be short to short - * transitions. This leaves just two cases (long to long and short to short) - * with a little special sauce for EIGHT_SHORT_SEQUENCE. - */ - if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) && - (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) { - ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 512); - } else { - memcpy( out, saved, 448 * sizeof(*out)); - - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - ac->fdsp->vector_fmul_window(out + 448 + 0*128, saved + 448, buf + 0*128, swindow_prev, 64); - ac->fdsp->vector_fmul_window(out + 448 + 1*128, buf + 0*128 + 64, buf + 1*128, swindow, 64); - ac->fdsp->vector_fmul_window(out + 448 + 2*128, buf + 1*128 + 64, buf + 2*128, swindow, 64); - ac->fdsp->vector_fmul_window(out + 448 + 3*128, buf + 2*128 + 64, buf + 3*128, swindow, 64); - ac->fdsp->vector_fmul_window(temp, buf + 3*128 + 64, buf + 4*128, swindow, 64); - memcpy( out + 448 + 4*128, temp, 64 * sizeof(*out)); - } else { - ac->fdsp->vector_fmul_window(out + 448, saved + 448, buf, swindow_prev, 64); - memcpy( out + 576, buf + 64, 448 * sizeof(*out)); - } - } - - // buffer update - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - memcpy( saved, temp + 64, 64 * sizeof(*saved)); - ac->fdsp->vector_fmul_window(saved + 64, buf + 4*128 + 64, buf + 5*128, swindow, 64); - ac->fdsp->vector_fmul_window(saved + 192, buf + 5*128 + 64, buf + 6*128, swindow, 64); - ac->fdsp->vector_fmul_window(saved + 320, buf + 6*128 + 64, buf + 7*128, swindow, 64); - memcpy( saved + 448, buf + 7*128 + 64, 64 * sizeof(*saved)); - } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { - memcpy( saved, buf + 512, 448 * sizeof(*saved)); - memcpy( saved + 448, buf + 7*128 + 64, 64 * sizeof(*saved)); - } else { // LONG_STOP or ONLY_LONG - memcpy( saved, buf + 512, 512 * sizeof(*saved)); - } -} - -/** - * Conduct IMDCT and windowing. - */ -static void imdct_and_windowing_960(AACDecContext *ac, SingleChannelElement *sce) -{ - IndividualChannelStream *ics = &sce->ics; - INTFLOAT *in = sce->coeffs; - INTFLOAT *out = sce->ret; - INTFLOAT *saved = sce->saved; - const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME(aac_kbd_short_120) : AAC_RENAME(sine_120); - const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME(aac_kbd_long_960) : AAC_RENAME(sine_960); - const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME(aac_kbd_short_120) : AAC_RENAME(sine_120); - INTFLOAT *buf = ac->buf_mdct; - INTFLOAT *temp = ac->temp; - int i; - - // imdct - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - for (i = 0; i < 8; i++) - ac->mdct120_fn(ac->mdct120, buf + i * 120, in + i * 128, sizeof(INTFLOAT)); - } else { - ac->mdct960_fn(ac->mdct960, buf, in, sizeof(INTFLOAT)); - } - - /* window overlapping - * NOTE: To simplify the overlapping code, all 'meaningless' short to long - * and long to short transitions are considered to be short to short - * transitions. This leaves just two cases (long to long and short to short) - * with a little special sauce for EIGHT_SHORT_SEQUENCE. - */ - - if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) && - (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) { - ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 480); - } else { - memcpy( out, saved, 420 * sizeof(*out)); - - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - ac->fdsp->vector_fmul_window(out + 420 + 0*120, saved + 420, buf + 0*120, swindow_prev, 60); - ac->fdsp->vector_fmul_window(out + 420 + 1*120, buf + 0*120 + 60, buf + 1*120, swindow, 60); - ac->fdsp->vector_fmul_window(out + 420 + 2*120, buf + 1*120 + 60, buf + 2*120, swindow, 60); - ac->fdsp->vector_fmul_window(out + 420 + 3*120, buf + 2*120 + 60, buf + 3*120, swindow, 60); - ac->fdsp->vector_fmul_window(temp, buf + 3*120 + 60, buf + 4*120, swindow, 60); - memcpy( out + 420 + 4*120, temp, 60 * sizeof(*out)); - } else { - ac->fdsp->vector_fmul_window(out + 420, saved + 420, buf, swindow_prev, 60); - memcpy( out + 540, buf + 60, 420 * sizeof(*out)); - } - } - - // buffer update - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - memcpy( saved, temp + 60, 60 * sizeof(*saved)); - ac->fdsp->vector_fmul_window(saved + 60, buf + 4*120 + 60, buf + 5*120, swindow, 60); - ac->fdsp->vector_fmul_window(saved + 180, buf + 5*120 + 60, buf + 6*120, swindow, 60); - ac->fdsp->vector_fmul_window(saved + 300, buf + 6*120 + 60, buf + 7*120, swindow, 60); - memcpy( saved + 420, buf + 7*120 + 60, 60 * sizeof(*saved)); - } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { - memcpy( saved, buf + 480, 420 * sizeof(*saved)); - memcpy( saved + 420, buf + 7*120 + 60, 60 * sizeof(*saved)); - } else { // LONG_STOP or ONLY_LONG - memcpy( saved, buf + 480, 480 * sizeof(*saved)); - } -} -static void imdct_and_windowing_ld(AACDecContext *ac, SingleChannelElement *sce) -{ - IndividualChannelStream *ics = &sce->ics; - INTFLOAT *in = sce->coeffs; - INTFLOAT *out = sce->ret; - INTFLOAT *saved = sce->saved; - INTFLOAT *buf = ac->buf_mdct; - - // imdct - ac->mdct512_fn(ac->mdct512, buf, in, sizeof(INTFLOAT)); - - // window overlapping - if (ics->use_kb_window[1]) { - // AAC LD uses a low overlap sine window instead of a KBD window - memcpy(out, saved, 192 * sizeof(*out)); - ac->fdsp->vector_fmul_window(out + 192, saved + 192, buf, AAC_RENAME2(sine_128), 64); - memcpy( out + 320, buf + 64, 192 * sizeof(*out)); - } else { - ac->fdsp->vector_fmul_window(out, saved, buf, AAC_RENAME2(sine_512), 256); - } - - // buffer update - memcpy(saved, buf + 256, 256 * sizeof(*saved)); -} - -static void imdct_and_windowing_eld(AACDecContext *ac, SingleChannelElement *sce) -{ - UINTFLOAT *in = sce->coeffs; - INTFLOAT *out = sce->ret; - INTFLOAT *saved = sce->saved; - INTFLOAT *buf = ac->buf_mdct; - int i; - const int n = ac->oc[1].m4ac.frame_length_short ? 480 : 512; - const int n2 = n >> 1; - const int n4 = n >> 2; - const INTFLOAT *const window = n == 480 ? AAC_RENAME(ff_aac_eld_window_480) : - AAC_RENAME(ff_aac_eld_window_512); - - // Inverse transform, mapped to the conventional IMDCT by - // Chivukula, R.K.; Reznik, Y.A.; Devarajan, V., - // "Efficient algorithms for MPEG-4 AAC-ELD, AAC-LD and AAC-LC filterbanks," - // International Conference on Audio, Language and Image Processing, ICALIP 2008. - // URL: http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4590245&isnumber=4589950 - for (i = 0; i < n2; i+=2) { - INTFLOAT temp; - temp = in[i ]; in[i ] = -in[n - 1 - i]; in[n - 1 - i] = temp; - temp = -in[i + 1]; in[i + 1] = in[n - 2 - i]; in[n - 2 - i] = temp; - } - - if (n == 480) - ac->mdct480_fn(ac->mdct480, buf, in, sizeof(INTFLOAT)); - else - ac->mdct512_fn(ac->mdct512, buf, in, sizeof(INTFLOAT)); - - for (i = 0; i < n; i+=2) { - buf[i + 0] = -(UINTFLOAT)(USE_FIXED + 1)*buf[i + 0]; - buf[i + 1] = (UINTFLOAT)(USE_FIXED + 1)*buf[i + 1]; - } - // Like with the regular IMDCT at this point we still have the middle half - // of a transform but with even symmetry on the left and odd symmetry on - // the right - - // window overlapping - // The spec says to use samples [0..511] but the reference decoder uses - // samples [128..639]. - for (i = n4; i < n2; i ++) { - out[i - n4] = AAC_MUL31( buf[ n2 - 1 - i] , window[i - n4]) + - AAC_MUL31( saved[ i + n2] , window[i + n - n4]) + - AAC_MUL31(-saved[n + n2 - 1 - i] , window[i + 2*n - n4]) + - AAC_MUL31(-saved[ 2*n + n2 + i] , window[i + 3*n - n4]); - } - for (i = 0; i < n2; i ++) { - out[n4 + i] = AAC_MUL31( buf[ i] , window[i + n2 - n4]) + - AAC_MUL31(-saved[ n - 1 - i] , window[i + n2 + n - n4]) + - AAC_MUL31(-saved[ n + i] , window[i + n2 + 2*n - n4]) + - AAC_MUL31( saved[2*n + n - 1 - i] , window[i + n2 + 3*n - n4]); - } - for (i = 0; i < n4; i ++) { - out[n2 + n4 + i] = AAC_MUL31( buf[ i + n2] , window[i + n - n4]) + - AAC_MUL31(-saved[n2 - 1 - i] , window[i + 2*n - n4]) + - AAC_MUL31(-saved[n + n2 + i] , window[i + 3*n - n4]); - } - - // buffer update - memmove(saved + n, saved, 2 * n * sizeof(*saved)); - memcpy( saved, buf, n * sizeof(*saved)); -} - /** * channel coupling transformation interface * @@ -2900,64 +2010,57 @@ static void spectral_to_sample(AACDecContext *ac, int samples) void (*imdct_and_window)(AACDecContext *ac, SingleChannelElement *sce); switch (ac->oc[1].m4ac.object_type) { case AOT_ER_AAC_LD: - imdct_and_window = imdct_and_windowing_ld; + imdct_and_window = ac->dsp.imdct_and_windowing_ld; break; case AOT_ER_AAC_ELD: - imdct_and_window = imdct_and_windowing_eld; + imdct_and_window = ac->dsp.imdct_and_windowing_eld; break; default: if (ac->oc[1].m4ac.frame_length_short) - imdct_and_window = imdct_and_windowing_960; + imdct_and_window = ac->dsp.imdct_and_windowing_960; else - imdct_and_window = ac->imdct_and_windowing; + imdct_and_window = ac->dsp.imdct_and_windowing; } for (type = 3; type >= 0; type--) { for (i = 0; i < MAX_ELEM_ID; i++) { ChannelElement *che = ac->che[type][i]; if (che && che->present) { if (type <= TYPE_CPE) - apply_channel_coupling(ac, che, type, i, BEFORE_TNS, AAC_RENAME(apply_dependent_coupling)); + apply_channel_coupling(ac, che, type, i, BEFORE_TNS, ac->dsp.apply_dependent_coupling); if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { if (che->ch[0].ics.predictor_present) { if (che->ch[0].ics.ltp.present) - ac->apply_ltp(ac, &che->ch[0]); + ac->dsp.apply_ltp(ac, &che->ch[0]); if (che->ch[1].ics.ltp.present && type == TYPE_CPE) - ac->apply_ltp(ac, &che->ch[1]); + ac->dsp.apply_ltp(ac, &che->ch[1]); } } if (che->ch[0].tns.present) - ac->apply_tns(che->ch[0].coeffs, &che->ch[0].tns, &che->ch[0].ics, 1); + ac->dsp.apply_tns(che->ch[0].coeffs, + &che->ch[0].tns, &che->ch[0].ics, 1); if (che->ch[1].tns.present) - ac->apply_tns(che->ch[1].coeffs, &che->ch[1].tns, &che->ch[1].ics, 1); + ac->dsp.apply_tns(che->ch[1].coeffs, + &che->ch[1].tns, &che->ch[1].ics, 1); if (type <= TYPE_CPE) - apply_channel_coupling(ac, che, type, i, BETWEEN_TNS_AND_IMDCT, AAC_RENAME(apply_dependent_coupling)); + apply_channel_coupling(ac, che, type, i, BETWEEN_TNS_AND_IMDCT, ac->dsp.apply_dependent_coupling); if (type != TYPE_CCE || che->coup.coupling_point == AFTER_IMDCT) { imdct_and_window(ac, &che->ch[0]); if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) - ac->update_ltp(ac, &che->ch[0]); + ac->dsp.update_ltp(ac, &che->ch[0]); if (type == TYPE_CPE) { imdct_and_window(ac, &che->ch[1]); if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) - ac->update_ltp(ac, &che->ch[1]); + ac->dsp.update_ltp(ac, &che->ch[1]); } if (ac->oc[1].m4ac.sbr > 0) { - AAC_RENAME(ff_sbr_apply)(ac, &che->sbr, type, che->ch[0].ret, che->ch[1].ret); + ac->proc.sbr_apply(ac, che, type, + che->ch[0].output, + che->ch[1].output); } } if (type <= TYPE_CCE) - apply_channel_coupling(ac, che, type, i, AFTER_IMDCT, AAC_RENAME(apply_independent_coupling)); - -#if USE_FIXED - { - int j; - /* preparation for resampler */ - for(j = 0; jch[0].ret[j] = (int32_t)av_clip64((int64_t)che->ch[0].ret[j]*128, INT32_MIN, INT32_MAX-0x8000)+0x8000; - if (type == TYPE_CPE || (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1)) - che->ch[1].ret[j] = (int32_t)av_clip64((int64_t)che->ch[1].ret[j]*128, INT32_MIN, INT32_MAX-0x8000)+0x8000; - } - } -#endif /* USE_FIXED */ + apply_channel_coupling(ac, che, type, i, AFTER_IMDCT, ac->dsp.apply_independent_coupling); + ac->dsp.clip_output(ac, che, type, samples); che->present = 0; } else if (che) { av_log(ac->avctx, AV_LOG_VERBOSE, "ChannelElement %d.%d missing \n", type, i); @@ -2985,13 +2088,13 @@ static int parse_adts_frame_header(AACDecContext *ac, GetBitContext *gb) push_output_configuration(ac); if (hdr_info.chan_config) { ac->oc[1].m4ac.chan_config = hdr_info.chan_config; - if ((ret = set_default_channel_config(ac, ac->avctx, - layout_map, - &layout_map_tags, - hdr_info.chan_config)) < 0) + if ((ret = ff_aac_set_default_channel_config(ac, ac->avctx, + layout_map, + &layout_map_tags, + hdr_info.chan_config)) < 0) return ret; - if ((ret = output_configure(ac, layout_map, layout_map_tags, - FFMAX(ac->oc[1].status, + if ((ret = ff_aac_output_configure(ac, layout_map, layout_map_tags, + FFMAX(ac->oc[1].status, OC_TRIAL_FRAME), 0)) < 0) return ret; } else { @@ -3007,8 +2110,8 @@ static int parse_adts_frame_header(AACDecContext *ac, GetBitContext *gb) layout_map[0][2] = layout_map[1][2] = AAC_CHANNEL_FRONT; layout_map[0][1] = 0; layout_map[1][1] = 1; - if (output_configure(ac, layout_map, layout_map_tags, - OC_TRIAL_FRAME, 0)) + if (ff_aac_output_configure(ac, layout_map, layout_map_tags, + OC_TRIAL_FRAME, 0)) return -7; } } @@ -3061,7 +2164,7 @@ static int aac_decode_er_frame(AVCodecContext *avctx, AVFrame *frame, for (i = 0; i < ff_tags_per_config[chan_config]; i++) { const int elem_type = ff_aac_channel_layout_map[chan_config-1][i][0]; const int elem_id = ff_aac_channel_layout_map[chan_config-1][i][1]; - if (!(che=get_che(ac, elem_type, elem_id))) { + if (!(che=ff_aac_get_che(ac, elem_type, elem_id))) { av_log(ac->avctx, AV_LOG_ERROR, "channel element %d.%d is not allocated\n", elem_type, elem_id); @@ -3072,13 +2175,13 @@ static int aac_decode_er_frame(AVCodecContext *avctx, AVFrame *frame, skip_bits(gb, 4); switch (elem_type) { case TYPE_SCE: - err = decode_ics(ac, &che->ch[0], gb, 0, 0); + err = ff_aac_decode_ics(ac, &che->ch[0], gb, 0, 0); break; case TYPE_CPE: err = decode_cpe(ac, gb, che); break; case TYPE_LFE: - err = decode_ics(ac, &che->ch[0], gb, 0, 0); + err = ff_aac_decode_ics(ac, &che->ch[0], gb, 0, 0); break; } if (err < 0) @@ -3094,48 +2197,26 @@ static int aac_decode_er_frame(AVCodecContext *avctx, AVFrame *frame, ac->frame->nb_samples = samples; ac->frame->sample_rate = avctx->sample_rate; + ac->frame->flags |= AV_FRAME_FLAG_KEY; *got_frame_ptr = 1; skip_bits_long(gb, get_bits_left(gb)); return 0; } -static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, - int *got_frame_ptr, GetBitContext *gb, - const AVPacket *avpkt) +static int decode_frame_ga(AVCodecContext *avctx, AACDecContext *ac, + GetBitContext *gb, int *got_frame_ptr) { - AACDecContext *ac = avctx->priv_data; - ChannelElement *che = NULL, *che_prev = NULL; + int err; + int is_dmono; + int elem_id; enum RawDataBlockType elem_type, che_prev_type = TYPE_END; - int err, elem_id; - int samples = 0, multiplier, audio_found = 0, pce_found = 0; - int is_dmono, sce_count = 0; - int payload_alignment; uint8_t che_presence[4][MAX_ELEM_ID] = {{0}}; + ChannelElement *che = NULL, *che_prev = NULL; + int samples = 0, multiplier, audio_found = 0, pce_found = 0, sce_count = 0; + AVFrame *frame = ac->frame; - ac->frame = frame; - - if (show_bits(gb, 12) == 0xfff) { - if ((err = parse_adts_frame_header(ac, gb)) < 0) { - av_log(avctx, AV_LOG_ERROR, "Error decoding AAC frame header.\n"); - goto fail; - } - if (ac->oc[1].m4ac.sampling_index > 12) { - av_log(ac->avctx, AV_LOG_ERROR, "invalid sampling rate index %d\n", ac->oc[1].m4ac.sampling_index); - err = AVERROR_INVALIDDATA; - goto fail; - } - } - - if ((err = frame_configure_elements(avctx)) < 0) - goto fail; - - // The AV_PROFILE_AAC_* defines are all object_type - 1 - // This may lead to an undefined profile being signaled - ac->avctx->profile = ac->oc[1].m4ac.object_type - 1; - - payload_alignment = get_bits_count(gb); - ac->tags_mapped = 0; + int payload_alignment = get_bits_count(gb); // parse while ((elem_type = get_bits(gb, 3)) != TYPE_END) { elem_id = get_bits(gb, 4); @@ -3143,28 +2224,23 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, if (avctx->debug & FF_DEBUG_STARTCODE) av_log(avctx, AV_LOG_DEBUG, "Elem type:%x id:%x\n", elem_type, elem_id); - if (!avctx->ch_layout.nb_channels && elem_type != TYPE_PCE) { - err = AVERROR_INVALIDDATA; - goto fail; - } + if (!avctx->ch_layout.nb_channels && elem_type != TYPE_PCE) + return AVERROR_INVALIDDATA; if (elem_type < TYPE_DSE) { if (che_presence[elem_type][elem_id]) { int error = che_presence[elem_type][elem_id] > 1; av_log(ac->avctx, error ? AV_LOG_ERROR : AV_LOG_DEBUG, "channel element %d.%d duplicate\n", elem_type, elem_id); - if (error) { - err = AVERROR_INVALIDDATA; - goto fail; - } + if (error) + return AVERROR_INVALIDDATA; } che_presence[elem_type][elem_id]++; - if (!(che=get_che(ac, elem_type, elem_id))) { + if (!(che=ff_aac_get_che(ac, elem_type, elem_id))) { av_log(ac->avctx, AV_LOG_ERROR, "channel element %d.%d is not allocated\n", elem_type, elem_id); - err = AVERROR_INVALIDDATA; - goto fail; + return AVERROR_INVALIDDATA; } samples = ac->oc[1].m4ac.frame_length_short ? 960 : 1024; che->present = 1; @@ -3173,7 +2249,7 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, switch (elem_type) { case TYPE_SCE: - err = decode_ics(ac, &che->ch[0], gb, 0, 0); + err = ff_aac_decode_ics(ac, &che->ch[0], gb, 0, 0); audio_found = 1; sce_count++; break; @@ -3184,11 +2260,11 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, break; case TYPE_CCE: - err = decode_cce(ac, gb, che); + err = ac->proc.decode_cce(ac, gb, che); break; case TYPE_LFE: - err = decode_ics(ac, &che->ch[0], gb, 0, 0); + err = ff_aac_decode_ics(ac, &che->ch[0], gb, 0, 0); audio_found = 1; break; @@ -3201,10 +2277,8 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, int tags; int pushed = push_output_configuration(ac); - if (pce_found && !pushed) { - err = AVERROR_INVALIDDATA; - goto fail; - } + if (pce_found && !pushed) + return AVERROR_INVALIDDATA; tags = decode_pce(avctx, &ac->oc[1].m4ac, layout_map, gb, payload_alignment); @@ -3217,7 +2291,7 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, "Not evaluating a further program_config_element as this construct is dubious at best.\n"); pop_output_configuration(ac); } else { - err = output_configure(ac, layout_map, tags, OC_TRIAL_PCE, 1); + err = ff_aac_output_configure(ac, layout_map, tags, OC_TRIAL_PCE, 1); if (!err) ac->oc[1].m4ac.chan_config = 0; pce_found = 1; @@ -3230,8 +2304,7 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, elem_id += get_bits(gb, 8) - 1; if (get_bits_left(gb) < 8 * elem_id) { av_log(avctx, AV_LOG_ERROR, "TYPE_FIL: "overread_err); - err = AVERROR_INVALIDDATA; - goto fail; + return AVERROR_INVALIDDATA; } err = 0; while (elem_id > 0) { @@ -3255,19 +2328,16 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, } if (err) - goto fail; + return err; if (get_bits_left(gb) < 3) { av_log(avctx, AV_LOG_ERROR, overread_err); - err = AVERROR_INVALIDDATA; - goto fail; + return AVERROR_INVALIDDATA; } } - if (!avctx->ch_layout.nb_channels) { - *got_frame_ptr = 0; + if (!avctx->ch_layout.nb_channels) return 0; - } multiplier = (ac->oc[1].m4ac.sbr == 1) ? ac->oc[1].m4ac.ext_sample_rate > ac->oc[1].m4ac.sample_rate : 0; samples <<= multiplier; @@ -3282,16 +2352,18 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, if (!ac->frame->data[0] && samples) { av_log(avctx, AV_LOG_ERROR, "no frame data found\n"); - err = AVERROR_INVALIDDATA; - goto fail; + return AVERROR_INVALIDDATA; } if (samples) { ac->frame->nb_samples = samples; ac->frame->sample_rate = avctx->sample_rate; - } else + ac->frame->flags |= AV_FRAME_FLAG_KEY; + *got_frame_ptr = 1; + } else { av_frame_unref(ac->frame); - *got_frame_ptr = !!samples; + *got_frame_ptr = 0; + } /* for dual-mono audio (SCE + SCE) */ is_dmono = ac->dmono_mode && sce_count == 2 && @@ -3305,6 +2377,58 @@ static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, } return 0; +} + +static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, GetBitContext *gb, + const AVPacket *avpkt) +{ + int err; + AACDecContext *ac = avctx->priv_data; + + ac->frame = frame; + *got_frame_ptr = 0; + + if (show_bits(gb, 12) == 0xfff) { + if ((err = parse_adts_frame_header(ac, gb)) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error decoding AAC frame header.\n"); + goto fail; + } + if (ac->oc[1].m4ac.sampling_index > 12) { + av_log(ac->avctx, AV_LOG_ERROR, "invalid sampling rate index %d\n", ac->oc[1].m4ac.sampling_index); + err = AVERROR_INVALIDDATA; + goto fail; + } + } + + if ((err = frame_configure_elements(avctx)) < 0) + goto fail; + + // The AV_PROFILE_AAC_* defines are all object_type - 1 + // This may lead to an undefined profile being signaled + ac->avctx->profile = ac->oc[1].m4ac.object_type - 1; + + ac->tags_mapped = 0; + + if (ac->oc[1].m4ac.object_type == AOT_USAC) { + if (ac->is_fixed) { + avpriv_report_missing_feature(ac->avctx, + "AAC USAC fixed-point decoding"); + return AVERROR_PATCHWELCOME; + } +#if CONFIG_AAC_DECODER + err = ff_aac_usac_decode_frame(avctx, ac, gb, got_frame_ptr); + if (err < 0) + goto fail; +#endif + } else { + err = decode_frame_ga(avctx, ac, gb, got_frame_ptr); + if (err < 0) + goto fail; + } + + return err; + fail: pop_output_configuration(ac); return err; @@ -3332,7 +2456,7 @@ static int aac_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (new_extradata) { /* discard previous configuration */ ac->oc[1].status = OC_NONE; - err = decode_audio_specific_config(ac, ac->avctx, &ac->oc[1].m4ac, + err = decode_audio_specific_config(ac, ac->avctx, &ac->oc[1], new_extradata, new_extradata_size * 8LL, 1); if (err < 0) { @@ -3373,55 +2497,16 @@ static int aac_decode_frame(AVCodecContext *avctx, AVFrame *frame, return buf_size > buf_offset ? buf_consumed : buf_size; } -static av_cold int aac_decode_close(AVCodecContext *avctx) -{ - AACDecContext *ac = avctx->priv_data; - int i, type; - - for (i = 0; i < MAX_ELEM_ID; i++) { - for (type = 0; type < 4; type++) { - if (ac->che[type][i]) - AAC_RENAME(ff_aac_sbr_ctx_close)(&ac->che[type][i]->sbr); - av_freep(&ac->che[type][i]); - } - } - - av_tx_uninit(&ac->mdct120); - av_tx_uninit(&ac->mdct128); - av_tx_uninit(&ac->mdct480); - av_tx_uninit(&ac->mdct512); - av_tx_uninit(&ac->mdct960); - av_tx_uninit(&ac->mdct1024); - av_tx_uninit(&ac->mdct_ltp); - - av_freep(&ac->fdsp); - return 0; -} - -static void aacdec_init(AACDecContext *c) -{ - c->imdct_and_windowing = imdct_and_windowing; - c->apply_ltp = apply_ltp; - c->apply_tns = apply_tns; - c->windowing_and_mdct_ltp = windowing_and_mdct_ltp; - c->update_ltp = update_ltp; -#if USE_FIXED - c->vector_pow43 = vector_pow43; - c->subband_scale = subband_scale; +#if CONFIG_AAC_LATM_DECODER +#include "aacdec_latm.h" #endif -#if !USE_FIXED -#if ARCH_MIPS - ff_aacdec_init_mips(c); -#endif -#endif /* !USE_FIXED */ -} -/** - * AVOptions for Japanese DTV specific extensions (ADTS only) - */ #define AACDEC_FLAGS AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM #define OFF(field) offsetof(AACDecContext, field) static const AVOption options[] = { + /** + * AVOptions for Japanese DTV specific extensions (ADTS only) + */ {"dual_mono_mode", "Select the channel to decode for dual mono", OFF(force_dmono_mode), AV_OPT_TYPE_INT, {.i64=-1}, -1, 2, AACDEC_FLAGS, .unit = "dual_mono_mode"}, @@ -3442,9 +2527,53 @@ static const AVOption options[] = { {NULL}, }; -static const AVClass aac_decoder_class = { +static const AVClass decoder_class = { .class_name = "AAC decoder", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, }; + +#if CONFIG_AAC_DECODER +const FFCodec ff_aac_decoder = { + .p.name = "aac", + CODEC_LONG_NAME("AAC (Advanced Audio Coding)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_AAC, + .p.priv_class = &decoder_class, + .priv_data_size = sizeof(AACDecContext), + .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 + }, + .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, + .flush = flush, + .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), +}; +#endif + +#if CONFIG_AAC_FIXED_DECODER +const FFCodec ff_aac_fixed_decoder = { + .p.name = "aac_fixed", + CODEC_LONG_NAME("AAC (Advanced Audio Coding)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_AAC, + .p.priv_class = &decoder_class, + .priv_data_size = sizeof(AACDecContext), + .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 + }, + .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, + .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), + .flush = flush, +}; +#endif diff --git a/libavcodec/aac/aacdec.h b/libavcodec/aac/aacdec.h new file mode 100644 index 000000000..e5a79a713 --- /dev/null +++ b/libavcodec/aac/aacdec.h @@ -0,0 +1,562 @@ +/* + * AAC decoder definitions and structures + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC decoder definitions and structures + * @author Oded Shimon ( ods15 ods15 dyndns org ) + * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) + */ + +#ifndef AVCODEC_AAC_AACDEC_H +#define AVCODEC_AAC_AACDEC_H + +#include + +#include "libavutil/channel_layout.h" +#include "libavutil/float_dsp.h" +#include "libavutil/fixed_dsp.h" +#include "libavutil/mem_internal.h" +#include "libavutil/tx.h" + +#include "libavcodec/aac.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/mpeg4audio.h" + +#include "aacdec_ac.h" + +typedef struct AACDecContext AACDecContext; + +/** + * Output configuration status + */ +enum OCStatus { + OC_NONE, ///< Output unconfigured + OC_TRIAL_PCE, ///< Output configuration under trial specified by an inband PCE + OC_TRIAL_FRAME, ///< Output configuration under trial specified by a frame header + OC_GLOBAL_HDR, ///< Output configuration set in a global header but not yet locked + OC_LOCKED, ///< Output configuration locked in place +}; + +enum AACOutputChannelOrder { + CHANNEL_ORDER_DEFAULT, + CHANNEL_ORDER_CODED, +}; + +/** + * The point during decoding at which channel coupling is applied. + */ +enum CouplingPoint { + BEFORE_TNS, + BETWEEN_TNS_AND_IMDCT, + AFTER_IMDCT = 3, +}; + +enum AACUsacElem { + ID_USAC_SCE = 0, + ID_USAC_CPE = 1, + ID_USAC_LFE = 2, + ID_USAC_EXT = 3, +}; + +enum ExtensionHeaderType { + ID_CONFIG_EXT_FILL = 0, + ID_CONFIG_EXT_LOUDNESS_INFO = 2, + ID_CONFIG_EXT_STREAM_ID = 7, +}; + +enum AACUsacExtension { + ID_EXT_ELE_FILL, + ID_EXT_ELE_MPEGS, + ID_EXT_ELE_SAOC, + ID_EXT_ELE_AUDIOPREROLL, + ID_EXT_ELE_UNI_DRC, +}; + +enum AACUSACLoudnessExt { + UNIDRCLOUDEXT_TERM = 0x0, + UNIDRCLOUDEXT_EQ = 0x1, +}; + +// Supposed to be equal to AAC_RENAME() in case of USE_FIXED. +#define RENAME_FIXED(name) name ## _fixed + +#define INTFLOAT_UNION(name, elems) \ + union { \ + int RENAME_FIXED(name) elems; \ + float name elems; \ + } + +#define INTFLOAT_ALIGNED_UNION(alignment, name, nb_elems) \ + union { \ + DECLARE_ALIGNED(alignment, int, RENAME_FIXED(name))[nb_elems]; \ + DECLARE_ALIGNED(alignment, float, name)[nb_elems]; \ + } +/** + * Long Term Prediction + */ +typedef struct LongTermPrediction { + int8_t present; + int16_t lag; + INTFLOAT_UNION(coef,); + int8_t used[MAX_LTP_LONG_SFB]; +} LongTermPrediction; + +/* Per channel core mode */ +typedef struct AACUsacElemData { + uint8_t core_mode; + uint8_t scale_factor_grouping; + uint8_t tns_data_present; + + /* Timewarping ratio */ +#define NUM_TW_NODES 16 + uint8_t tw_ratio[NUM_TW_NODES]; + + struct { + uint8_t acelp_core_mode : 3; + uint8_t lpd_mode : 5; + + uint8_t bpf_control_info : 1; + uint8_t core_mode_last : 1; + uint8_t fac_data_present : 1; + + int last_lpd_mode; + } ldp; + + struct { + unsigned int seed; + uint8_t level : 3; + uint8_t offset : 5; + } noise; + + struct { + uint8_t gain; + uint32_t kv[8 /* (1024 / 16) / 8 */][8]; + } fac; + + AACArithState ac; +} AACUsacElemData; + +/** + * Individual Channel Stream + */ +typedef struct IndividualChannelStream { + uint8_t max_sfb; ///< number of scalefactor bands per group + enum WindowSequence window_sequence[2]; + uint8_t use_kb_window[2]; ///< If set, use Kaiser-Bessel window, otherwise use a sine window. + int num_window_groups; + int prev_num_window_groups; ///< Previous frame's number of window groups + 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 + 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; + uint8_t prediction_used[41]; + uint8_t window_clipping[8]; ///< set if a certain window is near clipping +} IndividualChannelStream; + +/** + * Temporal Noise Shaping + */ +typedef struct TemporalNoiseShaping { + int present; + int n_filt[8]; + int length[8][4]; + int direction[8][4]; + int order[8][4]; + INTFLOAT_UNION(coef, [8][4][TNS_MAX_ORDER]); +} TemporalNoiseShaping; + +/** + * coupling parameters + */ +typedef struct ChannelCoupling { + enum CouplingPoint coupling_point; ///< The point during decoding at which coupling is applied. + int num_coupled; ///< number of target elements + enum RawDataBlockType type[8]; ///< Type of channel element to be coupled - SCE or CPE. + int id_select[8]; ///< element id + int ch_select[8]; /**< [0] shared list of gains; [1] list of gains for right channel; + * [2] list of gains for left channel; [3] lists of gains for both channels + */ + INTFLOAT_UNION(gain, [16][120]); +} ChannelCoupling; + +/** + * Single Channel Element - used for both SCE and LFE elements. + */ +typedef struct SingleChannelElement { + IndividualChannelStream ics; + AACUsacElemData ue; ///< USAC element data + TemporalNoiseShaping tns; + enum BandType band_type[128]; ///< band types + int sfo[128]; ///< scalefactor offsets + INTFLOAT_UNION(sf, [128]); ///< scalefactors (8 windows * 16 sfb max) + INTFLOAT_ALIGNED_UNION(32, coeffs, 1024); ///< coefficients for IMDCT, maybe processed + INTFLOAT_ALIGNED_UNION(32, prev_coeffs, 1024); ///< unscaled previous contents of coeffs[] for USAC + INTFLOAT_ALIGNED_UNION(32, saved, 1536); ///< overlap + INTFLOAT_ALIGNED_UNION(32, ret_buf, 2048); ///< PCM output buffer + INTFLOAT_ALIGNED_UNION(16, ltp_state, 3072); ///< time signal for LTP + union { + struct PredictorStateFixed *RENAME_FIXED(predictor_state); + struct PredictorState *predictor_state; + }; + union { + float *output; ///< PCM output + int *RENAME_FIXED(output); ///< PCM output + }; +} SingleChannelElement; + +typedef struct AACUsacStereo { + uint8_t common_window; + uint8_t common_tw; + uint8_t tns_on_lr; ///< Apply TNS before M/S and stereo prediction + + uint8_t ms_mask_mode; + uint8_t config_idx; + + /* Complex prediction */ + uint8_t use_prev_frame; + uint8_t pred_dir; + uint8_t complex_coef; + + uint8_t pred_used[128]; + + 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); + INTFLOAT_ALIGNED_UNION(32, prev_alpha_q_im, 1024); + + INTFLOAT_ALIGNED_UNION(32, dmix_re, 1024); + INTFLOAT_ALIGNED_UNION(32, prev_dmix_re, 1024); /* Recalculated on every frame */ + INTFLOAT_ALIGNED_UNION(32, dmix_im, 1024); /* Final prediction data */ +} AACUsacStereo; + +/** + * channel element - generic struct for SCE/CPE/CCE/LFE + */ +typedef struct ChannelElement { + int present; + // CPE specific + uint8_t max_sfb_ste; ///< (USAC) Maximum of both max_sfb values + uint8_t ms_mask[128]; ///< Set if mid/side stereo is used for each scalefactor window band + // shared + SingleChannelElement ch[2]; + // CCE specific + ChannelCoupling coup; + // USAC stereo coupling data + AACUsacStereo us; +} ChannelElement; + +typedef struct AACUSACLoudnessInfo { + uint8_t drc_set_id : 6; + uint8_t downmix_id : 7; + struct { + uint16_t lvl : 12; + uint8_t present : 1; + } sample_peak; + + struct { + uint16_t lvl : 12; + uint8_t measurement : 4; + uint8_t reliability : 2; + uint8_t present : 1; + } true_peak; + + uint8_t nb_measurements : 4; + struct { + uint8_t method_def : 4; + uint8_t method_val; + uint8_t measurement : 4; + uint8_t reliability : 2; + } measurements[16]; +} AACUSACLoudnessInfo; + +typedef struct AACUsacElemConfig { + enum AACUsacElem type; + + uint8_t tw_mdct : 1; + uint8_t noise_fill : 1; + + uint8_t stereo_config_index; + + struct { + int ratio; + + uint8_t harmonic_sbr : 1; /* harmonicSBR */ + uint8_t bs_intertes : 1; /* bs_interTes */ + uint8_t bs_pvc : 1; /* bs_pvc */ + + struct { + uint8_t start_freq; /* dflt_start_freq */ + uint8_t stop_freq; /* dflt_stop_freq */ + + uint8_t freq_scale; /* dflt_freq_scale */ + uint8_t alter_scale : 1; /* dflt_alter_scale */ + uint8_t noise_bands; /* dflt_noise_bands */ + + uint8_t limiter_bands; /* dflt_limiter_bands */ + uint8_t limiter_gains; /* dflt_limiter_gains */ + uint8_t interpol_freq : 1; /* dflt_interpol_freq */ + uint8_t smoothing_mode : 1; /* dflt_smoothing_mode */ + } dflt; + } sbr; + + struct { + uint8_t freq_res; /* bsFreqRes */ + uint8_t fixed_gain; /* bsFixedGainDMX */ + uint8_t temp_shape_config; /* bsTempShapeConfig */ + uint8_t decorr_config; /* bsDecorrConfig */ + uint8_t high_rate_mode : 1; /* bsHighRateMode */ + uint8_t phase_coding : 1; /* bsPhaseCoding */ + + uint8_t otts_bands_phase; /* bsOttBandsPhase */ + uint8_t residual_coding; /* bsResidualCoding */ + uint8_t residual_bands; /* bsResidualBands */ + uint8_t pseudo_lr : 1; /* bsPseudoLr */ + uint8_t env_quant_mode : 1; /* bsEnvQuantMode */ + } mps; + + struct { + enum AACUsacExtension type; + uint8_t payload_frag; + uint32_t default_len; + uint32_t pl_data_offset; + uint8_t *pl_data; + } ext; +} AACUsacElemConfig; + +typedef struct AACUSACConfig { + uint8_t core_sbr_frame_len_idx; /* coreSbrFrameLengthIndex */ + uint16_t core_frame_len; + uint16_t stream_identifier; + + AACUsacElemConfig elems[64]; + int nb_elems; + + struct { + uint8_t nb_album; + AACUSACLoudnessInfo album_info[64]; + uint8_t nb_info; + AACUSACLoudnessInfo info[64]; + } loudness; +} AACUSACConfig; + +typedef struct OutputConfiguration { + MPEG4AudioConfig m4ac; + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int layout_map_tags; + AVChannelLayout ch_layout; + enum OCStatus status; + AACUSACConfig usac; +} OutputConfiguration; + +/** + * Dynamic Range Control - decoded from the bitstream but not processed further. + */ +typedef struct DynamicRangeControl { + int pce_instance_tag; ///< Indicates with which program the DRC info is associated. + int dyn_rng_sgn[17]; ///< DRC sign information; 0 - positive, 1 - negative + int dyn_rng_ctl[17]; ///< DRC magnitude information + int exclude_mask[MAX_CHANNELS]; ///< Channels to be excluded from DRC processing. + int band_incr; ///< Number of DRC bands greater than 1 having DRC info. + int interpolation_scheme; ///< Indicates the interpolation scheme used in the SBR QMF domain. + int band_top[17]; ///< Indicates the top of the i-th DRC band in units of 4 spectral lines. + int prog_ref_level; /**< A reference level for the long-term program audio level for all + * channels combined. + */ +} DynamicRangeControl; + +/** + * Decode-specific primitives + */ +typedef struct AACDecProc { + int (*decode_spectrum_and_dequant)(AACDecContext *ac, + GetBitContext *gb, + const Pulse *pulse, + SingleChannelElement *sce); + + int (*decode_cce)(AACDecContext *ac, GetBitContext *gb, ChannelElement *che); + + int (*sbr_ctx_alloc_init)(AACDecContext *ac, ChannelElement **che, int id_aac); + int (*sbr_decode_extension)(AACDecContext *ac, ChannelElement *che, + GetBitContext *gb, int crc, int cnt, int id_aac); + void (*sbr_apply)(AACDecContext *ac, ChannelElement *che, + int id_aac, void /* INTFLOAT */ *L, void /* INTFLOAT */ *R); + void (*sbr_ctx_close)(ChannelElement *che); +} AACDecProc; + +/** + * DSP-specific primitives + */ +typedef struct AACDecDSP { + void (*dequant_scalefactors)(SingleChannelElement *sce); + + void (*apply_mid_side_stereo)(AACDecContext *ac, ChannelElement *cpe); + void (*apply_intensity_stereo)(AACDecContext *ac, ChannelElement *cpe, + int ms_present); + + void (*apply_tns)(void *_coef_param, TemporalNoiseShaping *tns, + IndividualChannelStream *ics, int decode); + + void (*apply_ltp)(AACDecContext *ac, SingleChannelElement *sce); + void (*update_ltp)(AACDecContext *ac, SingleChannelElement *sce); + + void (*apply_prediction)(AACDecContext *ac, SingleChannelElement *sce); + + void (*apply_dependent_coupling)(AACDecContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index); + void (*apply_independent_coupling)(AACDecContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index); + + void (*imdct_and_windowing)(AACDecContext *ac, SingleChannelElement *sce); + void (*imdct_and_windowing_768)(AACDecContext *ac, SingleChannelElement *sce); + void (*imdct_and_windowing_960)(AACDecContext *ac, SingleChannelElement *sce); + void (*imdct_and_windowing_ld)(AACDecContext *ac, SingleChannelElement *sce); + void (*imdct_and_windowing_eld)(AACDecContext *ac, SingleChannelElement *sce); + + void (*clip_output)(AACDecContext *ac, ChannelElement *che, int type, int samples); +} AACDecDSP; + +/** + * main AAC decoding context + */ +struct AACDecContext { + const struct AVClass *class; + struct AVCodecContext *avctx; + + AACDecDSP dsp; + AACDecProc proc; + + struct AVFrame *frame; + + int is_saved; ///< Set if elements have stored overlap from previous frame. + DynamicRangeControl che_drc; + + /** + * @name Channel element related data + * @{ + */ + ChannelElement *che[4][MAX_ELEM_ID]; + ChannelElement *tag_che_map[4][MAX_ELEM_ID]; + int tags_mapped; + int warned_remapping_once; + /** @} */ + + /** + * @name temporary aligned temporary buffers + * (We do not want to have these on the stack.) + * @{ + */ + INTFLOAT_ALIGNED_UNION(32, buf_mdct, 1024); + INTFLOAT_ALIGNED_UNION(32, temp, 128); + /** @} */ + + /** + * @name Computed / set up during initialization + * @{ + */ + AVTXContext *mdct96; + AVTXContext *mdct120; + AVTXContext *mdct128; + AVTXContext *mdct480; + AVTXContext *mdct512; + AVTXContext *mdct768; + AVTXContext *mdct960; + AVTXContext *mdct1024; + AVTXContext *mdct_ltp; + + av_tx_fn mdct96_fn; + av_tx_fn mdct120_fn; + av_tx_fn mdct128_fn; + av_tx_fn mdct480_fn; + av_tx_fn mdct512_fn; + av_tx_fn mdct768_fn; + av_tx_fn mdct960_fn; + av_tx_fn mdct1024_fn; + av_tx_fn mdct_ltp_fn; + union { + AVFixedDSPContext *RENAME_FIXED(fdsp); + AVFloatDSPContext *fdsp; + }; + int random_state; + /** @} */ + + /** + * @name Members used for output + * @{ + */ + SingleChannelElement *output_element[MAX_CHANNELS]; ///< Points to each SingleChannelElement + /** @} */ + + + /** + * @name Japanese DTV specific extension + * @{ + */ + int force_dmono_mode;///< 0->not dmono, 1->use first channel, 2->use second channel + int dmono_mode; ///< 0->not dmono, 1->use first channel, 2->use second channel + /** @} */ + + enum AACOutputChannelOrder output_channel_order; + + OutputConfiguration oc[2]; + int warned_num_aac_frames; + int warned_960_sbr; + unsigned warned_71_wide; + int warned_gain_control; + int warned_he_aac_mono; + + int is_fixed; +}; + +#if defined(USE_FIXED) && USE_FIXED +#define fdsp RENAME_FIXED(fdsp) +#endif + +int ff_aac_decode_init(AVCodecContext *avctx); +int ff_aac_decode_init_float(AVCodecContext *avctx); +int ff_aac_decode_init_fixed(AVCodecContext *avctx); + +int ff_aac_decode_ics(AACDecContext *ac, SingleChannelElement *sce, + GetBitContext *gb, int common_window, int scale_flag); + +int ff_aac_decode_tns(AACDecContext *ac, TemporalNoiseShaping *tns, + GetBitContext *gb, const IndividualChannelStream *ics); + +int ff_aac_set_default_channel_config(AACDecContext *ac, AVCodecContext *avctx, + uint8_t (*layout_map)[3], + int *tags, + int channel_config); + +int ff_aac_output_configure(AACDecContext *ac, + uint8_t layout_map[MAX_ELEM_ID * 4][3], int tags, + enum OCStatus oc_type, int get_new_frame); + +ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id); + +#endif /* AVCODEC_AAC_AACDEC_H */ diff --git a/libavcodec/aac/aacdec_ac.c b/libavcodec/aac/aacdec_ac.c new file mode 100644 index 000000000..7e5077cd1 --- /dev/null +++ b/libavcodec/aac/aacdec_ac.c @@ -0,0 +1,208 @@ +/* + * AAC definitions and structures + * 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 "libavcodec/aactab.h" +#include "aacdec_ac.h" + +uint32_t ff_aac_ac_map_process(AACArithState *state, int reset, int N) +{ + float ratio; + if (reset) { + memset(state->last, 0, sizeof(state->last)); + state->last_len = N; + } else if (state->last_len != N) { + int i; + uint8_t last[512 /* 2048 / 4 */]; + memcpy(last, state->last, sizeof(last)); + + ratio = state->last_len / (float)N; + for (i = 0; i < N/2; i++) { + int k = (int)(i * ratio); + state->last[i] = last[k]; + } + + for (; i < FF_ARRAY_ELEMS(state->last); i++) + state->last[i] = 0; + + state->last_len = N; + } + + state->cur[3] = 0; + state->cur[2] = 0; + state->cur[1] = 0; + state->cur[0] = 1; + + state->state_pre = state->last[0] << 12; + return state->last[0] << 12; +} + +uint32_t ff_aac_ac_get_context(AACArithState *state, uint32_t c, int i, int N) +{ + c = state->state_pre >> 8; + c = c + (state->last[i + 1] << 8); + c = (c << 4); + c += state->cur[1]; + + state->state_pre = c; + + if (i > 3 && + ((state->cur[3] + state->cur[2] + state->cur[1]) < 5)) + return c + 0x10000; + + return c; +} + +uint32_t ff_aac_ac_get_pk(uint32_t c) +{ + int i_min = -1; + int i, j; + int i_max = FF_ARRAY_ELEMS(ff_aac_ac_lookup_m) - 1; + while ((i_max - i_min) > 1) { + i = i_min + ((i_max - i_min) / 2); + j = ff_aac_ac_hash_m[i]; + if (c < (j >> 8)) + i_max = i; + else if (c > (j >> 8)) + i_min = i; + else + return (j & 0xFF); + } + return ff_aac_ac_lookup_m[i_max]; +} + +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[3] = state->cur[2]; + state->cur[2] = state->cur[1]; + state->cur[1] = state->cur[0]; + + state->last[idx] = state->cur[0]; +} + +/* Initialize AC */ +void ff_aac_ac_init(AACArith *ac, GetBitContext *gb) +{ + ac->low = 0; + ac->high = UINT16_MAX; + ac->val = get_bits(gb, 16); +} + +uint16_t ff_aac_ac_decode(AACArith *ac, GetBitContext *gb, + const uint16_t *cdf, uint16_t cdf_len) +{ + int val = ac->val; + int low = ac->low; + int high = ac->high; + + int sym; + int rng = high - low + 1; + int c = ((((int)(val - low + 1)) << 14) - ((int)1)); + + const uint16_t *p = cdf - 1; + + /* One for each possible CDF length in the spec */ + switch (cdf_len) { + case 2: + if ((p[1] * rng) > c) + p += 1; + break; + case 4: + if ((p[2] * rng) > c) + p += 2; + if ((p[1] * rng) > c) + p += 1; + break; + case 17: + /* First check if the current probability is even met at all */ + if ((p[1] * rng) <= c) + break; + p += 1; + for (int i = 8; i >= 1; i >>= 1) + if ((p[i] * rng) > c) + p += i; + break; + case 27: + if ((p[16] * rng) > c) + p += 16; + if ((p[8] * rng) > c) + p += 8; + if (p != (cdf - 1 + 24)) + if ((p[4] * rng) > c) + p += 4; + if ((p[2] * rng) > c) + p += 2; + + if (p != (cdf - 1 + 24 + 2)) + if ((p[1] * rng) > c) + p += 1; + break; + default: + /* This should never happen */ + av_assert2(0); + } + + sym = (int)((ptrdiff_t)(p - cdf)) + 1; + if (sym) + high = low + ((rng * cdf[sym - 1]) >> 14) - 1; + low += (rng * cdf[sym]) >> 14; + + /* This loop could be done faster */ + while (1) { + if (high < 32768) { + ; + } else if (low >= 32768) { + val -= 32768; + low -= 32768; + high -= 32768; + } else if (low >= 16384 && high < 49152) { + val -= 16384; + low -= 16384; + high -= 16384; + } else { + break; + } + low += low; + high += high + 1; + val = (val << 1) | get_bits1(gb); + }; + + ac->low = low; + ac->high = high; + ac->val = val; + + return sym; +} + +void ff_aac_ac_finish(AACArithState *state, int offset, int N) +{ + int i; + + for (i = offset; i < N/2; i++) + state->last[i] = 1; + + for (; i < FF_ARRAY_ELEMS(state->last); i++) + state->last[i] = 0; +} diff --git a/libavcodec/aac/aacdec_ac.h b/libavcodec/aac/aacdec_ac.h new file mode 100644 index 000000000..b8d4ade4c --- /dev/null +++ b/libavcodec/aac/aacdec_ac.h @@ -0,0 +1,54 @@ +/* + * AAC definitions and structures + * 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_AAC_AACDEC_AC_H +#define AVCODEC_AAC_AACDEC_AC_H + +#include "libavcodec/get_bits.h" + +typedef struct AACArithState { + uint8_t last[512 /* 2048 / 4 */ + 1]; + int last_len; + uint8_t cur[4]; + uint16_t state_pre; +} AACArithState; + +typedef struct AACArith { + uint16_t low; + uint16_t high; + uint16_t val; +} AACArith; + +#define FF_AAC_AC_ESCAPE 16 + +uint32_t ff_aac_ac_map_process(AACArithState *state, int reset, int len); +uint32_t ff_aac_ac_get_context(AACArithState *state, uint32_t old_c, int idx, int len); +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); +void ff_aac_ac_init(AACArith *ac, GetBitContext *gb); + +uint16_t ff_aac_ac_decode(AACArith *ac, GetBitContext *gb, + const uint16_t *cdf, uint16_t cdf_len); + +void ff_aac_ac_finish(AACArithState *state, int offset, int nb); + +#endif /* AVCODEC_AACDEC_AC_H */ diff --git a/libavcodec/aac/aacdec_dsp_template.c b/libavcodec/aac/aacdec_dsp_template.c new file mode 100644 index 000000000..8d31af22f --- /dev/null +++ b/libavcodec/aac/aacdec_dsp_template.c @@ -0,0 +1,688 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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.h" +#include "libavcodec/lpc_functions.h" + +#include "libavcodec/aactab.h" + +/** + * Convert integer scalefactors to the decoder's native expected + * scalefactor values. + */ +static void AAC_RENAME(dequant_scalefactors)(SingleChannelElement *sce) +{ + IndividualChannelStream *ics = &sce->ics; + const int *sfo = sce->sfo; + INTFLOAT *sf = sce->AAC_RENAME(sf); + + int idx = 0; + for (int g = 0; g < ics->num_window_groups; g++) { + for (int sfb = 0; sfb < ics->max_sfb; sfb++, idx++) { + switch (sce->band_type[g*ics->max_sfb + sfb]) { + case ZERO_BT: + sf[idx] = FIXR(0.); + break; + case INTENSITY_BT: /* fallthrough */ + case INTENSITY_BT2: +#if USE_FIXED + sf[idx] = 100 - (sfo[idx] + 100); +#else + sf[idx] = ff_aac_pow2sf_tab[-sfo[idx] - 100 + POW_SF2_ZERO]; +#endif /* USE_FIXED */ + break; + case NOISE_BT: +#if USE_FIXED + sf[idx] = -(100 + sfo[idx]); +#else + sf[idx] = -ff_aac_pow2sf_tab[sfo[idx] + POW_SF2_ZERO]; +#endif /* USE_FIXED */ + break; + default: +#if USE_FIXED + sf[idx] = -sfo[idx] - 100; +#else + sf[idx] = -ff_aac_pow2sf_tab[sfo[idx] + POW_SF2_ZERO]; +#endif /* USE_FIXED */ + break; + } + } + } +} + +/** + * Mid/Side stereo decoding; reference: 4.6.8.1.3. + */ +static void AAC_RENAME(apply_mid_side_stereo)(AACDecContext *ac, ChannelElement *cpe) +{ + const IndividualChannelStream *ics = &cpe->ch[0].ics; + INTFLOAT *ch0 = cpe->ch[0].AAC_RENAME(coeffs); + INTFLOAT *ch1 = cpe->ch[1].AAC_RENAME(coeffs); + const uint16_t *offsets = ics->swb_offset; + for (int g = 0; g < ics->num_window_groups; g++) { + for (int sfb = 0; sfb < cpe->max_sfb_ste; sfb++) { + const int idx = g*cpe->max_sfb_ste + sfb; + if (cpe->ms_mask[idx] && + cpe->ch[0].band_type[idx] < NOISE_BT && + cpe->ch[1].band_type[idx] < NOISE_BT) { + for (int group = 0; group < ics->group_len[g]; group++) +#if USE_FIXED + ac->fdsp->butterflies_fixed(ch0 + group * 128 + offsets[sfb], + ch1 + group * 128 + offsets[sfb], + offsets[sfb+1] - offsets[sfb]); +#else + ac->fdsp->butterflies_float(ch0 + group * 128 + offsets[sfb], + ch1 + group * 128 + offsets[sfb], + offsets[sfb+1] - offsets[sfb]); +#endif /* USE_FIXED */ + } + } + ch0 += ics->group_len[g] * 128; + ch1 += ics->group_len[g] * 128; + } +} + +/** + * intensity stereo decoding; reference: 4.6.8.2.3 + * + * @param ms_present Indicates mid/side stereo presence. [0] mask is all 0s; + * [1] mask is decoded from bitstream; [2] mask is all 1s; + * [3] reserved for scalable AAC + */ +static void AAC_RENAME(apply_intensity_stereo)(AACDecContext *ac, + ChannelElement *cpe, int ms_present) +{ + const IndividualChannelStream *ics = &cpe->ch[1].ics; + SingleChannelElement *sce1 = &cpe->ch[1]; + INTFLOAT *coef0 = cpe->ch[0].AAC_RENAME(coeffs), *coef1 = cpe->ch[1].AAC_RENAME(coeffs); + const uint16_t *offsets = ics->swb_offset; + int c; + INTFLOAT scale; + for (int g = 0; g < ics->num_window_groups; g++) { + for (int sfb = 0; sfb < ics->max_sfb; sfb++) { + const int idx = g*ics->max_sfb + sfb; + if (sce1->band_type[idx] == INTENSITY_BT || + sce1->band_type[idx] == INTENSITY_BT2) { + c = -1 + 2 * (sce1->band_type[idx] - 14); + if (ms_present) + c *= 1 - 2 * cpe->ms_mask[idx]; + scale = c * sce1->AAC_RENAME(sf)[idx]; + for (int group = 0; group < ics->group_len[g]; group++) +#if USE_FIXED + subband_scale(coef1 + group * 128 + offsets[sfb], + coef0 + group * 128 + offsets[sfb], + scale, + 23, + offsets[sfb + 1] - offsets[sfb], ac->avctx); +#else + ac->fdsp->vector_fmul_scalar(coef1 + group * 128 + offsets[sfb], + coef0 + group * 128 + offsets[sfb], + scale, + offsets[sfb + 1] - offsets[sfb]); +#endif /* USE_FIXED */ + } + } + coef0 += ics->group_len[g] * 128; + coef1 += ics->group_len[g] * 128; + } +} + +/** + * Decode Temporal Noise Shaping filter coefficients and apply all-pole filters; reference: 4.6.9.3. + * + * @param decode 1 if tool is used normally, 0 if tool is used in LTP. + * @param coef spectral coefficients + */ +static void AAC_RENAME(apply_tns)(void *_coef_param, TemporalNoiseShaping *tns, + IndividualChannelStream *ics, int decode) +{ + const int mmm = FFMIN(ics->tns_max_bands, ics->max_sfb); + int w, filt, m, i; + int bottom, top, order, start, end, size, inc; + INTFLOAT *coef_param = _coef_param; + INTFLOAT lpc[TNS_MAX_ORDER]; + INTFLOAT tmp[TNS_MAX_ORDER+1]; + UINTFLOAT *coef = coef_param; + + if(!mmm) + return; + + for (w = 0; w < ics->num_windows; w++) { + bottom = ics->num_swb; + for (filt = 0; filt < tns->n_filt[w]; filt++) { + top = bottom; + bottom = FFMAX(0, top - tns->length[w][filt]); + order = tns->order[w][filt]; + if (order == 0) + continue; + + // tns_decode_coef + compute_lpc_coefs(tns->AAC_RENAME(coef)[w][filt], order, lpc, 0, 0, 0); + + start = ics->swb_offset[FFMIN(bottom, mmm)]; + end = ics->swb_offset[FFMIN( top, mmm)]; + if ((size = end - start) <= 0) + continue; + if (tns->direction[w][filt]) { + inc = -1; + start = end - 1; + } else { + inc = 1; + } + start += w * 128; + + if (decode) { + // ar filter + for (m = 0; m < size; m++, start += inc) + for (i = 1; i <= FFMIN(m, order); i++) + coef[start] -= AAC_MUL26((INTFLOAT)coef[start - i * inc], lpc[i - 1]); + } else { + // ma filter + for (m = 0; m < size; m++, start += inc) { + tmp[0] = coef[start]; + for (i = 1; i <= FFMIN(m, order); i++) + coef[start] += AAC_MUL26(tmp[i], lpc[i - 1]); + for (i = order; i > 0; i--) + tmp[i] = tmp[i - 1]; + } + } + } + } +} + +/** + * Apply windowing and MDCT to obtain the spectral + * coefficient from the predicted sample by LTP. + */ +static inline void AAC_RENAME(windowing_and_mdct_ltp)(AACDecContext *ac, + INTFLOAT *out, INTFLOAT *in, + IndividualChannelStream *ics) +{ + const INTFLOAT *lwindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024); + const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); + const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024); + const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); + + if (ics->window_sequence[0] != LONG_STOP_SEQUENCE) { + ac->fdsp->vector_fmul(in, in, lwindow_prev, 1024); + } else { + memset(in, 0, 448 * sizeof(*in)); + ac->fdsp->vector_fmul(in + 448, in + 448, swindow_prev, 128); + } + if (ics->window_sequence[0] != LONG_START_SEQUENCE) { + ac->fdsp->vector_fmul_reverse(in + 1024, in + 1024, lwindow, 1024); + } else { + ac->fdsp->vector_fmul_reverse(in + 1024 + 448, in + 1024 + 448, swindow, 128); + memset(in + 1024 + 576, 0, 448 * sizeof(*in)); + } + ac->mdct_ltp_fn(ac->mdct_ltp, out, in, sizeof(INTFLOAT)); +} + +/** + * Apply the long term prediction + */ +static void AAC_RENAME(apply_ltp)(AACDecContext *ac, SingleChannelElement *sce) +{ + const LongTermPrediction *ltp = &sce->ics.ltp; + const uint16_t *offsets = sce->ics.swb_offset; + int i, sfb; + + if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { + INTFLOAT *predTime = sce->AAC_RENAME(output); + INTFLOAT *predFreq = ac->AAC_RENAME(buf_mdct); + int16_t num_samples = 2048; + + if (ltp->lag < 1024) + num_samples = ltp->lag + 1024; + for (i = 0; i < num_samples; i++) + predTime[i] = AAC_MUL30(sce->AAC_RENAME(ltp_state)[i + 2048 - ltp->lag], ltp->AAC_RENAME(coef)); + memset(&predTime[i], 0, (2048 - i) * sizeof(*predTime)); + + AAC_RENAME(windowing_and_mdct_ltp)(ac, predFreq, predTime, &sce->ics); + + if (sce->tns.present) + AAC_RENAME(apply_tns)(predFreq, &sce->tns, &sce->ics, 0); + + for (sfb = 0; sfb < FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) + if (ltp->used[sfb]) + for (i = offsets[sfb]; i < offsets[sfb + 1]; i++) + sce->AAC_RENAME(coeffs)[i] += (UINTFLOAT)predFreq[i]; + } +} + +/** + * Update the LTP buffer for next frame + */ +static void AAC_RENAME(update_ltp)(AACDecContext *ac, SingleChannelElement *sce) +{ + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *saved = sce->AAC_RENAME(saved); + INTFLOAT *saved_ltp = sce->AAC_RENAME(coeffs); + const INTFLOAT *lwindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024); + const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); + int i; + + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + memcpy(saved_ltp, saved, 512 * sizeof(*saved_ltp)); + memset(saved_ltp + 576, 0, 448 * sizeof(*saved_ltp)); + ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->AAC_RENAME(buf_mdct) + 960, &swindow[64], 64); + + for (i = 0; i < 64; i++) + saved_ltp[i + 512] = AAC_MUL31(ac->AAC_RENAME(buf_mdct)[1023 - i], swindow[63 - i]); + } else if (1 && ics->window_sequence[0] == LONG_START_SEQUENCE) { + memcpy(saved_ltp, ac->AAC_RENAME(buf_mdct) + 512, 448 * sizeof(*saved_ltp)); + memset(saved_ltp + 576, 0, 448 * sizeof(*saved_ltp)); + ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->AAC_RENAME(buf_mdct) + 960, &swindow[64], 64); + + for (i = 0; i < 64; i++) + saved_ltp[i + 512] = AAC_MUL31(ac->AAC_RENAME(buf_mdct)[1023 - i], swindow[63 - i]); + } else if (1) { // LONG_STOP or ONLY_LONG + ac->fdsp->vector_fmul_reverse(saved_ltp, ac->AAC_RENAME(buf_mdct) + 512, &lwindow[512], 512); + + for (i = 0; i < 512; i++) + saved_ltp[i + 512] = AAC_MUL31(ac->AAC_RENAME(buf_mdct)[1023 - i], lwindow[511 - i]); + } + + memcpy(sce->AAC_RENAME(ltp_state), sce->AAC_RENAME(ltp_state)+1024, + 1024 * sizeof(*sce->AAC_RENAME(ltp_state))); + memcpy(sce->AAC_RENAME(ltp_state) + 1024, sce->AAC_RENAME(output), + 1024 * sizeof(*sce->AAC_RENAME(ltp_state))); + memcpy(sce->AAC_RENAME(ltp_state) + 2048, saved_ltp, + 1024 * sizeof(*sce->AAC_RENAME(ltp_state))); +} + +/** + * Conduct IMDCT and windowing. + */ +static void AAC_RENAME(imdct_and_windowing)(AACDecContext *ac, SingleChannelElement *sce) +{ + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *in = sce->AAC_RENAME(coeffs); + INTFLOAT *out = sce->AAC_RENAME(output); + INTFLOAT *saved = sce->AAC_RENAME(saved); + const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); + const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024); + const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128); + INTFLOAT *buf = ac->AAC_RENAME(buf_mdct); + INTFLOAT *temp = ac->AAC_RENAME(temp); + int i; + + // imdct + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + for (i = 0; i < 1024; i += 128) + ac->mdct128_fn(ac->mdct128, buf + i, in + i, sizeof(INTFLOAT)); + } else { + ac->mdct1024_fn(ac->mdct1024, buf, in, sizeof(INTFLOAT)); + } + + /* window overlapping + * NOTE: To simplify the overlapping code, all 'meaningless' short to long + * and long to short transitions are considered to be short to short + * transitions. This leaves just two cases (long to long and short to short) + * with a little special sauce for EIGHT_SHORT_SEQUENCE. + */ + if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) && + (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) { + ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 512); + } else { + memcpy( out, saved, 448 * sizeof(*out)); + + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + ac->fdsp->vector_fmul_window(out + 448 + 0*128, saved + 448, buf + 0*128, swindow_prev, 64); + ac->fdsp->vector_fmul_window(out + 448 + 1*128, buf + 0*128 + 64, buf + 1*128, swindow, 64); + ac->fdsp->vector_fmul_window(out + 448 + 2*128, buf + 1*128 + 64, buf + 2*128, swindow, 64); + ac->fdsp->vector_fmul_window(out + 448 + 3*128, buf + 2*128 + 64, buf + 3*128, swindow, 64); + ac->fdsp->vector_fmul_window(temp, buf + 3*128 + 64, buf + 4*128, swindow, 64); + memcpy( out + 448 + 4*128, temp, 64 * sizeof(*out)); + } else { + ac->fdsp->vector_fmul_window(out + 448, saved + 448, buf, swindow_prev, 64); + memcpy( out + 576, buf + 64, 448 * sizeof(*out)); + } + } + + // buffer update + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + memcpy( saved, temp + 64, 64 * sizeof(*saved)); + ac->fdsp->vector_fmul_window(saved + 64, buf + 4*128 + 64, buf + 5*128, swindow, 64); + ac->fdsp->vector_fmul_window(saved + 192, buf + 5*128 + 64, buf + 6*128, swindow, 64); + ac->fdsp->vector_fmul_window(saved + 320, buf + 6*128 + 64, buf + 7*128, swindow, 64); + memcpy( saved + 448, buf + 7*128 + 64, 64 * sizeof(*saved)); + } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { + memcpy( saved, buf + 512, 448 * sizeof(*saved)); + memcpy( saved + 448, buf + 7*128 + 64, 64 * sizeof(*saved)); + } else { // LONG_STOP or ONLY_LONG + memcpy( saved, buf + 512, 512 * sizeof(*saved)); + } +} + +/** + * Conduct IMDCT and windowing for 768-point frames. + */ +static void AAC_RENAME(imdct_and_windowing_768)(AACDecContext *ac, SingleChannelElement *sce) +{ + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *in = sce->AAC_RENAME(coeffs); + INTFLOAT *out = sce->AAC_RENAME(output); + INTFLOAT *saved = sce->AAC_RENAME(saved); + const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME(aac_kbd_short_96) : AAC_RENAME(sine_96); + const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME(aac_kbd_long_768) : AAC_RENAME(sine_768); + const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME(aac_kbd_short_96) : AAC_RENAME(sine_96); + INTFLOAT *buf = ac->AAC_RENAME(buf_mdct); + INTFLOAT *temp = ac->AAC_RENAME(temp); + int i; + + // imdct + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + for (i = 0; i < 8; i++) + ac->mdct96_fn(ac->mdct96, buf + i * 96, in + i * 96, sizeof(INTFLOAT)); + } else { + ac->mdct768_fn(ac->mdct768, buf, in, sizeof(INTFLOAT)); + } + + /* window overlapping + * NOTE: To simplify the overlapping code, all 'meaningless' short to long + * and long to short transitions are considered to be short to short + * transitions. This leaves just two cases (long to long and short to short) + * with a little special sauce for EIGHT_SHORT_SEQUENCE. + */ + + if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) && + (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) { + ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 384); + } else { + memcpy( out, saved, 336 * sizeof(*out)); + + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + ac->fdsp->vector_fmul_window(out + 336 + 0*96, saved + 336, buf + 0*96, swindow_prev, 48); + ac->fdsp->vector_fmul_window(out + 336 + 1*96, buf + 0*96 + 48, buf + 1*96, swindow, 48); + ac->fdsp->vector_fmul_window(out + 336 + 2*96, buf + 1*96 + 48, buf + 2*96, swindow, 48); + ac->fdsp->vector_fmul_window(out + 336 + 3*96, buf + 2*96 + 48, buf + 3*96, swindow, 48); + ac->fdsp->vector_fmul_window(temp, buf + 3*96 + 48, buf + 4*96, swindow, 48); + memcpy( out + 336 + 4*96, temp, 48 * sizeof(*out)); + } else { + ac->fdsp->vector_fmul_window(out + 336, saved + 336, buf, swindow_prev, 48); + memcpy( out + 432, buf + 48, 336 * sizeof(*out)); + } + } + + // buffer update + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + memcpy( saved, temp + 48, 48 * sizeof(*saved)); + ac->fdsp->vector_fmul_window(saved + 48, buf + 4*96 + 48, buf + 5*96, swindow, 48); + ac->fdsp->vector_fmul_window(saved + 144, buf + 5*96 + 48, buf + 6*96, swindow, 48); + ac->fdsp->vector_fmul_window(saved + 240, buf + 6*96 + 48, buf + 7*96, swindow, 48); + memcpy( saved + 336, buf + 7*96 + 48, 48 * sizeof(*saved)); + } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { + memcpy( saved, buf + 384, 336 * sizeof(*saved)); + memcpy( saved + 336, buf + 7*96 + 48, 48 * sizeof(*saved)); + } else { // LONG_STOP or ONLY_LONG + memcpy( saved, buf + 384, 384 * sizeof(*saved)); + } +} + +/** + * Conduct IMDCT and windowing. + */ +static void AAC_RENAME(imdct_and_windowing_960)(AACDecContext *ac, SingleChannelElement *sce) +{ + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *in = sce->AAC_RENAME(coeffs); + INTFLOAT *out = sce->AAC_RENAME(output); + INTFLOAT *saved = sce->AAC_RENAME(saved); + const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME(aac_kbd_short_120) : AAC_RENAME(sine_120); + const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME(aac_kbd_long_960) : AAC_RENAME(sine_960); + const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME(aac_kbd_short_120) : AAC_RENAME(sine_120); + INTFLOAT *buf = ac->AAC_RENAME(buf_mdct); + INTFLOAT *temp = ac->AAC_RENAME(temp); + int i; + + // imdct + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + for (i = 0; i < 8; i++) + ac->mdct120_fn(ac->mdct120, buf + i * 120, in + i * 128, sizeof(INTFLOAT)); + } else { + ac->mdct960_fn(ac->mdct960, buf, in, sizeof(INTFLOAT)); + } + + /* window overlapping + * NOTE: To simplify the overlapping code, all 'meaningless' short to long + * and long to short transitions are considered to be short to short + * transitions. This leaves just two cases (long to long and short to short) + * with a little special sauce for EIGHT_SHORT_SEQUENCE. + */ + + if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) && + (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) { + ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 480); + } else { + memcpy( out, saved, 420 * sizeof(*out)); + + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + ac->fdsp->vector_fmul_window(out + 420 + 0*120, saved + 420, buf + 0*120, swindow_prev, 60); + ac->fdsp->vector_fmul_window(out + 420 + 1*120, buf + 0*120 + 60, buf + 1*120, swindow, 60); + ac->fdsp->vector_fmul_window(out + 420 + 2*120, buf + 1*120 + 60, buf + 2*120, swindow, 60); + ac->fdsp->vector_fmul_window(out + 420 + 3*120, buf + 2*120 + 60, buf + 3*120, swindow, 60); + ac->fdsp->vector_fmul_window(temp, buf + 3*120 + 60, buf + 4*120, swindow, 60); + memcpy( out + 420 + 4*120, temp, 60 * sizeof(*out)); + } else { + ac->fdsp->vector_fmul_window(out + 420, saved + 420, buf, swindow_prev, 60); + memcpy( out + 540, buf + 60, 420 * sizeof(*out)); + } + } + + // buffer update + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + memcpy( saved, temp + 60, 60 * sizeof(*saved)); + ac->fdsp->vector_fmul_window(saved + 60, buf + 4*120 + 60, buf + 5*120, swindow, 60); + ac->fdsp->vector_fmul_window(saved + 180, buf + 5*120 + 60, buf + 6*120, swindow, 60); + ac->fdsp->vector_fmul_window(saved + 300, buf + 6*120 + 60, buf + 7*120, swindow, 60); + memcpy( saved + 420, buf + 7*120 + 60, 60 * sizeof(*saved)); + } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { + memcpy( saved, buf + 480, 420 * sizeof(*saved)); + memcpy( saved + 420, buf + 7*120 + 60, 60 * sizeof(*saved)); + } else { // LONG_STOP or ONLY_LONG + memcpy( saved, buf + 480, 480 * sizeof(*saved)); + } +} + +static void AAC_RENAME(imdct_and_windowing_ld)(AACDecContext *ac, SingleChannelElement *sce) +{ + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *in = sce->AAC_RENAME(coeffs); + INTFLOAT *out = sce->AAC_RENAME(output); + INTFLOAT *saved = sce->AAC_RENAME(saved); + INTFLOAT *buf = ac->AAC_RENAME(buf_mdct); + + // imdct + ac->mdct512_fn(ac->mdct512, buf, in, sizeof(INTFLOAT)); + + // window overlapping + if (ics->use_kb_window[1]) { + // AAC LD uses a low overlap sine window instead of a KBD window + memcpy(out, saved, 192 * sizeof(*out)); + ac->fdsp->vector_fmul_window(out + 192, saved + 192, buf, AAC_RENAME2(sine_128), 64); + memcpy( out + 320, buf + 64, 192 * sizeof(*out)); + } else { + ac->fdsp->vector_fmul_window(out, saved, buf, AAC_RENAME2(sine_512), 256); + } + + // buffer update + memcpy(saved, buf + 256, 256 * sizeof(*saved)); +} + +static void AAC_RENAME(imdct_and_windowing_eld)(AACDecContext *ac, SingleChannelElement *sce) +{ + UINTFLOAT *in = sce->AAC_RENAME(coeffs); + INTFLOAT *out = sce->AAC_RENAME(output); + INTFLOAT *saved = sce->AAC_RENAME(saved); + INTFLOAT *buf = ac->AAC_RENAME(buf_mdct); + int i; + const int n = ac->oc[1].m4ac.frame_length_short ? 480 : 512; + const int n2 = n >> 1; + const int n4 = n >> 2; + const INTFLOAT *const window = n == 480 ? AAC_RENAME(ff_aac_eld_window_480) : + AAC_RENAME(ff_aac_eld_window_512); + + // Inverse transform, mapped to the conventional IMDCT by + // Chivukula, R.K.; Reznik, Y.A.; Devarajan, V., + // "Efficient algorithms for MPEG-4 AAC-ELD, AAC-LD and AAC-LC filterbanks," + // International Conference on Audio, Language and Image Processing, ICALIP 2008. + // URL: http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4590245&isnumber=4589950 + for (i = 0; i < n2; i+=2) { + INTFLOAT temp; + temp = in[i ]; in[i ] = -in[n - 1 - i]; in[n - 1 - i] = temp; + temp = -in[i + 1]; in[i + 1] = in[n - 2 - i]; in[n - 2 - i] = temp; + } + + if (n == 480) + ac->mdct480_fn(ac->mdct480, buf, in, sizeof(INTFLOAT)); + else + ac->mdct512_fn(ac->mdct512, buf, in, sizeof(INTFLOAT)); + + for (i = 0; i < n; i+=2) { + buf[i + 0] = -(UINTFLOAT)(USE_FIXED + 1)*buf[i + 0]; + buf[i + 1] = (UINTFLOAT)(USE_FIXED + 1)*buf[i + 1]; + } + // Like with the regular IMDCT at this point we still have the middle half + // of a transform but with even symmetry on the left and odd symmetry on + // the right + + // window overlapping + // The spec says to use samples [0..511] but the reference decoder uses + // samples [128..639]. + for (i = n4; i < n2; i ++) { + out[i - n4] = AAC_MUL31( buf[ n2 - 1 - i] , window[i - n4]) + + AAC_MUL31( saved[ i + n2] , window[i + n - n4]) + + AAC_MUL31(-saved[n + n2 - 1 - i] , window[i + 2*n - n4]) + + AAC_MUL31(-saved[ 2*n + n2 + i] , window[i + 3*n - n4]); + } + for (i = 0; i < n2; i ++) { + out[n4 + i] = AAC_MUL31( buf[ i] , window[i + n2 - n4]) + + AAC_MUL31(-saved[ n - 1 - i] , window[i + n2 + n - n4]) + + AAC_MUL31(-saved[ n + i] , window[i + n2 + 2*n - n4]) + + AAC_MUL31( saved[2*n + n - 1 - i] , window[i + n2 + 3*n - n4]); + } + for (i = 0; i < n4; i ++) { + out[n2 + n4 + i] = AAC_MUL31( buf[ i + n2] , window[i + n - n4]) + + AAC_MUL31(-saved[n2 - 1 - i] , window[i + 2*n - n4]) + + AAC_MUL31(-saved[n + n2 + i] , window[i + 3*n - n4]); + } + + // buffer update + memmove(saved + n, saved, 2 * n * sizeof(*saved)); + memcpy( saved, buf, n * sizeof(*saved)); +} + +static void AAC_RENAME(clip_output)(AACDecContext *ac, ChannelElement *che, + int type, int samples) +{ +#if USE_FIXED + /* preparation for resampler */ + for (int j = 0; j < samples; j++){ + che->ch[0].output_fixed[j] = (int32_t)av_clip64((int64_t)che->ch[0].output_fixed[j]*128, + INT32_MIN, INT32_MAX-0x8000)+0x8000; + if (type == TYPE_CPE || (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1)) + che->ch[1].output_fixed[j] = (int32_t)av_clip64((int64_t)che->ch[1].output_fixed[j]*128, + INT32_MIN, INT32_MAX-0x8000)+0x8000; + } +#endif +} + +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(PredictorState *ps, int group_num) +{ + int i; + for (i = group_num - 1; i < MAX_PREDICTORS; i += 30) + reset_predict_state(&ps[i]); +} + +/** + * Apply AAC-Main style frequency domain prediction. + */ +static void AAC_RENAME(apply_prediction)(AACDecContext *ac, SingleChannelElement *sce) +{ + int sfb, k; + + if (!sce->ics.predictor_initialized) { + reset_all_predictors(sce->AAC_RENAME(predictor_state)); + sce->ics.predictor_initialized = 1; + } + + if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { + for (sfb = 0; + sfb < ff_aac_pred_sfb_max[ac->oc[1].m4ac.sampling_index]; + sfb++) { + for (k = sce->ics.swb_offset[sfb]; + k < sce->ics.swb_offset[sfb + 1]; + k++) { + predict(&sce->AAC_RENAME(predictor_state)[k], + &sce->AAC_RENAME(coeffs)[k], + sce->ics.predictor_present && + sce->ics.prediction_used[sfb]); + } + } + if (sce->ics.predictor_reset_group) + reset_predictor_group(sce->AAC_RENAME(predictor_state), + sce->ics.predictor_reset_group); + } else + reset_all_predictors(sce->AAC_RENAME(predictor_state)); +} + +static av_cold void AAC_RENAME(aac_dsp_init)(AACDecDSP *aac_dsp) +{ +#define SET(member) aac_dsp->member = AAC_RENAME(member) + SET(dequant_scalefactors); + SET(apply_mid_side_stereo); + SET(apply_intensity_stereo); + SET(apply_tns); + SET(apply_ltp); + SET(update_ltp); + + SET(apply_prediction); + + SET(imdct_and_windowing); + SET(imdct_and_windowing_768); + SET(imdct_and_windowing_960); + SET(imdct_and_windowing_ld); + SET(imdct_and_windowing_eld); + + SET(apply_dependent_coupling); + SET(apply_independent_coupling); + + SET(clip_output); +#undef SET +} diff --git a/libavcodec/aac/aacdec_fixed.c b/libavcodec/aac/aacdec_fixed.c new file mode 100644 index 000000000..89f1ea038 --- /dev/null +++ b/libavcodec/aac/aacdec_fixed.c @@ -0,0 +1,105 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 USE_FIXED 1 + +#include "libavutil/thread.h" + +#include "libavcodec/aac_defines.h" + +#include "libavcodec/avcodec.h" +#include "aacdec.h" +#include "libavcodec/aactab.h" +#include "libavcodec/sinewin_fixed_tablegen.h" +#include "libavcodec/kbdwin.h" +#include "libavcodec/cbrt_data.h" +#include "libavcodec/aacsbr.h" + +DECLARE_ALIGNED(32, static int, aac_kbd_long_1024_fixed)[1024]; +DECLARE_ALIGNED(32, static int, aac_kbd_short_128_fixed)[128]; +DECLARE_ALIGNED(32, static int, aac_kbd_long_960_fixed)[960]; +DECLARE_ALIGNED(32, static int, aac_kbd_short_120_fixed)[120]; +DECLARE_ALIGNED(32, static int, aac_kbd_long_768_fixed)[768]; +DECLARE_ALIGNED(32, static int, aac_kbd_short_96_fixed)[96]; + +static void init_tables_fixed_fn(void) +{ + ff_cbrt_tableinit_fixed(); + + ff_kbd_window_init_fixed(aac_kbd_long_1024_fixed, 4.0, 1024); + ff_kbd_window_init_fixed(aac_kbd_short_128_fixed, 6.0, 128); + + ff_kbd_window_init_fixed(aac_kbd_long_960_fixed, 4.0, 960); + ff_kbd_window_init_fixed(aac_kbd_short_120_fixed, 6.0, 120); + + ff_aac_sbr_init_fixed(); + + init_sine_windows_fixed(); +} + +static const int cce_scale_fixed[8] = { + Q30(1.0), //2^(0/8) + Q30(1.0905077327), //2^(1/8) + Q30(1.1892071150), //2^(2/8) + Q30(1.2968395547), //2^(3/8) + Q30(1.4142135624), //2^(4/8) + Q30(1.5422108254), //2^(5/8) + Q30(1.6817928305), //2^(6/8) + Q30(1.8340080864), //2^(7/8) +}; + +/** Dequantization-related */ +#include "aacdec_fixed_dequant.h" + +#include "aacdec_fixed_coupling.h" +#include "aacdec_fixed_prediction.h" +#include "aacdec_dsp_template.c" +#include "aacdec_proc_template.c" + +av_cold int ff_aac_decode_init_fixed(AVCodecContext *avctx) +{ + static AVOnce init_fixed_once = AV_ONCE_INIT; + AACDecContext *ac = avctx->priv_data; + + ac->is_fixed = 1; + avctx->sample_fmt = AV_SAMPLE_FMT_S32P; + + aac_dsp_init_fixed(&ac->dsp); + aac_proc_init_fixed(&ac->proc); + + ac->fdsp = avpriv_alloc_fixed_dsp(avctx->flags & AV_CODEC_FLAG_BITEXACT); + if (!ac->fdsp) + return AVERROR(ENOMEM); + + ff_thread_once(&init_fixed_once, init_tables_fixed_fn); + + return ff_aac_decode_init(avctx); +} diff --git a/libavcodec/aac/aacdec_fixed_coupling.h b/libavcodec/aac/aacdec_fixed_coupling.h new file mode 100644 index 000000000..add4cd69d --- /dev/null +++ b/libavcodec/aac/aacdec_fixed_coupling.h @@ -0,0 +1,137 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_FIXED_COUPLING_H +#define AVCODEC_AAC_AACDEC_FIXED_COUPLING_H + +#include "aacdec.h" + +/** + * Apply dependent channel coupling (applied before IMDCT). + * + * @param index index into coupling gain array + */ +static void AAC_RENAME(apply_dependent_coupling)(AACDecContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index) +{ + IndividualChannelStream *ics = &cce->ch[0].ics; + const uint16_t *offsets = ics->swb_offset; + int *dest = target->coeffs_fixed; + const int *src = cce->ch[0].coeffs_fixed; + int g, i, group, k, idx = 0; + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { + av_log(ac->avctx, AV_LOG_ERROR, + "Dependent coupling is not supported together with LTP\n"); + return; + } + for (g = 0; g < ics->num_window_groups; g++) { + for (i = 0; i < ics->max_sfb; i++, idx++) { + if (cce->ch[0].band_type[idx] != ZERO_BT) { + const int gain = cce->coup.gain[index][idx]; + int shift, round, c, tmp; + + if (gain < 0) { + c = -cce_scale_fixed[-gain & 7]; + shift = (-gain-1024) >> 3; + } + else { + c = cce_scale_fixed[gain & 7]; + shift = (gain-1024) >> 3; + } + + if (shift < -31) { + // Nothing to do + } else if (shift < 0) { + shift = -shift; + round = 1 << (shift - 1); + + for (group = 0; group < ics->group_len[g]; group++) { + for (k = offsets[i]; k < offsets[i + 1]; k++) { + tmp = (int)(((int64_t)src[group * 128 + k] * c + \ + (int64_t)0x1000000000) >> 37); + dest[group * 128 + k] += (tmp + (int64_t)round) >> shift; + } + } + } + else { + for (group = 0; group < ics->group_len[g]; group++) { + for (k = offsets[i]; k < offsets[i + 1]; k++) { + tmp = (int)(((int64_t)src[group * 128 + k] * c + \ + (int64_t)0x1000000000) >> 37); + dest[group * 128 + k] += tmp * (1U << shift); + } + } + } + } + } + dest += ics->group_len[g] * 128; + src += ics->group_len[g] * 128; + } +} + +/** + * Apply independent channel coupling (applied after IMDCT). + * + * @param index index into coupling gain array + */ +static void AAC_RENAME(apply_independent_coupling)(AACDecContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index) +{ + int i, c, shift, round, tmp; + const int gain = cce->coup.gain[index][0]; + const int *src = cce->ch[0].output_fixed; + unsigned int *dest = target->output_fixed; + const int len = 1024 << (ac->oc[1].m4ac.sbr == 1); + + c = cce_scale_fixed[gain & 7]; + shift = (gain-1024) >> 3; + if (shift < -31) { + return; + } else if (shift < 0) { + shift = -shift; + round = 1 << (shift - 1); + + for (i = 0; i < len; i++) { + tmp = (int)(((int64_t)src[i] * c + (int64_t)0x1000000000) >> 37); + dest[i] += (tmp + round) >> shift; + } + } + else { + for (i = 0; i < len; i++) { + tmp = (int)(((int64_t)src[i] * c + (int64_t)0x1000000000) >> 37); + dest[i] += tmp * (1U << shift); + } + } +} + +#endif /* AVCODEC_AAC_AACDEC_FIXED_COUPLING_H */ diff --git a/libavcodec/aac/aacdec_fixed_dequant.h b/libavcodec/aac/aacdec_fixed_dequant.h new file mode 100644 index 000000000..5fb84fbed --- /dev/null +++ b/libavcodec/aac/aacdec_fixed_dequant.h @@ -0,0 +1,174 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_FIXED_DEQUANT_H +#define AVCODEC_AAC_AACDEC_FIXED_DEQUANT_H + +#include "aacdec_tab.h" + +static void inline vector_pow43(int *coefs, int len) +{ + int i, coef; + + for (i=0; i> 2); + + if (s > 31) { + for (i=0; i 0) { + round = 1 << (s-1); + for (i=0; i> 32); + dst[i] = ((int)(out+round) >> s) * ssign; + } + } else if (s > -32) { + s = s + 32; + round = 1U << (s-1); + for (i=0; i> s); + dst[i] = out * (unsigned)ssign; + } + } else { + av_log(log_context, AV_LOG_ERROR, "Overflow in subband_scale()\n"); + } +} + +static void noise_scale(int *coefs, int scale, int band_energy, int len) +{ + int s = -scale; + unsigned int round; + int i, out, c = exp2tab[s & 3]; + int nlz = 0; + + av_assert0(s >= 0); + while (band_energy > 0x7fff) { + band_energy >>= 1; + nlz++; + } + c /= band_energy; + s = 21 + nlz - (s >> 2); + + if (s > 31) { + for (i=0; i= 0) { + round = s ? 1 << (s-1) : 0; + for (i=0; i> 32); + coefs[i] = -((int)(out+round) >> s); + } + } + else { + s = s + 32; + if (s > 0) { + round = 1 << (s-1); + for (i=0; i> s); + coefs[i] = -out; + } + } else { + for (i=0; i> 4 & 15) - 4; + + return dst + 2; +} + +static inline int *DEC_SQUAD(int *dst, unsigned idx) +{ + dst[0] = (idx & 3) - 1; + dst[1] = (idx >> 2 & 3) - 1; + dst[2] = (idx >> 4 & 3) - 1; + dst[3] = (idx >> 6 & 3) - 1; + + return dst + 4; +} + +static inline int *DEC_UPAIR(int *dst, unsigned idx, unsigned sign) +{ + dst[0] = (idx & 15) * (1 - (sign & 0xFFFFFFFE)); + dst[1] = (idx >> 4 & 15) * (1 - ((sign & 1) * 2)); + + return dst + 2; +} + +static inline int *DEC_UQUAD(int *dst, unsigned idx, unsigned sign) +{ + unsigned nz = idx >> 12; + + dst[0] = (idx & 3) * (1 + (((int)sign >> 31) * 2)); + sign <<= nz & 1; + nz >>= 1; + dst[1] = (idx >> 2 & 3) * (1 + (((int)sign >> 31) * 2)); + sign <<= nz & 1; + nz >>= 1; + dst[2] = (idx >> 4 & 3) * (1 + (((int)sign >> 31) * 2)); + sign <<= nz & 1; + nz >>= 1; + dst[3] = (idx >> 6 & 3) * (1 + (((int)sign >> 31) * 2)); + + return dst + 4; +} + +#endif /* AVCODEC_AAC_AACDEC_FIXED_DEQUANT_H */ diff --git a/libavcodec/aac/aacdec_fixed_prediction.h b/libavcodec/aac/aacdec_fixed_prediction.h new file mode 100644 index 000000000..6fb335486 --- /dev/null +++ b/libavcodec/aac/aacdec_fixed_prediction.h @@ -0,0 +1,151 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_FIXED_PREDICTION_H +#define AVCODEC_AAC_AACDEC_FIXED_PREDICTION_H + +static av_always_inline SoftFloat flt16_round(SoftFloat pf) +{ + SoftFloat tmp; + int s; + + tmp.exp = pf.exp; + s = pf.mant >> 31; + tmp.mant = (pf.mant ^ s) - s; + tmp.mant = (tmp.mant + 0x00200000U) & 0xFFC00000U; + tmp.mant = (tmp.mant ^ s) - s; + + return tmp; +} + +static av_always_inline SoftFloat flt16_even(SoftFloat pf) +{ + SoftFloat tmp; + int s; + + tmp.exp = pf.exp; + s = pf.mant >> 31; + tmp.mant = (pf.mant ^ s) - s; + tmp.mant = (tmp.mant + 0x001FFFFFU + (tmp.mant & 0x00400000U >> 16)) & 0xFFC00000U; + tmp.mant = (tmp.mant ^ s) - s; + + return tmp; +} + +static av_always_inline SoftFloat flt16_trunc(SoftFloat pf) +{ + SoftFloat pun; + int s; + + pun.exp = pf.exp; + s = pf.mant >> 31; + pun.mant = (pf.mant ^ s) - s; + pun.mant = pun.mant & 0xFFC00000U; + pun.mant = (pun.mant ^ s) - s; + + return pun; +} + +static av_always_inline void predict(PredictorState *ps, int *coef, + int output_enable) +{ + const SoftFloat a = { 1023410176, 0 }; // 61.0 / 64 + const SoftFloat alpha = { 973078528, 0 }; // 29.0 / 32 + SoftFloat e0, e1; + SoftFloat pv; + SoftFloat k1, k2; + SoftFloat r0 = ps->r0, r1 = ps->r1; + SoftFloat cor0 = ps->cor0, cor1 = ps->cor1; + SoftFloat var0 = ps->var0, var1 = ps->var1; + SoftFloat tmp; + + if (var0.exp > 1 || (var0.exp == 1 && var0.mant > 0x20000000)) { + k1 = av_mul_sf(cor0, flt16_even(av_div_sf(a, var0))); + } + else { + k1.mant = 0; + k1.exp = 0; + } + + if (var1.exp > 1 || (var1.exp == 1 && var1.mant > 0x20000000)) { + k2 = av_mul_sf(cor1, flt16_even(av_div_sf(a, var1))); + } + else { + k2.mant = 0; + k2.exp = 0; + } + + tmp = av_mul_sf(k1, r0); + pv = flt16_round(av_add_sf(tmp, av_mul_sf(k2, r1))); + if (output_enable) { + int shift = 28 - pv.exp; + + if (shift < 31) { + if (shift > 0) { + *coef += (unsigned)((pv.mant + (1 << (shift - 1))) >> shift); + } else + *coef += (unsigned)pv.mant << -shift; + } + } + + e0 = av_int2sf(*coef, 2); + e1 = av_sub_sf(e0, tmp); + + ps->cor1 = flt16_trunc(av_add_sf(av_mul_sf(alpha, cor1), av_mul_sf(r1, e1))); + tmp = av_add_sf(av_mul_sf(r1, r1), av_mul_sf(e1, e1)); + tmp.exp--; + ps->var1 = flt16_trunc(av_add_sf(av_mul_sf(alpha, var1), tmp)); + ps->cor0 = flt16_trunc(av_add_sf(av_mul_sf(alpha, cor0), av_mul_sf(r0, e0))); + tmp = av_add_sf(av_mul_sf(r0, r0), av_mul_sf(e0, e0)); + tmp.exp--; + ps->var0 = flt16_trunc(av_add_sf(av_mul_sf(alpha, var0), tmp)); + + ps->r1 = flt16_trunc(av_mul_sf(a, av_sub_sf(r0, av_mul_sf(k1, e0)))); + ps->r0 = flt16_trunc(av_mul_sf(a, e0)); +} + +static av_always_inline void reset_predict_state(PredictorState *ps) +{ + ps->r0.mant = 0; + ps->r0.exp = 0; + ps->r1.mant = 0; + ps->r1.exp = 0; + ps->cor0.mant = 0; + ps->cor0.exp = 0; + ps->cor1.mant = 0; + ps->cor1.exp = 0; + ps->var0.mant = 0x20000000; + ps->var0.exp = 1; + ps->var1.mant = 0x20000000; + ps->var1.exp = 1; +} + +#endif /* AVCODEC_AAC_AACDEC_FIXED_PREDICTION_H */ diff --git a/libavcodec/aac/aacdec_float.c b/libavcodec/aac/aacdec_float.c new file mode 100644 index 000000000..14169e95d --- /dev/null +++ b/libavcodec/aac/aacdec_float.c @@ -0,0 +1,182 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 USE_FIXED 0 + +#include "libavutil/thread.h" + +#include "libavcodec/aac_defines.h" + +#include "libavcodec/avcodec.h" +#include "aacdec.h" +#include "libavcodec/aactab.h" +#include "libavcodec/sinewin.h" +#include "libavcodec/kbdwin.h" +#include "libavcodec/cbrt_data.h" +#include "libavutil/mathematics.h" +#include "libavcodec/aacsbr.h" + +DECLARE_ALIGNED(32, static float, sine_96)[96]; +DECLARE_ALIGNED(32, static float, sine_120)[120]; +DECLARE_ALIGNED(32, static float, sine_768)[768]; +DECLARE_ALIGNED(32, static float, sine_960)[960]; +DECLARE_ALIGNED(32, static float, aac_kbd_long_960)[960]; +DECLARE_ALIGNED(32, static float, aac_kbd_short_120)[120]; +DECLARE_ALIGNED(32, static float, aac_kbd_long_768)[768]; +DECLARE_ALIGNED(32, static float, aac_kbd_short_96)[96]; + +static void init_tables_float_fn(void) +{ + ff_cbrt_tableinit(); + + ff_kbd_window_init(ff_aac_kbd_long_1024, 4.0, 1024); + ff_kbd_window_init(ff_aac_kbd_short_128, 6.0, 128); + + ff_kbd_window_init(aac_kbd_long_960, 4.0, 960); + ff_kbd_window_init(aac_kbd_short_120, 6.0, 120); + + ff_sine_window_init(sine_960, 960); + ff_sine_window_init(sine_120, 120); + ff_init_ff_sine_windows(9); + + ff_aac_sbr_init(); + + ff_aac_float_common_init(); +} + +static const float cce_scale[] = { + 1.09050773266525765921, //2^(1/8) + 1.18920711500272106672, //2^(1/4) + M_SQRT2, + 2, +}; + +/** Dequantization-related **/ +#include "aacdec_tab.h" +#include "libavutil/intfloat.h" + +#include "config.h" +#if ARCH_ARM +#include "libavcodec/arm/aac.h" +#endif + +#ifndef VMUL2 +static inline float *VMUL2(float *dst, const float *v, unsigned idx, + const float *scale) +{ + float s = *scale; + *dst++ = v[idx & 15] * s; + *dst++ = v[idx>>4 & 15] * s; + return dst; +} +#endif + +#ifndef VMUL4 +static inline float *VMUL4(float *dst, const float *v, unsigned idx, + const float *scale) +{ + float s = *scale; + *dst++ = v[idx & 3] * s; + *dst++ = v[idx>>2 & 3] * s; + *dst++ = v[idx>>4 & 3] * s; + *dst++ = v[idx>>6 & 3] * s; + return dst; +} +#endif + +#ifndef VMUL2S +static inline float *VMUL2S(float *dst, const float *v, unsigned idx, + unsigned sign, const float *scale) +{ + union av_intfloat32 s0, s1; + + s0.f = s1.f = *scale; + s0.i ^= sign >> 1 << 31; + s1.i ^= sign << 31; + + *dst++ = v[idx & 15] * s0.f; + *dst++ = v[idx>>4 & 15] * s1.f; + + return dst; +} +#endif + +#ifndef VMUL4S +static inline float *VMUL4S(float *dst, const float *v, unsigned idx, + unsigned sign, const float *scale) +{ + unsigned nz = idx >> 12; + union av_intfloat32 s = { .f = *scale }; + union av_intfloat32 t; + + t.i = s.i ^ (sign & 1U<<31); + *dst++ = v[idx & 3] * t.f; + + sign <<= nz & 1; nz >>= 1; + t.i = s.i ^ (sign & 1U<<31); + *dst++ = v[idx>>2 & 3] * t.f; + + sign <<= nz & 1; nz >>= 1; + t.i = s.i ^ (sign & 1U<<31); + *dst++ = v[idx>>4 & 3] * t.f; + + sign <<= nz & 1; + t.i = s.i ^ (sign & 1U<<31); + *dst++ = v[idx>>6 & 3] * t.f; + + return dst; +} +#endif + +#include "aacdec_float_coupling.h" +#include "aacdec_float_prediction.h" +#include "aacdec_dsp_template.c" +#include "aacdec_proc_template.c" + +av_cold int ff_aac_decode_init_float(AVCodecContext *avctx) +{ + static AVOnce init_float_once = AV_ONCE_INIT; + AACDecContext *ac = avctx->priv_data; + + ac->is_fixed = 0; + avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; + + aac_dsp_init(&ac->dsp); + aac_proc_init(&ac->proc); + + ac->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); + if (!ac->fdsp) + return AVERROR(ENOMEM); + + ff_thread_once(&init_float_once, init_tables_float_fn); + + return ff_aac_decode_init(avctx); +} diff --git a/libavcodec/aac/aacdec_float_coupling.h b/libavcodec/aac/aacdec_float_coupling.h new file mode 100644 index 000000000..50ad76eda --- /dev/null +++ b/libavcodec/aac/aacdec_float_coupling.h @@ -0,0 +1,90 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_FLOAT_COUPLING_H +#define AVCODEC_AAC_AACDEC_FLOAT_COUPLING_H + +#include "aacdec.h" + +/** + * Apply dependent channel coupling (applied before IMDCT). + * + * @param index index into coupling gain array + */ +static void AAC_RENAME(apply_dependent_coupling)(AACDecContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index) +{ + IndividualChannelStream *ics = &cce->ch[0].ics; + const uint16_t *offsets = ics->swb_offset; + float *dest = target->coeffs; + const float *src = cce->ch[0].coeffs; + int g, i, group, k, idx = 0; + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { + av_log(ac->avctx, AV_LOG_ERROR, + "Dependent coupling is not supported together with LTP\n"); + return; + } + for (g = 0; g < ics->num_window_groups; g++) { + for (i = 0; i < ics->max_sfb; i++, idx++) { + if (cce->ch[0].band_type[idx] != ZERO_BT) { + const float gain = cce->coup.gain[index][idx]; + for (group = 0; group < ics->group_len[g]; group++) { + for (k = offsets[i]; k < offsets[i + 1]; k++) { + // FIXME: SIMDify + dest[group * 128 + k] += gain * src[group * 128 + k]; + } + } + } + } + dest += ics->group_len[g] * 128; + src += ics->group_len[g] * 128; + } +} + +/** + * Apply independent channel coupling (applied after IMDCT). + * + * @param index index into coupling gain array + */ +static void AAC_RENAME(apply_independent_coupling)(AACDecContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index) +{ + const float gain = cce->coup.gain[index][0]; + const float *src = cce->ch[0].output; + float *dest = target->output; + const int len = 1024 << (ac->oc[1].m4ac.sbr == 1); + + ac->fdsp->vector_fmac_scalar(dest, src, gain, len); +} + +#endif /* AVCODEC_AAC_AACDEC_FLOAT_COUPLING_H */ diff --git a/libavcodec/aac/aacdec_float_prediction.h b/libavcodec/aac/aacdec_float_prediction.h new file mode 100644 index 000000000..a4100fd36 --- /dev/null +++ b/libavcodec/aac/aacdec_float_prediction.h @@ -0,0 +1,100 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_FLOAT_PREDICTION_H +#define AVCODEC_AAC_AACDEC_FLOAT_PREDICTION_H + +static av_always_inline float flt16_round(float pf) +{ + union av_intfloat32 tmp; + tmp.f = pf; + tmp.i = (tmp.i + 0x00008000U) & 0xFFFF0000U; + return tmp.f; +} + +static av_always_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 av_always_inline float flt16_trunc(float pf) +{ + union av_intfloat32 pun; + pun.f = pf; + pun.i &= 0xFFFF0000U; + return pun.f; +} + +static av_always_inline void predict(PredictorState *ps, float *coef, + int output_enable) +{ + const float a = 0.953125; // 61.0 / 64 + const float alpha = 0.90625; // 29.0 / 32 + float e0, e1; + float pv; + float k1, k2; + float r0 = ps->r0, r1 = ps->r1; + float cor0 = ps->cor0, cor1 = ps->cor1; + float var0 = ps->var0, var1 = ps->var1; + + k1 = var0 > 1 ? cor0 * flt16_even(a / var0) : 0; + k2 = var1 > 1 ? cor1 * flt16_even(a / var1) : 0; + + pv = flt16_round(k1 * r0 + k2 * r1); + if (output_enable) + *coef += pv; + + e0 = *coef; + e1 = e0 - k1 * r0; + + 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); +} + +static av_always_inline void reset_predict_state(PredictorState *ps) +{ + ps->r0 = 0.0f; + ps->r1 = 0.0f; + ps->cor0 = 0.0f; + ps->cor1 = 0.0f; + ps->var0 = 1.0f; + ps->var1 = 1.0f; +} + +#endif /* AVCODEC_AAC_AACDEC_FLOAT_PREDICTION_H */ diff --git a/libavcodec/aacdec.c b/libavcodec/aac/aacdec_latm.h similarity index 60% rename from libavcodec/aacdec.c rename to libavcodec/aac/aacdec_latm.h index 97e51dd72..047c11e0f 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aac/aacdec_latm.h @@ -8,6 +8,10 @@ * Copyright (c) 2008-2010 Paul Kendall * Copyright (c) 2010 Janne Grunau * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -25,239 +29,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file - * AAC decoder - * @author Oded Shimon ( ods15 ods15 dyndns org ) - * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) - */ - -#define USE_FIXED 0 -#define TX_TYPE AV_TX_FLOAT_MDCT - -#include "libavutil/float_dsp.h" -#include "libavutil/opt.h" -#include "avcodec.h" -#include "codec_internal.h" -#include "get_bits.h" -#include "kbdwin.h" -#include "sinewin.h" - -#include "aac.h" -#include "aacdec.h" -#include "aactab.h" -#include "aacdectab.h" -#include "adts_header.h" -#include "cbrt_data.h" -#include "sbr.h" -#include "aacsbr.h" -#include "mpeg4audio.h" -#include "profiles.h" -#include "libavutil/intfloat.h" - -#include -#include -#include -#include - -#if ARCH_ARM -# include "arm/aac.h" -#elif ARCH_MIPS -# include "mips/aacdec_mips.h" -#endif - -DECLARE_ALIGNED(32, static INTFLOAT, AAC_RENAME(sine_120))[120]; -DECLARE_ALIGNED(32, static INTFLOAT, AAC_RENAME(sine_960))[960]; -DECLARE_ALIGNED(32, static INTFLOAT, AAC_RENAME(aac_kbd_long_960))[960]; -DECLARE_ALIGNED(32, static INTFLOAT, AAC_RENAME(aac_kbd_short_120))[120]; - -static av_always_inline void reset_predict_state(PredictorState *ps) -{ - ps->r0 = 0.0f; - ps->r1 = 0.0f; - ps->cor0 = 0.0f; - ps->cor1 = 0.0f; - ps->var0 = 1.0f; - ps->var1 = 1.0f; -} - -#ifndef VMUL2 -static inline float *VMUL2(float *dst, const float *v, unsigned idx, - const float *scale) -{ - float s = *scale; - *dst++ = v[idx & 15] * s; - *dst++ = v[idx>>4 & 15] * s; - return dst; -} -#endif - -#ifndef VMUL4 -static inline float *VMUL4(float *dst, const float *v, unsigned idx, - const float *scale) -{ - float s = *scale; - *dst++ = v[idx & 3] * s; - *dst++ = v[idx>>2 & 3] * s; - *dst++ = v[idx>>4 & 3] * s; - *dst++ = v[idx>>6 & 3] * s; - return dst; -} -#endif - -#ifndef VMUL2S -static inline float *VMUL2S(float *dst, const float *v, unsigned idx, - unsigned sign, const float *scale) -{ - union av_intfloat32 s0, s1; - - s0.f = s1.f = *scale; - s0.i ^= sign >> 1 << 31; - s1.i ^= sign << 31; - - *dst++ = v[idx & 15] * s0.f; - *dst++ = v[idx>>4 & 15] * s1.f; - - return dst; -} -#endif - -#ifndef VMUL4S -static inline float *VMUL4S(float *dst, const float *v, unsigned idx, - unsigned sign, const float *scale) -{ - unsigned nz = idx >> 12; - union av_intfloat32 s = { .f = *scale }; - union av_intfloat32 t; - - t.i = s.i ^ (sign & 1U<<31); - *dst++ = v[idx & 3] * t.f; - - sign <<= nz & 1; nz >>= 1; - t.i = s.i ^ (sign & 1U<<31); - *dst++ = v[idx>>2 & 3] * t.f; - - sign <<= nz & 1; nz >>= 1; - t.i = s.i ^ (sign & 1U<<31); - *dst++ = v[idx>>4 & 3] * t.f; - - sign <<= nz & 1; - t.i = s.i ^ (sign & 1U<<31); - *dst++ = v[idx>>6 & 3] * t.f; - - return dst; -} -#endif - -static av_always_inline float flt16_round(float pf) -{ - union av_intfloat32 tmp; - tmp.f = pf; - tmp.i = (tmp.i + 0x00008000U) & 0xFFFF0000U; - return tmp.f; -} - -static av_always_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 av_always_inline float flt16_trunc(float pf) -{ - union av_intfloat32 pun; - pun.f = pf; - pun.i &= 0xFFFF0000U; - return pun.f; -} - -static av_always_inline void predict(PredictorState *ps, float *coef, - int output_enable) -{ - const float a = 0.953125; // 61.0 / 64 - const float alpha = 0.90625; // 29.0 / 32 - float e0, e1; - float pv; - float k1, k2; - float r0 = ps->r0, r1 = ps->r1; - float cor0 = ps->cor0, cor1 = ps->cor1; - float var0 = ps->var0, var1 = ps->var1; - - k1 = var0 > 1 ? cor0 * flt16_even(a / var0) : 0; - k2 = var1 > 1 ? cor1 * flt16_even(a / var1) : 0; - - pv = flt16_round(k1 * r0 + k2 * r1); - if (output_enable) - *coef += pv; - - e0 = *coef; - e1 = e0 - k1 * r0; - - 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); -} - -/** - * Apply dependent channel coupling (applied before IMDCT). - * - * @param index index into coupling gain array - */ -static void apply_dependent_coupling(AACDecContext *ac, - SingleChannelElement *target, - ChannelElement *cce, int index) -{ - IndividualChannelStream *ics = &cce->ch[0].ics; - const uint16_t *offsets = ics->swb_offset; - float *dest = target->coeffs; - const float *src = cce->ch[0].coeffs; - int g, i, group, k, idx = 0; - if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { - av_log(ac->avctx, AV_LOG_ERROR, - "Dependent coupling is not supported together with LTP\n"); - return; - } - for (g = 0; g < ics->num_window_groups; g++) { - for (i = 0; i < ics->max_sfb; i++, idx++) { - if (cce->ch[0].band_type[idx] != ZERO_BT) { - const float gain = cce->coup.gain[index][idx]; - for (group = 0; group < ics->group_len[g]; group++) { - for (k = offsets[i]; k < offsets[i + 1]; k++) { - // FIXME: SIMDify - dest[group * 128 + k] += gain * src[group * 128 + k]; - } - } - } - } - dest += ics->group_len[g] * 128; - src += ics->group_len[g] * 128; - } -} - -/** - * Apply independent channel coupling (applied after IMDCT). - * - * @param index index into coupling gain array - */ -static void apply_independent_coupling(AACDecContext *ac, - SingleChannelElement *target, - ChannelElement *cce, int index) -{ - const float gain = cce->coup.gain[index][0]; - const float *src = cce->ch[0].ret; - float *dest = target->ret; - const int len = 1024 << (ac->oc[1].m4ac.sbr == 1); - - ac->fdsp->vector_fmac_scalar(dest, src, gain, len); -} - -#include "aacdec_template.c" +#ifndef AVCODEC_AAC_AACDEC_LATM_H +#define AVCODEC_AAC_AACDEC_LATM_H #define LOAS_SYNC_WORD 0x2b7 ///< 11 bits LOAS sync word @@ -283,7 +56,8 @@ static int latm_decode_audio_specific_config(struct LATMContext *latmctx, { AACDecContext *ac = &latmctx->aac_ctx; AVCodecContext *avctx = ac->avctx; - MPEG4AudioConfig m4ac = { 0 }; + OutputConfiguration oc = { 0 }; + MPEG4AudioConfig *m4ac = &oc.m4ac; GetBitContext gbc; int config_start_bit = get_bits_count(gb); int sync_extension = 0; @@ -303,7 +77,7 @@ static int latm_decode_audio_specific_config(struct LATMContext *latmctx, if (get_bits_left(gb) <= 0) return AVERROR_INVALIDDATA; - bits_consumed = decode_audio_specific_config_gb(NULL, avctx, &m4ac, + bits_consumed = decode_audio_specific_config_gb(NULL, avctx, &oc, &gbc, config_start_bit, sync_extension); @@ -315,11 +89,12 @@ static int latm_decode_audio_specific_config(struct LATMContext *latmctx, asclen = bits_consumed; if (!latmctx->initialized || - ac->oc[1].m4ac.sample_rate != m4ac.sample_rate || - ac->oc[1].m4ac.chan_config != m4ac.chan_config) { + ac->oc[1].m4ac.sample_rate != m4ac->sample_rate || + ac->oc[1].m4ac.chan_config != m4ac->chan_config) { if (latmctx->initialized) { - av_log(avctx, AV_LOG_INFO, "audio config changed (sample_rate=%d, chan_config=%d)\n", m4ac.sample_rate, m4ac.chan_config); + av_log(avctx, AV_LOG_INFO, "audio config changed (sample_rate=%d, chan_config=%d)\n", + m4ac->sample_rate, m4ac->chan_config); } else { av_log(avctx, AV_LOG_DEBUG, "initializing latmctx\n"); } @@ -507,7 +282,7 @@ static int latm_decode_frame(AVCodecContext *avctx, AVFrame *out, } else { push_output_configuration(&latmctx->aac_ctx); if ((err = decode_audio_specific_config( - &latmctx->aac_ctx, avctx, &latmctx->aac_ctx.oc[1].m4ac, + &latmctx->aac_ctx, avctx, &latmctx->aac_ctx.oc[1], avctx->extradata, avctx->extradata_size*8LL, 1)) < 0) { pop_output_configuration(&latmctx->aac_ctx); return err; @@ -542,7 +317,7 @@ static int latm_decode_frame(AVCodecContext *avctx, AVFrame *out, static av_cold int latm_decode_init(AVCodecContext *avctx) { struct LATMContext *latmctx = avctx->priv_data; - int ret = aac_decode_init(avctx); + int ret = ff_aac_decode_init_float(avctx); if (avctx->extradata_size > 0) latmctx->initialized = !ret; @@ -550,26 +325,6 @@ static av_cold int latm_decode_init(AVCodecContext *avctx) return ret; } -const FFCodec ff_aac_decoder = { - .p.name = "aac", - CODEC_LONG_NAME("AAC (Advanced Audio Coding)"), - .p.type = AVMEDIA_TYPE_AUDIO, - .p.id = AV_CODEC_ID_AAC, - .priv_data_size = sizeof(AACDecContext), - .init = aac_decode_init, - .close = aac_decode_close, - FF_CODEC_DECODE_CB(aac_decode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE - }, - .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, - .flush = flush, - .p.priv_class = &aac_decoder_class, - .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), -}; - /* Note: This decoder filter is intended to decode LATM streams transferred in MPEG transport streams which only contain one program. @@ -582,7 +337,7 @@ const FFCodec ff_aac_latm_decoder = { .p.id = AV_CODEC_ID_AAC_LATM, .priv_data_size = sizeof(struct LATMContext), .init = latm_decode_init, - .close = aac_decode_close, + .close = decode_close, FF_CODEC_DECODE_CB(latm_decode_frame), .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE @@ -593,3 +348,5 @@ const FFCodec ff_aac_latm_decoder = { .flush = flush, .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }; + +#endif /* AVCODEC_AAC_AACDEC_LATM_H */ diff --git a/libavcodec/aac/aacdec_lpd.c b/libavcodec/aac/aacdec_lpd.c new file mode 100644 index 000000000..a4b91a510 --- /dev/null +++ b/libavcodec/aac/aacdec_lpd.c @@ -0,0 +1,201 @@ +/* + * 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 "aacdec_lpd.h" +#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) { + for (int k = 0; k < no_qn; k++) { + qn[k] = get_unary(gb, 0, 68); // TODO: find proper ranges + if (qn[k]) + qn[k]++; + } + return; + } + + for (int k = 0; k < no_qn; k++) + qn[k] = get_bits(gb, 2) + 2; + + if (nk_mode == 2) { + for (int k = 0; k < no_qn; k++) { + if (qn[k] > 4) { + qn[k] = get_unary(gb, 0, 65); + if (qn[k]) + qn[k] += 4; + } + } + return; + } + + for (int k = 0; k < no_qn; k++) { + if (qn[k] > 4) { + int qn_ext = get_unary(gb, 0, 65); + switch (qn_ext) { + case 0: qn[k] = 5; break; + case 1: qn[k] = 6; break; + case 2: qn[k] = 0; break; + default: qn[k] = qn_ext + 4; break; + } + } + } +} + +static int parse_codebook_idx(GetBitContext *gb, uint32_t *kv, + int nk_mode, int no_qn) +{ + int n, nk; + + int qn[2]; + parse_qn(gb, qn, nk_mode, no_qn); + + for (int k = 0; k < no_qn; k++) { + if (qn[k] > 4) { + nk = (qn[k] - 3) / 2; + n = qn[k] - nk*2; + } else { + nk = 0; + n = qn[k]; + } + } + + if (nk > 25) + return AVERROR_PATCHWELCOME; + + skip_bits(gb, 4*n); + + if (nk > 0) + for (int i = 0; i < 8; i++) + kv[i] = get_bits(gb, nk); + + return 0; +} + +int ff_aac_parse_fac_data(AACUsacElemData *ce, GetBitContext *gb, + int use_gain, int len) +{ + int ret; + if (use_gain) + ce->fac.gain = get_bits(gb, 7); + + if (len/8 > 8) + return AVERROR_PATCHWELCOME; + + for (int i = 0; i < len/8; i++) { + ret = parse_codebook_idx(gb, ce->fac.kv[i], 1, 1); + if (ret < 0) + return ret; + } + + return 0; +} + +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); + ce->ldp.lpd_mode = get_bits(gb, 5); + + ce->ldp.bpf_control_info = get_bits1(gb); + 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; + uint16_t fac_len = get_bits1(gb) /* short_fac_flag */ ? len_8 : len_16; + int ret = ff_aac_parse_fac_data(ce, gb, 1, fac_len); + if (ret < 0) + return ret; + } + + return 0; +} diff --git a/libavcodec/aac/aacdec_lpd.h b/libavcodec/aac/aacdec_lpd.h new file mode 100644 index 000000000..924ff75e5 --- /dev/null +++ b/libavcodec/aac/aacdec_lpd.h @@ -0,0 +1,33 @@ +/* + * 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_AAC_AACDEC_LPD_H +#define AVCODEC_AAC_AACDEC_LPD_H + +#include "aacdec.h" +#include "libavcodec/get_bits.h" + +int ff_aac_parse_fac_data(AACUsacElemData *ce, GetBitContext *gb, + int use_gain, int len); + +int ff_aac_ldp_parse_channel_stream(AACDecContext *ac, AACUSACConfig *usac, + AACUsacElemData *ce, GetBitContext *gb); + +#endif /* AVCODEC_AAC_AACDEC_LPD_H */ diff --git a/libavcodec/aac/aacdec_proc_template.c b/libavcodec/aac/aacdec_proc_template.c new file mode 100644 index 000000000..327f3117b --- /dev/null +++ b/libavcodec/aac/aacdec_proc_template.c @@ -0,0 +1,448 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * linear congruential pseudorandom number generator + * + * @param previous_val pointer to the current state of the generator + * + * @return Returns a 32-bit pseudorandom integer + */ +static av_always_inline int lcg_random(unsigned previous_val) +{ + union { unsigned u; int s; } v = { previous_val * 1664525u + 1013904223 }; + return v.s; +} + +/** + * Decode spectral data; reference: table 4.50. + * Dequantize and scale spectral data; reference: 4.6.3.3. + * + * @param coef array of dequantized, scaled spectral data + * @param sf array of scalefactors or intensity stereo positions + * @param pulse_present set if pulses are present + * @param pulse pointer to pulse data struct + * @param band_type array of the used band type + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int AAC_RENAME(decode_spectrum_and_dequant)(AACDecContext *ac, + GetBitContext *gb, + const Pulse *pulse, + SingleChannelElement *sce) +{ + int i, k, g, idx = 0; + INTFLOAT *coef = sce->AAC_RENAME(coeffs); + IndividualChannelStream *ics = &sce->ics; + const int c = 1024 / ics->num_windows; + const uint16_t *offsets = ics->swb_offset; + const INTFLOAT *sf = sce->AAC_RENAME(sf); + const enum BandType *band_type = sce->band_type; + INTFLOAT *coef_base = coef; + + for (g = 0; g < ics->num_windows; g++) + memset(coef + g * 128 + offsets[ics->max_sfb], 0, + sizeof(INTFLOAT) * (c - offsets[ics->max_sfb])); + + for (g = 0; g < ics->num_window_groups; g++) { + unsigned g_len = ics->group_len[g]; + + for (i = 0; i < ics->max_sfb; i++, idx++) { + const unsigned cbt_m1 = band_type[idx] - 1; + INTFLOAT *cfo = coef + offsets[i]; + int off_len = offsets[i + 1] - offsets[i]; + int group; + + if (cbt_m1 >= INTENSITY_BT2 - 1) { + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + memset(cfo, 0, off_len * sizeof(*cfo)); + } + } else if (cbt_m1 == NOISE_BT - 1) { + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT band_energy; +#if USE_FIXED + for (k = 0; k < off_len; k++) { + ac->random_state = lcg_random(ac->random_state); + cfo[k] = ac->random_state >> 3; + } + + band_energy = ac->fdsp->scalarproduct_fixed(cfo, cfo, off_len); + band_energy = fixed_sqrt(band_energy, 31); + noise_scale(cfo, sf[idx], band_energy, off_len); +#else + float scale; + + for (k = 0; k < off_len; k++) { + ac->random_state = lcg_random(ac->random_state); + cfo[k] = ac->random_state; + } + + band_energy = ac->fdsp->scalarproduct_float(cfo, cfo, off_len); + scale = sf[idx] / sqrtf(band_energy); + ac->fdsp->vector_fmul_scalar(cfo, cfo, scale, off_len); +#endif /* USE_FIXED */ + } + } else { +#if !USE_FIXED + const float *vq = ff_aac_codebook_vector_vals[cbt_m1]; +#endif /* !USE_FIXED */ + const VLCElem *vlc_tab = ff_vlc_spectral[cbt_m1]; + OPEN_READER(re, gb); + + switch (cbt_m1 >> 1) { + case 0: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT *cf = cfo; + int len = off_len; + + do { + int code; + unsigned cb_idx; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + cb_idx = code; +#if USE_FIXED + cf = DEC_SQUAD(cf, cb_idx); +#else + cf = VMUL4(cf, vq, cb_idx, sf + idx); +#endif /* USE_FIXED */ + } while (len -= 4); + } + break; + + case 1: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT *cf = cfo; + int len = off_len; + + do { + int code; + unsigned nnz; + unsigned cb_idx; + uint32_t bits; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + cb_idx = code; + nnz = cb_idx >> 8 & 15; + bits = nnz ? GET_CACHE(re, gb) : 0; + LAST_SKIP_BITS(re, gb, nnz); +#if USE_FIXED + cf = DEC_UQUAD(cf, cb_idx, bits); +#else + cf = VMUL4S(cf, vq, cb_idx, bits, sf + idx); +#endif /* USE_FIXED */ + } while (len -= 4); + } + break; + + case 2: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT *cf = cfo; + int len = off_len; + + do { + int code; + unsigned cb_idx; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + cb_idx = code; +#if USE_FIXED + cf = DEC_SPAIR(cf, cb_idx); +#else + cf = VMUL2(cf, vq, cb_idx, sf + idx); +#endif /* USE_FIXED */ + } while (len -= 2); + } + break; + + case 3: + case 4: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT *cf = cfo; + int len = off_len; + + do { + int code; + unsigned nnz; + unsigned cb_idx; + unsigned sign; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + cb_idx = code; + nnz = cb_idx >> 8 & 15; + sign = nnz ? SHOW_UBITS(re, gb, nnz) << (cb_idx >> 12) : 0; + LAST_SKIP_BITS(re, gb, nnz); +#if USE_FIXED + cf = DEC_UPAIR(cf, cb_idx, sign); +#else + cf = VMUL2S(cf, vq, cb_idx, sign, sf + idx); +#endif /* USE_FIXED */ + } while (len -= 2); + } + break; + + default: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { +#if USE_FIXED + int *icf = cfo; + int v; +#else + float *cf = cfo; + uint32_t *icf = (uint32_t *) cf; +#endif /* USE_FIXED */ + int len = off_len; + + do { + int code; + unsigned nzt, nnz; + unsigned cb_idx; + uint32_t bits; + int j; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + cb_idx = code; + + if (cb_idx == 0x0000) { + *icf++ = 0; + *icf++ = 0; + continue; + } + + nnz = cb_idx >> 12; + nzt = cb_idx >> 8; + bits = SHOW_UBITS(re, gb, nnz) << (32-nnz); + LAST_SKIP_BITS(re, gb, nnz); + + for (j = 0; j < 2; j++) { + if (nzt & 1< 8) { + av_log(ac->avctx, AV_LOG_ERROR, "error in spectral data, ESC overflow\n"); + return AVERROR_INVALIDDATA; + } + + SKIP_BITS(re, gb, b + 1); + b += 4; + n = (1 << b) + SHOW_UBITS(re, gb, b); + LAST_SKIP_BITS(re, gb, b); +#if USE_FIXED + v = n; + if (bits & 1U<<31) + v = -v; + *icf++ = v; +#else + *icf++ = ff_cbrt_tab[n] | (bits & 1U<<31); +#endif /* USE_FIXED */ + bits <<= 1; + } else { +#if USE_FIXED + v = cb_idx & 15; + if (bits & 1U<<31) + v = -v; + *icf++ = v; +#else + unsigned v = ((const uint32_t*)vq)[cb_idx & 15]; + *icf++ = (bits & 1U<<31) | v; +#endif /* USE_FIXED */ + bits <<= !!v; + } + cb_idx >>= 4; + } + } while (len -= 2); +#if !USE_FIXED + ac->fdsp->vector_fmul_scalar(cfo, cfo, sf[idx], off_len); +#endif /* !USE_FIXED */ + } + } + + CLOSE_READER(re, gb); + } + } + coef += g_len << 7; + } + + if (pulse) { + idx = 0; + for (i = 0; i < pulse->num_pulse; i++) { + INTFLOAT co = coef_base[ pulse->pos[i] ]; + while (offsets[idx + 1] <= pulse->pos[i]) + idx++; + if (band_type[idx] != NOISE_BT && sf[idx]) { + INTFLOAT ico = -pulse->amp[i]; +#if USE_FIXED + if (co) { + ico = co + (co > 0 ? -ico : ico); + } + coef_base[ pulse->pos[i] ] = ico; +#else + if (co) { + co /= sf[idx]; + ico = co / sqrtf(sqrtf(fabsf(co))) + (co > 0 ? -ico : ico); + } + coef_base[ pulse->pos[i] ] = cbrtf(fabsf(ico)) * ico * sf[idx]; +#endif /* USE_FIXED */ + } + } + } +#if USE_FIXED + coef = coef_base; + idx = 0; + for (g = 0; g < ics->num_window_groups; g++) { + unsigned g_len = ics->group_len[g]; + + for (i = 0; i < ics->max_sfb; i++, idx++) { + const unsigned cbt_m1 = band_type[idx] - 1; + int *cfo = coef + offsets[i]; + int off_len = offsets[i + 1] - offsets[i]; + int group; + + if (cbt_m1 < NOISE_BT - 1) { + for (group = 0; group < (int)g_len; group++, cfo+=128) { + vector_pow43(cfo, off_len); + subband_scale(cfo, cfo, sf[idx], 34, off_len, ac->avctx); + } + } + } + coef += g_len << 7; + } +#endif /* USE_FIXED */ + return 0; +} + +/** + * Decode coupling_channel_element; reference: table 4.8. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int AAC_RENAME(decode_cce)(AACDecContext *ac, GetBitContext *gb, ChannelElement *che) +{ + int num_gain = 0; + int c, g, sfb, ret; + int sign; + INTFLOAT scale; + SingleChannelElement *sce = &che->ch[0]; + ChannelCoupling *coup = &che->coup; + + coup->coupling_point = 2 * get_bits1(gb); + coup->num_coupled = get_bits(gb, 3); + for (c = 0; c <= coup->num_coupled; c++) { + num_gain++; + coup->type[c] = get_bits1(gb) ? TYPE_CPE : TYPE_SCE; + coup->id_select[c] = get_bits(gb, 4); + if (coup->type[c] == TYPE_CPE) { + coup->ch_select[c] = get_bits(gb, 2); + if (coup->ch_select[c] == 3) + num_gain++; + } else + coup->ch_select[c] = 2; + } + coup->coupling_point += get_bits1(gb) || (coup->coupling_point >> 1); + + sign = get_bits(gb, 1); +#if USE_FIXED + scale = get_bits(gb, 2); +#else + scale = cce_scale[get_bits(gb, 2)]; +#endif + + if ((ret = ff_aac_decode_ics(ac, sce, gb, 0, 0))) + return ret; + + for (c = 0; c < num_gain; c++) { + int idx = 0; + int cge = 1; + int gain = 0; + INTFLOAT gain_cache = FIXR10(1.); + if (c) { + cge = coup->coupling_point == AFTER_IMDCT ? 1 : get_bits1(gb); + gain = cge ? get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - 60: 0; + gain_cache = GET_GAIN(scale, gain); +#if USE_FIXED + if ((abs(gain_cache)-1024) >> 3 > 30) + return AVERROR(ERANGE); +#endif + } + if (coup->coupling_point == AFTER_IMDCT) { + coup->gain[c][0] = gain_cache; + } else { + for (g = 0; g < sce->ics.num_window_groups; g++) { + for (sfb = 0; sfb < sce->ics.max_sfb; sfb++, idx++) { + if (sce->band_type[idx] != ZERO_BT) { + if (!cge) { + int t = get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - 60; + if (t) { + int s = 1; + t = gain += t; + if (sign) { + s -= 2 * (t & 0x1); + t >>= 1; + } + gain_cache = GET_GAIN(scale, t) * s; +#if USE_FIXED + if ((abs(gain_cache)-1024) >> 3 > 30) + return AVERROR(ERANGE); +#endif + } + } + coup->gain[c][idx] = gain_cache; + } + } + } + } + } + return 0; +} + +static av_cold void AAC_RENAME(aac_proc_init)(AACDecProc *aac_proc) +{ +#define SET(member) aac_proc->member = AAC_RENAME(member) + SET(decode_spectrum_and_dequant); + SET(decode_cce); +#undef SET +#define SET(member) aac_proc->member = AV_JOIN(ff_aac_, AAC_RENAME(member)); + SET(sbr_ctx_alloc_init); + SET(sbr_decode_extension); + SET(sbr_apply); + SET(sbr_ctx_close); +#undef SET +} diff --git a/libavcodec/aacdec_common.c b/libavcodec/aac/aacdec_tab.c similarity index 99% rename from libavcodec/aacdec_common.c rename to libavcodec/aac/aacdec_tab.c index 145c71804..45a84a9a7 100644 --- a/libavcodec/aacdec_common.c +++ b/libavcodec/aac/aacdec_tab.c @@ -25,11 +25,12 @@ * Common code and tables of the AAC fixed- and floating-point decoders */ -#include "aac.h" -#include "aacdectab.h" -#include "aacps.h" -#include "aactab.h" -#include "vlc.h" +#include "aacdec_tab.h" + +#include "libavcodec/aac.h" +#include "libavcodec/aacps.h" +#include "libavcodec/aactab.h" +#include "libavcodec/vlc.h" #include "libavutil/attributes.h" #include "libavutil/thread.h" diff --git a/libavcodec/aacdectab.h b/libavcodec/aac/aacdec_tab.h similarity index 91% rename from libavcodec/aacdectab.h rename to libavcodec/aac/aacdec_tab.h index 184508f2f..70e49af20 100644 --- a/libavcodec/aacdectab.h +++ b/libavcodec/aac/aacdec_tab.h @@ -25,12 +25,12 @@ * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) */ -#ifndef AVCODEC_AACDECTAB_H -#define AVCODEC_AACDECTAB_H +#ifndef AVCODEC_AAC_AACDEC_TAB_H +#define AVCODEC_AAC_AACDEC_TAB_H #include -#include "vlc.h" +#include "libavcodec/vlc.h" #include "libavutil/attributes_internal.h" #include "libavutil/channel_layout.h" @@ -52,4 +52,4 @@ extern const int16_t ff_aac_channel_map[3][4][6]; extern const AVChannelLayout ff_aac_ch_layout[]; FF_VISIBILITY_POP_HIDDEN -#endif /* AVCODEC_AACDECTAB_H */ +#endif /* AVCODEC_AAC_AACDEC_TAB_H */ diff --git a/libavcodec/aac/aacdec_usac.c b/libavcodec/aac/aacdec_usac.c new file mode 100644 index 000000000..ccdf58bc8 --- /dev/null +++ b/libavcodec/aac/aacdec_usac.c @@ -0,0 +1,1786 @@ +/* + * 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 "aacdec_usac.h" +#include "aacdec_tab.h" +#include "aacdec_lpd.h" +#include "aacdec_ac.h" + +#include "libavcodec/aacsbr.h" + +#include "libavcodec/aactab.h" +#include "libavutil/mem.h" +#include "libavcodec/mpeg4audio.h" +#include "libavcodec/unary.h" + +/* Number of scalefactor bands per complex prediction band, equal to 2. */ +#define SFB_PER_PRED_BAND 2 + +static inline uint32_t get_escaped_value(GetBitContext *gb, int nb1, int nb2, int nb3) +{ + uint32_t val = get_bits(gb, nb1), val2; + if (val < ((1 << nb1) - 1)) + return val; + + val += val2 = get_bits(gb, nb2); + if (nb3 && (val2 == ((1 << nb2) - 1))) + val += get_bits(gb, nb3); + + return val; +} + +/* ISO/IEC 23003-3, Table 74 — bsOutputChannelPos */ +static const enum AVChannel usac_ch_pos_to_av[64] = { + [0] = AV_CHAN_FRONT_LEFT, + [1] = AV_CHAN_FRONT_RIGHT, + [2] = AV_CHAN_FRONT_CENTER, + [3] = AV_CHAN_LOW_FREQUENCY, + [4] = AV_CHAN_SIDE_LEFT, // +110 degrees, Ls|LS|kAudioChannelLabel_LeftSurround + [5] = AV_CHAN_SIDE_RIGHT, // -110 degrees, Rs|RS|kAudioChannelLabel_RightSurround + [6] = AV_CHAN_FRONT_LEFT_OF_CENTER, + [7] = AV_CHAN_FRONT_RIGHT_OF_CENTER, + [8] = AV_CHAN_BACK_LEFT, // +135 degrees, Lsr|BL|kAudioChannelLabel_RearSurroundLeft + [9] = AV_CHAN_BACK_RIGHT, // -135 degrees, Rsr|BR|kAudioChannelLabel_RearSurroundRight + [10] = AV_CHAN_BACK_CENTER, + [11] = AV_CHAN_SURROUND_DIRECT_LEFT, + [12] = AV_CHAN_SURROUND_DIRECT_RIGHT, + [13] = AV_CHAN_SIDE_SURROUND_LEFT, // +90 degrees, Lss|SL|kAudioChannelLabel_LeftSideSurround + [14] = AV_CHAN_SIDE_SURROUND_RIGHT, // -90 degrees, Rss|SR|kAudioChannelLabel_RightSideSurround + [15] = AV_CHAN_WIDE_LEFT, // +60 degrees, Lw|FLw|kAudioChannelLabel_LeftWide + [16] = AV_CHAN_WIDE_RIGHT, // -60 degrees, Rw|FRw|kAudioChannelLabel_RightWide + [17] = AV_CHAN_TOP_FRONT_LEFT, + [18] = AV_CHAN_TOP_FRONT_RIGHT, + [19] = AV_CHAN_TOP_FRONT_CENTER, + [20] = AV_CHAN_TOP_BACK_LEFT, + [21] = AV_CHAN_TOP_BACK_RIGHT, + [22] = AV_CHAN_TOP_BACK_CENTER, + [23] = AV_CHAN_TOP_SIDE_LEFT, + [24] = AV_CHAN_TOP_SIDE_RIGHT, + [25] = AV_CHAN_TOP_CENTER, + [26] = AV_CHAN_LOW_FREQUENCY_2, + [27] = AV_CHAN_BOTTOM_FRONT_LEFT, + [28] = AV_CHAN_BOTTOM_FRONT_RIGHT, + [29] = AV_CHAN_BOTTOM_FRONT_CENTER, + [30] = AV_CHAN_TOP_SURROUND_LEFT, ///< +110 degrees, Lvs, TpLS + [31] = AV_CHAN_TOP_SURROUND_RIGHT, ///< -110 degrees, Rvs, TpRS +}; + +static int decode_loudness_info(AACDecContext *ac, AACUSACLoudnessInfo *info, + GetBitContext *gb) +{ + info->drc_set_id = get_bits(gb, 6); + info->downmix_id = get_bits(gb, 7); + + if ((info->sample_peak.present = get_bits1(gb))) /* samplePeakLevelPresent */ + info->sample_peak.lvl = get_bits(gb, 12); + + if ((info->true_peak.present = get_bits1(gb))) { /* truePeakLevelPresent */ + info->true_peak.lvl = get_bits(gb, 12); + info->true_peak.measurement = get_bits(gb, 4); + info->true_peak.reliability = get_bits(gb, 2); + } + + info->nb_measurements = get_bits(gb, 4); + for (int i = 0; i < info->nb_measurements; i++) { + info->measurements[i].method_def = get_bits(gb, 4); + info->measurements[i].method_val = get_unary(gb, 0, 8); + info->measurements[i].measurement = get_bits(gb, 4); + info->measurements[i].reliability = get_bits(gb, 2); + } + + return 0; +} + +static int decode_loudness_set(AACDecContext *ac, AACUSACConfig *usac, + GetBitContext *gb) +{ + int ret; + + usac->loudness.nb_album = get_bits(gb, 6); /* loudnessInfoAlbumCount */ + usac->loudness.nb_info = get_bits(gb, 6); /* loudnessInfoCount */ + + for (int i = 0; i < usac->loudness.nb_album; i++) { + ret = decode_loudness_info(ac, &usac->loudness.album_info[i], gb); + if (ret < 0) + return ret; + } + + for (int i = 0; i < usac->loudness.nb_info; i++) { + ret = decode_loudness_info(ac, &usac->loudness.info[i], gb); + if (ret < 0) + return ret; + } + + if (get_bits1(gb)) { /* loudnessInfoSetExtPresent */ + enum AACUSACLoudnessExt type; + while ((type = get_bits(gb, 4)) != UNIDRCLOUDEXT_TERM) { + uint8_t size_bits = get_bits(gb, 4) + 4; + uint8_t bit_size = get_bits(gb, size_bits) + 1; + switch (type) { + case UNIDRCLOUDEXT_EQ: + avpriv_report_missing_feature(ac->avctx, "loudnessInfoV1"); + return AVERROR_PATCHWELCOME; + default: + for (int i = 0; i < bit_size; i++) + skip_bits1(gb); + } + } + } + + return 0; +} + +static int decode_usac_sbr_data(AACDecContext *ac, + AACUsacElemConfig *e, GetBitContext *gb) +{ + uint8_t header_extra1; + uint8_t header_extra2; + + e->sbr.harmonic_sbr = get_bits1(gb); /* harmonicSBR */ + e->sbr.bs_intertes = get_bits1(gb); /* bs_interTes */ + e->sbr.bs_pvc = get_bits1(gb); /* bs_pvc */ + if (e->sbr.harmonic_sbr || e->sbr.bs_intertes || e->sbr.bs_pvc) { + avpriv_report_missing_feature(ac->avctx, "AAC USAC eSBR"); + return AVERROR_PATCHWELCOME; + } + + e->sbr.dflt.start_freq = get_bits(gb, 4); /* dflt_start_freq */ + e->sbr.dflt.stop_freq = get_bits(gb, 4); /* dflt_stop_freq */ + + header_extra1 = get_bits1(gb); /* dflt_header_extra1 */ + header_extra2 = get_bits1(gb); /* dflt_header_extra2 */ + + e->sbr.dflt.freq_scale = 2; + e->sbr.dflt.alter_scale = 1; + e->sbr.dflt.noise_bands = 2; + if (header_extra1) { + e->sbr.dflt.freq_scale = get_bits(gb, 2); /* dflt_freq_scale */ + e->sbr.dflt.alter_scale = get_bits1(gb); /* dflt_alter_scale */ + e->sbr.dflt.noise_bands = get_bits(gb, 2); /* dflt_noise_bands */ + } + + e->sbr.dflt.limiter_bands = 2; + e->sbr.dflt.limiter_gains = 2; + e->sbr.dflt.interpol_freq = 1; + e->sbr.dflt.smoothing_mode = 1; + if (header_extra2) { + e->sbr.dflt.limiter_bands = get_bits(gb, 2); /* dflt_limiter_bands */ + e->sbr.dflt.limiter_gains = get_bits(gb, 2); /* dflt_limiter_gains */ + e->sbr.dflt.interpol_freq = get_bits1(gb); /* dflt_interpol_freq */ + e->sbr.dflt.smoothing_mode = get_bits1(gb); /* dflt_smoothing_mode */ + } + + return 0; +} + +static void decode_usac_element_core(AACUsacElemConfig *e, + GetBitContext *gb, + int sbr_ratio) +{ + e->tw_mdct = get_bits1(gb); /* tw_mdct */ + e->noise_fill = get_bits1(gb); + e->sbr.ratio = sbr_ratio; +} + +static int decode_usac_element_pair(AACDecContext *ac, + AACUsacElemConfig *e, GetBitContext *gb) +{ + e->stereo_config_index = 0; + if (e->sbr.ratio) { + int ret = decode_usac_sbr_data(ac, e, gb); + if (ret < 0) + return ret; + e->stereo_config_index = get_bits(gb, 2); + } + + if (e->stereo_config_index) { + e->mps.freq_res = get_bits(gb, 3); /* bsFreqRes */ + e->mps.fixed_gain = get_bits(gb, 3); /* bsFixedGainDMX */ + e->mps.temp_shape_config = get_bits(gb, 2); /* bsTempShapeConfig */ + e->mps.decorr_config = get_bits(gb, 2); /* bsDecorrConfig */ + e->mps.high_rate_mode = get_bits1(gb); /* bsHighRateMode */ + e->mps.phase_coding = get_bits1(gb); /* bsPhaseCoding */ + + if (get_bits1(gb)) /* bsOttBandsPhasePresent */ + e->mps.otts_bands_phase = get_bits(gb, 5); /* bsOttBandsPhase */ + + e->mps.residual_coding = e->stereo_config_index >= 2; /* bsResidualCoding */ + if (e->mps.residual_coding) { + e->mps.residual_bands = get_bits(gb, 5); /* bsResidualBands */ + e->mps.pseudo_lr = get_bits1(gb); /* bsPseudoLr */ + } + if (e->mps.temp_shape_config == 2) + e->mps.env_quant_mode = get_bits1(gb); /* bsEnvQuantMode */ + } + + return 0; +} + +static int decode_usac_extension(AACDecContext *ac, AACUsacElemConfig *e, + GetBitContext *gb) +{ + int len = 0, ext_config_len; + + e->ext.type = get_escaped_value(gb, 4, 8, 16); /* usacExtElementType */ + ext_config_len = get_escaped_value(gb, 4, 8, 16); /* usacExtElementConfigLength */ + + if (get_bits1(gb)) /* usacExtElementDefaultLengthPresent */ + len = get_escaped_value(gb, 8, 16, 0) + 1; + + e->ext.default_len = len; + e->ext.payload_frag = get_bits1(gb); /* usacExtElementPayloadFrag */ + + av_log(ac->avctx, AV_LOG_DEBUG, "Extension present: type %i, len %i\n", + e->ext.type, ext_config_len); + + switch (e->ext.type) { +#if 0 /* Skip unsupported values */ + case ID_EXT_ELE_MPEGS: + break; + case ID_EXT_ELE_SAOC: + break; + case ID_EXT_ELE_UNI_DRC: + break; +#endif + case ID_EXT_ELE_FILL: + break; /* This is what the spec does */ + case ID_EXT_ELE_AUDIOPREROLL: + /* No configuration needed - fallthrough (len should be 0) */ + default: + skip_bits(gb, 8*ext_config_len); + e->ext.type = ID_EXT_ELE_FILL; + break; + }; + + return 0; +} + +int ff_aac_usac_reset_state(AACDecContext *ac, OutputConfiguration *oc) +{ + AACUSACConfig *usac = &oc->usac; + int elem_id[3 /* SCE, CPE, LFE */] = { 0, 0, 0 }; + + ChannelElement *che; + enum RawDataBlockType type; + int id, ch; + + /* Initialize state */ + for (int i = 0; i < usac->nb_elems; i++) { + AACUsacElemConfig *e = &usac->elems[i]; + if (e->type == ID_USAC_EXT) + continue; + + switch (e->type) { + case ID_USAC_SCE: + ch = 1; + type = TYPE_SCE; + id = elem_id[0]++; + break; + case ID_USAC_CPE: + ch = 2; + type = TYPE_CPE; + id = elem_id[1]++; + break; + case ID_USAC_LFE: + ch = 1; + type = TYPE_LFE; + id = elem_id[2]++; + break; + } + + che = ff_aac_get_che(ac, type, id); + if (che) { + AACUsacStereo *us = &che->us; + memset(us, 0, sizeof(*us)); + + if (e->sbr.ratio) + ff_aac_sbr_config_usac(ac, che, e); + + for (int j = 0; j < ch; j++) { + SingleChannelElement *sce = &che->ch[ch]; + AACUsacElemData *ue = &sce->ue; + + memset(ue, 0, sizeof(*ue)); + + if (!ch) + ue->noise.seed = 0x3039; + else + che->ch[1].ue.noise.seed = 0x10932; + } + } + } + + return 0; +} + +/* UsacConfig */ +int ff_aac_usac_config_decode(AACDecContext *ac, AVCodecContext *avctx, + GetBitContext *gb, OutputConfiguration *oc, + int channel_config) +{ + int ret; + uint8_t freq_idx; + uint8_t channel_config_idx; + int nb_channels = 0; + int ratio_mult, ratio_dec; + int samplerate; + int sbr_ratio; + MPEG4AudioConfig *m4ac = &oc->m4ac; + AACUSACConfig *usac = &oc->usac; + int elem_id[3 /* SCE, CPE, LFE */]; + + int map_pos_set = 0; + uint8_t layout_map[MAX_ELEM_ID*4][3] = { 0 }; + + if (!ac) + return AVERROR_PATCHWELCOME; + + memset(usac, 0, sizeof(*usac)); + + freq_idx = get_bits(gb, 5); /* usacSamplingFrequencyIndex */ + if (freq_idx == 0x1f) { + samplerate = get_bits(gb, 24); /* usacSamplingFrequency */ + } else { + samplerate = ff_aac_usac_samplerate[freq_idx]; + if (samplerate < 0) + return AVERROR(EINVAL); + } + + usac->core_sbr_frame_len_idx = get_bits(gb, 3); /* coreSbrFrameLengthIndex */ + m4ac->frame_length_short = usac->core_sbr_frame_len_idx == 0 || + usac->core_sbr_frame_len_idx == 2; + + usac->core_frame_len = (usac->core_sbr_frame_len_idx == 0 || + usac->core_sbr_frame_len_idx == 2) ? 768 : 1024; + + sbr_ratio = usac->core_sbr_frame_len_idx == 2 ? 2 : + usac->core_sbr_frame_len_idx == 3 ? 3 : + usac->core_sbr_frame_len_idx == 4 ? 1 : + 0; + + if (sbr_ratio == 2) { + ratio_mult = 8; + ratio_dec = 3; + } else if (sbr_ratio == 3) { + ratio_mult = 2; + ratio_dec = 1; + } else if (sbr_ratio == 4) { + ratio_mult = 4; + ratio_dec = 1; + } else { + ratio_mult = 1; + ratio_dec = 1; + } + + avctx->sample_rate = samplerate; + m4ac->ext_sample_rate = samplerate; + m4ac->sample_rate = (samplerate * ratio_dec) / ratio_mult; + + m4ac->sampling_index = ff_aac_sample_rate_idx(m4ac->sample_rate); + m4ac->sbr = sbr_ratio > 0; + + channel_config_idx = get_bits(gb, 5); /* channelConfigurationIndex */ + if (!channel_config_idx) { + /* UsacChannelConfig() */ + nb_channels = get_escaped_value(gb, 5, 8, 16); /* numOutChannels */ + if (nb_channels > 64) + return AVERROR(EINVAL); + + av_channel_layout_uninit(&ac->oc[1].ch_layout); + + ret = av_channel_layout_custom_init(&ac->oc[1].ch_layout, nb_channels); + if (ret < 0) + return ret; + + for (int i = 0; i < nb_channels; i++) { + AVChannelCustom *cm = &ac->oc[1].ch_layout.u.map[i]; + cm->id = usac_ch_pos_to_av[get_bits(gb, 5)]; /* bsOutputChannelPos */ + } + + ret = av_channel_layout_retype(&ac->oc[1].ch_layout, + AV_CHANNEL_ORDER_NATIVE, + AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL); + if (ret < 0) + return ret; + + ret = av_channel_layout_copy(&avctx->ch_layout, &ac->oc[1].ch_layout); + if (ret < 0) + return ret; + } else { + int nb_elements; + if ((ret = ff_aac_set_default_channel_config(ac, avctx, layout_map, + &nb_elements, channel_config_idx))) + return ret; + + /* Fill in the number of expected channels */ + for (int i = 0; i < nb_elements; i++) + nb_channels += layout_map[i][0] == TYPE_CPE ? 2 : 1; + + map_pos_set = 1; + } + + /* UsacDecoderConfig */ + elem_id[0] = elem_id[1] = elem_id[2] = 0; + usac->nb_elems = get_escaped_value(gb, 4, 8, 16) + 1; + if (usac->nb_elems > 64) { + av_log(ac->avctx, AV_LOG_ERROR, "Too many elements: %i\n", + usac->nb_elems); + usac->nb_elems = 0; + return AVERROR(EINVAL); + } + + for (int i = 0; i < usac->nb_elems; i++) { + int map_count = elem_id[0] + elem_id[1] + elem_id[2]; + AACUsacElemConfig *e = &usac->elems[i]; + memset(e, 0, sizeof(*e)); + + e->type = get_bits(gb, 2); /* usacElementType */ + if (e->type != ID_USAC_EXT && (map_count + 1) > nb_channels) { + av_log(ac->avctx, AV_LOG_ERROR, "Too many channels for the channel " + "configuration\n"); + usac->nb_elems = 0; + return AVERROR(EINVAL); + } + + av_log(ac->avctx, AV_LOG_DEBUG, "Element present: idx %i, type %i\n", + i, e->type); + + switch (e->type) { + case ID_USAC_SCE: /* SCE */ + /* UsacCoreConfig */ + decode_usac_element_core(e, gb, sbr_ratio); + if (e->sbr.ratio > 0) { + ret = decode_usac_sbr_data(ac, e, gb); + if (ret < 0) + return ret; + } + layout_map[map_count][0] = TYPE_SCE; + layout_map[map_count][1] = elem_id[0]++; + if (!map_pos_set) + layout_map[map_count][2] = AAC_CHANNEL_FRONT; + + break; + case ID_USAC_CPE: /* UsacChannelPairElementConf */ + /* UsacCoreConfig */ + decode_usac_element_core(e, gb, sbr_ratio); + ret = decode_usac_element_pair(ac, e, gb); + if (ret < 0) + return ret; + layout_map[map_count][0] = TYPE_CPE; + layout_map[map_count][1] = elem_id[1]++; + if (!map_pos_set) + layout_map[map_count][2] = AAC_CHANNEL_FRONT; + + break; + case ID_USAC_LFE: /* LFE */ + /* LFE has no need for any configuration */ + e->tw_mdct = 0; + e->noise_fill = 0; + layout_map[map_count][0] = TYPE_LFE; + layout_map[map_count][1] = elem_id[2]++; + if (!map_pos_set) + layout_map[map_count][2] = AAC_CHANNEL_LFE; + + break; + case ID_USAC_EXT: /* EXT */ + ret = decode_usac_extension(ac, e, gb); + if (ret < 0) + return ret; + break; + }; + } + + ret = ff_aac_output_configure(ac, layout_map, elem_id[0] + elem_id[1] + elem_id[2], + OC_GLOBAL_HDR, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to parse channel config!\n"); + usac->nb_elems = 0; + return ret; + } + + if (get_bits1(gb)) { /* usacConfigExtensionPresent */ + int invalid; + int nb_extensions = get_escaped_value(gb, 2, 4, 8) + 1; /* numConfigExtensions */ + for (int i = 0; i < nb_extensions; i++) { + int type = get_escaped_value(gb, 4, 8, 16); + int len = get_escaped_value(gb, 4, 8, 16); + switch (type) { + case ID_CONFIG_EXT_LOUDNESS_INFO: + ret = decode_loudness_set(ac, usac, gb); + if (ret < 0) + return ret; + break; + case ID_CONFIG_EXT_STREAM_ID: + usac->stream_identifier = get_bits(gb, 16); + break; + case ID_CONFIG_EXT_FILL: /* fallthrough */ + invalid = 0; + while (len--) { + if (get_bits(gb, 8) != 0xA5) + invalid++; + } + if (invalid) + av_log(avctx, AV_LOG_WARNING, "Invalid fill bytes: %i\n", + invalid); + break; + default: + while (len--) + skip_bits(gb, 8); + break; + } + } + } + + ac->avctx->profile = AV_PROFILE_AAC_USAC; + + ret = ff_aac_usac_reset_state(ac, oc); + if (ret < 0) + return ret; + + return 0; +} + +static int decode_usac_scale_factors(AACDecContext *ac, + SingleChannelElement *sce, + GetBitContext *gb, uint8_t global_gain) +{ + IndividualChannelStream *ics = &sce->ics; + + /* Decode all scalefactors. */ + int offset_sf = global_gain; + for (int g = 0; g < ics->num_window_groups; g++) { + for (int sfb = 0; sfb < ics->max_sfb; sfb++) { + if (g || sfb) + offset_sf += get_vlc2(gb, ff_vlc_scalefactors, 7, 3) - SCALE_DIFF_ZERO; + if (offset_sf > 255U) { + av_log(ac->avctx, AV_LOG_ERROR, + "Scalefactor (%d) out of range.\n", offset_sf); + return AVERROR_INVALIDDATA; + } + + sce->sfo[g*ics->max_sfb + sfb] = offset_sf - 100; + } + } + + return 0; +} + +/** + * Decode and dequantize arithmetically coded, uniformly quantized value + * + * @param coef array of dequantized, scaled spectral data + * @param sf array of scalefactors or intensity stereo positions + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_spectrum_ac(AACDecContext *s, float coef[1024], + GetBitContext *gb, AACArithState *state, + int reset, uint16_t len, uint16_t N) +{ + AACArith ac; + int i, a, b; + uint32_t c; + + int gb_count; + GetBitContext gb2; + + c = ff_aac_ac_map_process(state, reset, N); + + if (!len) { + ff_aac_ac_finish(state, 0, N); + return 0; + } + + ff_aac_ac_init(&ac, gb); + + /* Backup reader for rolling back by 14 bits at the end */ + gb2 = *gb; + gb_count = get_bits_count(&gb2); + + for (i = 0; i < len/2; i++) { + /* MSB */ + int lvl, esc_nb, m; + c = ff_aac_ac_get_context(state, c, i, N); + for (lvl=esc_nb=0;;) { + uint32_t pki = ff_aac_ac_get_pk(c + (esc_nb << 17)); + m = ff_aac_ac_decode(&ac, &gb2, ff_aac_ac_msb_cdfs[pki], + FF_ARRAY_ELEMS(ff_aac_ac_msb_cdfs[pki])); + if (m < FF_AAC_AC_ESCAPE) + break; + lvl++; + + /* Cargo-culted value. */ + if (lvl > 23) + return AVERROR(EINVAL); + + if ((esc_nb = lvl) > 7) + esc_nb = 7; + } + + b = m >> 2; + a = m - (b << 2); + + /* ARITH_STOP detection */ + if (!m) { + if (esc_nb) + break; + a = b = 0; + } + + /* LSB */ + for (int l = lvl; l > 0; l--) { + int lsbidx = !a ? 1 : (!b ? 0 : 2); + uint8_t r = ff_aac_ac_decode(&ac, &gb2, ff_aac_ac_lsb_cdfs[lsbidx], + FF_ARRAY_ELEMS(ff_aac_ac_lsb_cdfs[lsbidx])); + a = (a << 1) | (r & 1); + b = (b << 1) | ((r >> 1) & 1); + } + + /* Dequantize coeffs here */ + coef[2*i + 0] = a * cbrt(a); + coef[2*i + 1] = b * cbrt(b); + ff_aac_ac_update_context(state, i, a, b); + } + + if (len > 1) { + /* "Rewind" bitstream back by 14 bits */ + int gb_count2 = get_bits_count(&gb2); + skip_bits(gb, gb_count2 - gb_count - 14); + } else { + *gb = gb2; + } + + ff_aac_ac_finish(state, i, N); + + for (; i < N/2; i++) { + coef[2*i + 0] = 0; + coef[2*i + 1] = 0; + } + + /* Signs */ + for (i = 0; i < len; i++) { + if (coef[i]) { + if (!get_bits1(gb)) /* s */ + coef[i] *= -1; + } + } + + return 0; +} + +static int decode_usac_stereo_cplx(AACDecContext *ac, AACUsacStereo *us, + ChannelElement *cpe, GetBitContext *gb, + int num_window_groups, + int prev_num_window_groups, + int indep_flag) +{ + int delta_code_time; + IndividualChannelStream *ics = &cpe->ch[0].ics; + + if (!get_bits1(gb)) { /* cplx_pred_all */ + for (int g = 0; g < num_window_groups; g++) { + for (int sfb = 0; sfb < cpe->max_sfb_ste; sfb += SFB_PER_PRED_BAND) { + const uint8_t val = get_bits1(gb); + us->pred_used[g*cpe->max_sfb_ste + sfb] = val; + if ((sfb + 1) < cpe->max_sfb_ste) + us->pred_used[g*cpe->max_sfb_ste + sfb + 1] = val; + } + } + } else { + for (int g = 0; g < num_window_groups; g++) + for (int sfb = 0; sfb < cpe->max_sfb_ste; sfb++) + us->pred_used[g*cpe->max_sfb_ste + sfb] = 1; + } + + us->pred_dir = get_bits1(gb); + us->complex_coef = get_bits1(gb); + + us->use_prev_frame = 0; + if (us->complex_coef && !indep_flag) + us->use_prev_frame = get_bits1(gb); + + delta_code_time = 0; + if (!indep_flag) + delta_code_time = get_bits1(gb); + + /* TODO: shouldn't be needed */ + for (int g = 0; g < num_window_groups; g++) { + for (int sfb = 0; sfb < cpe->max_sfb_ste; sfb += SFB_PER_PRED_BAND) { + float last_alpha_q_re = 0; + float last_alpha_q_im = 0; + if (delta_code_time) { + if (g) { + /* Transient, after the first group - use the current frame, + * previous window, alpha values. */ + last_alpha_q_re = us->alpha_q_re[(g - 1)*cpe->max_sfb_ste + sfb]; + last_alpha_q_im = us->alpha_q_im[(g - 1)*cpe->max_sfb_ste + sfb]; + } else if (!g && + (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) && + (ics->window_sequence[1] == EIGHT_SHORT_SEQUENCE)) { + /* The spec doesn't explicitly mention this, but it doesn't make + * any other sense otherwise! */ + const int wg = prev_num_window_groups - 1; + last_alpha_q_re = us->prev_alpha_q_re[wg*cpe->max_sfb_ste + sfb]; + last_alpha_q_im = us->prev_alpha_q_im[wg*cpe->max_sfb_ste + sfb]; + } else { + last_alpha_q_re = us->prev_alpha_q_re[g*cpe->max_sfb_ste + sfb]; + last_alpha_q_im = us->prev_alpha_q_im[g*cpe->max_sfb_ste + sfb]; + } + } else { + if (sfb) { + last_alpha_q_re = us->alpha_q_re[g*cpe->max_sfb_ste + sfb - 1]; + last_alpha_q_im = us->alpha_q_im[g*cpe->max_sfb_ste + sfb - 1]; + } + } + + if (us->pred_used[g*cpe->max_sfb_ste + sfb]) { + int val = -get_vlc2(gb, ff_vlc_scalefactors, 7, 3) + 60; + last_alpha_q_re += val * 0.1f; + if (us->complex_coef) { + val = -get_vlc2(gb, ff_vlc_scalefactors, 7, 3) + 60; + last_alpha_q_im += val * 0.1f; + } + us->alpha_q_re[g*cpe->max_sfb_ste + sfb] = last_alpha_q_re; + us->alpha_q_im[g*cpe->max_sfb_ste + sfb] = last_alpha_q_im; + } else { + us->alpha_q_re[g*cpe->max_sfb_ste + sfb] = 0; + us->alpha_q_im[g*cpe->max_sfb_ste + sfb] = 0; + } + + if ((sfb + 1) < cpe->max_sfb_ste) { + us->alpha_q_re[g*cpe->max_sfb_ste + sfb + 1] = + us->alpha_q_re[g*cpe->max_sfb_ste + sfb]; + us->alpha_q_im[g*cpe->max_sfb_ste + sfb + 1] = + us->alpha_q_im[g*cpe->max_sfb_ste + sfb]; + } + } + } + + return 0; +} + +static int setup_sce(AACDecContext *ac, SingleChannelElement *sce, + AACUSACConfig *usac) +{ + AACUsacElemData *ue = &sce->ue; + IndividualChannelStream *ics = &sce->ics; + const int sampling_index = ac->oc[1].m4ac.sampling_index; + + /* Setup window parameters */ + ics->prev_num_window_groups = FFMAX(ics->num_window_groups, 1); + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + if (usac->core_frame_len == 768) { + ics->swb_offset = ff_swb_offset_96[sampling_index]; + ics->num_swb = ff_aac_num_swb_96[sampling_index]; + } else { + ics->swb_offset = ff_swb_offset_128[sampling_index]; + ics->num_swb = ff_aac_num_swb_128[sampling_index]; + } + ics->tns_max_bands = ff_tns_max_bands_usac_128[sampling_index]; + + /* Setup scalefactor grouping. 7 bit mask. */ + ics->num_window_groups = 0; + for (int j = 0; j < 7; j++) { + ics->group_len[j] = 1; + if (ue->scale_factor_grouping & (1 << (6 - j))) + ics->group_len[ics->num_window_groups] += 1; + else + ics->num_window_groups++; + } + + ics->group_len[7] = 1; + ics->num_window_groups++; + ics->num_windows = 8; + } else { + if (usac->core_frame_len == 768) { + ics->swb_offset = ff_swb_offset_768[sampling_index]; + ics->num_swb = ff_aac_num_swb_768[sampling_index]; + } else { + ics->swb_offset = ff_swb_offset_1024[sampling_index]; + ics->num_swb = ff_aac_num_swb_1024[sampling_index]; + } + ics->tns_max_bands = ff_tns_max_bands_usac_1024[sampling_index]; + + ics->group_len[0] = 1; + ics->num_window_groups = 1; + ics->num_windows = 1; + } + + if (ics->max_sfb > ics->num_swb) { + av_log(ac->avctx, AV_LOG_ERROR, + "Number of scalefactor bands in group (%d) " + "exceeds limit (%d).\n", + ics->max_sfb, ics->num_swb); + ics->max_sfb = 0; + return AVERROR(EINVAL); + } + + /* Just some defaults for the band types */ + for (int i = 0; i < FF_ARRAY_ELEMS(sce->band_type); i++) + sce->band_type[i] = ESC_BT; + + return 0; +} + +static int decode_usac_stereo_info(AACDecContext *ac, AACUSACConfig *usac, + AACUsacElemConfig *ec, ChannelElement *cpe, + GetBitContext *gb, int indep_flag) +{ + int ret, tns_active; + + AACUsacStereo *us = &cpe->us; + SingleChannelElement *sce1 = &cpe->ch[0]; + SingleChannelElement *sce2 = &cpe->ch[1]; + IndividualChannelStream *ics1 = &sce1->ics; + IndividualChannelStream *ics2 = &sce2->ics; + AACUsacElemData *ue1 = &sce1->ue; + AACUsacElemData *ue2 = &sce2->ue; + + us->common_window = 0; + us->common_tw = 0; + + /* Alpha values must always be zeroed out for the current frame, + * as they are propagated to the next frame and may be used. */ + memset(us->alpha_q_re, 0, sizeof(us->alpha_q_re)); + memset(us->alpha_q_im, 0, sizeof(us->alpha_q_im)); + + if (!(!ue1->core_mode && !ue2->core_mode)) + return 0; + + tns_active = get_bits1(gb); + us->common_window = get_bits1(gb); + + if (!us->common_window || indep_flag) { + memset(us->prev_alpha_q_re, 0, sizeof(us->prev_alpha_q_re)); + memset(us->prev_alpha_q_im, 0, sizeof(us->prev_alpha_q_im)); + } + + if (us->common_window) { + /* ics_info() */ + ics1->window_sequence[1] = ics1->window_sequence[0]; + ics2->window_sequence[1] = ics2->window_sequence[0]; + ics1->window_sequence[0] = ics2->window_sequence[0] = get_bits(gb, 2); + + ics1->use_kb_window[1] = ics1->use_kb_window[0]; + ics2->use_kb_window[1] = ics2->use_kb_window[0]; + ics1->use_kb_window[0] = ics2->use_kb_window[0] = get_bits1(gb); + + /* If there's a change in the transform sequence, zero out last frame's + * stereo prediction coefficients */ + if ((ics1->window_sequence[0] == EIGHT_SHORT_SEQUENCE && + ics1->window_sequence[1] != EIGHT_SHORT_SEQUENCE) || + (ics1->window_sequence[1] == EIGHT_SHORT_SEQUENCE && + ics1->window_sequence[0] != EIGHT_SHORT_SEQUENCE) || + (ics2->window_sequence[0] == EIGHT_SHORT_SEQUENCE && + ics2->window_sequence[1] != EIGHT_SHORT_SEQUENCE) || + (ics2->window_sequence[1] == EIGHT_SHORT_SEQUENCE && + ics2->window_sequence[0] != EIGHT_SHORT_SEQUENCE)) { + memset(us->prev_alpha_q_re, 0, sizeof(us->prev_alpha_q_re)); + memset(us->prev_alpha_q_im, 0, sizeof(us->prev_alpha_q_im)); + } + + if (ics1->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + ics1->max_sfb = ics2->max_sfb = get_bits(gb, 4); + ue1->scale_factor_grouping = ue2->scale_factor_grouping = get_bits(gb, 7); + } else { + ics1->max_sfb = ics2->max_sfb = get_bits(gb, 6); + } + + if (!get_bits1(gb)) { /* common_max_sfb */ + if (ics2->window_sequence[0] == EIGHT_SHORT_SEQUENCE) + ics2->max_sfb = get_bits(gb, 4); + else + ics2->max_sfb = get_bits(gb, 6); + } + + ret = setup_sce(ac, sce1, usac); + if (ret < 0) { + ics2->max_sfb = 0; + return ret; + } + + ret = setup_sce(ac, sce2, usac); + if (ret < 0) + return ret; + + cpe->max_sfb_ste = FFMAX(ics1->max_sfb, ics2->max_sfb); + + us->ms_mask_mode = get_bits(gb, 2); /* ms_mask_present */ + memset(cpe->ms_mask, 0, sizeof(cpe->ms_mask)); + if (us->ms_mask_mode == 1) { + for (int g = 0; g < ics1->num_window_groups; g++) + for (int sfb = 0; sfb < cpe->max_sfb_ste; sfb++) + cpe->ms_mask[g*cpe->max_sfb_ste + sfb] = get_bits1(gb); + } else if (us->ms_mask_mode == 2) { + memset(cpe->ms_mask, 0xFF, sizeof(cpe->ms_mask)); + } else if ((us->ms_mask_mode == 3) && !ec->stereo_config_index) { + ret = decode_usac_stereo_cplx(ac, us, cpe, gb, + ics1->num_window_groups, + ics1->prev_num_window_groups, + indep_flag); + if (ret < 0) + return ret; + } + } + + if (ec->tw_mdct) { + us->common_tw = get_bits1(gb); + avpriv_report_missing_feature(ac->avctx, + "AAC USAC timewarping"); + return AVERROR_PATCHWELCOME; + } + + us->tns_on_lr = 0; + ue1->tns_data_present = ue2->tns_data_present = 0; + if (tns_active) { + int common_tns = 0; + if (us->common_window) + common_tns = get_bits1(gb); + + us->tns_on_lr = get_bits1(gb); + if (common_tns) { + ret = ff_aac_decode_tns(ac, &sce1->tns, gb, ics1); + if (ret < 0) + return ret; + memcpy(&sce2->tns, &sce1->tns, sizeof(sce1->tns)); + sce2->tns.present = 1; + sce1->tns.present = 1; + ue1->tns_data_present = 0; + ue2->tns_data_present = 0; + } else { + if (get_bits1(gb)) { + ue1->tns_data_present = 1; + ue2->tns_data_present = 1; + } else { + ue2->tns_data_present = get_bits1(gb); + ue1->tns_data_present = !ue2->tns_data_present; + } + } + } + + return 0; +} + +/* 7.2.4 Generation of random signs for spectral noise filling + * This function is exactly defined, though we've helped the definition + * along with being slightly faster. */ +static inline float noise_random_sign(unsigned int *seed) +{ + unsigned int new_seed = *seed = ((*seed) * 69069) + 5; + if (((new_seed) & 0x10000) > 0) + return -1.f; + return +1.f; +} + +static void apply_noise_fill(AACDecContext *ac, SingleChannelElement *sce, + AACUsacElemData *ue) +{ + float *coef; + IndividualChannelStream *ics = &sce->ics; + + float noise_val = powf(2, ((float)ue->noise.level - 14.0f)/3.0f); + int noise_offset = ue->noise.offset - 16; + int band_off; + + band_off = ff_usac_noise_fill_start_offset[ac->oc[1].m4ac.frame_length_short] + [ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE]; + + coef = sce->coeffs; + for (int g = 0; g < ics->num_window_groups; g++) { + unsigned g_len = ics->group_len[g]; + + for (int sfb = 0; sfb < ics->max_sfb; sfb++) { + float *cb = coef + ics->swb_offset[sfb]; + int cb_len = ics->swb_offset[sfb + 1] - ics->swb_offset[sfb]; + int band_quantized_to_zero = 1; + + if (ics->swb_offset[sfb] < band_off) + continue; + + for (int group = 0; group < (unsigned)g_len; group++, cb += 128) { + for (int z = 0; z < cb_len; z++) { + if (cb[z] == 0) + cb[z] = noise_random_sign(&sce->ue.noise.seed) * noise_val; + else + band_quantized_to_zero = 0; + } + } + + if (band_quantized_to_zero) + sce->sfo[g*ics->max_sfb + sfb] += noise_offset; + } + coef += g_len << 7; + } +} + +static void spectrum_scale(AACDecContext *ac, SingleChannelElement *sce, + AACUsacElemData *ue) +{ + IndividualChannelStream *ics = &sce->ics; + float *coef; + + /* Synthesise noise */ + if (ue->noise.level) + apply_noise_fill(ac, sce, ue); + + /* Noise filling may apply an offset to the scalefactor offset */ + ac->dsp.dequant_scalefactors(sce); + + /* Apply scalefactors */ + coef = sce->coeffs; + for (int g = 0; g < ics->num_window_groups; g++) { + unsigned g_len = ics->group_len[g]; + + for (int sfb = 0; sfb < ics->max_sfb; sfb++) { + float *cb = coef + ics->swb_offset[sfb]; + int cb_len = ics->swb_offset[sfb + 1] - ics->swb_offset[sfb]; + float sf = sce->sf[g*ics->max_sfb + sfb]; + + for (int group = 0; group < (unsigned)g_len; group++, cb += 128) + ac->fdsp->vector_fmul_scalar(cb, cb, sf, cb_len); + } + coef += g_len << 7; + } +} + +static void complex_stereo_downmix_prev(AACDecContext *ac, ChannelElement *cpe, + float *dmix_re) +{ + IndividualChannelStream *ics = &cpe->ch[0].ics; + int sign = !cpe->us.pred_dir ? +1 : -1; + float *coef1 = cpe->ch[0].coeffs; + float *coef2 = cpe->ch[1].coeffs; + + for (int g = 0; g < ics->num_window_groups; g++) { + unsigned g_len = ics->group_len[g]; + for (int sfb = 0; sfb < cpe->max_sfb_ste; sfb++) { + int off = ics->swb_offset[sfb]; + int cb_len = ics->swb_offset[sfb + 1] - off; + + float *c1 = coef1 + off; + float *c2 = coef2 + off; + float *dm = dmix_re + off; + + for (int group = 0; group < (unsigned)g_len; + group++, c1 += 128, c2 += 128, dm += 128) { + for (int z = 0; z < cb_len; z++) + dm[z] = 0.5*(c1[z] + sign*c2[z]); + } + } + + coef1 += g_len << 7; + coef2 += g_len << 7; + dmix_re += g_len << 7; + } +} + +static void complex_stereo_downmix_cur(AACDecContext *ac, ChannelElement *cpe, + float *dmix_re) +{ + AACUsacStereo *us = &cpe->us; + IndividualChannelStream *ics = &cpe->ch[0].ics; + int sign = !cpe->us.pred_dir ? +1 : -1; + float *coef1 = cpe->ch[0].coeffs; + float *coef2 = cpe->ch[1].coeffs; + + for (int g = 0; g < ics->num_window_groups; g++) { + unsigned g_len = ics->group_len[g]; + for (int sfb = 0; sfb < cpe->max_sfb_ste; sfb++) { + int off = ics->swb_offset[sfb]; + int cb_len = ics->swb_offset[sfb + 1] - off; + + float *c1 = coef1 + off; + float *c2 = coef2 + off; + float *dm = dmix_re + off; + + if (us->pred_used[g*cpe->max_sfb_ste + sfb]) { + for (int group = 0; group < (unsigned)g_len; + group++, c1 += 128, c2 += 128, dm += 128) { + for (int z = 0; z < cb_len; z++) + dm[z] = 0.5*(c1[z] + sign*c2[z]); + } + } else { + for (int group = 0; group < (unsigned)g_len; + group++, c1 += 128, c2 += 128, dm += 128) { + for (int z = 0; z < cb_len; z++) + dm[z] = c1[z]; + } + } + } + + coef1 += g_len << 7; + coef2 += g_len << 7; + dmix_re += g_len << 7; + } +} + +static void complex_stereo_interpolate_imag(float *im, float *re, const float f[7], + int len, int factor_even, int factor_odd) +{ + int i = 0; + float s; + + s = f[6]*re[2] + f[5]*re[1] + f[4]*re[0] + + f[3]*re[0] + + f[2]*re[1] + f[1]*re[2] + f[0]*re[3]; + im[i] += s*factor_even; + + i = 1; + s = f[6]*re[1] + f[5]*re[0] + f[4]*re[0] + + f[3]*re[1] + + f[2]*re[2] + f[1]*re[3] + f[0]*re[4]; + im[i] += s*factor_odd; + + i = 2; + s = f[6]*re[0] + f[5]*re[0] + f[4]*re[1] + + f[3]*re[2] + + f[2]*re[3] + f[1]*re[4] + f[0]*re[5]; + + im[i] += s*factor_even; + for (i = 3; i < len - 4; i += 2) { + s = f[6]*re[i-3] + f[5]*re[i-2] + f[4]*re[i-1] + + f[3]*re[i] + + f[2]*re[i+1] + f[1]*re[i+2] + f[0]*re[i+3]; + im[i+0] += s*factor_odd; + + s = f[6]*re[i-2] + f[5]*re[i-1] + f[4]*re[i] + + f[3]*re[i+1] + + f[2]*re[i+2] + f[1]*re[i+3] + f[0]*re[i+4]; + im[i+1] += s*factor_even; + } + + i = len - 3; + s = f[6]*re[i-3] + f[5]*re[i-2] + f[4]*re[i-1] + + f[3]*re[i] + + f[2]*re[i+1] + f[1]*re[i+2] + f[0]*re[i+2]; + im[i] += s*factor_odd; + + i = len - 2; + s = f[6]*re[i-3] + f[5]*re[i-2] + f[4]*re[i-1] + + f[3]*re[i] + + f[2]*re[i+1] + f[1]*re[i+1] + f[0]*re[i]; + im[i] += s*factor_even; + + i = len - 1; + s = f[6]*re[i-3] + f[5]*re[i-2] + f[4]*re[i-1] + + f[3]*re[i] + + f[2]*re[i] + f[1]*re[i-1] + f[0]*re[i-2]; + im[i] += s*factor_odd; +} + +static void apply_complex_stereo(AACDecContext *ac, ChannelElement *cpe) +{ + AACUsacStereo *us = &cpe->us; + IndividualChannelStream *ics = &cpe->ch[0].ics; + float *coef1 = cpe->ch[0].coeffs; + float *coef2 = cpe->ch[1].coeffs; + float *dmix_im = us->dmix_im; + + for (int g = 0; g < ics->num_window_groups; g++) { + unsigned g_len = ics->group_len[g]; + for (int sfb = 0; sfb < cpe->max_sfb_ste; sfb++) { + int off = ics->swb_offset[sfb]; + int cb_len = ics->swb_offset[sfb + 1] - off; + + float *c1 = coef1 + off; + float *c2 = coef2 + off; + float *dm_im = dmix_im + off; + float alpha_re = us->alpha_q_re[g*cpe->max_sfb_ste + sfb]; + float alpha_im = us->alpha_q_im[g*cpe->max_sfb_ste + sfb]; + + if (!us->pred_used[g*cpe->max_sfb_ste + sfb]) + continue; + + if (!cpe->us.pred_dir) { + for (int group = 0; group < (unsigned)g_len; + group++, c1 += 128, c2 += 128, dm_im += 128) { + for (int z = 0; z < cb_len; z++) { + float side; + side = c2[z] - alpha_re*c1[z] - alpha_im*dm_im[z]; + c2[z] = c1[z] - side; + c1[z] = c1[z] + side; + } + } + } else { + for (int group = 0; group < (unsigned)g_len; + group++, c1 += 128, c2 += 128, dm_im += 128) { + for (int z = 0; z < cb_len; z++) { + float mid; + mid = c2[z] - alpha_re*c1[z] - alpha_im*dm_im[z]; + c2[z] = mid - c1[z]; + c1[z] = mid + c1[z]; + } + } + } + } + + coef1 += g_len << 7; + coef2 += g_len << 7; + dmix_im += g_len << 7; + } +} + +static const float *complex_stereo_get_filter(ChannelElement *cpe, int is_prev) +{ + int win, shape; + if (!is_prev) { + switch (cpe->ch[0].ics.window_sequence[0]) { + default: + case ONLY_LONG_SEQUENCE: + case EIGHT_SHORT_SEQUENCE: + win = 0; + break; + case LONG_START_SEQUENCE: + win = 1; + break; + case LONG_STOP_SEQUENCE: + win = 2; + break; + } + + if (cpe->ch[0].ics.use_kb_window[0] == 0 && + cpe->ch[0].ics.use_kb_window[1] == 0) + shape = 0; + else if (cpe->ch[0].ics.use_kb_window[0] == 1 && + cpe->ch[0].ics.use_kb_window[1] == 1) + shape = 1; + else if (cpe->ch[0].ics.use_kb_window[0] == 0 && + cpe->ch[0].ics.use_kb_window[1] == 1) + shape = 2; + else if (cpe->ch[0].ics.use_kb_window[0] == 1 && + cpe->ch[0].ics.use_kb_window[1] == 0) + shape = 3; + else + shape = 3; + } else { + win = cpe->ch[0].ics.window_sequence[0] == LONG_STOP_SEQUENCE; + shape = cpe->ch[0].ics.use_kb_window[1]; + } + + return ff_aac_usac_mdst_filt_cur[win][shape]; +} + +static void spectrum_decode(AACDecContext *ac, AACUSACConfig *usac, + ChannelElement *cpe, int nb_channels) +{ + AACUsacStereo *us = &cpe->us; + + for (int ch = 0; ch < nb_channels; ch++) { + SingleChannelElement *sce = &cpe->ch[ch]; + AACUsacElemData *ue = &sce->ue; + + spectrum_scale(ac, sce, ue); + } + + if (nb_channels > 1 && us->common_window) { + for (int ch = 0; ch < nb_channels; ch++) { + SingleChannelElement *sce = &cpe->ch[ch]; + + /* Apply TNS, if the tns_on_lr bit is not set. */ + if (sce->tns.present && !us->tns_on_lr) + ac->dsp.apply_tns(sce->coeffs, &sce->tns, &sce->ics, 1); + } + + if (us->ms_mask_mode == 3) { + const float *filt; + complex_stereo_downmix_cur(ac, cpe, us->dmix_re); + complex_stereo_downmix_prev(ac, cpe, us->prev_dmix_re); + + filt = complex_stereo_get_filter(cpe, 0); + complex_stereo_interpolate_imag(us->dmix_im, us->dmix_re, filt, + usac->core_frame_len, 1, 1); + if (us->use_prev_frame) { + filt = complex_stereo_get_filter(cpe, 1); + complex_stereo_interpolate_imag(us->dmix_im, us->prev_dmix_re, filt, + usac->core_frame_len, -1, 1); + } + + apply_complex_stereo(ac, cpe); + } else if (us->ms_mask_mode > 0) { + ac->dsp.apply_mid_side_stereo(ac, cpe); + } + } + + /* Save coefficients and alpha values for prediction reasons */ + if (nb_channels > 1) { + AACUsacStereo *us = &cpe->us; + for (int ch = 0; ch < nb_channels; ch++) { + SingleChannelElement *sce = &cpe->ch[ch]; + memcpy(sce->prev_coeffs, sce->coeffs, sizeof(sce->coeffs)); + } + memcpy(us->prev_alpha_q_re, us->alpha_q_re, sizeof(us->alpha_q_re)); + memcpy(us->prev_alpha_q_im, us->alpha_q_im, sizeof(us->alpha_q_im)); + } + + for (int ch = 0; ch < nb_channels; ch++) { + SingleChannelElement *sce = &cpe->ch[ch]; + + /* Apply TNS, if it hasn't been applied yet. */ + if (sce->tns.present && ((nb_channels == 1) || (us->tns_on_lr))) + ac->dsp.apply_tns(sce->coeffs, &sce->tns, &sce->ics, 1); + + ac->oc[1].m4ac.frame_length_short ? ac->dsp.imdct_and_windowing_768(ac, sce) : + ac->dsp.imdct_and_windowing(ac, sce); + } +} + +static int decode_usac_core_coder(AACDecContext *ac, AACUSACConfig *usac, + AACUsacElemConfig *ec, ChannelElement *che, + GetBitContext *gb, int indep_flag, int nb_channels) +{ + int ret; + int arith_reset_flag; + AACUsacStereo *us = &che->us; + int core_nb_channels = nb_channels; + + /* Local symbols */ + uint8_t global_gain; + + us->common_window = 0; + + for (int ch = 0; ch < core_nb_channels; ch++) { + SingleChannelElement *sce = &che->ch[ch]; + AACUsacElemData *ue = &sce->ue; + + sce->tns.present = 0; + ue->tns_data_present = 0; + + ue->core_mode = get_bits1(gb); + } + + if (nb_channels > 1 && ec->stereo_config_index == 1) + core_nb_channels = 1; + + if (core_nb_channels == 2) { + ret = decode_usac_stereo_info(ac, usac, ec, che, gb, indep_flag); + if (ret) + return ret; + } + + for (int ch = 0; ch < core_nb_channels; ch++) { + SingleChannelElement *sce = &che->ch[ch]; + IndividualChannelStream *ics = &sce->ics; + AACUsacElemData *ue = &sce->ue; + + if (ue->core_mode) { /* lpd_channel_stream */ + ret = ff_aac_ldp_parse_channel_stream(ac, usac, ue, gb); + if (ret < 0) + return ret; + continue; + } + + if ((core_nb_channels == 1) || + (che->ch[0].ue.core_mode != che->ch[1].ue.core_mode)) + ue->tns_data_present = get_bits1(gb); + + /* fd_channel_stream */ + global_gain = get_bits(gb, 8); + + ue->noise.level = 0; + if (ec->noise_fill) { + ue->noise.level = get_bits(gb, 3); + ue->noise.offset = get_bits(gb, 5); + } + + if (!us->common_window) { + /* ics_info() */ + ics->window_sequence[1] = ics->window_sequence[0]; + ics->window_sequence[0] = get_bits(gb, 2); + ics->use_kb_window[1] = ics->use_kb_window[0]; + ics->use_kb_window[0] = get_bits1(gb); + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + ics->max_sfb = get_bits(gb, 4); + ue->scale_factor_grouping = get_bits(gb, 7); + } else { + ics->max_sfb = get_bits(gb, 6); + } + + ret = setup_sce(ac, sce, usac); + if (ret < 0) + return ret; + } + + if (ec->tw_mdct && !us->common_tw) { + /* tw_data() */ + if (get_bits1(gb)) { /* tw_data_present */ + /* Time warping is not supported in baseline profile streams. */ + avpriv_report_missing_feature(ac->avctx, + "AAC USAC timewarping"); + return AVERROR_PATCHWELCOME; + } + } + + ret = decode_usac_scale_factors(ac, sce, gb, global_gain); + if (ret < 0) + return ret; + + if (ue->tns_data_present) { + sce->tns.present = 1; + ret = ff_aac_decode_tns(ac, &sce->tns, gb, ics); + if (ret < 0) + return ret; + } + + /* ac_spectral_data */ + arith_reset_flag = indep_flag; + if (!arith_reset_flag) + arith_reset_flag = get_bits1(gb); + + /* Decode coeffs */ + memset(&sce->coeffs[0], 0, 1024*sizeof(float)); + for (int win = 0; win < ics->num_windows; win++) { + int lg = ics->swb_offset[ics->max_sfb]; + int N; + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) + N = usac->core_frame_len / 8; + else + N = usac->core_frame_len; + + ret = decode_spectrum_ac(ac, sce->coeffs + win*128, gb, &ue->ac, + arith_reset_flag && (win == 0), lg, N); + if (ret < 0) + return ret; + } + + 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; + ret = ff_aac_parse_fac_data(ue, gb, 1, fac_len); + if (ret < 0) + return ret; + } + } + + if (ec->sbr.ratio) { + int sbr_ch = nb_channels; + if (nb_channels == 2 && + !(ec->stereo_config_index == 0 || ec->stereo_config_index == 3)) + sbr_ch = 1; + + 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; + } + } + + spectrum_decode(ac, usac, che, core_nb_channels); + + if (ac->oc[1].m4ac.sbr > 0) { + ac->proc.sbr_apply(ac, che, nb_channels == 2 ? TYPE_CPE : TYPE_SCE, + che->ch[0].output, + che->ch[1].output); + } + + return 0; +} + +static int parse_audio_preroll(AACDecContext *ac, GetBitContext *gb) +{ + int ret = 0; + GetBitContext gbc; + OutputConfiguration *oc = &ac->oc[1]; + MPEG4AudioConfig *m4ac = &oc->m4ac; + MPEG4AudioConfig m4ac_bak = oc->m4ac; + uint8_t temp_data[512]; + uint8_t *tmp_buf = temp_data; + size_t tmp_buf_size = sizeof(temp_data); + + av_unused int crossfade; + int num_preroll_frames; + + int config_len = get_escaped_value(gb, 4, 4, 8); + + /* Implementations are free to pad the config to any length, so use a + * different reader for this. */ + gbc = *gb; + ret = ff_aac_usac_config_decode(ac, ac->avctx, &gbc, oc, m4ac->chan_config); + if (ret < 0) { + *m4ac = m4ac_bak; + return ret; + } else { + ac->oc[1].m4ac.chan_config = 0; + } + + /* 7.18.3.3 Bitrate adaption + * If configuration didn't change after applying preroll, continue + * without decoding it. */ + if (!memcmp(m4ac, &m4ac_bak, sizeof(m4ac_bak))) + return 0; + + skip_bits_long(gb, config_len*8); + + crossfade = get_bits1(gb); /* applyCrossfade */ + skip_bits1(gb); /* reserved */ + num_preroll_frames = get_escaped_value(gb, 2, 4, 0); /* numPreRollFrames */ + + for (int i = 0; i < num_preroll_frames; i++) { + int got_frame_ptr = 0; + int au_len = get_escaped_value(gb, 16, 16, 0); + + if (au_len*8 > tmp_buf_size) { + uint8_t *tmp2; + tmp_buf = tmp_buf == temp_data ? NULL : tmp_buf; + tmp2 = av_realloc_array(tmp_buf, au_len, 8); + if (!tmp2) { + if (tmp_buf != temp_data) + av_free(tmp_buf); + return AVERROR(ENOMEM); + } + tmp_buf = tmp2; + } + + /* Byte alignment is not guaranteed. */ + for (int i = 0; i < au_len; i++) + tmp_buf[i] = get_bits(gb, 8); + + ret = init_get_bits8(&gbc, tmp_buf, au_len); + if (ret < 0) + break; + + ret = ff_aac_usac_decode_frame(ac->avctx, ac, &gbc, &got_frame_ptr); + if (ret < 0) + break; + } + + if (tmp_buf != temp_data) + av_free(tmp_buf); + + return 0; +} + +static int parse_ext_ele(AACDecContext *ac, AACUsacElemConfig *e, + GetBitContext *gb) +{ + uint8_t *tmp; + uint8_t pl_frag_start = 1; + uint8_t pl_frag_end = 1; + uint32_t len; + + if (!get_bits1(gb)) /* usacExtElementPresent */ + return 0; + + if (get_bits1(gb)) { /* usacExtElementUseDefaultLength */ + len = e->ext.default_len; + } else { + len = get_bits(gb, 8); /* usacExtElementPayloadLength */ + if (len == 255) + len += get_bits(gb, 16) - 2; + } + + if (!len) + return 0; + + if (e->ext.payload_frag) { + pl_frag_start = get_bits1(gb); /* usacExtElementStart */ + pl_frag_end = get_bits1(gb); /* usacExtElementStop */ + } + + if (pl_frag_start) + e->ext.pl_data_offset = 0; + + /* If an extension starts and ends this packet, we can directly use it */ + if (!(pl_frag_start && pl_frag_end)) { + tmp = av_realloc(e->ext.pl_data, e->ext.pl_data_offset + len); + if (!tmp) { + av_free(e->ext.pl_data); + return AVERROR(ENOMEM); + } + e->ext.pl_data = tmp; + + /* Readout data to a buffer */ + for (int i = 0; i < len; i++) + e->ext.pl_data[e->ext.pl_data_offset + i] = get_bits(gb, 8); + } + + e->ext.pl_data_offset += len; + + if (pl_frag_end) { + int ret = 0; + int start_bits = get_bits_count(gb); + const int pl_len = e->ext.pl_data_offset; + GetBitContext *gb2 = gb; + GetBitContext gbc; + if (!(pl_frag_start && pl_frag_end)) { + ret = init_get_bits8(&gbc, e->ext.pl_data, pl_len); + if (ret < 0) + return ret; + + gb2 = &gbc; + } + + switch (e->ext.type) { + case ID_EXT_ELE_FILL: + /* Filler elements have no usable payload */ + break; + case ID_EXT_ELE_AUDIOPREROLL: + ret = parse_audio_preroll(ac, gb2); + break; + default: + /* This should never happen */ + av_assert0(0); + } + av_freep(&e->ext.pl_data); + if (ret < 0) + return ret; + + skip_bits_long(gb, pl_len*8 - (get_bits_count(gb) - start_bits)); + } + + return 0; +} + +int ff_aac_usac_decode_frame(AVCodecContext *avctx, AACDecContext *ac, + GetBitContext *gb, int *got_frame_ptr) +{ + int ret, is_dmono = 0; + int indep_flag, samples = 0; + int audio_found = 0; + int elem_id[3 /* SCE, CPE, LFE */] = { 0, 0, 0 }; + AVFrame *frame = ac->frame; + + int ratio_mult, ratio_dec; + AACUSACConfig *usac = &ac->oc[1].usac; + int sbr_ratio = usac->core_sbr_frame_len_idx == 2 ? 2 : + usac->core_sbr_frame_len_idx == 3 ? 3 : + usac->core_sbr_frame_len_idx == 4 ? 1 : + 0; + + if (sbr_ratio == 2) { + ratio_mult = 8; + ratio_dec = 3; + } else if (sbr_ratio == 3) { + ratio_mult = 2; + ratio_dec = 1; + } else if (sbr_ratio == 4) { + ratio_mult = 4; + ratio_dec = 1; + } else { + ratio_mult = 1; + ratio_dec = 1; + } + + ff_aac_output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, + ac->oc[1].status, 0); + + ac->avctx->profile = AV_PROFILE_AAC_USAC; + + indep_flag = get_bits1(gb); + + for (int i = 0; i < ac->oc[1].usac.nb_elems; i++) { + int layout_id; + int layout_type; + AACUsacElemConfig *e = &ac->oc[1].usac.elems[i]; + ChannelElement *che; + + if (e->type == ID_USAC_SCE) { + layout_id = elem_id[0]++; + layout_type = TYPE_SCE; + che = ff_aac_get_che(ac, TYPE_SCE, layout_id); + } else if (e->type == ID_USAC_CPE) { + layout_id = elem_id[1]++; + layout_type = TYPE_CPE; + che = ff_aac_get_che(ac, TYPE_CPE, layout_id); + } else if (e->type == ID_USAC_LFE) { + layout_id = elem_id[2]++; + layout_type = TYPE_LFE; + che = ff_aac_get_che(ac, TYPE_LFE, layout_id); + } + + if (e->type != ID_USAC_EXT && !che) { + av_log(ac->avctx, AV_LOG_ERROR, + "channel element %d.%d is not allocated\n", + layout_type, layout_id); + return AVERROR_INVALIDDATA; + } + + switch (e->type) { + case ID_USAC_LFE: + /* Fallthrough */ + case ID_USAC_SCE: + ret = decode_usac_core_coder(ac, &ac->oc[1].usac, e, che, gb, + indep_flag, 1); + if (ret < 0) + return ret; + + audio_found = 1; + che->present = 1; + break; + case ID_USAC_CPE: + ret = decode_usac_core_coder(ac, &ac->oc[1].usac, e, che, gb, + indep_flag, 2); + if (ret < 0) + return ret; + + audio_found = 1; + che->present = 1; + break; + case ID_USAC_EXT: + ret = parse_ext_ele(ac, e, gb); + if (ret < 0) + return ret; + break; + } + } + + if (audio_found) + samples = ac->oc[1].m4ac.frame_length_short ? 768 : 1024; + + samples = (samples * ratio_mult) / ratio_dec; + + if (ac->oc[1].status && audio_found) { + avctx->sample_rate = ac->oc[1].m4ac.ext_sample_rate; + avctx->frame_size = samples; + ac->oc[1].status = OC_LOCKED; + } + + if (!frame->data[0] && samples) { + av_log(avctx, AV_LOG_ERROR, "no frame data found\n"); + return AVERROR_INVALIDDATA; + } + + if (samples) { + frame->nb_samples = samples; + frame->sample_rate = avctx->sample_rate; + frame->flags = indep_flag ? AV_FRAME_FLAG_KEY : 0x0; + *got_frame_ptr = 1; + } else { + av_frame_unref(ac->frame); + frame->flags = indep_flag ? AV_FRAME_FLAG_KEY : 0x0; + *got_frame_ptr = 0; + } + + /* for dual-mono audio (SCE + SCE) */ + is_dmono = ac->dmono_mode && elem_id[0] == 2 && + !av_channel_layout_compare(&ac->oc[1].ch_layout, + &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); + if (is_dmono) { + if (ac->dmono_mode == 1) + frame->data[1] = frame->data[0]; + else if (ac->dmono_mode == 2) + frame->data[0] = frame->data[1]; + } + + return 0; +} diff --git a/libavcodec/aac/aacdec_usac.h b/libavcodec/aac/aacdec_usac.h new file mode 100644 index 000000000..4116a2073 --- /dev/null +++ b/libavcodec/aac/aacdec_usac.h @@ -0,0 +1,37 @@ +/* + * 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_AAC_AACDEC_USAC_H +#define AVCODEC_AAC_AACDEC_USAC_H + +#include "aacdec.h" + +#include "libavcodec/get_bits.h" + +int ff_aac_usac_config_decode(AACDecContext *ac, AVCodecContext *avctx, + GetBitContext *gb, OutputConfiguration *oc, + int channel_config); + +int ff_aac_usac_reset_state(AACDecContext *ac, OutputConfiguration *oc); + +int ff_aac_usac_decode_frame(AVCodecContext *avctx, AACDecContext *ac, + GetBitContext *gb, int *got_frame_ptr); + +#endif /* AVCODEC_AAC_AACDEC_USAC_H */ diff --git a/libavcodec/aac_ac3_parser.c b/libavcodec/aac_ac3_parser.c index 9305b4c50..e2361d353 100644 --- a/libavcodec/aac_ac3_parser.c +++ b/libavcodec/aac_ac3_parser.c @@ -40,6 +40,8 @@ int ff_aac_ac3_parse(AVCodecParserContext *s1, int new_frame_start; int got_frame = 0; + s1->key_frame = -1; + if (s1->flags & PARSER_FLAG_COMPLETE_FRAMES) { i = buf_size; got_frame = 1; @@ -144,12 +146,16 @@ get_next: #endif } else { #if CONFIG_AAC_PARSER - AACADTSHeaderInfo hdr, *phrd = &hdr; - int ret = avpriv_adts_header_parse(&phrd, buf, buf_size); - - if (ret < 0) + 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) return i; + avctx->profile = hdr.object_type - 1; + s1->key_frame = (avctx->profile == AV_PROFILE_AAC_USAC) ? get_bits1(&gb) : 1; bit_rate = hdr.bit_rate; #endif } diff --git a/libavcodec/aac_ac3_parser.h b/libavcodec/aac_ac3_parser.h index bc16181a1..e3259d184 100644 --- a/libavcodec/aac_ac3_parser.h +++ b/libavcodec/aac_ac3_parser.h @@ -28,16 +28,6 @@ #include "avcodec.h" #include "parser.h" -typedef enum { - AAC_AC3_PARSE_ERROR_SYNC = -0x1030c0a, - AAC_AC3_PARSE_ERROR_BSID = -0x2030c0a, - AAC_AC3_PARSE_ERROR_SAMPLE_RATE = -0x3030c0a, - AAC_AC3_PARSE_ERROR_FRAME_SIZE = -0x4030c0a, - AAC_AC3_PARSE_ERROR_FRAME_TYPE = -0x5030c0a, - AAC_AC3_PARSE_ERROR_CRC = -0x6030c0a, - AAC_AC3_PARSE_ERROR_CHANNEL_CFG = -0x7030c0a, -} AACAC3ParseError; - typedef struct AACAC3ParseContext { ParseContext pc; int header_size; diff --git a/libavcodec/aac_defines.h b/libavcodec/aac_defines.h index a0c23c33f..a3b662115 100644 --- a/libavcodec/aac_defines.h +++ b/libavcodec/aac_defines.h @@ -42,7 +42,6 @@ typedef int AAC_SIGNE; #define Q23(a) (int)((a) * 8388608.0 + 0.5) #define Q30(x) (int)((x)*1073741824.0 + 0.5) #define Q31(x) (int)((x)*2147483648.0 + 0.5) -#define TX_SCALE(x) ((x) * 128.0f) #define GET_GAIN(x, y) (-(y) * (1 << (x))) + 1024 #define AAC_MUL16(x, y) (int)(((int64_t)(x) * (y) + 0x8000) >> 16) #define AAC_MUL26(x, y) (int)(((int64_t)(x) * (y) + 0x2000000) >> 26) @@ -72,6 +71,20 @@ typedef int AAC_SIGNE; 0x40000000) >> 31) #define AAC_HALF_SUM(x, y) (((x) >> 1) + ((y) >> 1)) +/** + * Predictor State + */ +typedef struct PredictorStateFixed { + SoftFloat cor0; + SoftFloat cor1; + SoftFloat var0; + SoftFloat var1; + SoftFloat r0; + SoftFloat r1; + SoftFloat k1; + SoftFloat x_est; +} PredictorState; + #ifdef LPC_USE_FIXED #error aac_defines.h must be included before lpc_functions.h for fixed point decoder #endif @@ -96,7 +109,6 @@ typedef unsigned AAC_SIGNE; #define Q23(x) ((float)(x)) #define Q30(x) ((float)(x)) #define Q31(x) ((float)(x)) -#define TX_SCALE(x) ((x) / 32768.0f) #define GET_GAIN(x, y) powf((x), -(y)) #define AAC_MUL16(x, y) ((x) * (y)) #define AAC_MUL26(x, y) ((x) * (y)) @@ -112,6 +124,20 @@ typedef unsigned AAC_SIGNE; #define AAC_MSUB31_V3(x, y, z) ((x) - (y)) * (z) #define AAC_HALF_SUM(x, y) ((x) + (y)) * 0.5f +/** + * Predictor State + */ +typedef struct PredictorState { + float cor0; + float cor1; + float var0; + float var1; + float r0; + float r1; + float k1; + float x_est; +} PredictorState; + #endif /* USE_FIXED */ #endif /* AVCODEC_AAC_DEFINES_H */ diff --git a/libavcodec/aac_parser.c b/libavcodec/aac_parser.c index f295dfccd..186fcd887 100644 --- a/libavcodec/aac_parser.c +++ b/libavcodec/aac_parser.c @@ -24,24 +24,18 @@ #include "aac_ac3_parser.h" #include "adts_header.h" #include "adts_parser.h" -#include "get_bits.h" -#include "mpeg4audio.h" +#include "libavutil/intreadwrite.h" static int aac_sync(uint64_t state, int *need_next_header, int *new_frame_start) { - GetBitContext bits; + uint8_t tmp[8 + AV_INPUT_BUFFER_PADDING_SIZE]; AACADTSHeaderInfo hdr; int size; - union { - uint64_t u64; - uint8_t u8[8 + AV_INPUT_BUFFER_PADDING_SIZE]; - } tmp; - tmp.u64 = av_be2ne64(state); - init_get_bits(&bits, tmp.u8 + 8 - AV_AAC_ADTS_HEADER_SIZE, - AV_AAC_ADTS_HEADER_SIZE * 8); + AV_WB64(tmp, state); - if ((size = ff_adts_header_parse(&bits, &hdr)) < 0) + size = ff_adts_header_parse_buf(tmp + 8 - AV_AAC_ADTS_HEADER_SIZE, &hdr); + if (size < 0) return 0; *need_next_header = 0; *new_frame_start = 1; diff --git a/libavcodec/aaccoder_twoloop.h b/libavcodec/aaccoder_twoloop.h index 92dc2911a..c56abc68a 100644 --- a/libavcodec/aaccoder_twoloop.h +++ b/libavcodec/aaccoder_twoloop.h @@ -53,8 +53,6 @@ /** Frequency in Hz for lower limit of noise substitution **/ #define NOISE_LOW_LIMIT 4000 -#define sclip(x) av_clip(x,60,218) - /* Reflects the cost to change codebooks */ static inline int ff_pns_bits(SingleChannelElement *sce, int w, int g) { @@ -103,7 +101,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, */ float sfoffs = av_clipf(log2f(120.0f / lambda) * 4.0f, -5, 10); - int fflag, minscaler, maxscaler, nminscaler; + int fflag, minscaler, nminscaler; int its = 0; int maxits = 30; int allz = 0; @@ -574,12 +572,10 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, } minscaler = SCALE_MAX_POS; - maxscaler = 0; for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { for (g = 0; g < sce->ics.num_swb; g++) { if (!sce->zeroes[w*16+g]) { minscaler = FFMIN(minscaler, sce->sf_idx[w*16+g]); - maxscaler = FFMAX(maxscaler, sce->sf_idx[w*16+g]); } } } diff --git a/libavcodec/aacdec.h b/libavcodec/aacdec.h deleted file mode 100644 index 1b245f925..000000000 --- a/libavcodec/aacdec.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * AAC decoder definitions and structures - * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) - * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * AAC decoder definitions and structures - * @author Oded Shimon ( ods15 ods15 dyndns org ) - * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) - */ - -#ifndef AVCODEC_AACDEC_H -#define AVCODEC_AACDEC_H - -#include - -#include "libavutil/channel_layout.h" -#include "libavutil/float_dsp.h" -#include "libavutil/fixed_dsp.h" -#include "libavutil/mem_internal.h" -#include "libavutil/tx.h" - -#include "aac.h" -#include "aac_defines.h" -#include "mpeg4audio.h" -#include "sbr.h" - -/** - * Output configuration status - */ -enum OCStatus { - OC_NONE, ///< Output unconfigured - OC_TRIAL_PCE, ///< Output configuration under trial specified by an inband PCE - OC_TRIAL_FRAME, ///< Output configuration under trial specified by a frame header - OC_GLOBAL_HDR, ///< Output configuration set in a global header but not yet locked - OC_LOCKED, ///< Output configuration locked in place -}; - -enum AACOutputChannelOrder { - CHANNEL_ORDER_DEFAULT, - CHANNEL_ORDER_CODED, -}; - -/** - * The point during decoding at which channel coupling is applied. - */ -enum CouplingPoint { - BEFORE_TNS, - BETWEEN_TNS_AND_IMDCT, - AFTER_IMDCT = 3, -}; - -/** - * Long Term Prediction - */ -typedef struct LongTermPrediction { - int8_t present; - int16_t lag; - INTFLOAT coef; - int8_t used[MAX_LTP_LONG_SFB]; -} LongTermPrediction; - -/** - * Individual Channel Stream - */ -typedef struct IndividualChannelStream { - uint8_t max_sfb; ///< number of scalefactor bands per group - enum WindowSequence window_sequence[2]; - uint8_t use_kb_window[2]; ///< If set, use Kaiser-Bessel window, otherwise use a sine window. - int num_window_groups; - 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 - 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; - uint8_t prediction_used[41]; - uint8_t window_clipping[8]; ///< set if a certain window is near clipping -} IndividualChannelStream; - -/** - * Temporal Noise Shaping - */ -typedef struct TemporalNoiseShaping { - int present; - int n_filt[8]; - int length[8][4]; - int direction[8][4]; - int order[8][4]; - INTFLOAT coef[8][4][TNS_MAX_ORDER]; -} TemporalNoiseShaping; - -/** - * coupling parameters - */ -typedef struct ChannelCoupling { - enum CouplingPoint coupling_point; ///< The point during decoding at which coupling is applied. - int num_coupled; ///< number of target elements - enum RawDataBlockType type[8]; ///< Type of channel element to be coupled - SCE or CPE. - int id_select[8]; ///< element id - int ch_select[8]; /**< [0] shared list of gains; [1] list of gains for right channel; - * [2] list of gains for left channel; [3] lists of gains for both channels - */ - INTFLOAT gain[16][120]; -} ChannelCoupling; - -/** - * Single Channel Element - used for both SCE and LFE elements. - */ -typedef struct SingleChannelElement { - IndividualChannelStream ics; - TemporalNoiseShaping tns; - enum BandType band_type[128]; ///< band types - int band_type_run_end[120]; ///< band type run end points - INTFLOAT sf[120]; ///< scalefactors - DECLARE_ALIGNED(32, INTFLOAT, coeffs)[1024]; ///< coefficients for IMDCT, maybe processed - DECLARE_ALIGNED(32, INTFLOAT, saved)[1536]; ///< overlap - DECLARE_ALIGNED(32, INTFLOAT, ret_buf)[2048]; ///< PCM output buffer - DECLARE_ALIGNED(16, INTFLOAT, ltp_state)[3072]; ///< time signal for LTP - PredictorState predictor_state[MAX_PREDICTORS]; - INTFLOAT *ret; ///< PCM output -} SingleChannelElement; - -/** - * channel element - generic struct for SCE/CPE/CCE/LFE - */ -typedef struct ChannelElement { - int present; - // CPE specific - uint8_t ms_mask[128]; ///< Set if mid/side stereo is used for each scalefactor window band - // shared - SingleChannelElement ch[2]; - // CCE specific - ChannelCoupling coup; - SpectralBandReplication sbr; -} ChannelElement; - -typedef struct OutputConfiguration { - MPEG4AudioConfig m4ac; - uint8_t layout_map[MAX_ELEM_ID*4][3]; - int layout_map_tags; - AVChannelLayout ch_layout; - enum OCStatus status; -} OutputConfiguration; - -/** - * Dynamic Range Control - decoded from the bitstream but not processed further. - */ -typedef struct DynamicRangeControl { - int pce_instance_tag; ///< Indicates with which program the DRC info is associated. - int dyn_rng_sgn[17]; ///< DRC sign information; 0 - positive, 1 - negative - int dyn_rng_ctl[17]; ///< DRC magnitude information - int exclude_mask[MAX_CHANNELS]; ///< Channels to be excluded from DRC processing. - int band_incr; ///< Number of DRC bands greater than 1 having DRC info. - int interpolation_scheme; ///< Indicates the interpolation scheme used in the SBR QMF domain. - int band_top[17]; ///< Indicates the top of the i-th DRC band in units of 4 spectral lines. - int prog_ref_level; /**< A reference level for the long-term program audio level for all - * channels combined. - */ -} DynamicRangeControl; - -/** - * main AAC decoding context - */ -typedef struct AACDecContext { - const struct AVClass *class; - struct AVCodecContext *avctx; - struct AVFrame *frame; - - int is_saved; ///< Set if elements have stored overlap from previous frame. - DynamicRangeControl che_drc; - - /** - * @name Channel element related data - * @{ - */ - ChannelElement *che[4][MAX_ELEM_ID]; - ChannelElement *tag_che_map[4][MAX_ELEM_ID]; - int tags_mapped; - int warned_remapping_once; - /** @} */ - - /** - * @name temporary aligned temporary buffers - * (We do not want to have these on the stack.) - * @{ - */ - DECLARE_ALIGNED(32, INTFLOAT, buf_mdct)[1024]; - DECLARE_ALIGNED(32, INTFLOAT, temp)[128]; - /** @} */ - - /** - * @name Computed / set up during initialization - * @{ - */ - AVTXContext *mdct120; - AVTXContext *mdct128; - AVTXContext *mdct480; - AVTXContext *mdct512; - AVTXContext *mdct960; - AVTXContext *mdct1024; - AVTXContext *mdct_ltp; - - av_tx_fn mdct120_fn; - av_tx_fn mdct128_fn; - av_tx_fn mdct480_fn; - av_tx_fn mdct512_fn; - av_tx_fn mdct960_fn; - av_tx_fn mdct1024_fn; - av_tx_fn mdct_ltp_fn; -#if USE_FIXED - AVFixedDSPContext *fdsp; -#else - AVFloatDSPContext *fdsp; -#endif /* USE_FIXED */ - int random_state; - /** @} */ - - /** - * @name Members used for output - * @{ - */ - SingleChannelElement *output_element[MAX_CHANNELS]; ///< Points to each SingleChannelElement - /** @} */ - - - /** - * @name Japanese DTV specific extension - * @{ - */ - int force_dmono_mode;///< 0->not dmono, 1->use first channel, 2->use second channel - int dmono_mode; ///< 0->not dmono, 1->use first channel, 2->use second channel - /** @} */ - - enum AACOutputChannelOrder output_channel_order; - - OutputConfiguration oc[2]; - int warned_num_aac_frames; - int warned_960_sbr; - unsigned warned_71_wide; - int warned_gain_control; - int warned_he_aac_mono; - - /* aacdec functions pointers */ - void (*imdct_and_windowing)(struct AACDecContext *ac, SingleChannelElement *sce); - void (*apply_ltp)(struct AACDecContext *ac, SingleChannelElement *sce); - void (*apply_tns)(INTFLOAT coef[1024], TemporalNoiseShaping *tns, - IndividualChannelStream *ics, int decode); - void (*windowing_and_mdct_ltp)(struct AACDecContext *ac, INTFLOAT *out, - INTFLOAT *in, IndividualChannelStream *ics); - void (*update_ltp)(struct AACDecContext *ac, SingleChannelElement *sce); - void (*vector_pow43)(int *coefs, int len); - void (*subband_scale)(int *dst, int *src, int scale, int offset, int len, void *log_context); -} AACDecContext; - -void ff_aacdec_init_mips(AACDecContext *c); - -#endif /* AVCODEC_AACDEC_H */ diff --git a/libavcodec/aacdec_fixed.c b/libavcodec/aacdec_fixed.c deleted file mode 100644 index 305bb0ba9..000000000 --- a/libavcodec/aacdec_fixed.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Copyright (c) 2013 - * 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. - * - * AAC decoder fixed-point implementation - * - * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) - * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * AAC decoder - * @author Oded Shimon ( ods15 ods15 dyndns org ) - * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) - * - * Fixed point implementation - * @author Stanislav Ocovaj ( stanislav.ocovaj imgtec com ) - */ - -#define USE_FIXED 1 -#define TX_TYPE AV_TX_INT32_MDCT - -#include "libavutil/fixed_dsp.h" -#include "libavutil/opt.h" -#include "avcodec.h" -#include "codec_internal.h" -#include "get_bits.h" -#include "kbdwin.h" -#include "sinewin_fixed_tablegen.h" - -#include "aac.h" -#include "aacdec.h" -#include "aactab.h" -#include "aacdectab.h" -#include "adts_header.h" -#include "cbrt_data.h" -#include "sbr.h" -#include "aacsbr.h" -#include "mpeg4audio.h" -#include "profiles.h" -#include "libavutil/intfloat.h" - -#include -#include - -DECLARE_ALIGNED(32, static int, AAC_RENAME2(aac_kbd_long_1024))[1024]; -DECLARE_ALIGNED(32, static int, AAC_RENAME2(aac_kbd_short_128))[128]; -DECLARE_ALIGNED(32, static int, AAC_RENAME2(aac_kbd_long_960))[960]; -DECLARE_ALIGNED(32, static int, AAC_RENAME2(aac_kbd_short_120))[120]; - -/* @name ltp_coef - * Table of the LTP coefficients - */ -static const int ltp_coef_fixed[8] = { - Q30(0.570829), Q30(0.696616), Q30(0.813004), Q30(0.911304), - Q30(0.984900), Q30(1.067894), Q30(1.194601), Q30(1.369533), -}; - -/* @name tns_tmp2_map - * Tables of the tmp2[] arrays of LPC coefficients used for TNS. - * The suffix _M_N[] indicate the values of coef_compress and coef_res - * respectively. - * @{ - */ -static const int tns_tmp2_map_1_3[4] = { - Q31(0.00000000), Q31(-0.43388373), Q31(0.64278758), Q31(0.34202015), -}; - -static const int tns_tmp2_map_0_3[8] = { - Q31(0.00000000), Q31(-0.43388373), Q31(-0.78183150), Q31(-0.97492790), - Q31(0.98480773), Q31( 0.86602539), Q31( 0.64278758), Q31( 0.34202015), -}; - -static const int tns_tmp2_map_1_4[8] = { - Q31(0.00000000), Q31(-0.20791170), Q31(-0.40673664), Q31(-0.58778524), - Q31(0.67369562), Q31( 0.52643216), Q31( 0.36124167), Q31( 0.18374951), -}; - -static const int tns_tmp2_map_0_4[16] = { - Q31( 0.00000000), Q31(-0.20791170), Q31(-0.40673664), Q31(-0.58778524), - Q31(-0.74314481), Q31(-0.86602539), Q31(-0.95105654), Q31(-0.99452192), - Q31( 0.99573416), Q31( 0.96182561), Q31( 0.89516330), Q31( 0.79801720), - Q31( 0.67369562), Q31( 0.52643216), Q31( 0.36124167), Q31( 0.18374951), -}; - -static const int * const tns_tmp2_map_fixed[4] = { - tns_tmp2_map_0_3, - tns_tmp2_map_0_4, - tns_tmp2_map_1_3, - tns_tmp2_map_1_4 -}; -// @} - -static av_always_inline void reset_predict_state(PredictorState *ps) -{ - ps->r0.mant = 0; - ps->r0.exp = 0; - ps->r1.mant = 0; - ps->r1.exp = 0; - ps->cor0.mant = 0; - ps->cor0.exp = 0; - ps->cor1.mant = 0; - ps->cor1.exp = 0; - ps->var0.mant = 0x20000000; - ps->var0.exp = 1; - ps->var1.mant = 0x20000000; - ps->var1.exp = 1; -} - -static const int exp2tab[4] = { Q31(1.0000000000/2), Q31(1.1892071150/2), Q31(1.4142135624/2), Q31(1.6817928305/2) }; // 2^0, 2^0.25, 2^0.5, 2^0.75 - -static inline int *DEC_SPAIR(int *dst, unsigned idx) -{ - dst[0] = (idx & 15) - 4; - dst[1] = (idx >> 4 & 15) - 4; - - return dst + 2; -} - -static inline int *DEC_SQUAD(int *dst, unsigned idx) -{ - dst[0] = (idx & 3) - 1; - dst[1] = (idx >> 2 & 3) - 1; - dst[2] = (idx >> 4 & 3) - 1; - dst[3] = (idx >> 6 & 3) - 1; - - return dst + 4; -} - -static inline int *DEC_UPAIR(int *dst, unsigned idx, unsigned sign) -{ - dst[0] = (idx & 15) * (1 - (sign & 0xFFFFFFFE)); - dst[1] = (idx >> 4 & 15) * (1 - ((sign & 1) * 2)); - - return dst + 2; -} - -static inline int *DEC_UQUAD(int *dst, unsigned idx, unsigned sign) -{ - unsigned nz = idx >> 12; - - dst[0] = (idx & 3) * (1 + (((int)sign >> 31) * 2)); - sign <<= nz & 1; - nz >>= 1; - dst[1] = (idx >> 2 & 3) * (1 + (((int)sign >> 31) * 2)); - sign <<= nz & 1; - nz >>= 1; - dst[2] = (idx >> 4 & 3) * (1 + (((int)sign >> 31) * 2)); - sign <<= nz & 1; - nz >>= 1; - dst[3] = (idx >> 6 & 3) * (1 + (((int)sign >> 31) * 2)); - - return dst + 4; -} - -static void vector_pow43(int *coefs, int len) -{ - int i, coef; - - for (i=0; i> 2); - - if (s > 31) { - for (i=0; i 0) { - round = 1 << (s-1); - for (i=0; i> 32); - dst[i] = ((int)(out+round) >> s) * ssign; - } - } else if (s > -32) { - s = s + 32; - round = 1U << (s-1); - for (i=0; i> s); - dst[i] = out * (unsigned)ssign; - } - } else { - av_log(log_context, AV_LOG_ERROR, "Overflow in subband_scale()\n"); - } -} - -static void noise_scale(int *coefs, int scale, int band_energy, int len) -{ - int s = -scale; - unsigned int round; - int i, out, c = exp2tab[s & 3]; - int nlz = 0; - - av_assert0(s >= 0); - while (band_energy > 0x7fff) { - band_energy >>= 1; - nlz++; - } - c /= band_energy; - s = 21 + nlz - (s >> 2); - - if (s > 31) { - for (i=0; i= 0) { - round = s ? 1 << (s-1) : 0; - for (i=0; i> 32); - coefs[i] = -((int)(out+round) >> s); - } - } - else { - s = s + 32; - if (s > 0) { - round = 1 << (s-1); - for (i=0; i> s); - coefs[i] = -out; - } - } else { - for (i=0; i> 31; - tmp.mant = (pf.mant ^ s) - s; - tmp.mant = (tmp.mant + 0x00200000U) & 0xFFC00000U; - tmp.mant = (tmp.mant ^ s) - s; - - return tmp; -} - -static av_always_inline SoftFloat flt16_even(SoftFloat pf) -{ - SoftFloat tmp; - int s; - - tmp.exp = pf.exp; - s = pf.mant >> 31; - tmp.mant = (pf.mant ^ s) - s; - tmp.mant = (tmp.mant + 0x001FFFFFU + (tmp.mant & 0x00400000U >> 16)) & 0xFFC00000U; - tmp.mant = (tmp.mant ^ s) - s; - - return tmp; -} - -static av_always_inline SoftFloat flt16_trunc(SoftFloat pf) -{ - SoftFloat pun; - int s; - - pun.exp = pf.exp; - s = pf.mant >> 31; - pun.mant = (pf.mant ^ s) - s; - pun.mant = pun.mant & 0xFFC00000U; - pun.mant = (pun.mant ^ s) - s; - - return pun; -} - -static av_always_inline void predict(PredictorState *ps, int *coef, - int output_enable) -{ - const SoftFloat a = { 1023410176, 0 }; // 61.0 / 64 - const SoftFloat alpha = { 973078528, 0 }; // 29.0 / 32 - SoftFloat e0, e1; - SoftFloat pv; - SoftFloat k1, k2; - SoftFloat r0 = ps->r0, r1 = ps->r1; - SoftFloat cor0 = ps->cor0, cor1 = ps->cor1; - SoftFloat var0 = ps->var0, var1 = ps->var1; - SoftFloat tmp; - - if (var0.exp > 1 || (var0.exp == 1 && var0.mant > 0x20000000)) { - k1 = av_mul_sf(cor0, flt16_even(av_div_sf(a, var0))); - } - else { - k1.mant = 0; - k1.exp = 0; - } - - if (var1.exp > 1 || (var1.exp == 1 && var1.mant > 0x20000000)) { - k2 = av_mul_sf(cor1, flt16_even(av_div_sf(a, var1))); - } - else { - k2.mant = 0; - k2.exp = 0; - } - - tmp = av_mul_sf(k1, r0); - pv = flt16_round(av_add_sf(tmp, av_mul_sf(k2, r1))); - if (output_enable) { - int shift = 28 - pv.exp; - - if (shift < 31) { - if (shift > 0) { - *coef += (unsigned)((pv.mant + (1 << (shift - 1))) >> shift); - } else - *coef += (unsigned)pv.mant << -shift; - } - } - - e0 = av_int2sf(*coef, 2); - e1 = av_sub_sf(e0, tmp); - - ps->cor1 = flt16_trunc(av_add_sf(av_mul_sf(alpha, cor1), av_mul_sf(r1, e1))); - tmp = av_add_sf(av_mul_sf(r1, r1), av_mul_sf(e1, e1)); - tmp.exp--; - ps->var1 = flt16_trunc(av_add_sf(av_mul_sf(alpha, var1), tmp)); - ps->cor0 = flt16_trunc(av_add_sf(av_mul_sf(alpha, cor0), av_mul_sf(r0, e0))); - tmp = av_add_sf(av_mul_sf(r0, r0), av_mul_sf(e0, e0)); - tmp.exp--; - ps->var0 = flt16_trunc(av_add_sf(av_mul_sf(alpha, var0), tmp)); - - ps->r1 = flt16_trunc(av_mul_sf(a, av_sub_sf(r0, av_mul_sf(k1, e0)))); - ps->r0 = flt16_trunc(av_mul_sf(a, e0)); -} - - -static const int cce_scale_fixed[8] = { - Q30(1.0), //2^(0/8) - Q30(1.0905077327), //2^(1/8) - Q30(1.1892071150), //2^(2/8) - Q30(1.2968395547), //2^(3/8) - Q30(1.4142135624), //2^(4/8) - Q30(1.5422108254), //2^(5/8) - Q30(1.6817928305), //2^(6/8) - Q30(1.8340080864), //2^(7/8) -}; - -/** - * Apply dependent channel coupling (applied before IMDCT). - * - * @param index index into coupling gain array - */ -static void apply_dependent_coupling_fixed(AACDecContext *ac, - SingleChannelElement *target, - ChannelElement *cce, int index) -{ - IndividualChannelStream *ics = &cce->ch[0].ics; - const uint16_t *offsets = ics->swb_offset; - int *dest = target->coeffs; - const int *src = cce->ch[0].coeffs; - int g, i, group, k, idx = 0; - if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { - av_log(ac->avctx, AV_LOG_ERROR, - "Dependent coupling is not supported together with LTP\n"); - return; - } - for (g = 0; g < ics->num_window_groups; g++) { - for (i = 0; i < ics->max_sfb; i++, idx++) { - if (cce->ch[0].band_type[idx] != ZERO_BT) { - const int gain = cce->coup.gain[index][idx]; - int shift, round, c, tmp; - - if (gain < 0) { - c = -cce_scale_fixed[-gain & 7]; - shift = (-gain-1024) >> 3; - } - else { - c = cce_scale_fixed[gain & 7]; - shift = (gain-1024) >> 3; - } - - if (shift < -31) { - // Nothing to do - } else if (shift < 0) { - shift = -shift; - round = 1 << (shift - 1); - - for (group = 0; group < ics->group_len[g]; group++) { - for (k = offsets[i]; k < offsets[i + 1]; k++) { - tmp = (int)(((int64_t)src[group * 128 + k] * c + \ - (int64_t)0x1000000000) >> 37); - dest[group * 128 + k] += (tmp + (int64_t)round) >> shift; - } - } - } - else { - for (group = 0; group < ics->group_len[g]; group++) { - for (k = offsets[i]; k < offsets[i + 1]; k++) { - tmp = (int)(((int64_t)src[group * 128 + k] * c + \ - (int64_t)0x1000000000) >> 37); - dest[group * 128 + k] += tmp * (1U << shift); - } - } - } - } - } - dest += ics->group_len[g] * 128; - src += ics->group_len[g] * 128; - } -} - -/** - * Apply independent channel coupling (applied after IMDCT). - * - * @param index index into coupling gain array - */ -static void apply_independent_coupling_fixed(AACDecContext *ac, - SingleChannelElement *target, - ChannelElement *cce, int index) -{ - int i, c, shift, round, tmp; - const int gain = cce->coup.gain[index][0]; - const int *src = cce->ch[0].ret; - unsigned int *dest = target->ret; - const int len = 1024 << (ac->oc[1].m4ac.sbr == 1); - - c = cce_scale_fixed[gain & 7]; - shift = (gain-1024) >> 3; - if (shift < -31) { - return; - } else if (shift < 0) { - shift = -shift; - round = 1 << (shift - 1); - - for (i = 0; i < len; i++) { - tmp = (int)(((int64_t)src[i] * c + (int64_t)0x1000000000) >> 37); - dest[i] += (tmp + round) >> shift; - } - } - else { - for (i = 0; i < len; i++) { - tmp = (int)(((int64_t)src[i] * c + (int64_t)0x1000000000) >> 37); - dest[i] += tmp * (1U << shift); - } - } -} - -#include "aacdec_template.c" - -const FFCodec ff_aac_fixed_decoder = { - .p.name = "aac_fixed", - CODEC_LONG_NAME("AAC (Advanced Audio Coding)"), - .p.type = AVMEDIA_TYPE_AUDIO, - .p.id = AV_CODEC_ID_AAC, - .priv_data_size = sizeof(AACDecContext), - .init = aac_decode_init, - .close = aac_decode_close, - FF_CODEC_DECODE_CB(aac_decode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE - }, - .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, - .p.priv_class = &aac_decoder_class, - .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), - .flush = flush, -}; diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index 55fa30780..3ff61f788 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -33,6 +33,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/libm.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "codec_internal.h" @@ -537,11 +538,9 @@ static void adjust_frame_information(ChannelElement *cpe, int chans) maxsfb = 0; cpe->ch[ch].pulse.num_pulse = 0; for (w = 0; w < ics->num_windows; w += ics->group_len[w]) { - for (w2 = 0; w2 < ics->group_len[w]; w2++) { - for (cmaxsfb = ics->num_swb; cmaxsfb > 0 && cpe->ch[ch].zeroes[w*16+cmaxsfb-1]; cmaxsfb--) - ; - maxsfb = FFMAX(maxsfb, cmaxsfb); - } + for (cmaxsfb = ics->num_swb; cmaxsfb > 0 && cpe->ch[ch].zeroes[w*16+cmaxsfb-1]; cmaxsfb--) + ; + maxsfb = FFMAX(maxsfb, cmaxsfb); } ics->max_sfb = maxsfb; @@ -1178,6 +1177,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, &avpkt->duration); + avpkt->flags |= AV_PKT_FLAG_KEY; + *got_packet_ptr = 1; return 0; } @@ -1393,7 +1394,7 @@ 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", "Default fast search", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, 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}, diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h index 8899f90ac..ae15f91e0 100644 --- a/libavcodec/aacenc.h +++ b/libavcodec/aacenc.h @@ -49,6 +49,20 @@ typedef enum AACCoder { AAC_CODER_NB, }AACCoder; +/** + * Predictor State + */ +typedef struct PredictorState { + float cor0; + float cor1; + float var0; + float var1; + float r0; + float r1; + float k1; + float x_est; +} PredictorState; + typedef struct AACEncOptions { int coder; int pns; @@ -228,7 +242,7 @@ typedef struct AACEncContext { enum RawDataBlockType cur_type; ///< channel group type cur_channel belongs to AudioFrameQueue afq; - DECLARE_ALIGNED(16, int, qcoefs)[96]; ///< quantized coefficients + DECLARE_ALIGNED(32, int, qcoefs)[96]; ///< quantized coefficients DECLARE_ALIGNED(32, float, scoefs)[1024]; ///< scaled coefficients uint16_t quantize_band_cost_cache_generation; diff --git a/libavcodec/aacenc_tns.c b/libavcodec/aacenc_tns.c index 60888fece..fa3cd2af3 100644 --- a/libavcodec/aacenc_tns.c +++ b/libavcodec/aacenc_tns.c @@ -181,7 +181,7 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce) for (w = 0; w < sce->ics.num_windows; w++) { float en[2] = {0.0f, 0.0f}; - int oc_start = 0, os_start = 0; + int oc_start = 0; int coef_start = sce->ics.swb_offset[sfb_start]; for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) { @@ -202,12 +202,11 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce) tns->n_filt[w] = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3; for (g = 0; g < tns->n_filt[w]; g++) { tns->direction[w][g] = slant != 2 ? slant : en[g] < en[!g]; - tns->order[w][g] = g < tns->n_filt[w] ? order/tns->n_filt[w] : order - oc_start; - tns->length[w][g] = g < tns->n_filt[w] ? sfb_len/tns->n_filt[w] : sfb_len - os_start; + tns->order[w][g] = order/tns->n_filt[w]; + tns->length[w][g] = sfb_len/tns->n_filt[w]; quantize_coefs(&coefs[oc_start], tns->coef_idx[w][g], tns->coef[w][g], tns->order[w][g], c_bits); oc_start += tns->order[w][g]; - os_start += tns->length[w][g]; } count++; } diff --git a/libavcodec/aacpsdsp.h b/libavcodec/aacpsdsp.h index 8b32761bd..149121225 100644 --- a/libavcodec/aacpsdsp.h +++ b/libavcodec/aacpsdsp.h @@ -54,7 +54,6 @@ typedef struct PSDSPContext { void AAC_RENAME(ff_psdsp_init)(PSDSPContext *s); void ff_psdsp_init_arm(PSDSPContext *s); void ff_psdsp_init_aarch64(PSDSPContext *s); -void ff_psdsp_init_mips(PSDSPContext *s); void ff_psdsp_init_riscv(PSDSPContext *s); void ff_psdsp_init_x86(PSDSPContext *s); diff --git a/libavcodec/aacpsdsp_template.c b/libavcodec/aacpsdsp_template.c index 7100ae7bc..c28ba2c9a 100644 --- a/libavcodec/aacpsdsp_template.c +++ b/libavcodec/aacpsdsp_template.c @@ -226,8 +226,6 @@ av_cold void AAC_RENAME(ff_psdsp_init)(PSDSPContext *s) ff_psdsp_init_arm(s); #elif ARCH_AARCH64 ff_psdsp_init_aarch64(s); -#elif ARCH_MIPS - ff_psdsp_init_mips(s); #elif ARCH_RISCV ff_psdsp_init_riscv(s); #elif ARCH_X86 diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c index 1fbd259e5..019be09fa 100644 --- a/libavcodec/aacpsy.c +++ b/libavcodec/aacpsy.c @@ -26,6 +26,7 @@ #include "libavutil/attributes.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "aac.h" @@ -222,10 +223,6 @@ static const float psy_fir_coeffs[] = { -5.52212e-17 * 2, -0.313819 * 2 }; -#if ARCH_MIPS -# include "mips/aacpsy_mips.h" -#endif /* ARCH_MIPS */ - /** * Calculate the ABR attack threshold from the above LAME psymodel table. */ diff --git a/libavcodec/aacsbr.c b/libavcodec/aacsbr.c index aafc00049..78f0aead8 100644 --- a/libavcodec/aacsbr.c +++ b/libavcodec/aacsbr.c @@ -43,10 +43,6 @@ #include #include -#if ARCH_MIPS -#include "mips/aacsbr_mips.h" -#endif /* ARCH_MIPS */ - /** * 2^(x) for integer x * @return correctly rounded float diff --git a/libavcodec/aacsbr.h b/libavcodec/aacsbr.h index cb680cc54..3958b43b9 100644 --- a/libavcodec/aacsbr.h +++ b/libavcodec/aacsbr.h @@ -30,14 +30,13 @@ #define AVCODEC_AACSBR_H #include "get_bits.h" -#include "aac_defines.h" -#include "sbr.h" +#include "aac/aacdec.h" + +#include "libavutil/attributes_internal.h" #define ENVELOPE_ADJUSTMENT_OFFSET 2 #define NOISE_FLOOR_OFFSET 6 -struct AACDecContext; - /** * SBR VLC tables */ @@ -68,19 +67,44 @@ enum { EXTENSION_ID_PS = 2, }; +FF_VISIBILITY_PUSH_HIDDEN /** Initialize SBR. */ -void AAC_RENAME(ff_aac_sbr_init)(void); -/** Initialize one SBR context. */ -int AAC_RENAME(ff_aac_sbr_ctx_init)(struct AACDecContext *ac, SpectralBandReplication *sbr, int id_aac); -/** Close one SBR context. */ -void AAC_RENAME(ff_aac_sbr_ctx_close)(SpectralBandReplication *sbr); -/** Decode one SBR element. */ -int AAC_RENAME(ff_decode_sbr_extension)(struct AACDecContext *ac, SpectralBandReplication *sbr, - GetBitContext *gb, int crc, int cnt, int id_aac); -/** Apply one SBR element to one AAC element. */ -void AAC_RENAME(ff_sbr_apply)(struct AACDecContext *ac, SpectralBandReplication *sbr, int id_aac, - INTFLOAT* L, INTFLOAT *R); +void ff_aac_sbr_init(void); +void ff_aac_sbr_init_fixed(void); +/** + * Allocate an ExtChannelElement (if necessary) and + * initialize the SBR context contained in it. + */ +int ff_aac_sbr_ctx_alloc_init(AACDecContext *ac, ChannelElement **che, int id_aac); +int ff_aac_sbr_ctx_alloc_init_fixed(AACDecContext *ac, ChannelElement **che, int id_aac); -void ff_aacsbr_func_ptr_init_mips(AACSBRContext *c); +/** Close the SBR context implicitly contained in a ChannelElement. */ +void ff_aac_sbr_ctx_close(ChannelElement *che); +void ff_aac_sbr_ctx_close_fixed(ChannelElement *che); + +/** Decode one SBR element. */ +int ff_aac_sbr_decode_extension(AACDecContext *ac, ChannelElement *che, + GetBitContext *gb, int crc, int cnt, int id_aac); +int ff_aac_sbr_decode_extension_fixed(AACDecContext *ac, ChannelElement *che, + GetBitContext *gb, int crc, int cnt, int id_aac); + +/** Due to channel allocation not being known upon SBR parameter transmission, + * supply the parameters separately. + * Functionally identical to ff_aac_sbr_decode_extension() */ +int ff_aac_sbr_config_usac(AACDecContext *ac, ChannelElement *che, + AACUsacElemConfig *ue); + +/** Decode frame SBR data, USAC. */ +int ff_aac_sbr_decode_usac_data(AACDecContext *ac, ChannelElement *che, + AACUsacElemConfig *ue, GetBitContext *gb, + int sbr_ch, int indep_flag); + +/** Apply one SBR element to one AAC element. */ +void ff_aac_sbr_apply(AACDecContext *ac, ChannelElement *che, + int id_aac, void /* float */ *L, void /* float */ *R); +void ff_aac_sbr_apply_fixed(AACDecContext *ac, ChannelElement *che, + int id_aac, void /* int */ *L, void /* int */ *R); + +FF_VISIBILITY_POP_HIDDEN #endif /* AVCODEC_AACSBR_H */ diff --git a/libavcodec/aacsbr_template.c b/libavcodec/aacsbr_template.c index cdfaed636..9fae44d9a 100644 --- a/libavcodec/aacsbr_template.c +++ b/libavcodec/aacsbr_template.c @@ -32,29 +32,32 @@ * @author Zoran Basaric ( zoran.basaric@imgtec.com ) */ -#include "aacdec.h" -#include "aacdectab.h" +#include "aac/aacdec.h" +#include "aac/aacdec_tab.h" #include "avcodec.h" #include "libavutil/qsort.h" +#include "libavutil/mem.h" -static av_cold void aacsbr_tableinit(void) +typedef struct ExtChannelElement { + ChannelElement ch; + PredictorState predictor_state[2][MAX_PREDICTORS]; + SpectralBandReplication sbr; +} ExtChannelElement; + +static inline SpectralBandReplication *get_sbr(ChannelElement *ch) { - int n; - - for (n = 0; n < 320; n++) - sbr_qmf_window_ds[n] = sbr_qmf_window_us[2*n]; + return &((ExtChannelElement*)ch)->sbr; } av_cold void AAC_RENAME(ff_aac_sbr_init)(void) { - aacsbr_tableinit(); - AAC_RENAME(ff_ps_init)(); } /** Places SBR in pure upsampling mode. */ static void sbr_turnoff(SpectralBandReplication *sbr) { sbr->start = 0; + sbr->usac = 0; sbr->ready_for_dequant = 0; // Init defults used in pure upsampling mode sbr->kx[1] = 32; //Typo in spec, kx' inits to 32 @@ -64,13 +67,20 @@ static void sbr_turnoff(SpectralBandReplication *sbr) { memset(&sbr->spectrum_params, -1, sizeof(SpectrumParameters)); } -av_cold int AAC_RENAME(ff_aac_sbr_ctx_init)(AACDecContext *ac, SpectralBandReplication *sbr, int id_aac) +av_cold int AAC_RENAME(ff_aac_sbr_ctx_alloc_init)(AACDecContext *ac, + ChannelElement **che, int id_aac) { + SpectralBandReplication *sbr; + ExtChannelElement *ext = av_mallocz(sizeof(*ext)); int ret; float scale; - if (sbr->mdct) - return 0; + if (!ext) + return AVERROR(ENOMEM); + *che = &ext->ch; + sbr = &ext->sbr; + ext->ch.ch[0].AAC_RENAME(predictor_state) = ext->predictor_state[0]; + ext->ch.ch[1].AAC_RENAME(predictor_state) = ext->predictor_state[1]; sbr->kx[0] = sbr->kx[1]; sbr->id_aac = id_aac; @@ -102,8 +112,9 @@ av_cold int AAC_RENAME(ff_aac_sbr_ctx_init)(AACDecContext *ac, SpectralBandRepli return 0; } -av_cold void AAC_RENAME(ff_aac_sbr_ctx_close)(SpectralBandReplication *sbr) +av_cold void AAC_RENAME(ff_aac_sbr_ctx_close)(ChannelElement *che) { + SpectralBandReplication *sbr = get_sbr(che); av_tx_uninit(&sbr->mdct); av_tx_uninit(&sbr->mdct_ana); } @@ -174,7 +185,8 @@ static void sbr_make_f_tablelim(SpectralBandReplication *sbr) } } -static unsigned int read_sbr_header(SpectralBandReplication *sbr, GetBitContext *gb) +static unsigned int read_sbr_header(SpectralBandReplication *sbr, + GetBitContext *gb, int is_usac) { unsigned int cnt = get_bits_count(gb); uint8_t bs_header_extra_1; @@ -184,15 +196,20 @@ static unsigned int read_sbr_header(SpectralBandReplication *sbr, GetBitContext sbr->start = 1; sbr->ready_for_dequant = 0; + sbr->usac = is_usac; // Save last spectrum parameters variables to compare to new ones memcpy(&old_spectrum_params, &sbr->spectrum_params, sizeof(SpectrumParameters)); - sbr->bs_amp_res_header = get_bits1(gb); + if (!is_usac) + sbr->bs_amp_res_header = get_bits1(gb); + sbr->spectrum_params.bs_start_freq = get_bits(gb, 4); sbr->spectrum_params.bs_stop_freq = get_bits(gb, 4); - sbr->spectrum_params.bs_xover_band = get_bits(gb, 3); - skip_bits(gb, 2); // bs_reserved + + if (!is_usac) + sbr->spectrum_params.bs_xover_band = get_bits(gb, 3); + skip_bits(gb, 2); // bs_reserved bs_header_extra_1 = get_bits1(gb); bs_header_extra_2 = get_bits1(gb); @@ -582,6 +599,7 @@ static int sbr_make_f_derived(AACDecContext *ac, SpectralBandReplication *sbr) if (sbr->n_q > 5) { av_log(ac->avctx, AV_LOG_ERROR, "Too many noise floor scale factors: %d\n", sbr->n_q); + sbr->n_q = 1; return -1; } @@ -635,7 +653,7 @@ static int read_sbr_grid(AACDecContext *ac, SpectralBandReplication *sbr, switch (bs_frame_class = get_bits(gb, 2)) { case FIXFIX: bs_num_env = 1 << get_bits(gb, 2); - if (bs_num_env > 4) { + if (bs_num_env > (sbr->usac ? 8 : 5)) { av_log(ac->avctx, AV_LOG_ERROR, "Invalid bitstream, too many SBR envelopes in FIXFIX type SBR frame: %d\n", bs_num_env); @@ -783,10 +801,26 @@ static void copy_sbr_grid(SBRData *dst, const SBRData *src) { /// Read how the envelope and noise floor data is delta coded static void read_sbr_dtdf(SpectralBandReplication *sbr, GetBitContext *gb, - SBRData *ch_data) + SBRData *ch_data, int indep_flag) { - get_bits1_vector(gb, ch_data->bs_df_env, ch_data->bs_num_env); - get_bits1_vector(gb, ch_data->bs_df_noise, ch_data->bs_num_noise); + if (sbr->usac) { + if (indep_flag) { + ch_data->bs_df_env[0] = 0; + get_bits1_vector(gb, &ch_data->bs_df_env[1], ch_data->bs_num_env - 1); + } else { + get_bits1_vector(gb, ch_data->bs_df_env, ch_data->bs_num_env); + } + + if (indep_flag) { + ch_data->bs_df_noise[0] = 0; + get_bits1_vector(gb, &ch_data->bs_df_noise[1], ch_data->bs_num_noise - 1); + } else { + get_bits1_vector(gb, ch_data->bs_df_noise, ch_data->bs_num_noise); + } + } else { + get_bits1_vector(gb, ch_data->bs_df_env, ch_data->bs_num_env); + get_bits1_vector(gb, ch_data->bs_df_noise, ch_data->bs_num_noise); + } } /// Read inverse filtering data @@ -801,7 +835,7 @@ static void read_sbr_invf(SpectralBandReplication *sbr, GetBitContext *gb, } static int read_sbr_envelope(AACDecContext *ac, SpectralBandReplication *sbr, GetBitContext *gb, - SBRData *ch_data, int ch) + SBRData *ch_data, int ch) { int bits; int i, j, k; @@ -871,6 +905,13 @@ static int read_sbr_envelope(AACDecContext *ac, SpectralBandReplication *sbr, Ge } } } + if (sbr->usac) { + if (sbr->inter_tes) { + ch_data->temp_shape[i] = get_bits(gb, 1); + if (ch_data->temp_shape[i]) + ch_data->temp_shape_mode[i] = get_bits(gb, 2); + } + } } //assign 0th elements of env_facs_q from last elements @@ -960,7 +1001,7 @@ static int read_sbr_single_channel_element(AACDecContext *ac, if (read_sbr_grid(ac, sbr, gb, &sbr->data[0])) return -1; - read_sbr_dtdf(sbr, gb, &sbr->data[0]); + read_sbr_dtdf(sbr, gb, &sbr->data[0], 0); read_sbr_invf(sbr, gb, &sbr->data[0]); if((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[0], 0)) < 0) return ret; @@ -986,8 +1027,8 @@ static int read_sbr_channel_pair_element(AACDecContext *ac, if (read_sbr_grid(ac, sbr, gb, &sbr->data[0])) return -1; copy_sbr_grid(&sbr->data[1], &sbr->data[0]); - read_sbr_dtdf(sbr, gb, &sbr->data[0]); - read_sbr_dtdf(sbr, gb, &sbr->data[1]); + read_sbr_dtdf(sbr, gb, &sbr->data[0], 0); + read_sbr_dtdf(sbr, gb, &sbr->data[1], 0); read_sbr_invf(sbr, gb, &sbr->data[0]); memcpy(sbr->data[1].bs_invf_mode[1], sbr->data[1].bs_invf_mode[0], sizeof(sbr->data[1].bs_invf_mode[0])); memcpy(sbr->data[1].bs_invf_mode[0], sbr->data[0].bs_invf_mode[0], sizeof(sbr->data[1].bs_invf_mode[0])); @@ -1003,8 +1044,8 @@ static int read_sbr_channel_pair_element(AACDecContext *ac, if (read_sbr_grid(ac, sbr, gb, &sbr->data[0]) || read_sbr_grid(ac, sbr, gb, &sbr->data[1])) return -1; - read_sbr_dtdf(sbr, gb, &sbr->data[0]); - read_sbr_dtdf(sbr, gb, &sbr->data[1]); + read_sbr_dtdf(sbr, gb, &sbr->data[0], 0); + read_sbr_dtdf(sbr, gb, &sbr->data[1], 0); read_sbr_invf(sbr, gb, &sbr->data[0]); read_sbr_invf(sbr, gb, &sbr->data[1]); if((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[0], 0)) < 0) @@ -1090,9 +1131,11 @@ static void sbr_reset(AACDecContext *ac, SpectralBandReplication *sbr) * * @return Returns number of bytes consumed from the TYPE_FIL element. */ -int AAC_RENAME(ff_decode_sbr_extension)(AACDecContext *ac, SpectralBandReplication *sbr, - GetBitContext *gb_host, int crc, int cnt, int id_aac) +int AAC_RENAME(ff_aac_sbr_decode_extension)(AACDecContext *ac, ChannelElement *che, + GetBitContext *gb_host, int crc, + int cnt, int id_aac) { + SpectralBandReplication *sbr = get_sbr(che); unsigned int num_sbr_bits = 0, num_align_bits; unsigned bytes_read; GetBitContext gbc = *gb_host, *gb = &gbc; @@ -1117,7 +1160,7 @@ int AAC_RENAME(ff_decode_sbr_extension)(AACDecContext *ac, SpectralBandReplicati num_sbr_bits++; if (get_bits1(gb)) // bs_header_flag - num_sbr_bits += read_sbr_header(sbr, gb); + num_sbr_bits += read_sbr_header(sbr, gb, 0); if (sbr->reset) sbr_reset(ac, sbr); @@ -1136,6 +1179,176 @@ int AAC_RENAME(ff_decode_sbr_extension)(AACDecContext *ac, SpectralBandReplicati return cnt; } +#if !USE_FIXED +static void copy_usac_default_header(SpectralBandReplication *sbr, + AACUsacElemConfig *ue) +{ + sbr->inter_tes = ue->sbr.bs_intertes; + + sbr->spectrum_params.bs_start_freq = ue->sbr.dflt.start_freq; + sbr->spectrum_params.bs_stop_freq = ue->sbr.dflt.stop_freq; + + sbr->spectrum_params.bs_freq_scale = ue->sbr.dflt.freq_scale; + sbr->spectrum_params.bs_alter_scale = ue->sbr.dflt.alter_scale; + sbr->spectrum_params.bs_noise_bands = ue->sbr.dflt.noise_bands; + + sbr->bs_limiter_bands = ue->sbr.dflt.limiter_bands; + sbr->bs_limiter_gains = ue->sbr.dflt.limiter_gains; + sbr->bs_interpol_freq = ue->sbr.dflt.interpol_freq; + sbr->bs_smoothing_mode = ue->sbr.dflt.smoothing_mode; +} + +int ff_aac_sbr_config_usac(AACDecContext *ac, ChannelElement *che, + AACUsacElemConfig *ue) +{ + SpectralBandReplication *sbr = get_sbr(che); + sbr_turnoff(sbr); + return 0; +} + +int ff_aac_sbr_decode_usac_data(AACDecContext *ac, ChannelElement *che, + AACUsacElemConfig *ue, GetBitContext *gb, + int sbr_ch, int indep_flag) +{ + int ret; + SpectralBandReplication *sbr = get_sbr(che); + int info_present = 1; + int header_present = 1; + + sbr->reset = 0; + sbr->usac = 1; + + sbr->sample_rate = ac->oc[1].m4ac.ext_sample_rate; + sbr->id_aac = sbr_ch == 2 ? TYPE_CPE : TYPE_SCE; + + if (!indep_flag) { + info_present = get_bits1(gb); + if (info_present) + header_present = get_bits1(gb); + else + header_present = 0; + } + + if (info_present) { + /* SbrInfo() */ + sbr->bs_amp_res_header = get_bits1(gb); + sbr->spectrum_params.bs_xover_band = get_bits(gb, 4); + sbr->bs_sbr_preprocessing = get_bits1(gb); + /* if (bs_pvc) ... */ + } + + if (header_present) { + if (get_bits1(gb)) { + int old_bs_limiter_bands = sbr->bs_limiter_bands; + SpectrumParameters old_spectrum_params; + memcpy(&old_spectrum_params, &sbr->spectrum_params, + sizeof(SpectrumParameters)); + + copy_usac_default_header(sbr, ue); + // Check if spectrum parameters changed + if (memcmp(&old_spectrum_params, &sbr->spectrum_params, + sizeof(SpectrumParameters))) + sbr->reset = 1; + + if (sbr->bs_limiter_bands != old_bs_limiter_bands && !sbr->reset) + sbr_make_f_tablelim(sbr); + } else { + read_sbr_header(sbr, gb, 1); + } + + sbr->start = 1; + } + + //Save some state from the previous frame. + sbr->kx[0] = sbr->kx[1]; + sbr->m[0] = sbr->m[1]; + sbr->kx_and_m_pushed = 1; + + if (sbr->reset) + sbr_reset(ac, sbr); + + sbr->ready_for_dequant = 1; + + if (sbr_ch == 1) { /* sbr_single_channel_element */ + /* if (harmonicSBR) ... */ + + if (read_sbr_grid(ac, sbr, gb, &sbr->data[0])) + return -1; + + read_sbr_dtdf(sbr, gb, &sbr->data[0], indep_flag); + read_sbr_invf(sbr, gb, &sbr->data[0]); + + if ((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + + if ((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + + 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 */ + /* if (harmonicSBR) ... */ + + if (read_sbr_grid(ac, sbr, gb, &sbr->data[0])) + return -1; + copy_sbr_grid(&sbr->data[1], &sbr->data[0]); + + read_sbr_dtdf(sbr, gb, &sbr->data[0], indep_flag); + read_sbr_dtdf(sbr, gb, &sbr->data[1], indep_flag); + + read_sbr_invf(sbr, gb, &sbr->data[0]); + memcpy(sbr->data[1].bs_invf_mode[1], sbr->data[1].bs_invf_mode[0], + sizeof(sbr->data[1].bs_invf_mode[0])); + memcpy(sbr->data[1].bs_invf_mode[0], sbr->data[0].bs_invf_mode[0], + sizeof(sbr->data[1].bs_invf_mode[0])); + + if ((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + if ((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + + if ((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[1], 1)) < 0) + return ret; + if ((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[1], 1)) < 0) + return ret; + + if ((sbr->data[0].bs_add_harmonic_flag = get_bits1(gb))) + get_bits1_vector(gb, sbr->data[0].bs_add_harmonic, sbr->n[1]); + 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 */ + /* if (harmonicSBR) ... */ + if (read_sbr_grid(ac, sbr, gb, &sbr->data[0])) + return -1; + if (read_sbr_grid(ac, sbr, gb, &sbr->data[1])) + return -1; + + read_sbr_dtdf(sbr, gb, &sbr->data[0], indep_flag); + read_sbr_dtdf(sbr, gb, &sbr->data[1], indep_flag); + + read_sbr_invf(sbr, gb, &sbr->data[0]); + read_sbr_invf(sbr, gb, &sbr->data[1]); + + if ((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + if ((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[1], 1)) < 0) + return ret; + + if ((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + if ((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[1], 1)) < 0) + return ret; + + if ((sbr->data[0].bs_add_harmonic_flag = get_bits1(gb))) + get_bits1_vector(gb, sbr->data[0].bs_add_harmonic, sbr->n[1]); + if ((sbr->data[1].bs_add_harmonic_flag = get_bits1(gb))) + get_bits1_vector(gb, sbr->data[1].bs_add_harmonic, sbr->n[1]); + } + + return 0; +} +#endif + /** * Analysis QMF Bank (14496-3 sp04 p206) * @@ -1456,9 +1669,11 @@ static void sbr_env_estimate(AAC_FLOAT (*e_curr)[48], INTFLOAT X_high[64][40][2] } } -void AAC_RENAME(ff_sbr_apply)(AACDecContext *ac, SpectralBandReplication *sbr, int id_aac, - INTFLOAT* L, INTFLOAT* R) +void AAC_RENAME(ff_aac_sbr_apply)(AACDecContext *ac, ChannelElement *che, + int id_aac, void *L_, void *R_) { + INTFLOAT *L = L_, *R = R_; + SpectralBandReplication *sbr = get_sbr(che); int downsampled = ac->oc[1].m4ac.ext_sample_rate < sbr->sample_rate; int ch; int nch = (id_aac == TYPE_CPE) ? 2 : 1; @@ -1556,10 +1771,4 @@ static void aacsbr_func_ptr_init(AACSBRContext *c) c->sbr_hf_assemble = sbr_hf_assemble; c->sbr_x_gen = sbr_x_gen; c->sbr_hf_inverse_filter = sbr_hf_inverse_filter; - -#if !USE_FIXED -#if ARCH_MIPS - ff_aacsbr_func_ptr_init_mips(c); -#endif -#endif } diff --git a/libavcodec/aacsbrdata.h b/libavcodec/aacsbrdata.h index b0585309e..9c2509824 100644 --- a/libavcodec/aacsbrdata.h +++ b/libavcodec/aacsbrdata.h @@ -42,7 +42,169 @@ static const int8_t sbr_offset[6][16] = { }; ///< window coefficients for analysis/synthesis QMF banks -static DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_ds)[320]; +static const DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_ds)[320] = { + Q31( 0.0000000000f), Q31(-0.0005617692f), + Q31(-0.0004875227f), Q31(-0.0005040714f), + Q31(-0.0005466565f), Q31(-0.0005870930f), + Q31(-0.0006312493f), Q31(-0.0006777690f), + Q31(-0.0007157736f), Q31(-0.0007440941f), + Q31(-0.0007681371f), Q31(-0.0007834332f), + Q31(-0.0007803664f), Q31(-0.0007757977f), + Q31(-0.0007530001f), Q31(-0.0007215391f), + Q31(-0.0006650415f), Q31(-0.0005946118f), + Q31(-0.0005145572f), Q31(-0.0004095121f), + Q31(-0.0002896981f), Q31(-0.0001446380f), + Q31( 0.0000134949f), Q31( 0.0002043017f), + Q31( 0.0004026540f), Q31( 0.0006239376f), + Q31( 0.0008608443f), Q31( 0.0011250155f), + Q31( 0.0013902494f), Q31( 0.0016868083f), + Q31( 0.0019841140f), Q31( 0.0023017254f), + Q31( 0.0026201758f), Q31( 0.0029469447f), + Q31( 0.0032739613f), Q31( 0.0036008268f), + Q31( 0.0039207432f), Q31( 0.0042264269f), + Q31( 0.0045209852f), Q31( 0.0047932560f), + Q31( 0.0050393022f), Q31( 0.0052461166f), + Q31( 0.0054196775f), Q31( 0.0055475714f), + Q31( 0.0056220643f), Q31( 0.0056389199f), + Q31( 0.0055917128f), Q31( 0.0054753783f), + Q31( 0.0052715758f), Q31( 0.0049839687f), + Q31( 0.0046039530f), Q31( 0.0041251642f), + Q31( 0.0035401246f), Q31( 0.0028446757f), + Q31( 0.0020274176f), Q31( 0.0010902329f), + Q31( 0.0000276045f), Q31(-0.0011568135f), + Q31(-0.0024826723f), Q31(-0.0039401124f), + Q31(-0.0055337211f), Q31(-0.0072615816f), + Q31(-0.0091325329f), Q31(-0.0111315548f), + Q31( 0.0132718220f), Q31( 0.0155405553f), + Q31( 0.0179433381f), Q31( 0.0204531793f), + Q31( 0.0230680169f), Q31( 0.0257875847f), + Q31( 0.0286072173f), Q31( 0.0315017608f), + Q31( 0.0344620948f), Q31( 0.0374812850f), + Q31( 0.0405349170f), Q31( 0.0436097542f), + Q31( 0.0466843027f), Q31( 0.0497385755f), + Q31( 0.0527630746f), Q31( 0.0557173648f), + Q31( 0.0585915683f), Q31( 0.0613455171f), + Q31( 0.0639715898f), Q31( 0.0664367512f), + Q31( 0.0687043828f), Q31( 0.0707628710f), + Q31( 0.0725682583f), Q31( 0.0741003642f), + Q31( 0.0753137336f), Q31( 0.0761992479f), + Q31( 0.0767093490f), Q31( 0.0768230011f), + Q31( 0.0765050718f), Q31( 0.0757305756f), + Q31( 0.0744664394f), Q31( 0.0726774642f), + Q31( 0.0703533073f), Q31( 0.0674525021f), + Q31( 0.0639444805f), Q31( 0.0598166570f), + Q31( 0.0550460034f), Q31( 0.0495978676f), + Q31( 0.0434768782f), Q31( 0.0366418116f), + Q31( 0.0290824006f), Q31( 0.0207997072f), + Q31( 0.0117623832f), Q31( 0.0019765601f), + Q31(-0.0085711749f), Q31(-0.0198834129f), + Q31(-0.0319531274f), Q31(-0.0447806821f), + Q31(-0.0583705326f), Q31(-0.0726943300f), + Q31(-0.0877547536f), Q31(-0.1035329531f), + Q31(-0.1200077984f), Q31(-0.1371551761f), + Q31(-0.1549607071f), Q31(-0.1733808172f), + Q31(-0.1923966745f), Q31(-0.2119735853f), + Q31(-0.2320690870f), Q31(-0.2526480309f), + Q31(-0.2736634040f), Q31(-0.2950716717f), + Q31(-0.3168278913f), Q31(-0.3388722693f), + Q31( 0.3611589903f), Q31( 0.3836350013f), + Q31( 0.4062317676f), Q31( 0.4289119920f), + Q31( 0.4515996535f), Q31( 0.4742453214f), + Q31( 0.4967708254f), Q31( 0.5191234970f), + Q31( 0.5412553448f), Q31( 0.5630789140f), + Q31( 0.5845403235f), Q31( 0.6055783538f), + Q31( 0.6261242695f), Q31( 0.6461269695f), + Q31( 0.6655139880f), Q31( 0.6842353293f), + Q31( 0.7022388719f), Q31( 0.7194462634f), + Q31( 0.7358211758f), Q31( 0.7513137456f), + Q31( 0.7658674865f), Q31( 0.7794287519f), + Q31( 0.7919735841f), Q31( 0.8034485751f), + Q31( 0.8138191270f), Q31( 0.8230419890f), + Q31( 0.8311038457f), Q31( 0.8379717337f), + Q31( 0.8436238281f), Q31( 0.8480315777f), + Q31( 0.8511971524f), Q31( 0.8531020949f), + Q31( 0.8537385600f), Q31( 0.8531020949f), + Q31( 0.8511971524f), Q31( 0.8480315777f), + Q31( 0.8436238281f), Q31( 0.8379717337f), + Q31( 0.8311038457f), Q31( 0.8230419890f), + Q31( 0.8138191270f), Q31( 0.8034485751f), + Q31( 0.7919735841f), Q31( 0.7794287519f), + Q31( 0.7658674865f), Q31( 0.7513137456f), + Q31( 0.7358211758f), Q31( 0.7194462634f), + Q31( 0.7022388719f), Q31( 0.6842353293f), + Q31( 0.6655139880f), Q31( 0.6461269695f), + Q31( 0.6261242695f), Q31( 0.6055783538f), + Q31( 0.5845403235f), Q31( 0.5630789140f), + Q31( 0.5412553448f), Q31( 0.5191234970f), + Q31( 0.4967708254f), Q31( 0.4742453214f), + Q31( 0.4515996535f), Q31( 0.4289119920f), + Q31( 0.4062317676f), Q31( 0.3836350013f), + -Q31( 0.3611589903f), Q31(-0.3388722693f), + Q31(-0.3168278913f), Q31(-0.2950716717f), + Q31(-0.2736634040f), Q31(-0.2526480309f), + Q31(-0.2320690870f), Q31(-0.2119735853f), + Q31(-0.1923966745f), Q31(-0.1733808172f), + Q31(-0.1549607071f), Q31(-0.1371551761f), + Q31(-0.1200077984f), Q31(-0.1035329531f), + Q31(-0.0877547536f), Q31(-0.0726943300f), + Q31(-0.0583705326f), Q31(-0.0447806821f), + Q31(-0.0319531274f), Q31(-0.0198834129f), + Q31(-0.0085711749f), Q31( 0.0019765601f), + Q31( 0.0117623832f), Q31( 0.0207997072f), + Q31( 0.0290824006f), Q31( 0.0366418116f), + Q31( 0.0434768782f), Q31( 0.0495978676f), + Q31( 0.0550460034f), Q31( 0.0598166570f), + Q31( 0.0639444805f), Q31( 0.0674525021f), + Q31( 0.0703533073f), Q31( 0.0726774642f), + Q31( 0.0744664394f), Q31( 0.0757305756f), + Q31( 0.0765050718f), Q31( 0.0768230011f), + Q31( 0.0767093490f), Q31( 0.0761992479f), + Q31( 0.0753137336f), Q31( 0.0741003642f), + Q31( 0.0725682583f), Q31( 0.0707628710f), + Q31( 0.0687043828f), Q31( 0.0664367512f), + Q31( 0.0639715898f), Q31( 0.0613455171f), + Q31( 0.0585915683f), Q31( 0.0557173648f), + Q31( 0.0527630746f), Q31( 0.0497385755f), + Q31( 0.0466843027f), Q31( 0.0436097542f), + Q31( 0.0405349170f), Q31( 0.0374812850f), + Q31( 0.0344620948f), Q31( 0.0315017608f), + Q31( 0.0286072173f), Q31( 0.0257875847f), + Q31( 0.0230680169f), Q31( 0.0204531793f), + Q31( 0.0179433381f), Q31( 0.0155405553f), + -Q31( 0.0132718220f), Q31(-0.0111315548f), + Q31(-0.0091325329f), Q31(-0.0072615816f), + Q31(-0.0055337211f), Q31(-0.0039401124f), + Q31(-0.0024826723f), Q31(-0.0011568135f), + Q31( 0.0000276045f), Q31( 0.0010902329f), + Q31( 0.0020274176f), Q31( 0.0028446757f), + Q31( 0.0035401246f), Q31( 0.0041251642f), + Q31( 0.0046039530f), Q31( 0.0049839687f), + Q31( 0.0052715758f), Q31( 0.0054753783f), + Q31( 0.0055917128f), Q31( 0.0056389199f), + Q31( 0.0056220643f), Q31( 0.0055475714f), + Q31( 0.0054196775f), Q31( 0.0052461166f), + Q31( 0.0050393022f), Q31( 0.0047932560f), + Q31( 0.0045209852f), Q31( 0.0042264269f), + Q31( 0.0039207432f), Q31( 0.0036008268f), + Q31( 0.0032739613f), Q31( 0.0029469447f), + Q31( 0.0026201758f), Q31( 0.0023017254f), + Q31( 0.0019841140f), Q31( 0.0016868083f), + Q31( 0.0013902494f), Q31( 0.0011250155f), + Q31( 0.0008608443f), Q31( 0.0006239376f), + Q31( 0.0004026540f), Q31( 0.0002043017f), + Q31( 0.0000134949f), Q31(-0.0001446380f), + Q31(-0.0002896981f), Q31(-0.0004095121f), + Q31(-0.0005145572f), Q31(-0.0005946118f), + Q31(-0.0006650415f), Q31(-0.0007215391f), + Q31(-0.0007530001f), Q31(-0.0007757977f), + Q31(-0.0007803664f), Q31(-0.0007834332f), + Q31(-0.0007681371f), Q31(-0.0007440941f), + Q31(-0.0007157736f), Q31(-0.0006777690f), + Q31(-0.0006312493f), Q31(-0.0005870930f), + Q31(-0.0005466565f), Q31(-0.0005040714f), + Q31(-0.0004875227f), Q31(-0.0005617692f), +}; + /* This table contains redundancy: It is symmetric about the entry #320 * with the exception of entries 384 and 512 which are negated. */ static const DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_us)[640] = { diff --git a/libavcodec/aactab.c b/libavcodec/aactab.c index 3cef9c5d2..8d4587d24 100644 --- a/libavcodec/aactab.c +++ b/libavcodec/aactab.c @@ -105,6 +105,7 @@ av_cold void ff_aac_float_common_init(void) static AVOnce init_static_once = AV_ONCE_INIT; ff_thread_once(&init_static_once, aac_float_common_init); } +#endif const float ff_ltp_coef[8] = { 0.570829, 0.696616, 0.813004, 0.911304, @@ -144,7 +145,6 @@ const float * const ff_tns_tmp2_map[4] = { tns_tmp2_map_1_3, tns_tmp2_map_1_4 }; -#endif const uint8_t ff_aac_num_swb_1024[] = { 41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40, 40 @@ -154,6 +154,10 @@ const uint8_t ff_aac_num_swb_960[] = { 40, 40, 46, 49, 49, 49, 46, 46, 42, 42, 42, 40, 40 }; +const uint8_t ff_aac_num_swb_768[] = { + 37, 37, 41, 43, 43, 43, 43, 43, 39, 39, 39, 37, 37 +}; + const uint8_t ff_aac_num_swb_512[] = { 0, 0, 0, 36, 36, 37, 31, 31, 0, 0, 0, 0, 0 }; @@ -170,6 +174,10 @@ 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 +}; + const uint8_t ff_aac_pred_sfb_max[] = { 33, 33, 38, 40, 40, 40, 41, 41, 37, 37, 37, 34, 34 }; @@ -1193,6 +1201,382 @@ const uint16_t *const ff_aac_codebook_vector_idx[] = { codebook_vector10_idx, }; +const uint16_t ff_aac_ac_msb_cdfs[64][17] = { + { 708, 706, 579, 569, 568, 567, 479, 469, + 297, 138, 97, 91, 72, 52, 38, 34, 0, }, + { 7619, 6917, 6519, 6412, 5514, 5003, 4683, 4563, + 3907, 3297, 3125, 3060, 2904, 2718, 2631, 2590, 0, }, + { 7263, 4888, 4810, 4803, 1889, 415, 335, 327, + 195, 72, 52, 49, 36, 20, 15, 14, 0, }, + { 3626, 2197, 2188, 2187, 582, 57, 47, 46, + 30, 12, 9, 8, 6, 4, 3, 2, 0, }, + { 7806, 5541, 5451, 5441, 2720, 834, 691, 674, + 487, 243, 179, 167, 139, 98, 77, 70, 0, }, + { 6684, 4101, 4058, 4055, 1748, 426, 368, 364, + 322, 257, 235, 232, 228, 222, 217, 215, 0, }, + { 9162, 5964, 5831, 5819, 3269, 866, 658, 638, + 535, 348, 258, 244, 234, 214, 195, 186, 0, }, + { 10638, 8491, 8365, 8351, 4418, 2067, 1859, 1834, + 1190, 601, 495, 478, 356, 217, 174, 164, 0, }, + { 13389, 10514, 10032, 9961, 7166, 3488, 2655, 2524, + 2015, 1140, 760, 672, 585, 426, 325, 283, 0, }, + { 14861, 12788, 12115, 11952, 9987, 6657, 5323, 4984, + 4324, 3001, 2205, 1943, 1764, 1394, 1115, 978, 0, }, + { 12876, 10004, 9661, 9610, 7107, 3435, 2711, 2595, + 2257, 1508, 1059, 952, 893, 753, 609, 538, 0, }, + { 15125, 13591, 13049, 12874, 11192, 8543, 7406, 7023, + 6291, 4922, 4104, 3769, 3465, 2890, 2486, 2275, 0, }, + { 14574, 13106, 12731, 12638, 10453, 7947, 7233, 7037, + 6031, 4618, 4081, 3906, 3465, 2802, 2476, 2349, 0, }, + { 15070, 13179, 12517, 12351, 10742, 7657, 6200, 5825, + 5264, 3998, 3014, 2662, 2510, 2153, 1799, 1564, 0, }, + { 15542, 14466, 14007, 13844, 12489, 10409, 9481, 9132, + 8305, 6940, 6193, 5867, 5458, 4743, 4291, 4047, 0, }, + { 15165, 14384, 14084, 13934, 12911, 11485, 10844, 10513, + 10002, 8993, 8380, 8051, 7711, 7036, 6514, 6233, 0, }, + { 15642, 14279, 13625, 13393, 12348, 9971, 8405, 7858, + 7335, 6119, 4918, 4376, 4185, 3719, 3231, 2860, 0, }, + { 13408, 13407, 11471, 11218, 11217, 11216, 9473, 9216, + 6480, 3689, 2857, 2690, 2256, 1732, 1405, 1302, 0, }, + { 16098, 15584, 15191, 14931, 14514, 13578, 12703, 12103, + 11830, 11172, 10475, 9867, 9695, 9281, 8825, 8389, 0, }, + { 15844, 14873, 14277, 13996, 13230, 11535, 10205, 9543, + 9107, 8086, 7085, 6419, 6214, 5713, 5195, 4731, 0, }, + { 16131, 15720, 15443, 15276, 14848, 13971, 13314, 12910, + 12591, 11874, 11225, 10788, 10573, 10077, 9585, 9209, 0, }, + { 16331, 16330, 12283, 11435, 11434, 11433, 8725, 8049, + 6065, 4138, 3187, 2842, 2529, 2171, 1907, 1745, 0, }, + { 16011, 15292, 14782, 14528, 14008, 12767, 11556, 10921, + 10591, 9759, 8813, 8043, 7855, 7383, 6863, 6282, 0, }, + { 16380, 16379, 15159, 14610, 14609, 14608, 12859, 12111, + 11046, 9536, 8348, 7713, 7216, 6533, 5964, 5546, 0, }, + { 16367, 16333, 16294, 16253, 16222, 16143, 16048, 15947, + 15915, 15832, 15731, 15619, 15589, 15512, 15416, 15310, 0, }, + { 15967, 15319, 14937, 14753, 14010, 12638, 11787, 11360, + 10805, 9706, 8934, 8515, 8166, 7456, 6911, 6575, 0, }, + { 4906, 3005, 2985, 2984, 875, 102, 83, 81, + 47, 17, 12, 11, 8, 5, 4, 3, 0, }, + { 7217, 4346, 4269, 4264, 1924, 428, 340, 332, + 280, 203, 179, 175, 171, 164, 159, 157, 0, }, + { 16010, 15415, 15032, 14805, 14228, 13043, 12168, 11634, + 11265, 10419, 9645, 9110, 8892, 8378, 7850, 7437, 0, }, + { 8573, 5218, 5046, 5032, 2787, 771, 555, 533, + 443, 286, 218, 205, 197, 181, 168, 162, 0, }, + { 11474, 8095, 7822, 7796, 4632, 1443, 1046, 1004, + 748, 351, 218, 194, 167, 121, 93, 83, 0, }, + { 16152, 15764, 15463, 15264, 14925, 14189, 13536, 13070, + 12846, 12314, 11763, 11277, 11131, 10777, 10383, 10011, 0, }, + { 14187, 11654, 11043, 10919, 8498, 4885, 3778, 3552, + 2947, 1835, 1283, 1134, 998, 749, 585, 514, 0, }, + { 14162, 11527, 10759, 10557, 8601, 5417, 4105, 3753, + 3286, 2353, 1708, 1473, 1370, 1148, 959, 840, 0, }, + { 16205, 15902, 15669, 15498, 15213, 14601, 14068, 13674, + 13463, 12970, 12471, 12061, 11916, 11564, 11183, 10841, 0, }, + { 15043, 12972, 12092, 11792, 10265, 7446, 5934, 5379, + 4883, 3825, 3036, 2647, 2507, 2185, 1901, 1699, 0, }, + { 15320, 13694, 12782, 12352, 11191, 8936, 7433, 6671, + 6255, 5366, 4622, 4158, 4020, 3712, 3420, 3198, 0, }, + { 16255, 16020, 15768, 15600, 15416, 14963, 14440, 14006, + 13875, 13534, 13137, 12697, 12602, 12364, 12084, 11781, 0, }, + { 15627, 14503, 13906, 13622, 12557, 10527, 9269, 8661, + 8117, 6933, 5994, 5474, 5222, 4664, 4166, 3841, 0, }, + { 16366, 16365, 14547, 14160, 14159, 14158, 11969, 11473, + 8735, 6147, 4911, 4530, 3865, 3180, 2710, 2473, 0, }, + { 16257, 16038, 15871, 15754, 15536, 15071, 14673, 14390, + 14230, 13842, 13452, 13136, 13021, 12745, 12434, 12154, 0, }, + { 15855, 14971, 14338, 13939, 13239, 11782, 10585, 9805, + 9444, 8623, 7846, 7254, 7079, 6673, 6262, 5923, 0, }, + { 9492, 6318, 6197, 6189, 3004, 652, 489, 477, + 333, 143, 96, 90, 78, 60, 50, 47, 0, }, + { 16313, 16191, 16063, 15968, 15851, 15590, 15303, 15082, + 14968, 14704, 14427, 14177, 14095, 13899, 13674, 13457, 0, }, + { 8485, 5473, 5389, 5383, 2411, 494, 386, 377, + 278, 150, 117, 112, 103, 89, 81, 78, 0, }, + { 10497, 7154, 6959, 6943, 3788, 1004, 734, 709, + 517, 238, 152, 138, 120, 90, 72, 66, 0, }, + { 16317, 16226, 16127, 16040, 15955, 15762, 15547, 15345, + 15277, 15111, 14922, 14723, 14671, 14546, 14396, 14239, 0, }, + { 16382, 16381, 15858, 15540, 15539, 15538, 14704, 14168, + 13768, 13092, 12452, 11925, 11683, 11268, 10841, 10460, 0, }, + { 5974, 3798, 3758, 3755, 1275, 205, 166, 162, + 95, 35, 26, 24, 18, 11, 8, 7, 0, }, + { 3532, 2258, 2246, 2244, 731, 135, 118, 115, + 87, 45, 36, 34, 29, 21, 17, 16, 0, }, + { 7466, 4882, 4821, 4811, 2476, 886, 788, 771, + 688, 531, 469, 457, 437, 400, 369, 361, 0, }, + { 9580, 5772, 5291, 5216, 3444, 1496, 1025, 928, + 806, 578, 433, 384, 366, 331, 296, 273, 0, }, + { 10692, 7730, 7543, 7521, 4679, 1746, 1391, 1346, + 1128, 692, 495, 458, 424, 353, 291, 268, 0, }, + { 11040, 7132, 6549, 6452, 4377, 1875, 1253, 1130, + 958, 631, 431, 370, 346, 296, 253, 227, 0, }, + { 12687, 9332, 8701, 8585, 6266, 3093, 2182, 2004, + 1683, 1072, 712, 608, 559, 458, 373, 323, 0, }, + { 13429, 9853, 8860, 8584, 6806, 4039, 2862, 2478, + 2239, 1764, 1409, 1224, 1178, 1077, 979, 903, 0, }, + { 14685, 12163, 11061, 10668, 9101, 6345, 4871, 4263, + 3908, 3200, 2668, 2368, 2285, 2106, 1942, 1819, 0, }, + { 13295, 11302, 10999, 10945, 7947, 5036, 4490, 4385, + 3391, 2185, 1836, 1757, 1424, 998, 833, 785, 0, }, + { 4992, 2993, 2972, 2970, 1269, 575, 552, 549, + 530, 505, 497, 495, 493, 489, 486, 485, 0, }, + { 15419, 13862, 13104, 12819, 11429, 8753, 7220, 6651, + 6020, 4667, 3663, 3220, 2995, 2511, 2107, 1871, 0, }, + { 12468, 9263, 8912, 8873, 5758, 2193, 1625, 1556, + 1187, 589, 371, 330, 283, 200, 149, 131, 0, }, + { 15870, 15076, 14615, 14369, 13586, 12034, 10990, 10423, + 9953, 8908, 8031, 7488, 7233, 6648, 6101, 5712, 0, }, + { 1693, 978, 976, 975, 194, 18, 16, 15, + 11, 7, 6, 5, 4, 3, 2, 1, 0, }, + { 7992, 5218, 5147, 5143, 2152, 366, 282, 276, + 173, 59, 38, 35, 27, 16, 11, 10, 0, } +}; + +const uint16_t ff_aac_ac_lsb_cdfs[3][4] = { + { 12571, 10569, 3696, 0 }, + { 12661, 5700, 3751, 0 }, + { 10827, 6884, 2929, 0 } +}; + +const uint8_t ff_aac_ac_lookup_m[742] = { + 0x01, 0x34, 0x0D, 0x13, 0x12, 0x25, 0x00, 0x3A, 0x05, 0x00, 0x21, 0x13, 0x1F, 0x1A, 0x1D, 0x36, + 0x24, 0x2B, 0x1B, 0x33, 0x37, 0x29, 0x1D, 0x33, 0x37, 0x33, 0x37, 0x33, 0x37, 0x33, 0x2C, 0x00, + 0x21, 0x13, 0x25, 0x2A, 0x00, 0x21, 0x24, 0x12, 0x2C, 0x1E, 0x37, 0x24, 0x1F, 0x35, 0x37, 0x24, + 0x35, 0x37, 0x35, 0x37, 0x38, 0x2D, 0x21, 0x29, 0x1E, 0x21, 0x13, 0x2D, 0x36, 0x38, 0x29, 0x36, + 0x37, 0x24, 0x36, 0x38, 0x37, 0x38, 0x00, 0x20, 0x23, 0x20, 0x23, 0x36, 0x38, 0x24, 0x3B, 0x24, + 0x26, 0x29, 0x1F, 0x30, 0x2D, 0x0D, 0x12, 0x3F, 0x2D, 0x21, 0x1C, 0x2A, 0x00, 0x21, 0x12, 0x1E, + 0x36, 0x38, 0x36, 0x37, 0x3F, 0x1E, 0x0D, 0x1F, 0x2A, 0x1E, 0x21, 0x24, 0x12, 0x2A, 0x3C, 0x21, + 0x24, 0x1F, 0x3C, 0x21, 0x29, 0x36, 0x38, 0x36, 0x37, 0x38, 0x21, 0x1E, 0x00, 0x3B, 0x25, 0x1E, + 0x20, 0x10, 0x1F, 0x3C, 0x20, 0x23, 0x29, 0x08, 0x23, 0x12, 0x08, 0x23, 0x21, 0x38, 0x00, 0x20, + 0x13, 0x20, 0x3B, 0x1C, 0x20, 0x3B, 0x29, 0x20, 0x23, 0x24, 0x21, 0x24, 0x21, 0x24, 0x3B, 0x13, + 0x23, 0x26, 0x23, 0x13, 0x21, 0x24, 0x26, 0x29, 0x12, 0x22, 0x2B, 0x02, 0x1E, 0x0D, 0x1F, 0x2D, + 0x00, 0x0D, 0x12, 0x00, 0x3C, 0x21, 0x29, 0x3C, 0x21, 0x2A, 0x3C, 0x3B, 0x22, 0x1E, 0x20, 0x10, + 0x1F, 0x3C, 0x0D, 0x29, 0x3C, 0x21, 0x24, 0x08, 0x23, 0x20, 0x38, 0x39, 0x3C, 0x20, 0x13, 0x3C, + 0x00, 0x0D, 0x13, 0x1F, 0x3C, 0x09, 0x26, 0x1F, 0x08, 0x09, 0x26, 0x12, 0x08, 0x23, 0x29, 0x20, + 0x23, 0x21, 0x24, 0x20, 0x13, 0x20, 0x3B, 0x16, 0x20, 0x3B, 0x29, 0x20, 0x3B, 0x29, 0x20, 0x3B, + 0x13, 0x21, 0x24, 0x29, 0x0B, 0x13, 0x09, 0x3B, 0x13, 0x09, 0x3B, 0x13, 0x21, 0x3B, 0x13, 0x0D, + 0x26, 0x29, 0x26, 0x29, 0x3D, 0x12, 0x22, 0x28, 0x2E, 0x04, 0x08, 0x13, 0x3C, 0x3B, 0x3C, 0x20, + 0x10, 0x3C, 0x21, 0x07, 0x08, 0x10, 0x00, 0x08, 0x0D, 0x29, 0x08, 0x0D, 0x29, 0x08, 0x09, 0x13, + 0x20, 0x23, 0x39, 0x08, 0x09, 0x13, 0x08, 0x09, 0x16, 0x08, 0x09, 0x10, 0x12, 0x20, 0x3B, 0x3D, + 0x09, 0x26, 0x20, 0x3B, 0x24, 0x39, 0x09, 0x26, 0x20, 0x0D, 0x13, 0x00, 0x09, 0x13, 0x20, 0x0D, + 0x26, 0x12, 0x20, 0x3B, 0x13, 0x21, 0x26, 0x0B, 0x12, 0x09, 0x3B, 0x16, 0x09, 0x3B, 0x3D, 0x09, + 0x26, 0x0D, 0x13, 0x26, 0x3D, 0x1C, 0x12, 0x1F, 0x28, 0x2E, 0x07, 0x0B, 0x08, 0x09, 0x00, 0x39, + 0x0B, 0x08, 0x26, 0x08, 0x09, 0x13, 0x20, 0x0B, 0x39, 0x10, 0x39, 0x0D, 0x13, 0x20, 0x10, 0x12, + 0x09, 0x13, 0x20, 0x3B, 0x13, 0x09, 0x26, 0x0B, 0x09, 0x3B, 0x1C, 0x09, 0x3B, 0x13, 0x20, 0x3B, + 0x13, 0x09, 0x26, 0x0B, 0x16, 0x0D, 0x13, 0x09, 0x13, 0x09, 0x13, 0x26, 0x3D, 0x1C, 0x1F, 0x28, + 0x2E, 0x07, 0x10, 0x39, 0x0B, 0x39, 0x39, 0x13, 0x39, 0x0B, 0x39, 0x0B, 0x39, 0x26, 0x39, 0x10, + 0x20, 0x3B, 0x16, 0x20, 0x10, 0x09, 0x26, 0x0B, 0x13, 0x09, 0x13, 0x26, 0x1C, 0x0B, 0x3D, 0x1C, + 0x1F, 0x28, 0x2B, 0x07, 0x0C, 0x39, 0x0B, 0x39, 0x0B, 0x0C, 0x0B, 0x26, 0x0B, 0x26, 0x3D, 0x0D, + 0x1C, 0x14, 0x28, 0x2B, 0x39, 0x0B, 0x0C, 0x0E, 0x3D, 0x1C, 0x0D, 0x12, 0x22, 0x2B, 0x07, 0x0C, + 0x0E, 0x3D, 0x1C, 0x10, 0x1F, 0x2B, 0x0C, 0x0E, 0x19, 0x14, 0x10, 0x1F, 0x28, 0x0C, 0x0E, 0x19, + 0x14, 0x26, 0x22, 0x2B, 0x0C, 0x0E, 0x19, 0x14, 0x26, 0x28, 0x0E, 0x19, 0x14, 0x26, 0x28, 0x0E, + 0x19, 0x14, 0x28, 0x0E, 0x19, 0x14, 0x22, 0x28, 0x2B, 0x0E, 0x14, 0x2B, 0x31, 0x00, 0x3A, 0x3A, + 0x05, 0x05, 0x1B, 0x1D, 0x33, 0x06, 0x35, 0x35, 0x20, 0x21, 0x37, 0x21, 0x24, 0x05, 0x1B, 0x2C, + 0x2C, 0x2C, 0x06, 0x34, 0x1E, 0x34, 0x00, 0x08, 0x36, 0x09, 0x21, 0x26, 0x1C, 0x2C, 0x00, 0x02, + 0x02, 0x02, 0x3F, 0x04, 0x04, 0x04, 0x34, 0x39, 0x20, 0x0A, 0x0C, 0x39, 0x0B, 0x0F, 0x07, 0x07, + 0x07, 0x07, 0x34, 0x39, 0x39, 0x0A, 0x0C, 0x39, 0x0C, 0x0F, 0x07, 0x07, 0x07, 0x00, 0x39, 0x39, + 0x0C, 0x0F, 0x07, 0x07, 0x39, 0x0C, 0x0F, 0x07, 0x39, 0x0C, 0x0F, 0x39, 0x39, 0x0C, 0x0F, 0x39, + 0x0C, 0x39, 0x0C, 0x0F, 0x00, 0x11, 0x27, 0x17, 0x2F, 0x27, 0x00, 0x27, 0x17, 0x00, 0x11, 0x17, + 0x00, 0x11, 0x17, 0x11, 0x00, 0x27, 0x15, 0x11, 0x17, 0x01, 0x15, 0x11, 0x15, 0x11, 0x15, 0x15, + 0x17, 0x00, 0x27, 0x01, 0x27, 0x27, 0x15, 0x00, 0x27, 0x11, 0x27, 0x15, 0x15, 0x15, 0x27, 0x15, + 0x15, 0x15, 0x15, 0x17, 0x2F, 0x11, 0x17, 0x27, 0x27, 0x27, 0x11, 0x27, 0x15, 0x27, 0x27, 0x15, + 0x15, 0x27, 0x17, 0x2F, 0x27, 0x17, 0x2F, 0x27, 0x17, 0x2F, 0x27, 0x17, 0x2F, 0x27, 0x17, 0x2F, + 0x27, 0x17, 0x2F, 0x27, 0x17, 0x2F, 0x27, 0x17, 0x2F, 0x27, 0x17, 0x2F, 0x27, 0x17, 0x2F, 0x27, + 0x17, 0x2F, 0x27, 0x17, 0x2F, 0x27, 0x17, 0x2F, 0x17, 0x2F, 0x2B, 0x00, 0x27, 0x00, 0x00, 0x11, + 0x15, 0x00, 0x11, 0x11, 0x27, 0x27, 0x15, 0x17, 0x15, 0x17, 0x15, 0x17, 0x27, 0x17, 0x27, 0x17, + 0x27, 0x17, 0x27, 0x17, 0x27, 0x17, 0x27, 0x17, 0x27, 0x17, 0x27, 0x17, 0x27, 0x17, 0x27, 0x17, + 0x27, 0x15, 0x27, 0x27, 0x15, 0x27 +}; + +const uint32_t ff_aac_ac_hash_m[742] = { + 0x00000104, 0x0000030A, 0x00000510, 0x00000716, + 0x00000A1F, 0x00000F2E, 0x00011100, 0x00111103, + 0x00111306, 0x00111436, 0x00111623, 0x00111929, + 0x00111F2E, 0x0011221B, 0x00112435, 0x00112621, + 0x00112D12, 0x00113130, 0x0011331D, 0x00113535, + 0x00113938, 0x0011411B, 0x00114433, 0x00114635, + 0x00114F29, 0x00116635, 0x00116F24, 0x00117433, + 0x0011FF0F, 0x00121102, 0x0012132D, 0x00121436, + 0x00121623, 0x00121912, 0x0012213F, 0x0012232D, + 0x00122436, 0x00122638, 0x00122A29, 0x00122F2B, + 0x0012322D, 0x00123436, 0x00123738, 0x00123B29, + 0x0012411D, 0x00124536, 0x00124938, 0x00124F12, + 0x00125535, 0x00125F29, 0x00126535, 0x0012B837, + 0x0013112A, 0x0013131E, 0x0013163B, 0x0013212D, + 0x0013233C, 0x00132623, 0x00132F2E, 0x0013321E, + 0x00133521, 0x00133824, 0x0013411E, 0x00134336, + 0x00134838, 0x00135135, 0x00135537, 0x00135F12, + 0x00137637, 0x0013FF29, 0x00140024, 0x00142321, + 0x00143136, 0x00143321, 0x00143F25, 0x00144321, + 0x00148638, 0x0014FF29, 0x00154323, 0x0015FF12, + 0x0016F20C, 0x0018A529, 0x00210031, 0x0021122C, + 0x00211408, 0x00211713, 0x00211F2E, 0x0021222A, + 0x00212408, 0x00212710, 0x00212F2E, 0x0021331E, + 0x00213436, 0x00213824, 0x0021412D, 0x0021431E, + 0x00214536, 0x00214F1F, 0x00216637, 0x00220004, + 0x0022122A, 0x00221420, 0x00221829, 0x00221F2E, + 0x0022222D, 0x00222408, 0x00222623, 0x00222929, + 0x00222F2B, 0x0022321E, 0x00223408, 0x00223724, + 0x00223A29, 0x0022411E, 0x00224436, 0x00224823, + 0x00225134, 0x00225621, 0x00225F12, 0x00226336, + 0x00227637, 0x0022FF29, 0x0023112D, 0x0023133C, + 0x00231420, 0x00231916, 0x0023212D, 0x0023233C, + 0x00232509, 0x00232929, 0x0023312D, 0x00233308, + 0x00233509, 0x00233724, 0x0023413C, 0x00234421, + 0x00234A13, 0x0023513C, 0x00235421, 0x00235F1F, + 0x00236421, 0x0023FF29, 0x00240024, 0x0024153B, + 0x00242108, 0x00242409, 0x00242726, 0x00243108, + 0x00243409, 0x00243610, 0x00244136, 0x00244321, + 0x00244523, 0x00244F1F, 0x00245423, 0x0024610A, + 0x00246423, 0x0024FF29, 0x00252510, 0x00253121, + 0x0025343B, 0x00254121, 0x00254510, 0x00254F25, + 0x00255221, 0x0025FF12, 0x00266513, 0x0027F529, + 0x0029F101, 0x002CF224, 0x00310030, 0x0031122A, + 0x00311420, 0x00311816, 0x0031212C, 0x0031231E, + 0x00312408, 0x00312710, 0x0031312A, 0x0031321E, + 0x00313408, 0x00313623, 0x0031411E, 0x0031433C, + 0x00320007, 0x0032122D, 0x00321420, 0x00321816, + 0x0032212D, 0x0032233C, 0x00322509, 0x00322916, + 0x0032312D, 0x00323420, 0x00323710, 0x00323F2B, + 0x00324308, 0x00324623, 0x00324F25, 0x00325421, + 0x00325F1F, 0x00326421, 0x0032FF29, 0x00331107, + 0x00331308, 0x0033150D, 0x0033211E, 0x00332308, + 0x00332420, 0x00332610, 0x00332929, 0x0033311E, + 0x00333308, 0x0033363B, 0x00333A29, 0x0033413C, + 0x00334320, 0x0033463B, 0x00334A29, 0x0033510A, + 0x00335320, 0x00335824, 0x0033610A, 0x00336321, + 0x00336F12, 0x00337623, 0x00341139, 0x0034153B, + 0x00342108, 0x00342409, 0x00342610, 0x00343108, + 0x00343409, 0x00343610, 0x00344108, 0x0034440D, + 0x00344610, 0x0034510A, 0x00345309, 0x0034553B, + 0x0034610A, 0x00346309, 0x0034F824, 0x00350029, + 0x00352510, 0x00353120, 0x0035330D, 0x00353510, + 0x00354120, 0x0035430D, 0x00354510, 0x00354F28, + 0x0035530D, 0x00355510, 0x00355F1F, 0x00356410, + 0x00359626, 0x0035FF12, 0x00366426, 0x0036FF12, + 0x0037F426, 0x0039D712, 0x003BF612, 0x003DF81F, + 0x00410004, 0x00411207, 0x0041150D, 0x0041212A, + 0x00412420, 0x0041311E, 0x00413308, 0x00413509, + 0x00413F2B, 0x00414208, 0x00420007, 0x0042123C, + 0x00421409, 0x00422107, 0x0042223C, 0x00422409, + 0x00422610, 0x0042313C, 0x00423409, 0x0042363B, + 0x0042413C, 0x00424320, 0x0042463B, 0x00425108, + 0x00425409, 0x0042FF29, 0x00431107, 0x00431320, + 0x0043153B, 0x0043213C, 0x00432320, 0x00432610, + 0x0043313C, 0x00433320, 0x0043353B, 0x00433813, + 0x00434108, 0x00434409, 0x00434610, 0x00435108, + 0x0043553B, 0x00435F25, 0x00436309, 0x0043753B, + 0x0043FF29, 0x00441239, 0x0044143B, 0x00442139, + 0x00442309, 0x0044253B, 0x00443108, 0x00443220, + 0x0044353B, 0x0044410A, 0x00444309, 0x0044453B, + 0x00444813, 0x0044510A, 0x00445309, 0x00445510, + 0x00445F25, 0x0044630D, 0x00450026, 0x00452713, + 0x00453120, 0x0045330D, 0x00453510, 0x00454120, + 0x0045430D, 0x00454510, 0x00455120, 0x0045530D, + 0x00456209, 0x00456410, 0x0045FF12, 0x00466513, + 0x0047FF22, 0x0048FF25, 0x0049F43D, 0x004BFB25, + 0x004EF825, 0x004FFF18, 0x00511339, 0x00512107, + 0x00513409, 0x00520007, 0x00521107, 0x00521320, + 0x00522107, 0x00522409, 0x0052313C, 0x00523320, + 0x0052353B, 0x00524108, 0x00524320, 0x00531139, + 0x00531309, 0x00532139, 0x00532309, 0x0053253B, + 0x00533108, 0x0053340D, 0x00533713, 0x00534108, + 0x0053453B, 0x00534F2B, 0x00535309, 0x00535610, + 0x00535F25, 0x0053643B, 0x00541139, 0x00542139, + 0x00542309, 0x00542613, 0x00543139, 0x00543309, + 0x00543510, 0x00543F2B, 0x00544309, 0x00544510, + 0x00544F28, 0x0054530D, 0x0054FF12, 0x00553613, + 0x00553F2B, 0x00554410, 0x0055510A, 0x0055543B, + 0x00555F25, 0x0055633B, 0x0055FF12, 0x00566513, + 0x00577413, 0x0059FF28, 0x005CC33D, 0x005EFB28, + 0x005FFF18, 0x00611339, 0x00612107, 0x00613320, + 0x0061A724, 0x00621107, 0x0062140B, 0x00622107, + 0x00622320, 0x00623139, 0x00623320, 0x00631139, + 0x0063130C, 0x00632139, 0x00632309, 0x00633139, + 0x00633309, 0x00633626, 0x00633F2B, 0x00634309, + 0x00634F2B, 0x0063543B, 0x0063FF12, 0x0064343B, + 0x00643F2B, 0x0064443B, 0x00645209, 0x00665513, + 0x0066610A, 0x00666526, 0x0067A616, 0x0069843D, + 0x006CF612, 0x006EF326, 0x006FFF18, 0x0071130C, + 0x00721107, 0x00722239, 0x0072291C, 0x0072340B, + 0x00731139, 0x00732239, 0x0073630B, 0x0073FF12, + 0x0074430B, 0x00755426, 0x00776F28, 0x00777410, + 0x0078843D, 0x007CF416, 0x007EF326, 0x007FFF18, + 0x00822239, 0x00831139, 0x0083430B, 0x0084530B, + 0x0087561C, 0x00887F25, 0x00888426, 0x008AF61C, + 0x008F0018, 0x008FFF18, 0x00911107, 0x0093230B, + 0x0094530B, 0x0097743D, 0x00998C25, 0x00999616, + 0x009EF825, 0x009FFF18, 0x00A3430B, 0x00A4530B, + 0x00A7743D, 0x00AA9F2B, 0x00AAA616, 0x00ABD61F, + 0x00AFFF18, 0x00B3330B, 0x00B44426, 0x00B7643D, + 0x00BB971F, 0x00BBB53D, 0x00BEF512, 0x00BFFF18, + 0x00C22139, 0x00C5330E, 0x00C7633D, 0x00CCAF2E, + 0x00CCC616, 0x00CFFF18, 0x00D4440E, 0x00D6420E, + 0x00DDCF2E, 0x00DDD516, 0x00DFFF18, 0x00E4330E, + 0x00E6841C, 0x00EEE61C, 0x00EFFF18, 0x00F3320E, + 0x00F55319, 0x00F8F41C, 0x00FAFF2E, 0x00FF002E, + 0x00FFF10C, 0x00FFF33D, 0x00FFF722, 0x00FFFF18, + 0x01000232, 0x0111113E, 0x01112103, 0x0111311A, + 0x0112111A, 0x01122130, 0x01123130, 0x0112411D, + 0x01131102, 0x01132102, 0x01133102, 0x01141108, + 0x01142136, 0x01143136, 0x01144135, 0x0115223B, + 0x01211103, 0x0121211A, 0x01213130, 0x01221130, + 0x01222130, 0x01223102, 0x01231104, 0x01232104, + 0x01233104, 0x01241139, 0x01241220, 0x01242220, + 0x01251109, 0x0125223B, 0x0125810A, 0x01283212, + 0x0131111A, 0x01312130, 0x0131222C, 0x0131322A, + 0x0132122A, 0x0132222D, 0x0132322D, 0x01331207, + 0x01332234, 0x01333234, 0x01341139, 0x01343134, + 0x01344134, 0x01348134, 0x0135220B, 0x0136110B, + 0x01365224, 0x01411102, 0x01412104, 0x01431239, + 0x01432239, 0x0143320A, 0x01435134, 0x01443107, + 0x01444134, 0x01446134, 0x0145220E, 0x01455134, + 0x0147110E, 0x01511102, 0x01521239, 0x01531239, + 0x01532239, 0x01533107, 0x0155220E, 0x01555134, + 0x0157110E, 0x01611107, 0x01621239, 0x01631239, + 0x01661139, 0x01666134, 0x01711107, 0x01721239, + 0x01745107, 0x0177110C, 0x01811107, 0x01821107, + 0x0185110C, 0x0188210C, 0x01911107, 0x01933139, + 0x01A11107, 0x01A31139, 0x01F5220E, 0x02000001, + 0x02000127, 0x02000427, 0x02000727, 0x02000E2F, + 0x02110000, 0x02111200, 0x02111411, 0x02111827, + 0x02111F2F, 0x02112411, 0x02112715, 0x02113200, + 0x02113411, 0x02113715, 0x02114200, 0x02121200, + 0x02121301, 0x02121F2F, 0x02122200, 0x02122615, + 0x02122F2F, 0x02123311, 0x02123F2F, 0x02124411, + 0x02131211, 0x02132311, 0x02133211, 0x02184415, + 0x02211200, 0x02211311, 0x02211F2F, 0x02212311, + 0x02212F2F, 0x02213211, 0x02221201, 0x02221311, + 0x02221F2F, 0x02222311, 0x02222F2F, 0x02223211, + 0x02223F2F, 0x02231211, 0x02232211, 0x02232F2F, + 0x02233211, 0x02233F2F, 0x02287515, 0x022DAB17, + 0x02311211, 0x02311527, 0x02312211, 0x02321211, + 0x02322211, 0x02322F2F, 0x02323311, 0x02323F2F, + 0x02331211, 0x02332211, 0x02332F2F, 0x02333F2F, + 0x0237FF17, 0x02385615, 0x023D9517, 0x02410027, + 0x02487827, 0x024E3117, 0x024FFF2F, 0x02598627, + 0x025DFF2F, 0x025FFF2F, 0x02687827, 0x026DFA17, + 0x026FFF2F, 0x02796427, 0x027E4217, 0x027FFF2F, + 0x02888727, 0x028EFF2F, 0x028FFF2F, 0x02984327, + 0x029F112F, 0x029FFF2F, 0x02A76527, 0x02AEF717, + 0x02AFFF2F, 0x02B7C827, 0x02BEF917, 0x02BFFF2F, + 0x02C66527, 0x02CD5517, 0x02CFFF2F, 0x02D63227, + 0x02DDD527, 0x02DFFF2B, 0x02E84717, 0x02EEE327, + 0x02EFFF2F, 0x02F54527, 0x02FCF817, 0x02FFEF2B, + 0x02FFFA2F, 0x02FFFE2F, 0x03000127, 0x03000201, + 0x03111200, 0x03122115, 0x03123200, 0x03133211, + 0x03211200, 0x03213127, 0x03221200, 0x03345215, + 0x04000F17, 0x04122F17, 0x043F6515, 0x043FFF17, + 0x044F5527, 0x044FFF17, 0x045F0017, 0x045FFF17, + 0x046F6517, 0x04710027, 0x047F4427, 0x04810027, + 0x048EFA15, 0x048FFF2F, 0x049F4427, 0x049FFF2F, + 0x04AEA727, 0x04AFFF2F, 0x04BE9C15, 0x04BFFF2F, + 0x04CE5427, 0x04CFFF2F, 0x04DE3527, 0x04DFFF17, + 0x04EE4627, 0x04EFFF17, 0x04FEF327, 0x04FFFF2F, + 0x06000F27, 0x069FFF17, 0x06FFFF17, 0x08110017, + 0x08EFFF15, 0xFFFFFF00 +}; + /* @name swb_offsets * Sample offset into the window indicating the beginning of a scalefactor * window band @@ -1430,6 +1814,99 @@ static const uint16_t swb_offset_120_8[] = 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 60, 72, 88, 108, 120 }; +static const uint16_t swb_offset_768_96[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, + 108, 120, 132, 144, 156, 172, 188, 212, 240, 276, + 320, 384, 448, 512, 576, 640, 704, 768 +}; + +static const uint16_t swb_offset_768_64[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, + 44, 48, 52, 56, 64, 72, 80, 88, 100, 112, 124, + 140, 156, 172, 192, 216, 240, 268, 304, 344, 384, 424, + 464, 504, 544, 584, 624, 664, 704, 744, 768 +}; + +static const uint16_t swb_offset_768_48[] = +{ + 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 +}; + +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 +}; + +static const uint16_t swb_offset_768_24[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, + 52, 60, 68, 76, 84, 92, 100, 108, 116, 124, 136, 148, + 160, 172, 188, 204, 220, 240, 260, 284, 308, 336, 364, 396, + 432, 468, 508, 552, 600, 652, 704, 768 +}; + +static const uint16_t swb_offset_768_16[] = +{ + 0, 8, 16, 24, 32, 40, 48, 56, 64, + 72, 80, 88, 100, 112, 124, 136, 148, 160, + 172, 184, 196, 212, 228, 244, 260, 280, 300, + 320, 344, 368, 396, 424, 456, 492, 532, 572, + 616, 664, 716, 768 +}; + +static const uint16_t swb_offset_768_8[] = +{ + 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, + 120, 132, 144, 156, 172, 188, 204, 220, 236, 252, + 268, 288, 308, 328, 348, 372, 396, 420, 448, 476, + 508, 544, 580, 620, 664, 712, 764, 768 +}; + +static const uint16_t swb_offset_96_96[] = +{ + 0, 4, 8, 12, 16, 20, 24, + 32, 40, 48, 64, 92, 96 +}; + +static const uint16_t swb_offset_96_64[] = +{ + 0, 4, 8, 12, 16, 20, 24, + 32, 40, 48, 64, 92, 96 +}; + +static const uint16_t swb_offset_96_48[] = +{ + 0, 4, 8, 12, 16, 20, 28, + 36, 44, 56, 68, 80, 96 +}; + +static const uint16_t swb_offset_96_24[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, + 36, 44, 52, 64, 76, 92, 96 +}; + +static const uint16_t swb_offset_96_16[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 40, 48, 60, 72, 88, 96 +}; + +static const uint16_t swb_offset_96_8[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, + 36, 44, 52, 60, 72, 88, 96 +}; + const uint16_t * const ff_swb_offset_1024[] = { swb_offset_1024_96, swb_offset_1024_96, swb_offset_1024_64, swb_offset_1024_48, swb_offset_1024_48, swb_offset_1024_32, @@ -1446,6 +1923,14 @@ const uint16_t * const ff_swb_offset_960[] = { swb_offset_960_8 }; +const uint16_t * const ff_swb_offset_768[] = { + swb_offset_768_96, swb_offset_768_96, swb_offset_768_64, + swb_offset_768_48, swb_offset_768_48, swb_offset_768_32, + swb_offset_768_24, swb_offset_768_24, swb_offset_768_16, + swb_offset_768_16, swb_offset_768_16, swb_offset_768_8, + swb_offset_768_8 +}; + const uint16_t * const ff_swb_offset_512[] = { NULL, NULL, NULL, swb_offset_512_48, swb_offset_512_48, swb_offset_512_32, @@ -1480,6 +1965,14 @@ const uint16_t * const ff_swb_offset_120[] = { swb_offset_120_8 }; +const uint16_t * const ff_swb_offset_96[] = { + swb_offset_96_96, swb_offset_96_96, swb_offset_96_96, + swb_offset_96_48, swb_offset_96_48, swb_offset_96_48, + swb_offset_96_24, swb_offset_96_24, swb_offset_96_16, + swb_offset_96_16, swb_offset_96_16, swb_offset_96_8, + swb_offset_96_8 +}; + // @} /* @name ff_tns_max_bands @@ -1492,6 +1985,10 @@ const uint8_t ff_tns_max_bands_1024[] = { 31, 31, 34, 40, 42, 51, 46, 46, 42, 42, 42, 39, 39 }; +const uint8_t ff_tns_max_bands_usac_1024[] = { + 31, 31, 34, 40, 42, 51, 47, 47, 43, 43, 43, 40, 40 +}; + const uint8_t ff_tns_max_bands_512[] = { 0, 0, 0, 31, 32, 37, 31, 31, 0, 0, 0, 0, 0 }; @@ -1503,8 +2000,17 @@ const uint8_t ff_tns_max_bands_480[] = { const uint8_t ff_tns_max_bands_128[] = { 9, 9, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 }; + +const uint8_t ff_tns_max_bands_usac_128[] = { + 9, 9, 10, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15 +}; // @} +const uint8_t ff_usac_noise_fill_start_offset[2][2] = { + { 160, 20 }, + { 120, 15 }, +}; + const DECLARE_ALIGNED(32, float, ff_aac_eld_window_512)[1920] = { 0.00338834, 0.00567745, 0.00847677, 0.01172641, 0.01532555, 0.01917664, 0.02318809, 0.02729259, @@ -3377,3 +3883,65 @@ const DECLARE_ALIGNED(32, int, ff_aac_eld_window_480_fixed)[1800] = { 0xffecff1c, 0xffed391e, 0xffed740c, 0xffedafb1, 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, + 51200, 40000, 38400, 34150, 28800, 25600, 20000, 19200, + 17075, 14400, 12800, 9600, -1, -1, -1, -1, +}; + +/* Window type (only long+eight, start/stop/stopstart), sine+sine, kbd+kbd, sine+kbd, kbd+sine */ +const float ff_aac_usac_mdst_filt_cur[4 /* Window */][4 /* Shape */][7] = +{ + { { 0.000000, 0.000000, 0.500000, 0.000000, -0.500000, 0.000000, 0.000000 }, + { 0.091497, 0.000000, 0.581427, 0.000000, -0.581427, 0.000000, -0.091497 }, + { 0.045748, 0.057238, 0.540714, 0.000000, -0.540714, -0.057238, -0.045748 }, + { 0.045748, -0.057238, 0.540714, 0.000000, -0.540714, 0.057238, -0.045748 } }, + { { 0.102658, 0.103791, 0.567149, 0.000000, -0.567149, -0.103791, -0.102658 }, + { 0.150512, 0.047969, 0.608574, 0.000000, -0.608574, -0.047969, -0.150512 }, + { 0.104763, 0.105207, 0.567861, 0.000000, -0.567861, -0.105207, -0.104763 }, + { 0.148406, 0.046553, 0.607863, 0.000000, -0.607863, -0.046553, -0.148406 } }, + { { 0.102658, -0.103791, 0.567149, 0.000000, -0.567149, 0.103791, -0.102658 }, + { 0.150512, -0.047969, 0.608574, 0.000000, -0.608574, 0.047969, -0.150512 }, + { 0.148406, -0.046553, 0.607863, 0.000000, -0.607863, 0.046553, -0.148406 }, + { 0.104763, -0.105207, 0.567861, 0.000000, -0.567861, 0.105207, -0.104763 } }, + { { 0.205316, 0.000000, 0.634298, 0.000000, -0.634298, 0.000000, -0.205316 }, + { 0.209526, 0.000000, 0.635722, 0.000000, -0.635722, 0.000000, -0.209526 }, + { 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 e1a2d8b9a..84879aa8f 100644 --- a/libavcodec/aactab.h +++ b/libavcodec/aactab.h @@ -64,6 +64,8 @@ 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); @@ -72,10 +74,12 @@ void ff_aac_float_common_init(void); */ extern const uint8_t ff_aac_num_swb_1024[]; extern const uint8_t ff_aac_num_swb_960 []; +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 []; +extern const uint8_t ff_aac_num_swb_96 []; // @} extern const uint8_t ff_aac_pred_sfb_max []; @@ -91,16 +95,37 @@ extern const float *const ff_aac_codebook_vectors[]; extern const float *const ff_aac_codebook_vector_vals[]; extern const uint16_t *const ff_aac_codebook_vector_idx[]; +extern const uint16_t ff_aac_ac_msb_cdfs[64][17]; +extern const uint16_t ff_aac_ac_lsb_cdfs[3][4]; +extern const uint8_t ff_aac_ac_lookup_m[742]; +extern const uint32_t ff_aac_ac_hash_m[742]; +extern const uint16_t ff_aac_ac_cf_m[64][17]; + extern const uint16_t * const ff_swb_offset_1024[13]; extern const uint16_t * const ff_swb_offset_960 [13]; +extern const uint16_t * const ff_swb_offset_768 [13]; extern const uint16_t * const ff_swb_offset_512 [13]; extern const uint16_t * const ff_swb_offset_480 [13]; extern const uint16_t * const ff_swb_offset_128 [13]; extern const uint16_t * const ff_swb_offset_120 [13]; +extern const uint16_t * const ff_swb_offset_96 [13]; extern const uint8_t ff_tns_max_bands_1024[13]; extern const uint8_t ff_tns_max_bands_512 [13]; extern const uint8_t ff_tns_max_bands_480 [13]; extern const uint8_t ff_tns_max_bands_128 [13]; +extern const uint8_t ff_tns_max_bands_usac_1024[13]; +extern const uint8_t ff_tns_max_bands_usac_128[13]; + +/* [x][y], x == 1 -> frame len is 768 frames, y == 1 -> is eight_short */ +extern const uint8_t ff_usac_noise_fill_start_offset[2][2]; + +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 beb6a02f5..9affb9278 100644 --- a/libavcodec/aarch64/Makefile +++ b/libavcodec/aarch64/Makefile @@ -1,4 +1,6 @@ # subsystems +OBJS-$(CONFIG_AC3DSP) += aarch64/ac3dsp_init_aarch64.o +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 @@ -8,6 +10,7 @@ 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_NEON_CLOBBER_TEST) += aarch64/neontest.o OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_init_aarch64.o OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp_init.o @@ -35,6 +38,8 @@ ARMV8-OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp.o # subsystems NEON-OBJS-$(CONFIG_AAC_DECODER) += aarch64/sbrdsp_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 NEON-OBJS-$(CONFIG_H264CHROMA) += aarch64/h264cmc_neon.o NEON-OBJS-$(CONFIG_H264DSP) += aarch64/h264dsp_neon.o \ @@ -47,6 +52,7 @@ 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_PIXBLOCKDSP) += aarch64/pixblockdsp_neon.o NEON-OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_neon.o NEON-OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_neon.o @@ -65,6 +71,6 @@ NEON-OBJS-$(CONFIG_VP9_DECODER) += aarch64/vp9itxfm_16bpp_neon.o \ NEON-OBJS-$(CONFIG_HEVC_DECODER) += aarch64/hevcdsp_deblock_neon.o \ aarch64/hevcdsp_idct_neon.o \ aarch64/hevcdsp_init_aarch64.o \ - aarch64/hevcdsp_qpel_neon.o \ - aarch64/hevcdsp_epel_neon.o \ - aarch64/hevcdsp_sao_neon.o + aarch64/h26x/epel_neon.o \ + aarch64/h26x/qpel_neon.o \ + aarch64/h26x/sao_neon.o diff --git a/libavcodec/aarch64/ac3dsp_init_aarch64.c b/libavcodec/aarch64/ac3dsp_init_aarch64.c new file mode 100644 index 000000000..e367353e1 --- /dev/null +++ b/libavcodec/aarch64/ac3dsp_init_aarch64.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 Geoff Hill + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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/arm/cpu.h" +#include "libavutil/attributes.h" +#include "libavcodec/ac3dsp.h" +#include "config.h" + +void ff_ac3_exponent_min_neon(uint8_t *exp, int num_reuse_blocks, int nb_coefs); +void ff_ac3_extract_exponents_neon(uint8_t *exp, int32_t *coef, int nb_coefs); +void ff_float_to_fixed24_neon(int32_t *dst, const float *src, size_t len); +void ff_ac3_sum_square_butterfly_int32_neon(int64_t sum[4], + const int32_t *coef0, + const int32_t *coef1, + int len); +void ff_ac3_sum_square_butterfly_float_neon(float sum[4], + const float *coef0, + const float *coef1, + int len); + +av_cold void ff_ac3dsp_init_aarch64(AC3DSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + if (!have_neon(cpu_flags)) return; + + c->ac3_exponent_min = ff_ac3_exponent_min_neon; + c->extract_exponents = ff_ac3_extract_exponents_neon; + c->float_to_fixed24 = ff_float_to_fixed24_neon; + c->sum_square_butterfly_int32 = ff_ac3_sum_square_butterfly_int32_neon; + c->sum_square_butterfly_float = ff_ac3_sum_square_butterfly_float_neon; +} diff --git a/libavcodec/aarch64/ac3dsp_neon.S b/libavcodec/aarch64/ac3dsp_neon.S new file mode 100644 index 000000000..7e97cc39f --- /dev/null +++ b/libavcodec/aarch64/ac3dsp_neon.S @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011 Mans Rullgard + * Copyright (c) 2024 Geoff Hill + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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_ac3_exponent_min_neon, export=1 + cbz w1, 3f +1: ld1 {v0.16b}, [x0] + mov w3, w1 + add x4, x0, #256 +2: ld1 {v1.16b}, [x4] + umin v0.16b, v0.16b, v1.16b + add x4, x4, #256 + subs w3, w3, #1 + b.gt 2b + st1 {v0.16b}, [x0], #16 + subs w2, w2, #16 + b.gt 1b +3: ret +endfunc + +function ff_ac3_extract_exponents_neon, export=1 + movi v1.4s, #8 +1: ld1 {v0.4s}, [x1], #16 + abs v0.4s, v0.4s + clz v0.4s, v0.4s + sub v0.4s, v0.4s, v1.4s + xtn v0.4h, v0.4s + xtn v0.8b, v0.8h + st1 {v0.s}[0], [x0], #4 + subs w2, w2, #4 + b.gt 1b + ret +endfunc + +function ff_float_to_fixed24_neon, export=1 +1: ld1 {v0.4s, v1.4s}, [x1], #32 + fcvtzs v0.4s, v0.4s, #24 + ld1 {v2.4s, v3.4s}, [x1], #32 + fcvtzs v1.4s, v1.4s, #24 + fcvtzs v2.4s, v2.4s, #24 + st1 {v0.4s, v1.4s}, [x0], #32 + fcvtzs v3.4s, v3.4s, #24 + st1 {v2.4s, v3.4s}, [x0], #32 + subs w2, w2, #16 + b.ne 1b + ret +endfunc + +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 + b.gt 1b + addp d0, v0.2d + addp d1, v1.2d + addp d2, v2.2d + addp d3, v3.2d + st1 {v0.1d-v3.1d}, [x0] + ret +endfunc + +function ff_ac3_sum_square_butterfly_float_neon, export=1 + movi v0.4s, #0 + movi v1.4s, #0 + movi v2.4s, #0 + movi v3.4s, #0 +1: ld1 {v30.4s}, [x1], #16 + ld1 {v31.4s}, [x2], #16 + fadd v16.4s, v30.4s, v31.4s + fsub v17.4s, v30.4s, v31.4s + fmla v0.4s, v30.4s, v30.4s + fmla v1.4s, v31.4s, v31.4s + fmla v2.4s, v16.4s, v16.4s + fmla v3.4s, v17.4s, v17.4s + subs w3, w3, #4 + b.gt 1b + faddp v0.4s, v0.4s, v1.4s + faddp v2.4s, v2.4s, v3.4s + faddp v0.4s, v0.4s, v2.4s + st1 {v0.4s}, [x0] + ret +endfunc diff --git a/libavcodec/alpha/hpeldsp_alpha.h b/libavcodec/aarch64/fdct.h similarity index 75% rename from libavcodec/alpha/hpeldsp_alpha.h rename to libavcodec/aarch64/fdct.h index 985182c67..0901b53a8 100644 --- a/libavcodec/alpha/hpeldsp_alpha.h +++ b/libavcodec/aarch64/fdct.h @@ -16,13 +16,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_ALPHA_HPELDSP_ALPHA_H -#define AVCODEC_ALPHA_HPELDSP_ALPHA_H +#ifndef AVCODEC_AARCH64_FDCT_H +#define AVCODEC_AARCH64_FDCT_H #include -#include -void put_pixels_axp_asm(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h); +void ff_fdct_neon(int16_t *block); -#endif /* AVCODEC_ALPHA_HPELDSP_ALPHA_H */ +#endif /* AVCODEC_AARCH64_FDCT_H */ diff --git a/libavcodec/aarch64/fdctdsp_init_aarch64.c b/libavcodec/aarch64/fdctdsp_init_aarch64.c new file mode 100644 index 000000000..59d91bc8f --- /dev/null +++ b/libavcodec/aarch64/fdctdsp_init_aarch64.c @@ -0,0 +1,39 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/avcodec.h" +#include "libavcodec/fdctdsp.h" +#include "fdct.h" + +av_cold void ff_fdctdsp_init_aarch64(FDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + if (!high_bit_depth) { + if (avctx->dct_algo == FF_DCT_AUTO || + avctx->dct_algo == FF_DCT_NEON) { + c->fdct = ff_fdct_neon; + } + } + } +} diff --git a/libavcodec/aarch64/fdctdsp_neon.S b/libavcodec/aarch64/fdctdsp_neon.S new file mode 100644 index 000000000..53fa4debe --- /dev/null +++ b/libavcodec/aarch64/fdctdsp_neon.S @@ -0,0 +1,368 @@ +/* + * Armv8 Neon optimizations for libjpeg-turbo + * + * Copyright (C) 2009-2011, Nokia Corporation and/or its subsidiary(-ies). + * All Rights Reserved. + * Author: Siarhei Siamashka + * Copyright (C) 2013-2014, Linaro Limited. All Rights Reserved. + * Author: Ragesh Radhakrishnan + * Copyright (C) 2014-2016, 2020, D. R. Commander. All Rights Reserved. + * Copyright (C) 2015-2016, 2018, Matthieu Darbois. All Rights Reserved. + * Copyright (C) 2016, Siarhei Siamashka. All Rights Reserved. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "libavutil/aarch64/asm.S" +#include "neon.S" + +// #define EIGHT_BIT_SAMPLES + +/* Constants for jsimd_fdct_islow_neon() */ + +#define F_0_298 2446 /* FIX(0.298631336) */ +#define F_0_390 3196 /* FIX(0.390180644) */ +#define F_0_541 4433 /* FIX(0.541196100) */ +#define F_0_765 6270 /* FIX(0.765366865) */ +#define F_0_899 7373 /* FIX(0.899976223) */ +#define F_1_175 9633 /* FIX(1.175875602) */ +#define F_1_501 12299 /* FIX(1.501321110) */ +#define F_1_847 15137 /* FIX(1.847759065) */ +#define F_1_961 16069 /* FIX(1.961570560) */ +#define F_2_053 16819 /* FIX(2.053119869) */ +#define F_2_562 20995 /* FIX(2.562915447) */ +#define F_3_072 25172 /* FIX(3.072711026) */ + +const jsimd_fdct_islow_neon_consts, align=4 + .short F_0_298 + .short -F_0_390 + .short F_0_541 + .short F_0_765 + .short - F_0_899 + .short F_1_175 + .short F_1_501 + .short - F_1_847 + .short - F_1_961 + .short F_2_053 + .short - F_2_562 + .short F_3_072 + .short 0 /* padding */ + .short 0 + .short 0 + .short 0 +endconst + +#undef F_0_298 +#undef F_0_390 +#undef F_0_541 +#undef F_0_765 +#undef F_0_899 +#undef F_1_175 +#undef F_1_501 +#undef F_1_847 +#undef F_1_961 +#undef F_2_053 +#undef F_2_562 +#undef F_3_072 + +/*****************************************************************************/ + +/* + * jsimd_fdct_islow_neon + * + * This file contains a slower but more accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). The following code is based + * directly on the IJG''s original jfdctint.c; see the jfdctint.c for + * more details. + */ + +#define CONST_BITS 13 +#ifdef EIGHT_BIT_SAMPLES +#define PASS1_BITS 2 +#else +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +#define DESCALE_P1 (CONST_BITS - PASS1_BITS) +#define DESCALE_P2 (CONST_BITS + PASS1_BITS) + +#define XFIX_P_0_298 v0.h[0] +#define XFIX_N_0_390 v0.h[1] +#define XFIX_P_0_541 v0.h[2] +#define XFIX_P_0_765 v0.h[3] +#define XFIX_N_0_899 v0.h[4] +#define XFIX_P_1_175 v0.h[5] +#define XFIX_P_1_501 v0.h[6] +#define XFIX_N_1_847 v0.h[7] +#define XFIX_N_1_961 v1.h[0] +#define XFIX_P_2_053 v1.h[1] +#define XFIX_N_2_562 v1.h[2] +#define XFIX_P_3_072 v1.h[3] + +function ff_fdct_neon, export=1 + + DATA .req x0 + TMP .req x9 + + /* Load constants */ + movrel TMP, jsimd_fdct_islow_neon_consts + ld1 {v0.8h, v1.8h}, [TMP] + + /* Load all DATA into Neon registers with the following allocation: + * 0 1 2 3 | 4 5 6 7 + * ---------+-------- + * 0 | d16 | d17 | v16.8h + * 1 | d18 | d19 | v17.8h + * 2 | d20 | d21 | v18.8h + * 3 | d22 | d23 | v19.8h + * 4 | d24 | d25 | v20.8h + * 5 | d26 | d27 | v21.8h + * 6 | d28 | d29 | v22.8h + * 7 | d30 | d31 | v23.8h + */ + + ld1 {v16.8h, v17.8h, v18.8h, v19.8h}, [DATA], 64 + ld1 {v20.8h, v21.8h, v22.8h, v23.8h}, [DATA] + sub DATA, DATA, #64 + + /* Transpose */ + transpose_8x8H v16, v17, v18, v19, v20, v21, v22, v23, v31, v2 + + /* 1-D FDCT */ + add v24.8h, v16.8h, v23.8h /* tmp0 = dataptr[0] + dataptr[7]; */ + sub v31.8h, v16.8h, v23.8h /* tmp7 = dataptr[0] - dataptr[7]; */ + add v25.8h, v17.8h, v22.8h /* tmp1 = dataptr[1] + dataptr[6]; */ + sub v30.8h, v17.8h, v22.8h /* tmp6 = dataptr[1] - dataptr[6]; */ + add v26.8h, v18.8h, v21.8h /* tmp2 = dataptr[2] + dataptr[5]; */ + sub v29.8h, v18.8h, v21.8h /* tmp5 = dataptr[2] - dataptr[5]; */ + add v27.8h, v19.8h, v20.8h /* tmp3 = dataptr[3] + dataptr[4]; */ + sub v28.8h, v19.8h, v20.8h /* tmp4 = dataptr[3] - dataptr[4]; */ + + /* Even part */ + add v4.8h, v24.8h, v27.8h /* tmp10 = tmp0 + tmp3; */ + sub v5.8h, v24.8h, v27.8h /* tmp13 = tmp0 - tmp3; */ + add v6.8h, v25.8h, v26.8h /* tmp11 = tmp1 + tmp2; */ + sub v7.8h, v25.8h, v26.8h /* tmp12 = tmp1 - tmp2; */ + + add v16.8h, v4.8h, v6.8h /* tmp10 + tmp11 */ + sub v20.8h, v4.8h, v6.8h /* tmp10 - tmp11 */ + + add v18.8h, v7.8h, v5.8h /* tmp12 + tmp13 */ + + shl v16.8h, v16.8h, #PASS1_BITS /* dataptr[0] = (DCTELEM)LEFT_SHIFT(tmp10 + tmp11, PASS1_BITS); */ + shl v20.8h, v20.8h, #PASS1_BITS /* dataptr[4] = (DCTELEM)LEFT_SHIFT(tmp10 - tmp11, PASS1_BITS); */ + + smull2 v24.4s, v18.8h, XFIX_P_0_541 /* z1 hi = MULTIPLY(tmp12 + tmp13, XFIX_P_0_541); */ + smull v18.4s, v18.4h, XFIX_P_0_541 /* z1 lo = MULTIPLY(tmp12 + tmp13, XFIX_P_0_541); */ + mov v22.16b, v18.16b + mov v25.16b, v24.16b + + smlal v18.4s, v5.4h, XFIX_P_0_765 /* lo z1 + MULTIPLY(tmp13, XFIX_P_0_765) */ + smlal2 v24.4s, v5.8h, XFIX_P_0_765 /* hi z1 + MULTIPLY(tmp13, XFIX_P_0_765) */ + smlal v22.4s, v7.4h, XFIX_N_1_847 /* lo z1 + MULTIPLY(tmp12, XFIX_N_1_847) */ + smlal2 v25.4s, v7.8h, XFIX_N_1_847 /* hi z1 + MULTIPLY(tmp12, XFIX_N_1_847) */ + + rshrn v18.4h, v18.4s, #DESCALE_P1 + rshrn v22.4h, v22.4s, #DESCALE_P1 + rshrn2 v18.8h, v24.4s, #DESCALE_P1 /* dataptr[2] = (DCTELEM)DESCALE(z1 + MULTIPLY(tmp13, XFIX_P_0_765), CONST_BITS-PASS1_BITS); */ + rshrn2 v22.8h, v25.4s, #DESCALE_P1 /* dataptr[6] = (DCTELEM)DESCALE(z1 + MULTIPLY(tmp12, XFIX_N_1_847), CONST_BITS-PASS1_BITS); */ + + /* Odd part */ + add v2.8h, v28.8h, v31.8h /* z1 = tmp4 + tmp7; */ + add v3.8h, v29.8h, v30.8h /* z2 = tmp5 + tmp6; */ + add v6.8h, v28.8h, v30.8h /* z3 = tmp4 + tmp6; */ + add v7.8h, v29.8h, v31.8h /* z4 = tmp5 + tmp7; */ + smull v4.4s, v6.4h, XFIX_P_1_175 /* z5 lo = z3 lo * XFIX_P_1_175 */ + smull2 v5.4s, v6.8h, XFIX_P_1_175 + smlal v4.4s, v7.4h, XFIX_P_1_175 /* z5 = MULTIPLY(z3 + z4, FIX_1_175875602); */ + smlal2 v5.4s, v7.8h, XFIX_P_1_175 + + smull2 v24.4s, v28.8h, XFIX_P_0_298 + smull2 v25.4s, v29.8h, XFIX_P_2_053 + smull2 v26.4s, v30.8h, XFIX_P_3_072 + smull2 v27.4s, v31.8h, XFIX_P_1_501 + smull v23.4s, v28.4h, XFIX_P_0_298 /* tmp4 = MULTIPLY(tmp4, FIX_0_298631336); */ + smull v21.4s, v29.4h, XFIX_P_2_053 /* tmp5 = MULTIPLY(tmp5, FIX_2_053119869); */ + smull v19.4s, v30.4h, XFIX_P_3_072 /* tmp6 = MULTIPLY(tmp6, FIX_3_072711026); */ + smull v17.4s, v31.4h, XFIX_P_1_501 /* tmp7 = MULTIPLY(tmp7, FIX_1_501321110); */ + + smull2 v28.4s, v2.8h, XFIX_N_0_899 + smull2 v29.4s, v3.8h, XFIX_N_2_562 + smull2 v30.4s, v6.8h, XFIX_N_1_961 + smull2 v31.4s, v7.8h, XFIX_N_0_390 + smull v2.4s, v2.4h, XFIX_N_0_899 /* z1 = MULTIPLY(z1, -FIX_0_899976223); */ + smull v3.4s, v3.4h, XFIX_N_2_562 /* z2 = MULTIPLY(z2, -FIX_2_562915447); */ + smull v6.4s, v6.4h, XFIX_N_1_961 /* z3 = MULTIPLY(z3, -FIX_1_961570560); */ + smull v7.4s, v7.4h, XFIX_N_0_390 /* z4 = MULTIPLY(z4, -FIX_0_390180644); */ + + add v6.4s, v6.4s, v4.4s /* z3 += z5 */ + add v30.4s, v30.4s, v5.4s + add v7.4s, v7.4s, v4.4s /* z4 += z5 */ + add v31.4s, v31.4s, v5.4s + + add v23.4s, v23.4s, v2.4s /* tmp4 += z1 */ + add v24.4s, v24.4s, v28.4s + add v21.4s, v21.4s, v3.4s /* tmp5 += z2 */ + add v25.4s, v25.4s, v29.4s + add v19.4s, v19.4s, v6.4s /* tmp6 += z3 */ + add v26.4s, v26.4s, v30.4s + add v17.4s, v17.4s, v7.4s /* tmp7 += z4 */ + add v27.4s, v27.4s, v31.4s + + add v23.4s, v23.4s, v6.4s /* tmp4 += z3 */ + add v24.4s, v24.4s, v30.4s + add v21.4s, v21.4s, v7.4s /* tmp5 += z4 */ + add v25.4s, v25.4s, v31.4s + add v19.4s, v19.4s, v3.4s /* tmp6 += z2 */ + add v26.4s, v26.4s, v29.4s + add v17.4s, v17.4s, v2.4s /* tmp7 += z1 */ + add v27.4s, v27.4s, v28.4s + + rshrn v23.4h, v23.4s, #DESCALE_P1 + rshrn v21.4h, v21.4s, #DESCALE_P1 + rshrn v19.4h, v19.4s, #DESCALE_P1 + rshrn v17.4h, v17.4s, #DESCALE_P1 + rshrn2 v23.8h, v24.4s, #DESCALE_P1 /* dataptr[7] = (DCTELEM)DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS); */ + rshrn2 v21.8h, v25.4s, #DESCALE_P1 /* dataptr[5] = (DCTELEM)DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS); */ + rshrn2 v19.8h, v26.4s, #DESCALE_P1 /* dataptr[3] = (DCTELEM)DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS); */ + rshrn2 v17.8h, v27.4s, #DESCALE_P1 /* dataptr[1] = (DCTELEM)DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS); */ + + /* Transpose */ + transpose_8x8H v16, v17, v18, v19, v20, v21, v22, v23, v31, v2 + + /* 1-D FDCT */ + add v24.8h, v16.8h, v23.8h /* tmp0 = dataptr[0] + dataptr[7]; */ + sub v31.8h, v16.8h, v23.8h /* tmp7 = dataptr[0] - dataptr[7]; */ + add v25.8h, v17.8h, v22.8h /* tmp1 = dataptr[1] + dataptr[6]; */ + sub v30.8h, v17.8h, v22.8h /* tmp6 = dataptr[1] - dataptr[6]; */ + add v26.8h, v18.8h, v21.8h /* tmp2 = dataptr[2] + dataptr[5]; */ + sub v29.8h, v18.8h, v21.8h /* tmp5 = dataptr[2] - dataptr[5]; */ + add v27.8h, v19.8h, v20.8h /* tmp3 = dataptr[3] + dataptr[4]; */ + sub v28.8h, v19.8h, v20.8h /* tmp4 = dataptr[3] - dataptr[4]; */ + + /* Even part */ + add v4.8h, v24.8h, v27.8h /* tmp10 = tmp0 + tmp3; */ + sub v5.8h, v24.8h, v27.8h /* tmp13 = tmp0 - tmp3; */ + add v6.8h, v25.8h, v26.8h /* tmp11 = tmp1 + tmp2; */ + sub v7.8h, v25.8h, v26.8h /* tmp12 = tmp1 - tmp2; */ + + add v16.8h, v4.8h, v6.8h /* tmp10 + tmp11 */ + sub v20.8h, v4.8h, v6.8h /* tmp10 - tmp11 */ + + add v18.8h, v7.8h, v5.8h /* tmp12 + tmp13 */ + + srshr v16.8h, v16.8h, #PASS1_BITS /* dataptr[0] = (DCTELEM)DESCALE(tmp10 + tmp11, PASS1_BITS); */ + srshr v20.8h, v20.8h, #PASS1_BITS /* dataptr[4] = (DCTELEM)DESCALE(tmp10 - tmp11, PASS1_BITS); */ + + smull2 v24.4s, v18.8h, XFIX_P_0_541 /* z1 hi = MULTIPLY(tmp12 + tmp13, XFIX_P_0_541); */ + smull v18.4s, v18.4h, XFIX_P_0_541 /* z1 lo = MULTIPLY(tmp12 + tmp13, XFIX_P_0_541); */ + mov v22.16b, v18.16b + mov v25.16b, v24.16b + + smlal v18.4s, v5.4h, XFIX_P_0_765 /* lo z1 + MULTIPLY(tmp13, XFIX_P_0_765) */ + smlal2 v24.4s, v5.8h, XFIX_P_0_765 /* hi z1 + MULTIPLY(tmp13, XFIX_P_0_765) */ + smlal v22.4s, v7.4h, XFIX_N_1_847 /* lo z1 + MULTIPLY(tmp12, XFIX_N_1_847) */ + smlal2 v25.4s, v7.8h, XFIX_N_1_847 /* hi z1 + MULTIPLY(tmp12, XFIX_N_1_847) */ + + rshrn v18.4h, v18.4s, #DESCALE_P2 + rshrn v22.4h, v22.4s, #DESCALE_P2 + rshrn2 v18.8h, v24.4s, #DESCALE_P2 /* dataptr[2] = (DCTELEM)DESCALE(z1 + MULTIPLY(tmp13, XFIX_P_0_765), CONST_BITS+PASS1_BITS); */ + rshrn2 v22.8h, v25.4s, #DESCALE_P2 /* dataptr[6] = (DCTELEM)DESCALE(z1 + MULTIPLY(tmp12, XFIX_N_1_847), CONST_BITS+PASS1_BITS); */ + + /* Odd part */ + add v2.8h, v28.8h, v31.8h /* z1 = tmp4 + tmp7; */ + add v3.8h, v29.8h, v30.8h /* z2 = tmp5 + tmp6; */ + add v6.8h, v28.8h, v30.8h /* z3 = tmp4 + tmp6; */ + add v7.8h, v29.8h, v31.8h /* z4 = tmp5 + tmp7; */ + + smull v4.4s, v6.4h, XFIX_P_1_175 /* z5 lo = z3 lo * XFIX_P_1_175 */ + smull2 v5.4s, v6.8h, XFIX_P_1_175 + smlal v4.4s, v7.4h, XFIX_P_1_175 /* z5 = MULTIPLY(z3 + z4, FIX_1_175875602); */ + smlal2 v5.4s, v7.8h, XFIX_P_1_175 + + smull2 v24.4s, v28.8h, XFIX_P_0_298 + smull2 v25.4s, v29.8h, XFIX_P_2_053 + smull2 v26.4s, v30.8h, XFIX_P_3_072 + smull2 v27.4s, v31.8h, XFIX_P_1_501 + smull v23.4s, v28.4h, XFIX_P_0_298 /* tmp4 = MULTIPLY(tmp4, FIX_0_298631336); */ + smull v21.4s, v29.4h, XFIX_P_2_053 /* tmp5 = MULTIPLY(tmp5, FIX_2_053119869); */ + smull v19.4s, v30.4h, XFIX_P_3_072 /* tmp6 = MULTIPLY(tmp6, FIX_3_072711026); */ + smull v17.4s, v31.4h, XFIX_P_1_501 /* tmp7 = MULTIPLY(tmp7, FIX_1_501321110); */ + + smull2 v28.4s, v2.8h, XFIX_N_0_899 + smull2 v29.4s, v3.8h, XFIX_N_2_562 + smull2 v30.4s, v6.8h, XFIX_N_1_961 + smull2 v31.4s, v7.8h, XFIX_N_0_390 + smull v2.4s, v2.4h, XFIX_N_0_899 /* z1 = MULTIPLY(z1, -FIX_0_899976223); */ + smull v3.4s, v3.4h, XFIX_N_2_562 /* z2 = MULTIPLY(z2, -FIX_2_562915447); */ + smull v6.4s, v6.4h, XFIX_N_1_961 /* z3 = MULTIPLY(z3, -FIX_1_961570560); */ + smull v7.4s, v7.4h, XFIX_N_0_390 /* z4 = MULTIPLY(z4, -FIX_0_390180644); */ + + add v6.4s, v6.4s, v4.4s /* z3 += z5 */ + add v30.4s, v30.4s, v5.4s + add v7.4s, v7.4s, v4.4s /* z4 += z5 */ + add v31.4s, v31.4s, v5.4s + + add v23.4s, v23.4s, v2.4s /* tmp4 += z1 */ + add v24.4s, v24.4s, v28.4s + add v21.4s, v21.4s, v3.4s /* tmp5 += z2 */ + add v25.4s, v25.4s, v29.4s + add v19.4s, v19.4s, v6.4s /* tmp6 += z3 */ + add v26.4s, v26.4s, v30.4s + add v17.4s, v17.4s, v7.4s /* tmp7 += z4 */ + add v27.4s, v27.4s, v31.4s + + add v23.4s, v23.4s, v6.4s /* tmp4 += z3 */ + add v24.4s, v24.4s, v30.4s + add v21.4s, v21.4s, v7.4s /* tmp5 += z4 */ + add v25.4s, v25.4s, v31.4s + add v19.4s, v19.4s, v3.4s /* tmp6 += z2 */ + add v26.4s, v26.4s, v29.4s + add v17.4s, v17.4s, v2.4s /* tmp7 += z1 */ + add v27.4s, v27.4s, v28.4s + + rshrn v23.4h, v23.4s, #DESCALE_P2 + rshrn v21.4h, v21.4s, #DESCALE_P2 + rshrn v19.4h, v19.4s, #DESCALE_P2 + rshrn v17.4h, v17.4s, #DESCALE_P2 + rshrn2 v23.8h, v24.4s, #DESCALE_P2 /* dataptr[7] = (DCTELEM)DESCALE(tmp4 + z1 + z3, CONST_BITS+PASS1_BITS); */ + rshrn2 v21.8h, v25.4s, #DESCALE_P2 /* dataptr[5] = (DCTELEM)DESCALE(tmp5 + z2 + z4, CONST_BITS+PASS1_BITS); */ + rshrn2 v19.8h, v26.4s, #DESCALE_P2 /* dataptr[3] = (DCTELEM)DESCALE(tmp6 + z2 + z3, CONST_BITS+PASS1_BITS); */ + rshrn2 v17.8h, v27.4s, #DESCALE_P2 /* dataptr[1] = (DCTELEM)DESCALE(tmp7 + z1 + z4, CONST_BITS+PASS1_BITS); */ + + /* Store results */ + st1 {v16.8h, v17.8h, v18.8h, v19.8h}, [DATA], 64 + st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [DATA] + + ret + + .unreq DATA + .unreq TMP +endfunc + +#undef XFIX_P_0_298 +#undef XFIX_N_0_390 +#undef XFIX_P_0_541 +#undef XFIX_P_0_765 +#undef XFIX_N_0_899 +#undef XFIX_P_1_175 +#undef XFIX_P_1_501 +#undef XFIX_N_1_847 +#undef XFIX_N_1_961 +#undef XFIX_P_2_053 +#undef XFIX_N_2_562 +#undef XFIX_P_3_072 diff --git a/libavcodec/aarch64/h264pred_neon.S b/libavcodec/aarch64/h264pred_neon.S index ea37689f3..d0999938e 100644 --- a/libavcodec/aarch64/h264pred_neon.S +++ b/libavcodec/aarch64/h264pred_neon.S @@ -502,28 +502,27 @@ function ff_pred16x16_plane_neon_10, export=1 add v7.4h, v7.4h, v0.4h shl v2.4h, v7.4h, #4 ssubl v2.4s, v2.4h, v3.4h - shl v3.4h, v4.4h, #4 ext v0.16b, v0.16b, v0.16b, #14 - ssubl v6.4s, v5.4h, v3.4h + sxtl v6.4s, v5.4h // c mov v0.h[0], wzr mul v0.8h, v0.8h, v4.h[0] dup v16.4s, v2.s[0] dup v17.4s, v2.s[0] - dup v2.8h, v4.h[0] - dup v3.4s, v6.s[0] - shl v2.8h, v2.8h, #3 + dup v2.8h, v4.h[0] // b + dup v3.4s, v6.s[0] // c + sshll v2.4s, v2.4h, #3 // b * 8 saddw v16.4s, v16.4s, v0.4h saddw2 v17.4s, v17.4s, v0.8h - saddw v3.4s, v3.4s, v2.4h + sub v3.4s, v3.4s, v2.4s mov w3, #16 mvni v4.8h, #0xFC, lsl #8 // 1023 for clipping 1: sqshrun v0.4h, v16.4s, #5 sqshrun2 v0.8h, v17.4s, #5 - saddw v16.4s, v16.4s, v2.4h - saddw v17.4s, v17.4s, v2.4h + add v16.4s, v16.4s, v2.4s + add v17.4s, v17.4s, v2.4s sqshrun v1.4h, v16.4s, #5 sqshrun2 v1.8h, v17.4s, #5 add v16.4s, v16.4s, v3.4s @@ -595,12 +594,11 @@ function ff_pred8x8_plane_neon_10, export=1 ssubl v2.4s, v2.4h, v3.4h ext v0.16b, v0.16b, v0.16b, #14 mov v0.h[0], wzr - mul v0.8h, v0.8h, v5.h[0] dup v1.4s, v2.s[0] dup v2.4s, v2.s[0] dup v3.8h, v5.h[1] - saddw v1.4s, v1.4s, v0.4h - saddw2 v2.4s, v2.4s, v0.8h + smlal v1.4s, v0.4h, v5.h[0] + smlal2 v2.4s, v0.8h, v5.h[0] mov w3, #8 mvni v4.8h, #0xFC, lsl #8 // 1023 for clipping 1: diff --git a/libavcodec/aarch64/h26x/dsp.h b/libavcodec/aarch64/h26x/dsp.h new file mode 100644 index 000000000..0fefb4d70 --- /dev/null +++ b/libavcodec/aarch64/h26x/dsp.h @@ -0,0 +1,308 @@ +/* + * 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_AARCH64_H26X_DSP_H +#define AVCODEC_AARCH64_H26X_DSP_H + +#include +#include + +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_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, + const int16_t *sao_offset_val, int eo, int width, int height); + +void ff_vvc_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_vvc_sao_edge_filter_8x8_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); + +#define NEON8_FNPROTO_PARTIAL_6(fn, args, ext) \ + void ff_hevc_put_hevc_##fn##_h4_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##_h6_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##_h8_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##_h12_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##_h16_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##_h32_8_neon##ext args; + +NEON8_FNPROTO_PARTIAL_6(qpel, (int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, + intptr_t mx, intptr_t my, int width),) + +NEON8_FNPROTO_PARTIAL_6(qpel_uni, (uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, + ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width),) + +NEON8_FNPROTO_PARTIAL_6(qpel_bi, (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 NEON8_FNPROTO(fn, args, ext) \ + void ff_hevc_put_hevc_##fn##4_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##6_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##8_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##12_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##16_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##24_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##32_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##48_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##64_8_neon##ext args + +#define NEON8_FNPROTO_PARTIAL_4(fn, args, ext) \ + void ff_hevc_put_hevc_##fn##4_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##8_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##16_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##64_8_neon##ext args + +#define NEON8_FNPROTO_PARTIAL_5(fn, args, ext) \ + void ff_hevc_put_hevc_##fn##4_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##8_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##16_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##32_8_neon##ext args; \ + void ff_hevc_put_hevc_##fn##64_8_neon##ext args + +NEON8_FNPROTO(pel_pixels, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +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(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),); + +NEON8_FNPROTO(epel_bi_v, (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(epel_bi_hv, (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(epel_bi_hv, (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), _i8mm); + +NEON8_FNPROTO(epel_v, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +NEON8_FNPROTO(pel_uni_pixels, (uint8_t *_dst, ptrdiff_t _dststride, + const uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +NEON8_FNPROTO(pel_uni_w_pixels, (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),); + +NEON8_FNPROTO(epel_uni_v, (uint8_t *dst, ptrdiff_t dststride, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +NEON8_FNPROTO(epel_uni_hv, (uint8_t *dst, ptrdiff_t _dststride, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +NEON8_FNPROTO(epel_uni_hv, (uint8_t *dst, ptrdiff_t _dststride, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width), _i8mm); + +NEON8_FNPROTO(epel_uni_w_v, (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),); + +NEON8_FNPROTO_PARTIAL_4(qpel_uni_w_v, (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),); + +NEON8_FNPROTO(epel_h, (int16_t *dst, + const uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +NEON8_FNPROTO(epel_hv, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width), ); + +NEON8_FNPROTO(epel_h, (int16_t *dst, + const uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width), _i8mm); + +NEON8_FNPROTO(epel_hv, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width), _i8mm); + +NEON8_FNPROTO(epel_uni_w_h, (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),); + +NEON8_FNPROTO(epel_uni_w_h, (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), _i8mm); + +NEON8_FNPROTO(qpel_h, (int16_t *dst, + const uint8_t *_src, ptrdiff_t _srcstride, + int height, intptr_t mx, intptr_t my, int width), _i8mm); + +NEON8_FNPROTO(qpel_v, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +NEON8_FNPROTO(qpel_hv, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +NEON8_FNPROTO(qpel_hv, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width), _i8mm); + +NEON8_FNPROTO(qpel_uni_v, (uint8_t *dst, ptrdiff_t dststride, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +NEON8_FNPROTO(qpel_uni_hv, (uint8_t *dst, ptrdiff_t dststride, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width),); + +NEON8_FNPROTO(qpel_uni_hv, (uint8_t *dst, ptrdiff_t dststride, + const uint8_t *src, ptrdiff_t srcstride, + int height, intptr_t mx, intptr_t my, int width), _i8mm); + +NEON8_FNPROTO(qpel_uni_w_h, (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),); + +NEON8_FNPROTO(qpel_uni_w_h, (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), _i8mm); + +NEON8_FNPROTO(epel_uni_w_hv, (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),); + +NEON8_FNPROTO(epel_uni_w_hv, (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), _i8mm); + +NEON8_FNPROTO_PARTIAL_5(qpel_uni_w_hv, (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),); + +NEON8_FNPROTO_PARTIAL_5(qpel_uni_w_hv, (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), _i8mm); + +NEON8_FNPROTO(qpel_bi_v, (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(qpel_bi_hv, (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(qpel_bi_hv, (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), _i8mm); + +#undef NEON8_FNPROTO_PARTIAL_4 +#define NEON8_FNPROTO_PARTIAL_4(fn, args, ext) \ + void ff_vvc_put_##fn##_h4_8_neon##ext args; \ + void ff_vvc_put_##fn##_h8_8_neon##ext args; \ + void ff_vvc_put_##fn##_h16_8_neon##ext args; \ + void ff_vvc_put_##fn##_h32_8_neon##ext args; + +NEON8_FNPROTO_PARTIAL_4(qpel, (int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, + const int8_t *hf, const int8_t *vf, int width),) + +NEON8_FNPROTO_PARTIAL_4(qpel_uni, (uint8_t *_dst, ptrdiff_t _dststride, const uint8_t *_src, + ptrdiff_t _srcstride, int height, const int8_t *hf, const int8_t *vf, int width),) + +NEON8_FNPROTO_PARTIAL_4(epel, (int16_t *dst, const uint8_t *_src, ptrdiff_t _srcstride, int height, + const int8_t *hf, const int8_t *vf, int width),) + +#undef NEON8_FNPROTO_PARTIAL_6 +#define NEON8_FNPROTO_PARTIAL_6(fn, args, ext) \ + void ff_vvc_put_##fn##4_8_neon##ext args; \ + void ff_vvc_put_##fn##8_8_neon##ext args; \ + void ff_vvc_put_##fn##16_8_neon##ext args; \ + void ff_vvc_put_##fn##32_8_neon##ext args; \ + void ff_vvc_put_##fn##64_8_neon##ext args; \ + void ff_vvc_put_##fn##128_8_neon##ext args + +NEON8_FNPROTO_PARTIAL_6(pel_pixels, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, int height, + const int8_t *hf, const int8_t *vf, int width),); + +NEON8_FNPROTO_PARTIAL_6(pel_uni_pixels, (uint8_t *_dst, ptrdiff_t _dststride, + const uint8_t *_src, ptrdiff_t _srcstride, int height, + const int8_t *hf, const int8_t *vf, int width),); + +NEON8_FNPROTO_PARTIAL_6(pel_uni_w_pixels, (uint8_t *_dst, ptrdiff_t _dststride, + const uint8_t *_src, ptrdiff_t _srcstride, + int height, int denom, int wx, int ox, + const int8_t *hf, const int8_t *vf, int width),); + +NEON8_FNPROTO_PARTIAL_6(qpel_h, (int16_t *dst, + const uint8_t *_src, ptrdiff_t _srcstride, int height, + const int8_t *hf, const int8_t *vf, int width), _i8mm); + +NEON8_FNPROTO_PARTIAL_6(epel_h, (int16_t *dst, + const uint8_t *_src, ptrdiff_t _srcstride, int height, + const int8_t *hf, const int8_t *vf, int width), _i8mm); + +void ff_vvc_put_qpel_v4_8_neon(int16_t *dst, const uint8_t *_src, + ptrdiff_t _srcstride, int height, + const int8_t *hf, const int8_t *vf, int width); + +void ff_vvc_put_qpel_v8_8_neon(int16_t *dst, const uint8_t *_src, + ptrdiff_t _srcstride, int height, + const int8_t *hf, const int8_t *vf, int width); + +NEON8_FNPROTO_PARTIAL_6(qpel_hv, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, int height, + const int8_t *hf, const int8_t *vf, int width),); + +NEON8_FNPROTO_PARTIAL_6(qpel_hv, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, int height, + const int8_t *hf, const int8_t *vf, int width), _i8mm); + +NEON8_FNPROTO_PARTIAL_6(epel_hv, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, int height, + const int8_t *hf, const int8_t *vf, int width),); + +NEON8_FNPROTO_PARTIAL_6(epel_hv, (int16_t *dst, + const uint8_t *src, ptrdiff_t srcstride, int height, + const int8_t *hf, const int8_t *vf, int width), _i8mm); + +#endif diff --git a/libavcodec/aarch64/hevcdsp_epel_neon.S b/libavcodec/aarch64/h26x/epel_neon.S similarity index 94% rename from libavcodec/aarch64/hevcdsp_epel_neon.S rename to libavcodec/aarch64/h26x/epel_neon.S index 378b0f7fb..e44a448b1 100644 --- a/libavcodec/aarch64/hevcdsp_epel_neon.S +++ b/libavcodec/aarch64/h26x/epel_neon.S @@ -19,7 +19,8 @@ */ #include "libavutil/aarch64/asm.S" -#define MAX_PB_SIZE 64 +#define HEVC_MAX_PB_SIZE 64 +#define VVC_MAX_PB_SIZE 128 const epel_filters, align=4 .byte 0, 0, 0, 0 @@ -71,6 +72,11 @@ endconst sxtl v0.8h, v0.8b .endm +.macro vvc_load_epel_filterh freg + ld1 {v0.8b}, [\freg] + sxtl v0.8h, v0.8b +.endm + .macro calc_epelh dst, src0, src1, src2, src3 smull \dst\().4s, \src0\().4h, v0.h[0] smlal \dst\().4s, \src1\().4h, v0.h[1] @@ -131,8 +137,13 @@ endconst b.ne 1b .endm +function ff_vvc_put_pel_pixels4_8_neon, export=1 + mov x7, #(VVC_MAX_PB_SIZE * 2) + b 1f +endfunc + function ff_hevc_put_hevc_pel_pixels4_8_neon, export=1 - mov x7, #(MAX_PB_SIZE * 2) + mov x7, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.s}[0], [x1], x2 ushll v4.8h, v0.8b, #6 subs w3, w3, #1 @@ -142,7 +153,7 @@ function ff_hevc_put_hevc_pel_pixels4_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_pixels6_8_neon, export=1 - mov x7, #(MAX_PB_SIZE * 2 - 8) + mov x7, #(HEVC_MAX_PB_SIZE * 2 - 8) 1: ld1 {v0.8b}, [x1], x2 ushll v4.8h, v0.8b, #6 st1 {v4.d}[0], [x0], #8 @@ -152,8 +163,13 @@ function ff_hevc_put_hevc_pel_pixels6_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_pixels8_8_neon, export=1 + mov x7, #(VVC_MAX_PB_SIZE * 2) + b 1f +endfunc + function ff_hevc_put_hevc_pel_pixels8_8_neon, export=1 - mov x7, #(MAX_PB_SIZE * 2) + mov x7, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.8b}, [x1], x2 ushll v4.8h, v0.8b, #6 subs w3, w3, #1 @@ -163,7 +179,7 @@ function ff_hevc_put_hevc_pel_pixels8_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_pixels12_8_neon, export=1 - mov x7, #(MAX_PB_SIZE * 2 - 16) + mov x7, #(HEVC_MAX_PB_SIZE * 2 - 16) 1: ld1 {v0.8b, v1.8b}, [x1], x2 ushll v4.8h, v0.8b, #6 st1 {v4.8h}, [x0], #16 @@ -174,8 +190,13 @@ function ff_hevc_put_hevc_pel_pixels12_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_pixels16_8_neon, export=1 + mov x7, #(VVC_MAX_PB_SIZE * 2) + b 1f +endfunc + function ff_hevc_put_hevc_pel_pixels16_8_neon, export=1 - mov x7, #(MAX_PB_SIZE * 2) + mov x7, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.8b, v1.8b}, [x1], x2 ushll v4.8h, v0.8b, #6 ushll v5.8h, v1.8b, #6 @@ -186,7 +207,7 @@ function ff_hevc_put_hevc_pel_pixels16_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_pixels24_8_neon, export=1 - mov x7, #(MAX_PB_SIZE * 2) + mov x7, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.8b-v2.8b}, [x1], x2 ushll v4.8h, v0.8b, #6 ushll v5.8h, v1.8b, #6 @@ -197,8 +218,13 @@ function ff_hevc_put_hevc_pel_pixels24_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_pixels32_8_neon, export=1 + mov x7, #(VVC_MAX_PB_SIZE * 2) + b 1f +endfunc + function ff_hevc_put_hevc_pel_pixels32_8_neon, export=1 - mov x7, #(MAX_PB_SIZE * 2) + mov x7, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.8b-v3.8b}, [x1], x2 ushll v4.8h, v0.8b, #6 ushll v5.8h, v1.8b, #6 @@ -211,7 +237,7 @@ function ff_hevc_put_hevc_pel_pixels32_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_pixels48_8_neon, export=1 - mov x7, #(MAX_PB_SIZE) + mov x7, #(HEVC_MAX_PB_SIZE) 1: ld1 {v0.16b-v2.16b}, [x1], x2 ushll v4.8h, v0.8b, #6 ushll2 v5.8h, v0.16b, #6 @@ -226,26 +252,50 @@ function ff_hevc_put_hevc_pel_pixels48_8_neon, export=1 ret endfunc -function ff_hevc_put_hevc_pel_pixels64_8_neon, export=1 -1: ld1 {v0.16b-v3.16b}, [x1], x2 +.macro put_pel_pixels64_8_neon ushll v4.8h, v0.8b, #6 ushll2 v5.8h, v0.16b, #6 ushll v6.8h, v1.8b, #6 ushll2 v7.8h, v1.16b, #6 - st1 {v4.8h-v7.8h}, [x0], #(MAX_PB_SIZE) + st1 {v4.8h-v7.8h}, [x0], #64 ushll v16.8h, v2.8b, #6 ushll2 v17.8h, v2.16b, #6 ushll v18.8h, v3.8b, #6 ushll2 v19.8h, v3.16b, #6 + st1 {v16.8h-v19.8h}, [x0], x7 +.endm + +function ff_vvc_put_pel_pixels64_8_neon, export=1 + mov x7, #(2 * VVC_MAX_PB_SIZE - 64) + b 1f +endfunc + +function ff_hevc_put_hevc_pel_pixels64_8_neon, export=1 + mov x7, #(HEVC_MAX_PB_SIZE) +1: + ld1 {v0.16b-v3.16b}, [x1], x2 subs w3, w3, #1 - st1 {v16.8h-v19.8h}, [x0], #(MAX_PB_SIZE) + put_pel_pixels64_8_neon b.ne 1b ret endfunc +function ff_vvc_put_pel_pixels128_8_neon, export=1 + mov x7, #64 +1: + mov x6, x1 + ld1 {v0.16b-v3.16b}, [x6], #64 + add x1, x1, x2 + subs w3, w3, #1 + put_pel_pixels64_8_neon + ld1 {v0.16b-v3.16b}, [x6], #64 + put_pel_pixels64_8_neon + b.ne 1b + ret +endfunc function ff_hevc_put_hevc_pel_bi_pixels4_8_neon, export=1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.s}[0], [x2], x3 // src ushll v16.8h, v0.8b, #6 ld1 {v20.4h}, [x4], x10 // src2 @@ -258,7 +308,7 @@ function ff_hevc_put_hevc_pel_bi_pixels4_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_bi_pixels6_8_neon, export=1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) sub x1, x1, #4 1: ld1 {v0.8b}, [x2], x3 ushll v16.8h, v0.8b, #6 @@ -273,7 +323,7 @@ function ff_hevc_put_hevc_pel_bi_pixels6_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_bi_pixels8_8_neon, export=1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.8b}, [x2], x3 // src ushll v16.8h, v0.8b, #6 ld1 {v20.8h}, [x4], x10 // src2 @@ -286,7 +336,7 @@ function ff_hevc_put_hevc_pel_bi_pixels8_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_bi_pixels12_8_neon, export=1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) sub x1, x1, #8 1: ld1 {v0.16b}, [x2], x3 ushll v16.8h, v0.8b, #6 @@ -304,7 +354,7 @@ function ff_hevc_put_hevc_pel_bi_pixels12_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_bi_pixels16_8_neon, export=1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.16b}, [x2], x3 // src ushll v16.8h, v0.8b, #6 ushll2 v17.8h, v0.16b, #6 @@ -320,7 +370,7 @@ function ff_hevc_put_hevc_pel_bi_pixels16_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_bi_pixels24_8_neon, export=1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.8b-v2.8b}, [x2], x3 // src ushll v16.8h, v0.8b, #6 ushll v17.8h, v1.8b, #6 @@ -339,7 +389,7 @@ function ff_hevc_put_hevc_pel_bi_pixels24_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_bi_pixels32_8_neon, export=1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v0.16b-v1.16b}, [x2], x3 // src ushll v16.8h, v0.8b, #6 ushll2 v17.8h, v0.16b, #6 @@ -361,7 +411,7 @@ function ff_hevc_put_hevc_pel_bi_pixels32_8_neon, export=1 endfunc function ff_hevc_put_hevc_pel_bi_pixels48_8_neon, export=1 - mov x10, #(MAX_PB_SIZE) + mov x10, #(HEVC_MAX_PB_SIZE) 1: ld1 {v0.16b-v2.16b}, [x2], x3 // src ushll v16.8h, v0.8b, #6 ushll2 v17.8h, v0.16b, #6 @@ -369,7 +419,7 @@ function ff_hevc_put_hevc_pel_bi_pixels48_8_neon, export=1 ushll2 v19.8h, v1.16b, #6 ushll v20.8h, v2.8b, #6 ushll2 v21.8h, v2.16b, #6 - ld1 {v24.8h-v27.8h}, [x4], #(MAX_PB_SIZE) // src2 + ld1 {v24.8h-v27.8h}, [x4], #(HEVC_MAX_PB_SIZE) // src2 sqadd v16.8h, v16.8h, v24.8h sqadd v17.8h, v17.8h, v25.8h sqadd v18.8h, v18.8h, v26.8h @@ -399,12 +449,12 @@ function ff_hevc_put_hevc_pel_bi_pixels64_8_neon, export=1 ushll2 v21.8h, v2.16b, #6 ushll v22.8h, v3.8b, #6 ushll2 v23.8h, v3.16b, #6 - ld1 {v24.8h, v25.8h, v26.8h, v27.8h}, [x4], #(MAX_PB_SIZE) // src2 + ld1 {v24.8h, v25.8h, v26.8h, v27.8h}, [x4], #(HEVC_MAX_PB_SIZE) // src2 sqadd v16.8h, v16.8h, v24.8h sqadd v17.8h, v17.8h, v25.8h sqadd v18.8h, v18.8h, v26.8h sqadd v19.8h, v19.8h, v27.8h - ld1 {v24.8h, v25.8h, v26.8h, v27.8h}, [x4], #(MAX_PB_SIZE) + ld1 {v24.8h, v25.8h, v26.8h, v27.8h}, [x4], #(HEVC_MAX_PB_SIZE) sqadd v20.8h, v20.8h, v24.8h sqadd v21.8h, v21.8h, v25.8h sqadd v22.8h, v22.8h, v26.8h @@ -427,7 +477,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_h4_8_neon, export=1 load_epel_filterb x6, x7 sub x2, x2, #1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v4.8b}, [x2], x3 ext v5.8b, v4.8b, v4.8b, #1 ext v6.8b, v4.8b, v4.8b, #2 @@ -446,7 +496,7 @@ function ff_hevc_put_hevc_epel_bi_h6_8_neon, export=1 load_epel_filterb x6, x7 sub w1, w1, #4 sub x2, x2, #1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v24.16b}, [x2], x3 ext v26.16b, v24.16b, v24.16b, #1 ext v27.16b, v24.16b, v24.16b, #2 @@ -465,7 +515,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_h8_8_neon, export=1 load_epel_filterb x6, x7 sub x2, x2, #1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v24.16b}, [x2], x3 ext v26.16b, v24.16b, v24.16b, #1 ext v27.16b, v24.16b, v24.16b, #2 @@ -484,7 +534,7 @@ function ff_hevc_put_hevc_epel_bi_h12_8_neon, export=1 load_epel_filterb x6, x7 sub x1, x1, #8 sub x2, x2, #1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v24.16b}, [x2], x3 ext v26.16b, v24.16b, v24.16b, #1 ext v27.16b, v24.16b, v24.16b, #2 @@ -506,7 +556,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_h16_8_neon, export=1 load_epel_filterb x6, x7 sub x2, x2, #1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ldr q24, [x2] ldr s25, [x2, #16] add x2, x2, x3 @@ -529,7 +579,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_h24_8_neon, export=1 load_epel_filterb x6, x7 sub x2, x2, #1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ld1 {v24.16b, v25.16b}, [x2], x3 ext v26.16b, v24.16b, v25.16b, #1 ext v27.16b, v24.16b, v25.16b, #2 @@ -556,7 +606,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_h32_8_neon, export=1 load_epel_filterb x6, x7 sub x2, x2, #1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) 1: ldp q24, q25, [x2] ldr s26, [x2, #32] add x2, x2, x3 @@ -589,7 +639,7 @@ function ff_hevc_put_hevc_epel_bi_h48_8_neon, export=1 load_epel_filterb x6, x7 sub x2, x2, #1 mov x7, #24 - mov x10, #(MAX_PB_SIZE * 2 - 48) + mov x10, #(HEVC_MAX_PB_SIZE * 2 - 48) 1: ld1 {v24.16b, v25.16b, v26.16b}, [x2] ldr s27, [x2, #48] add x2, x2, x3 @@ -683,7 +733,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_v4_8_neon, export=1 load_epel_filterb x7, x6 sub x2, x2, x3 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.s}[0], [x2], x3 ld1 {v17.s}[0], [x2], x3 ld1 {v18.s}[0], [x2], x3 @@ -705,7 +755,7 @@ function ff_hevc_put_hevc_epel_bi_v6_8_neon, export=1 load_epel_filterb x7, x6 sub x2, x2, x3 sub x1, x1, #4 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8b}, [x2], x3 ld1 {v17.8b}, [x2], x3 ld1 {v18.8b}, [x2], x3 @@ -727,7 +777,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_v8_8_neon, export=1 load_epel_filterb x7, x6 sub x2, x2, x3 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8b}, [x2], x3 ld1 {v17.8b}, [x2], x3 ld1 {v18.8b}, [x2], x3 @@ -749,7 +799,7 @@ function ff_hevc_put_hevc_epel_bi_v12_8_neon, export=1 load_epel_filterb x7, x6 sub x1, x1, #8 sub x2, x2, x3 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.16b}, [x2], x3 ld1 {v17.16b}, [x2], x3 ld1 {v18.16b}, [x2], x3 @@ -774,7 +824,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_v16_8_neon, export=1 load_epel_filterb x7, x6 sub x2, x2, x3 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.16b}, [x2], x3 ld1 {v17.16b}, [x2], x3 ld1 {v18.16b}, [x2], x3 @@ -798,7 +848,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_v24_8_neon, export=1 load_epel_filterb x7, x6 sub x2, x2, x3 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8b, v17.8b, v18.8b}, [x2], x3 ld1 {v19.8b, v20.8b, v21.8b}, [x2], x3 ld1 {v22.8b, v23.8b, v24.8b}, [x2], x3 @@ -825,7 +875,7 @@ endfunc function ff_hevc_put_hevc_epel_bi_v32_8_neon, export=1 load_epel_filterb x7, x6 sub x2, x2, x3 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.16b, v17.16b}, [x2], x3 ld1 {v18.16b, v19.16b}, [x2], x3 ld1 {v20.16b, v21.16b}, [x2], x3 @@ -895,7 +945,7 @@ endfunc function ff_hevc_put_hevc_epel_v4_8_neon, export=1 load_epel_filterb x5, x4 sub x1, x1, x2 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ldr s16, [x1] ldr s17, [x1, x2] add x1, x1, x2, lsl #1 @@ -915,7 +965,7 @@ endfunc function ff_hevc_put_hevc_epel_v6_8_neon, export=1 load_epel_filterb x5, x4 sub x1, x1, x2 - mov x10, #(MAX_PB_SIZE * 2 - 8) + mov x10, #(HEVC_MAX_PB_SIZE * 2 - 8) ldr d16, [x1] ldr d17, [x1, x2] add x1, x1, x2, lsl #1 @@ -936,7 +986,7 @@ endfunc function ff_hevc_put_hevc_epel_v8_8_neon, export=1 load_epel_filterb x5, x4 sub x1, x1, x2 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ldr d16, [x1] ldr d17, [x1, x2] add x1, x1, x2, lsl #1 @@ -956,7 +1006,7 @@ endfunc function ff_hevc_put_hevc_epel_v12_8_neon, export=1 load_epel_filterb x5, x4 sub x1, x1, x2 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ldr q16, [x1] ldr q17, [x1, x2] add x1, x1, x2, lsl #1 @@ -980,7 +1030,7 @@ endfunc function ff_hevc_put_hevc_epel_v16_8_neon, export=1 load_epel_filterb x5, x4 sub x1, x1, x2 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ldr q16, [x1] ldr q17, [x1, x2] add x1, x1, x2, lsl #1 @@ -1002,7 +1052,7 @@ endfunc function ff_hevc_put_hevc_epel_v24_8_neon, export=1 load_epel_filterb x5, x4 sub x1, x1, x2 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8b, v17.8b, v18.8b}, [x1], x2 ld1 {v19.8b, v20.8b, v21.8b}, [x1], x2 ld1 {v22.8b, v23.8b, v24.8b}, [x1], x2 @@ -1025,7 +1075,7 @@ endfunc function ff_hevc_put_hevc_epel_v32_8_neon, export=1 load_epel_filterb x5, x4 sub x1, x1, x2 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.16b, v17.16b}, [x1], x2 ld1 {v18.16b, v19.16b}, [x1], x2 ld1 {v20.16b, v21.16b}, [x1], x2 @@ -1327,9 +1377,21 @@ endfunc add x5, x5, x4, lsl #2 ld1r {v30.4s}, [x5] sub x1, x1, #1 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) .endm +.macro VVC_EPEL_H_HEADER + ld1r {v30.4s}, [x4] + sub x1, x1, #1 + mov x10, #(VVC_MAX_PB_SIZE * 2) +.endm + +function ff_vvc_put_epel_h4_8_neon, export=1 + VVC_EPEL_H_HEADER + sxtl v0.8h, v30.8b + b 1f +endfunc + function ff_hevc_put_hevc_epel_h4_8_neon, export=1 EPEL_H_HEADER sxtl v0.8h, v30.8b @@ -1369,6 +1431,12 @@ function ff_hevc_put_hevc_epel_h6_8_neon, export=1 ret endfunc +function ff_vvc_put_epel_h8_8_neon, export=1 + VVC_EPEL_H_HEADER + sxtl v0.8h, v30.8b + b 1f +endfunc + function ff_hevc_put_hevc_epel_h8_8_neon, export=1 EPEL_H_HEADER sxtl v0.8h, v30.8b @@ -1416,6 +1484,12 @@ function ff_hevc_put_hevc_epel_h12_8_neon, export=1 ret endfunc +function ff_vvc_put_epel_h16_8_neon, export=1 + VVC_EPEL_H_HEADER + sxtl v0.8h, v30.8b + b 1f +endfunc + function ff_hevc_put_hevc_epel_h16_8_neon, export=1 EPEL_H_HEADER sxtl v0.8h, v30.8b @@ -1478,8 +1552,14 @@ function ff_hevc_put_hevc_epel_h24_8_neon, export=1 ret endfunc +function ff_vvc_put_epel_h32_8_neon, export=1 + VVC_EPEL_H_HEADER + b 0f +endfunc + function ff_hevc_put_hevc_epel_h32_8_neon, export=1 EPEL_H_HEADER +0: ld1 {v1.8b}, [x1], #8 sub x2, x2, w6, uxtw // decrement src stride mov w7, w6 // original width @@ -1835,6 +1915,12 @@ endfunc #if HAVE_I8MM ENABLE_I8MM + +function ff_vvc_put_epel_h4_8_neon_i8mm, export=1 + VVC_EPEL_H_HEADER + b 1f +endfunc + function ff_hevc_put_hevc_epel_h4_8_neon_i8mm, export=1 EPEL_H_HEADER 1: ld1 {v4.8b}, [x1], x2 @@ -1878,6 +1964,11 @@ function ff_hevc_put_hevc_epel_h6_8_neon_i8mm, export=1 ret endfunc +function ff_vvc_put_epel_h8_8_neon_i8mm, export=1 + VVC_EPEL_H_HEADER + b 1f +endfunc + function ff_hevc_put_hevc_epel_h8_8_neon_i8mm, export=1 EPEL_H_HEADER 1: ld1 {v4.16b}, [x1], x2 @@ -1928,6 +2019,11 @@ function ff_hevc_put_hevc_epel_h12_8_neon_i8mm, export=1 ret endfunc +function ff_vvc_put_epel_h16_8_neon_i8mm, export=1 + VVC_EPEL_H_HEADER + b 1f +endfunc + function ff_hevc_put_hevc_epel_h16_8_neon_i8mm, export=1 EPEL_H_HEADER 1: ld1 {v0.16b, v1.16b}, [x1], x2 @@ -2002,6 +2098,11 @@ function ff_hevc_put_hevc_epel_h24_8_neon_i8mm, export=1 ret endfunc +function ff_vvc_put_epel_h32_8_neon_i8mm, export=1 + VVC_EPEL_H_HEADER + b 1f +endfunc + function ff_hevc_put_hevc_epel_h32_8_neon_i8mm, export=1 EPEL_H_HEADER 1: ld1 {v0.16b, v1.16b, v2.16b}, [x1], x2 @@ -2101,11 +2202,8 @@ function ff_hevc_put_hevc_epel_h48_8_neon_i8mm, export=1 ret endfunc -function ff_hevc_put_hevc_epel_h64_8_neon_i8mm, export=1 - EPEL_H_HEADER - sub x2, x2, #64 -1: ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x1], #64 - subs w3, w3, #1 // height +.macro put_epel_h64_8_neon_i8mm + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x1], #64 ext v4.16b, v0.16b, v1.16b, #1 ext v5.16b, v0.16b, v1.16b, #2 ext v6.16b, v0.16b, v1.16b, #3 @@ -2168,7 +2266,37 @@ function ff_hevc_put_hevc_epel_h64_8_neon_i8mm, export=1 xtn2 v22.8h, v26.4s xtn v23.4h, v23.4s xtn2 v23.8h, v27.4s - st4 {v20.8h, v21.8h, v22.8h, v23.8h}, [x0], #64 + st4 {v20.8h, v21.8h, v22.8h, v23.8h}, [x0], x10 +.endm + +function ff_vvc_put_epel_h64_8_neon_i8mm, export=1 + VVC_EPEL_H_HEADER + mov x10, #(VVC_MAX_PB_SIZE * 2 - 64) + sub x2, x2, #64 + b 1f +endfunc + +function ff_hevc_put_hevc_epel_h64_8_neon_i8mm, export=1 + EPEL_H_HEADER + mov x10, #64 + sub x2, x2, #64 +1: + subs w3, w3, #1 // height + put_epel_h64_8_neon_i8mm + b.ne 1b + ret +endfunc + +function ff_vvc_put_epel_h128_8_neon_i8mm, export=1 + VVC_EPEL_H_HEADER + sub x11, x2, #128 + mov x10, #64 + mov x2, #0 +1: + put_epel_h64_8_neon_i8mm + subs w3, w3, #1 + put_epel_h64_8_neon_i8mm + add x1, x1, x11 b.ne 1b ret endfunc @@ -2176,10 +2304,16 @@ endfunc DISABLE_I8MM #endif +function vvc_put_epel_hv4_8_end_neon + vvc_load_epel_filterh x5 + mov x10, #(VVC_MAX_PB_SIZE * 2) + b 0f +endfunc function hevc_put_hevc_epel_hv4_8_end_neon load_epel_filterh x5, x4 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) +0: ldr d16, [sp] ldr d17, [sp, x10] add sp, sp, x10, lsl #1 @@ -2198,7 +2332,7 @@ endfunc function hevc_put_hevc_epel_hv6_8_end_neon load_epel_filterh x5, x4 mov x5, #120 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ldr q16, [sp] ldr q17, [sp, x10] add sp, sp, x10, lsl #1 @@ -2216,9 +2350,16 @@ function hevc_put_hevc_epel_hv6_8_end_neon 2: ret endfunc +function vvc_put_epel_hv8_8_end_neon + vvc_load_epel_filterh x5 + mov x10, #(VVC_MAX_PB_SIZE * 2) + b 0f +endfunc + function hevc_put_hevc_epel_hv8_8_end_neon load_epel_filterh x5, x4 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) +0: ldr q16, [sp] ldr q17, [sp, x10] add sp, sp, x10, lsl #1 @@ -2238,7 +2379,7 @@ endfunc function hevc_put_hevc_epel_hv12_8_end_neon load_epel_filterh x5, x4 mov x5, #112 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h}, [sp], x10 ld1 {v18.8h, v19.8h}, [sp], x10 ld1 {v20.8h, v21.8h}, [sp], x10 @@ -2256,9 +2397,16 @@ function hevc_put_hevc_epel_hv12_8_end_neon 2: ret endfunc +function vvc_put_epel_hv16_8_end_neon + vvc_load_epel_filterh x5 + mov x10, #(VVC_MAX_PB_SIZE * 2) + b 0f +endfunc + function hevc_put_hevc_epel_hv16_8_end_neon load_epel_filterh x5, x4 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) +0: ld1 {v16.8h, v17.8h}, [sp], x10 ld1 {v18.8h, v19.8h}, [sp], x10 ld1 {v20.8h, v21.8h}, [sp], x10 @@ -2278,7 +2426,7 @@ endfunc function hevc_put_hevc_epel_hv24_8_end_neon load_epel_filterh x5, x4 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h, v18.8h}, [sp], x10 ld1 {v19.8h, v20.8h, v21.8h}, [sp], x10 ld1 {v22.8h, v23.8h, v24.8h}, [sp], x10 @@ -2314,6 +2462,21 @@ function ff_hevc_put_hevc_epel_hv4_8_\suffix, export=1 b hevc_put_hevc_epel_hv4_8_end_neon endfunc +function ff_vvc_put_epel_hv4_8_\suffix, export=1 + add w10, w3, #3 + lsl x10, x10, #8 + sub sp, sp, x10 // tmp_array + stp x5, x30, [sp, #-32]! + stp x0, x3, [sp, #16] + add x0, sp, #32 + sub x1, x1, x2 + add w3, w3, #3 + bl X(ff_vvc_put_epel_h4_8_\suffix) + ldp x0, x3, [sp, #16] + ldp x5, x30, [sp], #32 + b vvc_put_epel_hv4_8_end_neon +endfunc + function ff_hevc_put_hevc_epel_hv6_8_\suffix, export=1 add w10, w3, #3 lsl x10, x10, #7 @@ -2344,6 +2507,21 @@ function ff_hevc_put_hevc_epel_hv8_8_\suffix, export=1 b hevc_put_hevc_epel_hv8_8_end_neon endfunc +function ff_vvc_put_epel_hv8_8_\suffix, export=1 + add w10, w3, #3 + lsl x10, x10, #8 + sub sp, sp, x10 // tmp_array + stp x5, x30, [sp, #-32]! + stp x0, x3, [sp, #16] + add x0, sp, #32 + sub x1, x1, x2 + add w3, w3, #3 + bl X(ff_vvc_put_epel_h8_8_\suffix) + ldp x0, x3, [sp, #16] + ldp x5, x30, [sp], #32 + b vvc_put_epel_hv8_8_end_neon +endfunc + function ff_hevc_put_hevc_epel_hv12_8_\suffix, export=1 add w10, w3, #3 lsl x10, x10, #7 @@ -2374,6 +2552,21 @@ function ff_hevc_put_hevc_epel_hv16_8_\suffix, export=1 b hevc_put_hevc_epel_hv16_8_end_neon endfunc +function ff_vvc_put_epel_hv16_8_\suffix, export=1 + add w10, w3, #3 + lsl x10, x10, #8 + sub sp, sp, x10 // tmp_array + stp x5, x30, [sp, #-32]! + stp x0, x3, [sp, #16] + add x0, sp, #32 + sub x1, x1, x2 + add w3, w3, #3 + bl X(ff_vvc_put_epel_h16_8_\suffix) + ldp x0, x3, [sp, #16] + ldp x5, x30, [sp], #32 + b vvc_put_epel_hv16_8_end_neon +endfunc + function ff_hevc_put_hevc_epel_hv24_8_\suffix, export=1 add w10, w3, #3 lsl x10, x10, #7 @@ -2407,6 +2600,24 @@ function ff_hevc_put_hevc_epel_hv32_8_\suffix, export=1 ret endfunc +function ff_vvc_put_epel_hv32_8_\suffix, export=1 + stp x4, x5, [sp, #-64]! + stp x2, x3, [sp, #16] + stp x0, x1, [sp, #32] + str x30, [sp, #48] + mov x6, #16 + bl X(ff_vvc_put_epel_hv16_8_\suffix) + ldp x0, x1, [sp, #32] + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp], #48 + add x0, x0, #32 + add x1, x1, #16 + mov x6, #16 + bl X(ff_vvc_put_epel_hv16_8_\suffix) + ldr x30, [sp], #16 + ret +endfunc + function ff_hevc_put_hevc_epel_hv48_8_\suffix, export=1 stp x4, x5, [sp, #-64]! stp x2, x3, [sp, #16] @@ -2456,13 +2667,50 @@ function ff_hevc_put_hevc_epel_hv64_8_\suffix, export=1 ldr x30, [sp], #16 ret endfunc + +function ff_vvc_put_epel_hv64_8_\suffix, export=1 + stp x4, x5, [sp, #-64]! + stp x2, x3, [sp, #16] + stp x0, x1, [sp, #32] + str x30, [sp, #48] + mov x6, #32 + bl X(ff_vvc_put_epel_hv32_8_\suffix) + ldp x0, x1, [sp, #32] + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp], #48 + add x0, x0, #64 + add x1, x1, #32 + mov x6, #32 + bl X(ff_vvc_put_epel_hv32_8_\suffix) + ldr x30, [sp], #16 + ret +endfunc + +function ff_vvc_put_epel_hv128_8_\suffix, export=1 + stp x4, x5, [sp, #-64]! + stp x2, x3, [sp, #16] + stp x0, x1, [sp, #32] + str x30, [sp, #48] + mov x6, #64 + bl X(ff_vvc_put_epel_hv64_8_\suffix) + ldp x0, x1, [sp, #32] + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp], #48 + add x0, x0, #128 + add x1, x1, #64 + mov x6, #64 + bl X(ff_vvc_put_epel_hv64_8_\suffix) + ldr x30, [sp], #16 + ret +endfunc + .endm epel_hv neon function hevc_put_hevc_epel_uni_hv4_8_end_neon load_epel_filterh x6, x5 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.4h}, [sp], x10 ld1 {v17.4h}, [sp], x10 ld1 {v18.4h}, [sp], x10 @@ -2481,7 +2729,7 @@ endfunc function hevc_put_hevc_epel_uni_hv6_8_end_neon load_epel_filterh x6, x5 sub x1, x1, #4 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h}, [sp], x10 ld1 {v17.8h}, [sp], x10 ld1 {v18.8h}, [sp], x10 @@ -2501,7 +2749,7 @@ endfunc function hevc_put_hevc_epel_uni_hv8_8_end_neon load_epel_filterh x6, x5 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h}, [sp], x10 ld1 {v17.8h}, [sp], x10 ld1 {v18.8h}, [sp], x10 @@ -2521,7 +2769,7 @@ endfunc function hevc_put_hevc_epel_uni_hv12_8_end_neon load_epel_filterh x6, x5 sub x1, x1, #8 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h}, [sp], x10 ld1 {v18.8h, v19.8h}, [sp], x10 ld1 {v20.8h, v21.8h}, [sp], x10 @@ -2543,7 +2791,7 @@ endfunc function hevc_put_hevc_epel_uni_hv16_8_end_neon load_epel_filterh x6, x5 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h}, [sp], x10 ld1 {v18.8h, v19.8h}, [sp], x10 ld1 {v20.8h, v21.8h}, [sp], x10 @@ -2565,7 +2813,7 @@ endfunc function hevc_put_hevc_epel_uni_hv24_8_end_neon load_epel_filterh x6, x5 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h, v18.8h}, [sp], x10 ld1 {v19.8h, v20.8h, v21.8h}, [sp], x10 ld1 {v22.8h, v23.8h, v24.8h}, [sp], x10 @@ -3223,7 +3471,7 @@ DISABLE_I8MM function hevc_put_hevc_epel_uni_w_hv4_8_end_neon load_epel_filterh x6, x5 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.4h}, [sp], x10 ld1 {v17.4h}, [sp], x10 ld1 {v18.4h}, [sp], x10 @@ -3273,7 +3521,7 @@ endfunc function hevc_put_hevc_epel_uni_w_hv6_8_end_neon load_epel_filterh x6, x5 sub x1, x1, #4 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h}, [sp], x10 ld1 {v17.8h}, [sp], x10 ld1 {v18.8h}, [sp], x10 @@ -3326,7 +3574,7 @@ endfunc function hevc_put_hevc_epel_uni_w_hv8_8_end_neon load_epel_filterh x6, x5 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h}, [sp], x10 ld1 {v17.8h}, [sp], x10 ld1 {v18.8h}, [sp], x10 @@ -3376,7 +3624,7 @@ endfunc function hevc_put_hevc_epel_uni_w_hv12_8_end_neon load_epel_filterh x6, x5 sub x1, x1, #8 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h}, [sp], x10 ld1 {v18.8h, v19.8h}, [sp], x10 ld1 {v20.8h, v21.8h}, [sp], x10 @@ -3437,7 +3685,7 @@ endfunc function hevc_put_hevc_epel_uni_w_hv16_8_end_neon load_epel_filterh x6, x5 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h}, [sp], x10 ld1 {v18.8h, v19.8h}, [sp], x10 ld1 {v20.8h, v21.8h}, [sp], x10 @@ -3498,7 +3746,7 @@ endfunc function hevc_put_hevc_epel_uni_w_hv24_8_end_neon load_epel_filterh x6, x5 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h, v18.8h}, [sp], x10 ld1 {v19.8h, v20.8h, v21.8h}, [sp], x10 ld1 {v22.8h, v23.8h, v24.8h}, [sp], x10 @@ -3795,7 +4043,7 @@ epel_uni_w_hv neon function hevc_put_hevc_epel_bi_hv4_8_end_neon load_epel_filterh x7, x6 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.4h}, [sp], x10 ld1 {v17.4h}, [sp], x10 ld1 {v18.4h}, [sp], x10 @@ -3816,7 +4064,7 @@ endfunc function hevc_put_hevc_epel_bi_hv6_8_end_neon load_epel_filterh x7, x6 sub x1, x1, #4 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h}, [sp], x10 ld1 {v17.8h}, [sp], x10 ld1 {v18.8h}, [sp], x10 @@ -3838,7 +4086,7 @@ endfunc function hevc_put_hevc_epel_bi_hv8_8_end_neon load_epel_filterh x7, x6 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h}, [sp], x10 ld1 {v17.8h}, [sp], x10 ld1 {v18.8h}, [sp], x10 @@ -3860,7 +4108,7 @@ endfunc function hevc_put_hevc_epel_bi_hv12_8_end_neon load_epel_filterh x7, x6 sub x1, x1, #8 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h}, [sp], x10 ld1 {v18.8h, v19.8h}, [sp], x10 ld1 {v20.8h, v21.8h}, [sp], x10 @@ -3885,7 +4133,7 @@ endfunc function hevc_put_hevc_epel_bi_hv16_8_end_neon load_epel_filterh x7, x6 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h}, [sp], x10 ld1 {v18.8h, v19.8h}, [sp], x10 ld1 {v20.8h, v21.8h}, [sp], x10 @@ -3910,7 +4158,7 @@ endfunc function hevc_put_hevc_epel_bi_hv24_8_end_neon load_epel_filterh x7, x6 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h, v18.8h}, [sp], x10 ld1 {v19.8h, v20.8h, v21.8h}, [sp], x10 ld1 {v22.8h, v23.8h, v24.8h}, [sp], x10 @@ -3939,7 +4187,7 @@ endfunc function hevc_put_hevc_epel_bi_hv32_8_end_neon load_epel_filterh x7, x6 - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8h, v17.8h, v18.8h, v19.8h}, [sp], x10 ld1 {v20.8h, v21.8h, v22.8h, v23.8h}, [sp], x10 ld1 {v24.8h, v25.8h, v26.8h, v27.8h}, [sp], x10 diff --git a/libavcodec/aarch64/hevcdsp_qpel_neon.S b/libavcodec/aarch64/h26x/qpel_neon.S similarity index 91% rename from libavcodec/aarch64/hevcdsp_qpel_neon.S rename to libavcodec/aarch64/h26x/qpel_neon.S index 8ddaa32b7..5c3f0263b 100644 --- a/libavcodec/aarch64/hevcdsp_qpel_neon.S +++ b/libavcodec/aarch64/h26x/qpel_neon.S @@ -21,7 +21,8 @@ */ #include "libavutil/aarch64/asm.S" -#define MAX_PB_SIZE 64 +#define HEVC_MAX_PB_SIZE 64 +#define VVC_MAX_PB_SIZE 128 const qpel_filters, align=4 .byte 0, 0, 0, 0, 0, 0, 0, 0 @@ -44,6 +45,11 @@ endconst sxtl v0.8h, v0.8b .endm +.macro vvc_load_filter m + ld1 {v0.8b}, [\m] + sxtl v0.8h, v0.8b +.endm + .macro load_qpel_filterb freg, xreg movrel \xreg, qpel_filters_abs add \xreg, \xreg, \freg, lsl #3 @@ -80,6 +86,11 @@ endconst sxtl v0.8h, v0.8b .endm +.macro vvc_load_qpel_filterh freg + ld1 {v0.8b}, [\freg] + sxtl v0.8h, v0.8b +.endm + .macro calc_qpelh dst, src0, src1, src2, src3, src4, src5, src6, src7, op, shift=6 smull \dst\().4s, \src0\().4h, v0.h[0] smlal \dst\().4s, \src1\().4h, v0.h[1] @@ -89,11 +100,15 @@ endconst smlal \dst\().4s, \src5\().4h, v0.h[5] smlal \dst\().4s, \src6\().4h, v0.h[6] smlal \dst\().4s, \src7\().4h, v0.h[7] +.ifc \op, sqxtn + sqxtn \dst\().4h, \dst\().4s +.else .ifc \op, sshr sshr \dst\().4s, \dst\().4s, \shift .else \op \dst\().4h, \dst\().4s, \shift .endif +.endif .endm .macro calc_qpelh2 dst, dstt, src0, src1, src2, src3, src4, src5, src6, src7, op, shift=6 @@ -105,11 +120,15 @@ endconst smlal2 \dstt\().4s, \src5\().8h, v0.h[5] smlal2 \dstt\().4s, \src6\().8h, v0.h[6] smlal2 \dstt\().4s, \src7\().8h, v0.h[7] +.ifc \op, sqxtn2 + sqxtn2 \dst\().8h, \dstt\().4s +.else .ifc \op, sshr sshr \dst\().4s, \dstt\().4s, \shift .else \op \dst\().8h, \dstt\().4s, \shift .endif +.endif .endm .macro calc_all @@ -212,22 +231,40 @@ function ff_hevc_put_hevc_h4_8_neon, export=0 endfunc .endif -function ff_hevc_put_hevc_\type\()_h4_8_neon, export=1 - load_filter mx -.ifc \type, qpel_bi - mov x16, #(MAX_PB_SIZE << 2) // src2bstridel - add x15, x4, #(MAX_PB_SIZE << 1) // src2b -.endif +.ifnc \type, qpel_bi +function ff_vvc_put_\type\()_h4_8_neon, export=1 + vvc_load_filter mx sub src, src, #3 mov mx, x30 .ifc \type, qpel - mov dststride, #(MAX_PB_SIZE << 1) + mov dststride, #(VVC_MAX_PB_SIZE << 1) lsl x13, srcstride, #1 // srcstridel - mov x14, #(MAX_PB_SIZE << 2) + mov x14, #(VVC_MAX_PB_SIZE << 2) .else lsl x14, dststride, #1 // dststridel lsl x13, srcstride, #1 // srcstridel .endif + b 1f +endfunc +.endif // !qpel_bi + +function ff_hevc_put_hevc_\type\()_h4_8_neon, export=1 + load_filter mx +.ifc \type, qpel_bi + mov x16, #(HEVC_MAX_PB_SIZE << 2) // src2bstridel + add x15, x4, #(HEVC_MAX_PB_SIZE << 1) // src2b +.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 +1: add x10, dst, dststride // dstb add x12, src, srcstride // srcb 0: ld1 {v16.8b, v17.8b}, [src], x13 @@ -283,15 +320,15 @@ endfunc function ff_hevc_put_hevc_\type\()_h6_8_neon, export=1 load_filter mx .ifc \type, qpel_bi - mov x16, #(MAX_PB_SIZE << 2) // src2bstridel - add x15, x4, #(MAX_PB_SIZE << 1) // src2b + mov x16, #(HEVC_MAX_PB_SIZE << 2) // src2bstridel + add x15, x4, #(HEVC_MAX_PB_SIZE << 1) // src2b .endif sub src, src, #3 mov mx, x30 .ifc \type, qpel - mov dststride, #(MAX_PB_SIZE << 1) + mov dststride, #(HEVC_MAX_PB_SIZE << 1) lsl x13, srcstride, #1 // srcstridel - mov x14, #((MAX_PB_SIZE << 2) - 8) + mov x14, #((HEVC_MAX_PB_SIZE << 2) - 8) .else lsl x14, dststride, #1 // dststridel lsl x13, srcstride, #1 // srcstridel @@ -333,22 +370,40 @@ function ff_hevc_put_hevc_\type\()_h6_8_neon, export=1 ret mx endfunc -function ff_hevc_put_hevc_\type\()_h8_8_neon, export=1 - load_filter mx -.ifc \type, qpel_bi - mov x16, #(MAX_PB_SIZE << 2) // src2bstridel - add x15, x4, #(MAX_PB_SIZE << 1) // src2b -.endif +.ifnc \type, qpel_bi +function ff_vvc_put_\type\()_h8_8_neon, export=1 + vvc_load_filter mx sub src, src, #3 mov mx, x30 .ifc \type, qpel - mov dststride, #(MAX_PB_SIZE << 1) + mov dststride, #(VVC_MAX_PB_SIZE << 1) lsl x13, srcstride, #1 // srcstridel - mov x14, #(MAX_PB_SIZE << 2) + mov x14, #(VVC_MAX_PB_SIZE << 2) .else lsl x14, dststride, #1 // dststridel lsl x13, srcstride, #1 // srcstridel .endif + b 1f +endfunc +.endif // !qpel_bi + +function ff_hevc_put_hevc_\type\()_h8_8_neon, export=1 + load_filter mx +.ifc \type, qpel_bi + mov x16, #(HEVC_MAX_PB_SIZE << 2) // src2bstridel + add x15, x4, #(HEVC_MAX_PB_SIZE << 1) // src2b +.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 +1: add x10, dst, dststride // dstb add x12, src, srcstride // srcb 0: ld1 {v16.8b, v17.8b}, [src], x13 @@ -415,16 +470,16 @@ function ff_hevc_put_hevc_\type\()_h12_8_neon, export=1 sxtw height, heightw .ifc \type, qpel_bi ldrh w8, [sp] // width - mov x16, #(MAX_PB_SIZE << 2) // src2bstridel - lsl x17, height, #7 // src2b reset (height * (MAX_PB_SIZE << 1)) - add x15, x4, #(MAX_PB_SIZE << 1) // src2b + mov x16, #(HEVC_MAX_PB_SIZE << 2) // src2bstridel + lsl x17, height, #7 // src2b reset (height * (HEVC_MAX_PB_SIZE << 1)) + add x15, x4, #(HEVC_MAX_PB_SIZE << 1) // src2b .endif sub src, src, #3 mov mx, x30 .ifc \type, qpel - mov dststride, #(MAX_PB_SIZE << 1) + mov dststride, #(HEVC_MAX_PB_SIZE << 1) lsl x13, srcstride, #1 // srcstridel - mov x14, #((MAX_PB_SIZE << 2) - 16) + mov x14, #((HEVC_MAX_PB_SIZE << 2) - 16) .else lsl x14, dststride, #1 // dststridel lsl x13, srcstride, #1 // srcstridel @@ -497,25 +552,45 @@ function ff_hevc_put_hevc_\type\()_h12_8_neon, export=1 ret mx endfunc +.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 + function ff_hevc_put_hevc_\type\()_h16_8_neon, export=1 load_filter mx sxtw height, heightw mov mx, x30 .ifc \type, qpel_bi ldrh w8, [sp] // width - mov x16, #(MAX_PB_SIZE << 2) // src2bstridel - add x15, x4, #(MAX_PB_SIZE << 1) // src2b + mov x16, #(HEVC_MAX_PB_SIZE << 2) // src2bstridel + add x15, x4, #(HEVC_MAX_PB_SIZE << 1) // src2b .endif sub src, src, #3 mov mx, x30 .ifc \type, qpel - mov dststride, #(MAX_PB_SIZE << 1) + mov dststride, #(HEVC_MAX_PB_SIZE << 1) lsl x13, srcstride, #1 // srcstridel - mov x14, #(MAX_PB_SIZE << 2) + 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 @@ -555,29 +630,51 @@ function ff_hevc_put_hevc_\type\()_h16_8_neon, export=1 ret mx endfunc -function ff_hevc_put_hevc_\type\()_h32_8_neon, export=1 - load_filter mx +.ifnc \type, qpel_bi +function ff_vvc_put_\type\()_h32_8_neon, export=1 + vvc_load_filter mx sxtw height, heightw mov mx, x30 -.ifc \type, qpel_bi - ldrh w8, [sp] // width - mov x16, #(MAX_PB_SIZE << 2) // src2bstridel - lsl x17, x5, #7 // src2b reset - add x15, x4, #(MAX_PB_SIZE << 1) // src2b - sub x16, x16, width, uxtw #1 -.endif sub src, src, #3 mov mx, x30 .ifc \type, qpel - mov dststride, #(MAX_PB_SIZE << 1) + mov dststride, #(VVC_MAX_PB_SIZE << 1) lsl x13, srcstride, #1 // srcstridel - mov x14, #(MAX_PB_SIZE << 2) + 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 + +function ff_hevc_put_hevc_\type\()_h32_8_neon, export=1 + load_filter mx + sxtw height, heightw + mov mx, x30 +.ifc \type, qpel_bi + ldrh w8, [sp] // width + mov x16, #(HEVC_MAX_PB_SIZE << 2) // src2bstridel + lsl x17, x5, #7 // src2b reset + add x15, x4, #(HEVC_MAX_PB_SIZE << 1) // src2b + sub x16, x16, width, uxtw #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 add x10, dst, dststride // dstb @@ -651,7 +748,7 @@ put_hevc qpel_bi function ff_hevc_put_hevc_qpel_v4_8_neon, export=1 load_qpel_filterb x5, x4 sub x1, x1, x2, lsl #1 - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) sub x1, x1, x2 ldr s16, [x1] ldr s17, [x1, x2] @@ -670,7 +767,6 @@ function ff_hevc_put_hevc_qpel_v4_8_neon, export=1 calc_qpelb v24, \src0, \src1, \src2, \src3, \src4, \src5, \src6, \src7 st1 {v24.4h}, [x0], x9 subs w3, w3, #1 - b.eq 2f .endm 1: calc_all .purgem calc @@ -680,7 +776,7 @@ endfunc function ff_hevc_put_hevc_qpel_v6_8_neon, export=1 load_qpel_filterb x5, x4 sub x1, x1, x2, lsl #1 - mov x9, #(MAX_PB_SIZE * 2 - 8) + mov x9, #(HEVC_MAX_PB_SIZE * 2 - 8) sub x1, x1, x2 ldr d16, [x1] ldr d17, [x1, x2] @@ -709,7 +805,7 @@ endfunc function ff_hevc_put_hevc_qpel_v8_8_neon, export=1 load_qpel_filterb x5, x4 sub x1, x1, x2, lsl #1 - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) sub x1, x1, x2 ldr d16, [x1] ldr d17, [x1, x2] @@ -737,7 +833,7 @@ endfunc function ff_hevc_put_hevc_qpel_v12_8_neon, export=1 load_qpel_filterb x5, x4 sub x1, x1, x2, lsl #1 - mov x9, #(MAX_PB_SIZE * 2 - 16) + mov x9, #(HEVC_MAX_PB_SIZE * 2 - 16) sub x1, x1, x2 ldr q16, [x1] ldr q17, [x1, x2] @@ -768,7 +864,7 @@ endfunc function ff_hevc_put_hevc_qpel_v16_8_neon, export=1 load_qpel_filterb x5, x4 sub x1, x1, x2, lsl #1 - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) sub x1, x1, x2 ldr q16, [x1] ldr q17, [x1, x2] @@ -802,7 +898,7 @@ function ff_hevc_put_hevc_qpel_v24_8_neon, export=1 load_qpel_filterb x5, x4 sub x1, x1, x2, lsl #1 sub x1, x1, x2 - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.16b, v17.16b}, [x1], x2 ld1 {v18.16b, v19.16b}, [x1], x2 ld1 {v20.16b, v21.16b}, [x1], x2 @@ -833,7 +929,7 @@ function ff_hevc_put_hevc_qpel_v32_8_neon, export=1 st1 {v8.8b-v11.8b}, [sp] load_qpel_filterb x5, x4 sub x1, x1, x2, lsl #1 - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) sub x1, x1, x2 ld1 {v16.16b, v17.16b}, [x1], x2 ld1 {v18.16b, v19.16b}, [x1], x2 @@ -883,7 +979,7 @@ function ff_hevc_put_hevc_qpel_v64_8_neon, export=1 load_qpel_filterb x5, x4 sub x1, x1, x2, lsl #1 sub x1, x1, x2 - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) 0: mov x8, x1 // src ld1 {v16.16b, v17.16b}, [x8], x2 mov w11, w3 // height @@ -917,11 +1013,98 @@ function ff_hevc_put_hevc_qpel_v64_8_neon, export=1 ret endfunc +/* ff_hevc_put_hevc_qpel_vx require filter parameters be + * [-, +, -, +, +, -, +, -], + * vvc doesn't meet the requirement. + */ +function ff_vvc_put_qpel_v4_8_neon, export=1 + vvc_load_qpel_filterh x5 + sub x1, x1, x2, lsl #1 + mov x9, #(VVC_MAX_PB_SIZE * 2) + sub x1, x1, x2 + ldr s16, [x1] + ldr s17, [x1, x2] + add x1, x1, x2, lsl #1 + ldr s18, [x1] + ldr s19, [x1, x2] + uxtl v16.8h, v16.8b + uxtl v17.8h, v17.8b + add x1, x1, x2, lsl #1 + ldr s20, [x1] + ldr s21, [x1, x2] + uxtl v18.8h, v18.8b + uxtl v19.8h, v19.8b + add x1, x1, x2, lsl #1 + ldr s22, [x1] + add x1, x1, x2 + uxtl v20.8h, v20.8b + uxtl v21.8h, v21.8b + uxtl v22.8h, v22.8b +.macro calc tmp, src0, src1, src2, src3, src4, src5, src6, src7 + ld1 {\tmp\().s}[0], [x1], x2 + uxtl \tmp\().8h, \tmp\().8b + calc_qpelh v24, \src0, \src1, \src2, \src3, \src4, \src5, \src6, \src7, sqxtn + subs w3, w3, #1 + st1 {v24.4h}, [x0], x9 +.endm +1: + calc_all +.purgem calc +2: + ret +endfunc + +function ff_vvc_put_qpel_v8_8_neon, export=1 + vvc_load_qpel_filterh x5 + sub x1, x1, x2, lsl #1 + sub x1, x1, x2 + mov x9, #(VVC_MAX_PB_SIZE * 2) +0: + mov x8, x1 + ldr d16, [x8] + ldr d17, [x8, x2] + mov x10, x0 + mov w11, w3 + add x8, x8, x2, lsl #1 + ldr d18, [x8] + ldr d19, [x8, x2] + uxtl v16.8h, v16.8b + uxtl v17.8h, v17.8b + add x8, x8, x2, lsl #1 + ldr d20, [x8] + ldr d21, [x8, x2] + uxtl v18.8h, v18.8b + uxtl v19.8h, v19.8b + add x8, x8, x2, lsl #1 + ldr d22, [x8] + add x8, x8, x2 + uxtl v20.8h, v20.8b + uxtl v21.8h, v21.8b + uxtl v22.8h, v22.8b +.macro calc tmp, src0, src1, src2, src3, src4, src5, src6, src7 + ld1 {\tmp\().8b}, [x8], x2 + uxtl \tmp\().8h, \tmp\().8b + calc_qpelh v24, \src0, \src1, \src2, \src3, \src4, \src5, \src6, \src7, sqxtn + calc_qpelh2 v24, v25, \src0, \src1, \src2, \src3, \src4, \src5, \src6, \src7, sqxtn2 + subs w11, w11, #1 + st1 {v24.8h}, [x10], x9 +.endm +1: + calc_all +.purgem calc +2: + subs w6, w6, #8 + add x0, x0, #16 + add x1, x1, #8 + b.ne 0b + ret +endfunc + function ff_hevc_put_hevc_qpel_bi_v4_8_neon, export=1 load_qpel_filterb x7, x6 sub x2, x2, x3, lsl #1 sub x2, x2, x3 - mov x12, #(MAX_PB_SIZE * 2) + mov x12, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.s}[0], [x2], x3 ld1 {v17.s}[0], [x2], x3 ld1 {v18.s}[0], [x2], x3 @@ -951,7 +1134,7 @@ function ff_hevc_put_hevc_qpel_bi_v6_8_neon, export=1 ld1 {v16.8b}, [x2], x3 sub x1, x1, #4 ld1 {v17.8b}, [x2], x3 - mov x12, #(MAX_PB_SIZE * 2) + mov x12, #(HEVC_MAX_PB_SIZE * 2) ld1 {v18.8b}, [x2], x3 ld1 {v19.8b}, [x2], x3 ld1 {v20.8b}, [x2], x3 @@ -977,7 +1160,7 @@ function ff_hevc_put_hevc_qpel_bi_v8_8_neon, export=1 load_qpel_filterb x7, x6 sub x2, x2, x3, lsl #1 sub x2, x2, x3 - mov x12, #(MAX_PB_SIZE * 2) + mov x12, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.8b}, [x2], x3 ld1 {v17.8b}, [x2], x3 ld1 {v18.8b}, [x2], x3 @@ -1006,7 +1189,7 @@ function ff_hevc_put_hevc_qpel_bi_v12_8_neon, export=1 sub x2, x2, x3 sub x1, x1, #8 ld1 {v16.16b}, [x2], x3 - mov x12, #(MAX_PB_SIZE * 2) + mov x12, #(HEVC_MAX_PB_SIZE * 2) ld1 {v17.16b}, [x2], x3 ld1 {v18.16b}, [x2], x3 ld1 {v19.16b}, [x2], x3 @@ -1037,7 +1220,7 @@ function ff_hevc_put_hevc_qpel_bi_v16_8_neon, export=1 load_qpel_filterb x7, x6 sub x2, x2, x3, lsl #1 sub x2, x2, x3 - mov x12, #(MAX_PB_SIZE * 2) + mov x12, #(HEVC_MAX_PB_SIZE * 2) ld1 {v16.16b}, [x2], x3 ld1 {v17.16b}, [x2], x3 ld1 {v18.16b}, [x2], x3 @@ -1092,7 +1275,7 @@ function ff_hevc_put_hevc_qpel_bi_v32_8_neon, export=1 sub x2, x2, x3 load_qpel_filterb x7, x6 ldr w6, [sp, #64] - mov x12, #(MAX_PB_SIZE * 2) + mov x12, #(HEVC_MAX_PB_SIZE * 2) 0: mov x8, x2 // src ld1 {v16.16b, v17.16b}, [x8], x3 mov w11, w5 // height @@ -1166,6 +1349,10 @@ function ff_hevc_put_hevc_qpel_bi_v64_8_neon, export=1 b X(ff_hevc_put_hevc_qpel_bi_v32_8_neon) endfunc +function ff_vvc_put_pel_uni_pixels4_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_pixels4_8_neon) +endfunc + function ff_hevc_put_hevc_pel_uni_pixels4_8_neon, export=1 1: ldr s0, [x2] @@ -1194,6 +1381,10 @@ function ff_hevc_put_hevc_pel_uni_pixels6_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_uni_pixels8_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_pixels8_8_neon) +endfunc + function ff_hevc_put_hevc_pel_uni_pixels8_8_neon, export=1 1: ldr d0, [x2] @@ -1222,6 +1413,10 @@ function ff_hevc_put_hevc_pel_uni_pixels12_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_uni_pixels16_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_pixels16_8_neon) +endfunc + function ff_hevc_put_hevc_pel_uni_pixels16_8_neon, export=1 1: ldr q0, [x2] @@ -1244,6 +1439,10 @@ function ff_hevc_put_hevc_pel_uni_pixels24_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_uni_pixels32_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_pixels32_8_neon) +endfunc + function ff_hevc_put_hevc_pel_uni_pixels32_8_neon, export=1 1: ld1 {v0.16b, v1.16b}, [x2], x3 @@ -1262,6 +1461,10 @@ function ff_hevc_put_hevc_pel_uni_pixels48_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_uni_pixels64_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_pixels64_8_neon) +endfunc + function ff_hevc_put_hevc_pel_uni_pixels64_8_neon, export=1 1: ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x2], x3 @@ -1271,6 +1474,19 @@ function ff_hevc_put_hevc_pel_uni_pixels64_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_uni_pixels128_8_neon, export=1 + sub x1, x1, #64 + sub x3, x3, #64 +1: + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x2], #64 + subs w4, w4, #1 + ld1 {v4.16b, v5.16b, v6.16b, v7.16b}, [x2], x3 + st1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 + st1 {v4.16b, v5.16b, v6.16b, v7.16b}, [x0], x1 + b.ne 1b + ret +endfunc + function ff_hevc_put_hevc_qpel_uni_v4_8_neon, export=1 load_qpel_filterb x6, x5 sub x2, x2, x3, lsl #1 @@ -1444,6 +1660,10 @@ function ff_hevc_put_hevc_qpel_uni_v64_8_neon, export=1 b X(ff_hevc_put_hevc_qpel_uni_v16_8_neon) endfunc +function ff_vvc_put_pel_uni_w_pixels4_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_w_pixels4_8_neon) +endfunc + function ff_hevc_put_hevc_pel_uni_w_pixels4_8_neon, export=1 mov w10, #-6 sub w10, w10, w5 @@ -1514,6 +1734,10 @@ function ff_hevc_put_hevc_pel_uni_w_pixels6_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_uni_w_pixels8_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_w_pixels8_8_neon) +endfunc + function ff_hevc_put_hevc_pel_uni_w_pixels8_8_neon, export=1 mov w10, #-6 sub w10, w10, w5 @@ -1657,7 +1881,9 @@ function ff_hevc_put_hevc_pel_uni_w_pixels16_8_neon, export=1 ret endfunc - +function ff_vvc_put_pel_uni_w_pixels16_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_w_pixels16_8_neon) +endfunc function ff_hevc_put_hevc_pel_uni_w_pixels24_8_neon, export=1 mov w10, #-6 @@ -1719,6 +1945,9 @@ function ff_hevc_put_hevc_pel_uni_w_pixels32_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_uni_w_pixels32_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_w_pixels32_8_neon) +endfunc function ff_hevc_put_hevc_pel_uni_w_pixels48_8_neon, export=1 mov w10, #-6 @@ -1755,6 +1984,39 @@ function ff_hevc_put_hevc_pel_uni_w_pixels64_8_neon, export=1 ret endfunc +function ff_vvc_put_pel_uni_w_pixels64_8_neon, export=1 + b X(ff_hevc_put_hevc_pel_uni_w_pixels64_8_neon) +endfunc + +function ff_vvc_put_pel_uni_w_pixels128_8_neon, export=1 + mov w10, #-6 + sub w10, w10, w5 + dup v30.8h, w6 + dup v31.4s, w10 + dup v29.4s, w7 + sub x1, x1, #64 + sub x3, x3, #64 +1: + mov x11, x2 + mov x12, x0 + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x2], #64 + PEL_UNI_W_PIXEL_CALC v0, v4, v5, v16, v17, v18, v19 + PEL_UNI_W_PIXEL_CALC v1, v6, v7, v20, v21, v22, v23 + PEL_UNI_W_PIXEL_CALC v2, v4, v5, v16, v17, v18, v19 + PEL_UNI_W_PIXEL_CALC v3, v6, v7, v20, v21, v22, v23 + st1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], #64 + + ld1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x2], x3 + subs w4, w4, #1 + PEL_UNI_W_PIXEL_CALC v0, v4, v5, v16, v17, v18, v19 + PEL_UNI_W_PIXEL_CALC v1, v6, v7, v20, v21, v22, v23 + PEL_UNI_W_PIXEL_CALC v2, v4, v5, v16, v17, v18, v19 + PEL_UNI_W_PIXEL_CALC v3, v6, v7, v20, v21, v22, v23 + st1 {v0.16b, v1.16b, v2.16b, v3.16b}, [x0], x1 + b.ne 1b + ret +endfunc + .macro QPEL_UNI_W_V_HEADER ldur x12, [sp, #8] // my sub x2, x2, x3, lsl #1 @@ -2147,7 +2409,7 @@ function ff_hevc_put_hevc_qpel_uni_w_v64_8_neon, export=1 endfunc function hevc_put_hevc_qpel_uni_hv4_8_end_neon - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) load_qpel_filterh x6, x5 ldr d16, [sp] ldr d17, [sp, x9] @@ -2174,7 +2436,7 @@ function hevc_put_hevc_qpel_uni_hv4_8_end_neon endfunc function hevc_put_hevc_qpel_uni_hv6_8_end_neon - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) load_qpel_filterh x6, x5 sub x1, x1, #4 ldr q16, [sp] @@ -2204,7 +2466,7 @@ function hevc_put_hevc_qpel_uni_hv6_8_end_neon endfunc function hevc_put_hevc_qpel_uni_hv8_8_end_neon - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) load_qpel_filterh x6, x5 ldr q16, [sp] ldr q17, [sp, x9] @@ -2232,7 +2494,7 @@ function hevc_put_hevc_qpel_uni_hv8_8_end_neon endfunc function hevc_put_hevc_qpel_uni_hv12_8_end_neon - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) load_qpel_filterh x6, x5 sub x1, x1, #8 ld1 {v16.8h, v17.8h}, [sp], x9 @@ -2260,7 +2522,7 @@ function hevc_put_hevc_qpel_uni_hv12_8_end_neon endfunc function hevc_put_hevc_qpel_uni_hv16_8_end_neon - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) load_qpel_filterh x6, x5 sub w12, w9, w7, lsl #1 0: mov x8, sp // src @@ -3353,9 +3615,20 @@ endfunc sub x1, x1, #3 .endm +.macro VVC_QPEL_H_HEADER + ld1r {v31.2d}, [x4] + sub x1, x1, #3 +.endm + +function ff_vvc_put_qpel_h4_8_neon_i8mm, export=1 + VVC_QPEL_H_HEADER + mov x10, #VVC_MAX_PB_SIZE * 2 + b 1f +endfunc + function ff_hevc_put_hevc_qpel_h4_8_neon_i8mm, export=1 QPEL_H_HEADER - mov x10, #MAX_PB_SIZE * 2 + mov x10, #HEVC_MAX_PB_SIZE * 2 1: ld1 {v0.16b}, [x1], x2 ext v1.16b, v0.16b, v0.16b, #1 @@ -3378,7 +3651,7 @@ endfunc function ff_hevc_put_hevc_qpel_h6_8_neon_i8mm, export=1 QPEL_H_HEADER - mov x10, #MAX_PB_SIZE * 2 + mov x10, #HEVC_MAX_PB_SIZE * 2 add x15, x0, #8 1: ld1 {v0.16b}, [x1], x2 @@ -3409,9 +3682,15 @@ function ff_hevc_put_hevc_qpel_h6_8_neon_i8mm, export=1 ret endfunc +function ff_vvc_put_qpel_h8_8_neon_i8mm, export=1 + VVC_QPEL_H_HEADER + mov x10, #VVC_MAX_PB_SIZE * 2 + b 1f +endfunc + function ff_hevc_put_hevc_qpel_h8_8_neon_i8mm, export=1 QPEL_H_HEADER - mov x10, #MAX_PB_SIZE * 2 + mov x10, #HEVC_MAX_PB_SIZE * 2 1: ld1 {v0.16b}, [x1], x2 ext v1.16b, v0.16b, v0.16b, #1 @@ -3457,7 +3736,7 @@ endfunc function ff_hevc_put_hevc_qpel_h12_8_neon_i8mm, export=1 QPEL_H_HEADER - mov x10, #MAX_PB_SIZE * 2 + mov x10, #HEVC_MAX_PB_SIZE * 2 add x15, x0, #16 1: ld1 {v16.16b, v17.16b}, [x1], x2 @@ -3493,9 +3772,15 @@ function ff_hevc_put_hevc_qpel_h12_8_neon_i8mm, export=1 ret endfunc +function ff_vvc_put_qpel_h16_8_neon_i8mm, export=1 + VVC_QPEL_H_HEADER + mov x10, #VVC_MAX_PB_SIZE * 2 + b 1f +endfunc + function ff_hevc_put_hevc_qpel_h16_8_neon_i8mm, export=1 QPEL_H_HEADER - mov x10, #MAX_PB_SIZE * 2 + mov x10, #HEVC_MAX_PB_SIZE * 2 1: ld1 {v16.16b, v17.16b}, [x1], x2 ext v1.16b, v16.16b, v17.16b, #1 @@ -3533,7 +3818,7 @@ endfunc function ff_hevc_put_hevc_qpel_h24_8_neon_i8mm, export=1 QPEL_H_HEADER - mov x10, #MAX_PB_SIZE * 2 + mov x10, #HEVC_MAX_PB_SIZE * 2 add x15, x0, #32 1: ld1 {v16.16b, v17.16b}, [x1], x2 @@ -3583,9 +3868,16 @@ function ff_hevc_put_hevc_qpel_h24_8_neon_i8mm, export=1 ret endfunc +function ff_vvc_put_qpel_h32_8_neon_i8mm, export=1 + VVC_QPEL_H_HEADER + mov x10, #VVC_MAX_PB_SIZE * 2 + add x15, x0, #32 + b 1f +endfunc + function ff_hevc_put_hevc_qpel_h32_8_neon_i8mm, export=1 QPEL_H_HEADER - mov x10, #MAX_PB_SIZE * 2 + mov x10, #HEVC_MAX_PB_SIZE * 2 add x15, x0, #32 1: ld1 {v16.16b, v17.16b, v18.16b}, [x1], x2 @@ -3642,7 +3934,7 @@ endfunc function ff_hevc_put_hevc_qpel_h48_8_neon_i8mm, export=1 QPEL_H_HEADER - mov x10, #MAX_PB_SIZE * 2 - 64 + mov x10, #HEVC_MAX_PB_SIZE * 2 - 64 1: ld1 {v16.16b, v17.16b, v18.16b, v19.16b}, [x1], x2 ext v1.16b, v16.16b, v17.16b, #1 @@ -3718,10 +4010,7 @@ function ff_hevc_put_hevc_qpel_h48_8_neon_i8mm, export=1 ret endfunc -function ff_hevc_put_hevc_qpel_h64_8_neon_i8mm, export=1 - QPEL_H_HEADER - sub x2, x2, #64 -1: +.macro put_qpel_h64_8_neon_i8mm ld1 {v16.16b, v17.16b, v18.16b, v19.16b}, [x1], #64 ext v1.16b, v16.16b, v17.16b, #1 ext v2.16b, v16.16b, v17.16b, #2 @@ -3812,17 +4101,54 @@ function ff_hevc_put_hevc_qpel_h64_8_neon_i8mm, export=1 sqxtn2 v20.8h, v26.4s sqxtn v21.4h, v23.4s sqxtn2 v21.8h, v27.4s - stp q20, q21, [x0], #32 + stp q20, q21, [x0] + add x0, x0, x10 +.endm + +function ff_vvc_put_qpel_h64_8_neon_i8mm, export=1 + VVC_QPEL_H_HEADER + mov x10, #(VVC_MAX_PB_SIZE * 2 - 32 * 3) + sub x2, x2, #64 + b 1f +endfunc + +function ff_hevc_put_hevc_qpel_h64_8_neon_i8mm, export=1 + QPEL_H_HEADER + mov x10, #32 + sub x2, x2, #64 +1: + put_qpel_h64_8_neon_i8mm subs w3, w3, #1 b.ne 1b ret endfunc + +function ff_vvc_put_qpel_h128_8_neon_i8mm, export=1 + VVC_QPEL_H_HEADER + sub x11, x2, #128 + mov x10, #32 + mov x2, #0 +1: + put_qpel_h64_8_neon_i8mm + subs w3, w3, #1 + put_qpel_h64_8_neon_i8mm + add x1, x1, x11 + b.ne 1b + ret +endfunc + 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 +endfunc function hevc_put_hevc_qpel_hv4_8_end_neon load_qpel_filterh x5, x4 +1: ldr d16, [sp] ldr d17, [sp, x7] add sp, sp, x7, lsl #1 @@ -3874,9 +4200,16 @@ function hevc_put_hevc_qpel_hv6_8_end_neon ret endfunc +function vvc_put_qpel_hv8_8_end_neon + vvc_load_qpel_filterh x5 + mov x7, #(VVC_MAX_PB_SIZE * 2) + b 1f +endfunc + function hevc_put_hevc_qpel_hv8_8_end_neon mov x7, #128 load_qpel_filterh x5, x4 +1: ldr q16, [sp] ldr q17, [sp, x7] add sp, sp, x7, lsl #1 @@ -3927,9 +4260,16 @@ function hevc_put_hevc_qpel_hv12_8_end_neon ret endfunc +function vvc_put_qpel_hv16_8_end_neon + vvc_load_qpel_filterh x5 + mov x7, #(VVC_MAX_PB_SIZE * 2) + b 1f +endfunc + function hevc_put_hevc_qpel_hv16_8_end_neon mov x7, #128 load_qpel_filterh x5, x4 +1: ld1 {v16.8h, v17.8h}, [sp], x7 ld1 {v18.8h, v19.8h}, [sp], x7 ld1 {v20.8h, v21.8h}, [sp], x7 @@ -3952,6 +4292,12 @@ function hevc_put_hevc_qpel_hv16_8_end_neon ret endfunc +function vvc_put_qpel_hv32_8_end_neon + vvc_load_qpel_filterh x5 + mov x7, #(VVC_MAX_PB_SIZE * 2) + b 0f +endfunc + function hevc_put_hevc_qpel_hv32_8_end_neon mov x7, #128 load_qpel_filterh x5, x4 @@ -4005,6 +4351,25 @@ function ff_hevc_put_hevc_qpel_hv4_8_\suffix, export=1 b hevc_put_hevc_qpel_hv4_8_end_neon endfunc +function ff_vvc_put_qpel_hv4_8_\suffix, export=1 + add w10, w3, #8 + lsl x10, x10, #8 + mov x14, sp + sub sp, sp, x10 // tmp_array + stp x5, x30, [sp, #-48]! + stp x0, x3, [sp, #16] + str x14, [sp, #32] + add x0, sp, #48 + sub x1, x1, x2, lsl #1 + add x3, x3, #7 + sub x1, x1, x2 + bl X(ff_vvc_put_qpel_h4_8_\suffix) + ldr x14, [sp, #32] + ldp x0, x3, [sp, #16] + ldp x5, x30, [sp], #48 + b vvc_put_qpel_hv4_8_end_neon +endfunc + function ff_hevc_put_hevc_qpel_hv6_8_\suffix, export=1 add w10, w3, #8 mov x7, #128 @@ -4044,6 +4409,25 @@ function ff_hevc_put_hevc_qpel_hv8_8_\suffix, export=1 b hevc_put_hevc_qpel_hv8_8_end_neon endfunc +function ff_vvc_put_qpel_hv8_8_\suffix, export=1 + add w10, w3, #8 + lsl x10, x10, #8 + sub x1, x1, x2, lsl #1 + mov x14, sp + sub sp, sp, x10 // tmp_array + stp x5, x30, [sp, #-48]! + stp x0, x3, [sp, #16] + str x14, [sp, #32] + add x0, sp, #48 + add x3, x3, #7 + sub x1, x1, x2 + bl X(ff_vvc_put_qpel_h8_8_\suffix) + ldr x14, [sp, #32] + ldp x0, x3, [sp, #16] + ldp x5, x30, [sp], #48 + b vvc_put_qpel_hv8_8_end_neon +endfunc + function ff_hevc_put_hevc_qpel_hv12_8_\suffix, export=1 add w10, w3, #8 lsl x10, x10, #7 @@ -4083,6 +4467,25 @@ function ff_hevc_put_hevc_qpel_hv16_8_\suffix, export=1 b hevc_put_hevc_qpel_hv16_8_end_neon endfunc +function ff_vvc_put_qpel_hv16_8_\suffix, export=1 + add w10, w3, #8 + lsl x10, x10, #8 + sub x1, x1, x2, lsl #1 + mov x14, sp + sub sp, sp, x10 // tmp_array + stp x5, x30, [sp, #-48]! + stp x0, x3, [sp, #16] + str x14, [sp, #32] + add x3, x3, #7 + add x0, sp, #48 + sub x1, x1, x2 + bl X(ff_vvc_put_qpel_h16_8_\suffix) + ldr x14, [sp, #32] + ldp x0, x3, [sp, #16] + ldp x5, x30, [sp], #48 + b vvc_put_qpel_hv16_8_end_neon +endfunc + function ff_hevc_put_hevc_qpel_hv24_8_\suffix, export=1 stp x4, x5, [sp, #-64]! stp x2, x3, [sp, #16] @@ -4119,6 +4522,26 @@ function ff_hevc_put_hevc_qpel_hv32_8_\suffix, export=1 b hevc_put_hevc_qpel_hv32_8_end_neon endfunc +function ff_vvc_put_qpel_hv32_8_\suffix, export=1 + add w10, w3, #8 + sub x1, x1, x2, lsl #1 + lsl x10, x10, #8 + sub x1, x1, x2 + mov x14, sp + sub sp, sp, x10 // tmp_array + stp x5, x30, [sp, #-48]! + stp x0, x3, [sp, #16] + str x14, [sp, #32] + add x3, x3, #7 + add x0, sp, #48 + mov w6, #32 + bl X(ff_vvc_put_qpel_h32_8_\suffix) + ldr x14, [sp, #32] + ldp x0, x3, [sp, #16] + ldp x5, x30, [sp], #48 + b vvc_put_qpel_hv32_8_end_neon +endfunc + function ff_hevc_put_hevc_qpel_hv48_8_\suffix, export=1 stp x4, x5, [sp, #-64]! stp x2, x3, [sp, #16] @@ -4152,6 +4575,43 @@ function ff_hevc_put_hevc_qpel_hv64_8_\suffix, export=1 ldr x30, [sp], #16 ret endfunc + +function ff_vvc_put_qpel_hv64_8_\suffix, export=1 + stp x4, x5, [sp, #-64]! + stp x2, x3, [sp, #16] + stp x0, x1, [sp, #32] + str x30, [sp, #48] + mov x6, #32 + bl X(ff_vvc_put_qpel_hv32_8_\suffix) + ldp x0, x1, [sp, #32] + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp], #48 + add x1, x1, #32 + add x0, x0, #64 + mov x6, #32 + bl X(ff_vvc_put_qpel_hv32_8_\suffix) + ldr x30, [sp], #16 + ret +endfunc + +function ff_vvc_put_qpel_hv128_8_\suffix, export=1 + stp x4, x5, [sp, #-64]! + stp x2, x3, [sp, #16] + stp x0, x1, [sp, #32] + str x30, [sp, #48] + mov x6, #64 + bl X(ff_vvc_put_qpel_hv64_8_\suffix) + ldp x0, x1, [sp, #32] + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp], #48 + add x1, x1, #64 + add x0, x0, #128 + mov x6, #64 + bl X(ff_vvc_put_qpel_hv64_8_\suffix) + ldr x30, [sp], #16 + ret +endfunc + .endm qpel_hv neon @@ -4173,7 +4633,7 @@ DISABLE_I8MM stp x24, x25, [sp, #48] stp x26, x27, [sp, #64] mov x19, sp - mov x11, #(MAX_PB_SIZE*(MAX_PB_SIZE+8)*2) + mov x11, #(HEVC_MAX_PB_SIZE*(HEVC_MAX_PB_SIZE+8)*2) sub sp, sp, x11 mov x20, x0 mov x21, x1 @@ -4204,7 +4664,7 @@ DISABLE_I8MM add x9, x9, x23, lsl #3 ld1 {v0.8b}, [x9] sxtl v0.8h, v0.8b - mov x10, #(MAX_PB_SIZE * 2) + mov x10, #(HEVC_MAX_PB_SIZE * 2) dup v28.4s, w24 dup v29.4s, w25 dup v30.4s, w26 @@ -4591,7 +5051,7 @@ endfunc qpel_uni_w_hv neon function hevc_put_hevc_qpel_bi_hv4_8_end_neon - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) load_qpel_filterh x7, x6 ld1 {v16.4h}, [sp], x9 ld1 {v17.4h}, [sp], x9 @@ -4617,7 +5077,7 @@ function hevc_put_hevc_qpel_bi_hv4_8_end_neon endfunc function hevc_put_hevc_qpel_bi_hv6_8_end_neon - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) load_qpel_filterh x7, x6 sub x1, x1, #4 ld1 {v16.8h}, [sp], x9 @@ -4648,7 +5108,7 @@ function hevc_put_hevc_qpel_bi_hv6_8_end_neon endfunc function hevc_put_hevc_qpel_bi_hv8_8_end_neon - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) load_qpel_filterh x7, x6 ld1 {v16.8h}, [sp], x9 ld1 {v17.8h}, [sp], x9 @@ -4678,7 +5138,7 @@ endfunc function hevc_put_hevc_qpel_bi_hv16_8_end_neon load_qpel_filterh x7, x8 - mov x9, #(MAX_PB_SIZE * 2) + mov x9, #(HEVC_MAX_PB_SIZE * 2) mov x10, x6 0: mov x8, sp // src ld1 {v16.8h, v17.8h}, [x8], x9 diff --git a/libavcodec/aarch64/hevcdsp_sao_neon.S b/libavcodec/aarch64/h26x/sao_neon.S similarity index 88% rename from libavcodec/aarch64/hevcdsp_sao_neon.S rename to libavcodec/aarch64/h26x/sao_neon.S index 30e83dda5..c43820135 100644 --- a/libavcodec/aarch64/hevcdsp_sao_neon.S +++ b/libavcodec/aarch64/h26x/sao_neon.S @@ -1,7 +1,7 @@ /* -*-arm64-*- * vim: syntax=arm64asm * - * AArch64 NEON optimised SAO functions for HEVC decoding + * AArch64 NEON optimised SAO functions for h26x decoding * * Copyright (c) 2022 J. Dekker * @@ -24,15 +24,17 @@ #include "libavutil/aarch64/asm.S" -#define MAX_PB_SIZE 64 +#define HEVC_MAX_PB_SIZE 64 +#define VVC_MAX_PB_SIZE 128 #define AV_INPUT_BUFFER_PADDING_SIZE 64 -#define SAO_STRIDE (2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) +#define HEVC_SAO_STRIDE (2 * HEVC_MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) +#define VVC_SAO_STRIDE (2 * VVC_MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) // void sao_band_filter(uint8_t *_dst, uint8_t *_src, // ptrdiff_t stride_dst, ptrdiff_t stride_src, // int16_t *sao_offset_val, int sao_left_class, // int width, int height) -function ff_hevc_sao_band_filter_8x8_8_neon, export=1 +function ff_h26x_sao_band_filter_8x8_8_neon, export=1 stp xzr, xzr, [sp, #-64]! stp xzr, xzr, [sp, #16] stp xzr, xzr, [sp, #32] @@ -79,16 +81,30 @@ function ff_hevc_sao_band_filter_8x8_8_neon, export=1 ret endfunc -.Lsao_edge_pos: +.Lhevc_sao_edge_pos: .word 1 // horizontal -.word SAO_STRIDE // vertical -.word SAO_STRIDE + 1 // 45 degree -.word SAO_STRIDE - 1 // 135 degree +.word HEVC_SAO_STRIDE // vertical +.word HEVC_SAO_STRIDE + 1 // 45 degree +.word HEVC_SAO_STRIDE - 1 // 135 degree + +.Lvvc_sao_edge_pos: +.word 1 // horizontal +.word VVC_SAO_STRIDE // vertical +.word VVC_SAO_STRIDE + 1 // 45 degree +.word VVC_SAO_STRIDE - 1 // 135 degree + +function ff_vvc_sao_edge_filter_16x16_8_neon, export=1 + adr x7, .Lvvc_sao_edge_pos + mov x15, #VVC_SAO_STRIDE + b 1f +endfunc // ff_hevc_sao_edge_filter_16x16_8_neon(char *dst, char *src, ptrdiff stride_dst, // int16 *sao_offset_val, int eo, int width, int height) function ff_hevc_sao_edge_filter_16x16_8_neon, export=1 - adr x7, .Lsao_edge_pos + adr x7, .Lhevc_sao_edge_pos + mov x15, #HEVC_SAO_STRIDE +1: ld1 {v3.8h}, [x3] // load sao_offset_val add w5, w5, #0xF bic w5, w5, #0xF @@ -101,7 +117,6 @@ function ff_hevc_sao_edge_filter_16x16_8_neon, export=1 uzp2 v1.16b, v3.16b, v3.16b // sao_offset_val -> upper uzp1 v0.16b, v3.16b, v3.16b // sao_offset_val -> lower movi v2.16b, #2 - mov x15, #SAO_STRIDE // strides between end of line and next src/dst sub x15, x15, x5 // stride_src - width sub x16, x2, x5 // stride_dst - width @@ -145,10 +160,18 @@ function ff_hevc_sao_edge_filter_16x16_8_neon, export=1 ret endfunc +function ff_vvc_sao_edge_filter_8x8_8_neon, export=1 + adr x7, .Lvvc_sao_edge_pos + mov x15, #VVC_SAO_STRIDE + b 1f +endfunc + // ff_hevc_sao_edge_filter_8x8_8_neon(char *dst, char *src, ptrdiff stride_dst, // int16 *sao_offset_val, int eo, int width, int height) function ff_hevc_sao_edge_filter_8x8_8_neon, export=1 - adr x7, .Lsao_edge_pos + adr x7, .Lhevc_sao_edge_pos + mov x15, #HEVC_SAO_STRIDE +1: ldr w4, [x7, w4, uxtw #2] ld1 {v3.8h}, [x3] mov v3.h[7], v3.h[0] @@ -160,7 +183,6 @@ function ff_hevc_sao_edge_filter_8x8_8_neon, export=1 movi v2.16b, #2 add x16, x0, x2 lsl x2, x2, #1 - mov x15, #SAO_STRIDE mov x8, x1 sub x9, x1, x4 add x10, x1, x4 diff --git a/libavcodec/aarch64/hevcdsp_init_aarch64.c b/libavcodec/aarch64/hevcdsp_init_aarch64.c index e24dd0cbd..386d7c59c 100644 --- a/libavcodec/aarch64/hevcdsp_init_aarch64.c +++ b/libavcodec/aarch64/hevcdsp_init_aarch64.c @@ -24,7 +24,8 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/aarch64/cpu.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/aarch64/h26x/dsp.h" +#include "libavcodec/hevc/dsp.h" void ff_hevc_v_loop_filter_chroma_8_neon(uint8_t *_pix, ptrdiff_t _stride, const int *_tc, const uint8_t *_no_p, const uint8_t *_no_q); @@ -91,241 +92,6 @@ 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_transform_luma_4x4_neon_8(int16_t *coeffs); -void ff_hevc_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_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, - const int16_t *sao_offset_val, int eo, int width, int height); -void ff_hevc_put_hevc_qpel_h4_8_neon(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_h6_8_neon(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_neon(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_h12_8_neon(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_neon(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_neon(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_uni_h4_8_neon(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_qpel_uni_h6_8_neon(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_qpel_uni_h8_8_neon(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_qpel_uni_h12_8_neon(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_qpel_uni_h16_8_neon(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_qpel_uni_h32_8_neon(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_qpel_bi_h4_8_neon(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_qpel_bi_h6_8_neon(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_qpel_bi_h8_8_neon(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_qpel_bi_h12_8_neon(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_qpel_bi_h16_8_neon(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_qpel_bi_h32_8_neon(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 NEON8_FNPROTO(fn, args, ext) \ - void ff_hevc_put_hevc_##fn##4_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##6_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##8_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##12_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##16_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##24_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##32_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##48_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##64_8_neon##ext args - -#define NEON8_FNPROTO_PARTIAL_4(fn, args, ext) \ - void ff_hevc_put_hevc_##fn##4_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##8_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##16_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##64_8_neon##ext args - -#define NEON8_FNPROTO_PARTIAL_5(fn, args, ext) \ - void ff_hevc_put_hevc_##fn##4_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##8_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##16_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##32_8_neon##ext args; \ - void ff_hevc_put_hevc_##fn##64_8_neon##ext args - -NEON8_FNPROTO(pel_pixels, (int16_t *dst, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -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(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),); - -NEON8_FNPROTO(epel_bi_v, (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(epel_bi_hv, (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(epel_bi_hv, (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), _i8mm); - -NEON8_FNPROTO(epel_v, (int16_t *dst, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -NEON8_FNPROTO(pel_uni_pixels, (uint8_t *_dst, ptrdiff_t _dststride, - const uint8_t *_src, ptrdiff_t _srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -NEON8_FNPROTO(pel_uni_w_pixels, (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),); - -NEON8_FNPROTO(epel_uni_v, (uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -NEON8_FNPROTO(epel_uni_hv, (uint8_t *dst, ptrdiff_t _dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -NEON8_FNPROTO(epel_uni_hv, (uint8_t *dst, ptrdiff_t _dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width), _i8mm); - -NEON8_FNPROTO(epel_uni_w_v, (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),); - -NEON8_FNPROTO_PARTIAL_4(qpel_uni_w_v, (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),); - -NEON8_FNPROTO(epel_h, (int16_t *dst, - const uint8_t *_src, ptrdiff_t _srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -NEON8_FNPROTO(epel_hv, (int16_t *dst, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width), ); - -NEON8_FNPROTO(epel_h, (int16_t *dst, - const uint8_t *_src, ptrdiff_t _srcstride, - int height, intptr_t mx, intptr_t my, int width), _i8mm); - -NEON8_FNPROTO(epel_hv, (int16_t *dst, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width), _i8mm); - -NEON8_FNPROTO(epel_uni_w_h, (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),); - -NEON8_FNPROTO(epel_uni_w_h, (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), _i8mm); - -NEON8_FNPROTO(qpel_h, (int16_t *dst, - const uint8_t *_src, ptrdiff_t _srcstride, - int height, intptr_t mx, intptr_t my, int width), _i8mm); - -NEON8_FNPROTO(qpel_v, (int16_t *dst, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -NEON8_FNPROTO(qpel_hv, (int16_t *dst, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -NEON8_FNPROTO(qpel_hv, (int16_t *dst, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width), _i8mm); - -NEON8_FNPROTO(qpel_uni_v, (uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -NEON8_FNPROTO(qpel_uni_hv, (uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width),); - -NEON8_FNPROTO(qpel_uni_hv, (uint8_t *dst, ptrdiff_t dststride, - const uint8_t *src, ptrdiff_t srcstride, - int height, intptr_t mx, intptr_t my, int width), _i8mm); - -NEON8_FNPROTO(qpel_uni_w_h, (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),); - -NEON8_FNPROTO(qpel_uni_w_h, (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), _i8mm); - -NEON8_FNPROTO(epel_uni_w_hv, (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),); - -NEON8_FNPROTO(epel_uni_w_hv, (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), _i8mm); - -NEON8_FNPROTO_PARTIAL_5(qpel_uni_w_hv, (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),); - -NEON8_FNPROTO_PARTIAL_5(qpel_uni_w_hv, (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), _i8mm); - -NEON8_FNPROTO(qpel_bi_v, (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(qpel_bi_hv, (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(qpel_bi_hv, (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), _i8mm); #define NEON8_FNASSIGN(member, v, h, fn, ext) \ member[1][v][h] = ff_hevc_put_hevc_##fn##4_8_neon##ext; \ @@ -391,7 +157,7 @@ av_cold void ff_hevc_dsp_init_aarch64(HEVCDSPContext *c, const int bit_depth) 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_8x8_8_neon; + c->sao_band_filter[4] = ff_h26x_sao_band_filter_8x8_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] = diff --git a/libavcodec/aarch64/idctdsp_init_aarch64.c b/libavcodec/aarch64/idctdsp_init_aarch64.c index eec21aa5a..8efd5f532 100644 --- a/libavcodec/aarch64/idctdsp_init_aarch64.c +++ b/libavcodec/aarch64/idctdsp_init_aarch64.c @@ -22,7 +22,7 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" -#include "libavutil/arm/cpu.h" +#include "libavutil/aarch64/cpu.h" #include "libavcodec/avcodec.h" #include "libavcodec/idctdsp.h" #include "idct.h" diff --git a/libavcodec/aarch64/me_cmp_init_aarch64.c b/libavcodec/aarch64/me_cmp_init_aarch64.c index 1e0f1cf4f..fa2724403 100644 --- a/libavcodec/aarch64/me_cmp_init_aarch64.c +++ b/libavcodec/aarch64/me_cmp_init_aarch64.c @@ -77,6 +77,13 @@ int vsse8_neon(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, int vsse_intra8_neon(MpegEncContext *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, + ptrdiff_t stride, int h); +int vsse_intra16_neon_dotprod(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, + ptrdiff_t stride, int h); +#endif + av_cold void ff_me_cmp_init_aarch64(MECmpContext *c, AVCodecContext *avctx) { int cpu_flags = av_get_cpu_flags(); @@ -113,6 +120,13 @@ av_cold void ff_me_cmp_init_aarch64(MECmpContext *c, AVCodecContext *avctx) c->median_sad[0] = pix_median_abs16_neon; c->median_sad[1] = pix_median_abs8_neon; } + +#if HAVE_DOTPROD + if (have_dotprod(cpu_flags)) { + c->sse[0] = sse16_neon_dotprod; + c->vsse[4] = vsse_intra16_neon_dotprod; + } +#endif } int nsse16_neon_wrapper(MpegEncContext *c, const uint8_t *s1, const uint8_t *s2, diff --git a/libavcodec/aarch64/me_cmp_neon.S b/libavcodec/aarch64/me_cmp_neon.S index 7500c324b..20e3b33a8 100644 --- a/libavcodec/aarch64/me_cmp_neon.S +++ b/libavcodec/aarch64/me_cmp_neon.S @@ -1559,3 +1559,117 @@ function pix_median_abs8_neon, export=1 ret endfunc + +#if HAVE_DOTPROD +ENABLE_DOTPROD + +function sse16_neon_dotprod, export=1 + // x0 - unused + // x1 - pix1 + // x2 - pix2 + // x3 - stride + // w4 - h + + cmp w4, #4 + movi v17.4s, #0 + b.lt 2f + +// Make 4 iterations at once +1: + + // res = abs(pix1[0] - pix2[0]) + // res * res + + ld1 {v0.16b}, [x1], x3 // Load pix1 vector for first iteration + ld1 {v1.16b}, [x2], x3 // Load pix2 vector for first iteration + ld1 {v2.16b}, [x1], x3 // Load pix1 vector for second iteration + uabd v30.16b, v0.16b, v1.16b // Absolute difference, first iteration + ld1 {v3.16b}, [x2], x3 // Load pix2 vector for second iteration + udot v17.4s, v30.16b, v30.16b + uabd v27.16b, v2.16b, v3.16b // Absolute difference, second iteration + ld1 {v4.16b}, [x1], x3 // Load pix1 for third iteration + udot v17.4s, v27.16b, v27.16b + ld1 {v5.16b}, [x2], x3 // Load pix2 for third iteration + 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 + uabd v21.16b, v6.16b, v7.16b // Absolute difference, fourth iteration + sub w4, w4, #4 // h -= 4 + udot v17.4s, v21.16b, v21.16b + cmp w4, #4 + b.ge 1b + + cbz w4, 3f + +// iterate by one +2: + + ld1 {v0.16b}, [x1], x3 // Load pix1 + ld1 {v1.16b}, [x2], x3 // Load pix2 + + uabd v30.16b, v0.16b, v1.16b + subs w4, w4, #1 + udot v17.4s, v30.16b, v30.16b + + b.ne 2b + +3: + uaddlv d16, v17.4s // add up accumulator vector + + fmov w0, s16 + + ret +endfunc + +function vsse_intra16_neon_dotprod, export=1 + // x0 unused + // x1 uint8_t *pix1 + // x2 uint8_t *dummy + // x3 ptrdiff_t stride + // w4 int h + + ld1 {v0.16b}, [x1], x3 + movi v17.4s, #0 + + sub w4, w4, #1 // we need to make h-1 iterations + cmp w4, #3 + b.lt 2f + +1: + // v = abs( pix1[0] - pix1[0 + stride] ) + // score = sum( v * v ) + ld1 {v1.16b}, [x1], x3 + ld1 {v2.16b}, [x1], x3 + uabd v30.16b, v0.16b, v1.16b + ld1 {v3.16b}, [x1], x3 + udot v17.4s, v30.16b, v30.16b + uabd v27.16b, v1.16b, v2.16b + udot v17.4s, v27.16b, v27.16b + uabd v25.16b, v2.16b, v3.16b + sub w4, w4, #3 + udot v17.4s, v25.16b, v25.16b + cmp w4, #3 + mov v0.16b, v3.16b + + b.ge 1b + cbz w4, 3f + +// iterate by one +2: + ld1 {v1.16b}, [x1], x3 + subs w4, w4, #1 + uabd v30.16b, v0.16b, v1.16b + mov v0.16b, v1.16b + udot v17.4s, v30.16b, v30.16b + cbnz w4, 2b + +3: + uaddlv d17, v17.4s + fmov w0, s17 + + ret +endfunc + +DISABLE_DOTPROD +#endif diff --git a/libavutil/aarch64/bswap.h b/libavcodec/aarch64/mpegvideoencdsp_init.c similarity index 53% rename from libavutil/aarch64/bswap.h rename to libavcodec/aarch64/mpegvideoencdsp_init.c index 7abca657b..0402ac9e8 100644 --- a/libavutil/aarch64/bswap.h +++ b/libavcodec/aarch64/mpegvideoencdsp_init.c @@ -16,41 +16,34 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVUTIL_AARCH64_BSWAP_H -#define AVUTIL_AARCH64_BSWAP_H - +#include #include -#include "config.h" + #include "libavutil/attributes.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/mpegvideoencdsp.h" +#include "config.h" -#if HAVE_INLINE_ASM +int ff_pix_sum16_neon(const uint8_t *pix, ptrdiff_t line_size); +int ff_pix_norm1_neon(const uint8_t *pix, ptrdiff_t line_size); -#define av_bswap16 av_bswap16 -static av_always_inline av_const unsigned av_bswap16(unsigned x) +#if HAVE_DOTPROD +int ff_pix_norm1_neon_dotprod(const uint8_t *pix, ptrdiff_t line_size); +#endif + +av_cold void ff_mpegvideoencdsp_init_aarch64(MpegvideoEncDSPContext *c, + AVCodecContext *avctx) { - unsigned y; + int cpu_flags = av_get_cpu_flags(); - __asm__("rev16 %w0, %w1" : "=r"(y) : "r"(x)); - return y; + if (have_neon(cpu_flags)) { + c->pix_sum = ff_pix_sum16_neon; + c->pix_norm1 = ff_pix_norm1_neon; + } + +#if HAVE_DOTPROD + if (have_dotprod(cpu_flags)) { + c->pix_norm1 = ff_pix_norm1_neon_dotprod; + } +#endif } - -#define av_bswap32 av_bswap32 -static av_always_inline av_const uint32_t av_bswap32(uint32_t x) -{ - uint32_t y; - - __asm__("rev %w0, %w1" : "=r"(y) : "r"(x)); - return y; -} - -#define av_bswap64 av_bswap64 -static av_always_inline av_const uint64_t av_bswap64(uint64_t x) -{ - uint64_t y; - - __asm__("rev %0, %1" : "=r"(y) : "r"(x)); - return y; -} - -#endif /* HAVE_INLINE_ASM */ -#endif /* AVUTIL_AARCH64_BSWAP_H */ diff --git a/libavcodec/aarch64/mpegvideoencdsp_neon.S b/libavcodec/aarch64/mpegvideoencdsp_neon.S new file mode 100644 index 000000000..8175d8975 --- /dev/null +++ b/libavcodec/aarch64/mpegvideoencdsp_neon.S @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 Ramiro Polla + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_pix_sum16_neon, export=1 +// x0 const uint8_t *pix +// x1 ptrdiff_t line_size + + add x2, x0, x1 + lsl x1, x1, #1 + movi v0.16b, #0 + mov w3, #16 + +1: + ld1 {v1.16b}, [x0], x1 + ld1 {v2.16b}, [x2], x1 + subs w3, w3, #2 + uadalp v0.8h, v1.16b + uadalp v0.8h, v2.16b + b.ne 1b + + uaddlv s0, v0.8h + fmov w0, s0 + + ret +endfunc + +function ff_pix_norm1_neon, export=1 +// x0 const uint8_t *pix +// x1 ptrdiff_t line_size + + movi v0.16b, #0 + mov w2, #16 + +1: + ld1 {v1.16b}, [x0], x1 + subs w2, w2, #1 + umull v2.8h, v1.8b, v1.8b + umull2 v3.8h, v1.16b, v1.16b + uadalp v0.4s, v2.8h + uadalp v0.4s, v3.8h + b.ne 1b + + uaddlv d0, v0.4s + fmov w0, s0 + + ret +endfunc + +#if HAVE_DOTPROD +ENABLE_DOTPROD + +function ff_pix_norm1_neon_dotprod, export=1 +// x0 const uint8_t *pix +// x1 ptrdiff_t line_size + + movi v0.16b, #0 + mov w2, #16 + +1: + ld1 {v1.16b}, [x0], x1 + ld1 {v2.16b}, [x0], x1 + udot v0.4s, v1.16b, v1.16b + subs w2, w2, #2 + udot v0.4s, v2.16b, v2.16b + b.ne 1b + + uaddlv d0, v0.4s + fmov w0, s0 + + ret +endfunc + +DISABLE_DOTPROD +#endif diff --git a/libavcodec/aarch64/opusdsp_init.c b/libavcodec/aarch64/opusdsp_init.c index bb6d71b66..5452ea624 100644 --- a/libavcodec/aarch64/opusdsp_init.c +++ b/libavcodec/aarch64/opusdsp_init.c @@ -20,10 +20,10 @@ #include "libavutil/attributes.h" #include "libavutil/aarch64/cpu.h" -#include "libavcodec/opusdsp.h" +#include "libavcodec/opus/dsp.h" void ff_opus_postfilter_neon(float *data, int period, float *gains, int len); -float ff_opus_deemphasis_neon(float *out, float *in, float coeff, int len); +float ff_opus_deemphasis_neon(float *out, float *in, float coeff, const float *weights, int len); av_cold void ff_opus_dsp_init_aarch64(OpusDSP *ctx) { diff --git a/libavcodec/aarch64/opusdsp_neon.S b/libavcodec/aarch64/opusdsp_neon.S index e933151ab..253825aa6 100644 --- a/libavcodec/aarch64/opusdsp_neon.S +++ b/libavcodec/aarch64/opusdsp_neon.S @@ -18,29 +18,11 @@ #include "libavutil/aarch64/asm.S" - // 0.85..^1 0.85..^2 0.85..^3 0.85..^4 -const tab_st, align=4 - .word 0x3f599a00, 0x3f38f671, 0x3f1d382a, 0x3f05a32f -endconst -const tab_x0, align=4 - .word 0x0, 0x3f599a00, 0x3f38f671, 0x3f1d382a -endconst -const tab_x1, align=4 - .word 0x0, 0x0, 0x3f599a00, 0x3f38f671 -endconst -const tab_x2, align=4 - .word 0x0, 0x0, 0x0, 0x3f599a00 -endconst - function ff_opus_deemphasis_neon, export=1 - movrel x4, tab_st - ld1 {v4.4s}, [x4] - movrel x4, tab_x0 - ld1 {v5.4s}, [x4] - movrel x4, tab_x1 - ld1 {v6.4s}, [x4] - movrel x4, tab_x2 - ld1 {v7.4s}, [x4] + ld1 {v4.4s}, [x2], #16 + ld1 {v5.4s}, [x2], #16 + ld1 {v6.4s}, [x2], #16 + ld1 {v7.4s}, [x2] fmul v0.4s, v4.4s, v0.s[0] @@ -63,7 +45,7 @@ function ff_opus_deemphasis_neon, export=1 st1 {v1.4s, v2.4s}, [x0], #32 fmul v0.4s, v4.4s, v2.s[3] - subs w2, w2, #8 + subs w3, w3, #8 b.gt 1b mov s0, v2.s[3] diff --git a/libavcodec/aarch64/vp9mc_neon.S b/libavcodec/aarch64/vp9mc_neon.S index abf2bae9d..38f44ca56 100644 --- a/libavcodec/aarch64/vp9mc_neon.S +++ b/libavcodec/aarch64/vp9mc_neon.S @@ -230,6 +230,9 @@ function \type\()_8tap_\size\()h_\idx1\idx2 // reduced dst stride .if \size >= 16 sub x1, x1, x5 +.elseif \size == 4 + add x12, x2, #8 + add x13, x7, #8 .endif // size >= 16 loads two qwords and increments x2, // for size 4/8 it's enough with one qword and no @@ -248,9 +251,14 @@ function \type\()_8tap_\size\()h_\idx1\idx2 .if \size >= 16 ld1 {v4.8b, v5.8b, v6.8b}, [x2], #24 ld1 {v16.8b, v17.8b, v18.8b}, [x7], #24 -.else +.elseif \size == 8 ld1 {v4.8b, v5.8b}, [x2] ld1 {v16.8b, v17.8b}, [x7] +.else // \size == 4 + ld1 {v4.8b}, [x2] + ld1 {v16.8b}, [x7] + ld1 {v5.s}[0], [x12], x3 + ld1 {v17.s}[0], [x13], x3 .endif uxtl v4.8h, v4.8b uxtl v5.8h, v5.8b diff --git a/libavcodec/aarch64/vvc/Makefile b/libavcodec/aarch64/vvc/Makefile new file mode 100644 index 000000000..ed8033896 --- /dev/null +++ b/libavcodec/aarch64/vvc/Makefile @@ -0,0 +1,10 @@ +clean:: + $(RM) $(CLEANSUFFIXES:%=libavcodec/aarch64/vvc/%) + +OBJS-$(CONFIG_VVC_DECODER) += aarch64/vvc/dsp_init.o +NEON-OBJS-$(CONFIG_VVC_DECODER) += aarch64/vvc/alf.o \ + aarch64/vvc/inter.o \ + aarch64/vvc/sad.o \ + aarch64/h26x/epel_neon.o \ + aarch64/h26x/qpel_neon.o \ + aarch64/h26x/sao_neon.o diff --git a/libavcodec/aarch64/vvc/alf.S b/libavcodec/aarch64/vvc/alf.S new file mode 100644 index 000000000..8801b3afb --- /dev/null +++ b/libavcodec/aarch64/vvc/alf.S @@ -0,0 +1,293 @@ +/* + * 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/aarch64/asm.S" + +.macro alf_luma_filter_pixel index, pix_size, addr1, addr2, offset1, offset2 + .if \pix_size == 1 + ldur d3, [\addr1, #\offset1] + ldur d4, [\addr2, #\offset2] + uxtl v6.8h, v3.8b + uxtl v7.8h, v4.8b + .else + ldur q6, [\addr1, #(2*\offset1)] + ldur q7, [\addr2, #(2*\offset2)] + .endif + .if \index < 8 + dup v17.4h, v0.h[\index] // clip + dup v18.4h, v16.h[\index] // -clip + dup v19.4h, v1.h[\index] // filter + + dup v26.4h, v22.h[\index] // clip + dup v27.4h, v23.h[\index] // -clip + dup v28.4h, v24.h[\index] // filter + .else + dup v17.4h, v0.h[\index - 8] // clip + dup v18.4h, v16.h[\index - 8] // -clip + dup v19.4h, v1.h[\index - 8] // filter + + dup v26.4h, v22.h[\index - 8] // clip + dup v27.4h, v23.h[\index - 8] // -clip + dup v28.4h, v24.h[\index - 8] // filter + .endif + ins v17.d[1], v26.d[0] + ins v18.d[1], v27.d[0] + ins v19.d[1], v28.d[0] + + sub v6.8h, v6.8h, v5.8h + sub v7.8h, v7.8h, v5.8h + smin v6.8h, v6.8h, v17.8h + smin v7.8h, v7.8h, v17.8h + smax v6.8h, v6.8h, v18.8h + smax v7.8h, v7.8h, v18.8h + add v6.8h, v6.8h, v7.8h + smlal v20.4s, v19.4h, v6.4h // v20: sum + smlal2 v21.4s, v19.8h, v6.8h // v21: sum +.endm + +/* x0: dst + * x1: pp + * x2: filter + * x3: clip + * w4: is_near_vb + * w5: pix_max + */ +.macro alf_filter_luma_kernel, pix_size + dst .req x0 + pp .req x1 + filter .req x2 + clip .req x3 + is_near_vb .req w4 + pix_max .req w5 + .if \pix_size > 1 + dup v25.8h, pix_max // pix_max + .endif + ldr q0, [clip] // clip + ldr q1, [filter] // filter + ldur q22, [clip, #24] // clip + ldur q24, [filter, #24] // filter + + ldr x5, [pp] // x5: p0 + ldr x6, [pp, #(5*8)] // x6: p5 + ldr x7, [pp, #(6*8)] // x7: p6 + neg v16.8h, v0.8h // -clip + neg v23.8h, v22.8h // -clip + + .if \pix_size == 1 + ldr d2, [x5] // curr + .else + ldr q5, [x5] // curr + .endif + movi v20.4s, #64 + cbz is_near_vb, 1f + shl v20.4s, v20.4s, #3 +1: + .if \pix_size == 1 + uxtl v5.8h, v2.8b + .endif + mov v21.16b, v20.16b + ldr x8, [pp, #(3*8)] // p3 + ldr x9, [pp, #(4*8)] // p4 + alf_luma_filter_pixel 0, \pix_size, x6, x7, 0, 0 + + ldr x6, [pp, #(1*8)] // p1 + ldr x7, [pp, #(2*8)] // p2 + alf_luma_filter_pixel 1, \pix_size, x8, x9, 1, -1 + alf_luma_filter_pixel 2, \pix_size, x8, x9, 0, 0 + alf_luma_filter_pixel 3, \pix_size, x8, x9, -1, 1 + + alf_luma_filter_pixel 4, \pix_size, x6, x7, 2, -2 + alf_luma_filter_pixel 5, \pix_size, x6, x7, 1, -1 + alf_luma_filter_pixel 6, \pix_size, x6, x7, 0, 0 + alf_luma_filter_pixel 7, \pix_size, x6, x7, -1, 1 + + ldr d0, [clip, #16] // clip + ldr d1, [filter, #16] // filter + neg v16.4h, v0.4h // -clip + + ldr d22, [clip, #40] // clip + ldr d24, [filter, #40] // filter + neg v23.4h, v22.4h // -clip + alf_luma_filter_pixel 8, \pix_size, x6, x7, -2, 2 + alf_luma_filter_pixel 9, \pix_size, x5, x5, 3, -3 + alf_luma_filter_pixel 10, \pix_size, x5, x5, 2, -2 + alf_luma_filter_pixel 11, \pix_size, x5, x5, 1, -1 + + cbz is_near_vb, 2f + sshr v20.4s, v20.4s, #10 + sshr v21.4s, v21.4s, #10 + b 3f +2: + sshr v20.4s, v20.4s, #7 + sshr v21.4s, v21.4s, #7 +3: + uxtl v22.4s, v5.4h + uxtl2 v23.4s, v5.8h + add v20.4s, v20.4s, v22.4s + add v21.4s, v21.4s, v23.4s + sqxtun v20.4h, v20.4s + sqxtun2 v20.8h, v21.4s + .if \pix_size == 1 + sqxtun v20.8b, v20.8h + str d20, [dst] + .else + umin v20.8h, v20.8h, v25.8h + str q20, [dst] + .endif + ret + + .unreq dst + .unreq pp + .unreq filter + .unreq clip + .unreq is_near_vb + .unreq pix_max +.endm + +.macro alf_chroma_filter_pixel index, pix_size, addr1, addr2, offset1, offset2 + .if \pix_size == 1 + ldur s3, [\addr1, #\offset1] + ldur s4, [\addr2, #\offset2] + uxtl v6.8h, v3.8b + uxtl v7.8h, v4.8b + .else + ldur d6, [\addr1, #(2*\offset1)] + ldur d7, [\addr2, #(2*\offset2)] + .endif + .if \index < 8 + dup v17.4h, v0.h[\index] // v17: clip[0] + dup v18.4h, v16.h[\index] // v18: -clip[0] + dup v19.4h, v1.h[\index] // v19: filter[0] + .else + dup v17.4h, v0.h[\index - 8] // v17: clip[0] + dup v18.4h, v16.h[\index - 8] // v18: -clip[0] + dup v19.4h, v1.h[\index - 8] // v19: filter[0] + .endif + + sub v6.4h, v6.4h, v5.4h + sub v7.4h, v7.4h, v5.4h + smin v6.4h, v6.4h, v17.4h + smin v7.4h, v7.4h, v17.4h + smax v6.4h, v6.4h, v18.4h + smax v7.4h, v7.4h, v18.4h + add v6.4h, v6.4h, v7.4h + smlal v20.4s, v19.4h, v6.4h // v20: sum +.endm + +/* x0: dst + * x1: pp + * x2: filter + * x3: clip + * w4: is_near_vb + * w5: pix_max + */ +.macro alf_filter_chroma_kernel, pix_size + dst .req x0 + pp .req x1 + filter .req x2 + clip .req x3 + is_near_vb .req w4 + pix_max .req w5 + .if \pix_size > 1 + dup v25.4h, pix_max // pix_max + .endif + ldr q0, [clip] // clip + ldr q1, [filter] // filter + ldr x5, [pp] // p0 + ldr x6, [pp, #(3*8)] // p3 + ldr x7, [pp, #(4*8)] // p4 + neg v16.8h, v0.8h // -clip + + .if \pix_size == 1 + ldr s2, [x5] // curr + .else + ldr d5, [x5] // curr + .endif + movi v20.4s, #64 + cbz is_near_vb, 1f + shl v20.4s, v20.4s, #3 +1: + .if \pix_size == 1 + uxtl v5.8h, v2.8b + .endif + ldr x8, [pp, #(1*8)] // p1 + ldr x9, [pp, #(2*8)] // p2 + alf_chroma_filter_pixel 0, \pix_size, x6, x7, 0, 0 + alf_chroma_filter_pixel 1, \pix_size, x8, x9, 1, -1 + alf_chroma_filter_pixel 2, \pix_size, x8, x9, 0, 0 + alf_chroma_filter_pixel 3, \pix_size, x8, x9, -1, 1 + alf_chroma_filter_pixel 4, \pix_size, x5, x5, 2, -2 + alf_chroma_filter_pixel 5, \pix_size, x5, x5, 1, -1 + + uxtl v22.4s, v5.4h + cbz is_near_vb, 2f + sshr v20.4s, v20.4s, #10 + b 3f +2: + sshr v20.4s, v20.4s, #7 +3: + add v20.4s, v20.4s, v22.4s + sqxtun v20.4h, v20.4s + .if \pix_size == 1 + sqxtun v20.8b, v20.8h + str s20, [dst] + .else + umin v20.4h, v20.4h, v25.4h + str d20, [dst] + .endif + ret + + .unreq dst + .unreq pp + .unreq filter + .unreq clip + .unreq is_near_vb + .unreq pix_max +.endm + +function ff_alf_filter_luma_kernel_8_neon, export=1 + alf_filter_luma_kernel 1 +endfunc + +function ff_alf_filter_luma_kernel_12_neon, export=1 + mov w5, #4095 + b 1f +endfunc + +function ff_alf_filter_luma_kernel_10_neon, export=1 + mov w5, #1023 +1: + alf_filter_luma_kernel 2 +endfunc + +function ff_alf_filter_chroma_kernel_8_neon, export=1 + alf_filter_chroma_kernel 1 +endfunc + +function ff_alf_filter_chroma_kernel_12_neon, export=1 + mov w5, #4095 + b 1f +endfunc + +function ff_alf_filter_chroma_kernel_10_neon, export=1 + mov w5, #1023 +1: + alf_filter_chroma_kernel 2 +endfunc diff --git a/libavcodec/aarch64/vvc/alf_template.c b/libavcodec/aarch64/vvc/alf_template.c new file mode 100644 index 000000000..41f7bf899 --- /dev/null +++ b/libavcodec/aarch64/vvc/alf_template.c @@ -0,0 +1,157 @@ +/* + * VVC filters DSP + * + * 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/bit_depth_template.c" + +void FUNC2(ff_alf_filter_luma_kernel, BIT_DEPTH, _neon)(pixel *dst, + const pixel **p, + const int16_t *filter, + const int16_t *clip, + int is_near_vb); + +void FUNC2(ff_alf_filter_chroma_kernel, BIT_DEPTH, _neon)(pixel *dst, + const pixel **p, + const int16_t *filter, + const int16_t *clip, + int is_near_vb); + +static void FUNC2(alf_filter_luma, BIT_DEPTH, _neon)(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) +{ + const pixel *src = (pixel *)_src; + + dst_stride /= sizeof(pixel); + src_stride /= sizeof(pixel); + + for (int y = 0; y < height; y += ALF_BLOCK_SIZE) { + int far = (y + 3 < vb_pos - 3) || (y > vb_pos + 2); + + for (int x = 0; x < width; x += 2 * ALF_BLOCK_SIZE) { + const pixel *s0 = src + y * src_stride + x; + const pixel *s1 = s0 + src_stride; + const pixel *s2 = s0 - src_stride; + const pixel *s3 = s1 + src_stride; + const pixel *s4 = s2 - src_stride; + const pixel *s5 = s3 + src_stride; + const pixel *s6 = s4 - src_stride; + + for (int i = 0; i < ALF_BLOCK_SIZE; i++) { + pixel *dst = (pixel *) _dst + (y + i) * dst_stride + x; + + const pixel *p0 = s0 + i * src_stride; + const pixel *p1 = s1 + i * src_stride; + const pixel *p2 = s2 + i * src_stride; + const pixel *p3 = s3 + i * src_stride; + const pixel *p4 = s4 + i * src_stride; + const pixel *p5 = s5 + i * src_stride; + const pixel *p6 = s6 + i * src_stride; + int is_near_vb = 0; + + if (!far) { + is_near_vb = (y + i == vb_pos - 1) || (y + i == vb_pos); + if (is_near_vb) { + p1 = p0; + p2 = p0; + } + if (y + i >= vb_pos - 2 && y + i <= vb_pos + 1) { + p3 = p1; + p4 = p2; + } + if (y + i >= vb_pos - 3 && y + i <= vb_pos + 2) { + p5 = p3; + p6 = p4; + } + } + FUNC2(ff_alf_filter_luma_kernel, BIT_DEPTH, _neon)(dst, + (const pixel *[]) { p0, p1, p2, p3, p4, p5, p6}, + filter, + clip, + is_near_vb); + } + filter += 2 * ALF_NUM_COEFF_LUMA; + clip += 2 * ALF_NUM_COEFF_LUMA; + } + } +} + +static void FUNC2(alf_filter_chroma, BIT_DEPTH, _neon)(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) +{ + const pixel *src = (pixel *)_src; + + dst_stride /= sizeof(pixel); + src_stride /= sizeof(pixel); + + for (int y = 0; y < height; y += ALF_BLOCK_SIZE) { + int far = (y + 3 < vb_pos - 2) || (y > vb_pos + 1); + + for (int x = 0; x < width; x += ALF_BLOCK_SIZE) { + const pixel *s0 = src + y * src_stride + x; + const pixel *s1 = s0 + src_stride; + const pixel *s2 = s0 - src_stride; + const pixel *s3 = s1 + src_stride; + const pixel *s4 = s2 - src_stride; + + for (int i = 0; i < ALF_BLOCK_SIZE; i++) { + pixel *dst = (pixel *)_dst + (y + i) * dst_stride + x; + + const pixel *p0 = s0 + i * src_stride; + const pixel *p1 = s1 + i * src_stride; + const pixel *p2 = s2 + i * src_stride; + const pixel *p3 = s3 + i * src_stride; + const pixel *p4 = s4 + i * src_stride; + int is_near_vb = 0; + + if (!far) { + is_near_vb = (y + i == vb_pos - 1) || (y + i == vb_pos); + if (is_near_vb) { + p1 = p0; + p2 = p0; + } + + if (y + i >= vb_pos - 2 && y + i <= vb_pos + 1) { + p3 = p1; + p4 = p2; + } + } + + FUNC2(ff_alf_filter_chroma_kernel, BIT_DEPTH, _neon)(dst, + (const pixel *[]){p0, p1, p2, p3, p4}, + filter, clip, + is_near_vb); + } + } + } +} diff --git a/libavcodec/aarch64/vvc/dsp_init.c b/libavcodec/aarch64/vvc/dsp_init.c new file mode 100644 index 000000000..ad767d17e --- /dev/null +++ b/libavcodec/aarch64/vvc/dsp_init.c @@ -0,0 +1,177 @@ +/* + * VVC filters DSP + * + * 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.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/aarch64/h26x/dsp.h" +#include "libavcodec/vvc/dsp.h" +#include "libavcodec/vvc/dec.h" +#include "libavcodec/vvc/ctu.h" + +#define BIT_DEPTH 8 +#include "alf_template.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 10 +#include "alf_template.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 12 +#include "alf_template.c" +#undef BIT_DEPTH + +int ff_vvc_sad_neon(const int16_t *src0, const int16_t *src1, int dx, int dy, + const int block_w, const int block_h); + +void ff_vvc_avg_8_neon(uint8_t *dst, ptrdiff_t dst_stride, + const int16_t *src0, const int16_t *src1, int width, + int height); +void ff_vvc_avg_10_neon(uint8_t *dst, ptrdiff_t dst_stride, + const int16_t *src0, const int16_t *src1, int width, + int height); +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_dsp_init_aarch64(VVCDSPContext *const c, const int bd) +{ + int cpu_flags = av_get_cpu_flags(); + if (!have_neon(cpu_flags)) + return; + + if (bd == 8) { + c->inter.put[0][1][0][0] = ff_vvc_put_pel_pixels4_8_neon; + c->inter.put[0][2][0][0] = ff_vvc_put_pel_pixels8_8_neon; + c->inter.put[0][3][0][0] = ff_vvc_put_pel_pixels16_8_neon; + c->inter.put[0][4][0][0] = ff_vvc_put_pel_pixels32_8_neon; + c->inter.put[0][5][0][0] = ff_vvc_put_pel_pixels64_8_neon; + c->inter.put[0][6][0][0] = ff_vvc_put_pel_pixels128_8_neon; + + c->inter.put[0][1][0][1] = ff_vvc_put_qpel_h4_8_neon; + c->inter.put[0][2][0][1] = ff_vvc_put_qpel_h8_8_neon; + c->inter.put[0][3][0][1] = ff_vvc_put_qpel_h16_8_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_qpel_h32_8_neon; + + c->inter.put[0][1][1][0] = ff_vvc_put_qpel_v4_8_neon; + c->inter.put[0][2][1][0] = + c->inter.put[0][3][1][0] = + c->inter.put[0][4][1][0] = + c->inter.put[0][5][1][0] = + c->inter.put[0][6][1][0] = ff_vvc_put_qpel_v8_8_neon; + + c->inter.put[0][1][1][1] = ff_vvc_put_qpel_hv4_8_neon; + c->inter.put[0][2][1][1] = ff_vvc_put_qpel_hv8_8_neon; + c->inter.put[0][3][1][1] = ff_vvc_put_qpel_hv16_8_neon; + c->inter.put[0][4][1][1] = ff_vvc_put_qpel_hv32_8_neon; + 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][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; + c->inter.put[1][4][0][1] = + c->inter.put[1][5][0][1] = + c->inter.put[1][6][0][1] = ff_vvc_put_epel_h32_8_neon; + + c->inter.put[1][1][1][1] = ff_vvc_put_epel_hv4_8_neon; + c->inter.put[1][2][1][1] = ff_vvc_put_epel_hv8_8_neon; + c->inter.put[1][3][1][1] = ff_vvc_put_epel_hv16_8_neon; + c->inter.put[1][4][1][1] = ff_vvc_put_epel_hv32_8_neon; + c->inter.put[1][5][1][1] = ff_vvc_put_epel_hv64_8_neon; + c->inter.put[1][6][1][1] = ff_vvc_put_epel_hv128_8_neon; + + c->inter.put_uni[0][1][0][0] = ff_vvc_put_pel_uni_pixels4_8_neon; + c->inter.put_uni[0][2][0][0] = ff_vvc_put_pel_uni_pixels8_8_neon; + c->inter.put_uni[0][3][0][0] = ff_vvc_put_pel_uni_pixels16_8_neon; + c->inter.put_uni[0][4][0][0] = ff_vvc_put_pel_uni_pixels32_8_neon; + c->inter.put_uni[0][5][0][0] = ff_vvc_put_pel_uni_pixels64_8_neon; + c->inter.put_uni[0][6][0][0] = ff_vvc_put_pel_uni_pixels128_8_neon; + + c->inter.put_uni[0][1][0][1] = ff_vvc_put_qpel_uni_h4_8_neon; + c->inter.put_uni[0][2][0][1] = ff_vvc_put_qpel_uni_h8_8_neon; + c->inter.put_uni[0][3][0][1] = ff_vvc_put_qpel_uni_h16_8_neon; + c->inter.put_uni[0][4][0][1] = + c->inter.put_uni[0][5][0][1] = + c->inter.put_uni[0][6][0][1] = ff_vvc_put_qpel_uni_h32_8_neon; + + c->inter.put_uni_w[0][1][0][0] = ff_vvc_put_pel_uni_w_pixels4_8_neon; + c->inter.put_uni_w[0][2][0][0] = ff_vvc_put_pel_uni_w_pixels8_8_neon; + c->inter.put_uni_w[0][3][0][0] = ff_vvc_put_pel_uni_w_pixels16_8_neon; + c->inter.put_uni_w[0][4][0][0] = ff_vvc_put_pel_uni_w_pixels32_8_neon; + c->inter.put_uni_w[0][5][0][0] = ff_vvc_put_pel_uni_w_pixels64_8_neon; + 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; + + 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.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; + + if (have_i8mm(cpu_flags)) { + c->inter.put[0][1][0][1] = ff_vvc_put_qpel_h4_8_neon_i8mm; + c->inter.put[0][2][0][1] = ff_vvc_put_qpel_h8_8_neon_i8mm; + c->inter.put[0][3][0][1] = ff_vvc_put_qpel_h16_8_neon_i8mm; + c->inter.put[0][4][0][1] = ff_vvc_put_qpel_h32_8_neon_i8mm; + c->inter.put[0][5][0][1] = ff_vvc_put_qpel_h64_8_neon_i8mm; + c->inter.put[0][6][0][1] = ff_vvc_put_qpel_h128_8_neon_i8mm; + + c->inter.put[0][1][1][1] = ff_vvc_put_qpel_hv4_8_neon_i8mm; + c->inter.put[0][2][1][1] = ff_vvc_put_qpel_hv8_8_neon_i8mm; + c->inter.put[0][3][1][1] = ff_vvc_put_qpel_hv16_8_neon_i8mm; + c->inter.put[0][4][1][1] = ff_vvc_put_qpel_hv32_8_neon_i8mm; + c->inter.put[0][5][1][1] = ff_vvc_put_qpel_hv64_8_neon_i8mm; + c->inter.put[0][6][1][1] = ff_vvc_put_qpel_hv128_8_neon_i8mm; + + c->inter.put[1][1][0][1] = ff_vvc_put_epel_h4_8_neon_i8mm; + c->inter.put[1][2][0][1] = ff_vvc_put_epel_h8_8_neon_i8mm; + c->inter.put[1][3][0][1] = ff_vvc_put_epel_h16_8_neon_i8mm; + c->inter.put[1][4][0][1] = ff_vvc_put_epel_h32_8_neon_i8mm; + c->inter.put[1][5][0][1] = ff_vvc_put_epel_h64_8_neon_i8mm; + c->inter.put[1][6][0][1] = ff_vvc_put_epel_h128_8_neon_i8mm; + + c->inter.put[1][1][1][1] = ff_vvc_put_epel_hv4_8_neon_i8mm; + c->inter.put[1][2][1][1] = ff_vvc_put_epel_hv8_8_neon_i8mm; + c->inter.put[1][3][1][1] = ff_vvc_put_epel_hv16_8_neon_i8mm; + c->inter.put[1][4][1][1] = ff_vvc_put_epel_hv32_8_neon_i8mm; + 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; + } + } else if (bd == 10) { + c->inter.avg = ff_vvc_avg_10_neon; + + c->alf.filter[LUMA] = alf_filter_luma_10_neon; + c->alf.filter[CHROMA] = alf_filter_chroma_10_neon; + } else if (bd == 12) { + c->inter.avg = ff_vvc_avg_12_neon; + + c->alf.filter[LUMA] = alf_filter_luma_12_neon; + c->alf.filter[CHROMA] = alf_filter_chroma_12_neon; + } + + c->inter.sad = ff_vvc_sad_neon; +} diff --git a/libavcodec/aarch64/vvc/inter.S b/libavcodec/aarch64/vvc/inter.S new file mode 100644 index 000000000..2f69274b8 --- /dev/null +++ b/libavcodec/aarch64/vvc/inter.S @@ -0,0 +1,163 @@ +/* + * 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/aarch64/asm.S" + +#define VVC_MAX_PB_SIZE 128 + +.macro vvc_avg, bit_depth + +.macro vvc_avg_\bit_depth\()_2_4, tap +.if \tap == 2 + ldr s0, [src0] + ldr s2, [src1] +.else + 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) +.if \bit_depth == 8 + sqxtun v4.8b, v4.8h +.if \tap == 2 + str h4, [dst] +.else // tap == 4 + str s4, [dst] +.endif + +.else // bit_depth > 8 + smin v4.4h, v4.4h, v17.4h + smax v4.4h, v4.4h, v18.4h +.if \tap == 2 + str s4, [dst] +.else + str d4, [dst] +.endif +.endif + add src0, src0, x10 + add src1, src1, x10 + add dst, dst, dst_stride +.endm + +function ff_vvc_avg_\bit_depth\()_neon, export=1 + dst .req x0 + dst_stride .req x1 + src0 .req x2 + src1 .req x3 + width .req w4 + height .req w5 + + 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 + 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 + b.ne 2b + b 32f +4: // width == 4 + subs height, height, #1 + vvc_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) + 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 + st1 {v4.8h}, [dst], dst_stride +.endif + b.ne 8b + b 32f +16: // width >= 16 + mov w6, width + mov x7, src0 + mov x8, src1 + mov x9, dst +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) + 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 + stp q4, q6, [x9], #32 +.endif + b.ne 17b + + subs height, height, #1 + add src0, src0, x10 + add src1, src1, x10 + add dst, dst, dst_stride + b.ne 16b +32: + ret +endfunc +.endm + +vvc_avg 8 +vvc_avg 10 +vvc_avg 12 diff --git a/libavcodec/aarch64/vvc/sad.S b/libavcodec/aarch64/vvc/sad.S new file mode 100644 index 000000000..beca876fa --- /dev/null +++ b/libavcodec/aarch64/vvc/sad.S @@ -0,0 +1,75 @@ +/* + * 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/aarch64/asm.S" + +#define VVC_MAX_PB_SIZE 128 + +function ff_vvc_sad_neon, export=1 + src0 .req x0 + src1 .req x1 + dx .req w2 + dy .req w3 + block_w .req w4 + block_h .req w5 + + sub w7, dx, #4 + sub w8, dy, #4 + add w6, dx, dy, lsl #7 + add w7, w7, w8, lsl #7 + sxtw x6, w6 + sxtw x7, w7 + add src0, src0, x6, lsl #1 + sub src1, src1, x7, lsl #1 + + cmp block_w, #16 + movi v16.4s, #0 + b.ge 2f +1: + // block_w == 8 + ldr q0, [src0] + ldr q2, [src1] + subs block_h, block_h, #2 + sabal v16.4s, v0.4h, v2.4h + sabal2 v16.4s, v0.8h, v2.8h + + add src0, src0, #(2 * VVC_MAX_PB_SIZE * 2) + add src1, src1, #(2 * VVC_MAX_PB_SIZE * 2) + b.ne 1b + b 4f +2: + // block_w == 16, no block_w > 16 according the spec + movi v17.4s, #0 +3: + ldp q0, q1, [src0], #(2 * VVC_MAX_PB_SIZE * 2) + ldp q2, q3, [src1], #(2 * VVC_MAX_PB_SIZE * 2) + subs block_h, block_h, #2 + sabal v16.4s, v0.4h, v2.4h + sabal2 v16.4s, v0.8h, v2.8h + sabal v17.4s, v1.4h, v3.4h + sabal2 v17.4s, v1.8h, v3.8h + + b.ne 3b + add v16.4s, v16.4s, v17.4s +4: + addv s16, v16.4s + mov w0, v16.s[0] + ret +endfunc diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c index 283139288..69989690d 100644 --- a/libavcodec/ac3_parser.c +++ b/libavcodec/ac3_parser.c @@ -20,10 +20,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" #include "config_components.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "parser.h" #include "ac3defs.h" #include "ac3tab.h" @@ -81,12 +81,12 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) hdr->sync_word = get_bits(gbc, 16); if(hdr->sync_word != 0x0B77) - return AAC_AC3_PARSE_ERROR_SYNC; + return AC3_PARSE_ERROR_SYNC; /* read ahead to bsid to distinguish between AC-3 and E-AC-3 */ hdr->bitstream_id = show_bits_long(gbc, 29) & 0x1F; if(hdr->bitstream_id > 16) - return AAC_AC3_PARSE_ERROR_BSID; + return AC3_PARSE_ERROR_BSID; hdr->num_blocks = 6; hdr->ac3_bit_rate_code = -1; @@ -103,11 +103,11 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) hdr->crc1 = get_bits(gbc, 16); hdr->sr_code = get_bits(gbc, 2); if(hdr->sr_code == 3) - return AAC_AC3_PARSE_ERROR_SAMPLE_RATE; + return AC3_PARSE_ERROR_SAMPLE_RATE; frame_size_code = get_bits(gbc, 6); if(frame_size_code > 37) - return AAC_AC3_PARSE_ERROR_FRAME_SIZE; + return AC3_PARSE_ERROR_FRAME_SIZE; hdr->ac3_bit_rate_code = (frame_size_code >> 1); @@ -138,19 +138,19 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) hdr->crc1 = 0; hdr->frame_type = get_bits(gbc, 2); if(hdr->frame_type == EAC3_FRAME_TYPE_RESERVED) - return AAC_AC3_PARSE_ERROR_FRAME_TYPE; + return AC3_PARSE_ERROR_FRAME_TYPE; hdr->substreamid = get_bits(gbc, 3); hdr->frame_size = (get_bits(gbc, 11) + 1) << 1; if(hdr->frame_size < AC3_HEADER_SIZE) - return AAC_AC3_PARSE_ERROR_FRAME_SIZE; + return AC3_PARSE_ERROR_FRAME_SIZE; hdr->sr_code = get_bits(gbc, 2); if (hdr->sr_code == 3) { int sr_code2 = get_bits(gbc, 2); if(sr_code2 == 3) - return AAC_AC3_PARSE_ERROR_SAMPLE_RATE; + return AC3_PARSE_ERROR_SAMPLE_RATE; hdr->sample_rate = ff_ac3_sample_rate_tab[sr_code2] / 2; hdr->sr_shift = 1; } else { diff --git a/libavcodec/ac3_parser_internal.h b/libavcodec/ac3_parser_internal.h index 2ac0e67ec..46814bfb1 100644 --- a/libavcodec/ac3_parser_internal.h +++ b/libavcodec/ac3_parser_internal.h @@ -64,15 +64,22 @@ typedef struct AC3HeaderInfo { /** @} */ } AC3HeaderInfo; +typedef enum { + AC3_PARSE_ERROR_SYNC = -0x1030c0a, + AC3_PARSE_ERROR_BSID = -0x2030c0a, + AC3_PARSE_ERROR_SAMPLE_RATE = -0x3030c0a, + AC3_PARSE_ERROR_FRAME_SIZE = -0x4030c0a, + AC3_PARSE_ERROR_FRAME_TYPE = -0x5030c0a, + AC3_PARSE_ERROR_CRC = -0x6030c0a, +} AC3ParseError; + /** * Parse AC-3 frame header. * Parse the header up to the lfeon element, which is the first 52 or 54 bits * depending on the audio coding mode. * @param[in] gbc BitContext containing the first 54 bits of the frame. * @param[out] hdr Pointer to struct where header info is written. - * @return Returns 0 on success, -1 if there is a sync word mismatch, - * -2 if the bsid (version) element is invalid, -3 if the fscod (sample rate) - * element is invalid, or -4 if the frmsizecod (bit rate) element is invalid. + * @return 0 on success and AC3_PARSE_ERROR_* values otherwise. */ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr); diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c index 504c75cdd..3cc20f32a 100644 --- a/libavcodec/ac3dec.c +++ b/libavcodec/ac3dec.c @@ -35,10 +35,10 @@ #include "libavutil/crc.h" #include "libavutil/downmix_info.h" #include "libavutil/intmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/thread.h" #include "bswapdsp.h" -#include "aac_ac3_parser.h" #include "ac3_parser_internal.h" #include "ac3dec.h" #include "ac3dec_data.h" @@ -199,7 +199,6 @@ static void ac3_downmix(AVCodecContext *avctx) av_channel_layout_uninit(&avctx->ch_layout); avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; } - s->downmixed = 1; } /** @@ -241,6 +240,7 @@ static av_cold int ac3_decode_init(AVCodecContext *avctx) avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; ac3_downmix(avctx); + s->downmixed = 1; for (i = 0; i < AC3_MAX_CHANNELS; i++) { s->xcfptr[i] = s->transform_coeffs[i]; @@ -1537,19 +1537,19 @@ dependent_frame: if (err) { switch (err) { - case AAC_AC3_PARSE_ERROR_SYNC: + case AC3_PARSE_ERROR_SYNC: av_log(avctx, AV_LOG_ERROR, "frame sync error\n"); return AVERROR_INVALIDDATA; - case AAC_AC3_PARSE_ERROR_BSID: + case AC3_PARSE_ERROR_BSID: av_log(avctx, AV_LOG_ERROR, "invalid bitstream id\n"); break; - case AAC_AC3_PARSE_ERROR_SAMPLE_RATE: + case AC3_PARSE_ERROR_SAMPLE_RATE: av_log(avctx, AV_LOG_ERROR, "invalid sample rate\n"); break; - case AAC_AC3_PARSE_ERROR_FRAME_SIZE: + case AC3_PARSE_ERROR_FRAME_SIZE: av_log(avctx, AV_LOG_ERROR, "invalid frame size\n"); break; - case AAC_AC3_PARSE_ERROR_FRAME_TYPE: + case AC3_PARSE_ERROR_FRAME_TYPE: /* skip frame if CRC is ok. otherwise use error concealment. */ /* TODO: add support for substreams */ if (s->substreamid) { @@ -1562,8 +1562,7 @@ dependent_frame: av_log(avctx, AV_LOG_ERROR, "invalid frame type\n"); } break; - case AAC_AC3_PARSE_ERROR_CRC: - case AAC_AC3_PARSE_ERROR_CHANNEL_CFG: + case AC3_PARSE_ERROR_CRC: break; default: // Normal AVERROR do not try to recover. *got_frame_ptr = 0; @@ -1573,7 +1572,7 @@ dependent_frame: /* check that reported frame size fits in input buffer */ if (s->frame_size > buf_size) { av_log(avctx, AV_LOG_ERROR, "incomplete frame\n"); - err = AAC_AC3_PARSE_ERROR_FRAME_SIZE; + err = AC3_PARSE_ERROR_FRAME_SIZE; } else if (avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_CAREFUL)) { /* check for crc mismatch */ if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, &buf[2], @@ -1581,7 +1580,7 @@ dependent_frame: av_log(avctx, AV_LOG_ERROR, "frame CRC mismatch\n"); if (avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_INVALIDDATA; - err = AAC_AC3_PARSE_ERROR_CRC; + err = AC3_PARSE_ERROR_CRC; } } } diff --git a/libavcodec/ac3dsp.c b/libavcodec/ac3dsp.c index 8397e03d3..730fa70ff 100644 --- a/libavcodec/ac3dsp.c +++ b/libavcodec/ac3dsp.c @@ -389,7 +389,9 @@ av_cold void ff_ac3dsp_init(AC3DSPContext *c) c->downmix = NULL; c->downmix_fixed = NULL; -#if ARCH_ARM +#if ARCH_AARCH64 + ff_ac3dsp_init_aarch64(c); +#elif ARCH_ARM ff_ac3dsp_init_arm(c); #elif ARCH_X86 ff_ac3dsp_init_x86(c); diff --git a/libavcodec/ac3dsp.h b/libavcodec/ac3dsp.h index ae33b361a..b1b2bced8 100644 --- a/libavcodec/ac3dsp.h +++ b/libavcodec/ac3dsp.h @@ -106,7 +106,8 @@ typedef struct AC3DSPContext { void (*downmix_fixed)(int32_t **samples, int16_t **matrix, int len); } AC3DSPContext; -void ff_ac3dsp_init (AC3DSPContext *c); +void ff_ac3dsp_init(AC3DSPContext *c); +void ff_ac3dsp_init_aarch64(AC3DSPContext *c); void ff_ac3dsp_init_arm(AC3DSPContext *c); void ff_ac3dsp_init_x86(AC3DSPContext *c); void ff_ac3dsp_init_mips(AC3DSPContext *c); diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index ff43088df..364928986 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -30,11 +30,11 @@ #include "libavutil/attributes.h" #include "libavutil/avassert.h" -#include "libavutil/avstring.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" #include "libavutil/opt.h" #include "libavutil/thread.h" @@ -52,6 +52,9 @@ #include "ac3enc.h" #include "eac3enc.h" +#define SAMPLETYPE_SIZE(ctx) (sizeof(float) == sizeof(int32_t) ? sizeof(float) : \ + (ctx)->fixed_point ? sizeof(int32_t) : sizeof(float)) + typedef struct AC3Mant { int16_t *qmant1_ptr, *qmant2_ptr, *qmant4_ptr; ///< mantissa pointers for bap=1,2,4 int mant1_cnt, mant2_cnt, mant4_cnt; ///< mantissa counts for bap=1,2,4 @@ -273,13 +276,222 @@ static const int8_t ac3_coupling_start_tab[6][3][19] = { }; +#define FLT_OPTION_THRESHOLD 0.01 + +static int validate_float_option(float v, const float *v_list, int v_list_size) +{ + int i; + + for (i = 0; i < v_list_size; i++) { + if (v < (v_list[i] + FLT_OPTION_THRESHOLD) && + v > (v_list[i] - FLT_OPTION_THRESHOLD)) + break; + } + if (i == v_list_size) + return AVERROR(EINVAL); + + return i; +} + + +static void validate_mix_level(void *log_ctx, const char *opt_name, + float *opt_param, const float *list, + int list_size, int default_value, int min_value, + int *ctx_param) +{ + int mixlev = validate_float_option(*opt_param, list, list_size); + if (mixlev < min_value) { + mixlev = default_value; + if (*opt_param >= 0.0) { + av_log(log_ctx, AV_LOG_WARNING, "requested %s is not valid. using " + "default value: %0.3f\n", opt_name, list[mixlev]); + } + } + *opt_param = list[mixlev]; + *ctx_param = mixlev; +} + + +/** + * Validate metadata options as set by AVOption system. + * These values can optionally be changed per-frame. + * + * @param s AC-3 encoder private context + */ +static int ac3_validate_metadata(AC3EncodeContext *s) +{ + AVCodecContext *avctx = s->avctx; + AC3EncOptions *opt = &s->options; + + opt->audio_production_info = 0; + opt->extended_bsi_1 = 0; + opt->extended_bsi_2 = 0; + opt->eac3_mixing_metadata = 0; + opt->eac3_info_metadata = 0; + + /* determine mixing metadata / xbsi1 use */ + if (s->channel_mode > AC3_CHMODE_STEREO && opt->preferred_stereo_downmix != AC3ENC_OPT_NONE) { + opt->extended_bsi_1 = 1; + opt->eac3_mixing_metadata = 1; + } + if (s->has_center && + (opt->ltrt_center_mix_level >= 0 || opt->loro_center_mix_level >= 0)) { + opt->extended_bsi_1 = 1; + opt->eac3_mixing_metadata = 1; + } + if (s->has_surround && + (opt->ltrt_surround_mix_level >= 0 || opt->loro_surround_mix_level >= 0)) { + opt->extended_bsi_1 = 1; + opt->eac3_mixing_metadata = 1; + } + + if (s->eac3) { + /* determine info metadata use */ + if (avctx->audio_service_type != AV_AUDIO_SERVICE_TYPE_MAIN) + opt->eac3_info_metadata = 1; + if (opt->copyright != AC3ENC_OPT_NONE || opt->original != AC3ENC_OPT_NONE) + opt->eac3_info_metadata = 1; + if (s->channel_mode == AC3_CHMODE_STEREO && + (opt->dolby_headphone_mode != AC3ENC_OPT_NONE || opt->dolby_surround_mode != AC3ENC_OPT_NONE)) + opt->eac3_info_metadata = 1; + if (s->channel_mode >= AC3_CHMODE_2F2R && opt->dolby_surround_ex_mode != AC3ENC_OPT_NONE) + opt->eac3_info_metadata = 1; + if (opt->mixing_level != AC3ENC_OPT_NONE || opt->room_type != AC3ENC_OPT_NONE || + opt->ad_converter_type != AC3ENC_OPT_NONE) { + opt->audio_production_info = 1; + opt->eac3_info_metadata = 1; + } + } else { + /* determine audio production info use */ + if (opt->mixing_level != AC3ENC_OPT_NONE || opt->room_type != AC3ENC_OPT_NONE) + opt->audio_production_info = 1; + + /* determine xbsi2 use */ + if (s->channel_mode >= AC3_CHMODE_2F2R && opt->dolby_surround_ex_mode != AC3ENC_OPT_NONE) + opt->extended_bsi_2 = 1; + if (s->channel_mode == AC3_CHMODE_STEREO && opt->dolby_headphone_mode != AC3ENC_OPT_NONE) + opt->extended_bsi_2 = 1; + if (opt->ad_converter_type != AC3ENC_OPT_NONE) + opt->extended_bsi_2 = 1; + } + + /* validate AC-3 mixing levels */ + if (!s->eac3) { + if (s->has_center) { + validate_mix_level(avctx, "center_mix_level", &opt->center_mix_level, + cmixlev_options, CMIXLEV_NUM_OPTIONS, 1, 0, + &s->center_mix_level); + } + if (s->has_surround) { + validate_mix_level(avctx, "surround_mix_level", &opt->surround_mix_level, + surmixlev_options, SURMIXLEV_NUM_OPTIONS, 1, 0, + &s->surround_mix_level); + } + } + + /* validate extended bsi 1 / mixing metadata */ + if (opt->extended_bsi_1 || opt->eac3_mixing_metadata) { + /* default preferred stereo downmix */ + if (opt->preferred_stereo_downmix == AC3ENC_OPT_NONE) + opt->preferred_stereo_downmix = AC3ENC_OPT_NOT_INDICATED; + if (!s->eac3 || s->has_center) { + /* validate Lt/Rt center mix level */ + validate_mix_level(avctx, "ltrt_center_mix_level", + &opt->ltrt_center_mix_level, extmixlev_options, + EXTMIXLEV_NUM_OPTIONS, 5, 0, + &s->ltrt_center_mix_level); + /* validate Lo/Ro center mix level */ + validate_mix_level(avctx, "loro_center_mix_level", + &opt->loro_center_mix_level, extmixlev_options, + EXTMIXLEV_NUM_OPTIONS, 5, 0, + &s->loro_center_mix_level); + } + if (!s->eac3 || s->has_surround) { + /* validate Lt/Rt surround mix level */ + validate_mix_level(avctx, "ltrt_surround_mix_level", + &opt->ltrt_surround_mix_level, extmixlev_options, + EXTMIXLEV_NUM_OPTIONS, 6, 3, + &s->ltrt_surround_mix_level); + /* validate Lo/Ro surround mix level */ + validate_mix_level(avctx, "loro_surround_mix_level", + &opt->loro_surround_mix_level, extmixlev_options, + EXTMIXLEV_NUM_OPTIONS, 6, 3, + &s->loro_surround_mix_level); + } + } + + /* validate audio service type / channels combination */ + if ((avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_KARAOKE && + avctx->ch_layout.nb_channels == 1) || + ((avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_COMMENTARY || + avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_EMERGENCY || + avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_VOICE_OVER) + && avctx->ch_layout.nb_channels > 1)) { + av_log(avctx, AV_LOG_ERROR, "invalid audio service type for the " + "specified number of channels\n"); + return AVERROR(EINVAL); + } + + /* validate extended bsi 2 / info metadata */ + if (opt->extended_bsi_2 || opt->eac3_info_metadata) { + /* default dolby headphone mode */ + if (opt->dolby_headphone_mode == AC3ENC_OPT_NONE) + opt->dolby_headphone_mode = AC3ENC_OPT_NOT_INDICATED; + /* default dolby surround ex mode */ + if (opt->dolby_surround_ex_mode == AC3ENC_OPT_NONE) + opt->dolby_surround_ex_mode = AC3ENC_OPT_NOT_INDICATED; + /* default A/D converter type */ + if (opt->ad_converter_type == AC3ENC_OPT_NONE) + opt->ad_converter_type = AC3ENC_OPT_ADCONV_STANDARD; + } + + /* copyright & original defaults */ + if (!s->eac3 || opt->eac3_info_metadata) { + /* default copyright */ + if (opt->copyright == AC3ENC_OPT_NONE) + opt->copyright = AC3ENC_OPT_OFF; + /* default original */ + if (opt->original == AC3ENC_OPT_NONE) + opt->original = AC3ENC_OPT_ON; + } + + /* dolby surround mode default */ + if (!s->eac3 || opt->eac3_info_metadata) { + if (opt->dolby_surround_mode == AC3ENC_OPT_NONE) + opt->dolby_surround_mode = AC3ENC_OPT_NOT_INDICATED; + } + + /* validate audio production info */ + if (opt->audio_production_info) { + if (opt->mixing_level == AC3ENC_OPT_NONE) { + av_log(avctx, AV_LOG_ERROR, "mixing_level must be set if " + "room_type is set\n"); + return AVERROR(EINVAL); + } + if (opt->mixing_level < 80) { + av_log(avctx, AV_LOG_ERROR, "invalid mixing level. must be between " + "80dB and 111dB\n"); + return AVERROR(EINVAL); + } + /* default room type */ + if (opt->room_type == AC3ENC_OPT_NONE) + opt->room_type = AC3ENC_OPT_NOT_INDICATED; + } + + /* set bitstream id for alternate bitstream syntax */ + if (!s->eac3 && (opt->extended_bsi_1 || opt->extended_bsi_2)) + s->bitstream_id = 6; + + return 0; +} + /** * Adjust the frame size to make the average bit rate match the target bit rate. * This is only needed for 11025, 22050, and 44100 sample rates or any E-AC-3. * * @param s AC-3 encoder private context */ -void ff_ac3_adjust_frame_size(AC3EncodeContext *s) +static void ac3_adjust_frame_size(AC3EncodeContext *s) { while (s->bits_written >= s->bit_rate && s->samples_written >= s->sample_rate) { s->bits_written -= s->bit_rate; @@ -291,7 +503,6 @@ void ff_ac3_adjust_frame_size(AC3EncodeContext *s) s->samples_written += AC3_BLOCK_SIZE * s->num_blocks; } - /** * Set the initial coupling strategy parameters prior to coupling analysis. * @@ -874,8 +1085,8 @@ static av_cold void bit_alloc_init(AC3EncodeContext *s) /* compute real values */ /* currently none of these values change during encoding, so we can just set them once at initialization */ - s->bit_alloc.slow_decay = ff_ac3_slow_decay_tab[s->slow_decay_code] >> s->bit_alloc.sr_shift; - s->bit_alloc.fast_decay = ff_ac3_fast_decay_tab[s->fast_decay_code] >> s->bit_alloc.sr_shift; + s->bit_alloc.slow_decay = ff_ac3_slow_decay_tab[s->slow_decay_code]; + s->bit_alloc.fast_decay = ff_ac3_fast_decay_tab[s->fast_decay_code]; s->bit_alloc.slow_gain = ff_ac3_slow_gain_tab[s->slow_gain_code]; s->bit_alloc.db_per_bit = ff_ac3_db_per_bit_tab[s->db_per_bit_code]; s->bit_alloc.floor = ff_ac3_floor_tab[s->floor_code]; @@ -1423,63 +1634,63 @@ static void ac3_quantize_mantissas(AC3EncodeContext *s) /* * Write the AC-3 frame header to the output bitstream. */ -static void ac3_output_frame_header(AC3EncodeContext *s) +static void ac3_output_frame_header(AC3EncodeContext *s, PutBitContext *pb) { AC3EncOptions *opt = &s->options; - put_bits(&s->pb, 16, 0x0b77); /* frame header */ - put_bits(&s->pb, 16, 0); /* crc1: will be filled later */ - put_bits(&s->pb, 2, s->bit_alloc.sr_code); - put_bits(&s->pb, 6, s->frame_size_code + (s->frame_size - s->frame_size_min) / 2); - put_bits(&s->pb, 5, s->bitstream_id); - put_bits(&s->pb, 3, s->bitstream_mode); - put_bits(&s->pb, 3, s->channel_mode); + 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); + put_bits(pb, 6, s->frame_size_code + (s->frame_size - s->frame_size_min) / 2); + put_bits(pb, 5, s->bitstream_id); + put_bits(pb, 3, s->bitstream_mode); + put_bits(pb, 3, s->channel_mode); if ((s->channel_mode & 0x01) && s->channel_mode != AC3_CHMODE_MONO) - put_bits(&s->pb, 2, s->center_mix_level); + put_bits(pb, 2, s->center_mix_level); if (s->channel_mode & 0x04) - put_bits(&s->pb, 2, s->surround_mix_level); + put_bits(pb, 2, s->surround_mix_level); if (s->channel_mode == AC3_CHMODE_STEREO) - put_bits(&s->pb, 2, opt->dolby_surround_mode); - put_bits(&s->pb, 1, s->lfe_on); /* LFE */ - put_bits(&s->pb, 5, -opt->dialogue_level); - put_bits(&s->pb, 1, 0); /* no compression control word */ - put_bits(&s->pb, 1, 0); /* no lang code */ - put_bits(&s->pb, 1, opt->audio_production_info); + put_bits(pb, 2, opt->dolby_surround_mode); + put_bits(pb, 1, s->lfe_on); /* LFE */ + put_bits(pb, 5, -opt->dialogue_level); + put_bits(pb, 1, 0); /* no compression control word */ + put_bits(pb, 1, 0); /* no lang code */ + put_bits(pb, 1, opt->audio_production_info); if (opt->audio_production_info) { - put_bits(&s->pb, 5, opt->mixing_level - 80); - put_bits(&s->pb, 2, opt->room_type); + put_bits(pb, 5, opt->mixing_level - 80); + put_bits(pb, 2, opt->room_type); } - put_bits(&s->pb, 1, opt->copyright); - put_bits(&s->pb, 1, opt->original); + put_bits(pb, 1, opt->copyright); + put_bits(pb, 1, opt->original); if (s->bitstream_id == 6) { /* alternate bit stream syntax */ - put_bits(&s->pb, 1, opt->extended_bsi_1); + put_bits(pb, 1, opt->extended_bsi_1); if (opt->extended_bsi_1) { - put_bits(&s->pb, 2, opt->preferred_stereo_downmix); - put_bits(&s->pb, 3, s->ltrt_center_mix_level); - put_bits(&s->pb, 3, s->ltrt_surround_mix_level); - put_bits(&s->pb, 3, s->loro_center_mix_level); - put_bits(&s->pb, 3, s->loro_surround_mix_level); + put_bits(pb, 2, opt->preferred_stereo_downmix); + put_bits(pb, 3, s->ltrt_center_mix_level); + put_bits(pb, 3, s->ltrt_surround_mix_level); + put_bits(pb, 3, s->loro_center_mix_level); + put_bits(pb, 3, s->loro_surround_mix_level); } - put_bits(&s->pb, 1, opt->extended_bsi_2); + put_bits(pb, 1, opt->extended_bsi_2); if (opt->extended_bsi_2) { - put_bits(&s->pb, 2, opt->dolby_surround_ex_mode); - put_bits(&s->pb, 2, opt->dolby_headphone_mode); - put_bits(&s->pb, 1, opt->ad_converter_type); - put_bits(&s->pb, 9, 0); /* xbsi2 and encinfo : reserved */ + put_bits(pb, 2, opt->dolby_surround_ex_mode); + put_bits(pb, 2, opt->dolby_headphone_mode); + put_bits(pb, 1, opt->ad_converter_type); + put_bits(pb, 9, 0); /* xbsi2 and encinfo : reserved */ } } else { - put_bits(&s->pb, 1, 0); /* no time code 1 */ - put_bits(&s->pb, 1, 0); /* no time code 2 */ + put_bits(pb, 1, 0); /* no time code 1 */ + put_bits(pb, 1, 0); /* no time code 2 */ } - put_bits(&s->pb, 1, 0); /* no additional bit stream info */ + put_bits(pb, 1, 0); /* no additional bit stream info */ } /* * Write one audio block to the output bitstream. */ -static void output_audio_block(AC3EncodeContext *s, int blk) +static void output_audio_block(AC3EncodeContext *s, PutBitContext *pb, int blk) { int ch, i, baie, bnd, got_cpl, av_uninit(ch0); AC3Block *block = &s->blocks[blk]; @@ -1487,48 +1698,48 @@ static void output_audio_block(AC3EncodeContext *s, int blk) /* block switching */ if (!s->eac3) { for (ch = 0; ch < s->fbw_channels; ch++) - put_bits(&s->pb, 1, 0); + put_bits(pb, 1, 0); } /* dither flags */ if (!s->eac3) { for (ch = 0; ch < s->fbw_channels; ch++) - put_bits(&s->pb, 1, 1); + put_bits(pb, 1, 1); } /* dynamic range codes */ - put_bits(&s->pb, 1, 0); + put_bits(pb, 1, 0); /* spectral extension */ if (s->eac3) - put_bits(&s->pb, 1, 0); + put_bits(pb, 1, 0); /* channel coupling */ if (!s->eac3) - put_bits(&s->pb, 1, block->new_cpl_strategy); + put_bits(pb, 1, block->new_cpl_strategy); if (block->new_cpl_strategy) { if (!s->eac3) - put_bits(&s->pb, 1, block->cpl_in_use); + put_bits(pb, 1, block->cpl_in_use); if (block->cpl_in_use) { int start_sub, end_sub; if (s->eac3) - put_bits(&s->pb, 1, 0); /* enhanced coupling */ + put_bits(pb, 1, 0); /* enhanced coupling */ if (!s->eac3 || s->channel_mode != AC3_CHMODE_STEREO) { for (ch = 1; ch <= s->fbw_channels; ch++) - put_bits(&s->pb, 1, block->channel_in_cpl[ch]); + put_bits(pb, 1, block->channel_in_cpl[ch]); } if (s->channel_mode == AC3_CHMODE_STEREO) - put_bits(&s->pb, 1, 0); /* phase flags in use */ + put_bits(pb, 1, 0); /* phase flags in use */ start_sub = (s->start_freq[CPL_CH] - 37) / 12; end_sub = (s->cpl_end_freq - 37) / 12; - put_bits(&s->pb, 4, start_sub); - put_bits(&s->pb, 4, end_sub - 3); + put_bits(pb, 4, start_sub); + put_bits(pb, 4, end_sub - 3); /* coupling band structure */ if (s->eac3) { - put_bits(&s->pb, 1, 0); /* use default */ + put_bits(pb, 1, 0); /* use default */ } else { for (bnd = start_sub+1; bnd < end_sub; bnd++) - put_bits(&s->pb, 1, ff_eac3_default_cpl_band_struct[bnd]); + put_bits(pb, 1, ff_eac3_default_cpl_band_struct[bnd]); } } } @@ -1538,12 +1749,12 @@ static void output_audio_block(AC3EncodeContext *s, int blk) for (ch = 1; ch <= s->fbw_channels; ch++) { if (block->channel_in_cpl[ch]) { if (!s->eac3 || block->new_cpl_coords[ch] != 2) - put_bits(&s->pb, 1, block->new_cpl_coords[ch]); + put_bits(pb, 1, block->new_cpl_coords[ch]); if (block->new_cpl_coords[ch]) { - put_bits(&s->pb, 2, block->cpl_master_exp[ch]); + put_bits(pb, 2, block->cpl_master_exp[ch]); for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { - put_bits(&s->pb, 4, block->cpl_coord_exp [ch][bnd]); - put_bits(&s->pb, 4, block->cpl_coord_mant[ch][bnd]); + put_bits(pb, 4, block->cpl_coord_exp [ch][bnd]); + put_bits(pb, 4, block->cpl_coord_mant[ch][bnd]); } } } @@ -1553,26 +1764,26 @@ static void output_audio_block(AC3EncodeContext *s, int blk) /* stereo rematrixing */ if (s->channel_mode == AC3_CHMODE_STEREO) { if (!s->eac3 || blk > 0) - put_bits(&s->pb, 1, block->new_rematrixing_strategy); + put_bits(pb, 1, block->new_rematrixing_strategy); if (block->new_rematrixing_strategy) { /* rematrixing flags */ for (bnd = 0; bnd < block->num_rematrixing_bands; bnd++) - put_bits(&s->pb, 1, block->rematrixing_flags[bnd]); + put_bits(pb, 1, block->rematrixing_flags[bnd]); } } /* exponent strategy */ if (!s->eac3) { for (ch = !block->cpl_in_use; ch <= s->fbw_channels; ch++) - put_bits(&s->pb, 2, s->exp_strategy[ch][blk]); + put_bits(pb, 2, s->exp_strategy[ch][blk]); if (s->lfe_on) - put_bits(&s->pb, 1, s->exp_strategy[s->lfe_channel][blk]); + put_bits(pb, 1, s->exp_strategy[s->lfe_channel][blk]); } /* bandwidth */ for (ch = 1; ch <= s->fbw_channels; ch++) { if (s->exp_strategy[ch][blk] != EXP_REUSE && !block->channel_in_cpl[ch]) - put_bits(&s->pb, 6, s->bandwidth_code); + put_bits(pb, 6, s->bandwidth_code); } /* exponents */ @@ -1584,58 +1795,58 @@ static void output_audio_block(AC3EncodeContext *s, int blk) continue; /* DC exponent */ - put_bits(&s->pb, 4, block->grouped_exp[ch][0] >> cpl); + put_bits(pb, 4, block->grouped_exp[ch][0] >> cpl); /* exponent groups */ nb_groups = exponent_group_tab[cpl][s->exp_strategy[ch][blk]-1][block->end_freq[ch]-s->start_freq[ch]]; for (i = 1; i <= nb_groups; i++) - put_bits(&s->pb, 7, block->grouped_exp[ch][i]); + put_bits(pb, 7, block->grouped_exp[ch][i]); /* gain range info */ if (ch != s->lfe_channel && !cpl) - put_bits(&s->pb, 2, 0); + put_bits(pb, 2, 0); } /* bit allocation info */ if (!s->eac3) { baie = (blk == 0); - put_bits(&s->pb, 1, baie); + put_bits(pb, 1, baie); if (baie) { - put_bits(&s->pb, 2, s->slow_decay_code); - put_bits(&s->pb, 2, s->fast_decay_code); - put_bits(&s->pb, 2, s->slow_gain_code); - put_bits(&s->pb, 2, s->db_per_bit_code); - put_bits(&s->pb, 3, s->floor_code); + put_bits(pb, 2, s->slow_decay_code); + put_bits(pb, 2, s->fast_decay_code); + put_bits(pb, 2, s->slow_gain_code); + put_bits(pb, 2, s->db_per_bit_code); + put_bits(pb, 3, s->floor_code); } } /* snr offset */ if (!s->eac3) { - put_bits(&s->pb, 1, block->new_snr_offsets); + put_bits(pb, 1, block->new_snr_offsets); if (block->new_snr_offsets) { - put_bits(&s->pb, 6, s->coarse_snr_offset); + put_bits(pb, 6, s->coarse_snr_offset); for (ch = !block->cpl_in_use; ch <= s->channels; ch++) { - put_bits(&s->pb, 4, s->fine_snr_offset[ch]); - put_bits(&s->pb, 3, s->fast_gain_code[ch]); + put_bits(pb, 4, s->fine_snr_offset[ch]); + put_bits(pb, 3, s->fast_gain_code[ch]); } } } else { - put_bits(&s->pb, 1, 0); /* no converter snr offset */ + put_bits(pb, 1, 0); /* no converter snr offset */ } /* coupling leak */ if (block->cpl_in_use) { if (!s->eac3 || block->new_cpl_leak != 2) - put_bits(&s->pb, 1, block->new_cpl_leak); + put_bits(pb, 1, block->new_cpl_leak); if (block->new_cpl_leak) { - put_bits(&s->pb, 3, s->bit_alloc.cpl_fast_leak); - put_bits(&s->pb, 3, s->bit_alloc.cpl_slow_leak); + put_bits(pb, 3, s->bit_alloc.cpl_fast_leak); + put_bits(pb, 3, s->bit_alloc.cpl_slow_leak); } } if (!s->eac3) { - put_bits(&s->pb, 1, 0); /* no delta bit allocation */ - put_bits(&s->pb, 1, 0); /* no data to skip */ + put_bits(pb, 1, 0); /* no delta bit allocation */ + put_bits(pb, 1, 0); /* no data to skip */ } /* mantissas */ @@ -1653,13 +1864,13 @@ static void output_audio_block(AC3EncodeContext *s, int blk) b = s->ref_bap[ch][blk][i]; switch (b) { case 0: break; - case 1: if (q != 128) put_bits (&s->pb, 5, q); break; - case 2: if (q != 128) put_bits (&s->pb, 7, q); break; - case 3: put_sbits(&s->pb, 3, q); break; - case 4: if (q != 128) put_bits (&s->pb, 7, q); break; - case 14: put_sbits(&s->pb, 14, q); break; - case 15: put_sbits(&s->pb, 16, q); break; - default: put_sbits(&s->pb, b-1, q); break; + case 1: if (q != 128) put_bits (pb, 5, q); break; + case 2: if (q != 128) put_bits (pb, 7, q); break; + case 3: put_sbits(pb, 3, q); break; + case 4: if (q != 128) put_bits (pb, 7, q); break; + case 14: put_sbits(pb, 14, q); break; + case 15: put_sbits(pb, 16, q); break; + default: put_sbits(pb, b-1, q); break; } } if (ch == CPL_CH) @@ -1706,26 +1917,26 @@ static unsigned int pow_poly(unsigned int a, unsigned int n, unsigned int poly) /* * Fill the end of the frame with 0's and compute the two CRCs. */ -static void output_frame_end(AC3EncodeContext *s) +static void output_frame_end(AC3EncodeContext *s, PutBitContext *pb) { const AVCRC *crc_ctx = av_crc_get_table(AV_CRC_16_ANSI); - int frame_size_58, pad_bytes, crc1, crc2_partial, crc2, crc_inv; + int frame_size_58, pad_bytes, crc1, crc2, crc_inv; uint8_t *frame; frame_size_58 = ((s->frame_size >> 2) + (s->frame_size >> 4)) << 1; /* pad the remainder of the frame with zeros */ - av_assert2(s->frame_size * 8 - put_bits_count(&s->pb) >= 18); - flush_put_bits(&s->pb); - frame = s->pb.buf; - pad_bytes = s->frame_size - (put_bits_ptr(&s->pb) - frame) - 2; + av_assert2(s->frame_size * 8 - put_bits_count(pb) >= 18); + flush_put_bits(pb); + frame = pb->buf; + pad_bytes = s->frame_size - (put_bits_ptr(pb) - frame) - 2; av_assert2(pad_bytes >= 0); if (pad_bytes > 0) - memset(put_bits_ptr(&s->pb), 0, pad_bytes); + memset(put_bits_ptr(pb), 0, pad_bytes); if (s->eac3) { /* compute crc2 */ - crc2_partial = av_crc(crc_ctx, 0, frame + 2, s->frame_size - 5); + crc2 = av_crc(crc_ctx, 0, frame + 2, s->frame_size - 4); } else { /* compute crc1 */ /* this is not so easy because it is at the beginning of the data... */ @@ -1735,16 +1946,17 @@ static void output_frame_end(AC3EncodeContext *s) AV_WB16(frame + 2, crc1); /* compute crc2 */ - crc2_partial = av_crc(crc_ctx, 0, frame + frame_size_58, - s->frame_size - frame_size_58 - 3); - } - crc2 = av_crc(crc_ctx, crc2_partial, frame + s->frame_size - 3, 1); - /* ensure crc2 does not match sync word by flipping crcrsv bit if needed */ - if (crc2 == 0x770B) { - frame[s->frame_size - 3] ^= 0x1; - crc2 = av_crc(crc_ctx, crc2_partial, frame + s->frame_size - 3, 1); + crc2 = av_crc(crc_ctx, 0, frame + frame_size_58, + s->frame_size - frame_size_58 - 2); } crc2 = av_bswap16(crc2); + /* ensure crc2 does not match sync word by flipping crcrsv bit if needed */ + if (crc2 == 0x0B77) { + /* The CRC generator polynomial is x^16 + x^15 + x^2 + 1, + * so xor'ing with 0x18005 does not affect the CRC. */ + frame[s->frame_size - 3] ^= 0x1; + crc2 ^= 0x8005; + } AV_WB16(frame + s->frame_size - 2, crc2); } @@ -1757,24 +1969,36 @@ static void output_frame_end(AC3EncodeContext *s) */ static void ac3_output_frame(AC3EncodeContext *s, unsigned char *frame) { + PutBitContext pb; int blk; - init_put_bits(&s->pb, frame, s->frame_size); + init_put_bits(&pb, frame, s->frame_size); - s->output_frame_header(s); + s->output_frame_header(s, &pb); for (blk = 0; blk < s->num_blocks; blk++) - output_audio_block(s, blk); + output_audio_block(s, &pb, blk); - output_frame_end(s); + output_frame_end(s, &pb); } -int ff_ac3_encode_frame_common_end(AVCodecContext *avctx, AVPacket *avpkt, - const AVFrame *frame, int *got_packet_ptr) +int ff_ac3_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) { AC3EncodeContext *const s = avctx->priv_data; int ret; + if (s->options.allow_per_frame_metadata) { + ret = ac3_validate_metadata(s); + if (ret) + return ret; + } + + if (s->bit_alloc.sr_code == 1 || s->eac3) + ac3_adjust_frame_size(s); + + s->encode_frame(s, frame->extended_data); + ac3_apply_rematrixing(s); ac3_process_exponents(s); @@ -1806,17 +2030,16 @@ static void dprint_options(AC3EncodeContext *s) #ifdef DEBUG AVCodecContext *avctx = s->avctx; AC3EncOptions *opt = &s->options; + const char *msg; char strbuf[32]; switch (s->bitstream_id) { - case 6: av_strlcpy(strbuf, "AC-3 (alt syntax)", 32); break; - case 8: av_strlcpy(strbuf, "AC-3 (standard)", 32); break; - case 9: av_strlcpy(strbuf, "AC-3 (dnet half-rate)", 32); break; - case 10: av_strlcpy(strbuf, "AC-3 (dnet quater-rate)", 32); break; - case 16: av_strlcpy(strbuf, "E-AC-3 (enhanced)", 32); break; - default: snprintf(strbuf, 32, "ERROR"); + case 6: msg = "AC-3 (alt syntax)"; break; + case 8: msg = "AC-3 (standard)"; break; + case 16: msg = "E-AC-3 (enhanced)"; break; + default: msg = "ERROR"; } - ff_dlog(avctx, "bitstream_id: %s (%d)\n", strbuf, s->bitstream_id); + ff_dlog(avctx, "bitstream_id: %s (%d)\n", msg, s->bitstream_id); ff_dlog(avctx, "sample_fmt: %s\n", av_get_sample_fmt_name(avctx->sample_fmt)); av_channel_layout_describe(&avctx->ch_layout, strbuf, sizeof(strbuf)); ff_dlog(avctx, "channel_layout: %s\n", strbuf); @@ -1841,12 +2064,14 @@ static void dprint_options(AC3EncodeContext *s) if (opt->audio_production_info) { ff_dlog(avctx, "mixing_level: %ddB\n", opt->mixing_level); switch (opt->room_type) { - case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; - case AC3ENC_OPT_LARGE_ROOM: av_strlcpy(strbuf, "large", 32); break; - case AC3ENC_OPT_SMALL_ROOM: av_strlcpy(strbuf, "small", 32); break; - default: snprintf(strbuf, 32, "ERROR (%d)", opt->room_type); + case AC3ENC_OPT_NOT_INDICATED: msg = "notindicated"; break; + case AC3ENC_OPT_LARGE_ROOM: msg = "large"; break; + case AC3ENC_OPT_SMALL_ROOM: msg = "small"; break; + default: + snprintf(strbuf, sizeof(strbuf), "ERROR (%d)", opt->room_type); + msg = strbuf; } - ff_dlog(avctx, "room_type: %s\n", strbuf); + ff_dlog(avctx, "room_type: %s\n", msg); } else { ff_dlog(avctx, "mixing_level: {not written}\n"); ff_dlog(avctx, "room_type: {not written}\n"); @@ -1855,12 +2080,14 @@ static void dprint_options(AC3EncodeContext *s) ff_dlog(avctx, "dialnorm: %ddB\n", opt->dialogue_level); if (s->channel_mode == AC3_CHMODE_STEREO) { switch (opt->dolby_surround_mode) { - case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; - case AC3ENC_OPT_MODE_ON: av_strlcpy(strbuf, "on", 32); break; - case AC3ENC_OPT_MODE_OFF: av_strlcpy(strbuf, "off", 32); break; - default: snprintf(strbuf, 32, "ERROR (%d)", opt->dolby_surround_mode); + case AC3ENC_OPT_NOT_INDICATED: msg = "notindicated"; break; + case AC3ENC_OPT_MODE_ON: msg = "on"; break; + case AC3ENC_OPT_MODE_OFF: msg = "off"; break; + default: + snprintf(strbuf, sizeof(strbuf), "ERROR (%d)", opt->dolby_surround_mode); + msg = strbuf; } - ff_dlog(avctx, "dsur_mode: %s\n", strbuf); + ff_dlog(avctx, "dsur_mode: %s\n", msg); } else { ff_dlog(avctx, "dsur_mode: {not written}\n"); } @@ -1869,12 +2096,14 @@ static void dprint_options(AC3EncodeContext *s) if (s->bitstream_id == 6) { if (opt->extended_bsi_1) { switch (opt->preferred_stereo_downmix) { - case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; - case AC3ENC_OPT_DOWNMIX_LTRT: av_strlcpy(strbuf, "ltrt", 32); break; - case AC3ENC_OPT_DOWNMIX_LORO: av_strlcpy(strbuf, "loro", 32); break; - default: snprintf(strbuf, 32, "ERROR (%d)", opt->preferred_stereo_downmix); + case AC3ENC_OPT_NOT_INDICATED: msg = "notindicated"; break; + case AC3ENC_OPT_DOWNMIX_LTRT: msg = "ltrt"; break; + case AC3ENC_OPT_DOWNMIX_LORO: msg = "loro"; break; + default: + snprintf(strbuf, sizeof(strbuf), "ERROR (%d)", opt->preferred_stereo_downmix); + msg = strbuf; } - ff_dlog(avctx, "dmix_mode: %s\n", strbuf); + ff_dlog(avctx, "dmix_mode: %s\n", msg); ff_dlog(avctx, "ltrt_cmixlev: %0.3f (%d)\n", opt->ltrt_center_mix_level, s->ltrt_center_mix_level); ff_dlog(avctx, "ltrt_surmixlev: %0.3f (%d)\n", @@ -1888,26 +2117,32 @@ static void dprint_options(AC3EncodeContext *s) } if (opt->extended_bsi_2) { switch (opt->dolby_surround_ex_mode) { - case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; - case AC3ENC_OPT_MODE_ON: av_strlcpy(strbuf, "on", 32); break; - case AC3ENC_OPT_MODE_OFF: av_strlcpy(strbuf, "off", 32); break; - default: snprintf(strbuf, 32, "ERROR (%d)", opt->dolby_surround_ex_mode); + case AC3ENC_OPT_NOT_INDICATED: msg = "notindicated"; break; + case AC3ENC_OPT_MODE_ON: msg = "on"; break; + case AC3ENC_OPT_MODE_OFF: msg = "off"; break; + default: + snprintf(strbuf, sizeof(strbuf), "ERROR (%d)", opt->dolby_surround_ex_mode); + msg = strbuf; } - ff_dlog(avctx, "dsurex_mode: %s\n", strbuf); + ff_dlog(avctx, "dsurex_mode: %s\n", msg); switch (opt->dolby_headphone_mode) { - case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; - case AC3ENC_OPT_MODE_ON: av_strlcpy(strbuf, "on", 32); break; - case AC3ENC_OPT_MODE_OFF: av_strlcpy(strbuf, "off", 32); break; - default: snprintf(strbuf, 32, "ERROR (%d)", opt->dolby_headphone_mode); + case AC3ENC_OPT_NOT_INDICATED: msg = "notindicated"; break; + case AC3ENC_OPT_MODE_ON: msg = "on"; break; + case AC3ENC_OPT_MODE_OFF: msg = "off"; break; + default: + snprintf(strbuf, sizeof(strbuf), "ERROR (%d)", opt->dolby_headphone_mode); + msg = strbuf; } - ff_dlog(avctx, "dheadphone_mode: %s\n", strbuf); + ff_dlog(avctx, "dheadphone_mode: %s\n", msg); switch (opt->ad_converter_type) { - case AC3ENC_OPT_ADCONV_STANDARD: av_strlcpy(strbuf, "standard", 32); break; - case AC3ENC_OPT_ADCONV_HDCD: av_strlcpy(strbuf, "hdcd", 32); break; - default: snprintf(strbuf, 32, "ERROR (%d)", opt->ad_converter_type); + case AC3ENC_OPT_ADCONV_STANDARD: msg = "standard"; break; + case AC3ENC_OPT_ADCONV_HDCD: msg = "hdcd"; break; + default: + snprintf(strbuf, sizeof(strbuf), "ERROR (%d)", opt->ad_converter_type); + msg = strbuf; } - ff_dlog(avctx, "ad_conv_type: %s\n", strbuf); + ff_dlog(avctx, "ad_conv_type: %s\n", msg); } else { ff_dlog(avctx, "extended bitstream info 2: {not written}\n"); } @@ -1915,227 +2150,6 @@ static void dprint_options(AC3EncodeContext *s) #endif } - -#define FLT_OPTION_THRESHOLD 0.01 - -static int validate_float_option(float v, const float *v_list, int v_list_size) -{ - int i; - - for (i = 0; i < v_list_size; i++) { - if (v < (v_list[i] + FLT_OPTION_THRESHOLD) && - v > (v_list[i] - FLT_OPTION_THRESHOLD)) - break; - } - if (i == v_list_size) - return AVERROR(EINVAL); - - return i; -} - - -static void validate_mix_level(void *log_ctx, const char *opt_name, - float *opt_param, const float *list, - int list_size, int default_value, int min_value, - int *ctx_param) -{ - int mixlev = validate_float_option(*opt_param, list, list_size); - if (mixlev < min_value) { - mixlev = default_value; - if (*opt_param >= 0.0) { - av_log(log_ctx, AV_LOG_WARNING, "requested %s is not valid. using " - "default value: %0.3f\n", opt_name, list[mixlev]); - } - } - *opt_param = list[mixlev]; - *ctx_param = mixlev; -} - - -/** - * Validate metadata options as set by AVOption system. - * These values can optionally be changed per-frame. - * - * @param s AC-3 encoder private context - */ -int ff_ac3_validate_metadata(AC3EncodeContext *s) -{ - AVCodecContext *avctx = s->avctx; - AC3EncOptions *opt = &s->options; - - opt->audio_production_info = 0; - opt->extended_bsi_1 = 0; - opt->extended_bsi_2 = 0; - opt->eac3_mixing_metadata = 0; - opt->eac3_info_metadata = 0; - - /* determine mixing metadata / xbsi1 use */ - if (s->channel_mode > AC3_CHMODE_STEREO && opt->preferred_stereo_downmix != AC3ENC_OPT_NONE) { - opt->extended_bsi_1 = 1; - opt->eac3_mixing_metadata = 1; - } - if (s->has_center && - (opt->ltrt_center_mix_level >= 0 || opt->loro_center_mix_level >= 0)) { - opt->extended_bsi_1 = 1; - opt->eac3_mixing_metadata = 1; - } - if (s->has_surround && - (opt->ltrt_surround_mix_level >= 0 || opt->loro_surround_mix_level >= 0)) { - opt->extended_bsi_1 = 1; - opt->eac3_mixing_metadata = 1; - } - - if (s->eac3) { - /* determine info metadata use */ - if (avctx->audio_service_type != AV_AUDIO_SERVICE_TYPE_MAIN) - opt->eac3_info_metadata = 1; - if (opt->copyright != AC3ENC_OPT_NONE || opt->original != AC3ENC_OPT_NONE) - opt->eac3_info_metadata = 1; - if (s->channel_mode == AC3_CHMODE_STEREO && - (opt->dolby_headphone_mode != AC3ENC_OPT_NONE || opt->dolby_surround_mode != AC3ENC_OPT_NONE)) - opt->eac3_info_metadata = 1; - if (s->channel_mode >= AC3_CHMODE_2F2R && opt->dolby_surround_ex_mode != AC3ENC_OPT_NONE) - opt->eac3_info_metadata = 1; - if (opt->mixing_level != AC3ENC_OPT_NONE || opt->room_type != AC3ENC_OPT_NONE || - opt->ad_converter_type != AC3ENC_OPT_NONE) { - opt->audio_production_info = 1; - opt->eac3_info_metadata = 1; - } - } else { - /* determine audio production info use */ - if (opt->mixing_level != AC3ENC_OPT_NONE || opt->room_type != AC3ENC_OPT_NONE) - opt->audio_production_info = 1; - - /* determine xbsi2 use */ - if (s->channel_mode >= AC3_CHMODE_2F2R && opt->dolby_surround_ex_mode != AC3ENC_OPT_NONE) - opt->extended_bsi_2 = 1; - if (s->channel_mode == AC3_CHMODE_STEREO && opt->dolby_headphone_mode != AC3ENC_OPT_NONE) - opt->extended_bsi_2 = 1; - if (opt->ad_converter_type != AC3ENC_OPT_NONE) - opt->extended_bsi_2 = 1; - } - - /* validate AC-3 mixing levels */ - if (!s->eac3) { - if (s->has_center) { - validate_mix_level(avctx, "center_mix_level", &opt->center_mix_level, - cmixlev_options, CMIXLEV_NUM_OPTIONS, 1, 0, - &s->center_mix_level); - } - if (s->has_surround) { - validate_mix_level(avctx, "surround_mix_level", &opt->surround_mix_level, - surmixlev_options, SURMIXLEV_NUM_OPTIONS, 1, 0, - &s->surround_mix_level); - } - } - - /* validate extended bsi 1 / mixing metadata */ - if (opt->extended_bsi_1 || opt->eac3_mixing_metadata) { - /* default preferred stereo downmix */ - if (opt->preferred_stereo_downmix == AC3ENC_OPT_NONE) - opt->preferred_stereo_downmix = AC3ENC_OPT_NOT_INDICATED; - if (!s->eac3 || s->has_center) { - /* validate Lt/Rt center mix level */ - validate_mix_level(avctx, "ltrt_center_mix_level", - &opt->ltrt_center_mix_level, extmixlev_options, - EXTMIXLEV_NUM_OPTIONS, 5, 0, - &s->ltrt_center_mix_level); - /* validate Lo/Ro center mix level */ - validate_mix_level(avctx, "loro_center_mix_level", - &opt->loro_center_mix_level, extmixlev_options, - EXTMIXLEV_NUM_OPTIONS, 5, 0, - &s->loro_center_mix_level); - } - if (!s->eac3 || s->has_surround) { - /* validate Lt/Rt surround mix level */ - validate_mix_level(avctx, "ltrt_surround_mix_level", - &opt->ltrt_surround_mix_level, extmixlev_options, - EXTMIXLEV_NUM_OPTIONS, 6, 3, - &s->ltrt_surround_mix_level); - /* validate Lo/Ro surround mix level */ - validate_mix_level(avctx, "loro_surround_mix_level", - &opt->loro_surround_mix_level, extmixlev_options, - EXTMIXLEV_NUM_OPTIONS, 6, 3, - &s->loro_surround_mix_level); - } - } - - /* validate audio service type / channels combination */ - if ((avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_KARAOKE && - avctx->ch_layout.nb_channels == 1) || - ((avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_COMMENTARY || - avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_EMERGENCY || - avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_VOICE_OVER) - && avctx->ch_layout.nb_channels > 1)) { - av_log(avctx, AV_LOG_ERROR, "invalid audio service type for the " - "specified number of channels\n"); - return AVERROR(EINVAL); - } - - /* validate extended bsi 2 / info metadata */ - if (opt->extended_bsi_2 || opt->eac3_info_metadata) { - /* default dolby headphone mode */ - if (opt->dolby_headphone_mode == AC3ENC_OPT_NONE) - opt->dolby_headphone_mode = AC3ENC_OPT_NOT_INDICATED; - /* default dolby surround ex mode */ - if (opt->dolby_surround_ex_mode == AC3ENC_OPT_NONE) - opt->dolby_surround_ex_mode = AC3ENC_OPT_NOT_INDICATED; - /* default A/D converter type */ - if (opt->ad_converter_type == AC3ENC_OPT_NONE) - opt->ad_converter_type = AC3ENC_OPT_ADCONV_STANDARD; - } - - /* copyright & original defaults */ - if (!s->eac3 || opt->eac3_info_metadata) { - /* default copyright */ - if (opt->copyright == AC3ENC_OPT_NONE) - opt->copyright = AC3ENC_OPT_OFF; - /* default original */ - if (opt->original == AC3ENC_OPT_NONE) - opt->original = AC3ENC_OPT_ON; - } - - /* dolby surround mode default */ - if (!s->eac3 || opt->eac3_info_metadata) { - if (opt->dolby_surround_mode == AC3ENC_OPT_NONE) - opt->dolby_surround_mode = AC3ENC_OPT_NOT_INDICATED; - } - - /* validate audio production info */ - if (opt->audio_production_info) { - if (opt->mixing_level == AC3ENC_OPT_NONE) { - av_log(avctx, AV_LOG_ERROR, "mixing_level must be set if " - "room_type is set\n"); - return AVERROR(EINVAL); - } - if (opt->mixing_level < 80) { - av_log(avctx, AV_LOG_ERROR, "invalid mixing level. must be between " - "80dB and 111dB\n"); - return AVERROR(EINVAL); - } - /* default room type */ - if (opt->room_type == AC3ENC_OPT_NONE) - opt->room_type = AC3ENC_OPT_NOT_INDICATED; - } - - /* set bitstream id for alternate bitstream syntax */ - if (!s->eac3 && (opt->extended_bsi_1 || opt->extended_bsi_2)) { - if (s->bitstream_id > 8 && s->bitstream_id < 11) { - if (!s->warned_alternate_bitstream) { - av_log(avctx, AV_LOG_WARNING, "alternate bitstream syntax is " - "not compatible with reduced samplerates. writing of " - "extended bitstream information will be disabled.\n"); - s->warned_alternate_bitstream = 1; - } - } else { - s->bitstream_id = 6; - } - } - - return 0; -} - - /** * Finalize encoding and free any memory allocated by the encoder. * @@ -2143,15 +2157,10 @@ int ff_ac3_validate_metadata(AC3EncodeContext *s) */ av_cold int ff_ac3_encode_close(AVCodecContext *avctx) { - int blk, ch; AC3EncodeContext *s = avctx->priv_data; - av_freep(&s->mdct_window); - av_freep(&s->windowed_samples); - if (s->planar_samples) - for (ch = 0; ch < s->channels; ch++) - av_freep(&s->planar_samples[ch]); - av_freep(&s->planar_samples); + for (int ch = 0; ch < s->channels; ch++) + av_freep(&s->planar_samples[ch]); av_freep(&s->bap_buffer); av_freep(&s->bap1_buffer); av_freep(&s->mdct_coef_buffer); @@ -2162,22 +2171,8 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx) av_freep(&s->band_psd_buffer); av_freep(&s->mask_buffer); av_freep(&s->qmant_buffer); - av_freep(&s->cpl_coord_exp_buffer); - av_freep(&s->cpl_coord_mant_buffer); + av_freep(&s->cpl_coord_buffer); av_freep(&s->fdsp); - for (blk = 0; blk < s->num_blocks; blk++) { - AC3Block *block = &s->blocks[blk]; - av_freep(&block->mdct_coef); - av_freep(&block->fixed_coef); - av_freep(&block->exp); - av_freep(&block->grouped_exp); - av_freep(&block->psd); - av_freep(&block->band_psd); - av_freep(&block->mask); - av_freep(&block->qmant); - av_freep(&block->cpl_coord_exp); - av_freep(&block->cpl_coord_mant); - } av_tx_uninit(&s->tx); @@ -2188,29 +2183,18 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx) /* * Set channel information during initialization. */ -static av_cold int set_channel_info(AVCodecContext *avctx) +static av_cold void set_channel_info(AVCodecContext *avctx) { AC3EncodeContext *s = avctx->priv_data; + uint64_t mask = av_channel_layout_subset(&avctx->ch_layout, ~(uint64_t)0); int channels = avctx->ch_layout.nb_channels; - uint64_t mask = avctx->ch_layout.u.mask; - - if (channels < 1 || channels > AC3_MAX_CHANNELS) - return AVERROR(EINVAL); - if (mask > 0x7FF) - return AVERROR(EINVAL); - - if (!mask) - av_channel_layout_default(&avctx->ch_layout, channels); - mask = avctx->ch_layout.u.mask; s->lfe_on = !!(mask & AV_CH_LOW_FREQUENCY); s->channels = channels; s->fbw_channels = channels - s->lfe_on; s->lfe_channel = s->lfe_on ? s->fbw_channels + 1 : -1; - if (s->lfe_on) - mask -= AV_CH_LOW_FREQUENCY; - switch (mask) { + switch (mask & ~AV_CH_LOW_FREQUENCY) { case AV_CH_LAYOUT_MONO: s->channel_mode = AC3_CHMODE_MONO; break; case AV_CH_LAYOUT_STEREO: s->channel_mode = AC3_CHMODE_STEREO; break; case AV_CH_LAYOUT_SURROUND: s->channel_mode = AC3_CHMODE_3F; break; @@ -2220,55 +2204,30 @@ static av_cold int set_channel_info(AVCodecContext *avctx) case AV_CH_LAYOUT_2_2: s->channel_mode = AC3_CHMODE_2F2R; break; case AV_CH_LAYOUT_5POINT0: case AV_CH_LAYOUT_5POINT0_BACK: s->channel_mode = AC3_CHMODE_3F2R; break; - default: - return AVERROR(EINVAL); } s->has_center = (s->channel_mode & 0x01) && s->channel_mode != AC3_CHMODE_MONO; s->has_surround = s->channel_mode & 0x04; s->channel_map = ac3_enc_channel_map[s->channel_mode][s->lfe_on]; - if (s->lfe_on) - mask |= AV_CH_LOW_FREQUENCY; - av_channel_layout_from_mask(&avctx->ch_layout, mask); - - return 0; } static av_cold int validate_options(AC3EncodeContext *s) { AVCodecContext *avctx = s->avctx; - int i, ret, max_sr; + int ret; - /* validate channel layout */ - if (!avctx->ch_layout.nb_channels) { - av_log(avctx, AV_LOG_WARNING, "No channel layout specified. The " - "encoder will guess the layout, but it " - "might be incorrect.\n"); - } - ret = set_channel_info(avctx); - if (ret) { - av_log(avctx, AV_LOG_ERROR, "invalid channel layout\n"); - return ret; - } + set_channel_info(avctx); - /* validate sample rate */ - /* note: max_sr could be changed from 2 to 5 for E-AC-3 once we find a - decoder that supports half sample rate so we can validate that - the generated files are correct. */ - max_sr = s->eac3 ? 2 : 8; - for (i = 0; i <= max_sr; i++) { - if ((ff_ac3_sample_rate_tab[i % 3] >> (i / 3)) == avctx->sample_rate) + for (int i = 0;; i++) { + if (ff_ac3_sample_rate_tab[i] == avctx->sample_rate) { + s->bit_alloc.sr_code = i; break; - } - if (i > max_sr) { - av_log(avctx, AV_LOG_ERROR, "invalid sample rate\n"); - return AVERROR(EINVAL); + } + av_assert1(ff_ac3_sample_rate_tab[i] != 0); } s->sample_rate = avctx->sample_rate; - s->bit_alloc.sr_shift = i / 3; - s->bit_alloc.sr_code = i % 3; - s->bitstream_id = s->eac3 ? 16 : 8 + s->bit_alloc.sr_shift; + s->bitstream_id = s->eac3 ? 16 : 8; /* select a default bit rate if not set by the user */ if (!avctx->bit_rate) { @@ -2316,7 +2275,7 @@ static av_cold int validate_options(AC3EncodeContext *s) parameter selection */ min_br_code = -1; min_br_dist = INT64_MAX; - for (i = 0; i < 19; i++) { + for (int i = 0; i < 19; i++) { long long br_dist = llabs(ff_ac3_bitrate_tab[i] * 1000 - avctx->bit_rate); if (br_dist < min_br_dist) { min_br_dist = br_dist; @@ -2332,8 +2291,8 @@ static av_cold int validate_options(AC3EncodeContext *s) } else { int best_br = 0, best_code = 0; long long best_diff = INT64_MAX; - for (i = 0; i < 19; i++) { - int br = (ff_ac3_bitrate_tab[i] >> s->bit_alloc.sr_shift) * 1000; + for (int i = 0; i < 19; i++) { + int br = ff_ac3_bitrate_tab[i] * 1000; long long diff = llabs(br - avctx->bit_rate); if (diff < best_diff) { best_br = br; @@ -2361,7 +2320,7 @@ static av_cold int validate_options(AC3EncodeContext *s) if (s->cutoff > (s->sample_rate >> 1)) s->cutoff = s->sample_rate >> 1; - ret = ff_ac3_validate_metadata(s); + ret = ac3_validate_metadata(s); if (ret) return ret; @@ -2456,9 +2415,14 @@ static av_cold int allocate_buffers(AC3EncodeContext *s) int channels = s->channels + 1; /* includes coupling channel */ int channel_blocks = channels * s->num_blocks; int total_coefs = AC3_MAX_COEFS * channel_blocks; + uint8_t *cpl_coord_mant_buffer; + const unsigned sampletype_size = SAMPLETYPE_SIZE(s); - if (s->allocate_sample_buffers(s)) - return AVERROR(ENOMEM); + for (int ch = 0; ch < s->channels; ch++) { + s->planar_samples[ch] = av_mallocz(AC3_BLOCK_SIZE * sampletype_size); + if (!s->planar_samples[ch]) + return AVERROR(ENOMEM); + } if (!FF_ALLOC_TYPED_ARRAY(s->bap_buffer, total_coefs) || !FF_ALLOC_TYPED_ARRAY(s->bap1_buffer, total_coefs) || @@ -2471,29 +2435,18 @@ static av_cold int allocate_buffers(AC3EncodeContext *s) !FF_ALLOC_TYPED_ARRAY(s->qmant_buffer, total_coefs)) return AVERROR(ENOMEM); - if (s->cpl_enabled) { - if (!FF_ALLOC_TYPED_ARRAY(s->cpl_coord_exp_buffer, channel_blocks * 16) || - !FF_ALLOC_TYPED_ARRAY(s->cpl_coord_mant_buffer, channel_blocks * 16)) + if (!s->fixed_point) { + if (!FF_ALLOCZ_TYPED_ARRAY(s->fixed_coef_buffer, total_coefs)) return AVERROR(ENOMEM); } + if (s->cpl_enabled) { + if (!FF_ALLOC_TYPED_ARRAY(s->cpl_coord_buffer, channel_blocks * 32)) + return AVERROR(ENOMEM); + cpl_coord_mant_buffer = s->cpl_coord_buffer + 16 * channel_blocks; + } for (blk = 0; blk < s->num_blocks; blk++) { AC3Block *block = &s->blocks[blk]; - if (!FF_ALLOCZ_TYPED_ARRAY(block->mdct_coef, channels) || - !FF_ALLOCZ_TYPED_ARRAY(block->exp, channels) || - !FF_ALLOCZ_TYPED_ARRAY(block->grouped_exp, channels) || - !FF_ALLOCZ_TYPED_ARRAY(block->psd, channels) || - !FF_ALLOCZ_TYPED_ARRAY(block->band_psd, channels) || - !FF_ALLOCZ_TYPED_ARRAY(block->mask, channels) || - !FF_ALLOCZ_TYPED_ARRAY(block->qmant, channels)) - return AVERROR(ENOMEM); - - if (s->cpl_enabled) { - if (!FF_ALLOCZ_TYPED_ARRAY(block->cpl_coord_exp, channels) || - !FF_ALLOCZ_TYPED_ARRAY(block->cpl_coord_mant, channels)) - return AVERROR(ENOMEM); - } - for (ch = 0; ch < channels; ch++) { /* arrangement: block, channel, coeff */ block->grouped_exp[ch] = &s->grouped_exp_buffer[128 * (blk * channels + ch)]; @@ -2502,33 +2455,17 @@ static av_cold int allocate_buffers(AC3EncodeContext *s) block->mask[ch] = &s->mask_buffer [64 * (blk * channels + ch)]; block->qmant[ch] = &s->qmant_buffer [AC3_MAX_COEFS * (blk * channels + ch)]; if (s->cpl_enabled) { - block->cpl_coord_exp[ch] = &s->cpl_coord_exp_buffer [16 * (blk * channels + ch)]; - block->cpl_coord_mant[ch] = &s->cpl_coord_mant_buffer[16 * (blk * channels + ch)]; + block->cpl_coord_exp[ch] = &s->cpl_coord_buffer [16 * (blk * channels + ch)]; + block->cpl_coord_mant[ch] = &cpl_coord_mant_buffer[16 * (blk * channels + ch)]; } /* arrangement: channel, block, coeff */ block->exp[ch] = &s->exp_buffer [AC3_MAX_COEFS * (s->num_blocks * ch + blk)]; block->mdct_coef[ch] = &s->mdct_coef_buffer [AC3_MAX_COEFS * (s->num_blocks * ch + blk)]; - } - } - - if (!s->fixed_point) { - if (!FF_ALLOCZ_TYPED_ARRAY(s->fixed_coef_buffer, total_coefs)) - return AVERROR(ENOMEM); - for (blk = 0; blk < s->num_blocks; blk++) { - AC3Block *block = &s->blocks[blk]; - if (!FF_ALLOCZ_TYPED_ARRAY(block->fixed_coef, channels)) - return AVERROR(ENOMEM); - for (ch = 0; ch < channels; ch++) - block->fixed_coef[ch] = &s->fixed_coef_buffer[AC3_MAX_COEFS * (s->num_blocks * ch + blk)]; - } - } else { - for (blk = 0; blk < s->num_blocks; blk++) { - AC3Block *block = &s->blocks[blk]; - if (!FF_ALLOCZ_TYPED_ARRAY(block->fixed_coef, channels)) - return AVERROR(ENOMEM); - for (ch = 0; ch < channels; ch++) + if (s->fixed_point) block->fixed_coef[ch] = (int32_t *)block->mdct_coef[ch]; + else + block->fixed_coef[ch] = &s->fixed_coef_buffer[AC3_MAX_COEFS * (s->num_blocks * ch + blk)]; } } @@ -2544,8 +2481,6 @@ av_cold int ff_ac3_encode_init(AVCodecContext *avctx) s->avctx = avctx; - s->eac3 = avctx->codec_id == AV_CODEC_ID_EAC3; - ret = validate_options(s); if (ret) return ret; @@ -2568,21 +2503,13 @@ av_cold int ff_ac3_encode_init(AVCodecContext *avctx) s->crc_inv[1] = pow_poly((CRC16_POLY >> 1), (8 * frame_size_58) - 16, CRC16_POLY); } - if (CONFIG_EAC3_ENCODER && s->eac3) { - static AVOnce init_static_once_eac3 = AV_ONCE_INIT; - ff_thread_once(&init_static_once_eac3, ff_eac3_exponent_init); - s->output_frame_header = ff_eac3_output_frame_header; - } else + if (!s->output_frame_header) s->output_frame_header = ac3_output_frame_header; set_bandwidth(s); bit_alloc_init(s); - ret = s->mdct_init(s); - if (ret) - return ret; - ret = allocate_buffers(s); if (ret) return ret; diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h index 1cb1aac4b..5e98ad188 100644 --- a/libavcodec/ac3enc.h +++ b/libavcodec/ac3enc.h @@ -30,6 +30,7 @@ #include +#include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/tx.h" @@ -40,7 +41,6 @@ #include "codec_internal.h" #include "mathops.h" #include "me_cmp.h" -#include "put_bits.h" #include "audiodsp.h" #ifndef AC3ENC_FLOAT @@ -49,7 +49,6 @@ #if AC3ENC_FLOAT #include "libavutil/float_dsp.h" -#define AC3_NAME(x) ff_ac3_float_ ## x #define MAC_COEF(d,a,b) ((d)+=(a)*(b)) #define COEF_MIN (-16777215.0/16777216.0) #define COEF_MAX ( 16777215.0/16777216.0) @@ -59,7 +58,6 @@ typedef float CoefType; typedef float CoefSumType; #else #include "libavutil/fixed_dsp.h" -#define AC3_NAME(x) ff_ac3_fixed_ ## x #define MAC_COEF(d,a,b) MAC64(d,a,b) #define COEF_MIN -16777215 #define COEF_MAX 16777215 @@ -128,16 +126,16 @@ typedef struct AC3EncOptions { * Data for a single audio block. */ typedef struct AC3Block { - CoefType **mdct_coef; ///< MDCT coefficients - int32_t **fixed_coef; ///< fixed-point MDCT coefficients - uint8_t **exp; ///< original exponents - uint8_t **grouped_exp; ///< grouped exponents - int16_t **psd; ///< psd per frequency bin - int16_t **band_psd; ///< psd per critical band - int16_t **mask; ///< masking curve - uint16_t **qmant; ///< quantized mantissas - uint8_t **cpl_coord_exp; ///< coupling coord exponents (cplcoexp) - uint8_t **cpl_coord_mant; ///< coupling coord mantissas (cplcomant) + CoefType *mdct_coef[AC3_MAX_CHANNELS]; ///< MDCT coefficients + int32_t *fixed_coef[AC3_MAX_CHANNELS]; ///< fixed-point MDCT coefficients + uint8_t *exp[AC3_MAX_CHANNELS]; ///< original exponents + uint8_t *grouped_exp[AC3_MAX_CHANNELS]; ///< grouped exponents + int16_t *psd[AC3_MAX_CHANNELS]; ///< psd per frequency bin + int16_t *band_psd[AC3_MAX_CHANNELS]; ///< psd per critical band + int16_t *mask[AC3_MAX_CHANNELS]; ///< masking curve + uint16_t *qmant[AC3_MAX_CHANNELS]; ///< quantized mantissas + uint8_t *cpl_coord_exp[AC3_MAX_CHANNELS]; ///< coupling coord exponents (cplcoexp) + uint8_t *cpl_coord_mant[AC3_MAX_CHANNELS]; ///< coupling coord mantissas (cplcomant) uint8_t new_rematrixing_strategy; ///< send new rematrixing flags in this block int num_rematrixing_bands; ///< number of rematrixing bands uint8_t rematrixing_flags[4]; ///< rematrixing flags @@ -152,6 +150,8 @@ typedef struct AC3Block { int end_freq[AC3_MAX_CHANNELS]; ///< end frequency bin (endmant) } AC3Block; +struct PutBitContext; + /** * AC-3 encoder private context. */ @@ -159,7 +159,6 @@ typedef struct AC3EncodeContext { AVClass *av_class; ///< AVClass used for AVOption AC3EncOptions options; ///< encoding options AVCodecContext *avctx; ///< parent AVCodecContext - PutBitContext pb; ///< bitstream writer context AudioDSPContext adsp; #if AC3ENC_FLOAT AVFloatDSPContext *fdsp; @@ -170,7 +169,6 @@ typedef struct AC3EncodeContext { AC3DSPContext ac3dsp; ///< AC-3 optimized functions AVTXContext *tx; ///< FFT context for MDCT calculation av_tx_fn tx_fn; - const SampleType *mdct_window; ///< MDCT window function array AC3Block blocks[AC3_MAX_BLOCKS]; ///< per-block info @@ -234,8 +232,7 @@ typedef struct AC3EncodeContext { int frame_bits; ///< all frame bits except exponents and mantissas int exponent_bits; ///< number of bits used for exponents - SampleType *windowed_samples; - SampleType **planar_samples; + uint8_t *planar_samples[AC3_MAX_CHANNELS - 1]; uint8_t *bap_buffer; uint8_t *bap1_buffer; CoefType *mdct_coef_buffer; @@ -246,8 +243,7 @@ typedef struct AC3EncodeContext { int16_t *band_psd_buffer; int16_t *mask_buffer; int16_t *qmant_buffer; - uint8_t *cpl_coord_exp_buffer; - uint8_t *cpl_coord_mant_buffer; + uint8_t *cpl_coord_buffer; uint8_t exp_strategy[AC3_MAX_CHANNELS][AC3_MAX_BLOCKS]; ///< exponent strategies uint8_t frame_exp_strategy[AC3_MAX_CHANNELS]; ///< frame exp strategy index @@ -256,16 +252,20 @@ typedef struct AC3EncodeContext { uint8_t *ref_bap [AC3_MAX_CHANNELS][AC3_MAX_BLOCKS]; ///< bit allocation pointers (bap) int ref_bap_set; ///< indicates if ref_bap pointers have been set - int warned_alternate_bitstream; - - /* fixed vs. float function pointers */ - int (*mdct_init)(struct AC3EncodeContext *s); - - /* fixed vs. float templated function pointers */ - int (*allocate_sample_buffers)(struct AC3EncodeContext *s); + /** fixed vs. float function pointers */ + void (*encode_frame)(struct AC3EncodeContext *s, uint8_t * const *samples); /* AC-3 vs. E-AC-3 function pointers */ - void (*output_frame_header)(struct AC3EncodeContext *s); + void (*output_frame_header)(struct AC3EncodeContext *s, struct PutBitContext *pb); + + union { + DECLARE_ALIGNED(32, float, mdct_window_float)[AC3_BLOCK_SIZE]; + DECLARE_ALIGNED(32, int32_t, mdct_window_fixed)[AC3_BLOCK_SIZE]; + }; + union { + DECLARE_ALIGNED(32, float, windowed_samples_float)[AC3_WINDOW_SIZE]; + DECLARE_ALIGNED(32, int32_t, windowed_samples_fixed)[AC3_WINDOW_SIZE]; + }; } AC3EncodeContext; extern const AVChannelLayout ff_ac3_ch_layouts[19]; @@ -278,20 +278,10 @@ int ff_ac3_float_encode_init(AVCodecContext *avctx); int ff_ac3_encode_close(AVCodecContext *avctx); -int ff_ac3_validate_metadata(AC3EncodeContext *s); - -void ff_ac3_adjust_frame_size(AC3EncodeContext *s); void ff_ac3_compute_coupling_strategy(AC3EncodeContext *s); -int ff_ac3_encode_frame_common_end(AVCodecContext *avctx, AVPacket *avpkt, - const AVFrame *frame, int *got_packet_ptr); - -/* prototypes for functions in ac3enc_template.c */ - -int ff_ac3_fixed_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, - const AVFrame *frame, int *got_packet_ptr); -int ff_ac3_float_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, - const AVFrame *frame, int *got_packet_ptr); +int ff_ac3_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); #endif /* AVCODEC_AC3ENC_H */ diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c index a9bbb0a04..869e1f27a 100644 --- a/libavcodec/ac3enc_fixed.c +++ b/libavcodec/ac3enc_fixed.c @@ -73,22 +73,18 @@ static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl) * @param s AC-3 encoder private context * @return 0 on success, negative error code on failure */ -static av_cold int ac3_fixed_mdct_init(AC3EncodeContext *s) +static av_cold int ac3_fixed_mdct_init(AVCodecContext *avctx, AC3EncodeContext *s) { float fwin[AC3_BLOCK_SIZE]; const float scale = -1.0f; - int32_t *iwin = av_malloc_array(AC3_BLOCK_SIZE, sizeof(*iwin)); - if (!iwin) - return AVERROR(ENOMEM); + int32_t *iwin = s->mdct_window_fixed; ff_kbd_window_init(fwin, 5.0, AC3_BLOCK_SIZE); for (int i = 0; i < AC3_BLOCK_SIZE; i++) iwin[i] = lrintf(fwin[i] * (1 << 22)); - s->mdct_window = iwin; - - s->fdsp = avpriv_alloc_fixed_dsp(s->avctx->flags & AV_CODEC_FLAG_BITEXACT); + s->fdsp = avpriv_alloc_fixed_dsp(avctx->flags & AV_CODEC_FLAG_BITEXACT); if (!s->fdsp) return AVERROR(ENOMEM); @@ -100,9 +96,15 @@ static av_cold int ac3_fixed_mdct_init(AC3EncodeContext *s) static av_cold int ac3_fixed_encode_init(AVCodecContext *avctx) { AC3EncodeContext *s = avctx->priv_data; + int ret; + s->fixed_point = 1; - s->mdct_init = ac3_fixed_mdct_init; - s->allocate_sample_buffers = allocate_sample_buffers; + s->encode_frame = encode_frame; + + ret = ac3_fixed_mdct_init(avctx, s); + if (ret < 0) + return ret; + return ff_ac3_encode_init(avctx); } @@ -115,7 +117,7 @@ const FFCodec ff_ac3_fixed_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(AC3EncodeContext), .init = ac3_fixed_encode_init, - FF_CODEC_ENCODE_CB(ff_ac3_fixed_encode_frame), + 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 }, diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c index 3462c5f47..94e8ebc42 100644 --- a/libavcodec/ac3enc_float.c +++ b/libavcodec/ac3enc_float.c @@ -86,14 +86,8 @@ static void sum_square_butterfly(AC3EncodeContext *s, float sum[4], static av_cold int ac3_float_mdct_init(AC3EncodeContext *s) { const float scale = -2.0 / AC3_WINDOW_SIZE; - float *window = av_malloc_array(AC3_BLOCK_SIZE, sizeof(*window)); - if (!window) { - av_log(s->avctx, AV_LOG_ERROR, "Cannot allocate memory.\n"); - return AVERROR(ENOMEM); - } - ff_kbd_window_init(window, 5.0, AC3_BLOCK_SIZE); - s->mdct_window = window; + ff_kbd_window_init(s->mdct_window_float, 5.0, AC3_BLOCK_SIZE); return av_tx_init(&s->tx, &s->tx_fn, AV_TX_FLOAT_MDCT, 0, AC3_BLOCK_SIZE, &scale, 0); @@ -103,11 +97,17 @@ static av_cold int ac3_float_mdct_init(AC3EncodeContext *s) av_cold int ff_ac3_float_encode_init(AVCodecContext *avctx) { AC3EncodeContext *s = avctx->priv_data; - s->mdct_init = ac3_float_mdct_init; - s->allocate_sample_buffers = allocate_sample_buffers; + int ret; + + s->encode_frame = encode_frame; s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); if (!s->fdsp) return AVERROR(ENOMEM); + + ret = ac3_float_mdct_init(s); + if (ret < 0) + return ret; + return ff_ac3_encode_init(avctx); } @@ -119,7 +119,7 @@ const FFCodec ff_ac3_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(AC3EncodeContext), .init = ff_ac3_float_encode_init, - FF_CODEC_ENCODE_CB(ff_ac3_float_encode_frame), + 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 }, diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c index 34d07cc9e..049666fdc 100644 --- a/libavcodec/ac3enc_template.c +++ b/libavcodec/ac3enc_template.c @@ -31,76 +31,53 @@ #include #include "libavutil/attributes.h" -#include "libavutil/internal.h" +#include "libavutil/avassert.h" #include "libavutil/mem_internal.h" #include "audiodsp.h" #include "ac3enc.h" #include "eac3enc.h" - -static int allocate_sample_buffers(AC3EncodeContext *s) -{ - int ch; - - if (!FF_ALLOC_TYPED_ARRAY(s->windowed_samples, AC3_WINDOW_SIZE) || - !FF_ALLOCZ_TYPED_ARRAY(s->planar_samples, s->channels)) - return AVERROR(ENOMEM); - - for (ch = 0; ch < s->channels; ch++) { - if (!(s->planar_samples[ch] = av_mallocz((AC3_FRAME_SIZE + AC3_BLOCK_SIZE) * - sizeof(**s->planar_samples)))) - return AVERROR(ENOMEM); - } - return 0; -} - - -/* - * Copy input samples. - * Channels are reordered from FFmpeg's default order to AC-3 order. - */ -static void copy_input_samples(AC3EncodeContext *s, SampleType **samples) -{ - int ch; - - /* copy and remap input samples */ - for (ch = 0; ch < s->channels; ch++) { - /* copy last 256 samples of previous frame to the start of the current frame */ - memcpy(&s->planar_samples[ch][0], &s->planar_samples[ch][AC3_BLOCK_SIZE * s->num_blocks], - AC3_BLOCK_SIZE * sizeof(s->planar_samples[0][0])); - - /* copy new samples for current frame */ - memcpy(&s->planar_samples[ch][AC3_BLOCK_SIZE], - samples[s->channel_map[ch]], - AC3_BLOCK_SIZE * s->num_blocks * sizeof(s->planar_samples[0][0])); - } -} - +#if AC3ENC_FLOAT +#define RENAME(element) element ## _float +#else +#define RENAME(element) element ## _fixed +#endif /* * Apply the MDCT to input samples to generate frequency coefficients. * This applies the KBD window and normalizes the input to reduce precision * loss due to fixed-point calculations. */ -static void apply_mdct(AC3EncodeContext *s) +static void apply_mdct(AC3EncodeContext *s, uint8_t * const *samples) { - int blk, ch; + av_assert1(s->num_blocks > 0); - for (ch = 0; ch < s->channels; ch++) { - for (blk = 0; blk < s->num_blocks; blk++) { + for (int ch = 0; ch < s->channels; ch++) { + const SampleType *input_samples0 = (const SampleType*)s->planar_samples[ch]; + /* Reorder channels from native order to AC-3 order. */ + const SampleType *input_samples1 = (const SampleType*)samples[s->channel_map[ch]]; + int blk = 0; + + do { AC3Block *block = &s->blocks[blk]; - const SampleType *input_samples = &s->planar_samples[ch][blk * AC3_BLOCK_SIZE]; + SampleType *windowed_samples = s->RENAME(windowed_samples); - s->fdsp->vector_fmul(s->windowed_samples, input_samples, - s->mdct_window, AC3_BLOCK_SIZE); - s->fdsp->vector_fmul_reverse(s->windowed_samples + AC3_BLOCK_SIZE, - &input_samples[AC3_BLOCK_SIZE], - s->mdct_window, AC3_BLOCK_SIZE); + s->fdsp->vector_fmul(windowed_samples, input_samples0, + s->RENAME(mdct_window), AC3_BLOCK_SIZE); + s->fdsp->vector_fmul_reverse(windowed_samples + AC3_BLOCK_SIZE, + input_samples1, + s->RENAME(mdct_window), AC3_BLOCK_SIZE); s->tx_fn(s->tx, block->mdct_coef[ch+1], - s->windowed_samples, sizeof(float)); - } + windowed_samples, sizeof(*windowed_samples)); + input_samples0 = input_samples1; + input_samples1 += AC3_BLOCK_SIZE; + } while (++blk < s->num_blocks); + + /* Store last 256 samples of current frame */ + memcpy(s->planar_samples[ch], input_samples0, + AC3_BLOCK_SIZE * sizeof(*input_samples0)); } } @@ -370,24 +347,9 @@ static void compute_rematrixing_strategy(AC3EncodeContext *s) } -int AC3_NAME(encode_frame)(AVCodecContext *avctx, AVPacket *avpkt, - const AVFrame *frame, int *got_packet_ptr) +static void encode_frame(AC3EncodeContext *s, uint8_t * const *samples) { - AC3EncodeContext *s = avctx->priv_data; - int ret; - - if (s->options.allow_per_frame_metadata) { - ret = ff_ac3_validate_metadata(s); - if (ret) - return ret; - } - - if (s->bit_alloc.sr_code == 1 || (AC3ENC_FLOAT && s->eac3)) - ff_ac3_adjust_frame_size(s); - - copy_input_samples(s, (SampleType **)frame->extended_data); - - apply_mdct(s); + apply_mdct(s, samples); s->cpl_on = s->cpl_enabled; ff_ac3_compute_coupling_strategy(s); @@ -400,6 +362,4 @@ int AC3_NAME(encode_frame)(AVCodecContext *avctx, AVPacket *avpkt, #if AC3ENC_FLOAT scale_coefficients(s); #endif - - return ff_ac3_encode_frame_common_end(avctx, avpkt, frame, got_packet_ptr); } diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index 59b9ef349..c6b6e22e9 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -260,10 +260,6 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_IMA_AMV: max_channels = 1; break; - case AV_CODEC_ID_ADPCM_DTK: - case AV_CODEC_ID_ADPCM_EA: - min_channels = 2; - break; case AV_CODEC_ID_ADPCM_AFC: case AV_CODEC_ID_ADPCM_EA_R1: case AV_CODEC_ID_ADPCM_EA_R2: @@ -280,6 +276,9 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) return AVERROR_PATCHWELCOME; } break; + case AV_CODEC_ID_ADPCM_DTK: + min_channels = 2; + break; case AV_CODEC_ID_ADPCM_PSX: max_channels = 8; if (avctx->ch_layout.nb_channels <= 0 || @@ -493,7 +492,7 @@ static inline int16_t adpcm_ima_wav_expand_nibble(ADPCMChannelStatus *c, GetBitC step_index = av_clip(step_index, 0, 88); sign = nibble & (1 << shift); - delta = av_mod_uintp2(nibble, shift); + delta = av_zero_extend(nibble, shift); diff = ((2 * delta + 1) * step) >> shift; predictor = c->predictor; if (sign) predictor -= diff; @@ -914,10 +913,12 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, bytestream2_seek(gb, -8, SEEK_CUR); break; case AV_CODEC_ID_ADPCM_EA: + /* Stereo is 30 bytes per block */ + /* Mono is 15 bytes per block */ has_coded_samples = 1; *coded_samples = bytestream2_get_le32(gb); *coded_samples -= *coded_samples % 28; - nb_samples = (buf_size - 12) / 30 * 28; + nb_samples = (buf_size - 12) / (ch == 2 ? 30 : 15) * 28; break; case AV_CODEC_ID_ADPCM_IMA_EA_EACS: has_coded_samples = 1; @@ -1652,10 +1653,10 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, int coeff1l, coeff2l, coeff1r, coeff2r; int shift_left, shift_right; - /* Each EA ADPCM frame has a 12-byte header followed by 30-byte pieces, - each coding 28 stereo samples. */ + /* Each EA ADPCM frame has a 12-byte header followed by 30-byte (stereo) or 15-byte (mono) pieces, + each coding 28 stereo/mono samples. */ - if (channels != 2) + if (channels != 2 && channels != 1) return AVERROR_INVALIDDATA; current_left_sample = sign_extend(bytestream2_get_le16u(&gb), 16); @@ -1670,32 +1671,52 @@ static int adpcm_decode_frame(AVCodecContext *avctx, AVFrame *frame, coeff1r = ea_adpcm_table[ byte & 0x0F]; coeff2r = ea_adpcm_table[(byte & 0x0F) + 4]; - byte = bytestream2_get_byteu(&gb); - shift_left = 20 - (byte >> 4); - shift_right = 20 - (byte & 0x0F); + if (channels == 2){ + byte = bytestream2_get_byteu(&gb); + shift_left = 20 - (byte >> 4); + shift_right = 20 - (byte & 0x0F); + } else{ + /* Mono packs the shift into the coefficient byte's lower nibble instead */ + shift_left = 20 - (byte & 0x0F); + } - for (int count2 = 0; count2 < 28; count2++) { + for (int count2 = 0; count2 < (channels == 2 ? 28 : 14); count2++) { byte = bytestream2_get_byteu(&gb); next_left_sample = sign_extend(byte >> 4, 4) * (1 << shift_left); - next_right_sample = sign_extend(byte, 4) * (1 << shift_right); next_left_sample = (next_left_sample + (current_left_sample * coeff1l) + (previous_left_sample * coeff2l) + 0x80) >> 8; - next_right_sample = (next_right_sample + - (current_right_sample * coeff1r) + - (previous_right_sample * coeff2r) + 0x80) >> 8; previous_left_sample = current_left_sample; current_left_sample = av_clip_int16(next_left_sample); - previous_right_sample = current_right_sample; - current_right_sample = av_clip_int16(next_right_sample); *samples++ = current_left_sample; - *samples++ = current_right_sample; + + if (channels == 2){ + next_right_sample = sign_extend(byte, 4) * (1 << shift_right); + + next_right_sample = (next_right_sample + + (current_right_sample * coeff1r) + + (previous_right_sample * coeff2r) + 0x80) >> 8; + + previous_right_sample = current_right_sample; + current_right_sample = av_clip_int16(next_right_sample); + *samples++ = current_right_sample; + } else { + next_left_sample = sign_extend(byte, 4) * (1 << shift_left); + + next_left_sample = (next_left_sample + + (current_left_sample * coeff1l) + + (previous_left_sample * coeff2l) + 0x80) >> 8; + + previous_left_sample = current_left_sample; + current_left_sample = av_clip_int16(next_left_sample); + + *samples++ = current_left_sample; + } } } - - bytestream2_skip(&gb, 2); // Skip terminating 0x0000 + bytestream2_skip(&gb, channels == 2 ? 2 : 3); // Skip terminating NULs ) /* End of CASE */ CASE(ADPCM_EA_MAXIS_XA, int coeff[2][2], shift[2]; diff --git a/libavcodec/adpcmenc.c b/libavcodec/adpcmenc.c index 63afffc58..4d7534e47 100644 --- a/libavcodec/adpcmenc.c +++ b/libavcodec/adpcmenc.c @@ -24,6 +24,7 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" diff --git a/libavcodec/adts_header.c b/libavcodec/adts_header.c index 00fa0a5a9..0d6be1aa0 100644 --- a/libavcodec/adts_header.c +++ b/libavcodec/adts_header.c @@ -21,11 +21,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "aac_ac3_parser.h" #include "adts_header.h" #include "adts_parser.h" #include "get_bits.h" #include "mpeg4audio.h" +#include "libavutil/avassert.h" int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr) { @@ -35,7 +35,7 @@ int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr) memset(hdr, 0, sizeof(*hdr)); if (get_bits(gbc, 12) != 0xfff) - return AAC_AC3_PARSE_ERROR_SYNC; + return AAC_PARSE_ERROR_SYNC; skip_bits1(gbc); /* id */ skip_bits(gbc, 2); /* layer */ @@ -43,7 +43,7 @@ int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr) aot = get_bits(gbc, 2); /* profile_objecttype */ sr = get_bits(gbc, 4); /* sample_frequency_index */ if (!ff_mpeg4audio_sample_rates[sr]) - return AAC_AC3_PARSE_ERROR_SAMPLE_RATE; + return AAC_PARSE_ERROR_SAMPLE_RATE; skip_bits1(gbc); /* private_bit */ ch = get_bits(gbc, 3); /* channel_configuration */ @@ -55,7 +55,7 @@ int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr) skip_bits1(gbc); /* copyright_identification_start */ size = get_bits(gbc, 13); /* aac_frame_length */ if (size < AV_AAC_ADTS_HEADER_SIZE) - return AAC_AC3_PARSE_ERROR_FRAME_SIZE; + return AAC_PARSE_ERROR_FRAME_SIZE; skip_bits(gbc, 11); /* adts_buffer_fullness */ rdb = get_bits(gbc, 2); /* number_of_raw_data_blocks_in_frame */ @@ -72,3 +72,12 @@ int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr) return size; } + +int ff_adts_header_parse_buf(const uint8_t buf[AV_AAC_ADTS_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE], + AACADTSHeaderInfo *hdr) +{ + GetBitContext gb; + av_unused int ret = init_get_bits8(&gb, buf, AV_AAC_ADTS_HEADER_SIZE); + av_assert1(ret >= 0); + return ff_adts_header_parse(&gb, hdr); +} diff --git a/libavcodec/adts_header.h b/libavcodec/adts_header.h index 354d07e1f..49bb74ee2 100644 --- a/libavcodec/adts_header.h +++ b/libavcodec/adts_header.h @@ -23,7 +23,14 @@ #ifndef AVCODEC_ADTS_HEADER_H #define AVCODEC_ADTS_HEADER_H -#include "get_bits.h" +#include "adts_parser.h" +#include "defs.h" + +typedef enum { + AAC_PARSE_ERROR_SYNC = -0x1030c0a, + AAC_PARSE_ERROR_SAMPLE_RATE = -0x3030c0a, + AAC_PARSE_ERROR_FRAME_SIZE = -0x4030c0a, +} AACParseError; typedef struct AACADTSHeaderInfo { uint32_t sample_rate; @@ -37,16 +44,24 @@ typedef struct AACADTSHeaderInfo { uint32_t frame_length; } AACADTSHeaderInfo; +struct GetBitContext; + /** * Parse the ADTS frame header to the end of the variable header, which is * the first 54 bits. * @param[in] gbc BitContext containing the first 54 bits of the frame. * @param[out] hdr Pointer to struct where header info is written. - * @return Returns 0 on success, -1 if there is a sync word mismatch, - * -2 if the version element is invalid, -3 if the sample rate - * element is invalid, or -4 if the bit rate element is invalid. + * @return the size in bytes of the header parsed on success and + * AAC_PARSE_ERROR_* values otherwise. */ -int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr); +int ff_adts_header_parse(struct GetBitContext *gbc, AACADTSHeaderInfo *hdr); + +/** + * Wrapper around ff_adts_header_parse() for users that don't already have + * a suitable GetBitContext. + */ +int ff_adts_header_parse_buf(const uint8_t buf[AV_AAC_ADTS_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE], + AACADTSHeaderInfo *hdr); /** * Parse the ADTS frame header contained in the buffer, which is @@ -56,9 +71,8 @@ int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr); * @param[out] phdr Pointer to pointer to struct AACADTSHeaderInfo for which * memory is allocated and header info is written into it. After using the header * information, the allocated memory must be freed by using av_free. - * @return Returns 0 on success, -1 if there is a sync word mismatch, - * -2 if the version element is invalid, -3 if the sample rate - * element is invalid, or -4 if the bit rate element is invalid. + * @return 0 on success, AAC_PARSE_ERROR_* values on invalid input and + * ordinary AVERROR codes otherwise. */ int avpriv_adts_header_parse(AACADTSHeaderInfo **phdr, const uint8_t *buf, size_t size); diff --git a/libavcodec/adts_parser.c b/libavcodec/adts_parser.c index 28ad5ef5e..66b988d6f 100644 --- a/libavcodec/adts_parser.c +++ b/libavcodec/adts_parser.c @@ -20,7 +20,10 @@ #include #include +#include +#include "libavutil/error.h" +#include "libavutil/mem.h" #include "adts_header.h" #include "adts_parser.h" @@ -28,16 +31,12 @@ int av_adts_header_parse(const uint8_t *buf, uint32_t *samples, uint8_t *frames) { #if CONFIG_ADTS_HEADER uint8_t tmpbuf[AV_AAC_ADTS_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; - GetBitContext gb; AACADTSHeaderInfo hdr; int err; if (!buf) return AVERROR(EINVAL); memcpy(tmpbuf, buf, AV_AAC_ADTS_HEADER_SIZE); - err = init_get_bits8(&gb, tmpbuf, AV_AAC_ADTS_HEADER_SIZE); - if (err < 0) - return err; - err = ff_adts_header_parse(&gb, &hdr); + err = ff_adts_header_parse_buf(tmpbuf, &hdr); if (err < 0) return err; *samples = hdr.samples; @@ -53,7 +52,6 @@ int avpriv_adts_header_parse(AACADTSHeaderInfo **phdr, const uint8_t *buf, size_ #if CONFIG_ADTS_HEADER int ret = 0; int allocated = 0; - GetBitContext gb; if (!phdr || !buf || size < AV_AAC_ADTS_HEADER_SIZE) return AVERROR_INVALIDDATA; @@ -65,14 +63,7 @@ int avpriv_adts_header_parse(AACADTSHeaderInfo **phdr, const uint8_t *buf, size_ if (!*phdr) return AVERROR(ENOMEM); - ret = init_get_bits8(&gb, buf, AV_AAC_ADTS_HEADER_SIZE); - if (ret < 0) { - if (allocated) - av_freep(phdr); - return ret; - } - - ret = ff_adts_header_parse(&gb, *phdr); + ret = ff_adts_header_parse_buf(buf, *phdr); if (ret < 0) { if (allocated) av_freep(phdr); diff --git a/libavcodec/agm.c b/libavcodec/agm.c index 88272cc3a..fdf896d61 100644 --- a/libavcodec/agm.c +++ b/libavcodec/agm.c @@ -24,6 +24,7 @@ #define BITSTREAM_READER_LE +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" diff --git a/libavcodec/aic.c b/libavcodec/aic.c index f8b0f6035..e12d689c4 100644 --- a/libavcodec/aic.c +++ b/libavcodec/aic.c @@ -22,6 +22,7 @@ #include +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" @@ -392,8 +393,6 @@ static int aic_decode_frame(AVCodecContext *avctx, AVFrame *frame, int slice_size; ctx->frame = frame; - ctx->frame->pict_type = AV_PICTURE_TYPE_I; - ctx->frame->flags |= AV_FRAME_FLAG_KEY; off = FFALIGN(AIC_HDR_SIZE + ctx->num_x_slices * ctx->mb_height * 2, 4); @@ -466,8 +465,7 @@ static av_cold int aic_decode_init(AVCodecContext *avctx) } } - ctx->slice_data = av_malloc_array(ctx->slice_width, AIC_BAND_COEFFS - * sizeof(*ctx->slice_data)); + ctx->slice_data = av_calloc(ctx->slice_width, AIC_BAND_COEFFS * sizeof(*ctx->slice_data)); if (!ctx->slice_data) { av_log(avctx, AV_LOG_ERROR, "Error allocating slice buffer\n"); diff --git a/libavcodec/alac.c b/libavcodec/alac.c index 538d1e598..f91288e97 100644 --- a/libavcodec/alac.c +++ b/libavcodec/alac.c @@ -48,6 +48,7 @@ #include #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "get_bits.h" diff --git a/libavcodec/alacenc.c b/libavcodec/alacenc.c index f43adb57f..caac62421 100644 --- a/libavcodec/alacenc.c +++ b/libavcodec/alacenc.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" diff --git a/libavcodec/aliaspixdec.c b/libavcodec/aliaspixdec.c index 72f810d40..50a6b72a0 100644 --- a/libavcodec/aliaspixdec.c +++ b/libavcodec/aliaspixdec.c @@ -69,9 +69,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *f, if (ret < 0) return ret; - f->pict_type = AV_PICTURE_TYPE_I; - f->flags |= AV_FRAME_FLAG_KEY; - x = 0; y = 1; out_buf = f->data[0]; diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 2386b450a..aa0fc4764 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -28,7 +28,6 @@ #include #include "config.h" -#include "config_components.h" #include "libavutil/thread.h" #include "codec.h" #include "codec_id.h" @@ -776,6 +775,8 @@ extern const FFCodec ff_libilbc_encoder; extern const FFCodec ff_libilbc_decoder; 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_libopencore_amrnb_encoder; extern const FFCodec ff_libopencore_amrnb_decoder; @@ -799,19 +800,12 @@ extern const FFCodec ff_libvpx_vp8_encoder; extern const FFCodec ff_libvpx_vp8_decoder; extern FFCodec ff_libvpx_vp9_encoder; extern const FFCodec ff_libvpx_vp9_decoder; +extern const FFCodec ff_libvvenc_encoder; /* preferred over libwebp */ extern const FFCodec ff_libwebp_anim_encoder; extern const FFCodec ff_libwebp_encoder; extern const FFCodec ff_libx262_encoder; -#if CONFIG_LIBX264_ENCODER -#include -#if X264_BUILD < 153 -#define LIBX264_CONST -#else -#define LIBX264_CONST const -#endif -extern LIBX264_CONST FFCodec ff_libx264_encoder; -#endif +extern const FFCodec ff_libx264_encoder; extern const FFCodec ff_libx264rgb_encoder; extern FFCodec ff_libx265_encoder; extern const FFCodec ff_libxeve_encoder; @@ -828,8 +822,11 @@ extern const FFCodec ff_idf_decoder; /* external libraries, that shouldn't be used by default if one of the * above is available */ +extern const FFCodec ff_aac_mediacodec_decoder; extern const FFCodec ff_aac_mf_encoder; extern const FFCodec ff_ac3_mf_encoder; +extern const FFCodec ff_amrnb_mediacodec_decoder; +extern const FFCodec ff_amrwb_mediacodec_decoder; extern const FFCodec ff_h263_v4l2m2m_encoder; extern const FFCodec ff_libaom_av1_decoder; /* hwaccel hooks only, so prefer external decoders */ @@ -853,8 +850,10 @@ extern const FFCodec ff_h264_qsv_encoder; extern const FFCodec ff_h264_v4l2m2m_encoder; 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_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; @@ -863,11 +862,13 @@ extern const FFCodec ff_hevc_qsv_encoder; extern const FFCodec ff_hevc_v4l2m2m_encoder; extern const FFCodec ff_hevc_vaapi_encoder; extern const FFCodec ff_hevc_videotoolbox_encoder; +extern const FFCodec ff_hevc_vulkan_encoder; extern const FFCodec ff_libkvazaar_encoder; extern const FFCodec ff_mjpeg_cuvid_decoder; extern const FFCodec ff_mjpeg_qsv_encoder; extern const FFCodec ff_mjpeg_qsv_decoder; extern const FFCodec ff_mjpeg_vaapi_encoder; +extern const FFCodec ff_mp3_mediacodec_decoder; extern const FFCodec ff_mp3_mf_encoder; extern const FFCodec ff_mpeg1_cuvid_decoder; extern const FFCodec ff_mpeg2_cuvid_decoder; @@ -892,6 +893,7 @@ extern const FFCodec ff_vp9_mediacodec_encoder; extern const FFCodec ff_vp9_qsv_decoder; extern const FFCodec ff_vp9_vaapi_encoder; extern const FFCodec ff_vp9_qsv_encoder; +extern const FFCodec ff_vvc_qsv_decoder; // null codecs extern const FFCodec ff_vnull_decoder; @@ -913,9 +915,43 @@ const FFCodec * codec_list[] = { static AVOnce av_codec_static_init = AV_ONCE_INIT; static void av_codec_init_static(void) { + int dummy; for (int i = 0; codec_list[i]; i++) { - if (codec_list[i]->init_static_data) - codec_list[i]->init_static_data((FFCodec*)codec_list[i]); + /* Backward compatibility with deprecated public fields */ + const FFCodec *codec = codec_list[i]; + if (!codec->get_supported_config) + continue; + +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); + break; + case AVMEDIA_TYPE_AUDIO: + codec->get_supported_config(NULL, &codec->p, + AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, + (const void **) &codec->p.sample_fmts, + &dummy); + codec->get_supported_config(NULL, &codec->p, + AV_CODEC_CONFIG_SAMPLE_RATE, 0, + (const void **) &codec->p.supported_samplerates, + &dummy); + codec->get_supported_config(NULL, &codec->p, + AV_CODEC_CONFIG_CHANNEL_LAYOUT, 0, + (const void **) &codec->p.ch_layouts, + &dummy); + break; + default: + break; + } +FF_ENABLE_DEPRECATION_WARNINGS } } diff --git a/libavcodec/alpha/Makefile b/libavcodec/alpha/Makefile deleted file mode 100644 index 796d9762b..000000000 --- a/libavcodec/alpha/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -OBJS-$(CONFIG_BLOCKDSP) += alpha/blockdsp_alpha.o -OBJS-$(CONFIG_ME_CMP) += alpha/me_cmp_alpha.o \ - alpha/me_cmp_mvi_asm.o -OBJS-$(CONFIG_HPELDSP) += alpha/hpeldsp_alpha.o \ - alpha/hpeldsp_alpha_asm.o -OBJS-$(CONFIG_IDCTDSP) += alpha/idctdsp_alpha.o \ - alpha/idctdsp_alpha_asm.o \ - alpha/simple_idct_alpha.o -OBJS-$(CONFIG_MPEGVIDEO) += alpha/mpegvideo_alpha.o -OBJS-$(CONFIG_PIXBLOCKDSP) += alpha/pixblockdsp_alpha.o diff --git a/libavcodec/alpha/asm.h b/libavcodec/alpha/asm.h deleted file mode 100644 index 6d850cecc..000000000 --- a/libavcodec/alpha/asm.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Alpha optimized DSP utils - * Copyright (c) 2002 Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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_ALPHA_ASM_H -#define AVCODEC_ALPHA_ASM_H - -#include - -#include "libavutil/common.h" - -#if AV_GCC_VERSION_AT_LEAST(2,96) -# define likely(x) __builtin_expect((x) != 0, 1) -# define unlikely(x) __builtin_expect((x) != 0, 0) -#else -# define likely(x) (x) -# define unlikely(x) (x) -#endif - -#define AMASK_BWX (1 << 0) -#define AMASK_FIX (1 << 1) -#define AMASK_CIX (1 << 2) -#define AMASK_MVI (1 << 8) - -static inline uint64_t BYTE_VEC(uint64_t x) -{ - x |= x << 8; - x |= x << 16; - x |= x << 32; - return x; -} -static inline uint64_t WORD_VEC(uint64_t x) -{ - x |= x << 16; - x |= x << 32; - return x; -} - -#define sextw(x) ((int16_t) (x)) - -#ifdef __GNUC__ -#define ldq(p) \ - (((const union { \ - uint64_t __l; \ - __typeof__(*(p)) __s[sizeof (uint64_t) / sizeof *(p)]; \ - } *) (p))->__l) -#define ldl(p) \ - (((const union { \ - int32_t __l; \ - __typeof__(*(p)) __s[sizeof (int32_t) / sizeof *(p)]; \ - } *) (p))->__l) -#define stq(l, p) \ - do { \ - (((union { \ - uint64_t __l; \ - __typeof__(*(p)) __s[sizeof (uint64_t) / sizeof *(p)]; \ - } *) (p))->__l) = l; \ - } while (0) -#define stl(l, p) \ - do { \ - (((union { \ - int32_t __l; \ - __typeof__(*(p)) __s[sizeof (int32_t) / sizeof *(p)]; \ - } *) (p))->__l) = l; \ - } while (0) -struct unaligned_long { uint64_t l; } __attribute__((packed)); -#define ldq_u(p) (*(const uint64_t *) (((uint64_t) (p)) & ~7ul)) -#define uldq(a) (((const struct unaligned_long *) (a))->l) - -#if AV_GCC_VERSION_AT_LEAST(3,3) -#define prefetch(p) __builtin_prefetch((p), 0, 1) -#define prefetch_en(p) __builtin_prefetch((p), 0, 0) -#define prefetch_m(p) __builtin_prefetch((p), 1, 1) -#define prefetch_men(p) __builtin_prefetch((p), 1, 0) -#define cmpbge __builtin_alpha_cmpbge -/* Avoid warnings. */ -#define extql(a, b) __builtin_alpha_extql(a, (uint64_t) (b)) -#define extwl(a, b) __builtin_alpha_extwl(a, (uint64_t) (b)) -#define extqh(a, b) __builtin_alpha_extqh(a, (uint64_t) (b)) -#define zap __builtin_alpha_zap -#define zapnot __builtin_alpha_zapnot -#define amask __builtin_alpha_amask -#define implver __builtin_alpha_implver -#define rpcc __builtin_alpha_rpcc -#else -#define prefetch(p) __asm__ volatile("ldl $31,%0" : : "m"(*(const char *) (p)) : "memory") -#define prefetch_en(p) __asm__ volatile("ldq $31,%0" : : "m"(*(const char *) (p)) : "memory") -#define prefetch_m(p) __asm__ volatile("lds $f31,%0" : : "m"(*(const char *) (p)) : "memory") -#define prefetch_men(p) __asm__ volatile("ldt $f31,%0" : : "m"(*(const char *) (p)) : "memory") -#define cmpbge(a, b) ({ uint64_t __r; __asm__ ("cmpbge %r1,%2,%0" : "=r" (__r) : "rJ" (a), "rI" (b)); __r; }) -#define extql(a, b) ({ uint64_t __r; __asm__ ("extql %r1,%2,%0" : "=r" (__r) : "rJ" (a), "rI" (b)); __r; }) -#define extwl(a, b) ({ uint64_t __r; __asm__ ("extwl %r1,%2,%0" : "=r" (__r) : "rJ" (a), "rI" (b)); __r; }) -#define extqh(a, b) ({ uint64_t __r; __asm__ ("extqh %r1,%2,%0" : "=r" (__r) : "rJ" (a), "rI" (b)); __r; }) -#define zap(a, b) ({ uint64_t __r; __asm__ ("zap %r1,%2,%0" : "=r" (__r) : "rJ" (a), "rI" (b)); __r; }) -#define zapnot(a, b) ({ uint64_t __r; __asm__ ("zapnot %r1,%2,%0" : "=r" (__r) : "rJ" (a), "rI" (b)); __r; }) -#define amask(a) ({ uint64_t __r; __asm__ ("amask %1,%0" : "=r" (__r) : "rI" (a)); __r; }) -#define implver() ({ uint64_t __r; __asm__ ("implver %0" : "=r" (__r)); __r; }) -#define rpcc() ({ uint64_t __r; __asm__ volatile ("rpcc %0" : "=r" (__r)); __r; }) -#endif -#define wh64(p) __asm__ volatile("wh64 (%0)" : : "r"(p) : "memory") - -#if AV_GCC_VERSION_AT_LEAST(3,3) && defined(__alpha_max__) -#define minub8 __builtin_alpha_minub8 -#define minsb8 __builtin_alpha_minsb8 -#define minuw4 __builtin_alpha_minuw4 -#define minsw4 __builtin_alpha_minsw4 -#define maxub8 __builtin_alpha_maxub8 -#define maxsb8 __builtin_alpha_maxsb8 -#define maxuw4 __builtin_alpha_maxuw4 -#define maxsw4 __builtin_alpha_maxsw4 -#define perr __builtin_alpha_perr -#define pklb __builtin_alpha_pklb -#define pkwb __builtin_alpha_pkwb -#define unpkbl __builtin_alpha_unpkbl -#define unpkbw __builtin_alpha_unpkbw -#else -#define minub8(a, b) ({ uint64_t __r; __asm__ (".arch ev6; minub8 %r1,%2,%0" : "=r" (__r) : "%rJ" (a), "rI" (b)); __r; }) -#define minsb8(a, b) ({ uint64_t __r; __asm__ (".arch ev6; minsb8 %r1,%2,%0" : "=r" (__r) : "%rJ" (a), "rI" (b)); __r; }) -#define minuw4(a, b) ({ uint64_t __r; __asm__ (".arch ev6; minuw4 %r1,%2,%0" : "=r" (__r) : "%rJ" (a), "rI" (b)); __r; }) -#define minsw4(a, b) ({ uint64_t __r; __asm__ (".arch ev6; minsw4 %r1,%2,%0" : "=r" (__r) : "%rJ" (a), "rI" (b)); __r; }) -#define maxub8(a, b) ({ uint64_t __r; __asm__ (".arch ev6; maxub8 %r1,%2,%0" : "=r" (__r) : "%rJ" (a), "rI" (b)); __r; }) -#define maxsb8(a, b) ({ uint64_t __r; __asm__ (".arch ev6; maxsb8 %r1,%2,%0" : "=r" (__r) : "%rJ" (a), "rI" (b)); __r; }) -#define maxuw4(a, b) ({ uint64_t __r; __asm__ (".arch ev6; maxuw4 %r1,%2,%0" : "=r" (__r) : "%rJ" (a), "rI" (b)); __r; }) -#define maxsw4(a, b) ({ uint64_t __r; __asm__ (".arch ev6; maxsw4 %r1,%2,%0" : "=r" (__r) : "%rJ" (a), "rI" (b)); __r; }) -#define perr(a, b) ({ uint64_t __r; __asm__ (".arch ev6; perr %r1,%r2,%0" : "=r" (__r) : "%rJ" (a), "rJ" (b)); __r; }) -#define pklb(a) ({ uint64_t __r; __asm__ (".arch ev6; pklb %r1,%0" : "=r" (__r) : "rJ" (a)); __r; }) -#define pkwb(a) ({ uint64_t __r; __asm__ (".arch ev6; pkwb %r1,%0" : "=r" (__r) : "rJ" (a)); __r; }) -#define unpkbl(a) ({ uint64_t __r; __asm__ (".arch ev6; unpkbl %r1,%0" : "=r" (__r) : "rJ" (a)); __r; }) -#define unpkbw(a) ({ uint64_t __r; __asm__ (".arch ev6; unpkbw %r1,%0" : "=r" (__r) : "rJ" (a)); __r; }) -#endif - -#else -#error "Unknown compiler!" -#endif - -#endif /* AVCODEC_ALPHA_ASM_H */ diff --git a/libavcodec/alpha/hpeldsp_alpha.c b/libavcodec/alpha/hpeldsp_alpha.c deleted file mode 100644 index 8d54807d8..000000000 --- a/libavcodec/alpha/hpeldsp_alpha.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Alpha optimized DSP utils - * Copyright (c) 2002 Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 "libavcodec/hpeldsp.h" -#include "hpeldsp_alpha.h" -#include "asm.h" - -static inline uint64_t avg2_no_rnd(uint64_t a, uint64_t b) -{ - return (a & b) + (((a ^ b) & BYTE_VEC(0xfe)) >> 1); -} - -static inline uint64_t avg2(uint64_t a, uint64_t b) -{ - return (a | b) - (((a ^ b) & BYTE_VEC(0xfe)) >> 1); -} - -#if 0 -/* The XY2 routines basically utilize this scheme, but reuse parts in - each iteration. */ -static inline uint64_t avg4(uint64_t l1, uint64_t l2, uint64_t l3, uint64_t l4) -{ - uint64_t r1 = ((l1 & ~BYTE_VEC(0x03)) >> 2) - + ((l2 & ~BYTE_VEC(0x03)) >> 2) - + ((l3 & ~BYTE_VEC(0x03)) >> 2) - + ((l4 & ~BYTE_VEC(0x03)) >> 2); - uint64_t r2 = (( (l1 & BYTE_VEC(0x03)) - + (l2 & BYTE_VEC(0x03)) - + (l3 & BYTE_VEC(0x03)) - + (l4 & BYTE_VEC(0x03)) - + BYTE_VEC(0x02)) >> 2) & BYTE_VEC(0x03); - return r1 + r2; -} -#endif - -#define OP(LOAD, STORE) \ - do { \ - STORE(LOAD(pixels), block); \ - pixels += line_size; \ - block += line_size; \ - } while (--h) - -#define OP_X2(LOAD, STORE) \ - do { \ - uint64_t pix1, pix2; \ - \ - pix1 = LOAD(pixels); \ - pix2 = pix1 >> 8 | ((uint64_t) pixels[8] << 56); \ - STORE(AVG2(pix1, pix2), block); \ - pixels += line_size; \ - block += line_size; \ - } while (--h) - -#define OP_Y2(LOAD, STORE) \ - do { \ - uint64_t pix = LOAD(pixels); \ - do { \ - uint64_t next_pix; \ - \ - pixels += line_size; \ - next_pix = LOAD(pixels); \ - STORE(AVG2(pix, next_pix), block); \ - block += line_size; \ - pix = next_pix; \ - } while (--h); \ - } while (0) - -#define OP_XY2(LOAD, STORE) \ - do { \ - uint64_t pix1 = LOAD(pixels); \ - uint64_t pix2 = pix1 >> 8 | ((uint64_t) pixels[8] << 56); \ - uint64_t pix_l = (pix1 & BYTE_VEC(0x03)) \ - + (pix2 & BYTE_VEC(0x03)); \ - uint64_t pix_h = ((pix1 & ~BYTE_VEC(0x03)) >> 2) \ - + ((pix2 & ~BYTE_VEC(0x03)) >> 2); \ - \ - do { \ - uint64_t npix1, npix2; \ - uint64_t npix_l, npix_h; \ - uint64_t avg; \ - \ - pixels += line_size; \ - npix1 = LOAD(pixels); \ - npix2 = npix1 >> 8 | ((uint64_t) pixels[8] << 56); \ - npix_l = (npix1 & BYTE_VEC(0x03)) \ - + (npix2 & BYTE_VEC(0x03)); \ - npix_h = ((npix1 & ~BYTE_VEC(0x03)) >> 2) \ - + ((npix2 & ~BYTE_VEC(0x03)) >> 2); \ - avg = (((pix_l + npix_l + AVG4_ROUNDER) >> 2) & BYTE_VEC(0x03)) \ - + pix_h + npix_h; \ - STORE(avg, block); \ - \ - block += line_size; \ - pix_l = npix_l; \ - pix_h = npix_h; \ - } while (--h); \ - } while (0) - -#define MAKE_OP(OPNAME, SUFF, OPKIND, STORE) \ -static void OPNAME ## _pixels ## SUFF ## _axp \ - (uint8_t *restrict block, const uint8_t *restrict pixels, \ - ptrdiff_t line_size, int h) \ -{ \ - if ((size_t) pixels & 0x7) { \ - OPKIND(uldq, STORE); \ - } else { \ - OPKIND(ldq, STORE); \ - } \ -} \ - \ -static void OPNAME ## _pixels16 ## SUFF ## _axp \ - (uint8_t *restrict block, const uint8_t *restrict pixels, \ - ptrdiff_t line_size, int h) \ -{ \ - OPNAME ## _pixels ## SUFF ## _axp(block, pixels, line_size, h); \ - OPNAME ## _pixels ## SUFF ## _axp(block + 8, pixels + 8, line_size, h); \ -} - -#define PIXOP(OPNAME, STORE) \ - MAKE_OP(OPNAME, , OP, STORE) \ - MAKE_OP(OPNAME, _x2, OP_X2, STORE) \ - MAKE_OP(OPNAME, _y2, OP_Y2, STORE) \ - MAKE_OP(OPNAME, _xy2, OP_XY2, STORE) - -/* Rounding primitives. */ -#define AVG2 avg2 -#define AVG4 avg4 -#define AVG4_ROUNDER BYTE_VEC(0x02) -#define STORE(l, b) stq(l, b) -PIXOP(put, STORE); - -#undef STORE -#define STORE(l, b) stq(AVG2(l, ldq(b)), b); -PIXOP(avg, STORE); - -/* Not rounding primitives. */ -#undef AVG2 -#undef AVG4 -#undef AVG4_ROUNDER -#undef STORE -#define AVG2 avg2_no_rnd -#define AVG4 avg4_no_rnd -#define AVG4_ROUNDER BYTE_VEC(0x01) -#define STORE(l, b) stq(l, b) -PIXOP(put_no_rnd, STORE); - -#undef STORE -#define STORE(l, b) stq(AVG2(l, ldq(b)), b); -PIXOP(avg_no_rnd, STORE); - -static void put_pixels16_axp_asm(uint8_t *block, const uint8_t *pixels, - ptrdiff_t line_size, int h) -{ - put_pixels_axp_asm(block, pixels, line_size, h); - put_pixels_axp_asm(block + 8, pixels + 8, line_size, h); -} - -av_cold void ff_hpeldsp_init_alpha(HpelDSPContext *c, int flags) -{ - c->put_pixels_tab[0][0] = put_pixels16_axp_asm; - c->put_pixels_tab[0][1] = put_pixels16_x2_axp; - c->put_pixels_tab[0][2] = put_pixels16_y2_axp; - c->put_pixels_tab[0][3] = put_pixels16_xy2_axp; - - c->put_no_rnd_pixels_tab[0][0] = put_pixels16_axp_asm; - c->put_no_rnd_pixels_tab[0][1] = put_no_rnd_pixels16_x2_axp; - c->put_no_rnd_pixels_tab[0][2] = put_no_rnd_pixels16_y2_axp; - c->put_no_rnd_pixels_tab[0][3] = put_no_rnd_pixels16_xy2_axp; - - c->avg_pixels_tab[0][0] = avg_pixels16_axp; - c->avg_pixels_tab[0][1] = avg_pixels16_x2_axp; - c->avg_pixels_tab[0][2] = avg_pixels16_y2_axp; - c->avg_pixels_tab[0][3] = avg_pixels16_xy2_axp; - - c->avg_no_rnd_pixels_tab[0] = avg_no_rnd_pixels16_axp; - c->avg_no_rnd_pixels_tab[1] = avg_no_rnd_pixels16_x2_axp; - c->avg_no_rnd_pixels_tab[2] = avg_no_rnd_pixels16_y2_axp; - c->avg_no_rnd_pixels_tab[3] = avg_no_rnd_pixels16_xy2_axp; - - c->put_pixels_tab[1][0] = put_pixels_axp_asm; - c->put_pixels_tab[1][1] = put_pixels_x2_axp; - c->put_pixels_tab[1][2] = put_pixels_y2_axp; - c->put_pixels_tab[1][3] = put_pixels_xy2_axp; - - c->put_no_rnd_pixels_tab[1][0] = put_pixels_axp_asm; - c->put_no_rnd_pixels_tab[1][1] = put_no_rnd_pixels_x2_axp; - c->put_no_rnd_pixels_tab[1][2] = put_no_rnd_pixels_y2_axp; - c->put_no_rnd_pixels_tab[1][3] = put_no_rnd_pixels_xy2_axp; - - c->avg_pixels_tab[1][0] = avg_pixels_axp; - c->avg_pixels_tab[1][1] = avg_pixels_x2_axp; - c->avg_pixels_tab[1][2] = avg_pixels_y2_axp; - c->avg_pixels_tab[1][3] = avg_pixels_xy2_axp; -} diff --git a/libavcodec/alpha/hpeldsp_alpha_asm.S b/libavcodec/alpha/hpeldsp_alpha_asm.S deleted file mode 100644 index df386c429..000000000 --- a/libavcodec/alpha/hpeldsp_alpha_asm.S +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Alpha optimized DSP utils - * Copyright (c) 2002 Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * These functions are scheduled for pca56. They should work - * reasonably on ev6, though. - */ - -#include "regdef.h" - - - .set noat - .set noreorder - .arch pca56 - .text - -/************************************************************************ - * void put_pixels_axp_asm(uint8_t *block, const uint8_t *pixels, - * int line_size, int h) - */ - .align 6 - .globl put_pixels_axp_asm - .ent put_pixels_axp_asm -put_pixels_axp_asm: - .frame sp, 0, ra - .prologue 0 - - and a1, 7, t0 - beq t0, $aligned - - .align 4 -$unaligned: - ldq_u t0, 0(a1) - ldq_u t1, 8(a1) - addq a1, a2, a1 - nop - - ldq_u t2, 0(a1) - ldq_u t3, 8(a1) - addq a1, a2, a1 - nop - - ldq_u t4, 0(a1) - ldq_u t5, 8(a1) - addq a1, a2, a1 - nop - - ldq_u t6, 0(a1) - ldq_u t7, 8(a1) - extql t0, a1, t0 - addq a1, a2, a1 - - extqh t1, a1, t1 - addq a0, a2, t8 - extql t2, a1, t2 - addq t8, a2, t9 - - extqh t3, a1, t3 - addq t9, a2, ta - extql t4, a1, t4 - or t0, t1, t0 - - extqh t5, a1, t5 - or t2, t3, t2 - extql t6, a1, t6 - or t4, t5, t4 - - extqh t7, a1, t7 - or t6, t7, t6 - stq t0, 0(a0) - stq t2, 0(t8) - - stq t4, 0(t9) - subq a3, 4, a3 - stq t6, 0(ta) - addq ta, a2, a0 - - bne a3, $unaligned - ret - - .align 4 -$aligned: - ldq t0, 0(a1) - addq a1, a2, a1 - ldq t1, 0(a1) - addq a1, a2, a1 - - ldq t2, 0(a1) - addq a1, a2, a1 - ldq t3, 0(a1) - - addq a0, a2, t4 - addq a1, a2, a1 - addq t4, a2, t5 - subq a3, 4, a3 - - stq t0, 0(a0) - addq t5, a2, t6 - stq t1, 0(t4) - addq t6, a2, a0 - - stq t2, 0(t5) - stq t3, 0(t6) - - bne a3, $aligned - ret - .end put_pixels_axp_asm diff --git a/libavcodec/alpha/idctdsp_alpha.c b/libavcodec/alpha/idctdsp_alpha.c deleted file mode 100644 index ff770c15f..000000000 --- a/libavcodec/alpha/idctdsp_alpha.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2002 Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 "libavcodec/avcodec.h" -#include "libavcodec/idctdsp.h" -#include "idctdsp_alpha.h" -#include "asm.h" - -void put_pixels_clamped_mvi_asm(const int16_t *block, uint8_t *pixels, - ptrdiff_t line_size); -void add_pixels_clamped_mvi_asm(const int16_t *block, uint8_t *pixels, - ptrdiff_t line_size); - -void (*put_pixels_clamped_axp_p)(const int16_t *block, uint8_t *pixels, - ptrdiff_t line_size); -void (*add_pixels_clamped_axp_p)(const int16_t *block, uint8_t *pixels, - ptrdiff_t line_size); - -#if 0 -/* These functions were the base for the optimized assembler routines, - and remain here for documentation purposes. */ -static void put_pixels_clamped_mvi(const int16_t *block, uint8_t *pixels, - ptrdiff_t line_size) -{ - int i = 8; - uint64_t clampmask = zap(-1, 0xaa); /* 0x00ff00ff00ff00ff */ - - do { - uint64_t shorts0, shorts1; - - shorts0 = ldq(block); - shorts0 = maxsw4(shorts0, 0); - shorts0 = minsw4(shorts0, clampmask); - stl(pkwb(shorts0), pixels); - - shorts1 = ldq(block + 4); - shorts1 = maxsw4(shorts1, 0); - shorts1 = minsw4(shorts1, clampmask); - stl(pkwb(shorts1), pixels + 4); - - pixels += line_size; - block += 8; - } while (--i); -} - -void add_pixels_clamped_mvi(const int16_t *block, uint8_t *pixels, - ptrdiff_t line_size) -{ - int h = 8; - /* Keep this function a leaf function by generating the constants - manually (mainly for the hack value ;-). */ - uint64_t clampmask = zap(-1, 0xaa); /* 0x00ff00ff00ff00ff */ - uint64_t signmask = zap(-1, 0x33); - signmask ^= signmask >> 1; /* 0x8000800080008000 */ - - do { - uint64_t shorts0, pix0, signs0; - uint64_t shorts1, pix1, signs1; - - shorts0 = ldq(block); - shorts1 = ldq(block + 4); - - pix0 = unpkbw(ldl(pixels)); - /* Signed subword add (MMX paddw). */ - signs0 = shorts0 & signmask; - shorts0 &= ~signmask; - shorts0 += pix0; - shorts0 ^= signs0; - /* Clamp. */ - shorts0 = maxsw4(shorts0, 0); - shorts0 = minsw4(shorts0, clampmask); - - /* Next 4. */ - pix1 = unpkbw(ldl(pixels + 4)); - signs1 = shorts1 & signmask; - shorts1 &= ~signmask; - shorts1 += pix1; - shorts1 ^= signs1; - shorts1 = maxsw4(shorts1, 0); - shorts1 = minsw4(shorts1, clampmask); - - stl(pkwb(shorts0), pixels); - stl(pkwb(shorts1), pixels + 4); - - pixels += line_size; - block += 8; - } while (--h); -} -#endif - -av_cold void ff_idctdsp_init_alpha(IDCTDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth) -{ - /* amask clears all bits that correspond to present features. */ - if (amask(AMASK_MVI) == 0) { - c->put_pixels_clamped = put_pixels_clamped_mvi_asm; - c->add_pixels_clamped = add_pixels_clamped_mvi_asm; - } - - put_pixels_clamped_axp_p = c->put_pixels_clamped; - add_pixels_clamped_axp_p = c->add_pixels_clamped; - - if (!high_bit_depth && !avctx->lowres && - (avctx->idct_algo == FF_IDCT_AUTO)) { - c->idct_put = ff_simple_idct_put_axp; - c->idct_add = ff_simple_idct_add_axp; - c->idct = ff_simple_idct_axp; - } -} diff --git a/libavcodec/alpha/idctdsp_alpha.h b/libavcodec/alpha/idctdsp_alpha.h deleted file mode 100644 index 8cc969d7d..000000000 --- a/libavcodec/alpha/idctdsp_alpha.h +++ /dev/null @@ -1,34 +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_ALPHA_IDCTDSP_ALPHA_H -#define AVCODEC_ALPHA_IDCTDSP_ALPHA_H - -#include -#include - -extern void (*put_pixels_clamped_axp_p)(const int16_t *block, uint8_t *pixels, - ptrdiff_t line_size); -extern void (*add_pixels_clamped_axp_p)(const int16_t *block, uint8_t *pixels, - ptrdiff_t line_size); - -void ff_simple_idct_axp(int16_t *block); -void ff_simple_idct_put_axp(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_simple_idct_add_axp(uint8_t *dest, ptrdiff_t line_size, int16_t *block); - -#endif /* AVCODEC_ALPHA_IDCTDSP_ALPHA_H */ diff --git a/libavcodec/alpha/idctdsp_alpha_asm.S b/libavcodec/alpha/idctdsp_alpha_asm.S deleted file mode 100644 index f545df9e4..000000000 --- a/libavcodec/alpha/idctdsp_alpha_asm.S +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Alpha optimized IDCT-related routines - * Copyright (c) 2002 Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * These functions are scheduled for pca56. They should work - * reasonably on ev6, though. - */ - -#include "regdef.h" - - .set noat - .set noreorder - .arch pca56 - .text - -/************************************************************************ - * void put_pixels_clamped_mvi_asm(const int16_t *block, uint8_t *pixels, - * ptrdiff_t line_size) - */ - .align 6 - .globl put_pixels_clamped_mvi_asm - .ent put_pixels_clamped_mvi_asm -put_pixels_clamped_mvi_asm: - .frame sp, 0, ra - .prologue 0 - - lda t8, -1 - lda t9, 8 # loop counter - zap t8, 0xaa, t8 # 00ff00ff00ff00ff - - .align 4 -1: ldq t0, 0(a0) - ldq t1, 8(a0) - ldq t2, 16(a0) - ldq t3, 24(a0) - - maxsw4 t0, zero, t0 - subq t9, 2, t9 - maxsw4 t1, zero, t1 - lda a0, 32(a0) - - maxsw4 t2, zero, t2 - addq a1, a2, ta - maxsw4 t3, zero, t3 - minsw4 t0, t8, t0 - - minsw4 t1, t8, t1 - minsw4 t2, t8, t2 - minsw4 t3, t8, t3 - pkwb t0, t0 - - pkwb t1, t1 - pkwb t2, t2 - pkwb t3, t3 - stl t0, 0(a1) - - stl t1, 4(a1) - addq ta, a2, a1 - stl t2, 0(ta) - stl t3, 4(ta) - - bne t9, 1b - ret - .end put_pixels_clamped_mvi_asm - -/************************************************************************ - * void add_pixels_clamped_mvi_asm(const int16_t *block, uint8_t *pixels, - * ptrdiff_t line_size) - */ - .align 6 - .globl add_pixels_clamped_mvi_asm - .ent add_pixels_clamped_mvi_asm -add_pixels_clamped_mvi_asm: - .frame sp, 0, ra - .prologue 0 - - lda t1, -1 - lda th, 8 - zap t1, 0x33, tg - nop - - srl tg, 1, t0 - xor tg, t0, tg # 0x8000800080008000 - zap t1, 0xaa, tf # 0x00ff00ff00ff00ff - - .align 4 -1: ldl t1, 0(a1) # pix0 (try to hit cache line soon) - ldl t4, 4(a1) # pix1 - addq a1, a2, te # pixels += line_size - ldq t0, 0(a0) # shorts0 - - ldl t7, 0(te) # pix2 (try to hit cache line soon) - ldl ta, 4(te) # pix3 - ldq t3, 8(a0) # shorts1 - ldq t6, 16(a0) # shorts2 - - ldq t9, 24(a0) # shorts3 - unpkbw t1, t1 # 0 0 (quarter/op no.) - and t0, tg, t2 # 0 1 - unpkbw t4, t4 # 1 0 - - bic t0, tg, t0 # 0 2 - unpkbw t7, t7 # 2 0 - and t3, tg, t5 # 1 1 - addq t0, t1, t0 # 0 3 - - xor t0, t2, t0 # 0 4 - unpkbw ta, ta # 3 0 - and t6, tg, t8 # 2 1 - maxsw4 t0, zero, t0 # 0 5 - - bic t3, tg, t3 # 1 2 - bic t6, tg, t6 # 2 2 - minsw4 t0, tf, t0 # 0 6 - addq t3, t4, t3 # 1 3 - - pkwb t0, t0 # 0 7 - xor t3, t5, t3 # 1 4 - maxsw4 t3, zero, t3 # 1 5 - addq t6, t7, t6 # 2 3 - - xor t6, t8, t6 # 2 4 - and t9, tg, tb # 3 1 - minsw4 t3, tf, t3 # 1 6 - bic t9, tg, t9 # 3 2 - - maxsw4 t6, zero, t6 # 2 5 - addq t9, ta, t9 # 3 3 - stl t0, 0(a1) # 0 8 - minsw4 t6, tf, t6 # 2 6 - - xor t9, tb, t9 # 3 4 - maxsw4 t9, zero, t9 # 3 5 - lda a0, 32(a0) # block += 16; - pkwb t3, t3 # 1 7 - - minsw4 t9, tf, t9 # 3 6 - subq th, 2, th - pkwb t6, t6 # 2 7 - pkwb t9, t9 # 3 7 - - stl t3, 4(a1) # 1 8 - addq te, a2, a1 # pixels += line_size - stl t6, 0(te) # 2 8 - stl t9, 4(te) # 3 8 - - bne th, 1b - ret - .end add_pixels_clamped_mvi_asm diff --git a/libavcodec/alpha/me_cmp_alpha.c b/libavcodec/alpha/me_cmp_alpha.c deleted file mode 100644 index 0c1a4a62c..000000000 --- a/libavcodec/alpha/me_cmp_alpha.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Alpha optimized DSP utils - * Copyright (c) 2002 Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 "libavcodec/me_cmp.h" -#include "asm.h" - -int pix_abs16x16_mvi_asm(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t line_size, int h); - -static inline uint64_t avg2(uint64_t a, uint64_t b) -{ - return (a | b) - (((a ^ b) & BYTE_VEC(0xfe)) >> 1); -} - -static inline uint64_t avg4(uint64_t l1, uint64_t l2, uint64_t l3, uint64_t l4) -{ - uint64_t r1 = ((l1 & ~BYTE_VEC(0x03)) >> 2) - + ((l2 & ~BYTE_VEC(0x03)) >> 2) - + ((l3 & ~BYTE_VEC(0x03)) >> 2) - + ((l4 & ~BYTE_VEC(0x03)) >> 2); - uint64_t r2 = (( (l1 & BYTE_VEC(0x03)) - + (l2 & BYTE_VEC(0x03)) - + (l3 & BYTE_VEC(0x03)) - + (l4 & BYTE_VEC(0x03)) - + BYTE_VEC(0x02)) >> 2) & BYTE_VEC(0x03); - return r1 + r2; -} - -static int pix_abs8x8_mvi(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t line_size, int h) -{ - int result = 0; - - if ((size_t) pix2 & 0x7) { - /* works only when pix2 is actually unaligned */ - do { /* do 8 pixel a time */ - uint64_t p1, p2; - - p1 = ldq(pix1); - p2 = uldq(pix2); - result += perr(p1, p2); - - pix1 += line_size; - pix2 += line_size; - } while (--h); - } else { - do { - uint64_t p1, p2; - - p1 = ldq(pix1); - p2 = ldq(pix2); - result += perr(p1, p2); - - pix1 += line_size; - pix2 += line_size; - } while (--h); - } - - return result; -} - -static int pix_abs16x16_x2_mvi(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t line_size, int h) -{ - int result = 0; - uint64_t disalign = (size_t) pix2 & 0x7; - - switch (disalign) { - case 0: - do { - uint64_t p1_l, p1_r, p2_l, p2_r; - uint64_t l, r; - - p1_l = ldq(pix1); - p1_r = ldq(pix1 + 8); - l = ldq(pix2); - r = ldq(pix2 + 8); - p2_l = avg2(l, (l >> 8) | ((uint64_t) r << 56)); - p2_r = avg2(r, (r >> 8) | ((uint64_t) pix2[16] << 56)); - pix1 += line_size; - pix2 += line_size; - - result += perr(p1_l, p2_l) - + perr(p1_r, p2_r); - } while (--h); - break; - case 7: - /* |.......l|lllllllr|rrrrrrr*| - This case is special because disalign1 would be 8, which - gets treated as 0 by extqh. At least it is a bit faster - that way :) */ - do { - uint64_t p1_l, p1_r, p2_l, p2_r; - uint64_t l, m, r; - - p1_l = ldq(pix1); - p1_r = ldq(pix1 + 8); - l = ldq_u(pix2); - m = ldq_u(pix2 + 8); - r = ldq_u(pix2 + 16); - p2_l = avg2(extql(l, disalign) | extqh(m, disalign), m); - p2_r = avg2(extql(m, disalign) | extqh(r, disalign), r); - pix1 += line_size; - pix2 += line_size; - - result += perr(p1_l, p2_l) - + perr(p1_r, p2_r); - } while (--h); - break; - default: - do { - uint64_t disalign1 = disalign + 1; - uint64_t p1_l, p1_r, p2_l, p2_r; - uint64_t l, m, r; - - p1_l = ldq(pix1); - p1_r = ldq(pix1 + 8); - l = ldq_u(pix2); - m = ldq_u(pix2 + 8); - r = ldq_u(pix2 + 16); - p2_l = avg2(extql(l, disalign) | extqh(m, disalign), - extql(l, disalign1) | extqh(m, disalign1)); - p2_r = avg2(extql(m, disalign) | extqh(r, disalign), - extql(m, disalign1) | extqh(r, disalign1)); - pix1 += line_size; - pix2 += line_size; - - result += perr(p1_l, p2_l) - + perr(p1_r, p2_r); - } while (--h); - break; - } - return result; -} - -static int pix_abs16x16_y2_mvi(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t line_size, int h) -{ - int result = 0; - - if ((size_t) pix2 & 0x7) { - uint64_t t, p2_l, p2_r; - t = ldq_u(pix2 + 8); - p2_l = extql(ldq_u(pix2), pix2) | extqh(t, pix2); - p2_r = extql(t, pix2) | extqh(ldq_u(pix2 + 16), pix2); - - do { - uint64_t p1_l, p1_r, np2_l, np2_r; - uint64_t t; - - p1_l = ldq(pix1); - p1_r = ldq(pix1 + 8); - pix2 += line_size; - t = ldq_u(pix2 + 8); - np2_l = extql(ldq_u(pix2), pix2) | extqh(t, pix2); - np2_r = extql(t, pix2) | extqh(ldq_u(pix2 + 16), pix2); - - result += perr(p1_l, avg2(p2_l, np2_l)) - + perr(p1_r, avg2(p2_r, np2_r)); - - pix1 += line_size; - p2_l = np2_l; - p2_r = np2_r; - - } while (--h); - } else { - uint64_t p2_l, p2_r; - p2_l = ldq(pix2); - p2_r = ldq(pix2 + 8); - do { - uint64_t p1_l, p1_r, np2_l, np2_r; - - p1_l = ldq(pix1); - p1_r = ldq(pix1 + 8); - pix2 += line_size; - np2_l = ldq(pix2); - np2_r = ldq(pix2 + 8); - - result += perr(p1_l, avg2(p2_l, np2_l)) - + perr(p1_r, avg2(p2_r, np2_r)); - - pix1 += line_size; - p2_l = np2_l; - p2_r = np2_r; - } while (--h); - } - return result; -} - -static int pix_abs16x16_xy2_mvi(struct MpegEncContext *v, const uint8_t *pix1, const uint8_t *pix2, - ptrdiff_t line_size, int h) -{ - int result = 0; - - uint64_t p1_l, p1_r; - uint64_t p2_l, p2_r, p2_x; - - p1_l = ldq(pix1); - p1_r = ldq(pix1 + 8); - - if ((size_t) pix2 & 0x7) { /* could be optimized a lot */ - p2_l = uldq(pix2); - p2_r = uldq(pix2 + 8); - p2_x = (uint64_t) pix2[16] << 56; - } else { - p2_l = ldq(pix2); - p2_r = ldq(pix2 + 8); - p2_x = ldq(pix2 + 16) << 56; - } - - do { - uint64_t np1_l, np1_r; - uint64_t np2_l, np2_r, np2_x; - - pix1 += line_size; - pix2 += line_size; - - np1_l = ldq(pix1); - np1_r = ldq(pix1 + 8); - - if ((size_t) pix2 & 0x7) { /* could be optimized a lot */ - np2_l = uldq(pix2); - np2_r = uldq(pix2 + 8); - np2_x = (uint64_t) pix2[16] << 56; - } else { - np2_l = ldq(pix2); - np2_r = ldq(pix2 + 8); - np2_x = ldq(pix2 + 16) << 56; - } - - result += perr(p1_l, - avg4( p2_l, ( p2_l >> 8) | ((uint64_t) p2_r << 56), - np2_l, (np2_l >> 8) | ((uint64_t) np2_r << 56))) - + perr(p1_r, - avg4( p2_r, ( p2_r >> 8) | ((uint64_t) p2_x), - np2_r, (np2_r >> 8) | ((uint64_t) np2_x))); - - p1_l = np1_l; - p1_r = np1_r; - p2_l = np2_l; - p2_r = np2_r; - p2_x = np2_x; - } while (--h); - - return result; -} - -av_cold void ff_me_cmp_init_alpha(MECmpContext *c, AVCodecContext *avctx) -{ - /* amask clears all bits that correspond to present features. */ - if (amask(AMASK_MVI) == 0) { - c->sad[0] = pix_abs16x16_mvi_asm; - c->sad[1] = pix_abs8x8_mvi; - c->pix_abs[0][0] = pix_abs16x16_mvi_asm; - c->pix_abs[1][0] = pix_abs8x8_mvi; - c->pix_abs[0][1] = pix_abs16x16_x2_mvi; - c->pix_abs[0][2] = pix_abs16x16_y2_mvi; - c->pix_abs[0][3] = pix_abs16x16_xy2_mvi; - } -} diff --git a/libavcodec/alpha/me_cmp_mvi_asm.S b/libavcodec/alpha/me_cmp_mvi_asm.S deleted file mode 100644 index 183feeb40..000000000 --- a/libavcodec/alpha/me_cmp_mvi_asm.S +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Alpha optimized DSP utils - * Copyright (c) 2002 Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 "regdef.h" - -/* Some nicer register names. */ -#define ta t10 -#define tb t11 -#define tc t12 -#define td AT -/* Danger: these overlap with the argument list and the return value */ -#define te a5 -#define tf a4 -#define tg a3 -#define th v0 - - .set noat - .set noreorder - .arch pca56 - .text - -/***************************************************************************** - * int pix_abs16x16_mvi_asm(const uint8_t *pix1, const uint8_t *pix2, int line_size) - * - * This code is written with a pca56 in mind. For ev6, one should - * really take the increased latency of 3 cycles for MVI instructions - * into account. - * - * It is important to keep the loading and first use of a register as - * far apart as possible, because if a register is accessed before it - * has been fetched from memory, the CPU will stall. - */ - .align 4 - .globl pix_abs16x16_mvi_asm - .ent pix_abs16x16_mvi_asm -pix_abs16x16_mvi_asm: - .frame sp, 0, ra, 0 - .prologue 0 - - and a2, 7, t0 - clr v0 - beq t0, $aligned - .align 4 -$unaligned: - /* Registers: - line 0: - t0: left_u -> left lo -> left - t1: mid - t2: right_u -> right hi -> right - t3: ref left - t4: ref right - line 1: - t5: left_u -> left lo -> left - t6: mid - t7: right_u -> right hi -> right - t8: ref left - t9: ref right - temp: - ta: left hi - tb: right lo - tc: error left - td: error right */ - - /* load line 0 */ - ldq_u t0, 0(a2) # left_u - ldq_u t1, 8(a2) # mid - ldq_u t2, 16(a2) # right_u - ldq t3, 0(a1) # ref left - ldq t4, 8(a1) # ref right - addq a1, a3, a1 # pix1 - addq a2, a3, a2 # pix2 - /* load line 1 */ - ldq_u t5, 0(a2) # left_u - ldq_u t6, 8(a2) # mid - ldq_u t7, 16(a2) # right_u - ldq t8, 0(a1) # ref left - ldq t9, 8(a1) # ref right - addq a1, a3, a1 # pix1 - addq a2, a3, a2 # pix2 - /* calc line 0 */ - extql t0, a2, t0 # left lo - extqh t1, a2, ta # left hi - extql t1, a2, tb # right lo - or t0, ta, t0 # left - extqh t2, a2, t2 # right hi - perr t3, t0, tc # error left - or t2, tb, t2 # right - perr t4, t2, td # error right - addq v0, tc, v0 # add error left - addq v0, td, v0 # add error left - /* calc line 1 */ - extql t5, a2, t5 # left lo - extqh t6, a2, ta # left hi - extql t6, a2, tb # right lo - or t5, ta, t5 # left - extqh t7, a2, t7 # right hi - perr t8, t5, tc # error left - or t7, tb, t7 # right - perr t9, t7, td # error right - addq v0, tc, v0 # add error left - addq v0, td, v0 # add error left - /* loop */ - subq a4, 2, a4 # h -= 2 - bne a4, $unaligned - ret - - .align 4 -$aligned: - /* load line 0 */ - ldq t0, 0(a2) # left - ldq t1, 8(a2) # right - addq a2, a3, a2 # pix2 - ldq t2, 0(a1) # ref left - ldq t3, 8(a1) # ref right - addq a1, a3, a1 # pix1 - /* load line 1 */ - ldq t4, 0(a2) # left - ldq t5, 8(a2) # right - addq a2, a3, a2 # pix2 - ldq t6, 0(a1) # ref left - ldq t7, 8(a1) # ref right - addq a1, a3, a1 # pix1 - /* load line 2 */ - ldq t8, 0(a2) # left - ldq t9, 8(a2) # right - addq a2, a3, a2 # pix2 - ldq ta, 0(a1) # ref left - ldq tb, 8(a1) # ref right - addq a1, a3, a1 # pix1 - /* load line 3 */ - ldq tc, 0(a2) # left - ldq td, 8(a2) # right - addq a2, a3, a2 # pix2 - ldq te, 0(a1) # ref left - ldq a0, 8(a1) # ref right - /* calc line 0 */ - perr t0, t2, t0 # error left - addq a1, a3, a1 # pix1 - perr t1, t3, t1 # error right - addq v0, t0, v0 # add error left - /* calc line 1 */ - perr t4, t6, t0 # error left - addq v0, t1, v0 # add error right - perr t5, t7, t1 # error right - addq v0, t0, v0 # add error left - /* calc line 2 */ - perr t8, ta, t0 # error left - addq v0, t1, v0 # add error right - perr t9, tb, t1 # error right - addq v0, t0, v0 # add error left - /* calc line 3 */ - perr tc, te, t0 # error left - addq v0, t1, v0 # add error right - perr td, a0, t1 # error right - addq v0, t0, v0 # add error left - addq v0, t1, v0 # add error right - /* loop */ - subq a4, 4, a4 # h -= 4 - bne a4, $aligned - ret - .end pix_abs16x16_mvi_asm diff --git a/libavcodec/alpha/mpegvideo_alpha.c b/libavcodec/alpha/mpegvideo_alpha.c deleted file mode 100644 index 126fe264a..000000000 --- a/libavcodec/alpha/mpegvideo_alpha.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Alpha optimized DSP utils - * Copyright (c) 2002 Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 "libavcodec/mpegvideo.h" -#include "asm.h" - -static void dct_unquantize_h263_axp(int16_t *block, int n_coeffs, - uint64_t qscale, uint64_t qadd) -{ - uint64_t qmul = qscale << 1; - uint64_t correction = WORD_VEC(qmul * 255 >> 8); - int i; - - qadd = WORD_VEC(qadd); - - for(i = 0; i <= n_coeffs; block += 4, i += 4) { - uint64_t levels, negmask, zeros, add, sub; - - levels = ldq(block); - if (levels == 0) - continue; - -#ifdef __alpha_max__ - /* I don't think the speed difference justifies runtime - detection. */ - negmask = maxsw4(levels, -1); /* negative -> ffff (-1) */ - negmask = minsw4(negmask, 0); /* positive -> 0000 (0) */ -#else - negmask = cmpbge(WORD_VEC(0x7fff), levels); - negmask &= (negmask >> 1) | (1 << 7); - negmask = zap(-1, negmask); -#endif - - zeros = cmpbge(0, levels); - zeros &= zeros >> 1; - /* zeros |= zeros << 1 is not needed since qadd <= 255, so - zapping the lower byte suffices. */ - - levels *= qmul; - levels -= correction & (negmask << 16); - - add = qadd & ~negmask; - sub = qadd & negmask; - /* Set qadd to 0 for levels == 0. */ - add = zap(add, zeros); - levels += add; - levels -= sub; - - stq(levels, block); - } -} - -static void dct_unquantize_h263_intra_axp(MpegEncContext *s, int16_t *block, - int n, int qscale) -{ - int n_coeffs; - uint64_t qadd; - int16_t block0 = block[0]; - - if (!s->h263_aic) { - if (n < 4) - block0 *= s->y_dc_scale; - else - block0 *= s->c_dc_scale; - qadd = (qscale - 1) | 1; - } else { - qadd = 0; - } - - if(s->ac_pred) - n_coeffs = 63; - else - n_coeffs = s->inter_scantable.raster_end[s->block_last_index[n]]; - - dct_unquantize_h263_axp(block, n_coeffs, qscale, qadd); - - block[0] = block0; -} - -static void dct_unquantize_h263_inter_axp(MpegEncContext *s, int16_t *block, - int n, int qscale) -{ - int n_coeffs = s->inter_scantable.raster_end[s->block_last_index[n]]; - dct_unquantize_h263_axp(block, n_coeffs, qscale, (qscale - 1) | 1); -} - -av_cold void ff_mpv_common_init_axp(MpegEncContext *s) -{ - s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_axp; - s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_axp; -} diff --git a/libavcodec/alpha/pixblockdsp_alpha.c b/libavcodec/alpha/pixblockdsp_alpha.c deleted file mode 100644 index c2f1a1d79..000000000 --- a/libavcodec/alpha/pixblockdsp_alpha.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SIMD-optimized pixel operations - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 "libavcodec/pixblockdsp.h" -#include "asm.h" - -static void get_pixels_mvi(int16_t *restrict block, - const uint8_t *restrict pixels, ptrdiff_t stride) -{ - int h = 8; - - do { - uint64_t p; - - p = ldq(pixels); - stq(unpkbw(p), block); - stq(unpkbw(p >> 32), block + 4); - - pixels += stride; - block += 8; - } while (--h); -} - -static void diff_pixels_mvi(int16_t *block, const uint8_t *s1, const uint8_t *s2, - ptrdiff_t stride) -{ - int h = 8; - uint64_t mask = 0x4040; - - mask |= mask << 16; - mask |= mask << 32; - do { - uint64_t x, y, c, d, a; - uint64_t signs; - - x = ldq(s1); - y = ldq(s2); - c = cmpbge(x, y); - d = x - y; - a = zap(mask, c); /* We use 0x4040404040404040 here... */ - d += 4 * a; /* ...so we can use s4addq here. */ - signs = zap(-1, c); - - stq(unpkbw(d) | (unpkbw(signs) << 8), block); - stq(unpkbw(d >> 32) | (unpkbw(signs >> 32) << 8), block + 4); - - s1 += stride; - s2 += stride; - block += 8; - } while (--h); -} - -av_cold void ff_pixblockdsp_init_alpha(PixblockDSPContext *c, AVCodecContext *avctx, - unsigned high_bit_depth) -{ - if (amask(AMASK_MVI) == 0) { - if (!high_bit_depth) - c->get_pixels = get_pixels_mvi; - c->diff_pixels = diff_pixels_mvi; - } -} diff --git a/libavcodec/alpha/regdef.h b/libavcodec/alpha/regdef.h deleted file mode 100644 index f05577a89..000000000 --- a/libavcodec/alpha/regdef.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Alpha optimized DSP utils - * copyright (c) 2002 Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* Some BSDs don't seem to have regdef.h... sigh */ -#ifndef AVCODEC_ALPHA_REGDEF_H -#define AVCODEC_ALPHA_REGDEF_H - -#define v0 $0 /* function return value */ - -#define t0 $1 /* temporary registers (caller-saved) */ -#define t1 $2 -#define t2 $3 -#define t3 $4 -#define t4 $5 -#define t5 $6 -#define t6 $7 -#define t7 $8 - -#define s0 $9 /* saved-registers (callee-saved registers) */ -#define s1 $10 -#define s2 $11 -#define s3 $12 -#define s4 $13 -#define s5 $14 -#define s6 $15 -#define fp s6 /* frame-pointer (s6 in frame-less procedures) */ - -#define a0 $16 /* argument registers (caller-saved) */ -#define a1 $17 -#define a2 $18 -#define a3 $19 -#define a4 $20 -#define a5 $21 - -#define t8 $22 /* more temps (caller-saved) */ -#define t9 $23 -#define t10 $24 -#define t11 $25 -#define ra $26 /* return address register */ -#define t12 $27 - -#define pv t12 /* procedure-variable register */ -#define AT $at /* assembler temporary */ -#define gp $29 /* global pointer */ -#define sp $30 /* stack pointer */ -#define zero $31 /* reads as zero, writes are noops */ - -/* Some nicer register names. */ -#define ta t10 -#define tb t11 -#define tc t12 -#define td AT -/* Danger: these overlap with the argument list and the return value */ -#define te a5 -#define tf a4 -#define tg a3 -#define th v0 - -#endif /* AVCODEC_ALPHA_REGDEF_H */ diff --git a/libavcodec/alpha/simple_idct_alpha.c b/libavcodec/alpha/simple_idct_alpha.c deleted file mode 100644 index 6e377ef24..000000000 --- a/libavcodec/alpha/simple_idct_alpha.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Simple IDCT (Alpha optimized) - * - * Copyright (c) 2001 Michael Niedermayer - * - * based upon some outcommented C code from mpeg2dec (idct_mmx.c - * written by Aaron Holtzman ) - * - * Alpha optimizations by Måns Rullgård - * and Falk Hueffner - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 "idctdsp_alpha.h" -#include "asm.h" - -// cos(i * M_PI / 16) * sqrt(2) * (1 << 14) -// W4 is actually exactly 16384, but using 16383 works around -// accumulating rounding errors for some encoders -#define W1 22725 -#define W2 21407 -#define W3 19266 -#define W4 16383 -#define W5 12873 -#define W6 8867 -#define W7 4520 -#define ROW_SHIFT 11 -#define COL_SHIFT 20 - -/* 0: all entries 0, 1: only first entry nonzero, 2: otherwise */ -static inline int idct_row(int16_t *row) -{ - int a0, a1, a2, a3, b0, b1, b2, b3, t; - uint64_t l, r, t2; - l = ldq(row); - r = ldq(row + 4); - - if (l == 0 && r == 0) - return 0; - - a0 = W4 * sextw(l) + (1 << (ROW_SHIFT - 1)); - - if (((l & ~0xffffUL) | r) == 0) { - a0 >>= ROW_SHIFT; - t2 = (uint16_t) a0; - t2 |= t2 << 16; - t2 |= t2 << 32; - - stq(t2, row); - stq(t2, row + 4); - return 1; - } - - a1 = a0; - a2 = a0; - a3 = a0; - - t = extwl(l, 4); /* row[2] */ - if (t != 0) { - t = sextw(t); - a0 += W2 * t; - a1 += W6 * t; - a2 -= W6 * t; - a3 -= W2 * t; - } - - t = extwl(r, 0); /* row[4] */ - if (t != 0) { - t = sextw(t); - a0 += W4 * t; - a1 -= W4 * t; - a2 -= W4 * t; - a3 += W4 * t; - } - - t = extwl(r, 4); /* row[6] */ - if (t != 0) { - t = sextw(t); - a0 += W6 * t; - a1 -= W2 * t; - a2 += W2 * t; - a3 -= W6 * t; - } - - t = extwl(l, 2); /* row[1] */ - if (t != 0) { - t = sextw(t); - b0 = W1 * t; - b1 = W3 * t; - b2 = W5 * t; - b3 = W7 * t; - } else { - b0 = 0; - b1 = 0; - b2 = 0; - b3 = 0; - } - - t = extwl(l, 6); /* row[3] */ - if (t) { - t = sextw(t); - b0 += W3 * t; - b1 -= W7 * t; - b2 -= W1 * t; - b3 -= W5 * t; - } - - - t = extwl(r, 2); /* row[5] */ - if (t) { - t = sextw(t); - b0 += W5 * t; - b1 -= W1 * t; - b2 += W7 * t; - b3 += W3 * t; - } - - t = extwl(r, 6); /* row[7] */ - if (t) { - t = sextw(t); - b0 += W7 * t; - b1 -= W5 * t; - b2 += W3 * t; - b3 -= W1 * t; - } - - row[0] = (a0 + b0) >> ROW_SHIFT; - row[1] = (a1 + b1) >> ROW_SHIFT; - row[2] = (a2 + b2) >> ROW_SHIFT; - row[3] = (a3 + b3) >> ROW_SHIFT; - row[4] = (a3 - b3) >> ROW_SHIFT; - row[5] = (a2 - b2) >> ROW_SHIFT; - row[6] = (a1 - b1) >> ROW_SHIFT; - row[7] = (a0 - b0) >> ROW_SHIFT; - - return 2; -} - -static inline void idct_col(int16_t *col) -{ - int a0, a1, a2, a3, b0, b1, b2, b3; - - col[0] += (1 << (COL_SHIFT - 1)) / W4; - - a0 = W4 * col[8 * 0]; - a1 = W4 * col[8 * 0]; - a2 = W4 * col[8 * 0]; - a3 = W4 * col[8 * 0]; - - if (col[8 * 2]) { - a0 += W2 * col[8 * 2]; - a1 += W6 * col[8 * 2]; - a2 -= W6 * col[8 * 2]; - a3 -= W2 * col[8 * 2]; - } - - if (col[8 * 4]) { - a0 += W4 * col[8 * 4]; - a1 -= W4 * col[8 * 4]; - a2 -= W4 * col[8 * 4]; - a3 += W4 * col[8 * 4]; - } - - if (col[8 * 6]) { - a0 += W6 * col[8 * 6]; - a1 -= W2 * col[8 * 6]; - a2 += W2 * col[8 * 6]; - a3 -= W6 * col[8 * 6]; - } - - if (col[8 * 1]) { - b0 = W1 * col[8 * 1]; - b1 = W3 * col[8 * 1]; - b2 = W5 * col[8 * 1]; - b3 = W7 * col[8 * 1]; - } else { - b0 = 0; - b1 = 0; - b2 = 0; - b3 = 0; - } - - if (col[8 * 3]) { - b0 += W3 * col[8 * 3]; - b1 -= W7 * col[8 * 3]; - b2 -= W1 * col[8 * 3]; - b3 -= W5 * col[8 * 3]; - } - - if (col[8 * 5]) { - b0 += W5 * col[8 * 5]; - b1 -= W1 * col[8 * 5]; - b2 += W7 * col[8 * 5]; - b3 += W3 * col[8 * 5]; - } - - if (col[8 * 7]) { - b0 += W7 * col[8 * 7]; - b1 -= W5 * col[8 * 7]; - b2 += W3 * col[8 * 7]; - b3 -= W1 * col[8 * 7]; - } - - col[8 * 0] = (a0 + b0) >> COL_SHIFT; - col[8 * 7] = (a0 - b0) >> COL_SHIFT; - col[8 * 1] = (a1 + b1) >> COL_SHIFT; - col[8 * 6] = (a1 - b1) >> COL_SHIFT; - col[8 * 2] = (a2 + b2) >> COL_SHIFT; - col[8 * 5] = (a2 - b2) >> COL_SHIFT; - col[8 * 3] = (a3 + b3) >> COL_SHIFT; - col[8 * 4] = (a3 - b3) >> COL_SHIFT; -} - -/* If all rows but the first one are zero after row transformation, - all rows will be identical after column transformation. */ -static inline void idct_col2(int16_t *col) -{ - int i; - uint64_t l, r; - - for (i = 0; i < 8; ++i) { - int a0 = col[i] + (1 << (COL_SHIFT - 1)) / W4; - - a0 *= W4; - col[i] = a0 >> COL_SHIFT; - } - - l = ldq(col + 0 * 4); r = ldq(col + 1 * 4); - stq(l, col + 2 * 4); stq(r, col + 3 * 4); - stq(l, col + 4 * 4); stq(r, col + 5 * 4); - stq(l, col + 6 * 4); stq(r, col + 7 * 4); - stq(l, col + 8 * 4); stq(r, col + 9 * 4); - stq(l, col + 10 * 4); stq(r, col + 11 * 4); - stq(l, col + 12 * 4); stq(r, col + 13 * 4); - stq(l, col + 14 * 4); stq(r, col + 15 * 4); -} - -void ff_simple_idct_axp(int16_t *block) -{ - - int i; - int rowsZero = 1; /* all rows except row 0 zero */ - int rowsConstant = 1; /* all rows consist of a constant value */ - - for (i = 0; i < 8; i++) { - int sparseness = idct_row(block + 8 * i); - - if (i > 0 && sparseness > 0) - rowsZero = 0; - if (sparseness == 2) - rowsConstant = 0; - } - - if (rowsZero) { - idct_col2(block); - } else if (rowsConstant) { - idct_col(block); - for (i = 0; i < 8; i += 2) { - uint64_t v = (uint16_t) block[0]; - uint64_t w = (uint16_t) block[8]; - - v |= v << 16; - w |= w << 16; - v |= v << 32; - w |= w << 32; - stq(v, block + 0 * 4); - stq(v, block + 1 * 4); - stq(w, block + 2 * 4); - stq(w, block + 3 * 4); - block += 4 * 4; - } - } else { - for (i = 0; i < 8; i++) - idct_col(block + i); - } -} - -void ff_simple_idct_put_axp(uint8_t *dest, ptrdiff_t line_size, int16_t *block) -{ - ff_simple_idct_axp(block); - put_pixels_clamped_axp_p(block, dest, line_size); -} - -void ff_simple_idct_add_axp(uint8_t *dest, ptrdiff_t line_size, int16_t *block) -{ - ff_simple_idct_axp(block); - add_pixels_clamped_axp_p(block, dest, line_size); -} diff --git a/libavcodec/alsdec.c b/libavcodec/alsdec.c index 7262cdb4b..28f207998 100644 --- a/libavcodec/alsdec.c +++ b/libavcodec/alsdec.c @@ -37,10 +37,10 @@ #include "decode.h" #include "internal.h" #include "mlz.h" +#include "libavutil/mem.h" #include "libavutil/samplefmt.h" #include "libavutil/crc.h" #include "libavutil/softfloat_ieee754.h" -#include "libavutil/intfloat.h" #include "libavutil/intreadwrite.h" #include @@ -2112,7 +2112,7 @@ static av_cold int decode_init(AVCodecContext *avctx) ctx->acf = av_malloc_array(channels, sizeof(*ctx->acf)); ctx->shift_value = av_calloc(channels, sizeof(*ctx->shift_value)); ctx->last_shift_value = av_calloc(channels, sizeof(*ctx->last_shift_value)); - ctx->last_acf_mantissa = av_malloc_array(channels, sizeof(*ctx->last_acf_mantissa)); + ctx->last_acf_mantissa = av_calloc(channels, sizeof(*ctx->last_acf_mantissa)); ctx->raw_mantissa = av_calloc(channels, sizeof(*ctx->raw_mantissa)); ctx->larray = av_malloc_array(ctx->cur_frame_length * 4, sizeof(*ctx->larray)); diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 061859f85..a47aea610 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -36,6 +36,57 @@ #include "amfenc.h" #include "encode.h" #include "internal.h" +#include "libavutil/mastering_display_metadata.h" + +static int amf_save_hdr_metadata(AVCodecContext *avctx, const AVFrame *frame, AMFHDRMetadata *hdrmeta) +{ + AVFrameSideData *sd_display; + AVFrameSideData *sd_light; + AVMasteringDisplayMetadata *display_meta; + AVContentLightMetadata *light_meta; + + sd_display = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + if (sd_display) { + display_meta = (AVMasteringDisplayMetadata *)sd_display->data; + if (display_meta->has_luminance) { + const unsigned int luma_den = 10000; + hdrmeta->maxMasteringLuminance = + (amf_uint32)(luma_den * av_q2d(display_meta->max_luminance)); + hdrmeta->minMasteringLuminance = + FFMIN((amf_uint32)(luma_den * av_q2d(display_meta->min_luminance)), hdrmeta->maxMasteringLuminance); + } + if (display_meta->has_primaries) { + const unsigned int chroma_den = 50000; + hdrmeta->redPrimary[0] = + FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[0][0])), chroma_den); + hdrmeta->redPrimary[1] = + FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[0][1])), chroma_den); + hdrmeta->greenPrimary[0] = + FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[1][0])), chroma_den); + hdrmeta->greenPrimary[1] = + FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[1][1])), chroma_den); + hdrmeta->bluePrimary[0] = + FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[2][0])), chroma_den); + hdrmeta->bluePrimary[1] = + FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->display_primaries[2][1])), chroma_den); + hdrmeta->whitePoint[0] = + FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->white_point[0])), chroma_den); + hdrmeta->whitePoint[1] = + FFMIN((amf_uint16)(chroma_den * av_q2d(display_meta->white_point[1])), chroma_den); + } + + sd_light = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + if (sd_light) { + light_meta = (AVContentLightMetadata *)sd_light->data; + if (light_meta) { + hdrmeta->maxContentLightLevel = (amf_uint16)light_meta->MaxCLL; + hdrmeta->maxFrameAverageLightLevel = (amf_uint16)light_meta->MaxFALL; + } + } + return 0; + } + return 1; +} #if CONFIG_D3D11VA #include @@ -60,6 +111,7 @@ const enum AVPixelFormat ff_amf_pix_fmts[] = { #if CONFIG_DXVA2 AV_PIX_FMT_DXVA2_VLD, #endif + AV_PIX_FMT_P010, AV_PIX_FMT_NONE }; @@ -72,6 +124,7 @@ 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 }, @@ -362,6 +415,10 @@ static int amf_init_encoder(AVCodecContext *avctx) 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"); + } + ctx->format = amf_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)); @@ -681,6 +738,28 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) 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); @@ -744,6 +823,20 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) } 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); + 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; + } + hdrmeta_buffer->pVtbl->Release(hdrmeta_buffer); + } 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); @@ -785,6 +878,41 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) return ret; } +int ff_amf_get_color_profile(AVCodecContext *avctx) +{ + amf_int64 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN; + if (avctx->color_range == AVCOL_RANGE_JPEG) { + /// Color Space for Full (JPEG) Range + switch (avctx->colorspace) { + case AVCOL_SPC_SMPTE170M: + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_601; + break; + case AVCOL_SPC_BT709: + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_709; + break; + case AVCOL_SPC_BT2020_NCL: + case AVCOL_SPC_BT2020_CL: + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_FULL_2020; + break; + } + } else { + /// Color Space for Limited (MPEG) range + switch (avctx->colorspace) { + case AVCOL_SPC_SMPTE170M: + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_601; + break; + case AVCOL_SPC_BT709: + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_709; + break; + case AVCOL_SPC_BT2020_NCL: + case AVCOL_SPC_BT2020_CL: + color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020; + break; + } + } + return color_profile; +} + const AVCodecHWConfigInternal *const ff_amfenc_hw_configs[] = { #if CONFIG_D3D11VA HW_CONFIG_ENCODER_FRAMES(D3D11, D3D11VA), diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h index 2dbd378ef..d985d01bb 100644 --- a/libavcodec/amfenc.h +++ b/libavcodec/amfenc.h @@ -21,6 +21,7 @@ #include +#include #include #include #include @@ -85,6 +86,7 @@ typedef struct AmfContext { int usage; int profile; int level; + int latency; int preencode; int quality; int b_frame_delta_qp; @@ -126,6 +128,7 @@ typedef struct AmfContext { // AV1 - specific options enum AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_ENUM align; + enum AMF_VIDEO_ENCODER_AV1_AQ_MODE_ENUM aq_mode; // Preanalysis - specific options @@ -170,6 +173,8 @@ int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt); */ extern const enum AVPixelFormat ff_amf_pix_fmts[]; +int ff_amf_get_color_profile(AVCodecContext *avctx); + /** * Error handling helper */ diff --git a/libavcodec/amfenc_av1.c b/libavcodec/amfenc_av1.c index 3878f0d46..2a7a78206 100644 --- a/libavcodec/amfenc_av1.c +++ b/libavcodec/amfenc_av1.c @@ -17,23 +17,32 @@ */ #include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "amfenc.h" #include "codec_internal.h" -#include "internal.h" + +#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 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 = AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING }, AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING, AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY, VE, .unit = "usage" }, - { "transcoding", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_TRANSCODING }, 0, 0, VE, .unit = "usage" }, - { "lowlatency", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_USAGE_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, - { "profile", "Set the profile (default main)", OFFSET(profile), AV_OPT_TYPE_INT,{.i64 = AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN }, AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN, AMF_VIDEO_ENCODER_AV1_PROFILE_MAIN, VE, .unit = "profile" }, + { "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" }, + { "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" }, + + { "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" }, - { "level", "Set the encoding level (default auto)", OFFSET(level), AV_OPT_TYPE_INT,{.i64 = 0 }, 0, AMF_VIDEO_ENCODER_AV1_LEVEL_7_3, VE, .unit = "level" }, - { "auto", "", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, VE, .unit = "level" }, + { "level", "Set the encoding level (default auto)", OFFSET(level), AV_OPT_TYPE_INT,{.i64 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_LEVEL_7_3, VE, .unit = "level" }, + { "auto", "", 0, AV_OPT_TYPE_CONST, {.i64 = -1 }, 0, 0, VE, .unit = "level" }, { "2.0", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_LEVEL_2_0 }, 0, 0, VE, .unit = "level" }, { "2.1", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_LEVEL_2_1 }, 0, 0, VE, .unit = "level" }, { "2.2", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_LEVEL_2_2 }, 0, 0, VE, .unit = "level" }, @@ -59,11 +68,18 @@ static const AVOption options[] = { { "7.2", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_LEVEL_7_2 }, 0, 0, VE, .unit = "level" }, { "7.3", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_LEVEL_7_3 }, 0, 0, VE, .unit = "level" }, - { "quality", "Set the encoding quality", OFFSET(quality), AV_OPT_TYPE_INT, {.i64 = AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED }, AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY, AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, + { "quality", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, + { "preset", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED, VE, .unit = "quality" }, + { "high_quality", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY }, 0, 0, VE, .unit = "quality" }, + { "quality", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_QUALITY }, 0, 0, VE, .unit = "quality" }, { "balanced", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_BALANCED }, 0, 0, VE, .unit = "quality" }, { "speed", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_SPEED }, 0, 0, VE, .unit = "quality" }, - { "quality", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_QUALITY }, 0, 0, VE, .unit = "quality" }, - { "high_quality", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET_HIGH_QUALITY }, 0, 0, VE, .unit = "quality" }, + + { "latency", "Set the encoding latency mode", OFFSET(latency), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_LOWEST_LATENCY, VE, .unit = "latency_mode" }, + { "none", "No encoding latency requirement.", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_NONE }, 0, 0, VE, .unit = "latency_mode" }, + { "power_saving_real_time", "Try the best to finish encoding a frame within 1/framerate sec.", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_POWER_SAVING_REAL_TIME }, 0, 0, VE, .unit = "latency_mode" }, + { "real_time", "Try the best to finish encoding a frame within 1/(2 x framerate) sec.", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_REAL_TIME }, 0, 0, VE, .unit = "latency_mode" }, + { "lowest_latency", "Encoding as fast as possible. This mode causes highest power consumption", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE_LOWEST_LATENCY }, 0, 0, VE, .unit = "latency_mode" }, { "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" }, @@ -76,15 +92,14 @@ static const AVOption options[] = { { "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_AV1_HEADER_INSERTION_MODE_KEY_FRAME_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_AV1_HEADER_INSERTION_MODE_KEY_FRAME_ALIGNED, VE, .unit = "hdrmode" }, { "none", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE_NONE }, 0, 0, VE, .unit = "hdrmode" }, { "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" }, - { "preencode", "Enable preencode", OFFSET(preencode), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, VE}, - { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, VE}, - { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 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}, { "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 }, @@ -95,7 +110,12 @@ static const AVOption options[] = { { "max_qp_p", "max quantization parameter for P-frame", OFFSET(max_qp_p), 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 }, - { "skip_frame", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL,{.i64 = 0 }, 0, 1, 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" }, + { "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" }, @@ -165,8 +185,15 @@ static av_cold int amf_encode_init_av1(AVCodecContext* avctx) AMFGuid guid; AMFRate framerate; AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); + amf_int64 color_depth; + amf_int64 color_profile; + enum AVPixelFormat pix_fmt; - + //for av1 alignment and crop + uint32_t crop_right = 0; + uint32_t crop_bottom = 0; + int width_alignment_factor = -1; + int height_alignment_factor = -1; if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); @@ -185,7 +212,9 @@ FF_ENABLE_DEPRECATION_WARNINGS return ret; // init static parameters - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_USAGE, ctx->usage); + if (ctx->usage != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_USAGE, ctx->usage); + } AMF_ASSIGN_PROPERTY_SIZE(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_FRAMESIZE, framesize); @@ -199,18 +228,51 @@ FF_ENABLE_DEPRECATION_WARNINGS break; } if (profile == 0) { - profile = ctx->profile; + if (ctx->profile != -1) { + profile = ctx->profile; + } + } + + if (profile != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PROFILE, profile); + } + + /// 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; + } + + 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); } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PROFILE, profile); profile_level = avctx->level; if (profile_level == AV_LEVEL_UNKNOWN) { profile_level = ctx->level; } - if (profile_level != 0) { + + if (profile_level != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_LEVEL, profile_level); } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET, ctx->quality); + + if (ctx->quality != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_QUALITY_PRESET, ctx->quality); + } // Maximum Reference Frames if (avctx->refs != -1) { @@ -221,8 +283,9 @@ FF_ENABLE_DEPRECATION_WARNINGS 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) + if (ctx->header_insertion_mode != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_HEADER_INSERTION_MODE, ctx->header_insertion_mode); + } // Rate control // autodetect rate control method @@ -233,24 +296,29 @@ FF_ENABLE_DEPRECATION_WARNINGS 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"); } - else if (avctx->rc_max_rate > 0) { - ctx->rate_control_mode = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; - av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); - } - else { + else if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate) { ctx->rate_control_mode = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR; av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CBR\n"); } + else { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); + } } // Pre-Pass, Pre-Analysis, Two-Pass if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_PREENCODE, 0); - if (ctx->preencode) - av_log(ctx, AV_LOG_WARNING, "Preencode is not supported by cqp Rate Control Method, automatically disabled\n"); + if (ctx->preencode != -1) { + if (ctx->preencode) { + av_log(ctx, AV_LOG_WARNING, "Preencode is not supported by cqp Rate Control Method, automatically disabled\n"); + } + } } else { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_PREENCODE, ctx->preencode); + if (ctx->preencode != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_PREENCODE, ((ctx->preencode == 0) ? false : true)); + } } if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_QUALITY_VBR) { @@ -264,6 +332,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD, ctx->rate_control_mode); + if (avctx->rc_buffer_size) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_VBV_BUFFER_SIZE, avctx->rc_buffer_size); @@ -276,16 +345,24 @@ FF_ENABLE_DEPRECATION_WARNINGS } // init dynamic rate control params - if (ctx->max_au_size) - ctx->enforce_hrd = 1; - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ENFORCE_HRD, ctx->enforce_hrd); - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_FILLER_DATA, ctx->filler_data); + if (ctx->enforce_hrd != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ENFORCE_HRD, ((ctx->enforce_hrd == 0) ? false : true)); + } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_TARGET_BITRATE, avctx->bit_rate); + if (ctx->filler_data != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_FILLER_DATA, ((ctx->filler_data == 0) ? false : true)); + } + + if (avctx->bit_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_TARGET_BITRATE, avctx->bit_rate); + } if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE, avctx->bit_rate); + if (avctx->bit_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE, avctx->bit_rate); + } } + if (avctx->rc_max_rate) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PEAK_BITRATE, avctx->rc_max_rate); } @@ -329,6 +406,14 @@ FF_ENABLE_DEPRECATION_WARNINGS } AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE, ctx->align); + if (ctx->aq_mode != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_AQ_MODE, ctx->aq_mode); + } + + if (ctx->latency != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_ENCODING_LATENCY_MODE, ctx->latency); + } + if (ctx->preanalysis != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PRE_ANALYSIS_ENABLE, !!((ctx->preanalysis == 0) ? false : true)); } @@ -336,6 +421,8 @@ FF_ENABLE_DEPRECATION_WARNINGS res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_PRE_ANALYSIS_ENABLE, &var); if ((int)var.int64Value) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_PRE_ANALYSIS_ENABLE, true); + if (ctx->pa_activity_type != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_ACTIVITY_TYPE, ctx->pa_activity_type); } @@ -420,7 +507,10 @@ 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); } - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_SKIP_FRAME, ctx->skip_frame); + + 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)); + } // fill extradata res = AMFVariantInit(&var); @@ -450,14 +540,68 @@ FF_ENABLE_DEPRECATION_WARNINGS buffer->pVtbl->Release(buffer); var.pInterface->pVtbl->Release(var.pInterface); + //processing crop informaiton 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; + else + width_alignment_factor = (int)var.int64Value; + + if (ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_AV1_CAP_HEIGHT_ALIGNMENT_FACTOR_LOCAL, &var) != AMF_OK) + // assume older driver and Navi3x + height_alignment_factor = 16; + else + height_alignment_factor = (int)var.int64Value; + + if (width_alignment_factor != -1 && height_alignment_factor != -1) { + if (avctx->width % width_alignment_factor != 0) + crop_right = width_alignment_factor - (avctx->width & (width_alignment_factor - 1)); + + if (avctx->height % height_alignment_factor != 0) + crop_bottom = height_alignment_factor - (avctx->height & (height_alignment_factor - 1)); + + // There is special processing for crop_bottom equal to 8 in hardware + if (crop_bottom == 8) + crop_bottom = 2; + } + + if (crop_right != 0 || crop_bottom != 0) { + AVPacketSideData* sd_crop = av_realloc_array(avctx->coded_side_data, avctx->nb_coded_side_data + 1, sizeof(*sd_crop)); + uint32_t* crop; + + if (!sd_crop) { + av_log(ctx, AV_LOG_ERROR, "Can't allocate memory for amf av1 encoder crop information\n"); + return AVERROR(ENOMEM); + } + avctx->coded_side_data = sd_crop; + + crop = av_malloc(sizeof(uint32_t) * 4); + if (!crop) { + av_log(ctx, AV_LOG_ERROR, "Can't allocate memory for amf av1 encoder crop information\n"); + return AVERROR(ENOMEM); + } + + avctx->nb_coded_side_data++; + + //top, bottom, left,right + AV_WL32A(crop + 0, 0); + AV_WL32A(crop + 1, crop_bottom); + AV_WL32A(crop + 2, 0); + AV_WL32A(crop + 3, crop_right); + + avctx->coded_side_data[avctx->nb_coded_side_data - 1].type = AV_PKT_DATA_FRAME_CROPPING; + avctx->coded_side_data[avctx->nb_coded_side_data - 1].data = (uint8_t*)crop; + avctx->coded_side_data[avctx->nb_coded_side_data - 1].size = sizeof(uint32_t) * 4; + } + return 0; } static const FFCodecDefault defaults[] = { { "refs", "-1" }, { "aspect", "0" }, - { "b", "2M" }, - { "g", "250" }, + { "b", "0" }, + { "g", "-1" }, { "qmin", "-1" }, { "qmax", "-1" }, { NULL }, @@ -485,6 +629,7 @@ const FFCodec ff_av1_amf_encoder = { AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.pix_fmts = 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 c1d5f4054..8edd39c63 100644 --- a/libavcodec/amfenc_h264.c +++ b/libavcodec/amfenc_h264.c @@ -18,10 +18,10 @@ #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "amfenc.h" #include "codec_internal.h" -#include "internal.h" #include #define OFFSET(x) offsetof(AmfContext, x) @@ -30,17 +30,16 @@ static const AVOption options[] = { // Static /// Usage - { "usage", "Encoder Usage", OFFSET(usage), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_USAGE_TRANSCODING }, AMF_VIDEO_ENCODER_USAGE_TRANSCODING, AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY_HIGH_QUALITY, VE, .unit = "usage" }, - { "transcoding", "Generic Transcoding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_TRANSCODING }, 0, 0, VE, .unit = "usage" }, - { "ultralowlatency","ultra low latency trancoding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, - { "lowlatency", "low latency trancoding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, - { "webcam", "Webcam", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_WEBCAM }, 0, 0, VE, .unit = "usage" }, - { "high_quality", "high quality trancoding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_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_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, - + { "usage", "Encoder Usage", OFFSET(usage), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY_HIGH_QUALITY, VE, .unit = "usage" }, + { "transcoding", "Generic Transcoding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_TRANSCODING }, 0, 0, VE, .unit = "usage" }, + { "ultralowlatency","Ultra low latency usecase", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, + { "lowlatency", "Low latency usecase", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, + { "webcam", "Webcam", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_WEBCAM }, 0, 0, VE, .unit = "usage" }, + { "high_quality", "High quality usecase", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_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_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, VE, .unit = "usage" }, /// Profile, - { "profile", "Profile", OFFSET(profile),AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_PROFILE_MAIN }, AMF_VIDEO_ENCODER_PROFILE_BASELINE, AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH, VE, .unit = "profile" }, + { "profile", "Profile", OFFSET(profile),AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH, VE, .unit = "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_MAIN }, 0, 0, VE, .unit = "profile" }, { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_HIGH }, 0, 0, VE, .unit = "profile" }, { "constrained_baseline", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE }, 0, 0, VE, .unit = "profile" }, @@ -69,12 +68,14 @@ static const AVOption options[] = { { "6.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 61 }, 0, 0, VE, .unit = "level" }, { "6.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 62 }, 0, 0, VE, .unit = "level" }, + { "latency", "enables low latency mode", OFFSET(latency), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE }, /// Quality Preset - { "quality", "Quality Preference", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED }, AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED, AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, VE, .unit = "quality" }, - { "speed", "Prefer Speed", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED }, 0, 0, VE, .unit = "quality" }, - { "balanced", "Balanced", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED }, 0, 0, VE, .unit = "quality" }, - { "quality", "Prefer Quality", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY }, 0, 0, VE, .unit = "quality" }, + { "quality", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, VE, .unit = "quality" }, + { "preset", "Set the encoding quality preset", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, VE, .unit = "quality" }, + { "balanced", "Balanced", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED }, 0, 0, VE, .unit = "quality" }, + { "speed", "Prefer Speed", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED }, 0, 0, VE, .unit = "quality" }, + { "quality", "Prefer Quality", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY }, 0, 0, VE, .unit = "quality" }, // Dynamic /// Rate Control Method @@ -90,10 +91,10 @@ static const AVOption options[] = { { "qvbr_quality_level", "Sets the QVBR quality level", OFFSET(qvbr_quality_level),AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, /// Enforce HRD, Filler Data, VBAQ, Frame Skipping - { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "vbaq", "Enable VBAQ", OFFSET(enable_vbaq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "frame_skipping", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 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 }, + { "vbaq", "Enable VBAQ", OFFSET(enable_vbaq), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + { "frame_skipping", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, /// QP Values { "qp_i", "Quantization Parameter for I-Frame", OFFSET(qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, @@ -101,10 +102,10 @@ static const AVOption options[] = { { "qp_b", "Quantization Parameter for B-Frame", OFFSET(qp_b), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, /// Pre-Pass, Pre-Analysis, Two-Pass - { "preencode", "Pre-encode assisted rate control", OFFSET(preencode), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE, .unit = NULL }, + { "preencode", "Pre-encode assisted rate control", OFFSET(preencode), AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE, NULL }, /// Maximum Access Unit Size - { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 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 }, /// Header Insertion Spacing { "header_spacing", "Header Insertion Spacing", OFFSET(header_spacing), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1000, VE }, @@ -119,7 +120,7 @@ static const AVOption options[] = { { "bf", "B Picture Pattern", OFFSET(max_b_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 3, VE }, /// Intra-Refresh - { "intra_refresh_mb","Intra Refresh MBs Number Per Slot in Macroblocks", OFFSET(intra_refresh_mb), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + { "intra_refresh_mb","Intra Refresh MBs Number Per Slot in Macroblocks", OFFSET(intra_refresh_mb), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE }, /// coder { "coder", "Coding Type", OFFSET(coding_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_UNDEFINED }, AMF_VIDEO_ENCODER_UNDEFINED, AMF_VIDEO_ENCODER_CALV, VE, .unit = "coder" }, @@ -129,10 +130,11 @@ static const AVOption options[] = { { "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 }, - { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, - { "me_quarter_pel", "Enable ME Quarter Pixel", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, + { "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 }, + + { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) , AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, - { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg) , AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, @@ -199,6 +201,8 @@ static av_cold int amf_encode_init_h264(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_profile; + enum AVPixelFormat pix_fmt; if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); @@ -215,8 +219,10 @@ FF_ENABLE_DEPRECATION_WARNINGS if ((ret = ff_amf_encode_init(avctx)) != 0) return ret; - // Static parameters - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_USAGE, ctx->usage); + // init static parameters + if (ctx->usage != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_USAGE, ctx->usage); + } AMF_ASSIGN_PROPERTY_SIZE(res, ctx->encoder, AMF_VIDEO_ENCODER_FRAMESIZE, framesize); @@ -240,15 +246,20 @@ FF_ENABLE_DEPRECATION_WARNINGS break; } if (profile == 0) { - profile = ctx->profile; + if (ctx->profile != -1) { + profile = ctx->profile; + } } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PROFILE, profile); + if (profile != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PROFILE, profile); + } profile_level = avctx->level; if (profile_level == AV_LEVEL_UNKNOWN) { profile_level = ctx->level; } + if (profile_level != 0) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PROFILE_LEVEL, profile_level); } @@ -262,31 +273,51 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_ASPECT_RATIO, ratio); } - /// Color Range (Partial/TV/MPEG or Full/PC/JPEG) - if (avctx->color_range == AVCOL_RANGE_JPEG) { - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_FULL_RANGE_COLOR, 1); - } + color_profile = ff_amf_get_color_profile(avctx); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_OUTPUT_COLOR_PROFILE, color_profile); + + /// Color Range (Support for older Drivers) + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_FULL_RANGE_COLOR, !!(avctx->color_range == AVCOL_RANGE_JPEG)); + + /// Color Depth + pix_fmt = avctx->hw_frames_ctx ? ((AVHWFramesContext*)avctx->hw_frames_ctx->data)->sw_format + : avctx->pix_fmt; + + // 10 bit input video is not supported by AMF H264 encoder + AMF_RETURN_IF_FALSE(ctx, pix_fmt != AV_PIX_FMT_P010, AVERROR_INVALIDDATA, "10-bit input video is not supported by AMF H264 encoder\n"); + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_COLOR_BIT_DEPTH, AMF_COLOR_BIT_DEPTH_8); + /// Color Transfer Characteristics (AMF matches ISO/IEC) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_OUTPUT_TRANSFER_CHARACTERISTIC, (amf_int64)avctx->color_trc); + /// Color Primaries (AMF matches ISO/IEC) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_OUTPUT_COLOR_PRIMARIES, (amf_int64)avctx->color_primaries); // autodetect rate control method if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN) { if (ctx->qp_i != -1 || ctx->qp_p != -1 || ctx->qp_b != -1) { ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP; av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CQP\n"); - } else if (avctx->rc_max_rate > 0 ) { - ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; - av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); - } else { + } else if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate) { ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR; av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CBR\n"); + } else { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); } } if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PREENCODE_ENABLE, AMF_VIDEO_ENCODER_PREENCODE_DISABLED); - if (ctx->preencode) - av_log(ctx, AV_LOG_WARNING, "Preencode is not supported by cqp Rate Control Method, automatically disabled\n"); - } else { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PREENCODE_ENABLE, ctx->preencode); + if (ctx->preencode != -1) { + if (ctx->preencode) { + av_log(ctx, AV_LOG_WARNING, "Preencode is not supported by cqp Rate Control Method, automatically disabled\n"); + } + } + } + else { + if (ctx->preencode != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PREENCODE_ENABLE, ctx->preencode); + } } if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_QUALITY_VBR) { @@ -299,9 +330,11 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HIGH_MOTION_QUALITY_BOOST_ENABLE, ((ctx->hw_high_motion_quality_boost == 0) ? false : true)); } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QUALITY_PRESET, ctx->quality); + if (ctx->quality != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QUALITY_PRESET, ctx->quality); + } - // Dynamic parmaters + // Dynamic parameters AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD, ctx->rate_control_mode); /// VBV Buffer @@ -314,11 +347,14 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_INITIAL_VBV_BUFFER_FULLNESS, amf_buffer_fullness); } } - /// Maximum Access Unit Size - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_AU_SIZE, ctx->max_au_size); + /// Maximum Access Unit Size and AUD + if (ctx->max_au_size != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_AU_SIZE, ctx->max_au_size); + } - if (ctx->max_au_size) - ctx->enforce_hrd = 1; + if (ctx->aud != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_INSERT_AUD, ctx->aud); + } // QP Minimum / Maximum if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { @@ -342,17 +378,26 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->qp_b != -1) AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QP_B, ctx->qp_b); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_TARGET_BITRATE, avctx->bit_rate); + if (avctx->bit_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_TARGET_BITRATE, avctx->bit_rate); + } if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PEAK_BITRATE, avctx->bit_rate); + if (avctx->bit_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PEAK_BITRATE, avctx->bit_rate); + } } + 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"); } + if (ctx->latency != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_LOWLATENCY_MODE, ((ctx->latency == 0) ? false : true)); + } + if (ctx->preanalysis != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_PRE_ANALYSIS_ENABLE, !!((ctx->preanalysis == 0) ? false : true)); } @@ -360,6 +405,8 @@ FF_ENABLE_DEPRECATION_WARNINGS res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_PRE_ANALYSIS_ENABLE, &var); if ((int)var.int64Value) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_PRE_ANALYSIS_ENABLE, true); + if (ctx->pa_activity_type != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_ACTIVITY_TYPE, ctx->pa_activity_type); } @@ -440,15 +487,26 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); // Enforce HRD, Filler Data, VBAQ, Frame Skipping, Deblocking Filter - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENFORCE_HRD, !!ctx->enforce_hrd); - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_FILLER_DATA_ENABLE, !!ctx->filler_data); - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE, !!ctx->skip_frame); + if (ctx->enforce_hrd != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENFORCE_HRD, ((ctx->enforce_hrd == 0) ? false : true)); + } + + if (ctx->filler_data != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_FILLER_DATA_ENABLE, ((ctx->filler_data == 0) ? false : true)); + } + + if (ctx->skip_frame != -1) { + 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 { - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, !!ctx->enable_vbaq); + 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); @@ -460,7 +518,7 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEADER_INSERTION_SPACING, ctx->header_spacing); // Intra-Refresh, Slicing - if (ctx->intra_refresh_mb > 0) + if (ctx->intra_refresh_mb != -1) AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_INTRA_REFRESH_NUM_MBS_PER_SLOT, ctx->intra_refresh_mb); if (avctx->slices > 1) AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_SLICES_PER_FRAME, avctx->slices); @@ -470,8 +528,13 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_CABAC_ENABLE, ctx->coding_mode); // Motion Estimation - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_MOTION_HALF_PIXEL, !!ctx->me_half_pel); - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_MOTION_QUARTERPIXEL, !!ctx->me_quarter_pel); + if (ctx->me_half_pel != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_MOTION_HALF_PIXEL, !!ctx->me_half_pel); + } + + if (ctx->me_quarter_pel != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_MOTION_QUARTERPIXEL, !!ctx->me_quarter_pel); + } // fill extradata res = AMFVariantInit(&var); @@ -509,8 +572,8 @@ static const FFCodecDefault defaults[] = { { "aspect", "0" }, { "qmin", "-1" }, { "qmax", "-1" }, - { "b", "2M" }, - { "g", "250" }, + { "b", "0" }, + { "g", "-1" }, { "slices", "1" }, { "flags", "+loop"}, { NULL }, @@ -539,6 +602,7 @@ const FFCodec ff_h264_amf_encoder = { .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 | 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 33a167aa5..4898824f3 100644 --- a/libavcodec/amfenc_hevc.c +++ b/libavcodec/amfenc_hevc.c @@ -17,27 +17,29 @@ */ #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "amfenc.h" #include "codec_internal.h" -#include "internal.h" #include #define OFFSET(x) offsetof(AmfContext, 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 = AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCODING }, AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCODING, 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 trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, - { "lowlatency", "low latency trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY }, 0, 0, VE, .unit = "usage" }, - { "webcam", "Webcam", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_WEBCAM }, 0, 0, VE, .unit = "usage" }, - { "high_quality", "high quality trancoding", 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 trancoding", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY_HIGH_QUALITY }, 0, 0, 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" }, + { "webcam", "Webcam", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_WEBCAM }, 0, 0, VE, .unit = "usage" }, + { "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 (default main)", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN, VE, .unit = "profile" }, + { "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 = AMF_VIDEO_ENCODER_HEVC_TIER_MAIN }, AMF_VIDEO_ENCODER_HEVC_TIER_MAIN, 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" }, @@ -57,10 +59,13 @@ 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", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED }, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY, 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" }, - { "quality", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY }, 0, 0, VE, .unit = "quality" }, + + { "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" }, { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, .unit = "rc" }, @@ -73,29 +78,30 @@ static const AVOption options[] = { { "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 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE }, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE, 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" }, { "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 = 0 }, 0, 1, VE}, - { "vbaq", "Enable VBAQ", OFFSET(enable_vbaq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, - { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, - { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, - { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT,{ .i64 = 0 }, 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}, { "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 }, { "max_qp_p", "max quantization parameter for P-frame", OFFSET(max_qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, { "qp_p", "quantization parameter for P-frame", OFFSET(qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, { "qp_i", "quantization parameter for I-frame", OFFSET(qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, - { "skip_frame", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, - { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL,{ .i64 = 1 }, 0, 1, VE }, - { "me_quarter_pel", "Enable ME Quarter Pixel ", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL,{ .i64 = 1 }, 0, 1, VE }, + { "skip_frame", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, + { "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 }, + + { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, - { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, @@ -160,6 +166,9 @@ 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 color_profile; + enum AVPixelFormat pix_fmt; if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); @@ -177,7 +186,9 @@ FF_ENABLE_DEPRECATION_WARNINGS return ret; // init static parameters - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_USAGE, ctx->usage); + if (ctx->usage != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_USAGE, ctx->usage); + } AMF_ASSIGN_PROPERTY_SIZE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_FRAMESIZE, framesize); @@ -187,24 +198,39 @@ FF_ENABLE_DEPRECATION_WARNINGS case AV_PROFILE_HEVC_MAIN: profile = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN; break; + case AV_PROFILE_HEVC_MAIN_10: + profile = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN_10; + break; default: break; } if (profile == 0) { - profile = ctx->profile; + if (ctx->profile != -1) { + profile = ctx->profile; + } } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PROFILE, profile); - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_TIER, ctx->tier); + if (profile != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PROFILE, profile); + } + + if (ctx->tier != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_TIER, ctx->tier); + } profile_level = avctx->level; if (profile_level == AV_LEVEL_UNKNOWN) { profile_level = ctx->level; } + if (profile_level != 0) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PROFILE_LEVEL, profile_level); } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET, ctx->quality); + + if (ctx->quality != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET, ctx->quality); + } + // Maximum Reference Frames if (avctx->refs != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_NUM_REFRAMES, avctx->refs); @@ -215,6 +241,28 @@ 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; + 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; + } + 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); + } + // 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); @@ -222,7 +270,10 @@ FF_ENABLE_DEPRECATION_WARNINGS 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_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE, ctx->header_insertion_mode); + + if (ctx->header_insertion_mode != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE, ctx->header_insertion_mode); + } // Rate control // autodetect rate control method @@ -232,23 +283,28 @@ FF_ENABLE_DEPRECATION_WARNINGS ctx->qp_i !=-1 || ctx->qp_p != -1) { ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP; av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CQP\n"); - } else if (avctx->rc_max_rate > 0) { - ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; - av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); - } else { + } else if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate) { ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR; av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CBR\n"); + } else { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\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); - if (ctx->preencode) - av_log(ctx, AV_LOG_WARNING, "Preencode is not supported by cqp Rate Control Method, automatically disabled\n"); + if (ctx->preencode != -1) { + if (ctx->preencode) { + av_log(ctx, AV_LOG_WARNING, "Preencode is not supported by cqp Rate Control Method, automatically disabled\n"); + } + } } else { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PREENCODE_ENABLE, ctx->preencode); + if (ctx->preencode != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PREENCODE_ENABLE, ctx->preencode); + } } if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_QUALITY_VBR) { @@ -262,6 +318,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD, ctx->rate_control_mode); + if (avctx->rc_buffer_size) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_VBV_BUFFER_SIZE, avctx->rc_buffer_size); @@ -278,28 +335,47 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->enable_vbaq) av_log(ctx, AV_LOG_WARNING, "VBAQ is not supported by cqp Rate Control Method, automatically disabled\n"); } else { - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENABLE_VBAQ, !!ctx->enable_vbaq); + if (ctx->enable_vbaq != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENABLE_VBAQ, !!ctx->enable_vbaq); + } } - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MOTION_HALF_PIXEL, ctx->me_half_pel); - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MOTION_QUARTERPIXEL, ctx->me_quarter_pel); + + if (ctx->me_half_pel != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MOTION_HALF_PIXEL, ctx->me_half_pel); + } + if (ctx->me_quarter_pel != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MOTION_QUARTERPIXEL, ctx->me_quarter_pel); + } // init dynamic rate control params - if (ctx->max_au_size) - ctx->enforce_hrd = 1; - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENFORCE_HRD, ctx->enforce_hrd); - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_FILLER_DATA_ENABLE, ctx->filler_data); + if (ctx->enforce_hrd != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENFORCE_HRD, ((ctx->enforce_hrd == 0) ? false : true)); + } - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_TARGET_BITRATE, avctx->bit_rate); + if (ctx->filler_data != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_FILLER_DATA_ENABLE, ((ctx->filler_data == 0) ? false : true)); + } + + if (avctx->bit_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_TARGET_BITRATE, avctx->bit_rate); + } if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR) { - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PEAK_BITRATE, avctx->bit_rate); + if (avctx->bit_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PEAK_BITRATE, avctx->bit_rate); + } } + 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"); } + if (ctx->latency != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_LOWLATENCY_MODE, ((ctx->latency == 0) ? false : true)); + } + if (ctx->preanalysis != -1) { AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PRE_ANALYSIS_ENABLE, !!((ctx->preanalysis == 0) ? false : true)); } @@ -307,6 +383,8 @@ FF_ENABLE_DEPRECATION_WARNINGS res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PRE_ANALYSIS_ENABLE, &var); if ((int)var.int64Value) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PRE_ANALYSIS_ENABLE, true); + if (ctx->pa_activity_type != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_PA_ACTIVITY_TYPE, ctx->pa_activity_type); } @@ -356,7 +434,9 @@ FF_ENABLE_DEPRECATION_WARNINGS AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); // init dynamic picture control params - AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_AU_SIZE, ctx->max_au_size); + if (ctx->max_au_size != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_AU_SIZE, ctx->max_au_size); + } if (ctx->min_qp_i != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MIN_QP_I, ctx->min_qp_i); @@ -389,7 +469,9 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->qp_i != -1) { AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QP_I, ctx->qp_i); } - AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_SKIP_FRAME_ENABLE, ctx->skip_frame); + if (ctx->skip_frame != -1) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_SKIP_FRAME_ENABLE, ((ctx->skip_frame == 0) ? false : true)); + } // fill extradata res = AMFVariantInit(&var); @@ -424,8 +506,8 @@ FF_ENABLE_DEPRECATION_WARNINGS static const FFCodecDefault defaults[] = { { "refs", "-1" }, { "aspect", "0" }, - { "b", "2M" }, - { "g", "250" }, + { "b", "0" }, + { "g", "-1" }, { "slices", "1" }, { "qmin", "-1" }, { "qmax", "-1" }, @@ -454,6 +536,7 @@ const FFCodec ff_hevc_amf_encoder = { .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 */ .p.wrapper_name = "amf", .hw_configs = ff_amfenc_hw_configs, }; diff --git a/libavcodec/amrwbdec.c b/libavcodec/amrwbdec.c index 21a730b83..bb0864587 100644 --- a/libavcodec/amrwbdec.c +++ b/libavcodec/amrwbdec.c @@ -370,7 +370,7 @@ static void decode_pitch_vector(AMRWBContext *ctx, } /** Get x bits in the index interval [lsb,lsb+len-1] inclusive */ -#define BIT_STR(x,lsb,len) av_mod_uintp2((x) >> (lsb), (len)) +#define BIT_STR(x,lsb,len) av_zero_extend((x) >> (lsb), (len)) /** Get the bit at specified position */ #define BIT_POS(x, p) (((x) >> (p)) & 1) diff --git a/libavcodec/aom_film_grain.c b/libavcodec/aom_film_grain.c index e302567ba..1b1693dcd 100644 --- a/libavcodec/aom_film_grain.c +++ b/libavcodec/aom_film_grain.c @@ -26,7 +26,9 @@ */ #include "libavutil/avassert.h" +#include "libavutil/buffer.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "aom_film_grain.h" #include "get_bits.h" @@ -124,7 +126,7 @@ int ff_aom_parse_film_grain_sets(AVFilmGrainAFGS1Params *s, { GetBitContext gbc, *gb = &gbc; AVFilmGrainAOMParams *aom; - AVFilmGrainParams *fgp, *ref = NULL; + AVFilmGrainParams *fgp = NULL, *ref = NULL; int ret, num_sets, n, i, uv, num_y_coeffs, update_grain, luma_only; ret = init_get_bits8(gb, payload, payload_size); @@ -135,28 +137,38 @@ int ff_aom_parse_film_grain_sets(AVFilmGrainAFGS1Params *s, if (!s->enable) return 0; + for (int i = 0; i < FF_ARRAY_ELEMS(s->sets); i++) + av_buffer_unref(&s->sets[i]); + skip_bits(gb, 4); // reserved num_sets = get_bits(gb, 3) + 1; for (n = 0; n < num_sets; n++) { int payload_4byte, payload_size, set_idx, apply_units_log2, vsc_flag; int predict_scaling, predict_y_scaling, predict_uv_scaling[2]; int payload_bits, start_position; + size_t fgp_size; start_position = get_bits_count(gb); payload_4byte = get_bits1(gb); payload_size = get_bits(gb, payload_4byte ? 2 : 8); set_idx = get_bits(gb, 3); - fgp = &s->sets[set_idx]; + fgp = av_film_grain_params_alloc(&fgp_size); + if (!fgp) + goto error; aom = &fgp->codec.aom; fgp->type = get_bits1(gb) ? AV_FILM_GRAIN_PARAMS_AV1 : AV_FILM_GRAIN_PARAMS_NONE; - if (!fgp->type) + if (!fgp->type) { + av_freep(&fgp); continue; + } fgp->seed = get_bits(gb, 16); update_grain = get_bits1(gb); - if (!update_grain) + if (!update_grain) { + av_freep(&fgp); continue; + } apply_units_log2 = get_bits(gb, 4); fgp->width = get_bits(gb, 12) << apply_units_log2; @@ -330,32 +342,49 @@ int ff_aom_parse_film_grain_sets(AVFilmGrainAFGS1Params *s, if (payload_bits > payload_size * 8) goto error; skip_bits(gb, payload_size * 8 - payload_bits); + + av_buffer_unref(&s->sets[set_idx]); + s->sets[set_idx] = av_buffer_create((uint8_t *)fgp, fgp_size, NULL, NULL, 0); + if (!s->sets[set_idx]) + goto error; } return 0; error: - memset(s, 0, sizeof(*s)); + av_free(fgp); + ff_aom_uninit_film_grain_params(s); return AVERROR_INVALIDDATA; } int ff_aom_attach_film_grain_sets(const AVFilmGrainAFGS1Params *s, AVFrame *frame) { - AVFilmGrainParams *fgp; if (!s->enable) return 0; for (int i = 0; i < FF_ARRAY_ELEMS(s->sets); i++) { - if (s->sets[i].type != AV_FILM_GRAIN_PARAMS_AV1) + AVBufferRef *buf; + + if (!s->sets[i]) continue; - fgp = av_film_grain_params_create_side_data(frame); - if (!fgp) + + 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); return AVERROR(ENOMEM); - memcpy(fgp, &s->sets[i], sizeof(*fgp)); + } } return 0; } +void ff_aom_uninit_film_grain_params(AVFilmGrainAFGS1Params *s) +{ + for (int i = 0; i < FF_ARRAY_ELEMS(s->sets); i++) + av_buffer_unref(&s->sets[i]); + s->enable = 0; +} + // Taken from the AV1 spec. Range is [-2048, 2047], mean is 0 and stddev is 512 static const int16_t gaussian_sequence[2048] = { 56, 568, -180, 172, 124, -84, 172, -64, -900, 24, 820, diff --git a/libavcodec/aom_film_grain.h b/libavcodec/aom_film_grain.h index 1f8c78f65..97c33deb4 100644 --- a/libavcodec/aom_film_grain.h +++ b/libavcodec/aom_film_grain.h @@ -28,11 +28,12 @@ #ifndef AVCODEC_AOM_FILM_GRAIN_H #define AVCODEC_AOM_FILM_GRAIN_H +#include "libavutil/buffer.h" #include "libavutil/film_grain_params.h" typedef struct AVFilmGrainAFGS1Params { int enable; - AVFilmGrainParams sets[8]; + AVBufferRef *sets[8]; } AVFilmGrainAFGS1Params; // Synthesizes film grain on top of `in` and stores the result to `out`. `out` @@ -48,4 +49,7 @@ int ff_aom_parse_film_grain_sets(AVFilmGrainAFGS1Params *s, // Attach all valid film grain param sets to `frame`. int ff_aom_attach_film_grain_sets(const AVFilmGrainAFGS1Params *s, AVFrame *frame); +// Free all allocations in `s` and zero the entire struct. +void ff_aom_uninit_film_grain_params(AVFilmGrainAFGS1Params *s); + #endif /* AVCODEC_AOM_FILM_GRAIN_H */ diff --git a/libavcodec/apac.c b/libavcodec/apac.c index b6cb6c669..eb05d3863 100644 --- a/libavcodec/apac.c +++ b/libavcodec/apac.c @@ -19,8 +19,7 @@ */ #include "libavutil/audio_fifo.h" -#include "libavutil/internal.h" -#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" @@ -130,7 +129,7 @@ static int apac_decode(AVCodecContext *avctx, AVFrame *frame, APACContext *s = avctx->priv_data; GetBitContext *gb = &s->gb; int ret, n, buf_size, input_buf_size; - const uint8_t *buf; + uint8_t *buf; int nb_samples; if (!pkt->size && s->bitstream_size <= 0) { @@ -160,6 +159,7 @@ static int apac_decode(AVCodecContext *avctx, AVFrame *frame, buf = &s->bitstream[s->bitstream_index]; buf_size += s->bitstream_size; s->bitstream_size = buf_size; + memset(buf + buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); frame->nb_samples = s->bitstream_size * 16 * 8; if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) diff --git a/libavcodec/apedec.c b/libavcodec/apedec.c index 7d96182d0..d75a85f46 100644 --- a/libavcodec/apedec.c +++ b/libavcodec/apedec.c @@ -25,6 +25,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/crc.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "lossless_audiodsp.h" #include "avcodec.h" diff --git a/libavcodec/arm/ac3dsp_neon.S b/libavcodec/arm/ac3dsp_neon.S index 89d0ae804..dc829541a 100644 --- a/libavcodec/arm/ac3dsp_neon.S +++ b/libavcodec/arm/ac3dsp_neon.S @@ -20,25 +20,6 @@ #include "libavutil/arm/asm.S" -function ff_ac3_max_msb_abs_int16_neon, export=1 - vmov.i16 q0, #0 - vmov.i16 q2, #0 -1: vld1.16 {q1}, [r0,:128]! - vabs.s16 q1, q1 - vld1.16 {q3}, [r0,:128]! - vabs.s16 q3, q3 - vorr q0, q0, q1 - vorr q2, q2, q3 - subs r1, r1, #16 - bgt 1b - vorr q0, q0, q2 - vorr d0, d0, d1 - vpmax.u16 d0, d0, d0 - vpmax.u16 d0, d0, d0 - vmov.u16 r0, d0[0] - bx lr -endfunc - function ff_ac3_exponent_min_neon, export=1 cmp r1, #0 it eq @@ -59,27 +40,6 @@ function ff_ac3_exponent_min_neon, export=1 pop {pc} endfunc -function ff_ac3_lshift_int16_neon, export=1 - vdup.16 q0, r2 -1: vld1.16 {q1}, [r0,:128] - vshl.s16 q1, q1, q0 - vst1.16 {q1}, [r0,:128]! - subs r1, r1, #8 - bgt 1b - bx lr -endfunc - -function ff_ac3_rshift_int32_neon, export=1 - rsb r2, r2, #0 - vdup.32 q0, r2 -1: vld1.32 {q1}, [r0,:128] - vshl.s32 q1, q1, q0 - vst1.32 {q1}, [r0,:128]! - subs r1, r1, #4 - bgt 1b - bx lr -endfunc - function ff_float_to_fixed24_neon, export=1 1: vld1.32 {q0-q1}, [r1,:128]! vcvt.s32.f32 q0, q0, #24 @@ -109,29 +69,6 @@ function ff_ac3_extract_exponents_neon, export=1 bx lr endfunc -function ff_apply_window_int16_neon, export=1 - push {r4,lr} - add r4, r1, r3, lsl #1 - add lr, r0, r3, lsl #1 - sub r4, r4, #16 - sub lr, lr, #16 - mov r12, #-16 -1: - vld1.16 {q0}, [r1,:128]! - vld1.16 {q2}, [r2,:128]! - vld1.16 {q1}, [r4,:128], r12 - vrev64.16 q3, q2 - vqrdmulh.s16 q0, q0, q2 - vqrdmulh.s16 d2, d2, d7 - vqrdmulh.s16 d3, d3, d6 - vst1.16 {q0}, [r0,:128]! - vst1.16 {q1}, [lr,:128], r12 - subs r3, r3, #16 - bgt 1b - - pop {r4,pc} -endfunc - function ff_ac3_sum_square_butterfly_int32_neon, export=1 vmov.i64 q0, #0 vmov.i64 q1, #0 diff --git a/libavcodec/arm/hevcdsp_arm.h b/libavcodec/arm/hevcdsp_arm.h index 47cdfa574..de2303314 100644 --- a/libavcodec/arm/hevcdsp_arm.h +++ b/libavcodec/arm/hevcdsp_arm.h @@ -19,7 +19,7 @@ #ifndef AVCODEC_ARM_HEVCDSP_ARM_H #define AVCODEC_ARM_HEVCDSP_ARM_H -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" void ff_hevc_dsp_init_neon(HEVCDSPContext *c, const int bit_depth); diff --git a/libavcodec/arm/hevcdsp_init_arm.c b/libavcodec/arm/hevcdsp_init_arm.c index e8fa1f79a..5e5da5ac6 100644 --- a/libavcodec/arm/hevcdsp_init_arm.c +++ b/libavcodec/arm/hevcdsp_init_arm.c @@ -22,7 +22,7 @@ #include "libavutil/cpu.h" #include "libavutil/arm/cpu.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #include "hevcdsp_arm.h" av_cold void ff_hevc_dsp_init_arm(HEVCDSPContext *c, const int bit_depth) diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c index 1f26fc645..6f113618c 100644 --- a/libavcodec/arm/hevcdsp_init_neon.c +++ b/libavcodec/arm/hevcdsp_init_neon.c @@ -20,7 +20,7 @@ #include "libavutil/attributes.h" #include "libavutil/arm/cpu.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #include "libavcodec/avcodec.h" #include "hevcdsp_arm.h" diff --git a/libavcodec/arm/mlpdsp_armv5te.S b/libavcodec/arm/mlpdsp_armv5te.S index 4f9aa485f..d31568611 100644 --- a/libavcodec/arm/mlpdsp_armv5te.S +++ b/libavcodec/arm/mlpdsp_armv5te.S @@ -229,7 +229,7 @@ A .endif .endif // Begin loop -01: +1: .if TOTAL_TAPS == 0 // Things simplify a lot in this case // In fact this could be pipelined further if it's worth it... @@ -241,7 +241,7 @@ A .endif str ST0, [PST, #-4]! str ST0, [PST, #4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)] str ST0, [PSAMP], #4 * MAX_CHANNELS - bne 01b + bne 1b .else .if \fir_taps & 1 .set LOAD_REG, 1 @@ -333,7 +333,7 @@ T orr AC0, AC0, AC1 str ST3, [PST, #-4]! str ST2, [PST, #4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)] str ST3, [PSAMP], #4 * MAX_CHANNELS - bne 01b + bne 1b .endif b 99f diff --git a/libavcodec/arm/mpegvideo_arm.c b/libavcodec/arm/mpegvideo_arm.c index 008ef18ee..28a3f2cdd 100644 --- a/libavcodec/arm/mpegvideo_arm.c +++ b/libavcodec/arm/mpegvideo_arm.c @@ -18,8 +18,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/attributes.h" -#include "libavutil/internal.h" #include "libavutil/arm/cpu.h" #include "libavcodec/avcodec.h" #include "libavcodec/mpegvideo.h" @@ -27,13 +28,16 @@ #include "asm-offsets.h" #if HAVE_NEON -AV_CHECK_OFFSET(MpegEncContext, y_dc_scale, Y_DC_SCALE); -AV_CHECK_OFFSET(MpegEncContext, c_dc_scale, C_DC_SCALE); -AV_CHECK_OFFSET(MpegEncContext, ac_pred, AC_PRED); -AV_CHECK_OFFSET(MpegEncContext, block_last_index, BLOCK_LAST_INDEX); -AV_CHECK_OFFSET(MpegEncContext, inter_scantable.raster_end, - INTER_SCANTAB_RASTER_END); -AV_CHECK_OFFSET(MpegEncContext, h263_aic, H263_AIC); +#define CHECK_OFFSET(s, m, o) \ + static_assert(offsetof(s, m) == o, \ + "Hardcoded ASM offset of " #s " field " #o " needs to be updated."); +CHECK_OFFSET(MpegEncContext, y_dc_scale, Y_DC_SCALE); +CHECK_OFFSET(MpegEncContext, c_dc_scale, C_DC_SCALE); +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, h263_aic, H263_AIC); #endif void ff_dct_unquantize_h263_inter_neon(MpegEncContext *s, int16_t *block, diff --git a/libavcodec/arm/mpegvideoencdsp_init_arm.c b/libavcodec/arm/mpegvideoencdsp_init_arm.c index a95b5bebe..74c5964f7 100644 --- a/libavcodec/arm/mpegvideoencdsp_init_arm.c +++ b/libavcodec/arm/mpegvideoencdsp_init_arm.c @@ -24,8 +24,8 @@ #include "libavcodec/avcodec.h" #include "libavcodec/mpegvideoencdsp.h" -int ff_pix_norm1_armv6(const uint8_t *pix, int line_size); -int ff_pix_sum_armv6(const uint8_t *pix, int line_size); +int ff_pix_norm1_armv6(const uint8_t *pix, ptrdiff_t line_size); +int ff_pix_sum_armv6(const uint8_t *pix, ptrdiff_t line_size); av_cold void ff_mpegvideoencdsp_init_arm(MpegvideoEncDSPContext *c, AVCodecContext *avctx) diff --git a/libavcodec/arm/vp8.h b/libavcodec/arm/vp8.h index 7c59a7d63..6f128ffeb 100644 --- a/libavcodec/arm/vp8.h +++ b/libavcodec/arm/vp8.h @@ -29,7 +29,8 @@ #define vp8_decode_block_coeffs_internal ff_decode_block_coeffs_armv6 int ff_decode_block_coeffs_armv6(VPXRangeCoder *rc, int16_t block[16], uint8_t probs[8][3][NUM_DCT_TOKENS-1], - int i, uint8_t *token_prob, int16_t qmul[2]); + int i, const uint8_t *token_prob, + const int16_t qmul[2]); #endif #endif /* AVCODEC_ARM_VP8_H */ diff --git a/libavcodec/arm/vp9mc_neon.S b/libavcodec/arm/vp9mc_neon.S index bd8cda7c3..2ec729bb3 100644 --- a/libavcodec/arm/vp9mc_neon.S +++ b/libavcodec/arm/vp9mc_neon.S @@ -279,11 +279,13 @@ function \type\()_8tap_\size\()h_\idx1\idx2 sub r1, r1, r5 .endif @ size >= 16 loads two qwords and increments r2, - @ for size 4/8 it's enough with one qword and no - @ postincrement + @ size 4 loads 1 d word, increments r2 and loads 1 32-bit lane + @ for size 8 it's enough with one qword and no postincrement .if \size >= 16 sub r3, r3, r5 sub r3, r3, #8 +.elseif \size == 4 + sub r3, r3, #8 .endif @ Load the filter vector vld1.16 {q0}, [r12,:128] @@ -295,9 +297,14 @@ function \type\()_8tap_\size\()h_\idx1\idx2 .if \size >= 16 vld1.8 {d18, d19, d20}, [r2]! vld1.8 {d24, d25, d26}, [r7]! -.else +.elseif \size == 8 vld1.8 {q9}, [r2] vld1.8 {q12}, [r7] +.else @ size == 4 + vld1.8 {d18}, [r2]! + vld1.8 {d24}, [r7]! + vld1.32 {d19[0]}, [r2] + vld1.32 {d25[0]}, [r7] .endif vmovl.u8 q8, d18 vmovl.u8 q9, d19 diff --git a/libavcodec/ass.c b/libavcodec/ass.c index 5058dc833..35861139e 100644 --- a/libavcodec/ass.c +++ b/libavcodec/ass.c @@ -23,7 +23,7 @@ #include "ass.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" -#include "libavutil/common.h" +#include "libavutil/mem.h" #include "version.h" int ff_ass_subtitle_header_full(AVCodecContext *avctx, @@ -35,15 +35,15 @@ int ff_ass_subtitle_header_full(AVCodecContext *avctx, int border_style, int alignment) { 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" - "ScaledBorderAndShadow: yes\r\n" - "YCbCr Matrix: None\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" + "ScaledBorderAndShadow: yes\n" + "YCbCr Matrix: None\n" + "\n" + "[V4+ Styles]\n" /* ASS (v4+) header */ "Format: Name, " @@ -54,7 +54,7 @@ int ff_ass_subtitle_header_full(AVCodecContext *avctx, "Spacing, Angle, " "BorderStyle, Outline, Shadow, " "Alignment, MarginL, MarginR, MarginV, " - "Encoding\r\n" + "Encoding\n" "Style: " "Default," /* Name */ @@ -65,11 +65,11 @@ int ff_ass_subtitle_header_full(AVCodecContext *avctx, "0,0," /* Spacing, Angle */ "%d,1,0," /* BorderStyle, Outline, Shadow */ "%d,10,10,10," /* Alignment, Margin[LRV] */ - "1\r\n" /* Encoding */ + "1\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) : "", play_res_x, play_res_y, font, font_size, primary_color, secondary_color, outline_color, back_color, @@ -181,10 +181,21 @@ void ff_ass_bprint_text_event(AVBPrint *buf, const char *p, int size, if (linebreaks && strchr(linebreaks, *p)) { av_bprintf(buf, "\\N"); - /* standard ASS escaping so random characters don't get mis-interpreted - * as ASS */ - } else if (!keep_ass_markup && strchr("{}\\", *p)) { - av_bprintf(buf, "\\%c", *p); + /* cancel curly brackets to avoid bogus override tag blocks + * hiding text. Standard ASS has no character escapes, + * though (only) libass provides \{ and \}. + * Unpaired closing brackets don't need escaping at all though and + * to make the situation less bad in standard ASS insert an empty block + */ + } else if (!keep_ass_markup && *p == '{') { + av_bprintf(buf, "\\{{}"); + + /* append word-joiner U+2060 as UTF-8 to break up sequences like \N */ + } else if (!keep_ass_markup && *p == '\\') { + if (p_end - p <= 3 || strncmp(p + 1, "\xe2\x81\xa0", 3)) + av_bprintf(buf, "\\\xe2\x81\xa0"); + else + av_bprintf(buf, "\\"); /* some packets might end abruptly (no \0 at the end, like for example * in some cases of demuxing from a classic video container), some diff --git a/libavcodec/asvdec.c b/libavcodec/asvdec.c index 568881ccd..5abe279f3 100644 --- a/libavcodec/asvdec.c +++ b/libavcodec/asvdec.c @@ -244,8 +244,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; if (avctx->codec_id == AV_CODEC_ID_ASV1) { av_fast_padded_malloc(&a->bitstream_buffer, &a->bitstream_buffer_size, diff --git a/libavcodec/asvenc.c b/libavcodec/asvenc.c index 6179b5058..4f81a4015 100644 --- a/libavcodec/asvenc.c +++ b/libavcodec/asvenc.c @@ -367,6 +367,7 @@ const FFCodec ff_asv1_encoder = { FF_CODEC_ENCODE_CB(encode_frame), .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, }; #endif @@ -382,5 +383,6 @@ const FFCodec ff_asv2_encoder = { FF_CODEC_ENCODE_CB(encode_frame), .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, }; #endif diff --git a/libavcodec/atrac1.c b/libavcodec/atrac1.c index 1309bb95a..cdcc7a669 100644 --- a/libavcodec/atrac1.c +++ b/libavcodec/atrac1.c @@ -31,6 +31,7 @@ #include #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/tx.h" diff --git a/libavcodec/atrac3.c b/libavcodec/atrac3.c index fad2299aa..39ddfd9e4 100644 --- a/libavcodec/atrac3.c +++ b/libavcodec/atrac3.c @@ -38,6 +38,7 @@ #include "libavutil/attributes.h" #include "libavutil/float_dsp.h" #include "libavutil/libm.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" #include "libavutil/tx.h" diff --git a/libavcodec/atrac3plus.c b/libavcodec/atrac3plus.c index 61753af73..f17ed0cbb 100644 --- a/libavcodec/atrac3plus.c +++ b/libavcodec/atrac3plus.c @@ -734,7 +734,7 @@ static void decode_qu_spectra(GetBitContext *gb, const Atrac3pSpecCodeTab *tab, val = get_vlc2(gb, vlc_tab->table, vlc_tab->bits, 1); for (i = 0; i < num_coeffs; i++) { - cf = av_mod_uintp2(val, bits); + cf = av_zero_extend(val, bits); if (is_signed) cf = sign_extend(cf, bits); else if (cf && get_bits1(gb)) diff --git a/libavcodec/atrac3plusdec.c b/libavcodec/atrac3plusdec.c index aa4d42f44..9696a523b 100644 --- a/libavcodec/atrac3plusdec.c +++ b/libavcodec/atrac3plusdec.c @@ -39,6 +39,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" #include "avcodec.h" diff --git a/libavcodec/atrac9dec.c b/libavcodec/atrac9dec.c index 91f2e50b0..e375f46fd 100644 --- a/libavcodec/atrac9dec.c +++ b/libavcodec/atrac9dec.c @@ -20,6 +20,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "codec_internal.h" diff --git a/libavcodec/atsc_a53.c b/libavcodec/atsc_a53.c index 29ec71bc5..1e9ea15ae 100644 --- a/libavcodec/atsc_a53.c +++ b/libavcodec/atsc_a53.c @@ -19,6 +19,7 @@ #include #include +#include "libavutil/mem.h" #include "atsc_a53.h" #include "get_bits.h" diff --git a/libavcodec/audio_frame_queue.c b/libavcodec/audio_frame_queue.c index 08b4b368c..10b5d2139 100644 --- a/libavcodec/audio_frame_queue.c +++ b/libavcodec/audio_frame_queue.c @@ -20,7 +20,7 @@ */ #include "libavutil/attributes.h" -#include "libavutil/common.h" +#include "libavutil/mem.h" #include "audio_frame_queue.h" #include "encode.h" #include "libavutil/avassert.h" diff --git a/libavcodec/audiodsp.c b/libavcodec/audiodsp.c index c5427d353..fd6a00345 100644 --- a/libavcodec/audiodsp.c +++ b/libavcodec/audiodsp.c @@ -22,57 +22,16 @@ #include "libavutil/common.h" #include "audiodsp.h" -static inline float clipf_c_one(float a, uint32_t mini, - uint32_t maxi, uint32_t maxisign) -{ - uint32_t ai = av_float2int(a); - - if (ai > mini) - return av_int2float(mini); - else if ((ai ^ (1U << 31)) > maxisign) - return av_int2float(maxi); - else - return a; -} - -static void vector_clipf_c_opposite_sign(float *dst, const float *src, - float min, float max, int len) -{ - int i; - uint32_t mini = av_float2int(min); - uint32_t maxi = av_float2int(max); - uint32_t maxisign = maxi ^ (1U << 31); - - for (i = 0; i < len; i += 8) { - dst[i + 0] = clipf_c_one(src[i + 0], mini, maxi, maxisign); - dst[i + 1] = clipf_c_one(src[i + 1], mini, maxi, maxisign); - dst[i + 2] = clipf_c_one(src[i + 2], mini, maxi, maxisign); - dst[i + 3] = clipf_c_one(src[i + 3], mini, maxi, maxisign); - dst[i + 4] = clipf_c_one(src[i + 4], mini, maxi, maxisign); - dst[i + 5] = clipf_c_one(src[i + 5], mini, maxi, maxisign); - dst[i + 6] = clipf_c_one(src[i + 6], mini, maxi, maxisign); - dst[i + 7] = clipf_c_one(src[i + 7], mini, maxi, maxisign); - } -} - static void vector_clipf_c(float *dst, const float *src, int len, float min, float max) { - int i; + for (int i = 0; i < len; i += 8) { + float tmp[8]; - if (min < 0 && max > 0) { - vector_clipf_c_opposite_sign(dst, src, min, max, len); - } else { - for (i = 0; i < len; i += 8) { - dst[i] = av_clipf(src[i], min, max); - dst[i + 1] = av_clipf(src[i + 1], min, max); - dst[i + 2] = av_clipf(src[i + 2], min, max); - dst[i + 3] = av_clipf(src[i + 3], min, max); - dst[i + 4] = av_clipf(src[i + 4], min, max); - dst[i + 5] = av_clipf(src[i + 5], min, max); - dst[i + 6] = av_clipf(src[i + 6], min, max); - dst[i + 7] = av_clipf(src[i + 7], min, max); - } + for (int j = 0; j < 8; j++) + tmp[j]= av_clipf(src[i + j], min, max); + for (int j = 0; j < 8; j++) + dst[i + j] = tmp[j]; } } diff --git a/libavcodec/audiotoolboxdec.c b/libavcodec/audiotoolboxdec.c index 5456f916c..08203c531 100644 --- a/libavcodec/audiotoolboxdec.c +++ b/libavcodec/audiotoolboxdec.c @@ -32,6 +32,7 @@ #include "mpegaudiodecheader.h" #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/log.h" @@ -541,6 +542,8 @@ static int ffat_decode(AVCodecContext *avctx, AVFrame *frame, frame->nb_samples = avctx->frame_size; + frame->flags |= AV_FRAME_FLAG_KEY; + out_buffers.mBuffers[0].mData = at->decoded_data; ret = AudioConverterFillComplexBuffer(at->converter, ffat_decode_callback, avctx, diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index 2c65101fd..908b56055 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -35,6 +35,7 @@ #include "libavformat/isom.h" #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/log.h" @@ -575,6 +576,7 @@ static int ffat_encode(AVCodecContext *avctx, AVPacket *avpkt, avctx->frame_size, &avpkt->pts, &avpkt->duration); + avpkt->flags |= AV_PKT_FLAG_KEY; } else if (ret && ret != 1) { av_log(avctx, AV_LOG_ERROR, "Encode error: %i\n", ret); return AVERROR_EXTERNAL; diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c index 32c2379a4..1d5b9ef4f 100644 --- a/libavcodec/av1dec.c +++ b/libavcodec/av1dec.c @@ -23,6 +23,7 @@ #include "libavutil/hdr_dynamic_metadata.h" #include "libavutil/film_grain_params.h" #include "libavutil/mastering_display_metadata.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avcodec.h" @@ -37,8 +38,8 @@ #include "itut35.h" #include "hwconfig.h" #include "profiles.h" +#include "progressframe.h" #include "refstruct.h" -#include "thread.h" /**< same with Div_Lut defined in spec 7.11.3.7 */ static const uint16_t div_lut[AV1_DIV_LUT_NUM] = { @@ -676,7 +677,7 @@ static int get_pixel_format(AVCodecContext *avctx) static void av1_frame_unref(AV1Frame *f) { - av_frame_unref(f->f); + ff_progress_frame_unref(&f->pf); ff_refstruct_unref(&f->hwaccel_picture_private); ff_refstruct_unref(&f->header_ref); f->raw_frame_header = NULL; @@ -687,20 +688,15 @@ static void av1_frame_unref(AV1Frame *f) f->coded_lossless = 0; } -static int av1_frame_ref(AVCodecContext *avctx, AV1Frame *dst, const AV1Frame *src) +static void av1_frame_replace(AV1Frame *dst, const AV1Frame *src) { - int ret; + av_assert1(dst != src); ff_refstruct_replace(&dst->header_ref, src->header_ref); dst->raw_frame_header = src->raw_frame_header; - if (!src->f->buf[0]) - return 0; - - ret = av_frame_ref(dst->f, src->f); - if (ret < 0) - goto fail; + ff_progress_frame_replace(&dst->pf, &src->pf); ff_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); @@ -731,12 +727,6 @@ static int av1_frame_ref(AVCodecContext *avctx, AV1Frame *dst, const AV1Frame *s sizeof(dst->order_hints)); dst->force_integer_mv = src->force_integer_mv; - - return 0; - -fail: - av1_frame_unref(dst); - return AVERROR(ENOMEM); } static av_cold int av1_decode_free(AVCodecContext *avctx) @@ -744,16 +734,9 @@ static av_cold int av1_decode_free(AVCodecContext *avctx) AV1DecContext *s = avctx->priv_data; AV1RawMetadataITUTT35 itut_t35; - for (int i = 0; i < FF_ARRAY_ELEMS(s->ref); i++) { - if (s->ref[i].f) { - av1_frame_unref(&s->ref[i]); - av_frame_free(&s->ref[i].f); - } - } - if (s->cur_frame.f) { - av1_frame_unref(&s->cur_frame); - av_frame_free(&s->cur_frame.f); - } + for (int i = 0; i < FF_ARRAY_ELEMS(s->ref); i++) + 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); @@ -869,16 +852,6 @@ static av_cold int av1_decode_init(AVCodecContext *avctx) s->pkt = avctx->internal->in_pkt; s->pix_fmt = AV_PIX_FMT_NONE; - for (int i = 0; i < FF_ARRAY_ELEMS(s->ref); i++) { - s->ref[i].f = av_frame_alloc(); - if (!s->ref[i].f) - return AVERROR(ENOMEM); - } - - s->cur_frame.f = av_frame_alloc(); - if (!s->cur_frame.f) - return AVERROR(ENOMEM); - ret = ff_cbs_init(&s->cbc, AV_CODEC_ID_AV1, avctx); if (ret < 0) return ret; @@ -919,10 +892,10 @@ static av_cold int av1_decode_init(AVCodecContext *avctx) } s->dovi.logctx = avctx; - s->dovi.dv_profile = 10; // default for AV1 + s->dovi.cfg.dv_profile = 10; // default for AV1 sd = ff_get_coded_side_data(avctx, AV_PKT_DATA_DOVI_CONF); - if (sd && sd->size > 0) - ff_dovi_update_cfg(&s->dovi, (AVDOVIDecoderConfigurationRecord *) sd->data); + if (sd && sd->size >= sizeof(s->dovi.cfg)) + s->dovi.cfg = *(AVDOVIDecoderConfigurationRecord *) sd->data; return ret; } @@ -940,7 +913,8 @@ static int av1_frame_alloc(AVCodecContext *avctx, AV1Frame *f) return ret; } - if ((ret = ff_thread_get_buffer(avctx, f->f, AV_GET_BUFFER_FLAG_REF)) < 0) + ret = ff_progress_frame_get_buffer(avctx, &f->pf, AV_GET_BUFFER_FLAG_REF); + if (ret < 0) goto fail; frame = f->f; @@ -996,7 +970,7 @@ static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame, if (!ret) break; - ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_A53_CC, &buf, NULL); + ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_A53_CC, &buf); if (ret < 0) return ret; @@ -1033,7 +1007,8 @@ static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame, provider_oriented_code != 0x800) break; - ret = ff_dovi_rpu_parse(&s->dovi, gb.buffer, gb.buffer_end - gb.buffer); + ret = ff_dovi_rpu_parse(&s->dovi, gb.buffer, gb.buffer_end - gb.buffer, + avctx->err_recognition); if (ret < 0) { av_log(avctx, AV_LOG_WARNING, "Error parsing DOVI OBU.\n"); break; // ignore @@ -1216,23 +1191,15 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; } -static int update_reference_list(AVCodecContext *avctx) +static void update_reference_list(AVCodecContext *avctx) { AV1DecContext *s = avctx->priv_data; const AV1RawFrameHeader *header = s->raw_frame_header; - int ret; for (int i = 0; i < AV1_NUM_REF_FRAMES; i++) { - if (header->refresh_frame_flags & (1 << i)) { - av1_frame_unref(&s->ref[i]); - if ((ret = av1_frame_ref(avctx, &s->ref[i], &s->cur_frame)) < 0) { - av_log(avctx, AV_LOG_ERROR, - "Failed to update frame %d in reference list\n", i); - return ret; - } - } + if (header->refresh_frame_flags & (1 << i)) + av1_frame_replace(&s->ref[i], &s->cur_frame); } - return 0; } static int get_current_frame(AVCodecContext *avctx) @@ -1366,29 +1333,22 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) s->raw_frame_header = &obu->obu.frame_header; if (s->raw_frame_header->show_existing_frame) { - av1_frame_unref(&s->cur_frame); + av1_frame_replace(&s->cur_frame, + &s->ref[s->raw_frame_header->frame_to_show_map_idx]); - ret = av1_frame_ref(avctx, &s->cur_frame, - &s->ref[s->raw_frame_header->frame_to_show_map_idx]); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to get reference frame.\n"); - goto end; - } + update_reference_list(avctx); - ret = update_reference_list(avctx); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to update reference list.\n"); - goto end; - } - - if (s->cur_frame.f->buf[0]) { + if (s->cur_frame.f) { ret = set_output_frame(avctx, frame); - if (ret < 0) + if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Set output frame error.\n"); + goto end; + } } s->raw_frame_header = NULL; i++; + ret = 0; goto end; } @@ -1402,7 +1362,7 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) s->cur_frame.spatial_id = header->spatial_id; s->cur_frame.temporal_id = header->temporal_id; - if (avctx->hwaccel && s->cur_frame.f->buf[0]) { + if (avctx->hwaccel && s->cur_frame.f) { ret = FF_HW_CALL(avctx, start_frame, unit->data, unit->data_size); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "HW accel start frame fail.\n"); @@ -1428,7 +1388,7 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) if (ret < 0) goto end; - if (avctx->hwaccel && s->cur_frame.f->buf[0]) { + if (avctx->hwaccel && s->cur_frame.f) { ret = FF_HW_CALL(avctx, decode_slice, raw_tile_group->tile_data.data, raw_tile_group->tile_data.data_size); if (ret < 0) { @@ -1479,7 +1439,7 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) if (raw_tile_group && (s->tile_num == raw_tile_group->tg_end + 1)) { int show_frame = s->raw_frame_header->show_frame; - if (avctx->hwaccel && s->cur_frame.f->buf[0]) { + if (avctx->hwaccel && s->cur_frame.f) { ret = FF_HW_SIMPLE_CALL(avctx, end_frame); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "HW accel end frame fail.\n"); @@ -1487,23 +1447,22 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) } } - ret = update_reference_list(avctx); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to update reference list.\n"); - goto end; - } + update_reference_list(avctx); - if (s->raw_frame_header->show_frame && s->cur_frame.f->buf[0]) { - ret = set_output_frame(avctx, frame); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Set output frame error\n"); - goto end; - } - } - raw_tile_group = NULL; + raw_tile_group = NULL; s->raw_frame_header = NULL; + if (show_frame) { + // cur_frame.f needn't exist due to skip_frame. + if (s->cur_frame.f) { + ret = set_output_frame(avctx, frame); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Set output frame error\n"); + goto end; + } + } i++; + ret = 0; goto end; } } @@ -1607,7 +1566,9 @@ const FFCodec ff_av1_decoder = { .close = av1_decode_free, FF_CODEC_RECEIVE_FRAME_CB(av1_receive_frame), .p.capabilities = AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | + FF_CODEC_CAP_USES_PROGRESSFRAMES, .flush = av1_decode_flush, .p.profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles), .p.priv_class = &av1_class, diff --git a/libavcodec/av1dec.h b/libavcodec/av1dec.h index b903b359c..8b2a7b089 100644 --- a/libavcodec/av1dec.h +++ b/libavcodec/av1dec.h @@ -32,9 +32,15 @@ #include "cbs.h" #include "cbs_av1.h" #include "dovi_rpu.h" +#include "progressframe.h" typedef struct AV1Frame { - AVFrame *f; + union { + struct { + struct AVFrame *f; + }; + ProgressFrame pf; + }; void *hwaccel_picture_private; ///< RefStruct reference diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c index a9a87bb58..1fa8704c9 100644 --- a/libavcodec/avcodec.c +++ b/libavcodec/avcodec.c @@ -28,6 +28,7 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" +#include "libavutil/common.h" #include "libavutil/emms.h" #include "libavutil/fifo.h" #include "libavutil/imgutils.h" @@ -54,6 +55,20 @@ */ #define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) +const SideDataMap ff_sd_global_map[] = { + { AV_PKT_DATA_REPLAYGAIN , AV_FRAME_DATA_REPLAYGAIN }, + { AV_PKT_DATA_DISPLAYMATRIX, AV_FRAME_DATA_DISPLAYMATRIX }, + { AV_PKT_DATA_SPHERICAL, AV_FRAME_DATA_SPHERICAL }, + { AV_PKT_DATA_STEREO3D, AV_FRAME_DATA_STEREO3D }, + { AV_PKT_DATA_AUDIO_SERVICE_TYPE, AV_FRAME_DATA_AUDIO_SERVICE_TYPE }, + { AV_PKT_DATA_MASTERING_DISPLAY_METADATA, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA }, + { 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_NB }, +}; + + int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2), void *arg, int *ret, int count, int size) { size_t i; @@ -130,6 +145,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code int ret = 0; AVCodecInternal *avci; const FFCodec *codec2; + const AVDictionaryEntry *e; if (avcodec_is_open(avctx)) return 0; @@ -160,6 +176,20 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if (avctx->extradata_size < 0 || avctx->extradata_size >= FF_MAX_EXTRADATA_SIZE) return AVERROR(EINVAL); + // set the whitelist from provided options dict, + // so we can check it immediately + e = options ? av_dict_get(*options, "codec_whitelist", NULL, 0) : NULL; + if (e) { + ret = av_opt_set(avctx, e->key, e->value, 0); + if (ret < 0) + return ret; + } + + if (avctx->codec_whitelist && av_match_list(codec->name, avctx->codec_whitelist, ',') <= 0) { + av_log(avctx, AV_LOG_ERROR, "Codec (%s) not on whitelist \'%s\'\n", codec->name, avctx->codec_whitelist); + return AVERROR(EINVAL); + } + avci = av_codec_is_decoder(codec) ? ff_decode_internal_alloc() : ff_encode_internal_alloc(); @@ -188,19 +218,13 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code av_opt_set_defaults(avctx->priv_data); } } - if (codec->priv_class && (ret = av_opt_set_dict(avctx->priv_data, options)) < 0) - goto free_and_end; } else { avctx->priv_data = NULL; } - if ((ret = av_opt_set_dict(avctx, options)) < 0) - goto free_and_end; - if (avctx->codec_whitelist && av_match_list(codec->name, avctx->codec_whitelist, ',') <= 0) { - av_log(avctx, AV_LOG_ERROR, "Codec (%s) not on whitelist \'%s\'\n", codec->name, avctx->codec_whitelist); - ret = AVERROR(EINVAL); + ret = av_opt_set_dict2(avctx, options, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) goto free_and_end; - } // only call ff_set_dimensions() for non H.264/VP6F/DXV codecs so as not to overwrite previously setup dimensions if (!(avctx->coded_width && avctx->coded_height && avctx->width && avctx->height && @@ -367,10 +391,13 @@ void avcodec_flush_buffers(AVCodecContext *avctx) avci->draining = 0; avci->draining_done = 0; - av_frame_unref(avci->buffer_frame); - av_packet_unref(avci->buffer_pkt); + if (avci->buffer_frame) + av_frame_unref(avci->buffer_frame); + if (avci->buffer_pkt) + av_packet_unref(avci->buffer_pkt); - if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) + if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME && + !avci->is_frame_mt) ff_thread_flush(avctx); else if (ffcodec(avctx->codec)->flush) ffcodec(avctx->codec)->flush(avctx); @@ -427,6 +454,9 @@ av_cold void ff_codec_close(AVCodecContext *avctx) av_frame_free(&avci->recon_frame); ff_refstruct_unref(&avci->pool); + ff_refstruct_pool_uninit(&avci->progress_frame_pool); + if (av_codec_is_decoder(avctx->codec)) + ff_decode_internal_uninit(avctx); ff_hwaccel_uninit(avctx); @@ -447,6 +477,8 @@ av_cold void ff_codec_close(AVCodecContext *avctx) av_freep(&avctx->coded_side_data[i].data); av_freep(&avctx->coded_side_data); avctx->nb_coded_side_data = 0; + av_frame_side_data_free(&avctx->decoded_side_data, + &avctx->nb_decoded_side_data); av_buffer_unref(&avctx->hw_frames_ctx); av_buffer_unref(&avctx->hw_device_ctx); @@ -686,3 +718,96 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr return ff_decode_receive_frame(avctx, frame); return ff_encode_receive_frame(avctx, frame); } + +#define WRAP_CONFIG(allowed_type, field, field_type, terminator) \ + do { \ + static const field_type end = terminator; \ + if (codec->type != (allowed_type)) \ + return AVERROR(EINVAL); \ + *out_configs = (field); \ + if (out_num_configs) { \ + for (int i = 0;; i++) { \ + if (!(field) || !memcmp(&(field)[i], &end, sizeof(end))) { \ + *out_num_configs = i; \ + break; \ + } \ + } \ + } \ + return 0; \ + } while (0) + +static const enum AVColorRange color_range_jpeg[] = { + AVCOL_RANGE_JPEG, AVCOL_RANGE_UNSPECIFIED +}; + +static const enum AVColorRange color_range_mpeg[] = { + AVCOL_RANGE_MPEG, AVCOL_RANGE_UNSPECIFIED +}; + +static const enum AVColorRange color_range_all[] = { + AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG, AVCOL_RANGE_UNSPECIFIED +}; + +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, +}; + +int ff_default_get_supported_config(const AVCodecContext *avctx, + const AVCodec *codec, + enum AVCodecConfig config, + unsigned flags, + const void **out_configs, + int *out_num_configs) +{ + 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); + case AV_CODEC_CONFIG_FRAME_RATE: + WRAP_CONFIG(AVMEDIA_TYPE_VIDEO, codec->supported_framerates, AVRational, {0}); + case AV_CODEC_CONFIG_SAMPLE_RATE: + WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, codec->supported_samplerates, int, 0); + case AV_CODEC_CONFIG_SAMPLE_FORMAT: + WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, codec->sample_fmts, enum AVSampleFormat, AV_SAMPLE_FMT_NONE); + case AV_CODEC_CONFIG_CHANNEL_LAYOUT: + WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, codec->ch_layouts, AVChannelLayout, {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); + return 0; + + case AV_CODEC_CONFIG_COLOR_SPACE: + *out_configs = NULL; + if (out_num_configs) + *out_num_configs = 0; + return 0; + default: + return AVERROR(EINVAL); + } +} + +int avcodec_get_supported_config(const AVCodecContext *avctx, const AVCodec *codec, + enum AVCodecConfig config, unsigned flags, + const void **out, int *out_num) +{ + const FFCodec *codec2; + int dummy_num = 0; + if (!codec) + codec = avctx->codec; + if (!out_num) + out_num = &dummy_num; + + codec2 = ffcodec(codec); + if (codec2->get_supported_config) { + return codec2->get_supported_config(avctx, codec, config, flags, out, out_num); + } else { + return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num); + } +} diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 83dc48725..77ca8dee1 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -419,6 +419,12 @@ typedef struct RcOverride{ */ #define AV_CODEC_EXPORT_DATA_FILM_GRAIN (1 << 3) +/** + * Decoding only. + * Do not apply picture enhancement layers, export them instead. + */ +#define AV_CODEC_EXPORT_DATA_ENHANCEMENTS (1 << 4) + /** * The decoder will keep a reference to the frame and may reuse it later. */ @@ -1175,6 +1181,10 @@ typedef struct AVCodecContext { * this callback and filled with the extra buffers if there are more * buffers than buf[] can hold. extended_buf will be freed in * av_frame_unref(). + * Decoders will generally initialize the whole buffer before it is output + * but it can in rare error conditions happen that uninitialized data is passed + * through. \important The buffers returned by get_buffer* should thus not contain sensitive + * data. * * If AV_CODEC_CAP_DR1 is not set then get_buffer2() must call * avcodec_default_get_buffer2() instead of providing buffers allocated by @@ -1538,6 +1548,7 @@ typedef struct AVCodecContext { #define FF_DCT_MMX 3 #define FF_DCT_ALTIVEC 5 #define FF_DCT_FAAN 6 +#define FF_DCT_NEON 7 /** * IDCT algorithm, see FF_IDCT_* below. @@ -2071,7 +2082,7 @@ typedef struct AVCodecContext { * - encoding: may be set by user before calling avcodec_open2() for * encoder configuration. Afterwards owned and freed by the * encoder. - * - decoding: unused + * - decoding: may be set by libavcodec in avcodec_open2(). */ AVFrameSideData **decoded_side_data; int nb_decoded_side_data; @@ -2690,6 +2701,36 @@ int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, enum AVPixelFormat hw_pix_fmt, AVBufferRef **out_frames_ref); +enum AVCodecConfig { + AV_CODEC_CONFIG_PIX_FORMAT, ///< AVPixelFormat, terminated by AV_PIX_FMT_NONE + AV_CODEC_CONFIG_FRAME_RATE, ///< AVRational, terminated by {0, 0} + AV_CODEC_CONFIG_SAMPLE_RATE, ///< int, terminated by 0 + AV_CODEC_CONFIG_SAMPLE_FORMAT, ///< AVSampleFormat, terminated by AV_SAMPLE_FMT_NONE + 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 +}; + +/** + * Retrieve a list of all supported values for a given configuration type. + * + * @param avctx An optional context to use. Values such as + * `strict_std_compliance` may affect the result. If NULL, + * default values are used. + * @param codec The codec to query, or NULL to use avctx->codec. + * @param config The configuration to query. + * @param flags Currently unused; should be set to zero. + * @param out_configs On success, set to a list of configurations, terminated + * by a config-specific terminator, or NULL if all + * possible values are supported. + * @param out_num_configs On success, set to the number of elements in + *out_configs, excluding the terminator. Optional. + */ +int avcodec_get_supported_config(const AVCodecContext *avctx, + const AVCodec *codec, enum AVCodecConfig config, + unsigned flags, const void **out_configs, + int *out_num_configs); + /** diff --git a/libavcodec/avcodec_internal.h b/libavcodec/avcodec_internal.h index 4d1cb3a31..184d7b526 100644 --- a/libavcodec/avcodec_internal.h +++ b/libavcodec/avcodec_internal.h @@ -25,8 +25,22 @@ #ifndef AVCODEC_AVCODEC_INTERNAL_H #define AVCODEC_AVCODEC_INTERNAL_H +#include "libavutil/frame.h" + +#include "packet.h" + struct AVCodecContext; -struct AVFrame; + +typedef struct SideDataMap { + enum AVPacketSideDataType packet; + enum AVFrameSideDataType frame; +} SideDataMap; + +/** + * A map between packet and frame side data types. + * Terminated with an entry where packet=AV_PKT_DATA_NB. + */ +extern const SideDataMap ff_sd_global_map[]; /** * avcodec_receive_frame() implementation for decoders. @@ -54,8 +68,43 @@ void ff_decode_flush_buffers(struct AVCodecContext *avctx); void ff_encode_flush_buffers(struct AVCodecContext *avctx); struct AVCodecInternal *ff_decode_internal_alloc(void); +void ff_decode_internal_sync(struct AVCodecContext *dst, + const struct AVCodecContext *src); +void ff_decode_internal_uninit(struct AVCodecContext *avctx); + struct AVCodecInternal *ff_encode_internal_alloc(void); void ff_codec_close(struct AVCodecContext *avctx); +int ff_thread_init(struct AVCodecContext *s); +void ff_thread_free(struct AVCodecContext *s); + +/** + * Wait for decoding threads to finish and reset internal state. + * Called by avcodec_flush_buffers(). + * + * @param avctx The context. + */ +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. + */ +int ff_thread_receive_frame(struct AVCodecContext *avctx, AVFrame *frame); + +/** + * Do the actual decoding and obtain a decoded frame from the decoder, if + * available. When frame threading is used, this is invoked by the worker + * threads, otherwise by the top layer directly. + */ +int ff_decode_receive_frame_internal(struct AVCodecContext *avctx, AVFrame *frame); + +/** + * Get a packet for decoding. This gets invoked by the worker threads. + */ +int ff_thread_get_packet(struct AVCodecContext *avctx, AVPacket *pkt); + #endif // AVCODEC_AVCODEC_INTERNAL_H diff --git a/libavcodec/avdct.c b/libavcodec/avdct.c index 37266f4b4..f995e73ea 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/mem.h" #include "avcodec.h" #include "idctdsp.h" #include "fdctdsp.h" diff --git a/libavcodec/avfft.c b/libavcodec/avfft.c index 627fd7a0b..f6787937f 100644 --- a/libavcodec/avfft.c +++ b/libavcodec/avfft.c @@ -158,7 +158,7 @@ RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans) return NULL; } - s->stride = (trans == DFT_C2R) ? sizeof(float) : sizeof(AVComplexFloat); + s->stride = (trans == DFT_C2R) ? sizeof(AVComplexFloat) : sizeof(float); s->len = 1 << nbits; s->inv = trans == IDFT_C2R; diff --git a/libavcodec/avr32/mathops.h b/libavcodec/avr32/mathops.h deleted file mode 100644 index 85f42b594..000000000 --- a/libavcodec/avr32/mathops.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Simple math operations - * Copyright (c) 2009 Mans Rullgard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_AVR32_MATHOPS_H -#define AVCODEC_AVR32_MATHOPS_H - -#include -#include "config.h" -#include "libavutil/common.h" - -#if HAVE_INLINE_ASM - -#define MULL MULL -static inline av_const int MULL(int a, int b, unsigned shift) -{ - union { int64_t x; int hl[2]; } x; - __asm__ ("muls.d %0, %1, %2 \n\t" - "lsr %0, %3 \n\t" - "or %0, %0, %m0<<%4 \n\t" - : "=r"(x) : "r"(b), "r"(a), "i"(shift), "i"(32-shift)); - return x.hl[1]; -} - -#define MULH MULH -static inline av_const int MULH(int a, int b) -{ - union { int64_t x; int hl[2]; } x; - __asm__ ("muls.d %0, %1, %2" : "=r"(x.x) : "r"(a), "r"(b)); - return x.hl[0]; -} - -#define MUL64 MUL64 -static inline av_const int64_t MUL64(int a, int b) -{ - int64_t x; - __asm__ ("muls.d %0, %1, %2" : "=r"(x) : "r"(a), "r"(b)); - return x; -} - -static inline av_const int64_t MAC64(int64_t d, int a, int b) -{ - __asm__ ("macs.d %0, %1, %2" : "+r"(d) : "r"(a), "r"(b)); - return d; -} -#define MAC64(d, a, b) ((d) = MAC64(d, a, b)) -#define MLS64(d, a, b) MAC64(d, -(a), b) - -static inline av_const int MAC16(int d, int a, int b) -{ - __asm__ ("machh.w %0, %1:b, %2:b" : "+r"(d) : "r"(a), "r"(b)); - return d; -} -#define MAC16(d, a, b) ((d) = MAC16(d, a, b)) -#define MLS16(d, a, b) MAC16(d, -(a), b) - -#define MUL16 MUL16 -static inline av_const int MUL16(int a, int b) -{ - int d; - __asm__ ("mulhh.w %0, %1:b, %2:b" : "=r"(d) : "r"(a), "r"(b)); - return d; -} - -#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" - "cp.w %1, %2 \n\t" - "movgt %0, %1 \n\t" - "movgt %1, %2 \n\t" - "cp.w %1, %3 \n\t" - "movle %1, %3 \n\t" - "cp.w %0, %1 \n\t" - "movgt %0, %1 \n\t" - : "=&r"(m), "+r"(a) - : "r"(b), "r"(c)); - return m; -} - -#endif /* HAVE_INLINE_ASM */ - -#endif /* AVCODEC_AVR32_MATHOPS_H */ diff --git a/libavcodec/avrndec.c b/libavcodec/avrndec.c index 97d282462..02bdfb651 100644 --- a/libavcodec/avrndec.c +++ b/libavcodec/avrndec.c @@ -67,8 +67,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type= AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; if(a->interlace) { buf += (true_height - avctx->height)*avctx->width; diff --git a/libavcodec/avuidec.c b/libavcodec/avuidec.c index 48b23d487..64a1d019d 100644 --- a/libavcodec/avuidec.c +++ b/libavcodec/avuidec.c @@ -71,9 +71,6 @@ static int avui_decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - if (!interlaced) { src += avctx->width * skip; srca += avctx->width * skip; diff --git a/libavcodec/avuienc.c b/libavcodec/avuienc.c index 8a093d3d1..a2391b31e 100644 --- a/libavcodec/avuienc.c +++ b/libavcodec/avuienc.c @@ -24,6 +24,7 @@ #include "codec_internal.h" #include "encode.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" static av_cold int avui_encode_init(AVCodecContext *avctx) { @@ -99,6 +100,7 @@ const FFCodec ff_avui_encoder = { .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 }, + .color_ranges = AVCOL_RANGE_MPEG, .init = avui_encode_init, FF_CODEC_ENCODE_CB(avui_encode_frame), }; diff --git a/libavcodec/bfi.c b/libavcodec/bfi.c index 901669a3a..58158f6ee 100644 --- a/libavcodec/bfi.c +++ b/libavcodec/bfi.c @@ -26,14 +26,13 @@ * @see http://wiki.multimedia.cx/index.php?title=BFI */ -#include "libavutil/common.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" #include "decode.h" typedef struct BFIContext { - AVCodecContext *avctx; uint8_t *dst; uint32_t pal[256]; } BFIContext; diff --git a/libavcodec/bgmc.c b/libavcodec/bgmc.c index 0e41a39e0..97c53a49c 100644 --- a/libavcodec/bgmc.c +++ b/libavcodec/bgmc.c @@ -26,6 +26,7 @@ */ #include "libavutil/attributes.h" +#include "libavutil/mem.h" #include "bgmc.h" #define FREQ_BITS 14 // bits used by frequency counters diff --git a/libavcodec/bink.c b/libavcodec/bink.c index 804c14198..04fd90aa1 100644 --- a/libavcodec/bink.c +++ b/libavcodec/bink.c @@ -23,7 +23,7 @@ #include "libavutil/attributes.h" #include "libavutil/emms.h" #include "libavutil/imgutils.h" -#include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" diff --git a/libavcodec/bitpacked_dec.c b/libavcodec/bitpacked_dec.c index 54c008bd8..a1d3b7b50 100644 --- a/libavcodec/bitpacked_dec.c +++ b/libavcodec/bitpacked_dec.c @@ -130,9 +130,6 @@ static int bitpacked_decode(AVCodecContext *avctx, AVFrame *frame, if (res) return res; - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; - *got_frame = 1; return buf_size; diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index 12860c332..f923411be 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -31,9 +31,11 @@ extern const FFBitStreamFilter ff_av1_metadata_bsf; extern const FFBitStreamFilter ff_chomp_bsf; extern const FFBitStreamFilter ff_dump_extradata_bsf; extern const FFBitStreamFilter ff_dca_core_bsf; +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_evc_frame_merge_bsf; extern const FFBitStreamFilter ff_extract_extradata_bsf; extern const FFBitStreamFilter ff_filter_units_bsf; extern const FFBitStreamFilter ff_h264_metadata_bsf; @@ -67,7 +69,6 @@ extern const FFBitStreamFilter ff_vp9_superframe_bsf; extern const FFBitStreamFilter ff_vp9_superframe_split_bsf; extern const FFBitStreamFilter ff_vvc_metadata_bsf; extern const FFBitStreamFilter ff_vvc_mp4toannexb_bsf; -extern const FFBitStreamFilter ff_evc_frame_merge_bsf; #include "libavcodec/bsf_list.c" diff --git a/libavcodec/bitstream_template.h b/libavcodec/bitstream_template.h index c8e4a5131..bbb8dfa55 100644 --- a/libavcodec/bitstream_template.h +++ b/libavcodec/bitstream_template.h @@ -542,7 +542,7 @@ static inline int BS_FUNC(read_vlc_multi)(BSCTX *bc, uint8_t dst[8], unsigned idx = BS_FUNC(peek)(bc, bits); int ret, nb_bits, code, n = Jtable[idx].len; if (Jtable[idx].num) { - AV_COPY64U(dst, Jtable[idx].val); + AV_COPY64U(dst, Jtable[idx].val8); ret = Jtable[idx].num; } else { code = table[idx].sym; diff --git a/libavcodec/blockdsp.c b/libavcodec/blockdsp.c index 79a881426..57ca41bd9 100644 --- a/libavcodec/blockdsp.c +++ b/libavcodec/blockdsp.c @@ -63,9 +63,7 @@ av_cold void ff_blockdsp_init(BlockDSPContext *c) c->fill_block_tab[0] = fill_block16_c; c->fill_block_tab[1] = fill_block8_c; -#if ARCH_ALPHA - ff_blockdsp_init_alpha(c); -#elif ARCH_ARM +#if ARCH_ARM ff_blockdsp_init_arm(c); #elif ARCH_PPC ff_blockdsp_init_ppc(c); diff --git a/libavcodec/bmp.c b/libavcodec/bmp.c index d117c06cf..360c10320 100644 --- a/libavcodec/bmp.c +++ b/libavcodec/bmp.c @@ -209,8 +209,6 @@ static int bmp_decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; buf = buf0 + hsize; dsize = buf_size - hsize; diff --git a/libavcodec/bmpenc.c b/libavcodec/bmpenc.c index 3e3ca324e..48f25170b 100644 --- a/libavcodec/bmpenc.c +++ b/libavcodec/bmpenc.c @@ -22,8 +22,8 @@ #include "config.h" -#include "libavutil/imgutils.h" #include "libavutil/avassert.h" +#include "libavutil/imgutils_internal.h" #include "avcodec.h" #include "bytestream.h" #include "bmp.h" diff --git a/libavcodec/bonk.c b/libavcodec/bonk.c index 65679e5fb..14b7457a1 100644 --- a/libavcodec/bonk.c +++ b/libavcodec/bonk.c @@ -18,14 +18,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" #define BITSTREAM_READER_LE #include "get_bits.h" -#include "bytestream.h" typedef struct BitCount { uint8_t bit; diff --git a/libavcodec/brenderpix.c b/libavcodec/brenderpix.c index 70a3e6be2..07bb47fff 100644 --- a/libavcodec/brenderpix.c +++ b/libavcodec/brenderpix.c @@ -285,8 +285,6 @@ FF_ENABLE_DEPRECATION_WARNINGS bytes_per_scanline, bytes_per_scanline, hdr.height); - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/bsf/Makefile b/libavcodec/bsf/Makefile index fb70ad0c2..40b7fc6e9 100644 --- a/libavcodec/bsf/Makefile +++ b/libavcodec/bsf/Makefile @@ -19,6 +19,7 @@ OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF) += bsf/h264_mp4toannexb.o OBJS-$(CONFIG_H264_REDUNDANT_PPS_BSF) += bsf/h264_redundant_pps.o OBJS-$(CONFIG_HAPQA_EXTRACT_BSF) += bsf/hapqa_extract.o 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_MEDIA100_TO_MJPEGB_BSF) += bsf/media100_to_mjpegb.o diff --git a/libavcodec/bsf/aac_adtstoasc.c b/libavcodec/bsf/aac_adtstoasc.c index dd5e8b2a3..b821414f2 100644 --- a/libavcodec/bsf/aac_adtstoasc.c +++ b/libavcodec/bsf/aac_adtstoasc.c @@ -40,7 +40,6 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *pkt) { AACBSFContext *ctx = bsfc->priv_data; - GetBitContext gb; PutBitContext pb; AACADTSHeaderInfo hdr; int ret; @@ -55,9 +54,7 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *pkt) if (pkt->size < AV_AAC_ADTS_HEADER_SIZE) goto packet_too_small; - init_get_bits(&gb, pkt->data, AV_AAC_ADTS_HEADER_SIZE * 8); - - if (ff_adts_header_parse(&gb, &hdr) < 0) { + if (ff_adts_header_parse_buf(pkt->data, &hdr) < 0) { av_log(bsfc, AV_LOG_ERROR, "Error parsing ADTS frame header!\n"); ret = AVERROR_INVALIDDATA; goto fail; @@ -81,6 +78,7 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *pkt) uint8_t *extradata; if (!hdr.chan_config) { + GetBitContext gb; init_get_bits(&gb, pkt->data, pkt->size * 8); if (get_bits(&gb, 3) != 5) { avpriv_report_missing_feature(bsfc, diff --git a/libavcodec/bsf/dovi_rpu.c b/libavcodec/bsf/dovi_rpu.c new file mode 100644 index 000000000..ae04d1636 --- /dev/null +++ b/libavcodec/bsf/dovi_rpu.c @@ -0,0 +1,285 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/mem.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "bsf_internal.h" +#include "cbs.h" +#include "cbs_bsf.h" +#include "cbs_av1.h" +#include "cbs_h265.h" +#include "dovi_rpu.h" +#include "h2645data.h" +#include "h265_profile_level.h" +#include "itut35.h" + +#include "hevc/hevc.h" + +typedef struct DoviRpuContext { + CBSBSFContext common; + DOVIContext dec; + DOVIContext enc; + + int strip; + int compression; +} DoviRpuContext; + +static int update_rpu(AVBSFContext *bsf, const AVPacket *pkt, int flags, + const uint8_t *rpu, size_t rpu_size, + uint8_t **out_rpu, int *out_size) +{ + DoviRpuContext *s = bsf->priv_data; + AVDOVIMetadata *metadata = NULL; + int ret; + + ret = ff_dovi_rpu_parse(&s->dec, rpu, rpu_size, 0); + if (ret < 0) { + ff_dovi_ctx_flush(&s->dec); + return ret; + } + + ret = ff_dovi_get_metadata(&s->dec, &metadata); + if (ret == 0 /* no metadata */) { + *out_rpu = NULL; + *out_size = 0; + return 0; + } else if (ret < 0) { + ff_dovi_ctx_flush(&s->dec); + return ret; + } + + if (pkt && !(pkt->flags & AV_PKT_FLAG_KEY)) + flags |= FF_DOVI_COMPRESS_RPU; + ret = ff_dovi_rpu_generate(&s->enc, metadata, flags, out_rpu, out_size); + av_free(metadata); + if (ret < 0) + ff_dovi_ctx_flush(&s->enc); + + return ret; +} + +static int dovi_rpu_update_fragment_hevc(AVBSFContext *bsf, AVPacket *pkt, + CodedBitstreamFragment *au) +{ + DoviRpuContext *s = bsf->priv_data; + CodedBitstreamUnit *nal = au->nb_units ? &au->units[au->nb_units - 1] : NULL; + uint8_t *rpu = NULL; + int rpu_size, ret; + + if (!nal || nal->type != HEVC_NAL_UNSPEC62) + return 0; + + if (s->strip) { + ff_cbs_delete_unit(au, au->nb_units - 1); + return 0; + } + + ret = update_rpu(bsf, pkt, 0, nal->data + 2, nal->data_size - 2, &rpu, &rpu_size); + if (ret < 0) + return ret; + + /* NAL unit header + NAL prefix */ + if (rpu_size + 3 <= nal->data_size && av_buffer_is_writable(nal->data_ref)) { + memcpy(nal->data + 3, rpu, rpu_size); + av_free(rpu); + nal->data_size = rpu_size + 3; + } else { + AVBufferRef *ref = av_buffer_alloc(rpu_size + 3); + if (!ref) { + av_free(rpu); + return AVERROR(ENOMEM); + } + + memcpy(ref->data, nal->data, 3); + memcpy(ref->data + 3, rpu, rpu_size); + av_buffer_unref(&nal->data_ref); + av_free(rpu); + nal->data = ref->data; + nal->data_size = rpu_size + 3; + nal->data_ref = ref; + nal->data_bit_padding = 0; + } + + return 0; +} + +static int dovi_rpu_update_fragment_av1(AVBSFContext *bsf, AVPacket *pkt, + CodedBitstreamFragment *frag) +{ + DoviRpuContext *s = bsf->priv_data; + int provider_code, provider_oriented_code, rpu_size, ret; + AVBufferRef *ref; + uint8_t *rpu; + + for (int i = 0; i < frag->nb_units; i++) { + AV1RawOBU *obu = frag->units[i].content; + AV1RawMetadataITUTT35 *t35 = &obu->obu.metadata.metadata.itut_t35; + if (frag->units[i].type != AV1_OBU_METADATA || + obu->obu.metadata.metadata_type != AV1_METADATA_TYPE_ITUT_T35 || + t35->itu_t_t35_country_code != ITU_T_T35_COUNTRY_CODE_US || + t35->payload_size < 6) + continue; + + provider_code = AV_RB16(t35->payload); + provider_oriented_code = AV_RB32(t35->payload + 2); + if (provider_code != ITU_T_T35_PROVIDER_CODE_DOLBY || + provider_oriented_code != 0x800) + continue; + + if (s->strip) { + ff_cbs_delete_unit(frag, i); + return 0; + } + + ret = update_rpu(bsf, pkt, FF_DOVI_WRAP_T35, + t35->payload + 6, t35->payload_size - 6, + &rpu, &rpu_size); + if (ret < 0) + return ret; + + ref = av_buffer_create(rpu, rpu_size, av_buffer_default_free, NULL, 0); + if (!ref) { + av_free(rpu); + return AVERROR(ENOMEM); + } + + av_buffer_unref(&t35->payload_ref); + t35->payload_ref = ref; + t35->payload = rpu + 1; /* skip country code */ + t35->payload_size = rpu_size - 1; + break; /* should be only one RPU per packet */ + } + + return 0; +} + +static const CBSBSFType dovi_rpu_hevc_type = { + .codec_id = AV_CODEC_ID_HEVC, + .fragment_name = "access unit", + .unit_name = "NAL unit", + .update_fragment = &dovi_rpu_update_fragment_hevc, +}; + +static const CBSBSFType dovi_rpu_av1_type = { + .codec_id = AV_CODEC_ID_AV1, + .fragment_name = "temporal unit", + .unit_name = "OBU", + .update_fragment = &dovi_rpu_update_fragment_av1, +}; + +static int dovi_rpu_init(AVBSFContext *bsf) +{ + int ret; + DoviRpuContext *s = bsf->priv_data; + s->dec.logctx = s->enc.logctx = bsf; + s->enc.enable = 1; + + if (s->compression == AV_DOVI_COMPRESSION_RESERVED) { + av_log(bsf, AV_LOG_ERROR, "Invalid compression level: %d\n", s->compression); + return AVERROR(EINVAL); + } + + if (s->strip) { + av_packet_side_data_remove(bsf->par_out->coded_side_data, + &bsf->par_out->nb_coded_side_data, + AV_PKT_DATA_DOVI_CONF); + } else { + const AVPacketSideData *sd; + sd = av_packet_side_data_get(bsf->par_out->coded_side_data, + bsf->par_out->nb_coded_side_data, + AV_PKT_DATA_DOVI_CONF); + + if (sd) { + AVDOVIDecoderConfigurationRecord *cfg; + cfg = (AVDOVIDecoderConfigurationRecord *) sd->data; + s->dec.cfg = *cfg; + + /* Update configuration record before setting to enc ctx */ + cfg->dv_md_compression = s->compression; + if (s->compression && s->dec.cfg.dv_profile < 8) { + av_log(bsf, AV_LOG_ERROR, "Invalid compression level %d for " + "Dolby Vision profile %d.\n", s->compression, s->dec.cfg.dv_profile); + return AVERROR(EINVAL); + } + + s->enc.cfg = *cfg; + } 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); + if (ret < 0) + return ret; + /* Be conservative in accepting all compressed RPUs */ + s->dec.cfg = s->enc.cfg; + s->dec.cfg.dv_md_compression = AV_DOVI_COMPRESSION_EXTENDED; + } + } + + switch (bsf->par_in->codec_id) { + case AV_CODEC_ID_HEVC: + return ff_cbs_bsf_generic_init(bsf, &dovi_rpu_hevc_type); + case AV_CODEC_ID_AV1: + return ff_cbs_bsf_generic_init(bsf, &dovi_rpu_av1_type); + default: + return AVERROR_BUG; + } +} + +static void dovi_rpu_close(AVBSFContext *bsf) +{ + DoviRpuContext *s = bsf->priv_data; + ff_dovi_ctx_unref(&s->dec); + ff_dovi_ctx_unref(&s->enc); + ff_cbs_bsf_generic_close(bsf); +} + +#define OFFSET(x) offsetof(DoviRpuContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption dovi_rpu_options[] = { + { "strip", "Strip Dolby Vision metadata", OFFSET(strip), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { "compression", "DV metadata compression mode", OFFSET(compression), AV_OPT_TYPE_INT, { .i64 = AV_DOVI_COMPRESSION_LIMITED }, 0, AV_DOVI_COMPRESSION_EXTENDED, FLAGS, .unit = "compression" }, + { "none", "Don't compress metadata", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, .flags = FLAGS, .unit = "compression" }, + { "limited", "Limited metadata compression", 0, AV_OPT_TYPE_CONST, {.i64 = AV_DOVI_COMPRESSION_LIMITED}, .flags = FLAGS, .unit = "compression" }, + { "extended", "Extended metadata compression",0, AV_OPT_TYPE_CONST, {.i64 = AV_DOVI_COMPRESSION_EXTENDED}, .flags = FLAGS, .unit = "compression" }, + { NULL } +}; + +static const AVClass dovi_rpu_class = { + .class_name = "dovi_rpu_bsf", + .item_name = av_default_item_name, + .option = dovi_rpu_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID dovi_rpu_codec_ids[] = { + AV_CODEC_ID_HEVC, AV_CODEC_ID_AV1, AV_CODEC_ID_NONE, +}; + +const FFBitStreamFilter ff_dovi_rpu_bsf = { + .p.name = "dovi_rpu", + .p.codec_ids = dovi_rpu_codec_ids, + .p.priv_class = &dovi_rpu_class, + .priv_data_size = sizeof(DoviRpuContext), + .init = &dovi_rpu_init, + .close = &dovi_rpu_close, + .filter = &ff_cbs_bsf_generic_filter, +}; diff --git a/libavcodec/bsf/dts2pts.c b/libavcodec/bsf/dts2pts.c index 263514faa..62838d4f7 100644 --- a/libavcodec/bsf/dts2pts.c +++ b/libavcodec/bsf/dts2pts.c @@ -25,6 +25,7 @@ #include "libavutil/avassert.h" #include "libavutil/fifo.h" +#include "libavutil/mem.h" #include "libavutil/tree.h" #include "bsf.h" @@ -33,6 +34,7 @@ #include "cbs_h264.h" #include "h264_parse.h" #include "h264_ps.h" +#include "refstruct.h" typedef struct DTS2PTSNode { int64_t dts; @@ -60,6 +62,7 @@ typedef struct DTS2PTSH264Context { typedef struct DTS2PTSContext { struct AVTreeNode *root; AVFifo *fifo; + FFRefStructPool *node_pool; // Codec specific function pointers and constants int (*init)(AVBSFContext *ctx); @@ -109,7 +112,7 @@ static int dec_poc(void *opaque, void *elem) static int free_node(void *opaque, void *elem) { DTS2PTSNode *node = elem; - av_free(node); + ff_refstruct_unref(&node); return 0; } @@ -123,7 +126,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 = av_malloc(sizeof(*poc_node)); + poc_node = ff_refstruct_pool_get(s->node_pool); if (!poc_node) { av_free(node); return AVERROR(ENOMEM); @@ -134,7 +137,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; - av_free(poc_node); + ff_refstruct_unref(&poc_node); av_free(node); } } @@ -268,8 +271,8 @@ static int h264_filter(AVBSFContext *ctx) h264->sps.offset_for_non_ref_pic = sps->offset_for_non_ref_pic; h264->sps.offset_for_top_to_bottom_field = sps->offset_for_top_to_bottom_field; h264->sps.poc_cycle_length = sps->num_ref_frames_in_pic_order_cnt_cycle; - for (int i = 0; i < h264->sps.poc_cycle_length; i++) - h264->sps.offset_for_ref_frame[i] = sps->offset_for_ref_frame[i]; + for (int j = 0; j < h264->sps.poc_cycle_length; j++) + h264->sps.offset_for_ref_frame[j] = sps->offset_for_ref_frame[j]; h264->picture_structure = sps->frame_mbs_only_flag ? 3 : (header->field_pic_flag ? @@ -393,6 +396,12 @@ 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); + + if (!s->node_pool) + return AVERROR(ENOMEM); + ret = ff_cbs_init(&s->cbc, ctx->par_in->codec_id, ctx); if (ret < 0) return ret; @@ -458,7 +467,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); - av_free(poc_node); + ff_refstruct_unref(&poc_node); av_free(node); poc_node = av_tree_find(s->root, &dup, cmp_find, NULL); } @@ -520,6 +529,7 @@ static void dts2pts_close(AVBSFContext *ctx) dts2pts_flush(ctx); av_fifo_freep2(&s->fifo); + ff_refstruct_pool_uninit(&s->node_pool); ff_cbs_fragment_free(&s->au); ff_cbs_close(&s->cbc); } diff --git a/libavcodec/bsf/evc_frame_merge.c b/libavcodec/bsf/evc_frame_merge.c index 7b8e6b1c9..1b52ba290 100644 --- a/libavcodec/bsf/evc_frame_merge.c +++ b/libavcodec/bsf/evc_frame_merge.c @@ -17,6 +17,7 @@ * 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 "get_bits.h" #include "bsf.h" #include "bsf_internal.h" diff --git a/libavcodec/bsf/extract_extradata.c b/libavcodec/bsf/extract_extradata.c index 5d5d80c90..43f4d6285 100644 --- a/libavcodec/bsf/extract_extradata.c +++ b/libavcodec/bsf/extract_extradata.c @@ -19,6 +19,7 @@ #include #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "av1.h" @@ -28,11 +29,12 @@ #include "bytestream.h" #include "h2645_parse.h" #include "h264.h" -#include "hevc.h" #include "startcode.h" #include "vc1_common.h" #include "vvc.h" +#include "hevc/hevc.h" + typedef struct ExtractExtradataContext { const AVClass *class; @@ -191,7 +193,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, } ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size, - ctx, 0, 0, ctx->par_in->codec_id, 1, 0); + ctx, 0, ctx->par_in->codec_id, H2645_FLAG_SMALL_PADDING); if (ret < 0) return ret; diff --git a/libavcodec/bsf/filter_units.c b/libavcodec/bsf/filter_units.c index 9aead542c..336331733 100644 --- a/libavcodec/bsf/filter_units.c +++ b/libavcodec/bsf/filter_units.c @@ -16,9 +16,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include -#include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "bsf.h" @@ -44,6 +45,7 @@ typedef struct FilterUnitsContext { } mode; CodedBitstreamUnitType *type_list; int nb_types; + bool passthrough; } FilterUnitsContext; @@ -111,7 +113,7 @@ static int filter_units_filter(AVBSFContext *bsf, AVPacket *pkt) if (err < 0) return err; - if (ctx->mode == NOOP && ctx->discard <= AVDISCARD_DEFAULT) + if (ctx->passthrough) return 0; err = ff_cbs_read_packet(ctx->cbc, frag, pkt); @@ -181,6 +183,7 @@ static int filter_units_init(AVBSFContext *bsf) return err; } } else if (ctx->discard == AVDISCARD_NONE) { + ctx->passthrough = true; return 0; } diff --git a/libavcodec/bsf/h264_metadata.c b/libavcodec/bsf/h264_metadata.c index 239e82aa3..477f1b18b 100644 --- a/libavcodec/bsf/h264_metadata.c +++ b/libavcodec/bsf/h264_metadata.c @@ -19,6 +19,7 @@ #include "libavutil/avstring.h" #include "libavutil/display.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "bsf.h" diff --git a/libavcodec/bsf/h264_mp4toannexb.c b/libavcodec/bsf/h264_mp4toannexb.c index 92af6a688..dda064287 100644 --- a/libavcodec/bsf/h264_mp4toannexb.c +++ b/libavcodec/bsf/h264_mp4toannexb.c @@ -30,6 +30,7 @@ #include "bytestream.h" #include "defs.h" #include "h264.h" +#include "sei.h" typedef struct H264BSFContext { uint8_t *sps; @@ -363,6 +364,20 @@ static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *opkt) if (!new_idr && unit_type == H264_NAL_IDR_SLICE && (buf[1] & 0x80)) new_idr = 1; + /* If this is a buffering period SEI without a corresponding sps/pps + * then prepend any existing sps/pps before the SEI */ + if (unit_type == H264_NAL_SEI && buf[1] == SEI_TYPE_BUFFERING_PERIOD && + !sps_seen && !pps_seen) { + if (s->sps_size) { + count_or_copy(&out, &out_size, s->sps, s->sps_size, PS_OUT_OF_BAND, j); + sps_seen = 1; + } + if (s->pps_size) { + count_or_copy(&out, &out_size, s->pps, s->pps_size, PS_OUT_OF_BAND, j); + pps_seen = 1; + } + } + /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */ if (new_idr && unit_type == H264_NAL_IDR_SLICE && !sps_seen && !pps_seen) { if (s->sps_size) diff --git a/libavcodec/bsf/h265_metadata.c b/libavcodec/bsf/h265_metadata.c index c9e1cc3ee..4b0601bee 100644 --- a/libavcodec/bsf/h265_metadata.c +++ b/libavcodec/bsf/h265_metadata.c @@ -25,9 +25,10 @@ #include "cbs_bsf.h" #include "cbs_h265.h" #include "h2645data.h" -#include "hevc.h" #include "h265_profile_level.h" +#include "hevc/hevc.h" + enum { LEVEL_UNSET = -2, LEVEL_AUTO = -1, @@ -58,6 +59,8 @@ typedef struct H265MetadataContext { int crop_right; int crop_top; int crop_bottom; + int width; + int height; int level; int level_guess; @@ -187,12 +190,94 @@ static int h265_metadata_update_vps(AVBSFContext *bsf, return 0; } +static int h265_metadata_deduce_crop(AVBSFContext *bsf, const H265RawSPS *sps, + int *crop_left, int *crop_right, + int *crop_top, int *crop_bottom) +{ + const H265MetadataContext *ctx = bsf->priv_data; + int left = ctx->crop_left; + int right = ctx->crop_right; + int top = ctx->crop_top; + int bottom = ctx->crop_bottom; + + if (ctx->width > 0) { + if (ctx->width > sps->pic_width_in_luma_samples) { + av_log(bsf, AV_LOG_ERROR, + "The width option value %d is larger than picture width %d\n", + ctx->width, sps->pic_width_in_luma_samples); + return AVERROR(EINVAL); + } + + if (left < 0) { + if (right > 0) + left = sps->pic_width_in_luma_samples - ctx->width - right; + else + left = 0; + } + + if (right < 0) + right = sps->pic_width_in_luma_samples - ctx->width - left; + + if (left < 0 || right < 0 || (left + right + ctx->width) != + sps->pic_width_in_luma_samples) { + av_log(bsf, AV_LOG_ERROR, + "Invalid value for crop_left %d, crop_right %d, width after " + "crop %d, with picture width %d\n", + ctx->crop_left, ctx->crop_right, ctx->width, + sps->pic_width_in_luma_samples); + return AVERROR(EINVAL); + } + } + + if (ctx->height > 0) { + if (ctx->height > sps->pic_height_in_luma_samples) { + av_log(bsf, AV_LOG_ERROR, + "The height option value %d is larger than picture height %d\n", + ctx->height, sps->pic_height_in_luma_samples); + return AVERROR(EINVAL); + } + + if (top < 0) { + if (bottom > 0) + top = sps->pic_height_in_luma_samples - ctx->height - bottom; + else + top = 0; + } + + if (bottom < 0) + bottom = sps->pic_height_in_luma_samples - ctx->height - top; + + if (top < 0 || bottom < 0 || (top + bottom + ctx->height) != + sps->pic_height_in_luma_samples) { + av_log(bsf, AV_LOG_ERROR, + "Invalid value for crop_top %d, crop_bottom %d, height after " + "crop %d, with picture height %d\n", + ctx->crop_top, ctx->crop_bottom, ctx->height, + sps->pic_height_in_luma_samples); + return AVERROR(EINVAL); + } + } + + *crop_left = left; + *crop_right = right; + *crop_top = top; + *crop_bottom = bottom; + + return 0; +} + static int h265_metadata_update_sps(AVBSFContext *bsf, H265RawSPS *sps) { H265MetadataContext *ctx = bsf->priv_data; int need_vui = 0; int crop_unit_x, crop_unit_y; + /* Use local variables to avoid modifying context fields in case of video + * resolution changed. Crop doesn't work well with resolution change, this + * is the best we can do. + */ + int crop_left, crop_right, crop_top, crop_bottom; + int ret; if (ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) { int num, den, i; @@ -289,6 +374,11 @@ static int h265_metadata_update_sps(AVBSFContext *bsf, } } + ret = h265_metadata_deduce_crop(bsf, sps, &crop_left, &crop_right, + &crop_top, &crop_bottom); + if (ret < 0) + return ret; + if (sps->separate_colour_plane_flag || sps->chroma_format_idc == 0) { crop_unit_x = 1; crop_unit_y = 1; @@ -297,14 +387,14 @@ static int h265_metadata_update_sps(AVBSFContext *bsf, crop_unit_y = 1 + (sps->chroma_format_idc < 2); } #define CROP(border, unit) do { \ - if (ctx->crop_ ## border >= 0) { \ - if (ctx->crop_ ## border % unit != 0) { \ + if (crop_ ## border >= 0) { \ + if (crop_ ## border % unit != 0) { \ av_log(bsf, AV_LOG_ERROR, "Invalid value for crop_%s: " \ "must be a multiple of %d.\n", #border, unit); \ return AVERROR(EINVAL); \ } \ sps->conf_win_ ## border ## _offset = \ - ctx->crop_ ## border / unit; \ + crop_ ## border / unit; \ sps->conformance_window_flag = 1; \ } \ } while (0) @@ -453,6 +543,12 @@ static const AVOption h265_metadata_options[] = { { "crop_bottom", "Set bottom border crop offset", OFFSET(crop_bottom), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, HEVC_MAX_HEIGHT, FLAGS }, + { "width", "Set width after crop", + OFFSET(width), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_WIDTH, FLAGS }, + { "height", "Set height after crop", + OFFSET(height), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_HEIGHT, FLAGS }, { "level", "Set level (tables A.6 and A.7)", OFFSET(level), AV_OPT_TYPE_INT, diff --git a/libavcodec/bsf/hevc_mp4toannexb.c b/libavcodec/bsf/hevc_mp4toannexb.c index 8eec18f31..f28118576 100644 --- a/libavcodec/bsf/hevc_mp4toannexb.c +++ b/libavcodec/bsf/hevc_mp4toannexb.c @@ -28,7 +28,8 @@ #include "bsf_internal.h" #include "bytestream.h" #include "defs.h" -#include "hevc.h" + +#include "hevc/hevc.h" #define MIN_HEVCC_LENGTH 23 diff --git a/libavcodec/bsf/media100_to_mjpegb.c b/libavcodec/bsf/media100_to_mjpegb.c index 6e117ae20..4b2dc1a35 100644 --- a/libavcodec/bsf/media100_to_mjpegb.c +++ b/libavcodec/bsf/media100_to_mjpegb.c @@ -148,6 +148,7 @@ second_field: AV_WB32(out->data + second_field_offset + 36, sod_offset[1] - second_field_offset); out->size = bytestream2_tell_p(&pb); + memset(out->data + out->size, 0, AV_INPUT_BUFFER_PADDING_SIZE); ret = av_packet_copy_props(out, in); if (ret < 0) diff --git a/libavcodec/bsf/noise.c b/libavcodec/bsf/noise.c index 3a0f388dd..a62285571 100644 --- a/libavcodec/bsf/noise.c +++ b/libavcodec/bsf/noise.c @@ -24,6 +24,7 @@ #include "bsf_internal.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/eval.h" diff --git a/libavcodec/bsf/remove_extradata.c b/libavcodec/bsf/remove_extradata.c index 3010eba05..b4a035943 100644 --- a/libavcodec/bsf/remove_extradata.c +++ b/libavcodec/bsf/remove_extradata.c @@ -25,10 +25,11 @@ #include "bsf.h" #include "bsf_internal.h" #include "h264.h" -#include "hevc.h" #include "startcode.h" #include "vc1_common.h" +#include "hevc/hevc.h" + enum RemoveFreq { REMOVE_FREQ_KEYFRAME, REMOVE_FREQ_ALL, diff --git a/libavcodec/bsf/showinfo.c b/libavcodec/bsf/showinfo.c index 4e31e0b5c..715b160b6 100644 --- a/libavcodec/bsf/showinfo.c +++ b/libavcodec/bsf/showinfo.c @@ -23,6 +23,7 @@ #include "bsf.h" #include "bsf_internal.h" +#include "libavutil/adler32.h" #include "libavutil/log.h" #include "libavutil/timestamp.h" @@ -33,23 +34,26 @@ typedef struct ShowinfoContext { static int showinfo_filter(AVBSFContext *ctx, AVPacket *pkt) { ShowinfoContext *priv = ctx->priv_data; + uint32_t crc; int ret; ret = ff_bsf_get_packet_ref(ctx, pkt); if (ret < 0) return ret; + crc = av_adler32_update(0, pkt->data, pkt->size); av_log(ctx, AV_LOG_INFO, "n:%7"PRIu64" " "size:%7d " "pts:%s pt:%s " "dts:%s dt:%s " "ds:%"PRId64" d:%s " + "adler32:0x%08"PRIx32 "\n", priv->nb_packets, pkt->size, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ctx->time_base_in), av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ctx->time_base_in), - pkt->duration, av_ts2timestr(pkt->duration, &ctx->time_base_in)); + pkt->duration, av_ts2timestr(pkt->duration, &ctx->time_base_in), crc); priv->nb_packets++; diff --git a/libavcodec/cavs.c b/libavcodec/cavs.c index fdd577f7f..172cc5cc7 100644 --- a/libavcodec/cavs.c +++ b/libavcodec/cavs.c @@ -25,6 +25,7 @@ * @author Stefan Gehrer */ +#include "libavutil/mem.h" #include "avcodec.h" #include "golomb.h" #include "h264chroma.h" diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c index b356da0b0..3cf8c9fb3 100644 --- a/libavcodec/cavsdec.c +++ b/libavcodec/cavsdec.c @@ -27,6 +27,7 @@ #include "libavutil/avassert.h" #include "libavutil/emms.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "get_bits.h" #include "golomb.h" diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index de7b1361a..b26e39eab 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -23,6 +23,7 @@ #include "libavutil/avassert.h" #include "libavutil/buffer.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c index 458381f03..98d745f49 100644 --- a/libavcodec/cbs_av1.c +++ b/libavcodec/cbs_av1.c @@ -728,16 +728,16 @@ static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, } while (size > 0) { - AV1RawOBUHeader header; + AV1RawOBUHeader obu_header; uint64_t obu_size; init_get_bits(&gbc, data, 8 * size); - err = cbs_av1_read_obu_header(ctx, &gbc, &header); + err = cbs_av1_read_obu_header(ctx, &gbc, &obu_header); if (err < 0) goto fail; - if (header.obu_has_size_field) { + 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); @@ -748,7 +748,7 @@ static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, if (err < 0) goto fail; } else - obu_size = size - 1 - header.obu_extension_flag; + obu_size = size - 1 - obu_header.obu_extension_flag; pos = get_bits_count(&gbc); av_assert0(pos % 8 == 0 && pos / 8 <= size); @@ -763,7 +763,7 @@ static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, goto fail; } - err = ff_cbs_append_unit_data(frag, header.obu_type, + err = ff_cbs_append_unit_data(frag, obu_header.obu_type, data, obu_length, frag->data_ref); if (err < 0) goto fail; diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h index a027013bc..8586f2bf4 100644 --- a/libavcodec/cbs_av1.h +++ b/libavcodec/cbs_av1.h @@ -477,6 +477,11 @@ typedef struct CodedBitstreamAV1Context { // Writing will fail with an error if an OBU larger than can be // represented by the fixed size is encountered. int fixed_obu_size_length; + + int8_t loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME]; + int8_t loop_filter_mode_deltas[2]; + uint8_t feature_enabled[AV1_MAX_SEGMENTS][AV1_SEG_LVL_MAX]; + int16_t feature_value[AV1_MAX_SEGMENTS][AV1_SEG_LVL_MAX]; } CodedBitstreamAV1Context; diff --git a/libavcodec/cbs_av1_syntax_template.c b/libavcodec/cbs_av1_syntax_template.c index 3f4b13a17..a4a912482 100644 --- a/libavcodec/cbs_av1_syntax_template.c +++ b/libavcodec/cbs_av1_syntax_template.c @@ -1374,6 +1374,15 @@ static int FUNC(uncompressed_header)(CodedBitstreamContext *ctx, RWContext *rw, priv->render_height = ref->render_height; priv->bit_depth = ref->bit_depth; priv->order_hint = ref->order_hint; + + memcpy(priv->loop_filter_ref_deltas, ref->loop_filter_ref_deltas, + sizeof(ref->loop_filter_ref_deltas)); + memcpy(priv->loop_filter_mode_deltas, ref->loop_filter_mode_deltas, + sizeof(ref->loop_filter_mode_deltas)); + memcpy(priv->feature_enabled, ref->feature_enabled, + sizeof(ref->feature_enabled)); + memcpy(priv->feature_value, ref->feature_value, + sizeof(ref->feature_value)); } else infer(refresh_frame_flags, 0); @@ -1691,14 +1700,25 @@ update_refs: priv->order_hints[j + AV1_REF_FRAME_LAST]; } - memcpy(priv->ref[i].loop_filter_ref_deltas, current->loop_filter_ref_deltas, - sizeof(current->loop_filter_ref_deltas)); - memcpy(priv->ref[i].loop_filter_mode_deltas, current->loop_filter_mode_deltas, - sizeof(current->loop_filter_mode_deltas)); - memcpy(priv->ref[i].feature_enabled, current->feature_enabled, - sizeof(current->feature_enabled)); - memcpy(priv->ref[i].feature_value, current->feature_value, - sizeof(current->feature_value)); + if (current->show_existing_frame) { + memcpy(priv->ref[i].loop_filter_ref_deltas, priv->loop_filter_ref_deltas, + sizeof(priv->loop_filter_ref_deltas)); + memcpy(priv->ref[i].loop_filter_mode_deltas, priv->loop_filter_mode_deltas, + sizeof(priv->loop_filter_mode_deltas)); + memcpy(priv->ref[i].feature_enabled, priv->feature_enabled, + sizeof(priv->feature_enabled)); + memcpy(priv->ref[i].feature_value, priv->feature_value, + sizeof(priv->feature_value)); + } else { + memcpy(priv->ref[i].loop_filter_ref_deltas, current->loop_filter_ref_deltas, + sizeof(current->loop_filter_ref_deltas)); + memcpy(priv->ref[i].loop_filter_mode_deltas, current->loop_filter_mode_deltas, + sizeof(current->loop_filter_mode_deltas)); + memcpy(priv->ref[i].feature_enabled, current->feature_enabled, + sizeof(current->feature_enabled)); + memcpy(priv->ref[i].feature_value, current->feature_value, + sizeof(current->feature_value)); + } } } diff --git a/libavcodec/cbs_h264.h b/libavcodec/cbs_h264.h index db9123133..3763f2492 100644 --- a/libavcodec/cbs_h264.h +++ b/libavcodec/cbs_h264.h @@ -293,6 +293,26 @@ typedef struct H264RawFilmGrainCharacteristics { uint8_t film_grain_characteristics_repetition_period; } H264RawFilmGrainCharacteristics; +typedef struct H264RawSEIFramePackingArrangement { + uint32_t frame_packing_arrangement_id; + uint8_t frame_packing_arrangement_cancel_flag; + uint8_t frame_packing_arrangement_type; + uint8_t quincunx_sampling_flag; + uint8_t content_interpretation_type; + uint8_t spatial_flipping_flag; + uint8_t frame0_flipped_flag; + uint8_t field_views_flag; + uint8_t current_frame_is_frame0_flag; + uint8_t frame0_self_contained_flag; + uint8_t frame1_self_contained_flag; + uint8_t frame0_grid_position_x; + uint8_t frame0_grid_position_y; + uint8_t frame1_grid_position_x; + uint8_t frame1_grid_position_y; + uint16_t frame_packing_arrangement_repetition_period; + uint8_t frame_packing_arrangement_extension_flag; +} H264RawSEIFramePackingArrangement; + typedef struct H264RawSEIDisplayOrientation { uint8_t display_orientation_cancel_flag; uint8_t hor_flip; diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c index db803ea35..2de74691c 100644 --- a/libavcodec/cbs_h2645.c +++ b/libavcodec/cbs_h2645.c @@ -18,6 +18,7 @@ #include "libavutil/attributes.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "bytestream.h" #include "cbs.h" @@ -27,10 +28,10 @@ #include "cbs_h266.h" #include "h264.h" #include "h2645_parse.h" -#include "hevc.h" #include "refstruct.h" #include "vvc.h" +#include "hevc/hevc.h" static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, const char *name, const int *subscripts, @@ -498,7 +499,8 @@ static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, size_t size = nal->size; enum AVCodecID codec_id = ctx->codec->codec_id; - if (codec_id != AV_CODEC_ID_VVC && nal->nuh_layer_id > 0) + if (codec_id == AV_CODEC_ID_HEVC && nal->nuh_layer_id > 0 && + (nal->type < HEVC_NAL_VPS || nal->type > HEVC_NAL_PPS)) continue; // Remove trailing zeroes. @@ -571,7 +573,8 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, err = ff_h2645_packet_split(&priv->read_packet, frag->data + start, end - start, - ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1, 1); + 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; @@ -595,7 +598,8 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, err = ff_h2645_packet_split(&priv->read_packet, frag->data + start, end - start, - ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1, 1); + 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; @@ -649,7 +653,8 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, err = ff_h2645_packet_split(&priv->read_packet, frag->data + start, end - start, - ctx->log_ctx, 1, 2, AV_CODEC_ID_HEVC, 1, 1); + 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", @@ -719,7 +724,8 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, err = ff_h2645_packet_split(&priv->read_packet, frag->data + start, end - start, - ctx->log_ctx, 1, 2, AV_CODEC_ID_VVC, 1, 1); + 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", @@ -731,13 +737,14 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, 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->mp4, priv->nal_length_size, - codec_id, 1, 1); + priv->nal_length_size, + codec_id, flags); if (err < 0) return err; @@ -788,9 +795,28 @@ static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ } cbs_h266_replace_ps(6, VPS, vps, vps_video_parameter_set_id) -cbs_h266_replace_ps(6, SPS, sps, sps_seq_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) @@ -1029,6 +1055,14 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, } 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: { @@ -1471,6 +1505,14 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, } 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: { @@ -1980,6 +2022,7 @@ static const CodedBitstreamUnitTypeDescriptor cbs_h265_unit_types[] = { 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, @@ -2108,6 +2151,18 @@ static const SEIMessageTypeDescriptor cbs_sei_common_types[] = { 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, @@ -2166,6 +2221,12 @@ static const SEIMessageTypeDescriptor cbs_sei_h264_types[] = { 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, @@ -2236,16 +2297,16 @@ static const SEIMessageTypeDescriptor cbs_sei_h265_types[] = { 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_TYPE_DECODED_PICTURE_HASH, - 0, 1, - sizeof(H266RawSEIDecodedPictureHash), - SEI_MESSAGE_RW(h266, sei_decoded_picture_hash), - }, SEI_MESSAGE_TYPE_END }; @@ -2255,11 +2316,6 @@ const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx, const SEIMessageTypeDescriptor *codec_list; int 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]; - } - switch (ctx->codec->codec_id) { case AV_CODEC_ID_H264: codec_list = cbs_sei_h264_types; @@ -2279,5 +2335,10 @@ const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx, 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_h264_syntax_template.c b/libavcodec/cbs_h264_syntax_template.c index 4d2d30372..9d0386c24 100644 --- a/libavcodec/cbs_h264_syntax_template.c +++ b/libavcodec/cbs_h264_syntax_template.c @@ -801,6 +801,40 @@ SEI_FUNC(film_grain_characteristics, (CodedBitstreamContext *ctx, RWContext *rw, return 0; } +SEI_FUNC(sei_frame_packing_arrangement, (CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIFramePackingArrangement *current, + SEIMessageState *sei)) +{ + int err; + + HEADER("Frame Packing Arrangement"); + + ue(frame_packing_arrangement_id, 0, MAX_UINT_BITS(31)); + flag(frame_packing_arrangement_cancel_flag); + if (!current->frame_packing_arrangement_cancel_flag) { + u(7, frame_packing_arrangement_type, 0, 7); + flag(quincunx_sampling_flag); + u(6, content_interpretation_type, 0, 2); + flag(spatial_flipping_flag); + flag(frame0_flipped_flag); + flag(field_views_flag); + flag(current_frame_is_frame0_flag); + flag(frame0_self_contained_flag); + flag(frame1_self_contained_flag); + if (!current->quincunx_sampling_flag && current->frame_packing_arrangement_type != 5) { + ub(4, frame0_grid_position_x); + ub(4, frame0_grid_position_y); + ub(4, frame1_grid_position_x); + ub(4, frame1_grid_position_y); + } + fixed(8, frame_packing_arrangement_reserved_byte, 0); + ue(frame_packing_arrangement_repetition_period, 0, 16384); + } + flag(frame_packing_arrangement_extension_flag); + + return 0; +} + SEI_FUNC(sei_display_orientation, (CodedBitstreamContext *ctx, RWContext *rw, H264RawSEIDisplayOrientation *current, SEIMessageState *sei)) diff --git a/libavcodec/cbs_h265.h b/libavcodec/cbs_h265.h index 1b1195f19..bb7a29c2e 100644 --- a/libavcodec/cbs_h265.h +++ b/libavcodec/cbs_h265.h @@ -24,7 +24,8 @@ #include "cbs_h2645.h" #include "cbs_sei.h" -#include "hevc.h" + +#include "hevc/hevc.h" typedef struct H265RawNALUnitHeader { uint8_t nal_unit_type; @@ -247,12 +248,16 @@ typedef struct H265RawSPS { uint8_t sps_video_parameter_set_id; uint8_t sps_max_sub_layers_minus1; + uint8_t sps_ext_or_max_sub_layers_minus1; uint8_t sps_temporal_id_nesting_flag; H265RawProfileTierLevel profile_tier_level; uint8_t sps_seq_parameter_set_id; + uint8_t update_rep_format_flag; + uint8_t sps_rep_format_idx; + uint8_t chroma_format_idc; uint8_t separate_colour_plane_flag; @@ -283,6 +288,8 @@ typedef struct H265RawSPS { uint8_t max_transform_hierarchy_depth_intra; uint8_t scaling_list_enabled_flag; + uint8_t sps_infer_scaling_list_flag; + uint8_t sps_scaling_list_ref_layer_id; uint8_t sps_scaling_list_data_present_flag; H265RawScalingList scaling_list; @@ -341,6 +348,9 @@ typedef struct H265RawSPS { uint8_t motion_vector_resolution_control_idc; uint8_t intra_boundary_filtering_disable_flag; + + // Multilayer extension. + uint8_t inter_view_mv_vert_constraint_flag; } H265RawSPS; typedef struct H265RawPPS { @@ -432,6 +442,46 @@ typedef struct H265RawPPS { uint8_t luma_bit_depth_entry_minus8; uint8_t chroma_bit_depth_entry_minus8; uint16_t pps_palette_predictor_initializers[3][128]; + + // Multilayer extension. + uint8_t poc_reset_info_present_flag; + uint8_t pps_infer_scaling_list_flag; + uint8_t pps_scaling_list_ref_layer_id; + uint8_t num_ref_loc_offsets; + uint8_t ref_loc_offset_layer_id[64]; + uint8_t scaled_ref_layer_offset_present_flag[64]; + int16_t scaled_ref_layer_left_offset[64]; + int16_t scaled_ref_layer_top_offset[64]; + int16_t scaled_ref_layer_right_offset[64]; + int16_t scaled_ref_layer_bottom_offset[64]; + uint8_t ref_region_offset_present_flag[64]; + int16_t ref_region_left_offset[64]; + int16_t ref_region_top_offset[64]; + int16_t ref_region_right_offset[64]; + int16_t ref_region_bottom_offset[64]; + uint8_t resample_phase_set_present_flag[64]; + uint8_t phase_hor_luma[64]; + uint8_t phase_ver_luma[64]; + uint8_t phase_hor_chroma_plus8[64]; + uint8_t phase_ver_chroma_plus8[64]; + uint8_t colour_mapping_enabled_flag; + uint8_t num_cm_ref_layers_minus1; + uint8_t cm_ref_layer_id[62]; + uint8_t cm_octant_depth; + uint8_t cm_y_part_num_log2; + uint8_t luma_bit_depth_cm_input_minus8; + uint8_t chroma_bit_depth_cm_input_minus8; + uint8_t luma_bit_depth_cm_output_minus8; + uint8_t chroma_bit_depth_cm_output_minus8; + uint8_t cm_res_quant_bits; + uint8_t cm_delta_flc_bits_minus1; + int16_t cm_adapt_threshold_u_delta; + int16_t cm_adapt_threshold_v_delta; + uint8_t split_octant_flag[2]; + uint8_t coded_res_flag[12][2][2][4]; + uint8_t res_coeff_q[12][2][2][4][3]; + uint32_t res_coeff_s[12][2][2][4][3]; + uint8_t res_coeff_r[12][2][2][4][3]; } H265RawPPS; typedef struct H265RawAUD { @@ -670,11 +720,33 @@ typedef struct H265RawSEIAlphaChannelInfo { uint8_t alpha_channel_clip_type_flag; } H265RawSEIAlphaChannelInfo; +typedef struct H265RawSEI3DReferenceDisplaysInfo { + uint8_t prec_ref_display_width; + uint8_t ref_viewing_distance_flag; + uint8_t prec_ref_viewing_dist; + uint8_t num_ref_displays_minus1; + uint16_t left_view_id[32]; + uint16_t right_view_id[32]; + uint8_t exponent_ref_display_width[32]; + uint8_t mantissa_ref_display_width[32]; + uint8_t exponent_ref_viewing_distance[32]; + uint8_t mantissa_ref_viewing_distance[32]; + uint8_t additional_shift_present_flag[32]; + uint16_t num_sample_shift_plus512[32]; + uint8_t three_dimensional_reference_displays_extension_flag; +} H265RawSEI3DReferenceDisplaysInfo; + typedef struct H265RawSEI { H265RawNALUnitHeader nal_unit_header; SEIRawMessageList message_list; } H265RawSEI; +typedef struct H265RawFiller { + H265RawNALUnitHeader nal_unit_header; + + uint32_t filler_size; +} H265RawFiller; + typedef struct CodedBitstreamH265Context { // Reader/writer context in common with the H.264 implementation. CodedBitstreamH2645Context common; diff --git a/libavcodec/cbs_h265_syntax_template.c b/libavcodec/cbs_h265_syntax_template.c index 86ca00a0c..e976c38b8 100644 --- a/libavcodec/cbs_h265_syntax_template.c +++ b/libavcodec/cbs_h265_syntax_template.c @@ -747,6 +747,16 @@ static int FUNC(sps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } +static int FUNC(sps_multilayer_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) +{ + int err; + + flag(inter_view_mv_vert_constraint_flag); + + return 0; +} + static int FUNC(vui_parameters_default)(CodedBitstreamContext *ctx, RWContext *rw, H265RawVUI *current, H265RawSPS *sps) @@ -781,6 +791,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, int err, i; unsigned int min_cb_log2_size_y, ctb_log2_size_y, min_cb_size_y, min_tb_log2_size_y; + unsigned int multi_layer_ext_sps_flag; HEADER("Sequence Parameter Set"); @@ -788,18 +799,25 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, ub(4, sps_video_parameter_set_id); h265->active_vps = vps = h265->vps[current->sps_video_parameter_set_id]; + if (!vps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "VPS id %d not available.\n", + current->sps_video_parameter_set_id); + return AVERROR_INVALIDDATA; + } + + if (current->nal_unit_header.nuh_layer_id == 0) + u(3, sps_max_sub_layers_minus1, 0, vps->vps_max_sub_layers_minus1); + else { + u(3, sps_ext_or_max_sub_layers_minus1, 0, HEVC_MAX_SUB_LAYERS); + infer(sps_max_sub_layers_minus1, current->sps_ext_or_max_sub_layers_minus1 == HEVC_MAX_SUB_LAYERS + ? vps->vps_max_sub_layers_minus1 + : current->sps_ext_or_max_sub_layers_minus1); + } + multi_layer_ext_sps_flag = current->nal_unit_header.nuh_layer_id && + current->sps_ext_or_max_sub_layers_minus1 == HEVC_MAX_SUB_LAYERS; + if (!multi_layer_ext_sps_flag) { + flag(sps_temporal_id_nesting_flag); - u(3, sps_max_sub_layers_minus1, 0, HEVC_MAX_SUB_LAYERS - 1); - flag(sps_temporal_id_nesting_flag); - if (vps) { - if (vps->vps_max_sub_layers_minus1 > current->sps_max_sub_layers_minus1) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " - "sps_max_sub_layers_minus1 (%d) must be less than or equal to " - "vps_max_sub_layers_minus1 (%d).\n", - vps->vps_max_sub_layers_minus1, - current->sps_max_sub_layers_minus1); - return AVERROR_INVALIDDATA; - } if (vps->vps_temporal_id_nesting_flag && !current->sps_temporal_id_nesting_flag) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " @@ -807,59 +825,79 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, "vps_temporal_id_nesting_flag is 1.\n"); return AVERROR_INVALIDDATA; } - } + if (current->sps_max_sub_layers_minus1 == 0 && + current->sps_temporal_id_nesting_flag != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "sps_temporal_id_nesting_flag must be 1 if " + "sps_max_sub_layers_minus1 is 0.\n"); + return AVERROR_INVALIDDATA; + } - CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level, - 1, current->sps_max_sub_layers_minus1)); + CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level, + 1, current->sps_max_sub_layers_minus1)); + } else { + if (current->sps_max_sub_layers_minus1 > 0) + infer(sps_temporal_id_nesting_flag, vps->vps_temporal_id_nesting_flag); + else + infer(sps_temporal_id_nesting_flag, 1); + } ue(sps_seq_parameter_set_id, 0, 15); - ue(chroma_format_idc, 0, 3); - if (current->chroma_format_idc == 3) - flag(separate_colour_plane_flag); - else - infer(separate_colour_plane_flag, 0); - - ue(pic_width_in_luma_samples, 1, HEVC_MAX_WIDTH); - ue(pic_height_in_luma_samples, 1, HEVC_MAX_HEIGHT); - - flag(conformance_window_flag); - if (current->conformance_window_flag) { - ue(conf_win_left_offset, 0, current->pic_width_in_luma_samples); - ue(conf_win_right_offset, 0, current->pic_width_in_luma_samples); - ue(conf_win_top_offset, 0, current->pic_height_in_luma_samples); - ue(conf_win_bottom_offset, 0, current->pic_height_in_luma_samples); + if (multi_layer_ext_sps_flag) { + flag(update_rep_format_flag); + if (current->update_rep_format_flag) + ub(8, sps_rep_format_idx); } else { - infer(conf_win_left_offset, 0); - infer(conf_win_right_offset, 0); - infer(conf_win_top_offset, 0); - infer(conf_win_bottom_offset, 0); - } + ue(chroma_format_idc, 0, 3); + if (current->chroma_format_idc == 3) + flag(separate_colour_plane_flag); + else + infer(separate_colour_plane_flag, 0); - ue(bit_depth_luma_minus8, 0, 8); - ue(bit_depth_chroma_minus8, 0, 8); + ue(pic_width_in_luma_samples, 1, HEVC_MAX_WIDTH); + ue(pic_height_in_luma_samples, 1, HEVC_MAX_HEIGHT); + + flag(conformance_window_flag); + if (current->conformance_window_flag) { + ue(conf_win_left_offset, 0, current->pic_width_in_luma_samples); + ue(conf_win_right_offset, 0, current->pic_width_in_luma_samples); + ue(conf_win_top_offset, 0, current->pic_height_in_luma_samples); + ue(conf_win_bottom_offset, 0, current->pic_height_in_luma_samples); + } else { + infer(conf_win_left_offset, 0); + infer(conf_win_right_offset, 0); + infer(conf_win_top_offset, 0); + infer(conf_win_bottom_offset, 0); + } + + ue(bit_depth_luma_minus8, 0, 8); + ue(bit_depth_chroma_minus8, 0, 8); + } ue(log2_max_pic_order_cnt_lsb_minus4, 0, 12); - flag(sps_sub_layer_ordering_info_present_flag); - for (i = (current->sps_sub_layer_ordering_info_present_flag ? - 0 : current->sps_max_sub_layers_minus1); - i <= current->sps_max_sub_layers_minus1; i++) { - ues(sps_max_dec_pic_buffering_minus1[i], - 0, HEVC_MAX_DPB_SIZE - 1, 1, i); - ues(sps_max_num_reorder_pics[i], - 0, current->sps_max_dec_pic_buffering_minus1[i], 1, i); - ues(sps_max_latency_increase_plus1[i], - 0, UINT32_MAX - 1, 1, i); - } - if (!current->sps_sub_layer_ordering_info_present_flag) { - for (i = 0; i < current->sps_max_sub_layers_minus1; i++) { - infer(sps_max_dec_pic_buffering_minus1[i], - current->sps_max_dec_pic_buffering_minus1[current->sps_max_sub_layers_minus1]); - infer(sps_max_num_reorder_pics[i], - current->sps_max_num_reorder_pics[current->sps_max_sub_layers_minus1]); - infer(sps_max_latency_increase_plus1[i], - current->sps_max_latency_increase_plus1[current->sps_max_sub_layers_minus1]); + if (!multi_layer_ext_sps_flag) { + flag(sps_sub_layer_ordering_info_present_flag); + for (i = (current->sps_sub_layer_ordering_info_present_flag ? + 0 : current->sps_max_sub_layers_minus1); + i <= current->sps_max_sub_layers_minus1; i++) { + ues(sps_max_dec_pic_buffering_minus1[i], + 0, HEVC_MAX_DPB_SIZE - 1, 1, i); + ues(sps_max_num_reorder_pics[i], + 0, current->sps_max_dec_pic_buffering_minus1[i], 1, i); + ues(sps_max_latency_increase_plus1[i], + 0, UINT32_MAX - 1, 1, i); + } + if (!current->sps_sub_layer_ordering_info_present_flag) { + for (i = 0; i < current->sps_max_sub_layers_minus1; i++) { + infer(sps_max_dec_pic_buffering_minus1[i], + current->sps_max_dec_pic_buffering_minus1[current->sps_max_sub_layers_minus1]); + infer(sps_max_num_reorder_pics[i], + current->sps_max_num_reorder_pics[current->sps_max_sub_layers_minus1]); + infer(sps_max_latency_increase_plus1[i], + current->sps_max_latency_increase_plus1[current->sps_max_sub_layers_minus1]); + } } } @@ -892,9 +930,17 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, flag(scaling_list_enabled_flag); if (current->scaling_list_enabled_flag) { - flag(sps_scaling_list_data_present_flag); - if (current->sps_scaling_list_data_present_flag) - CHECK(FUNC(scaling_list_data)(ctx, rw, ¤t->scaling_list)); + if (multi_layer_ext_sps_flag) + flag(sps_infer_scaling_list_flag); + else + infer(sps_infer_scaling_list_flag, 0); + if (current->sps_infer_scaling_list_flag) + ub(6, sps_scaling_list_ref_layer_id); + else { + flag(sps_scaling_list_data_present_flag); + if (current->sps_scaling_list_data_present_flag) + CHECK(FUNC(scaling_list_data)(ctx, rw, ¤t->scaling_list)); + } } else { infer(sps_scaling_list_data_present_flag, 0); } @@ -952,7 +998,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, if (current->sps_range_extension_flag) CHECK(FUNC(sps_range_extension)(ctx, rw, current)); if (current->sps_multilayer_extension_flag) - return AVERROR_PATCHWELCOME; + CHECK(FUNC(sps_multilayer_extension)(ctx, rw, current)); if (current->sps_3d_extension_flag) return AVERROR_PATCHWELCOME; if (current->sps_scc_extension_flag) @@ -993,6 +1039,167 @@ static int FUNC(pps_range_extension)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } +static int FUNC(colour_mapping_octants)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current, unsigned int inp_depth, + unsigned int idx_y, unsigned int idx_cb, + unsigned int idx_cr, unsigned int inp_length) +{ + int part_num_y, cm_res_bits; + int err; + + part_num_y = 1 << current->cm_y_part_num_log2; + + av_assert0(inp_depth <= 1); + if (inp_depth < current->cm_octant_depth) + flags(split_octant_flag[inp_depth], 1, inp_depth); + else + infer(split_octant_flag[inp_depth], 0); + + if (current->split_octant_flag[inp_depth]) + for (int k = 0; k < 2; k++) + for (int m = 0; m < 2; m++) + for (int n = 0; n < 2; n++) + CHECK(FUNC(colour_mapping_octants)(ctx, rw, current, inp_depth + 1, + idx_y + part_num_y * k * inp_length / 2, + idx_cb + m * inp_length / 2, + idx_cr + n * inp_length / 2, + inp_length / 2)); + else + for (int i = 0; i < part_num_y; i++) { + int idx_shift_y = idx_y + (i << (current->cm_octant_depth - inp_depth)); + for (int j = 0; j < 4; j++) { + flags(coded_res_flag[idx_shift_y][idx_cb][idx_cr][j], + 4, idx_shift_y, idx_cb, idx_cr, j); + if (current->coded_res_flag[idx_shift_y][idx_cb][idx_cr][j]) { + for (int c = 0; c < 3; c++) { + ues(res_coeff_q[idx_shift_y][idx_cb][idx_cr][j][c], 0, 3, + 5, idx_shift_y, idx_cb, idx_cr, j, c); + cm_res_bits = FFMAX(0, 10 + (current->luma_bit_depth_cm_input_minus8 + 8) - + (current->luma_bit_depth_cm_output_minus8 + 8) - + current->cm_res_quant_bits - (current->cm_delta_flc_bits_minus1 + 1)); + if (cm_res_bits) + ubs(cm_res_bits, res_coeff_r[idx_shift_y][idx_cb][idx_cr][j][c], + 5, idx_shift_y, idx_cb, idx_cr, j, c); + else + infer(res_coeff_r[idx_shift_y][idx_cb][idx_cr][j][c], 0); + if (current->res_coeff_q[idx_shift_y][idx_cb][idx_cr][j][c] || + current->res_coeff_r[idx_shift_y][idx_cb][idx_cr][j][c]) + ub(1, res_coeff_s[idx_shift_y][idx_cb][idx_cr][j][c]); + else + infer(res_coeff_s[idx_shift_y][idx_cb][idx_cr][j][c], 0); + } + } else { + for (int c = 0; c < 3; c++) { + infer(res_coeff_q[idx_shift_y][idx_cb][idx_cr][j][c], 0); + infer(res_coeff_r[idx_shift_y][idx_cb][idx_cr][j][c], 0); + infer(res_coeff_s[idx_shift_y][idx_cb][idx_cr][j][c], 0); + } + } + } + } + + return 0; +} + +static int FUNC(colour_mapping_table)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) +{ + int err; + + ue(num_cm_ref_layers_minus1, 0, 61); + for (int i = 0; i <= current->num_cm_ref_layers_minus1; i++) + ubs(6, cm_ref_layer_id[i], 1, i); + + u(2, cm_octant_depth, 0, 1); + u(2, cm_y_part_num_log2, 0, 3 - current->cm_octant_depth); + + ue(luma_bit_depth_cm_input_minus8, 0, 8); + ue(chroma_bit_depth_cm_input_minus8, 0, 8); + ue(luma_bit_depth_cm_output_minus8, 0, 8); + ue(chroma_bit_depth_cm_output_minus8, 0, 8); + + ub(2, cm_res_quant_bits); + ub(2, cm_delta_flc_bits_minus1); + + if (current->cm_octant_depth == 1) { + se(cm_adapt_threshold_u_delta, -32768, 32767); + se(cm_adapt_threshold_v_delta, -32768, 32767); + } else { + infer(cm_adapt_threshold_u_delta, 0); + infer(cm_adapt_threshold_v_delta, 0); + } + + CHECK(FUNC(colour_mapping_octants)(ctx, rw, current, 0, 0, 0, 0, 1 << current->cm_octant_depth)); + + return 0; +} + +static int FUNC(pps_multilayer_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawVPS *vps = h265->active_vps; + int offset; + int err, i; + + flag(poc_reset_info_present_flag); + flag(pps_infer_scaling_list_flag); + if (current->pps_infer_scaling_list_flag) + ub(6, pps_scaling_list_ref_layer_id); + + if (!vps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "VPS missing for PPS Multilayer Extension.\n"); + return AVERROR_INVALIDDATA; + } + + ue(num_ref_loc_offsets, 0, vps->vps_max_layers_minus1); + for (i = 0; i < current->num_ref_loc_offsets; i++) { + ubs(6, ref_loc_offset_layer_id[i], 1, i); + offset = current->ref_loc_offset_layer_id[i]; + flags(scaled_ref_layer_offset_present_flag[i], 1, i); + if (current->scaled_ref_layer_offset_present_flag[i]) { + ses(scaled_ref_layer_left_offset[offset], -16384, 16383, 1, offset); + ses(scaled_ref_layer_top_offset[offset], -16384, 16383, 1, offset); + ses(scaled_ref_layer_right_offset[offset], -16384, 16383, 1, offset); + ses(scaled_ref_layer_bottom_offset[offset], -16384, 16383, 1, offset); + } else { + infer(scaled_ref_layer_left_offset[offset], 0); + infer(scaled_ref_layer_top_offset[offset], 0); + infer(scaled_ref_layer_right_offset[offset], 0); + infer(scaled_ref_layer_bottom_offset[offset], 0); + } + flags(ref_region_offset_present_flag[i], 1, i); + if (current->ref_region_offset_present_flag[i]) { + ses(ref_region_left_offset[offset], -16384, 16383, 1, offset); + ses(ref_region_top_offset[offset], -16384, 16383, 1, offset); + ses(ref_region_right_offset[offset], -16384, 16383, 1, offset); + ses(ref_region_bottom_offset[offset], -16384, 16383, 1, offset); + } else { + infer(ref_region_left_offset[offset], 0); + infer(ref_region_top_offset[offset], 0); + infer(ref_region_right_offset[offset], 0); + infer(ref_region_bottom_offset[offset], 0); + } + flags(resample_phase_set_present_flag[i], 1, i); + if (current->resample_phase_set_present_flag[i]) { + ues(phase_hor_luma[offset], 0, 31, 1, offset); + ues(phase_ver_luma[offset], 0, 31, 1, offset); + ues(phase_hor_chroma_plus8[offset], 0, 63, 1, offset); + ues(phase_ver_chroma_plus8[offset], 0, 63, 1, offset); + } else { + infer(phase_hor_luma[offset], 0); + infer(phase_ver_luma[offset], 0); + infer(phase_hor_chroma_plus8[offset], 8); + } + } + + flag(colour_mapping_enabled_flag); + if (current->colour_mapping_enabled_flag) + CHECK(FUNC(colour_mapping_table)(ctx, rw, current)); + + return 0; +} + static int FUNC(pps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, H265RawPPS *current) { @@ -1143,7 +1350,7 @@ static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, if (current->pps_range_extension_flag) CHECK(FUNC(pps_range_extension)(ctx, rw, current)); if (current->pps_multilayer_extension_flag) - return AVERROR_PATCHWELCOME; + CHECK(FUNC(pps_multilayer_extension)(ctx, rw, current)); if (current->pps_3d_extension_flag) return AVERROR_PATCHWELCOME; if (current->pps_scc_extension_flag) @@ -2077,6 +2284,66 @@ SEI_FUNC(sei_alpha_channel_info, (CodedBitstreamContext *ctx, RWContext *rw, return 0; } +SEI_FUNC(sei_3d_reference_displays_info, (CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEI3DReferenceDisplaysInfo *current, + SEIMessageState *sei)) +{ + int length; + int err, i; + + HEADER("Three Dimensional Reference Displays Information"); + + ue(prec_ref_display_width, 0, 31); + flag(ref_viewing_distance_flag); + if (current->ref_viewing_distance_flag) + ue(prec_ref_viewing_dist, 0, 31); + ue(num_ref_displays_minus1, 0, 31); + for (i = 0; i <= current->num_ref_displays_minus1; i++) { + ues(left_view_id[i], 0, MAX_UINT_BITS(15), 1, i); + ues(right_view_id[i], 0, MAX_UINT_BITS(15), 1, i); + us(6, exponent_ref_display_width[i], 0, 62, 1, i); + if (!current->exponent_ref_display_width[i]) + length = FFMAX(0, (int)current->prec_ref_display_width - 30); + else + length = FFMAX(0, (int)current->exponent_ref_display_width[i] + + (int)current->prec_ref_display_width - 31); + + if (length > 32) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "refDispWidthBits > 32 is not supported\n"); + return AVERROR_PATCHWELCOME; + } + + if (length) + ubs(length, mantissa_ref_display_width[i], 1, i); + else + infer(mantissa_ref_display_width[i], 0); + if (current->ref_viewing_distance_flag) { + us(6, exponent_ref_viewing_distance[i], 0, 62, 1, i); + if (!current->exponent_ref_viewing_distance[i]) + length = FFMAX(0, (int)current->prec_ref_viewing_dist - 30); + else + length = FFMAX(0, (int)current->exponent_ref_viewing_distance[i] + + (int)current->prec_ref_viewing_dist - 31); + + if (length > 32) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "refViewDistBits > 32 is not supported\n"); + return AVERROR_PATCHWELCOME; + } + + if (length) + ubs(length, mantissa_ref_viewing_distance[i], 1, i); + else + infer(mantissa_ref_viewing_distance[i], 0); + } + flags(additional_shift_present_flag[i], 1, i); + if (current->additional_shift_present_flag[i]) + us(10, num_sample_shift_plus512[i], 0, 1023, 1, i); + } + flag(three_dimensional_reference_displays_extension_flag); + + return 0; +} + static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, H265RawSEI *current, int prefix) { @@ -2097,3 +2364,32 @@ static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } + + +static int FUNC(filler)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawFiller *current) +{ + int err; + + HEADER("Filler Data"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + HEVC_NAL_FD_NUT)); + +#ifdef READ + 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 + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} diff --git a/libavcodec/cbs_h266.h b/libavcodec/cbs_h266.h index 73d94157d..d24a8e931 100644 --- a/libavcodec/cbs_h266.h +++ b/libavcodec/cbs_h266.h @@ -464,9 +464,9 @@ typedef struct H266RawSPS { uint8_t sps_virtual_boundaries_enabled_flag; uint8_t sps_virtual_boundaries_present_flag; uint8_t sps_num_ver_virtual_boundaries; - uint16_t sps_virtual_boundary_pos_x_minus1[3]; + uint16_t sps_virtual_boundary_pos_x_minus1[VVC_MAX_VBS]; uint8_t sps_num_hor_virtual_boundaries; - uint16_t sps_virtual_boundary_pos_y_minus1[3]; + uint16_t sps_virtual_boundary_pos_y_minus1[VVC_MAX_VBS]; uint8_t sps_timing_hrd_params_present_flag; uint8_t sps_sublayer_cpb_params_present_flag; @@ -588,11 +588,11 @@ typedef struct H266RawPPS { uint16_t num_tile_columns; uint16_t num_tile_rows; uint16_t num_tiles_in_pic; - uint16_t slice_height_in_ctus[VVC_MAX_SLICES]; - uint16_t num_slices_in_subpic[VVC_MAX_SLICES]; - uint16_t sub_pic_id_val[VVC_MAX_SLICES]; - uint16_t col_width_val[VVC_MAX_TILE_COLUMNS]; - uint16_t row_height_val[VVC_MAX_TILE_ROWS]; + uint16_t slice_height_in_ctus[VVC_MAX_SLICES]; ///< sliceHeightInCtus + uint16_t num_slices_in_subpic[VVC_MAX_SLICES]; ///< NumSlicesInSubpic + 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 } H266RawPPS; typedef struct H266RawAPS { @@ -703,9 +703,9 @@ typedef struct H266RawPictureHeader { uint8_t ph_virtual_boundaries_present_flag; uint8_t ph_num_ver_virtual_boundaries; - uint16_t ph_virtual_boundary_pos_x_minus1[3]; + uint16_t ph_virtual_boundary_pos_x_minus1[VVC_MAX_VBS]; uint8_t ph_num_hor_virtual_boundaries; - uint16_t ph_virtual_boundary_pos_y_minus1[3]; + uint16_t ph_virtual_boundary_pos_y_minus1[VVC_MAX_VBS]; uint8_t ph_pic_output_flag; H266RefPicLists ph_ref_pic_lists; @@ -848,16 +848,6 @@ typedef struct H266RawSlice { int data_bit_start; } H266RawSlice; -typedef struct H266RawSEIDecodedPictureHash { - uint8_t dph_sei_hash_type; - uint8_t dph_sei_single_component_flag; - uint8_t dph_sei_picture_md5[3][16]; - uint16_t dph_sei_picture_crc[3]; - uint32_t dph_sei_picture_checksum[3]; - - uint8_t dph_sei_reserved_zero_7bits; -} H266RawSEIDecodedPictureHash; - typedef struct H266RawSEI { H266RawNALUnitHeader nal_unit_header; SEIRawMessageList message_list; diff --git a/libavcodec/cbs_h266_syntax_template.c b/libavcodec/cbs_h266_syntax_template.c index 281069f06..d33629b06 100644 --- a/libavcodec/cbs_h266_syntax_template.c +++ b/libavcodec/cbs_h266_syntax_template.c @@ -1061,7 +1061,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, 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; - uint8_t qp_bd_offset; + uint8_t qp_bd_offset, sub_width_c, sub_height_c; static const uint8_t h266_sub_width_c[] = { 1, 2, 2, 1 @@ -1089,6 +1089,9 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, u(3, sps_max_sublayers_minus1, 0, VVC_MAX_SUBLAYERS - 1); u(2, sps_chroma_format_idc, 0, 3); + sub_width_c = h266_sub_width_c[current->sps_chroma_format_idc]; + sub_height_c = h266_sub_height_c[current->sps_chroma_format_idc]; + u(2, sps_log2_ctu_size_minus5, 0, 3); ctb_log2_size_y = current->sps_log2_ctu_size_minus5 + 5; ctb_size_y = 1 << ctb_log2_size_y; @@ -1110,8 +1113,6 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, flag(sps_conformance_window_flag); if (current->sps_conformance_window_flag) { - uint8_t sub_width_c = h266_sub_width_c[current->sps_chroma_format_idc]; - uint8_t sub_height_c = h266_sub_height_c[current->sps_chroma_format_idc]; uint16_t width = current->sps_pic_width_max_in_luma_samples / sub_width_c; uint16_t height = current->sps_pic_height_max_in_luma_samples / sub_height_c; ue(sps_conf_win_left_offset, 0, width); @@ -1160,19 +1161,37 @@ 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) - ubs(wlen, sps_subpic_ctu_top_left_x[i], 1, i); - else + 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 infer(sps_subpic_ctu_top_left_x[i], 0); if (current->sps_pic_height_max_in_luma_samples > - ctb_size_y) - ubs(hlen, sps_subpic_ctu_top_left_y[i], 1, i); - else + 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 infer(sps_subpic_ctu_top_left_y[i], 0); if (i < current->sps_num_subpics_minus1 && current->sps_pic_width_max_in_luma_samples > ctb_size_y) { - ubs(wlen, sps_subpic_width_minus1[i], 1, i); + 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); } else { infer(sps_subpic_width_minus1[i], tmp_width_val - @@ -1181,7 +1200,15 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, if (i < current->sps_num_subpics_minus1 && current->sps_pic_height_max_in_luma_samples > ctb_size_y) { - ubs(hlen, sps_subpic_height_minus1[i], 1, i); + 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); } else { infer(sps_subpic_height_minus1[i], tmp_height_val - @@ -1562,13 +1589,13 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, flag(sps_virtual_boundaries_present_flag); if (current->sps_virtual_boundaries_present_flag) { ue(sps_num_ver_virtual_boundaries, - 0, current->sps_pic_width_max_in_luma_samples <= 8 ? 0 : 3); + 0, current->sps_pic_width_max_in_luma_samples <= 8 ? 0 : VVC_MAX_VBS); for (i = 0; i < current->sps_num_ver_virtual_boundaries; i++) ues(sps_virtual_boundary_pos_x_minus1[i], 0, (current->sps_pic_width_max_in_luma_samples + 7) / 8 - 2, 1, i); ue(sps_num_hor_virtual_boundaries, - 0, current->sps_pic_height_max_in_luma_samples <= 8 ? 0 : 3); + 0, current->sps_pic_height_max_in_luma_samples <= 8 ? 0 : VVC_MAX_VBS); for (i = 0; i < current->sps_num_hor_virtual_boundaries; i++) ues(sps_virtual_boundary_pos_y_minus1[i], 0, (current->sps_pic_height_max_in_luma_samples + 7) / @@ -1618,6 +1645,8 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, ub(7, sps_extension_7bits); if (current->sps_range_extension_flag) { + if (current->sps_bitdepth_minus8 <= 10 - 8) + return AVERROR_INVALIDDATA; CHECK(FUNC(sps_range_extension)(ctx, rw, current)); } else { infer(sps_extended_precision_flag, 0); @@ -2122,9 +2151,12 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, } else { if (current->pps_no_pic_partition_flag) infer(pps_num_slices_in_pic_minus1, 0); - else if (current->pps_single_slice_per_subpic_flag) + else if (current->pps_single_slice_per_subpic_flag) { + for (i = 0; i <= sps->sps_num_subpics_minus1; i++) + current->num_slices_in_subpic[i] = 1; infer(pps_num_slices_in_pic_minus1, sps->sps_num_subpics_minus1); + } // else? } if (!current->pps_rect_slice_flag || @@ -2711,13 +2743,13 @@ static int FUNC(picture_header) (CodedBitstreamContext *ctx, RWContext *rw, flag(ph_virtual_boundaries_present_flag); if (current->ph_virtual_boundaries_present_flag) { ue(ph_num_ver_virtual_boundaries, - 0, pps->pps_pic_width_in_luma_samples <= 8 ? 0 : 3); + 0, pps->pps_pic_width_in_luma_samples <= 8 ? 0 : VVC_MAX_VBS); for (i = 0; i < current->ph_num_ver_virtual_boundaries; i++) { ues(ph_virtual_boundary_pos_x_minus1[i], 0, (pps->pps_pic_width_in_luma_samples + 7) / 8 - 2, 1, i); } ue(ph_num_hor_virtual_boundaries, - 0, pps->pps_pic_height_in_luma_samples <= 8 ? 0 : 3); + 0, pps->pps_pic_height_in_luma_samples <= 8 ? 0 : VVC_MAX_VBS); for (i = 0; i < current->ph_num_hor_virtual_boundaries; i++) { ues(ph_virtual_boundary_pos_y_minus1[i], 0, (pps->pps_pic_height_in_luma_samples + 7) / 8 - 2, 1, i); @@ -3423,7 +3455,7 @@ static int FUNC(slice_header) (CodedBitstreamContext *ctx, RWContext *rw, current->num_entry_points--; if (current->num_entry_points > VVC_MAX_ENTRY_POINTS) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many entry points: " - "%" PRIu16 ".\n", current->num_entry_points); + "%" PRIu32 ".\n", current->num_entry_points); return AVERROR_PATCHWELCOME; } if (current->num_entry_points > 0) { @@ -3439,34 +3471,6 @@ static int FUNC(slice_header) (CodedBitstreamContext *ctx, RWContext *rw, return 0; } -SEI_FUNC(sei_decoded_picture_hash, (CodedBitstreamContext *ctx, - RWContext *rw, - H266RawSEIDecodedPictureHash *current, - SEIMessageState *unused)) -{ - int err, c_idx, i; - - HEADER("Decoded Picture Hash"); - - u(8, dph_sei_hash_type, 0, 2); - flag(dph_sei_single_component_flag); - ub(7, dph_sei_reserved_zero_7bits); - - for (c_idx = 0; c_idx < (current->dph_sei_single_component_flag ? 1 : 3); - c_idx++) { - if (current->dph_sei_hash_type == 0) { - for (i = 0; i < 16; i++) - us(8, dph_sei_picture_md5[c_idx][i], 0x00, 0xff, 2, c_idx, i); - } else if (current->dph_sei_hash_type == 1) { - us(16, dph_sei_picture_crc[c_idx], 0x0000, 0xffff, 1, c_idx); - } else if (current->dph_sei_hash_type == 2) { - us(32, dph_sei_picture_checksum[c_idx], 0x00000000, 0xffffffff, 1, - c_idx); - } - } - return 0; -} - static int FUNC(sei) (CodedBitstreamContext *ctx, RWContext *rw, H266RawSEI *current, int prefix) { diff --git a/libavcodec/cbs_jpeg.c b/libavcodec/cbs_jpeg.c index f2aa49661..406147c08 100644 --- a/libavcodec/cbs_jpeg.c +++ b/libavcodec/cbs_jpeg.c @@ -16,6 +16,7 @@ * 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_jpeg.h" diff --git a/libavcodec/cbs_sei.c b/libavcodec/cbs_sei.c index e28c2f909..458751d92 100644 --- a/libavcodec/cbs_sei.c +++ b/libavcodec/cbs_sei.c @@ -16,6 +16,7 @@ * 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_h264.h" @@ -40,7 +41,6 @@ int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, const SEIMessageTypeDescriptor *desc) { void (*free_func)(FFRefStructOpaque, void*); - unsigned flags = 0; av_assert0(message->payload == NULL && message->payload_ref == NULL); @@ -52,10 +52,9 @@ int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, free_func = &cbs_free_user_data_unregistered; else { free_func = NULL; - flags = FF_REFSTRUCT_FLAG_NO_ZEROING; } - message->payload_ref = ff_refstruct_alloc_ext(desc->size, flags, + message->payload_ref = ff_refstruct_alloc_ext(desc->size, 0, NULL, free_func); if (!message->payload_ref) return AVERROR(ENOMEM); diff --git a/libavcodec/cbs_sei.h b/libavcodec/cbs_sei.h index ec7cdb62f..15ef3415a 100644 --- a/libavcodec/cbs_sei.h +++ b/libavcodec/cbs_sei.h @@ -43,6 +43,36 @@ typedef struct SEIRawUserDataUnregistered { size_t data_length; } SEIRawUserDataUnregistered; +typedef struct SEIRawFramePackingArrangement { + uint32_t fp_arrangement_id; + uint8_t fp_arrangement_cancel_flag; + uint8_t fp_arrangement_type; + uint8_t fp_quincunx_sampling_flag; + uint8_t fp_content_interpretation_type; + uint8_t fp_spatial_flipping_flag; + uint8_t fp_frame0_flipped_flag; + uint8_t fp_field_views_flag; + uint8_t fp_current_frame_is_frame0_flag; + uint8_t fp_frame0_self_contained_flag; + uint8_t fp_frame1_self_contained_flag; + uint8_t fp_frame0_grid_position_x; + uint8_t fp_frame0_grid_position_y; + uint8_t fp_frame1_grid_position_x; + uint8_t fp_frame1_grid_position_y; + uint8_t fp_arrangement_persistence_flag; + uint8_t fp_upsampled_aspect_ratio_flag; +} SEIRawFramePackingArrangement; + +typedef struct SEIRawDecodedPictureHash { + uint8_t dph_sei_hash_type; + uint8_t dph_sei_single_component_flag; + uint8_t dph_sei_picture_md5[3][16]; + uint16_t dph_sei_picture_crc[3]; + uint32_t dph_sei_picture_checksum[3]; + + uint8_t dph_sei_reserved_zero_7bits; +} SEIRawDecodedPictureHash; + typedef struct SEIRawMasteringDisplayColourVolume { uint16_t display_primaries_x[3]; uint16_t display_primaries_y[3]; diff --git a/libavcodec/cbs_sei_syntax_template.c b/libavcodec/cbs_sei_syntax_template.c index 81448ef3f..0205bb47a 100644 --- a/libavcodec/cbs_sei_syntax_template.c +++ b/libavcodec/cbs_sei_syntax_template.c @@ -94,6 +94,68 @@ SEI_FUNC(user_data_unregistered, (CodedBitstreamContext *ctx, RWContext *rw, return 0; } +SEI_FUNC(frame_packing_arrangement, (CodedBitstreamContext *ctx, RWContext *rw, + SEIRawFramePackingArrangement *current, + SEIMessageState *unused)) +{ + int err; + + HEADER("Frame Packing Arrangement"); + + ue(fp_arrangement_id, 0, MAX_UINT_BITS(31)); + flag(fp_arrangement_cancel_flag); + if (!current->fp_arrangement_cancel_flag) { + u(7, fp_arrangement_type, 3, 5); + flag(fp_quincunx_sampling_flag); + u(6, fp_content_interpretation_type, 0, 2); + flag(fp_spatial_flipping_flag); + flag(fp_frame0_flipped_flag); + flag(fp_field_views_flag); + flag(fp_current_frame_is_frame0_flag); + flag(fp_frame0_self_contained_flag); + flag(fp_frame1_self_contained_flag); + if (!current->fp_quincunx_sampling_flag && current->fp_arrangement_type != 5) { + ub(4, fp_frame0_grid_position_x); + ub(4, fp_frame0_grid_position_y); + ub(4, fp_frame1_grid_position_x); + ub(4, fp_frame1_grid_position_y); + } + fixed(8, fp_arrangement_reserved_byte, 0); + flag(fp_arrangement_persistence_flag); + } + flag(fp_upsampled_aspect_ratio_flag); + + return 0; +} + +SEI_FUNC(decoded_picture_hash, (CodedBitstreamContext *ctx, + RWContext *rw, + SEIRawDecodedPictureHash *current, + SEIMessageState *unused)) +{ + int err, c_idx, i; + + HEADER("Decoded Picture Hash"); + + u(8, dph_sei_hash_type, 0, 2); + flag(dph_sei_single_component_flag); + ub(7, dph_sei_reserved_zero_7bits); + + for (c_idx = 0; c_idx < (current->dph_sei_single_component_flag ? 1 : 3); + c_idx++) { + if (current->dph_sei_hash_type == 0) { + for (i = 0; i < 16; i++) + us(8, dph_sei_picture_md5[c_idx][i], 0x00, 0xff, 2, c_idx, i); + } else if (current->dph_sei_hash_type == 1) { + us(16, dph_sei_picture_crc[c_idx], 0x0000, 0xffff, 1, c_idx); + } else if (current->dph_sei_hash_type == 2) { + us(32, dph_sei_picture_checksum[c_idx], 0x00000000, 0xffffffff, 1, + c_idx); + } + } + return 0; +} + SEI_FUNC(mastering_display_colour_volume, (CodedBitstreamContext *ctx, RWContext *rw, SEIRawMasteringDisplayColourVolume *current, diff --git a/libavcodec/cbs_vp9.c b/libavcodec/cbs_vp9.c index 816d06da0..ff99fe32f 100644 --- a/libavcodec/cbs_vp9.c +++ b/libavcodec/cbs_vp9.c @@ -375,7 +375,7 @@ static int cbs_vp9_split_fragment(CodedBitstreamContext *ctx, superframe_header = frag->data[frag->data_size - 1]; if ((superframe_header & 0xe0) == 0xc0) { - VP9RawSuperframeIndex sfi; + VP9RawSuperframeIndex sfi = {0}; GetBitContext gbc; size_t index_size, pos; int i; diff --git a/libavcodec/cdtoons.c b/libavcodec/cdtoons.c index 94c49f0c8..89b6d76d8 100644 --- a/libavcodec/cdtoons.c +++ b/libavcodec/cdtoons.c @@ -29,6 +29,7 @@ #include "libavutil/attributes.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/cdxl.c b/libavcodec/cdxl.c index 6843fceb2..c30e85b2e 100644 --- a/libavcodec/cdxl.c +++ b/libavcodec/cdxl.c @@ -28,6 +28,7 @@ #define UNCHECKED_BITSTREAM_READER 1 #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" @@ -305,8 +306,6 @@ static int cdxl_decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; if (encoding) { av_fast_padded_malloc(&c->new_video, &c->new_video_size, diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c index 42d7dcc3f..6f1d96005 100644 --- a/libavcodec/cfhd.c +++ b/libavcodec/cfhd.c @@ -24,9 +24,9 @@ */ #include "libavutil/attributes.h" -#include "libavutil/buffer.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "avcodec.h" diff --git a/libavcodec/cfhdenc.c b/libavcodec/cfhdenc.c index 1412d35d3..ceea15efc 100644 --- a/libavcodec/cfhdenc.c +++ b/libavcodec/cfhdenc.c @@ -23,11 +23,11 @@ * Cineform HD video encoder */ -#include -#include +#include -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "avcodec.h" #include "bytestream.h" @@ -36,7 +36,6 @@ #include "codec_internal.h" #include "encode.h" #include "put_bits.h" -#include "thread.h" /* Derived from existing tables from decoder */ static const unsigned codebook[256][2] = { @@ -286,7 +285,7 @@ static av_cold int cfhd_encode_init(AVCodecContext *avctx) s->plane[i].dwt_buf = av_calloc(h8 * 8 * w8 * 8, sizeof(*s->plane[i].dwt_buf)); s->plane[i].dwt_tmp = - av_malloc_array(h8 * 8 * w8 * 8, sizeof(*s->plane[i].dwt_tmp)); + av_calloc(h8 * 8 * w8 * 8, sizeof(*s->plane[i].dwt_tmp)); if (!s->plane[i].dwt_buf || !s->plane[i].dwt_tmp) return AVERROR(ENOMEM); @@ -871,5 +870,6 @@ const FFCodec ff_cfhd_encoder = { AV_PIX_FMT_GBRAP12, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cinepakenc.c b/libavcodec/cinepakenc.c index f15325ad0..f6145131a 100644 --- a/libavcodec/cinepakenc.c +++ b/libavcodec/cinepakenc.c @@ -37,10 +37,9 @@ #include #include "libavutil/avassert.h" -#include "libavutil/common.h" -#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" diff --git a/libavcodec/clearvideo.c b/libavcodec/clearvideo.c index 0b59d44cd..bb1e818c9 100644 --- a/libavcodec/clearvideo.c +++ b/libavcodec/clearvideo.c @@ -24,6 +24,7 @@ * ClearVideo decoder */ +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" diff --git a/libavcodec/cljrdec.c b/libavcodec/cljrdec.c index a4baa015f..66e9d56e0 100644 --- a/libavcodec/cljrdec.c +++ b/libavcodec/cljrdec.c @@ -50,8 +50,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; init_get_bits(&gb, buf, buf_size * 8); diff --git a/libavcodec/cljrenc.c b/libavcodec/cljrenc.c index 31ad5ce0c..4698dfd72 100644 --- a/libavcodec/cljrenc.c +++ b/libavcodec/cljrenc.c @@ -118,5 +118,6 @@ const FFCodec ff_cljr_encoder = { FF_CODEC_ENCODE_CB(encode_frame), .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &cljr_class, }; diff --git a/libavcodec/cllc.c b/libavcodec/cllc.c index 0c6ae13d0..168b8cb3d 100644 --- a/libavcodec/cllc.c +++ b/libavcodec/cllc.c @@ -23,6 +23,7 @@ #include #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "bswapdsp.h" #include "canopus.h" #include "get_bits.h" @@ -460,9 +461,6 @@ static int cllc_decode_frame(AVCodecContext *avctx, AVFrame *pic, return AVERROR_INVALIDDATA; } - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - *got_picture_ptr = 1; return avpkt->size; diff --git a/libavcodec/cngdec.c b/libavcodec/cngdec.c index 5cf5dc9bc..bacbd54fa 100644 --- a/libavcodec/cngdec.c +++ b/libavcodec/cngdec.c @@ -23,7 +23,7 @@ #include "libavutil/common.h" #include "libavutil/ffmath.h" -#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "celp_filters.h" #include "codec_internal.h" diff --git a/libavcodec/cngenc.c b/libavcodec/cngenc.c index 15a410ea5..c43013680 100644 --- a/libavcodec/cngenc.c +++ b/libavcodec/cngenc.c @@ -23,6 +23,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" diff --git a/libavcodec/codec.h b/libavcodec/codec.h index 6f9b42760..f7541ffc4 100644 --- a/libavcodec/codec.h +++ b/libavcodec/codec.h @@ -205,10 +205,19 @@ typedef struct AVCodec { */ int capabilities; uint8_t max_lowres; ///< maximum value for lowres supported by the decoder - const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} - const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1 - const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0 - const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1 + + /** + * Deprecated codec capabilities. + */ + attribute_deprecated + const AVRational *supported_framerates; ///< @deprecated use avcodec_get_supported_config() + attribute_deprecated + const enum AVPixelFormat *pix_fmts; ///< @deprecated use avcodec_get_supported_config() + attribute_deprecated + const int *supported_samplerates; ///< @deprecated use avcodec_get_supported_config() + attribute_deprecated + const enum AVSampleFormat *sample_fmts; ///< @deprecated use avcodec_get_supported_config() + const AVClass *priv_class; ///< AVClass for the private context const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {AV_PROFILE_UNKNOWN} @@ -226,7 +235,9 @@ typedef struct AVCodec { /** * Array of supported channel layouts, terminated with a zeroed layout. + * @deprecated use avcodec_get_supported_config() */ + attribute_deprecated const AVChannelLayout *ch_layouts; } AVCodec; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 3bab86db6..d58c3d889 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_LOSSY, + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, { .id = AV_CODEC_ID_TQI, @@ -1095,7 +1095,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_VIDEO, .name = "jv", .long_name = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV video"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_LOSSY, }, { .id = AV_CODEC_ID_DFA, @@ -1503,6 +1503,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_VIDEO, .name = "avrn", .long_name = NULL_IF_CONFIG_SMALL("Avid AVI Codec"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { .id = AV_CODEC_ID_CPIA, @@ -1820,7 +1821,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_VIDEO, .name = "photocd", .long_name = NULL_IF_CONFIG_SMALL("Kodak Photo CD"), - .props = AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, { .id = AV_CODEC_ID_IPU, @@ -1869,7 +1870,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_VIDEO, .name = "vbn", .long_name = NULL_IF_CONFIG_SMALL("Vizrt Binary Image"), - .props = AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, { .id = AV_CODEC_ID_JPEGXL, @@ -2696,7 +2697,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_AUDIO, .name = "aac", .long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_LOSSY, .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }, { @@ -3030,7 +3031,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_AUDIO, .name = "aac_latm", .long_name = NULL_IF_CONFIG_SMALL("AAC LATM (Advanced Audio Coding LATM syntax)"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_LOSSY, .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }, { @@ -3425,6 +3426,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("QOA (Quite OK Audio)"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_LC3, + .type = AVMEDIA_TYPE_AUDIO, + .name = "lc3", + .long_name = NULL_IF_CONFIG_SMALL("LC3 (Low Complexity Communication Codec)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* subtitle codecs */ { @@ -3688,6 +3696,12 @@ static const AVCodecDescriptor codec_descriptors[] = { .name = "smpte_2038", .long_name = NULL_IF_CONFIG_SMALL("SMPTE ST 2038 VANC in MPEG-2 TS"), }, + { + .id = AV_CODEC_ID_LCEVC, + .type = AVMEDIA_TYPE_DATA, + .name = "lcevc", + .long_name = NULL_IF_CONFIG_SMALL("LCEVC (Low Complexity Enhancement Video Coding) / MPEG-5 LCEVC / MPEG-5 part 2"), + }, { .id = AV_CODEC_ID_MPEG2TS, .type = AVMEDIA_TYPE_DATA, diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index c8dc21da7..0a8d3bed1 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -543,6 +543,7 @@ enum AVCodecID { AV_CODEC_ID_AC4, AV_CODEC_ID_OSQ, AV_CODEC_ID_QOA, + AV_CODEC_ID_LC3, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. @@ -588,6 +589,7 @@ enum AVCodecID { AV_CODEC_ID_TIMED_ID3, AV_CODEC_ID_BIN_DATA, AV_CODEC_ID_SMPTE_2038, + AV_CODEC_ID_LCEVC, 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 d6757e2de..5b2db7459 100644 --- a/libavcodec/codec_internal.h +++ b/libavcodec/codec_internal.h @@ -22,6 +22,7 @@ #include #include "libavutil/attributes.h" +#include "avcodec.h" #include "codec.h" #include "config.h" @@ -62,11 +63,10 @@ * Codec initializes slice-based threading with a main function */ #define FF_CODEC_CAP_SLICE_THREAD_HAS_MF (1 << 5) -/* - * The codec supports frame threading and has inter-frame dependencies, so it - * uses ff_thread_report/await_progress(). +/** + * The decoder might make use of the ProgressFrame API. */ -#define FF_CODEC_CAP_ALLOCATE_PROGRESS (1 << 6) +#define FF_CODEC_CAP_USES_PROGRESSFRAMES (1 << 6) /** * Codec handles avctx->thread_count == 0 (auto) internally. */ @@ -133,7 +133,13 @@ typedef struct FFCodec { /** * Internal codec capabilities FF_CODEC_CAP_*. */ - unsigned caps_internal:29; + unsigned caps_internal:27; + + /** + * This field determines the video color ranges supported by an encoder. + * Should be set to a bitmask of AVCOL_RANGE_MPEG and AVCOL_RANGE_JPEG. + */ + unsigned color_ranges:2; /** * This field determines the type of the codec (decoder/encoder) @@ -167,14 +173,6 @@ typedef struct FFCodec { */ const FFCodecDefault *defaults; - /** - * Initialize codec static data, called from av_codec_iterate(). - * - * This is not intended for time consuming operations as it is - * run for every codec regardless of that codec being used. - */ - void (*init_static_data)(struct FFCodec *codec); - int (*init)(struct AVCodecContext *); union { @@ -264,8 +262,34 @@ typedef struct FFCodec { * List of supported codec_tags, terminated by FF_CODEC_TAGS_END. */ const uint32_t *codec_tags; + + /** + * Custom callback for avcodec_get_supported_config(). If absent, + * 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, + const AVCodec *codec, + enum AVCodecConfig config, + unsigned flags, + const void **out_configs, + int *out_num_configs); } FFCodec; +/** + * Default implementation for avcodec_get_supported_config(). Will return the + * relevant fields from AVCodec if present, or NULL otherwise. + * + * 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, + const AVCodec *codec, + enum AVCodecConfig config, + unsigned flags, + const void **out_configs, + int *out_num_configs); + #if CONFIG_SMALL #define CODEC_LONG_NAME(str) .p.long_name = NULL #else diff --git a/libavcodec/container_fifo.c b/libavcodec/container_fifo.c new file mode 100644 index 000000000..82e86d946 --- /dev/null +++ b/libavcodec/container_fifo.c @@ -0,0 +1,195 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 new file mode 100644 index 000000000..dd8b1d380 --- /dev/null +++ b/libavcodec/container_fifo.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_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 705213de4..dbe6b5b96 100644 --- a/libavcodec/cook.c +++ b/libavcodec/cook.c @@ -44,6 +44,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" #include "libavutil/tx.h" diff --git a/libavcodec/cri.c b/libavcodec/cri.c index 7297c0350..6932bb674 100644 --- a/libavcodec/cri.c +++ b/libavcodec/cri.c @@ -410,9 +410,6 @@ skip: } } - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; - *got_frame = 1; return 0; diff --git a/libavcodec/cscd.c b/libavcodec/cscd.c index 685cf18ce..e552b0a14 100644 --- a/libavcodec/cscd.c +++ b/libavcodec/cscd.c @@ -22,7 +22,7 @@ #include "avcodec.h" #include "codec_internal.h" #include "decode.h" -#include "libavutil/common.h" +#include "libavutil/mem.h" #if CONFIG_ZLIB #include diff --git a/libavcodec/cuviddec.c b/libavcodec/cuviddec.c index acc405f78..3fae9c12e 100644 --- a/libavcodec/cuviddec.c +++ b/libavcodec/cuviddec.c @@ -30,6 +30,7 @@ #include "libavutil/cuda_check.h" #include "libavutil/fifo.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -833,22 +834,39 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) int ret = 0; enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_CUDA, - AV_PIX_FMT_NV12, + AV_PIX_FMT_NONE, AV_PIX_FMT_NONE }; 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; + int probed_bit_depth = 8, is_yuv444 = 0; const AVPixFmtDescriptor *probe_desc = av_pix_fmt_desc_get(avctx->pix_fmt); if (probe_desc && probe_desc->nb_components) probed_bit_depth = probe_desc->comp[0].depth; + if (probe_desc && !probe_desc->log2_chroma_w && !probe_desc->log2_chroma_h) + is_yuv444 = 1; + + // 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; + break; + case 12: + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016; + break; + default: + pix_fmts[1] = is_yuv444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12; + break; + } + ctx->pkt = avctx->internal->in_pkt; // Accelerated transcoding scenarios with 'ffmpeg' require that the // pix_fmt be set to AV_PIX_FMT_CUDA early. The sw_pix_fmt, and the // pix_fmt for non-accelerated transcoding, do not need to be correct - // but need to be set to something. We arbitrarily pick NV12. + // but need to be set to something. ret = ff_get_format(avctx, pix_fmts); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "ff_get_format failed: %d\n", ret); diff --git a/libavcodec/d3d12va_av1.c b/libavcodec/d3d12va_av1.c index 76d972990..4a4d207b4 100644 --- a/libavcodec/d3d12va_av1.c +++ b/libavcodec/d3d12va_av1.c @@ -23,6 +23,7 @@ #include "config_components.h" #include "libavutil/avassert.h" #include "libavutil/hwcontext_d3d12va_internal.h" +#include "libavutil/mem.h" #include "av1dec.h" #include "dxva2_internal.h" #include "d3d12va_decode.h" diff --git a/libavcodec/d3d12va_decode.c b/libavcodec/d3d12va_decode.c index af7cf1164..3b8978635 100644 --- a/libavcodec/d3d12va_decode.c +++ b/libavcodec/d3d12va_decode.c @@ -25,6 +25,7 @@ #include "libavutil/common.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/time.h" #include "libavutil/imgutils.h" #include "libavutil/hwcontext_d3d12va_internal.h" @@ -269,7 +270,7 @@ fail: int ff_d3d12va_common_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { - AVHWFramesContext *frames_ctx = (AVHWFramesContext *)hw_frames_ctx->data; + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)hw_frames_ctx->data; frames_ctx->format = AV_PIX_FMT_D3D12; frames_ctx->sw_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? AV_PIX_FMT_P010 : AV_PIX_FMT_NV12; @@ -410,7 +411,7 @@ int ff_d3d12va_decode_uninit(AVCodecContext *avctx) static inline int d3d12va_update_reference_frames_state(AVCodecContext *avctx, D3D12_RESOURCE_BARRIER *barriers, ID3D12Resource *current_resource, int state_before, int state_end) { - D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); + D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); int num_barrier = 0; for (int i = 0; i < ctx->max_num_ref; i++) { diff --git a/libavcodec/d3d12va_encode.c b/libavcodec/d3d12va_encode.c new file mode 100644 index 000000000..68fb9927a --- /dev/null +++ b/libavcodec/d3d12va_encode.c @@ -0,0 +1,1557 @@ +/* + * 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/avassert.h" +#include "libavutil/common.h" +#include "libavutil/internal.h" +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "libavutil/hwcontext_d3d12va_internal.h" +#include "libavutil/hwcontext_d3d12va.h" + +#include "avcodec.h" +#include "d3d12va_encode.h" +#include "encode.h" + +const AVCodecHWConfigInternal *const ff_d3d12va_encode_hw_configs[] = { + HW_CONFIG_ENCODER_FRAMES(D3D12, D3D12VA), + NULL, +}; + +static int d3d12va_fence_completion(AVD3D12VASyncContext *psync_ctx) +{ + uint64_t completion = ID3D12Fence_GetCompletedValue(psync_ctx->fence); + if (completion < psync_ctx->fence_value) { + if (FAILED(ID3D12Fence_SetEventOnCompletion(psync_ctx->fence, psync_ctx->fence_value, psync_ctx->event))) + return AVERROR(EINVAL); + + WaitForSingleObjectEx(psync_ctx->event, INFINITE, FALSE); + } + + return 0; +} + +static int d3d12va_sync_with_gpu(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + + DX_CHECK(ID3D12CommandQueue_Signal(ctx->command_queue, ctx->sync_ctx.fence, ++ctx->sync_ctx.fence_value)); + return d3d12va_fence_completion(&ctx->sync_ctx); + +fail: + return AVERROR(EINVAL); +} + +typedef struct CommandAllocator { + ID3D12CommandAllocator *command_allocator; + uint64_t fence_value; +} CommandAllocator; + +static int d3d12va_get_valid_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator **ppAllocator) +{ + HRESULT hr; + D3D12VAEncodeContext *ctx = avctx->priv_data; + CommandAllocator allocator; + + if (av_fifo_peek(ctx->allocator_queue, &allocator, 1, 0) >= 0) { + uint64_t completion = ID3D12Fence_GetCompletedValue(ctx->sync_ctx.fence); + if (completion >= allocator.fence_value) { + *ppAllocator = allocator.command_allocator; + av_fifo_read(ctx->allocator_queue, &allocator, 1); + return 0; + } + } + + hr = ID3D12Device_CreateCommandAllocator(ctx->hwctx->device, D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE, + &IID_ID3D12CommandAllocator, (void **)ppAllocator); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create a new command allocator!\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static int d3d12va_discard_command_allocator(AVCodecContext *avctx, ID3D12CommandAllocator *pAllocator, uint64_t fence_value) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + + CommandAllocator allocator = { + .command_allocator = pAllocator, + .fence_value = fence_value, + }; + + av_fifo_write(ctx->allocator_queue, &allocator, 1); + + return 0; +} + +static int d3d12va_encode_wait(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodePicture *pic = base_pic->priv; + uint64_t completion; + + av_assert0(base_pic->encode_issued); + + if (base_pic->encode_complete) { + // Already waited for this picture. + return 0; + } + + completion = ID3D12Fence_GetCompletedValue(ctx->sync_ctx.fence); + if (completion < pic->fence_value) { + if (FAILED(ID3D12Fence_SetEventOnCompletion(ctx->sync_ctx.fence, pic->fence_value, + ctx->sync_ctx.event))) + return AVERROR(EINVAL); + + WaitForSingleObjectEx(ctx->sync_ctx.event, INFINITE, FALSE); + } + + av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" " + "(input surface %p).\n", base_pic->display_order, + base_pic->encode_order, pic->input_surface->texture); + + av_frame_free(&base_pic->input_image); + + base_pic->encode_complete = 1; + 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); + 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; + + D3D12_RESOURCE_DESC meta_desc = { + .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER, + .Alignment = 0, + .Width = ctx->req.MaxEncoderOutputMetadataBufferSize, + .Height = 1, + .DepthOrArraySize = 1, + .MipLevels = 1, + .Format = DXGI_FORMAT_UNKNOWN, + .SampleDesc = { .Count = 1, .Quality = 0 }, + .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + .Flags = D3D12_RESOURCE_FLAG_NONE, + }; + + hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &encoded_meta_props, D3D12_HEAP_FLAG_NONE, + &meta_desc, D3D12_RESOURCE_STATE_COMMON, NULL, + &IID_ID3D12Resource, (void **)&pic->encoded_metadata); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create metadata buffer.\n"); + return AVERROR_UNKNOWN; + } + + ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &resolved_meta_props, 0, resolved_heap_type); + + meta_desc.Width = width; + + hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &resolved_meta_props, D3D12_HEAP_FLAG_NONE, + &meta_desc, D3D12_RESOURCE_STATE_COMMON, NULL, + &IID_ID3D12Resource, (void **)&pic->resolved_metadata); + + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create output metadata buffer.\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + +static int d3d12va_encode_issue(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodePicture *pic = base_pic->priv; + AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx; + int err, i, j; + HRESULT hr; + char data[MAX_PARAM_BUFFER_SIZE]; + void *ptr; + size_t bit_len; + ID3D12CommandAllocator *command_allocator = NULL; + ID3D12VideoEncodeCommandList2 *cmd_list = ctx->command_list; + D3D12_RESOURCE_BARRIER barriers[32] = { 0 }; + D3D12_VIDEO_ENCODE_REFERENCE_FRAMES d3d12_refs = { 0 }; + + D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS input_args = { + .SequenceControlDesc = { + .Flags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE, + .IntraRefreshConfig = { 0 }, + .RateControl = ctx->rc, + .PictureTargetResolution = ctx->resolution, + .SelectedLayoutMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME, + .FrameSubregionsLayoutData = { 0 }, + .CodecGopSequence = ctx->gop, + }, + .pInputFrame = pic->input_surface->texture, + .InputFrameSubresource = 0, + }; + + D3D12_VIDEO_ENCODER_ENCODEFRAME_OUTPUT_ARGUMENTS output_args = { 0 }; + + D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS input_metadata = { + .EncoderCodec = ctx->codec->d3d12_codec, + .EncoderProfile = ctx->profile->d3d12_profile, + .EncoderInputFormat = frames_hwctx->format, + .EncodedPictureEffectiveResolution = ctx->resolution, + }; + + D3D12_VIDEO_ENCODER_RESOLVE_METADATA_OUTPUT_ARGUMENTS output_metadata = { 0 }; + + memset(data, 0, sizeof(data)); + + av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" " + "as type %s.\n", base_pic->display_order, base_pic->encode_order, + ff_hw_base_encode_get_pictype_name(base_pic->type)); + if (base_pic->nb_refs[0] == 0 && base_pic->nb_refs[1] == 0) { + av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n"); + } else { + av_log(avctx, AV_LOG_DEBUG, "L0 refers to"); + for (i = 0; i < base_pic->nb_refs[0]; i++) { + av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, + base_pic->refs[0][i]->display_order, base_pic->refs[0][i]->encode_order); + } + av_log(avctx, AV_LOG_DEBUG, ".\n"); + + if (base_pic->nb_refs[1]) { + av_log(avctx, AV_LOG_DEBUG, "L1 refers to"); + for (i = 0; i < base_pic->nb_refs[1]; i++) { + av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, + base_pic->refs[1][i]->display_order, base_pic->refs[1][i]->encode_order); + } + av_log(avctx, AV_LOG_DEBUG, ".\n"); + } + } + + av_assert0(!base_pic->encode_issued); + for (i = 0; i < base_pic->nb_refs[0]; i++) { + av_assert0(base_pic->refs[0][i]); + av_assert0(base_pic->refs[0][i]->encode_issued); + } + for (i = 0; i < base_pic->nb_refs[1]; i++) { + av_assert0(base_pic->refs[1][i]); + av_assert0(base_pic->refs[1][i]->encode_issued); + } + + av_log(avctx, AV_LOG_DEBUG, "Input surface is %p.\n", pic->input_surface->texture); + + pic->recon_surface = (AVD3D12VAFrame *)base_pic->recon_image->data[0]; + av_log(avctx, AV_LOG_DEBUG, "Recon surface is %p.\n", + pic->recon_surface->texture); + + pic->output_buffer_ref = av_buffer_pool_get(ctx->output_buffer_pool); + if (!pic->output_buffer_ref) { + err = AVERROR(ENOMEM); + goto fail; + } + pic->output_buffer = (ID3D12Resource *)pic->output_buffer_ref->data; + av_log(avctx, AV_LOG_DEBUG, "Output buffer is %p.\n", + pic->output_buffer); + + err = d3d12va_encode_create_metadata_buffers(avctx, pic); + if (err < 0) + goto fail; + + if (ctx->codec->init_picture_params) { + err = ctx->codec->init_picture_params(avctx, base_pic); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture " + "parameters: %d.\n", err); + goto fail; + } + } + + if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) { + if (ctx->codec->write_sequence_header) { + bit_len = 8 * sizeof(data); + err = ctx->codec->write_sequence_header(avctx, data, &bit_len); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write per-sequence " + "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); + } + + d3d12_refs.NumTexture2Ds = base_pic->nb_refs[0] + base_pic->nb_refs[1]; + if (d3d12_refs.NumTexture2Ds) { + d3d12_refs.ppTexture2Ds = av_calloc(d3d12_refs.NumTexture2Ds, + sizeof(*d3d12_refs.ppTexture2Ds)); + if (!d3d12_refs.ppTexture2Ds) { + 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; + } + + input_args.PictureControlDesc.IntraRefreshFrameIndex = 0; + if (base_pic->is_reference) + input_args.PictureControlDesc.Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE; + + input_args.PictureControlDesc.PictureControlCodecData = pic->pic_ctl; + input_args.PictureControlDesc.ReferenceFrames = d3d12_refs; + input_args.CurrentFrameBitstreamMetadataSize = pic->aligned_header_size; + + 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.EncoderOutputMetadata.pBuffer = pic->encoded_metadata; + output_args.EncoderOutputMetadata.Offset = 0; + + input_metadata.HWLayoutMetadata.pBuffer = pic->encoded_metadata; + input_metadata.HWLayoutMetadata.Offset = 0; + + output_metadata.ResolvedLayoutMetadata.pBuffer = pic->resolved_metadata; + output_metadata.ResolvedLayoutMetadata.Offset = 0; + + err = d3d12va_get_valid_command_allocator(avctx, &command_allocator); + if (err < 0) + goto fail; + + hr = ID3D12CommandAllocator_Reset(command_allocator); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + goto fail; + } + + hr = ID3D12VideoEncodeCommandList2_Reset(cmd_list, command_allocator); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + goto fail; + } + +#define TRANSITION_BARRIER(res, 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, \ + .StateBefore = before, \ + .StateAfter = after, \ + }, \ + } + + barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ); + barriers[1] = TRANSITION_BARRIER(pic->output_buffer, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE); + barriers[2] = TRANSITION_BARRIER(pic->recon_surface->texture, + 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, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE); + + ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers); + + if (d3d12_refs.NumTexture2Ds) { + D3D12_RESOURCE_BARRIER refs_barriers[3]; + + 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); + + ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, d3d12_refs.NumTexture2Ds, + refs_barriers); + } + + ID3D12VideoEncodeCommandList2_EncodeFrame(cmd_list, ctx->encoder, ctx->encoder_heap, + &input_args, &output_args); + + barriers[3] = TRANSITION_BARRIER(pic->encoded_metadata, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ); + + ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 1, &barriers[3]); + + ID3D12VideoEncodeCommandList2_ResolveEncoderOutputMetadata(cmd_list, &input_metadata, &output_metadata); + + if (d3d12_refs.NumTexture2Ds) { + D3D12_RESOURCE_BARRIER refs_barriers[3]; + + 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); + } + + barriers[0] = TRANSITION_BARRIER(pic->input_surface->texture, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ, + D3D12_RESOURCE_STATE_COMMON); + barriers[1] = TRANSITION_BARRIER(pic->output_buffer, + 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, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ, + D3D12_RESOURCE_STATE_COMMON); + barriers[4] = TRANSITION_BARRIER(pic->resolved_metadata, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE, + D3D12_RESOURCE_STATE_COMMON); + + ID3D12VideoEncodeCommandList2_ResourceBarrier(cmd_list, 5, barriers); + + hr = ID3D12VideoEncodeCommandList2_Close(cmd_list); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + goto fail; + } + + hr = ID3D12CommandQueue_Wait(ctx->command_queue, pic->input_surface->sync_ctx.fence, + pic->input_surface->sync_ctx.fence_value); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + goto fail; + } + + ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list); + + hr = ID3D12CommandQueue_Signal(ctx->command_queue, pic->input_surface->sync_ctx.fence, + ++pic->input_surface->sync_ctx.fence_value); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + goto fail; + } + + hr = ID3D12CommandQueue_Signal(ctx->command_queue, ctx->sync_ctx.fence, ++ctx->sync_ctx.fence_value); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + goto fail; + } + + err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value); + if (err < 0) + goto fail; + + pic->fence_value = ctx->sync_ctx.fence_value; + + if (d3d12_refs.ppTexture2Ds) + av_freep(&d3d12_refs.ppTexture2Ds); + + return 0; + +fail: + if (command_allocator) + d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value); + + if (d3d12_refs.ppTexture2Ds) + av_freep(&d3d12_refs.ppTexture2Ds); + + if (ctx->codec->free_picture_params) + ctx->codec->free_picture_params(pic); + + av_buffer_unref(&pic->output_buffer_ref); + pic->output_buffer = NULL; + D3D12_OBJECT_RELEASE(pic->encoded_metadata); + D3D12_OBJECT_RELEASE(pic->resolved_metadata); + return err; +} + +static int d3d12va_encode_discard(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic) +{ + D3D12VAEncodePicture *pic = base_pic->priv; + + d3d12va_encode_wait(avctx, base_pic); + + if (pic->output_buffer_ref) { + av_log(avctx, AV_LOG_DEBUG, "Discard output for pic " + "%"PRId64"/%"PRId64".\n", + base_pic->display_order, base_pic->encode_order); + + av_buffer_unref(&pic->output_buffer_ref); + pic->output_buffer = NULL; + } + + D3D12_OBJECT_RELEASE(pic->encoded_metadata); + D3D12_OBJECT_RELEASE(pic->resolved_metadata); + + return 0; +} + +static int d3d12va_encode_free_rc_params(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + + switch (ctx->rc.Mode) + { + case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP: + av_freep(&ctx->rc.ConfigParams.pConfiguration_CQP); + break; + case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR: + av_freep(&ctx->rc.ConfigParams.pConfiguration_CBR); + break; + case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR: + av_freep(&ctx->rc.ConfigParams.pConfiguration_VBR); + break; + case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR: + av_freep(&ctx->rc.ConfigParams.pConfiguration_QVBR); + break; + default: + break; + } + + return 0; +} + +static int d3d12va_encode_init(AVCodecContext *avctx, FFHWBaseEncodePicture *pic) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodePicture *priv = pic->priv; + AVFrame *frame = pic->input_image; + + if (ctx->codec->picture_priv_data_size > 0) { + pic->codec_priv = av_mallocz(ctx->codec->picture_priv_data_size); + if (!pic->codec_priv) + return AVERROR(ENOMEM); + } + + priv->input_surface = (AVD3D12VAFrame *)frame->data[0]; + + return 0; +} + +static int d3d12va_encode_free(AVCodecContext *avctx, FFHWBaseEncodePicture *pic) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodePicture *priv = pic->priv; + + if (pic->encode_issued) + d3d12va_encode_discard(avctx, pic); + + if (ctx->codec->free_picture_params) + ctx->codec->free_picture_params(priv); + + return 0; +} + +static int d3d12va_encode_get_buffer_size(AVCodecContext *avctx, + D3D12VAEncodePicture *pic, size_t *size) +{ + D3D12_VIDEO_ENCODER_OUTPUT_METADATA *meta = NULL; + uint8_t *data; + HRESULT hr; + int err; + + hr = ID3D12Resource_Map(pic->resolved_metadata, 0, NULL, (void **)&data); + if (FAILED(hr)) { + err = AVERROR_UNKNOWN; + return err; + } + + meta = (D3D12_VIDEO_ENCODER_OUTPUT_METADATA *)data; + + if (meta->EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) { + av_log(avctx, AV_LOG_ERROR, "Encode failed %"PRIu64"\n", meta->EncodeErrorFlags); + err = AVERROR(EINVAL); + return err; + } + + if (meta->EncodedBitstreamWrittenBytesCount == 0) { + av_log(avctx, AV_LOG_ERROR, "No bytes were written to encoded bitstream\n"); + err = AVERROR(EINVAL); + return err; + } + + *size = meta->EncodedBitstreamWrittenBytesCount; + + ID3D12Resource_Unmap(pic->resolved_metadata, 0, NULL); + + return 0; +} + +static int d3d12va_encode_get_coded_data(AVCodecContext *avctx, + D3D12VAEncodePicture *pic, AVPacket *pkt) +{ + int err; + uint8_t *ptr, *mapped_data; + size_t total_size = 0; + HRESULT hr; + + err = d3d12va_encode_get_buffer_size(avctx, pic, &total_size); + if (err < 0) + goto end; + + total_size += pic->header_size; + av_log(avctx, AV_LOG_DEBUG, "Output buffer size %"PRId64"\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, mapped_data, total_size); + + ID3D12Resource_Unmap(pic->output_buffer, 0, NULL); + +end: + av_buffer_unref(&pic->output_buffer_ref); + pic->output_buffer = NULL; + return err; +} + +static int d3d12va_encode_output(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, AVPacket *pkt) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodePicture *pic = base_pic->priv; + AVPacket *pkt_ptr = pkt; + int err; + + err = d3d12va_encode_wait(avctx, base_pic); + if (err < 0) + return err; + + err = d3d12va_encode_get_coded_data(avctx, pic, pkt); + if (err < 0) + return err; + + av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n", + base_pic->display_order, base_pic->encode_order); + + ff_hw_base_encode_set_output_property(base_ctx, avctx, (FFHWBaseEncodePicture *)base_pic, + pkt_ptr, 0); + + return 0; +} + +static int d3d12va_encode_set_profile(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + const D3D12VAEncodeProfile *profile; + const AVPixFmtDescriptor *desc; + int i, depth; + + desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); + if (!desc) { + av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%d).\n", + base_ctx->input_frames->sw_format); + return AVERROR(EINVAL); + } + + depth = desc->comp[0].depth; + for (i = 1; i < desc->nb_components; i++) { + if (desc->comp[i].depth != depth) { + av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%s).\n", + desc->name); + return AVERROR(EINVAL); + } + } + av_log(avctx, AV_LOG_VERBOSE, "Input surface format is %s.\n", + desc->name); + + av_assert0(ctx->codec->profiles); + for (i = 0; (ctx->codec->profiles[i].av_profile != + AV_PROFILE_UNKNOWN); i++) { + profile = &ctx->codec->profiles[i]; + if (depth != profile->depth || + desc->nb_components != profile->nb_components) + continue; + if (desc->nb_components > 1 && + (desc->log2_chroma_w != profile->log2_chroma_w || + desc->log2_chroma_h != profile->log2_chroma_h)) + continue; + if (avctx->profile != profile->av_profile && + avctx->profile != AV_PROFILE_UNKNOWN) + continue; + + ctx->profile = profile; + break; + } + if (!ctx->profile) { + av_log(avctx, AV_LOG_ERROR, "No usable encoding profile found.\n"); + return AVERROR(ENOSYS); + } + + avctx->profile = profile->av_profile; + return 0; +} + +static const D3D12VAEncodeRCMode d3d12va_encode_rc_modes[] = { + // Bitrate Quality + // | Maxrate | HRD/VBV + { 0 }, // | | | | + { RC_MODE_CQP, "CQP", 0, 0, 1, 0, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP }, + { RC_MODE_CBR, "CBR", 1, 0, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR }, + { RC_MODE_VBR, "VBR", 1, 1, 0, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR }, + { RC_MODE_QVBR, "QVBR", 1, 1, 1, 1, D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR }, +}; + +static int check_rate_control_support(AVCodecContext *avctx, const D3D12VAEncodeRCMode *rc_mode) +{ + HRESULT hr; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12_FEATURE_DATA_VIDEO_ENCODER_RATE_CONTROL_MODE d3d12_rc_mode = { + .Codec = ctx->codec->d3d12_codec, + }; + + if (!rc_mode->d3d12_mode) + return 0; + + d3d12_rc_mode.IsSupported = 0; + d3d12_rc_mode.RateControlMode = rc_mode->d3d12_mode; + + hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, + D3D12_FEATURE_VIDEO_ENCODER_RATE_CONTROL_MODE, + &d3d12_rc_mode, sizeof(d3d12_rc_mode)); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to check rate control support.\n"); + return 0; + } + + return d3d12_rc_mode.IsSupported; +} + +static int d3d12va_encode_init_rate_control(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + int64_t rc_target_bitrate; + int64_t rc_peak_bitrate; + int rc_quality; + int64_t hrd_buffer_size; + int64_t hrd_initial_buffer_fullness; + int fr_num, fr_den; + const D3D12VAEncodeRCMode *rc_mode; + + // 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. + // * If an explicit QP option has been set, use CQP. + // * If the codec is CQ-only, use CQP. + // * If the QSCALE avcodec option is set, use CQP. + // * If bitrate and quality are both set, try QVBR. + // * If quality is set, try CQP. + // * If bitrate and maxrate are set and have the same value, try CBR. + // * If a bitrate is set, try VBR, then CBR. + // * If no bitrate is set, try CQP. + +#define TRY_RC_MODE(mode, fail) do { \ + rc_mode = &d3d12va_encode_rc_modes[mode]; \ + if (!(rc_mode->d3d12_mode && check_rate_control_support(avctx, rc_mode))) { \ + if (fail) { \ + av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \ + "RC mode.\n", rc_mode->name); \ + return AVERROR(EINVAL); \ + } \ + av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \ + "RC mode.\n", rc_mode->name); \ + rc_mode = NULL; \ + } else { \ + goto rc_mode_found; \ + } \ + } while (0) + + if (ctx->explicit_rc_mode) + TRY_RC_MODE(ctx->explicit_rc_mode, 1); + + if (ctx->explicit_qp) + TRY_RC_MODE(RC_MODE_CQP, 1); + + if (ctx->codec->flags & FF_HW_FLAG_CONSTANT_QUALITY_ONLY) + TRY_RC_MODE(RC_MODE_CQP, 1); + + if (avctx->flags & AV_CODEC_FLAG_QSCALE) + TRY_RC_MODE(RC_MODE_CQP, 1); + + if (avctx->bit_rate > 0 && avctx->global_quality > 0) + TRY_RC_MODE(RC_MODE_QVBR, 0); + + if (avctx->global_quality > 0) { + TRY_RC_MODE(RC_MODE_CQP, 0); + } + + if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate) + TRY_RC_MODE(RC_MODE_CBR, 0); + + if (avctx->bit_rate > 0) { + TRY_RC_MODE(RC_MODE_VBR, 0); + TRY_RC_MODE(RC_MODE_CBR, 0); + } else { + TRY_RC_MODE(RC_MODE_CQP, 0); + } + + av_log(avctx, AV_LOG_ERROR, "Driver does not support any " + "RC mode compatible with selected options.\n"); + return AVERROR(EINVAL); + +rc_mode_found: + if (rc_mode->bitrate) { + if (avctx->bit_rate <= 0) { + av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s " + "RC mode.\n", rc_mode->name); + return AVERROR(EINVAL); + } + + if (rc_mode->maxrate) { + if (avctx->rc_max_rate > 0) { + if (avctx->rc_max_rate < avctx->bit_rate) { + av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: " + "bitrate (%"PRId64") must not be greater than " + "maxrate (%"PRId64").\n", avctx->bit_rate, + avctx->rc_max_rate); + return AVERROR(EINVAL); + } + rc_target_bitrate = avctx->bit_rate; + rc_peak_bitrate = avctx->rc_max_rate; + } else { + // We only have a target bitrate, but this mode requires + // that a maximum rate be supplied as well. Since the + // user does not want this to be a constraint, arbitrarily + // pick a maximum rate of double the target rate. + rc_target_bitrate = avctx->bit_rate; + rc_peak_bitrate = 2 * avctx->bit_rate; + } + } else { + if (avctx->rc_max_rate > avctx->bit_rate) { + av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored " + "in %s RC mode.\n", rc_mode->name); + } + rc_target_bitrate = avctx->bit_rate; + rc_peak_bitrate = 0; + } + } else { + rc_target_bitrate = 0; + rc_peak_bitrate = 0; + } + + if (rc_mode->quality) { + if (ctx->explicit_qp) { + rc_quality = ctx->explicit_qp; + } else if (avctx->global_quality > 0) { + if (avctx->flags & AV_CODEC_FLAG_QSCALE) + rc_quality = avctx->global_quality / FF_QP2LAMBDA; + else + rc_quality = avctx->global_quality; + } else { + rc_quality = ctx->codec->default_quality; + av_log(avctx, AV_LOG_WARNING, "No quality level set; " + "using default (%d).\n", rc_quality); + } + } else { + rc_quality = 0; + } + + if (rc_mode->hrd) { + if (avctx->rc_buffer_size) + hrd_buffer_size = avctx->rc_buffer_size; + else if (avctx->rc_max_rate > 0) + hrd_buffer_size = avctx->rc_max_rate; + else + hrd_buffer_size = avctx->bit_rate; + if (avctx->rc_initial_buffer_occupancy) { + if (avctx->rc_initial_buffer_occupancy > 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, hrd_buffer_size); + return AVERROR(EINVAL); + } + hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; + } else { + hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4; + } + } else { + if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) { + av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored " + "in %s RC mode.\n", rc_mode->name); + } + + hrd_buffer_size = 0; + hrd_initial_buffer_fullness = 0; + } + + if (rc_target_bitrate > UINT32_MAX || + hrd_buffer_size > UINT32_MAX || + hrd_initial_buffer_fullness > UINT32_MAX) { + av_log(avctx, AV_LOG_ERROR, "RC parameters of 2^32 or " + "greater are not supported by D3D12.\n"); + return AVERROR(EINVAL); + } + + ctx->rc_quality = rc_quality; + + av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name); + + if (rc_mode->quality) + av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality); + + if (rc_mode->hrd) { + av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, " + "initial fullness %"PRId64" bits.\n", + hrd_buffer_size, hrd_initial_buffer_fullness); + } + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + av_reduce(&fr_num, &fr_den, + avctx->framerate.num, avctx->framerate.den, 65535); + else + av_reduce(&fr_num, &fr_den, + avctx->time_base.den, avctx->time_base.num, 65535); + + av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n", + fr_num, fr_den, (double)fr_num / fr_den); + + ctx->rc.Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE; + ctx->rc.TargetFrameRate.Numerator = fr_num; + ctx->rc.TargetFrameRate.Denominator = fr_den; + ctx->rc.Mode = rc_mode->d3d12_mode; + + switch (rc_mode->mode) { + case RC_MODE_CQP: + // cqp ConfigParams will be updated in ctx->codec->configure. + break; + + case RC_MODE_CBR: + D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR *cbr_ctl; + + ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR); + cbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize); + if (!cbr_ctl) + return AVERROR(ENOMEM); + + cbr_ctl->TargetBitRate = rc_target_bitrate; + cbr_ctl->VBVCapacity = hrd_buffer_size; + 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; + } + + ctx->rc.ConfigParams.pConfiguration_CBR = cbr_ctl; + break; + + case RC_MODE_VBR: + D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR *vbr_ctl; + + ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR); + vbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize); + if (!vbr_ctl) + return AVERROR(ENOMEM); + + vbr_ctl->TargetAvgBitRate = rc_target_bitrate; + vbr_ctl->PeakBitRate = rc_peak_bitrate; + vbr_ctl->VBVCapacity = hrd_buffer_size; + 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; + } + + ctx->rc.ConfigParams.pConfiguration_VBR = vbr_ctl; + break; + + case RC_MODE_QVBR: + D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR *qvbr_ctl; + + ctx->rc.ConfigParams.DataSize = sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR); + qvbr_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize); + if (!qvbr_ctl) + return AVERROR(ENOMEM); + + qvbr_ctl->TargetAvgBitRate = rc_target_bitrate; + 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; + } + + ctx->rc.ConfigParams.pConfiguration_QVBR = qvbr_ctl; + break; + + default: + break; + } + return 0; +} + +static int d3d12va_encode_init_gop_structure(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + uint32_t ref_l0, ref_l1; + int err; + HRESULT hr; + D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT support; + union { + D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264; + D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_HEVC hevc; + } codec_support; + + support.NodeIndex = 0; + support.Codec = ctx->codec->d3d12_codec; + support.Profile = ctx->profile->d3d12_profile; + + switch (ctx->codec->d3d12_codec) { + case D3D12_VIDEO_ENCODER_CODEC_H264: + support.PictureSupport.DataSize = sizeof(codec_support.h264); + support.PictureSupport.pH264Support = &codec_support.h264; + break; + + case D3D12_VIDEO_ENCODER_CODEC_HEVC: + support.PictureSupport.DataSize = sizeof(codec_support.hevc); + support.PictureSupport.pHEVCSupport = &codec_support.hevc; + break; + + default: + av_assert0(0); + } + + hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT, + &support, sizeof(support)); + if (FAILED(hr)) + return AVERROR(EINVAL); + + if (support.IsSupported) { + switch (ctx->codec->d3d12_codec) { + case D3D12_VIDEO_ENCODER_CODEC_H264: + ref_l0 = FFMIN(support.PictureSupport.pH264Support->MaxL0ReferencesForP, + support.PictureSupport.pH264Support->MaxL1ReferencesForB); + ref_l1 = support.PictureSupport.pH264Support->MaxL1ReferencesForB; + break; + + case D3D12_VIDEO_ENCODER_CODEC_HEVC: + ref_l0 = FFMIN(support.PictureSupport.pHEVCSupport->MaxL0ReferencesForP, + support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB); + ref_l1 = support.PictureSupport.pHEVCSupport->MaxL1ReferencesForB; + break; + + default: + av_assert0(0); + } + } else { + ref_l0 = ref_l1 = 0; + } + + if (ref_l0 > 0 && ref_l1 > 0 && ctx->bi_not_empty) { + base_ctx->p_to_gpb = 1; + av_log(avctx, AV_LOG_VERBOSE, "Driver does not support P-frames, " + "replacing them with B-frames.\n"); + } + + err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1, ctx->codec->flags, 0); + if (err < 0) + return err; + + return 0; +} + +static int d3d12va_create_encoder(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + AVD3D12VAFramesContext *frames_hwctx = base_ctx->input_frames->hwctx; + HRESULT hr; + + D3D12_VIDEO_ENCODER_DESC desc = { + .NodeMask = 0, + .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE, + .EncodeCodec = ctx->codec->d3d12_codec, + .EncodeProfile = ctx->profile->d3d12_profile, + .InputFormat = frames_hwctx->format, + .CodecConfiguration = ctx->codec_conf, + .MaxMotionEstimationPrecision = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM, + }; + + hr = ID3D12VideoDevice3_CreateVideoEncoder(ctx->video_device3, &desc, &IID_ID3D12VideoEncoder, + (void **)&ctx->encoder); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create encoder.\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static int d3d12va_create_encoder_heap(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + HRESULT hr; + + D3D12_VIDEO_ENCODER_HEAP_DESC desc = { + .NodeMask = 0, + .Flags = D3D12_VIDEO_ENCODER_FLAG_NONE, + .EncodeCodec = ctx->codec->d3d12_codec, + .EncodeProfile = ctx->profile->d3d12_profile, + .EncodeLevel = ctx->level, + .ResolutionsListCount = 1, + .pResolutionList = &ctx->resolution, + }; + + hr = ID3D12VideoDevice3_CreateVideoEncoderHeap(ctx->video_device3, &desc, + &IID_ID3D12VideoEncoderHeap, (void **)&ctx->encoder_heap); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create encoder heap.\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static void d3d12va_encode_free_buffer(void *opaque, uint8_t *data) +{ + ID3D12Resource *pResource; + + pResource = (ID3D12Resource *)data; + D3D12_OBJECT_RELEASE(pResource); +} + +static AVBufferRef *d3d12va_encode_alloc_output_buffer(void *opaque, size_t size) +{ + AVCodecContext *avctx = opaque; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + ID3D12Resource *pResource = NULL; + HRESULT hr; + AVBufferRef *ref; + D3D12_HEAP_PROPERTIES heap_props; + D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_READBACK; + + D3D12_RESOURCE_DESC desc = { + .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER, + .Alignment = 0, + .Width = FFALIGN(3 * base_ctx->surface_width * base_ctx->surface_height + (1 << 16), + D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT), + .Height = 1, + .DepthOrArraySize = 1, + .MipLevels = 1, + .Format = DXGI_FORMAT_UNKNOWN, + .SampleDesc = { .Count = 1, .Quality = 0 }, + .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + .Flags = D3D12_RESOURCE_FLAG_NONE, + }; + + ctx->hwctx->device->lpVtbl->GetCustomHeapProperties(ctx->hwctx->device, &heap_props, 0, heap_type); + + hr = ID3D12Device_CreateCommittedResource(ctx->hwctx->device, &heap_props, D3D12_HEAP_FLAG_NONE, + &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, + (void **)&pResource); + + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create d3d12 buffer.\n"); + return NULL; + } + + ref = av_buffer_create((uint8_t *)(uintptr_t)pResource, + sizeof(pResource), + &d3d12va_encode_free_buffer, + avctx, AV_BUFFER_FLAG_READONLY); + if (!ref) { + D3D12_OBJECT_RELEASE(pResource); + return NULL; + } + + return ref; +} + +static int d3d12va_encode_prepare_output_buffers(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + AVD3D12VAFramesContext *frames_ctx = base_ctx->input_frames->hwctx; + HRESULT hr; + + ctx->req.NodeIndex = 0; + ctx->req.Codec = ctx->codec->d3d12_codec; + ctx->req.Profile = ctx->profile->d3d12_profile; + ctx->req.InputFormat = frames_ctx->format; + ctx->req.PictureTargetResolution = ctx->resolution; + + hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, + D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS, + &ctx->req, sizeof(ctx->req)); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to check encoder resource requirements support.\n"); + return AVERROR(EINVAL); + } + + if (!ctx->req.IsSupported) { + av_log(avctx, AV_LOG_ERROR, "Encoder resource requirements unsupported.\n"); + return AVERROR(EINVAL); + } + + ctx->output_buffer_pool = av_buffer_pool_init2(sizeof(ID3D12Resource *), avctx, + &d3d12va_encode_alloc_output_buffer, NULL); + if (!ctx->output_buffer_pool) + return AVERROR(ENOMEM); + + return 0; +} + +static int d3d12va_encode_create_command_objects(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + ID3D12CommandAllocator *command_allocator = NULL; + int err; + HRESULT hr; + + D3D12_COMMAND_QUEUE_DESC queue_desc = { + .Type = D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE, + .Priority = 0, + .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE, + .NodeMask = 0, + }; + + ctx->allocator_queue = av_fifo_alloc2(D3D12VA_VIDEO_ENC_ASYNC_DEPTH, + sizeof(CommandAllocator), AV_FIFO_FLAG_AUTO_GROW); + if (!ctx->allocator_queue) + return AVERROR(ENOMEM); + + hr = ID3D12Device_CreateFence(ctx->hwctx->device, 0, D3D12_FENCE_FLAG_NONE, + &IID_ID3D12Fence, (void **)&ctx->sync_ctx.fence); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create fence(%lx)\n", (long)hr); + err = AVERROR_UNKNOWN; + goto fail; + } + + ctx->sync_ctx.event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!ctx->sync_ctx.event) + goto fail; + + err = d3d12va_get_valid_command_allocator(avctx, &command_allocator); + if (err < 0) + goto fail; + + hr = ID3D12Device_CreateCommandQueue(ctx->hwctx->device, &queue_desc, + &IID_ID3D12CommandQueue, (void **)&ctx->command_queue); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create command queue(%lx)\n", (long)hr); + err = AVERROR_UNKNOWN; + goto fail; + } + + hr = ID3D12Device_CreateCommandList(ctx->hwctx->device, 0, queue_desc.Type, + command_allocator, NULL, &IID_ID3D12CommandList, + (void **)&ctx->command_list); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create command list(%lx)\n", (long)hr); + err = AVERROR_UNKNOWN; + goto fail; + } + + hr = ID3D12VideoEncodeCommandList2_Close(ctx->command_list); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to close the command list(%lx)\n", (long)hr); + err = AVERROR_UNKNOWN; + goto fail; + } + + ID3D12CommandQueue_ExecuteCommandLists(ctx->command_queue, 1, (ID3D12CommandList **)&ctx->command_list); + + err = d3d12va_sync_with_gpu(avctx); + if (err < 0) + goto fail; + + err = d3d12va_discard_command_allocator(avctx, command_allocator, ctx->sync_ctx.fence_value); + if (err < 0) + goto fail; + + return 0; + +fail: + D3D12_OBJECT_RELEASE(command_allocator); + return err; +} + +static int d3d12va_encode_create_recon_frames(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + AVD3D12VAFramesContext *hwctx; + enum AVPixelFormat recon_format; + int err; + + err = ff_hw_base_get_recon_format(base_ctx, NULL, &recon_format); + if (err < 0) + return err; + + base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref); + if (!base_ctx->recon_frames_ref) + return AVERROR(ENOMEM); + + base_ctx->recon_frames = (AVHWFramesContext *)base_ctx->recon_frames_ref->data; + hwctx = (AVD3D12VAFramesContext *)base_ctx->recon_frames->hwctx; + + base_ctx->recon_frames->format = AV_PIX_FMT_D3D12; + base_ctx->recon_frames->sw_format = recon_format; + 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; + + err = av_hwframe_ctx_init(base_ctx->recon_frames_ref); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed " + "frame context: %d.\n", err); + return err; + } + + return 0; +} + +static const FFHWEncodePictureOperation d3d12va_type = { + .priv_size = sizeof(D3D12VAEncodePicture), + + .init = &d3d12va_encode_init, + + .issue = &d3d12va_encode_issue, + + .output = &d3d12va_encode_output, + + .free = &d3d12va_encode_free, +}; + +int ff_d3d12va_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt) +{ + return ff_hw_base_encode_receive_packet(avctx->priv_data, avctx, pkt); +} + +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 }; + int err; + HRESULT hr; + + err = ff_hw_base_encode_init(avctx, base_ctx); + if (err < 0) + goto fail; + + base_ctx->op = &d3d12va_type; + + ctx->hwctx = base_ctx->device->hwctx; + + ctx->resolution.Width = base_ctx->input_frames->width; + ctx->resolution.Height = base_ctx->input_frames->height; + + hr = ID3D12Device_QueryInterface(ctx->hwctx->device, &IID_ID3D12Device3, (void **)&ctx->device3); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "ID3D12Device3 interface is not supported.\n"); + err = AVERROR_UNKNOWN; + goto fail; + } + + hr = ID3D12Device3_QueryInterface(ctx->device3, &IID_ID3D12VideoDevice3, (void **)&ctx->video_device3); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "ID3D12VideoDevice3 interface is not supported.\n"); + err = AVERROR_UNKNOWN; + goto fail; + } + + if (FAILED(ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT, + &support, sizeof(support))) && !support.VideoEncodeSupport) { + av_log(avctx, AV_LOG_ERROR, "D3D12 video device has no video encoder support.\n"); + err = AVERROR(EINVAL); + goto fail; + } + + err = d3d12va_encode_set_profile(avctx); + if (err < 0) + goto fail; + + err = d3d12va_encode_init_rate_control(avctx); + if (err < 0) + goto fail; + + if (ctx->codec->get_encoder_caps) { + err = ctx->codec->get_encoder_caps(avctx); + if (err < 0) + goto fail; + } + + err = d3d12va_encode_init_gop_structure(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"); + } + + err = d3d12va_encode_create_command_objects(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; + + if (ctx->codec->configure) { + err = ctx->codec->configure(avctx); + if (err < 0) + goto fail; + } + + if (ctx->codec->init_sequence_params) { + err = ctx->codec->init_sequence_params(avctx); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Codec sequence initialisation " + "failed: %d.\n", err); + goto fail; + } + } + + if (ctx->codec->set_level) { + err = ctx->codec->set_level(avctx); + if (err < 0) + goto fail; + } + + base_ctx->output_delay = base_ctx->b_per_p; + base_ctx->decode_delay = base_ctx->max_b_depth; + + err = d3d12va_create_encoder(avctx); + if (err < 0) + goto fail; + + err = d3d12va_create_encoder_heap(avctx); + if (err < 0) + goto fail; + + base_ctx->async_encode = 1; + base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth, + sizeof(D3D12VAEncodePicture *), 0); + if (!base_ctx->encode_fifo) + return AVERROR(ENOMEM); + + return 0; + +fail: + return err; +} + +int ff_d3d12va_encode_close(AVCodecContext *avctx) +{ + int num_allocator = 0; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodePicture *pic, *next; + CommandAllocator allocator; + + if (!base_ctx->frame) + return 0; + + for (pic = base_ctx->pic_start; pic; pic = next) { + next = pic->next; + d3d12va_encode_free(avctx, pic); + } + + d3d12va_encode_free_rc_params(avctx); + + av_buffer_pool_uninit(&ctx->output_buffer_pool); + + D3D12_OBJECT_RELEASE(ctx->command_list); + D3D12_OBJECT_RELEASE(ctx->command_queue); + + if (ctx->allocator_queue) { + while (av_fifo_read(ctx->allocator_queue, &allocator, 1) >= 0) { + num_allocator++; + D3D12_OBJECT_RELEASE(allocator.command_allocator); + } + + av_log(avctx, AV_LOG_VERBOSE, "Total number of command allocators reused: %d\n", num_allocator); + } + + av_fifo_freep2(&ctx->allocator_queue); + + D3D12_OBJECT_RELEASE(ctx->sync_ctx.fence); + if (ctx->sync_ctx.event) + CloseHandle(ctx->sync_ctx.event); + + D3D12_OBJECT_RELEASE(ctx->encoder_heap); + D3D12_OBJECT_RELEASE(ctx->encoder); + D3D12_OBJECT_RELEASE(ctx->video_device3); + D3D12_OBJECT_RELEASE(ctx->device3); + + ff_hw_base_encode_close(base_ctx); + + return 0; +} diff --git a/libavcodec/d3d12va_encode.h b/libavcodec/d3d12va_encode.h new file mode 100644 index 000000000..3b0b8153d --- /dev/null +++ b/libavcodec/d3d12va_encode.h @@ -0,0 +1,335 @@ +/* + * 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 + */ + +#ifndef AVCODEC_D3D12VA_ENCODE_H +#define AVCODEC_D3D12VA_ENCODE_H + +#include "libavutil/fifo.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_d3d12va_internal.h" +#include "libavutil/hwcontext_d3d12va.h" +#include "avcodec.h" +#include "internal.h" +#include "hwconfig.h" +#include "hw_base_encode.h" + +struct D3D12VAEncodeType; + +extern const AVCodecHWConfigInternal *const ff_d3d12va_encode_hw_configs[]; + +#define MAX_PARAM_BUFFER_SIZE 4096 +#define D3D12VA_VIDEO_ENC_ASYNC_DEPTH 8 + +typedef struct D3D12VAEncodePicture { + int header_size; + int aligned_header_size; + + AVD3D12VAFrame *input_surface; + AVD3D12VAFrame *recon_surface; + + AVBufferRef *output_buffer_ref; + ID3D12Resource *output_buffer; + + ID3D12Resource *encoded_metadata; + ID3D12Resource *resolved_metadata; + + D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA pic_ctl; + + int fence_value; +} D3D12VAEncodePicture; + +typedef struct D3D12VAEncodeProfile { + /** + * lavc profile value (AV_PROFILE_*). + */ + int av_profile; + + /** + * Supported bit depth. + */ + int depth; + + /** + * Number of components. + */ + int nb_components; + + /** + * Chroma subsampling in width dimension. + */ + int log2_chroma_w; + + /** + * Chroma subsampling in height dimension. + */ + int log2_chroma_h; + + /** + * D3D12 profile value. + */ + D3D12_VIDEO_ENCODER_PROFILE_DESC d3d12_profile; +} D3D12VAEncodeProfile; + +enum { + RC_MODE_AUTO, + RC_MODE_CQP, + RC_MODE_CBR, + RC_MODE_VBR, + RC_MODE_QVBR, + RC_MODE_MAX = RC_MODE_QVBR, +}; + + +typedef struct D3D12VAEncodeRCMode { + /** + * Mode from above enum (RC_MODE_*). + */ + int mode; + + /** + * Name. + * + */ + const char *name; + + /** + * Uses bitrate parameters. + * + */ + int bitrate; + + /** + * Supports maxrate distinct from bitrate. + * + */ + int maxrate; + + /** + * Uses quality value. + * + */ + int quality; + + /** + * Supports HRD/VBV parameters. + * + */ + int hrd; + + /** + * D3D12 mode value. + */ + D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE d3d12_mode; +} D3D12VAEncodeRCMode; + +typedef struct D3D12VAEncodeContext { + FFHWBaseEncodeContext base; + + /** + * Codec-specific hooks. + */ + const struct D3D12VAEncodeType *codec; + + /** + * Explicitly set RC mode (otherwise attempt to pick from + * available modes). + */ + int explicit_rc_mode; + + /** + * Explicitly-set QP, for use with the "qp" options. + * (Forces CQP mode when set, overriding everything else.) + */ + int explicit_qp; + + /** + * RC quality level - meaning depends on codec and RC mode. + * In CQP mode this sets the fixed quantiser value. + */ + int rc_quality; + + /** + * Chosen encoding profile details. + */ + const D3D12VAEncodeProfile *profile; + + AVD3D12VADeviceContext *hwctx; + + /** + * ID3D12Device3 interface. + */ + ID3D12Device3 *device3; + + /** + * ID3D12VideoDevice3 interface. + */ + ID3D12VideoDevice3 *video_device3; + + /** + * Pool of (reusable) bitstream output buffers. + */ + AVBufferPool *output_buffer_pool; + + /** + * D3D12 video encoder. + */ + AVBufferRef *encoder_ref; + + ID3D12VideoEncoder *encoder; + + /** + * D3D12 video encoder heap. + */ + ID3D12VideoEncoderHeap *encoder_heap; + + /** + * A cached queue for reusing the D3D12 command allocators. + * + * @see https://learn.microsoft.com/en-us/windows/win32/direct3d12/recording-command-lists-and-bundles#id3d12commandallocator + */ + AVFifo *allocator_queue; + + /** + * D3D12 command queue. + */ + ID3D12CommandQueue *command_queue; + + /** + * D3D12 video encode command list. + */ + ID3D12VideoEncodeCommandList2 *command_list; + + /** + * The sync context used to sync command queue. + */ + AVD3D12VASyncContext sync_ctx; + + /** + * The bi_not_empty feature. + */ + int bi_not_empty; + + /** + * D3D12_FEATURE structures. + */ + D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS req; + + D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS res_limits; + + /** + * D3D12_VIDEO_ENCODER structures. + */ + D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC resolution; + + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION codec_conf; + + D3D12_VIDEO_ENCODER_RATE_CONTROL rc; + + D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE gop; + + D3D12_VIDEO_ENCODER_LEVEL_SETTING level; +} D3D12VAEncodeContext; + +typedef struct D3D12VAEncodeType { + /** + * List of supported profiles. + */ + const D3D12VAEncodeProfile *profiles; + + /** + * D3D12 codec name. + */ + D3D12_VIDEO_ENCODER_CODEC d3d12_codec; + + /** + * Codec feature flags. + */ + int flags; + + /** + * Default quality for this codec - used as quantiser or RC quality + * factor depending on RC mode. + */ + int default_quality; + + /** + * Query codec configuration and determine encode parameters like + * block sizes for surface alignment and slices. If not set, assume + * that all blocks are 16x16 and that surfaces should be aligned to match + * this. + */ + int (*get_encoder_caps)(AVCodecContext *avctx); + + /** + * Perform any extra codec-specific configuration. + */ + int (*configure)(AVCodecContext *avctx); + + /** + * Set codec-specific level setting. + */ + int (*set_level)(AVCodecContext *avctx); + + /** + * The size of any private data structure associated with each + * picture (can be zero if not required). + */ + size_t picture_priv_data_size; + + /** + * Fill the corresponding parameters. + */ + int (*init_sequence_params)(AVCodecContext *avctx); + + int (*init_picture_params)(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic); + + void (*free_picture_params)(D3D12VAEncodePicture *pic); + + /** + * Write the packed header data to the provided buffer. + */ + int (*write_sequence_header)(AVCodecContext *avctx, + char *data, size_t *data_len); +} D3D12VAEncodeType; + +int ff_d3d12va_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt); + +int ff_d3d12va_encode_init(AVCodecContext *avctx); +int ff_d3d12va_encode_close(AVCodecContext *avctx); + +#define D3D12VA_ENCODE_RC_MODE(name, desc) \ + { #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_ ## name }, \ + 0, 0, FLAGS, .unit = "rc_mode" } +#define D3D12VA_ENCODE_RC_OPTIONS \ + { "rc_mode",\ + "Set rate control mode", \ + OFFSET(common.explicit_rc_mode), AV_OPT_TYPE_INT, \ + { .i64 = RC_MODE_AUTO }, RC_MODE_AUTO, RC_MODE_MAX, FLAGS, .unit = "rc_mode" }, \ + { "auto", "Choose mode automatically based on other parameters", \ + 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_AUTO }, 0, 0, FLAGS, .unit = "rc_mode" }, \ + D3D12VA_ENCODE_RC_MODE(CQP, "Constant-quality"), \ + D3D12VA_ENCODE_RC_MODE(CBR, "Constant-bitrate"), \ + D3D12VA_ENCODE_RC_MODE(VBR, "Variable-bitrate"), \ + D3D12VA_ENCODE_RC_MODE(QVBR, "Quality-defined variable-bitrate") + +#endif /* AVCODEC_D3D12VA_ENCODE_H */ diff --git a/libavcodec/d3d12va_encode_hevc.c b/libavcodec/d3d12va_encode_hevc.c new file mode 100644 index 000000000..571ce5738 --- /dev/null +++ b/libavcodec/d3d12va_encode_hevc.c @@ -0,0 +1,1007 @@ +/* + * 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 "avcodec.h" +#include "cbs.h" +#include "cbs_h265.h" +#include "h2645data.h" +#include "h265_profile_level.h" +#include "codec_internal.h" +#include "d3d12va_encode.h" + +typedef struct D3D12VAEncodeHEVCPicture { + int pic_order_cnt; + int64_t last_idr_frame; +} D3D12VAEncodeHEVCPicture; + +typedef struct D3D12VAEncodeHEVCContext { + D3D12VAEncodeContext common; + + // User options. + int qp; + int profile; + int tier; + int level; + + // Writer structures. + H265RawVPS raw_vps; + H265RawSPS raw_sps; + H265RawPPS raw_pps; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_access_unit; +} D3D12VAEncodeHEVCContext; + +typedef struct D3D12VAEncodeHEVCLevel { + int level; + D3D12_VIDEO_ENCODER_LEVELS_HEVC d3d12_level; +} D3D12VAEncodeHEVCLevel; + +static const D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC hevc_config_support_sets[] = +{ + { + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_32x32, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32, + 3, + 3, + }, + { + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_32x32, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32, + 0, + 0, + }, + { + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_32x32, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32, + 2, + 2, + }, + { + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_64x64, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32, + 2, + 2, + }, + { + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_NONE, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_64x64, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4, + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32, + 4, + 4, + }, +}; + +static const D3D12VAEncodeHEVCLevel hevc_levels[] = { + { 30, D3D12_VIDEO_ENCODER_LEVELS_HEVC_1 }, + { 60, D3D12_VIDEO_ENCODER_LEVELS_HEVC_2 }, + { 63, D3D12_VIDEO_ENCODER_LEVELS_HEVC_21 }, + { 90, D3D12_VIDEO_ENCODER_LEVELS_HEVC_3 }, + { 93, D3D12_VIDEO_ENCODER_LEVELS_HEVC_31 }, + { 120, D3D12_VIDEO_ENCODER_LEVELS_HEVC_4 }, + { 123, D3D12_VIDEO_ENCODER_LEVELS_HEVC_41 }, + { 150, D3D12_VIDEO_ENCODER_LEVELS_HEVC_5 }, + { 153, D3D12_VIDEO_ENCODER_LEVELS_HEVC_51 }, + { 156, D3D12_VIDEO_ENCODER_LEVELS_HEVC_52 }, + { 180, D3D12_VIDEO_ENCODER_LEVELS_HEVC_6 }, + { 183, D3D12_VIDEO_ENCODER_LEVELS_HEVC_61 }, + { 186, D3D12_VIDEO_ENCODER_LEVELS_HEVC_62 }, +}; + +static const D3D12_VIDEO_ENCODER_PROFILE_HEVC profile_main = D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN; +static const D3D12_VIDEO_ENCODER_PROFILE_HEVC profile_main10 = D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN10; + +#define D3D_PROFILE_DESC(name) \ + { sizeof(D3D12_VIDEO_ENCODER_PROFILE_HEVC), { .pHEVCProfile = (D3D12_VIDEO_ENCODER_PROFILE_HEVC *)&profile_ ## name } } +static const D3D12VAEncodeProfile d3d12va_encode_hevc_profiles[] = { + { AV_PROFILE_HEVC_MAIN, 8, 3, 1, 1, D3D_PROFILE_DESC(main) }, + { AV_PROFILE_HEVC_MAIN_10, 10, 3, 1, 1, D3D_PROFILE_DESC(main10) }, + { AV_PROFILE_UNKNOWN }, +}; + +static uint8_t d3d12va_encode_hevc_map_cusize(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE cusize) +{ + switch (cusize) { + case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_8x8: return 8; + case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_16x16: return 16; + case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_32x32: return 32; + case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_CUSIZE_64x64: return 64; + default: av_assert0(0); + } + return 0; +} + +static uint8_t d3d12va_encode_hevc_map_tusize(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE tusize) +{ + switch (tusize) { + case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_4x4: return 4; + case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_8x8: return 8; + case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_16x16: return 16; + case D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_TUSIZE_32x32: return 32; + default: av_assert0(0); + } + return 0; +} + +static int d3d12va_encode_hevc_write_access_unit(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *au) +{ + D3D12VAEncodeHEVCContext *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_hevc_add_nal(AVCodecContext *avctx, + CodedBitstreamFragment *au, + void *nal_unit) +{ + H265RawNALUnitHeader *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_hevc_write_sequence_header(AVCodecContext *avctx, + char *data, size_t *data_len) +{ + D3D12VAEncodeHEVCContext *priv = avctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err; + + err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->raw_vps); + if (err < 0) + goto fail; + + err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->raw_sps); + if (err < 0) + goto fail; + + err = d3d12va_encode_hevc_add_nal(avctx, au, &priv->raw_pps); + if (err < 0) + goto fail; + + err = d3d12va_encode_hevc_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_reset(au); + return err; + +} + +static int d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + 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; + 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; + + 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, + .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_HEVC), + .SuggestedProfile.pHEVCProfile = &profile, + .SuggestedLevel.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC), + .SuggestedLevel.pHEVCLevelSetting = &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 some request features. %#x\n", + 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; + } + + memset(vps, 0, sizeof(*vps)); + memset(sps, 0, sizeof(*sps)); + memset(pps, 0, sizeof(*pps)); + + 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 + + vps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_VPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + + 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; + + av_assert0(ctx->res_limits.SubregionBlockPixelsSize % min_cu_size == 0); + + sps->pic_width_in_luma_samples = FFALIGN(base_ctx->surface_width, + ctx->res_limits.SubregionBlockPixelsSize); + sps->pic_height_in_luma_samples = FFALIGN(base_ctx->surface_height, + ctx->res_limits.SubregionBlockPixelsSize); + + if (avctx->width != sps->pic_width_in_luma_samples || + avctx->height != sps->pic_height_in_luma_samples) { + sps->conformance_window_flag = 1; + sps->conf_win_left_offset = 0; + sps->conf_win_right_offset = + (sps->pic_width_in_luma_samples - avctx->width) >> desc->log2_chroma_w; + sps->conf_win_top_offset = 0; + sps->conf_win_bottom_offset = + (sps->pic_height_in_luma_samples - avctx->height) >> desc->log2_chroma_h; + } else { + 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); + sps->log2_diff_max_min_luma_transform_block_size = (uint8_t)(av_log2(max_tu_size) - av_log2(min_tu_size)); + + sps->max_transform_hierarchy_depth_inter = ctx->codec_conf.pHEVCConfig->max_transform_hierarchy_depth_inter; + sps->max_transform_hierarchy_depth_intra = ctx->codec_conf.pHEVCConfig->max_transform_hierarchy_depth_intra; + + sps->amp_enabled_flag = !!(ctx->codec_conf.pHEVCConfig->ConfigurationFlags & + 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; +} + +static int d3d12va_encode_hevc_get_encoder_caps(AVCodecContext *avctx) +{ + int i; + HRESULT hr; + uint8_t min_cu_size, max_cu_size; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC *config; + D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC hevc_caps; + + D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT codec_caps = { + .NodeIndex = 0, + .Codec = D3D12_VIDEO_ENCODER_CODEC_HEVC, + .Profile = ctx->profile->d3d12_profile, + .CodecSupportLimits.DataSize = sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC), + }; + + for (i = 0; i < FF_ARRAY_ELEMS(hevc_config_support_sets); i++) { + hevc_caps = hevc_config_support_sets[i]; + codec_caps.CodecSupportLimits.pHEVCSupport = &hevc_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) + break; + } + + if (i == FF_ARRAY_ELEMS(hevc_config_support_sets)) { + av_log(avctx, AV_LOG_ERROR, "Unsupported codec configuration\n"); + return AVERROR(EINVAL); + } + + ctx->codec_conf.DataSize = sizeof(D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC); + ctx->codec_conf.pHEVCConfig = av_mallocz(ctx->codec_conf.DataSize); + if (!ctx->codec_conf.pHEVCConfig) + return AVERROR(ENOMEM); + + config = ctx->codec_conf.pHEVCConfig; + + config->ConfigurationFlags = D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_NONE; + config->MinLumaCodingUnitSize = hevc_caps.MinLumaCodingUnitSize; + config->MaxLumaCodingUnitSize = hevc_caps.MaxLumaCodingUnitSize; + config->MinLumaTransformUnitSize = hevc_caps.MinLumaTransformUnitSize; + config->MaxLumaTransformUnitSize = hevc_caps.MaxLumaTransformUnitSize; + config->max_transform_hierarchy_depth_inter = hevc_caps.max_transform_hierarchy_depth_inter; + config->max_transform_hierarchy_depth_intra = hevc_caps.max_transform_hierarchy_depth_intra; + + if (hevc_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_SUPPORT || + hevc_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_REQUIRED) + config->ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION; + + if (hevc_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_SAO_FILTER_SUPPORT) + config->ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_SAO_FILTER; + + if (hevc_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_DISABLING_LOOP_FILTER_ACROSS_SLICES_SUPPORT) + config->ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_DISABLE_LOOP_FILTER_ACROSS_SLICES; + + if (hevc_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_TRANSFORM_SKIP_SUPPORT) + config->ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ENABLE_TRANSFORM_SKIPPING; + + if (hevc_caps.SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_P_FRAMES_IMPLEMENTED_AS_LOW_DELAY_B_FRAMES) + ctx->bi_not_empty = 1; + + // block sizes + min_cu_size = d3d12va_encode_hevc_map_cusize(hevc_caps.MinLumaCodingUnitSize); + max_cu_size = d3d12va_encode_hevc_map_cusize(hevc_caps.MaxLumaCodingUnitSize); + + av_log(avctx, AV_LOG_VERBOSE, "Using CTU size %dx%d, " + "min CB size %dx%d.\n", max_cu_size, max_cu_size, + min_cu_size, min_cu_size); + + base_ctx->surface_width = FFALIGN(avctx->width, min_cu_size); + base_ctx->surface_height = FFALIGN(avctx->height, min_cu_size); + + return 0; +} + +static int d3d12va_encode_hevc_configure(AVCodecContext *avctx) +{ + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeHEVCContext *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_HEVC, 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; + } + + // GOP + ctx->gop.DataSize = sizeof(D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC); + ctx->gop.pHEVCGroupOfPictures = av_mallocz(ctx->gop.DataSize); + if (!ctx->gop.pHEVCGroupOfPictures) + return AVERROR(ENOMEM); + + ctx->gop.pHEVCGroupOfPictures->GOPLength = base_ctx->gop_size; + ctx->gop.pHEVCGroupOfPictures->PPicturePeriod = base_ctx->b_per_p + 1; + // Power of 2 + if (base_ctx->gop_size & base_ctx->gop_size - 1 == 0) + ctx->gop.pHEVCGroupOfPictures->log2_max_pic_order_cnt_lsb_minus4 = + FFMAX(av_log2(base_ctx->gop_size) - 4, 0); + else + ctx->gop.pHEVCGroupOfPictures->log2_max_pic_order_cnt_lsb_minus4 = + FFMAX(av_log2(base_ctx->gop_size) - 3, 0); + + return 0; +} + +static int d3d12va_encode_hevc_set_level(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeHEVCContext *priv = avctx->priv_data; + int i; + + ctx->level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC); + ctx->level.pHEVCLevelSetting = av_mallocz(ctx->level.DataSize); + if (!ctx->level.pHEVCLevelSetting) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(hevc_levels); i++) { + if (avctx->level == hevc_levels[i].level) { + ctx->level.pHEVCLevelSetting->Level = hevc_levels[i].d3d12_level; + break; + } + } + + if (i == FF_ARRAY_ELEMS(hevc_levels)) { + av_log(avctx, AV_LOG_ERROR, "Invalid level %d.\n", avctx->level); + return AVERROR(EINVAL); + } + + ctx->level.pHEVCLevelSetting->Tier = priv->raw_vps.profile_tier_level.general_tier_flag == 0 ? + D3D12_VIDEO_ENCODER_TIER_HEVC_MAIN : + D3D12_VIDEO_ENCODER_TIER_HEVC_HIGH; + + return 0; +} + +static void d3d12va_encode_hevc_free_picture_params(D3D12VAEncodePicture *pic) +{ + if (!pic->pic_ctl.pHEVCPicData) + return; + + av_freep(&pic->pic_ctl.pHEVCPicData->pList0ReferenceFrames); + av_freep(&pic->pic_ctl.pHEVCPicData->pList1ReferenceFrames); + av_freep(&pic->pic_ctl.pHEVCPicData->pReferenceFramesReconPictureDescriptors); + av_freep(&pic->pic_ctl.pHEVCPicData); +} + +static int d3d12va_encode_hevc_init_picture_params(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic) +{ + D3D12VAEncodePicture *pic = base_pic->priv; + D3D12VAEncodeHEVCPicture *hpic = base_pic->codec_priv; + FFHWBaseEncodePicture *prev = base_pic->prev; + D3D12VAEncodeHEVCPicture *hprev = prev ? prev->codec_priv : NULL; + D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_HEVC *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_HEVC); + pic->pic_ctl.pHEVCPicData = av_mallocz(pic->pic_ctl.DataSize); + if (!pic->pic_ctl.pHEVCPicData) + 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; + } 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.pHEVCPicData->FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_IDR_FRAME; + break; + case FF_HW_PICTURE_TYPE_I: + pic->pic_ctl.pHEVCPicData->FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_I_FRAME; + break; + case FF_HW_PICTURE_TYPE_P: + pic->pic_ctl.pHEVCPicData->FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_P_FRAME; + break; + case FF_HW_PICTURE_TYPE_B: + pic->pic_ctl.pHEVCPicData->FrameType = D3D12_VIDEO_ENCODER_FRAME_TYPE_HEVC_B_FRAME; + break; + default: + av_assert0(0 && "invalid picture type"); + } + + pic->pic_ctl.pHEVCPicData->slice_pic_parameter_set_id = 0; + pic->pic_ctl.pHEVCPicData->PictureOrderCountNumber = 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.pHEVCPicData->List0ReferenceFramesCount = base_pic->nb_refs[0]; + for (i = 0; i < base_pic->nb_refs[0]; i++) { + FFHWBaseEncodePicture *ref = base_pic->refs[0][i]; + D3D12VAEncodeHEVCPicture *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].IsRefUsedByCurrentPic = TRUE; + 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.pHEVCPicData->List1ReferenceFramesCount = base_pic->nb_refs[1]; + for (i = 0; i < base_pic->nb_refs[1]; i++) { + FFHWBaseEncodePicture *ref = base_pic->refs[1][i]; + D3D12VAEncodeHEVCPicture *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].IsRefUsedByCurrentPic = TRUE; + pd[idx].PictureOrderCountNumber = href->pic_order_cnt; + idx++; + } + } + + pic->pic_ctl.pHEVCPicData->pList0ReferenceFrames = ref_list0; + pic->pic_ctl.pHEVCPicData->pList1ReferenceFrames = ref_list1; + pic->pic_ctl.pHEVCPicData->ReferenceFramesReconPictureDescriptorsCount = idx; + pic->pic_ctl.pHEVCPicData->pReferenceFramesReconPictureDescriptors = pd; + + return 0; +} + +static const D3D12VAEncodeType d3d12va_encode_type_hevc = { + .profiles = d3d12va_encode_hevc_profiles, + + .d3d12_codec = D3D12_VIDEO_ENCODER_CODEC_HEVC, + + .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_hevc_get_encoder_caps, + + .configure = &d3d12va_encode_hevc_configure, + + .set_level = &d3d12va_encode_hevc_set_level, + + .picture_priv_data_size = sizeof(D3D12VAEncodeHEVCPicture), + + .init_sequence_params = &d3d12va_encode_hevc_init_sequence_params, + + .init_picture_params = &d3d12va_encode_hevc_init_picture_params, + + .free_picture_params = &d3d12va_encode_hevc_free_picture_params, + + .write_sequence_header = &d3d12va_encode_hevc_write_sequence_header, +}; + +static int d3d12va_encode_hevc_init(AVCodecContext *avctx) +{ + D3D12VAEncodeContext *ctx = avctx->priv_data; + D3D12VAEncodeHEVCContext *priv = avctx->priv_data; + + ctx->codec = &d3d12va_encode_type_hevc; + + if (avctx->profile == AV_PROFILE_UNKNOWN) + avctx->profile = priv->profile; + if (avctx->level == FF_LEVEL_UNKNOWN) + avctx->level = priv->level; + + if (avctx->level != FF_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_hevc_close(AVCodecContext *avctx) +{ + D3D12VAEncodeHEVCContext *priv = avctx->priv_data; + + ff_cbs_fragment_free(&priv->current_access_unit); + ff_cbs_close(&priv->cbc); + + av_freep(&priv->common.codec_conf.pHEVCConfig); + av_freep(&priv->common.gop.pHEVCGroupOfPictures); + av_freep(&priv->common.level.pHEVCLevelSetting); + + return ff_d3d12va_encode_close(avctx); +} + +#define OFFSET(x) offsetof(D3D12VAEncodeHEVCContext, x) +#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_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_HEVC_MAIN) }, + { PROFILE("main10", AV_PROFILE_HEVC_MAIN_10) }, +#undef PROFILE + + { "tier", "Set tier (general_tier_flag)", + OFFSET(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 = FF_LEVEL_UNKNOWN }, FF_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "level" + { LEVEL("1", 30) }, + { LEVEL("2", 60) }, + { LEVEL("2.1", 63) }, + { LEVEL("3", 90) }, + { LEVEL("3.1", 93) }, + { LEVEL("4", 120) }, + { LEVEL("4.1", 123) }, + { LEVEL("5", 150) }, + { LEVEL("5.1", 153) }, + { LEVEL("5.2", 156) }, + { LEVEL("6", 180) }, + { LEVEL("6.1", 183) }, + { LEVEL("6.2", 186) }, +#undef LEVEL + + { NULL }, +}; + +static const FFCodecDefault d3d12va_encode_hevc_defaults[] = { + { "b", "0" }, + { "bf", "2" }, + { "g", "120" }, + { "i_qfactor", "1" }, + { "i_qoffset", "0" }, + { "b_qfactor", "1" }, + { "b_qoffset", "0" }, + { "qmin", "-1" }, + { "qmax", "-1" }, + { NULL }, +}; + +static const AVClass d3d12va_encode_hevc_class = { + .class_name = "hevc_d3d12va", + .item_name = av_default_item_name, + .option = d3d12va_encode_hevc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_hevc_d3d12va_encoder = { + .p.name = "hevc_d3d12va", + CODEC_LONG_NAME("D3D12VA hevc encoder"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_HEVC, + .priv_data_size = sizeof(D3D12VAEncodeHEVCContext), + .init = &d3d12va_encode_hevc_init, + FF_CODEC_RECEIVE_PACKET_CB(&ff_d3d12va_encode_receive_packet), + .close = &d3d12va_encode_hevc_close, + .p.priv_class = &d3d12va_encode_hevc_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_hevc_defaults, + .p.pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_D3D12, + AV_PIX_FMT_NONE, + }, + .hw_configs = ff_d3d12va_encode_hw_configs, + .p.wrapper_name = "d3d12va", +}; diff --git a/libavcodec/d3d12va_hevc.c b/libavcodec/d3d12va_hevc.c index a4964a05c..7686f0eb6 100644 --- a/libavcodec/d3d12va_hevc.c +++ b/libavcodec/d3d12va_hevc.c @@ -24,8 +24,8 @@ #include "libavutil/avassert.h" #include "libavutil/hwcontext_d3d12va_internal.h" -#include "hevc_data.h" -#include "hevcdec.h" +#include "hevc/data.h" +#include "hevc/hevcdec.h" #include "dxva2_internal.h" #include "d3d12va_decode.h" #include @@ -53,7 +53,7 @@ static int d3d12va_hevc_start_frame(AVCodecContext *avctx, av_unused const uint8 { const HEVCContext *h = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); - HEVCDecodePictureContext *ctx_pic = h->ref->hwaccel_picture_private; + HEVCDecodePictureContext *ctx_pic = h->cur_frame->hwaccel_picture_private; if (!ctx) return -1; @@ -76,7 +76,7 @@ static int d3d12va_hevc_start_frame(AVCodecContext *avctx, av_unused const uint8 static int d3d12va_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { const HEVCContext *h = avctx->priv_data; - const HEVCFrame *current_picture = h->ref; + const HEVCFrame *current_picture = h->cur_frame; HEVCDecodePictureContext *ctx_pic = current_picture->hwaccel_picture_private; unsigned position; @@ -99,7 +99,7 @@ static int d3d12va_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffe static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer) { const HEVCContext *h = avctx->priv_data; - const HEVCFrame *current_picture = h->ref; + const HEVCFrame *current_picture = h->cur_frame; HEVCDecodePictureContext *ctx_pic = current_picture->hwaccel_picture_private; int i; @@ -149,14 +149,14 @@ static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPU static int d3d12va_hevc_end_frame(AVCodecContext *avctx) { HEVCContext *h = avctx->priv_data; - HEVCDecodePictureContext *ctx_pic = h->ref->hwaccel_picture_private; + HEVCDecodePictureContext *ctx_pic = h->cur_frame->hwaccel_picture_private; int scale = ctx_pic->pp.dwCodingParamToolFlags & 1; if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0) return -1; - return ff_d3d12va_common_end_frame(avctx, h->ref->frame, &ctx_pic->pp, sizeof(ctx_pic->pp), + return ff_d3d12va_common_end_frame(avctx, h->cur_frame->f, &ctx_pic->pp, sizeof(ctx_pic->pp), scale ? &ctx_pic->qm : NULL, scale ? sizeof(ctx_pic->qm) : 0, update_input_arguments); } diff --git a/libavcodec/d3d12va_mpeg2.c b/libavcodec/d3d12va_mpeg2.c index 936af5f86..86a7d97b3 100644 --- a/libavcodec/d3d12va_mpeg2.c +++ b/libavcodec/d3d12va_mpeg2.c @@ -44,7 +44,7 @@ static int d3d12va_mpeg2_start_frame(AVCodecContext *avctx, av_unused const uint { const MpegEncContext *s = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); - D3D12DecodePictureContext *ctx_pic = s->current_picture_ptr->hwaccel_picture_private; + D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private; if (!ctx) return -1; @@ -69,7 +69,7 @@ static int d3d12va_mpeg2_start_frame(AVCodecContext *avctx, av_unused const uint static int d3d12va_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { const MpegEncContext *s = avctx->priv_data; - D3D12DecodePictureContext *ctx_pic = s->current_picture_ptr->hwaccel_picture_private; + D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private; if (ctx_pic->slice_count >= MAX_SLICES) { return AVERROR(ERANGE); @@ -88,7 +88,7 @@ static int d3d12va_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buff static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS *input_args, ID3D12Resource *buffer) { const MpegEncContext *s = avctx->priv_data; - D3D12DecodePictureContext *ctx_pic = s->current_picture_ptr->hwaccel_picture_private; + D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private; const int is_field = s->picture_structure != PICT_FRAME; const unsigned mb_count = s->mb_width * (s->mb_height >> is_field); @@ -137,12 +137,12 @@ static int d3d12va_mpeg2_end_frame(AVCodecContext *avctx) { int ret; MpegEncContext *s = avctx->priv_data; - D3D12DecodePictureContext *ctx_pic = s->current_picture_ptr->hwaccel_picture_private; + D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private; if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0) return -1; - ret = ff_d3d12va_common_end_frame(avctx, s->current_picture_ptr->f, &ctx_pic->pp, sizeof(ctx_pic->pp), + ret = ff_d3d12va_common_end_frame(avctx, s->cur_pic.ptr->f, &ctx_pic->pp, sizeof(ctx_pic->pp), &ctx_pic->qm, sizeof(ctx_pic->qm), update_input_arguments); if (!ret) ff_mpeg_draw_horiz_band(s, 0, avctx->height); diff --git a/libavcodec/d3d12va_vc1.c b/libavcodec/d3d12va_vc1.c index 110926be8..dccc0fbff 100644 --- a/libavcodec/d3d12va_vc1.c +++ b/libavcodec/d3d12va_vc1.c @@ -45,7 +45,7 @@ static int d3d12va_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_ { const VC1Context *v = avctx->priv_data; D3D12VADecodeContext *ctx = D3D12VA_DECODE_CONTEXT(avctx); - D3D12DecodePictureContext *ctx_pic = v->s.current_picture_ptr->hwaccel_picture_private; + D3D12DecodePictureContext *ctx_pic = v->s.cur_pic.ptr->hwaccel_picture_private; if (!ctx) return -1; @@ -67,7 +67,7 @@ static int d3d12va_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_ static int d3d12va_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { const VC1Context *v = avctx->priv_data; - D3D12DecodePictureContext *ctx_pic = v->s.current_picture_ptr->hwaccel_picture_private; + D3D12DecodePictureContext *ctx_pic = v->s.cur_pic.ptr->hwaccel_picture_private; if (ctx_pic->slice_count >= MAX_SLICES) { return AVERROR(ERANGE); @@ -93,7 +93,7 @@ static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPU { const VC1Context *v = avctx->priv_data; const MpegEncContext *s = &v->s; - D3D12DecodePictureContext *ctx_pic = s->current_picture_ptr->hwaccel_picture_private; + D3D12DecodePictureContext *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private; D3D12_VIDEO_DECODE_FRAME_ARGUMENT *args = &input_args->FrameArguments[input_args->NumFrameArguments++]; const unsigned mb_count = s->mb_width * (s->mb_height >> v->field_mode); @@ -151,12 +151,12 @@ static int update_input_arguments(AVCodecContext *avctx, D3D12_VIDEO_DECODE_INPU static int d3d12va_vc1_end_frame(AVCodecContext *avctx) { const VC1Context *v = avctx->priv_data; - D3D12DecodePictureContext *ctx_pic = v->s.current_picture_ptr->hwaccel_picture_private; + D3D12DecodePictureContext *ctx_pic = v->s.cur_pic.ptr->hwaccel_picture_private; if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0) return -1; - return ff_d3d12va_common_end_frame(avctx, v->s.current_picture_ptr->f, + return ff_d3d12va_common_end_frame(avctx, v->s.cur_pic.ptr->f, &ctx_pic->pp, sizeof(ctx_pic->pp), NULL, 0, update_input_arguments); diff --git a/libavcodec/dca_core.c b/libavcodec/dca_core.c index 697fc7429..cb1f7b7bb 100644 --- a/libavcodec/dca_core.c +++ b/libavcodec/dca_core.c @@ -19,6 +19,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "dcaadpcm.h" #include "dcadec.h" #include "dcadata.h" diff --git a/libavcodec/dca_lbr.c b/libavcodec/dca_lbr.c index c9c5c0f85..4996c204e 100644 --- a/libavcodec/dca_lbr.c +++ b/libavcodec/dca_lbr.c @@ -21,6 +21,7 @@ #define BITSTREAM_READER_LE #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "dcadec.h" diff --git a/libavcodec/dca_xll.c b/libavcodec/dca_xll.c index 15f9bd919..005a51ed6 100644 --- a/libavcodec/dca_xll.c +++ b/libavcodec/dca_xll.c @@ -20,6 +20,7 @@ #include "avcodec.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "dcadec.h" #include "dcadata.h" #include "dcamath.h" diff --git a/libavcodec/dcaadpcm.c b/libavcodec/dcaadpcm.c index 9f615e379..1d39da9ff 100644 --- a/libavcodec/dcaadpcm.c +++ b/libavcodec/dcaadpcm.c @@ -20,6 +20,7 @@ */ +#include "libavutil/mem.h" #include "dcaadpcm.h" #include "dcaenc.h" #include "dca_core.h" diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c index 8a62d3b87..86d86ea45 100644 --- a/libavcodec/dcadec.c +++ b/libavcodec/dcadec.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/channel_layout.h" #include "libavutil/thread.h" diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c index 192121524..83f13472d 100644 --- a/libavcodec/dcaenc.c +++ b/libavcodec/dcaenc.c @@ -25,13 +25,13 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/thread.h" #include "libavutil/tx.h" #include "avcodec.h" #include "codec_internal.h" -#include "dca.h" #include "dcaadpcm.h" #include "dcamath.h" #include "dca_core.h" diff --git a/libavcodec/dds.c b/libavcodec/dds.c index 89cf225f2..2af7f5c98 100644 --- a/libavcodec/dds.c +++ b/libavcodec/dds.c @@ -711,8 +711,6 @@ FF_ENABLE_DEPRECATION_WARNINGS run_postproc(avctx, frame); /* Frame is ready to be output. */ - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/decode.c b/libavcodec/decode.c index ac18544b2..148af71ac 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -36,6 +36,8 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/mastering_display_metadata.h" +#include "libavutil/mem.h" +#include "libavutil/stereo3d.h" #include "avcodec.h" #include "avcodec_internal.h" @@ -47,13 +49,30 @@ #include "hwaccel_internal.h" #include "hwconfig.h" #include "internal.h" +#include "lcevcdec.h" #include "packet_internal.h" +#include "progressframe.h" #include "refstruct.h" #include "thread.h" +#include "threadprogress.h" typedef struct DecodeContext { AVCodecInternal avci; + /** + * This is set to AV_FRAME_FLAG_KEY for decoders of intra-only formats + * (those whose codec descriptor has AV_CODEC_PROP_INTRA_ONLY set) + * to set the flag generically. + */ + int intra_only_flag; + + /** + * This is set to AV_PICTURE_TYPE_I for intra only video decoders + * and to AV_PICTURE_TYPE_NONE for other decoders. It is used to set + * the AVFrame's pict_type before the decoder receives it. + */ + enum AVPictureType initial_pict_type; + /* to prevent infinite loop on errors when draining */ int nb_draining_errors; @@ -72,6 +91,11 @@ typedef struct DecodeContext { * (global or attached to packets) side data over bytestream. */ uint64_t side_data_pref_mask; + + FFLCEVCContext *lcevc; + int lcevc_frame; + int width; + int height; } DecodeContext; static DecodeContext *decode_ctx(AVCodecInternal *avci) @@ -190,14 +214,17 @@ fail: return ret; } +#if !HAVE_THREADS +#define ff_thread_get_packet(avctx, pkt) (AVERROR_BUG) +#define ff_thread_receive_frame(avctx, frame) (AVERROR_BUG) +#endif + static int decode_get_packet(AVCodecContext *avctx, AVPacket *pkt) { AVCodecInternal *avci = avctx->internal; int ret; ret = av_bsf_receive_packet(avci->bsf, pkt); - if (ret == AVERROR_EOF) - avci->draining = 1; if (ret < 0) return ret; @@ -225,19 +252,26 @@ int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt) if (avci->draining) return AVERROR_EOF; + /* If we are a worker thread, get the next packet from the threading + * context. Otherwise we are the main (user-facing) context, so we get the + * next packet from the input filterchain. + */ + if (avctx->internal->is_frame_mt) + return ff_thread_get_packet(avctx, pkt); + while (1) { int ret = decode_get_packet(avctx, pkt); if (ret == AVERROR(EAGAIN) && (!AVPACKET_IS_EMPTY(avci->buffer_pkt) || dc->draining_started)) { ret = av_bsf_send_packet(avci->bsf, avci->buffer_pkt); - if (ret < 0) { - av_packet_unref(avci->buffer_pkt); - return ret; - } + if (ret >= 0) + continue; - continue; + av_packet_unref(avci->buffer_pkt); } + if (ret == AVERROR_EOF) + avci->draining = 1; return ret; } } @@ -379,6 +413,7 @@ static int discard_samples(AVCodecContext *avctx, AVFrame *frame, int64_t *disca static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame, int64_t *discarded_samples) { AVCodecInternal *avci = avctx->internal; + DecodeContext *dc = decode_ctx(avci); AVPacket *const pkt = avci->in_pkt; const FFCodec *const codec = ffcodec(avctx->codec); int got_frame, consumed; @@ -397,27 +432,24 @@ static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame, return AVERROR_EOF; if (!pkt->data && - !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY || - avctx->active_thread_type & FF_THREAD_FRAME)) + !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) return AVERROR_EOF; got_frame = 0; - if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) { - consumed = ff_thread_decode_frame(avctx, frame, &got_frame, pkt); - } else { - consumed = codec->cb.decode(avctx, frame, &got_frame, pkt); + frame->pict_type = dc->initial_pict_type; + frame->flags |= dc->intra_only_flag; + consumed = codec->cb.decode(avctx, frame, &got_frame, pkt); - if (!(codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS)) - frame->pkt_dts = pkt->dts; - if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) { + 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; + if(!avctx->has_b_frames) + frame->pkt_pos = pkt->pos; FF_ENABLE_DEPRECATION_WARNINGS #endif - } } emms_c(); @@ -585,25 +617,32 @@ static int decode_simple_receive_frame(AVCodecContext *avctx, AVFrame *frame) return 0; } -static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) +int ff_decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) { AVCodecInternal *avci = avctx->internal; DecodeContext *dc = decode_ctx(avci); const FFCodec *const codec = ffcodec(avctx->codec); - int ret, ok; + int ret; av_assert0(!frame->buf[0]); if (codec->cb_type == FF_CODEC_CB_TYPE_RECEIVE_FRAME) { - ret = codec->cb.receive_frame(avctx, frame); - emms_c(); - if (!ret) { - if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) - ret = (frame->flags & AV_FRAME_FLAG_DISCARD) ? AVERROR(EAGAIN) : 0; - else if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) { - int64_t discarded_samples = 0; - ret = discard_samples(avctx, frame, &discarded_samples); + while (1) { + frame->pict_type = dc->initial_pict_type; + frame->flags |= dc->intra_only_flag; + ret = codec->cb.receive_frame(avctx, frame); + emms_c(); + if (!ret) { + if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) { + int64_t discarded_samples = 0; + ret = discard_samples(avctx, frame, &discarded_samples); + } + if (ret == AVERROR(EAGAIN) || (frame->flags & AV_FRAME_FLAG_DISCARD)) { + av_frame_unref(frame); + continue; + } } + break; } } else ret = decode_simple_receive_frame(avctx, frame); @@ -611,6 +650,20 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) if (ret == AVERROR_EOF) avci->draining_done = 1; + return ret; +} + +static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) +{ + 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); + else + ret = ff_decode_receive_frame_internal(avctx, frame); + /* preserve ret */ ok = detect_colorspace(avctx, frame); if (ok < 0) { @@ -624,8 +677,7 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) frame->width = avctx->width; if (!frame->height) frame->height = avctx->height; - } else - frame->flags |= AV_FRAME_FLAG_KEY; + } ret = fill_frame_props(avctx, frame); if (ret < 0) { @@ -1355,14 +1407,93 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) return ret; } +static const AVPacketSideData* +packet_side_data_get(const AVPacketSideData *sd, int nb_sd, + enum AVPacketSideDataType type) +{ + for (int i = 0; i < nb_sd; i++) + if (sd[i].type == type) + return &sd[i]; + + return NULL; +} + const AVPacketSideData *ff_get_coded_side_data(const AVCodecContext *avctx, enum AVPacketSideDataType type) { - for (int i = 0; i < avctx->nb_coded_side_data; i++) - if (avctx->coded_side_data[i].type == type) - return &avctx->coded_side_data[i]; + return packet_side_data_get(avctx->coded_side_data, avctx->nb_coded_side_data, type); +} - return NULL; +static int side_data_stereo3d_merge(AVFrameSideData *sd_frame, + const AVPacketSideData *sd_pkt) +{ + const AVStereo3D *src; + AVStereo3D *dst; + int ret; + + ret = av_buffer_make_writable(&sd_frame->buf); + if (ret < 0) + return ret; + sd_frame->data = sd_frame->buf->data; + + dst = ( AVStereo3D*)sd_frame->data; + src = (const AVStereo3D*)sd_pkt->data; + + if (dst->type == AV_STEREO3D_UNSPEC) + dst->type = src->type; + + if (dst->view == AV_STEREO3D_VIEW_UNSPEC) + dst->view = src->view; + + if (dst->primary_eye == AV_PRIMARY_EYE_NONE) + dst->primary_eye = src->primary_eye; + + if (!dst->baseline) + dst->baseline = src->baseline; + + if (!dst->horizontal_disparity_adjustment.num) + dst->horizontal_disparity_adjustment = src->horizontal_disparity_adjustment; + + if (!dst->horizontal_field_of_view.num) + dst->horizontal_field_of_view = src->horizontal_field_of_view; + + return 0; +} + +static int side_data_map(AVFrame *dst, + const AVPacketSideData *sd_src, int nb_sd_src, + const SideDataMap *map) + +{ + for (int i = 0; map[i].packet < AV_PKT_DATA_NB; i++) { + const enum AVPacketSideDataType type_pkt = map[i].packet; + const enum AVFrameSideDataType type_frame = map[i].frame; + const AVPacketSideData *sd_pkt; + AVFrameSideData *sd_frame; + + sd_pkt = packet_side_data_get(sd_src, nb_sd_src, type_pkt); + if (!sd_pkt) + continue; + + sd_frame = av_frame_get_side_data(dst, type_frame); + if (sd_frame) { + if (type_frame == AV_FRAME_DATA_STEREO3D) { + int ret = side_data_stereo3d_merge(sd_frame, sd_pkt); + if (ret < 0) + return ret; + } + + continue; + } + + 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); + } + + return 0; } static int add_metadata_from_side_data(const AVPacket *avpkt, AVFrame *frame) @@ -1377,35 +1508,21 @@ static int add_metadata_from_side_data(const AVPacket *avpkt, AVFrame *frame) return av_packet_unpack_dictionary(side_metadata, size, frame_md); } -static const struct { - enum AVPacketSideDataType packet; - enum AVFrameSideDataType frame; -} sd_global_map[] = { - { AV_PKT_DATA_REPLAYGAIN , AV_FRAME_DATA_REPLAYGAIN }, - { AV_PKT_DATA_DISPLAYMATRIX, AV_FRAME_DATA_DISPLAYMATRIX }, - { AV_PKT_DATA_SPHERICAL, AV_FRAME_DATA_SPHERICAL }, - { AV_PKT_DATA_STEREO3D, AV_FRAME_DATA_STEREO3D }, - { AV_PKT_DATA_AUDIO_SERVICE_TYPE, AV_FRAME_DATA_AUDIO_SERVICE_TYPE }, - { AV_PKT_DATA_MASTERING_DISPLAY_METADATA, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA }, - { 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 }, -}; - int ff_decode_frame_props_from_pkt(const AVCodecContext *avctx, AVFrame *frame, const AVPacket *pkt) { - static const struct { - enum AVPacketSideDataType packet; - enum AVFrameSideDataType frame; - } sd[] = { + static const SideDataMap sd[] = { { AV_PKT_DATA_A53_CC, AV_FRAME_DATA_A53_CC }, { AV_PKT_DATA_AFD, AV_FRAME_DATA_AFD }, { AV_PKT_DATA_DYNAMIC_HDR10_PLUS, AV_FRAME_DATA_DYNAMIC_HDR_PLUS }, { AV_PKT_DATA_S12M_TIMECODE, AV_FRAME_DATA_S12M_TIMECODE }, { AV_PKT_DATA_SKIP_SAMPLES, AV_FRAME_DATA_SKIP_SAMPLES }, + { AV_PKT_DATA_LCEVC, AV_FRAME_DATA_LCEVC }, + { AV_PKT_DATA_NB } }; + int ret = 0; + frame->pts = pkt->pts; frame->duration = pkt->duration; #if FF_API_FRAME_PKT @@ -1415,37 +1532,18 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif - for (int i = 0; i < FF_ARRAY_ELEMS(sd_global_map); i++) { - size_t size; - const uint8_t *packet_sd = av_packet_get_side_data(pkt, sd_global_map[i].packet, &size); - if (packet_sd) { - AVFrameSideData *frame_sd; + ret = side_data_map(frame, pkt->side_data, pkt->side_data_elems, ff_sd_global_map); + if (ret < 0) + return ret; - frame_sd = av_frame_new_side_data(frame, sd_global_map[i].frame, size); - if (!frame_sd) - return AVERROR(ENOMEM); - memcpy(frame_sd->data, packet_sd, size); - } - } - for (int i = 0; i < FF_ARRAY_ELEMS(sd); i++) { - size_t size; - uint8_t *packet_sd = av_packet_get_side_data(pkt, sd[i].packet, &size); - if (packet_sd) { - AVFrameSideData *frame_sd = av_frame_new_side_data(frame, - sd[i].frame, - size); - if (!frame_sd) - return AVERROR(ENOMEM); + ret = side_data_map(frame, pkt->side_data, pkt->side_data_elems, sd); + if (ret < 0) + return ret; - memcpy(frame_sd->data, packet_sd, size); - } - } add_metadata_from_side_data(pkt, frame); if (pkt->flags & AV_PKT_FLAG_DISCARD) { frame->flags |= AV_FRAME_FLAG_DISCARD; - } else { - frame->flags = (frame->flags & ~AV_FRAME_FLAG_DISCARD); } if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { @@ -1462,19 +1560,10 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame) { int ret; - for (int i = 0; i < FF_ARRAY_ELEMS(sd_global_map); i++) { - const AVPacketSideData *packet_sd = ff_get_coded_side_data(avctx, - sd_global_map[i].packet); - if (packet_sd) { - AVFrameSideData *frame_sd = av_frame_new_side_data(frame, - sd_global_map[i].frame, - packet_sd->size); - if (!frame_sd) - return AVERROR(ENOMEM); - - memcpy(frame_sd->data, packet_sd->data, packet_sd->size); - } - } + ret = side_data_map(frame, avctx->coded_side_data, avctx->nb_coded_side_data, + ff_sd_global_map); + 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; @@ -1566,6 +1655,40 @@ int ff_attach_decode_data(AVFrame *frame) return 0; } +static void update_frame_props(AVCodecContext *avctx, AVFrame *frame) +{ + AVCodecInternal *avci = avctx->internal; + DecodeContext *dc = decode_ctx(avci); + + dc->lcevc_frame = dc->lcevc && avctx->codec_type == AVMEDIA_TYPE_VIDEO && + av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); + + if (dc->lcevc_frame) { + dc->width = frame->width; + dc->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); + } +} + +static void attach_post_process_data(AVCodecContext *avctx, AVFrame *frame) +{ + AVCodecInternal *avci = avctx->internal; + DecodeContext *dc = decode_ctx(avci); + + if (dc->lcevc_frame) { + FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + + fdd->post_process_opaque = ff_refstruct_ref(dc->lcevc); + fdd->post_process_opaque_free = ff_lcevc_unref; + fdd->post_process = ff_lcevc_process; + + frame->width = dc->width; + frame->height = dc->height; + } + dc->lcevc_frame = 0; +} + int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) { const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel); @@ -1609,8 +1732,10 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) ret = hwaccel->alloc_frame(avctx, frame); goto end; } - } else + } else { avctx->sw_pix_fmt = avctx->pix_fmt; + update_frame_props(avctx, frame); + } ret = avctx->get_buffer2(avctx, frame, flags); if (ret < 0) @@ -1622,6 +1747,8 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) if (ret < 0) goto fail; + attach_post_process_data(avctx, frame); + end: if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions && !(ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) { @@ -1645,6 +1772,9 @@ static int reget_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flag av_assert0(avctx->codec_type == AVMEDIA_TYPE_VIDEO); + // make sure the discard flag does not persist + frame->flags &= ~AV_FRAME_FLAG_DISCARD; + if (frame->data[0] && (frame->width != avctx->width || frame->height != avctx->height || frame->format != avctx->pix_fmt)) { av_log(avctx, AV_LOG_WARNING, "Picture changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s in reget buffer()\n", frame->width, frame->height, av_get_pix_fmt_name(frame->format), avctx->width, avctx->height, av_get_pix_fmt_name(avctx->pix_fmt)); @@ -1654,6 +1784,8 @@ static int reget_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flag if (!frame->data[0]) return ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF); + av_frame_side_data_free(&frame->side_data, &frame->nb_side_data); + if ((flags & FF_REGET_BUFFER_FLAG_READONLY) || av_frame_is_writable(frame)) return ff_decode_frame_props(avctx, frame); @@ -1683,12 +1815,139 @@ int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) return ret; } +typedef struct ProgressInternal { + ThreadProgress progress; + struct AVFrame *f; +} ProgressInternal; + +static void check_progress_consistency(const ProgressFrame *f) +{ + av_assert1(!!f->f == !!f->progress); + av_assert1(!f->progress || f->progress->f == f->f); +} + +int ff_progress_frame_alloc(AVCodecContext *avctx, ProgressFrame *f) +{ + FFRefStructPool *pool = avctx->internal->progress_frame_pool; + + av_assert1(!f->f && !f->progress); + + f->progress = ff_refstruct_pool_get(pool); + if (!f->progress) + return AVERROR(ENOMEM); + + f->f = f->progress->f; + return 0; +} + +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; + } + + ret = ff_thread_get_buffer(avctx, f->progress->f, flags); + if (ret < 0) { + f->f = NULL; + ff_refstruct_unref(&f->progress); + return ret; + } + return 0; +} + +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); +} + +void ff_progress_frame_unref(ProgressFrame *f) +{ + check_progress_consistency(f); + f->f = NULL; + ff_refstruct_unref(&f->progress); +} + +void ff_progress_frame_replace(ProgressFrame *dst, const ProgressFrame *src) +{ + if (dst == src) + return; + ff_progress_frame_unref(dst); + check_progress_consistency(src); + if (src->f) + ff_progress_frame_ref(dst, src); +} + +void ff_progress_frame_report(ProgressFrame *f, int n) +{ + ff_thread_progress_report(&f->progress->progress, n); +} + +void ff_progress_frame_await(const ProgressFrame *f, int n) +{ + ff_thread_progress_await(&f->progress->progress, n); +} + +#if !HAVE_THREADS +enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) +{ + return FF_THREAD_NO_FRAME_THREADING; +} +#endif /* !HAVE_THREADS */ + +static av_cold int progress_frame_pool_init_cb(FFRefStructOpaque opaque, void *obj) +{ + const AVCodecContext *avctx = opaque.nc; + ProgressInternal *progress = obj; + int ret; + + ret = ff_thread_progress_init(&progress->progress, avctx->active_thread_type & FF_THREAD_FRAME); + if (ret < 0) + return ret; + + progress->f = av_frame_alloc(); + if (!progress->f) + return AVERROR(ENOMEM); + + return 0; +} + +static void progress_frame_pool_reset_cb(FFRefStructOpaque unused, void *obj) +{ + ProgressInternal *progress = obj; + + ff_thread_progress_reset(&progress->progress); + av_frame_unref(progress->f); +} + +static av_cold void progress_frame_pool_free_entry_cb(FFRefStructOpaque opaque, void *obj) +{ + ProgressInternal *progress = obj; + + ff_thread_progress_destroy(&progress->progress); + av_frame_free(&progress->f); +} + int ff_decode_preinit(AVCodecContext *avctx) { AVCodecInternal *avci = avctx->internal; DecodeContext *dc = decode_ctx(avci); int ret = 0; + dc->initial_pict_type = AV_PICTURE_TYPE_NONE; + if (avctx->codec_descriptor->props & AV_CODEC_PROP_INTRA_ONLY) { + dc->intra_only_flag = AV_FRAME_FLAG_KEY; + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) + dc->initial_pict_type = AV_PICTURE_TYPE_I; + } + /* if the decoder init function was already called previously, * free the already allocated subtitle_header before overwriting it */ av_freep(&avctx->subtitle_header); @@ -1759,9 +2018,9 @@ int ff_decode_preinit(AVCodecContext *avctx) return AVERROR(EINVAL); } - for (unsigned j = 0; j < FF_ARRAY_ELEMS(sd_global_map); j++) { - if (sd_global_map[j].packet == val) { - val = sd_global_map[j].frame; + for (unsigned j = 0; ff_sd_global_map[j].packet < AV_PKT_DATA_NB; j++) { + if (ff_sd_global_map[j].packet == val) { + val = ff_sd_global_map[j].frame; // this code will need to be changed when we have more than // 64 frame side data types @@ -1781,10 +2040,26 @@ int ff_decode_preinit(AVCodecContext *avctx) if (!avci->in_pkt || !avci->last_pkt_props) return AVERROR(ENOMEM); + 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, + avctx, progress_frame_pool_init_cb, + progress_frame_pool_reset_cb, + progress_frame_pool_free_entry_cb, NULL); + if (!avci->progress_frame_pool) + return AVERROR(ENOMEM); + } ret = decode_bsfs_init(avctx); if (ret < 0) return ret; + if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS)) { + ret = ff_lcevc_alloc(&dc->lcevc); + if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) + return ret; + } + #if FF_API_DROPCHANGED if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n"); @@ -1800,16 +2075,16 @@ int ff_decode_preinit(AVCodecContext *avctx) * @retval 0 side data of this type can be added to frame * @retval 1 side data of this type should not be added to frame */ -static int side_data_pref(const AVCodecContext *avctx, AVFrame *frame, - enum AVFrameSideDataType type) +static int side_data_pref(const AVCodecContext *avctx, AVFrameSideData ***sd, + int *nb_sd, enum AVFrameSideDataType type) { DecodeContext *dc = decode_ctx(avctx->internal); // Note: could be skipped for `type` without corresponding packet sd - if (av_frame_get_side_data(frame, type)) { + if (av_frame_side_data_get(*sd, *nb_sd, type)) { if (dc->side_data_pref_mask & (1ULL << type)) return 1; - av_frame_remove_side_data(frame, type); + av_frame_side_data_remove(sd, nb_sd, type); } return 0; @@ -1822,7 +2097,7 @@ int ff_frame_new_side_data(const AVCodecContext *avctx, AVFrame *frame, { AVFrameSideData *sd; - if (side_data_pref(avctx, frame, type)) { + if (side_data_pref(avctx, &frame->side_data, &frame->nb_side_data, type)) { if (psd) *psd = NULL; return 0; @@ -1835,34 +2110,71 @@ int ff_frame_new_side_data(const AVCodecContext *avctx, AVFrame *frame, return sd ? 0 : AVERROR(ENOMEM); } -int ff_frame_new_side_data_from_buf(const AVCodecContext *avctx, - AVFrame *frame, enum AVFrameSideDataType type, - AVBufferRef **buf, AVFrameSideData **psd) +int ff_frame_new_side_data_from_buf_ext(const AVCodecContext *avctx, + AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type, + AVBufferRef **buf) { - AVFrameSideData *sd = NULL; int ret = 0; - if (side_data_pref(avctx, frame, type)) + if (side_data_pref(avctx, sd, nb_sd, type)) goto finish; - sd = av_frame_new_side_data_from_buf(frame, type, *buf); - if (sd) - *buf = NULL; - else + if (!av_frame_side_data_add(sd, nb_sd, type, buf, 0)) ret = AVERROR(ENOMEM); finish: av_buffer_unref(buf); - if (psd) - *psd = sd; return ret; } +int ff_frame_new_side_data_from_buf(const AVCodecContext *avctx, + AVFrame *frame, enum AVFrameSideDataType type, + AVBufferRef **buf) +{ + return ff_frame_new_side_data_from_buf_ext(avctx, + &frame->side_data, &frame->nb_side_data, + type, buf); +} + +int ff_decode_mastering_display_new_ext(const AVCodecContext *avctx, + AVFrameSideData ***sd, int *nb_sd, + struct AVMasteringDisplayMetadata **mdm) +{ + AVBufferRef *buf; + size_t size; + + if (side_data_pref(avctx, sd, nb_sd, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA)) { + *mdm = NULL; + return 0; + } + + *mdm = av_mastering_display_metadata_alloc_size(&size); + if (!*mdm) + return AVERROR(ENOMEM); + + buf = av_buffer_create((uint8_t *)*mdm, size, NULL, NULL, 0); + if (!buf) { + av_freep(mdm); + return AVERROR(ENOMEM); + } + + if (!av_frame_side_data_add(sd, nb_sd, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA, + &buf, 0)) { + *mdm = NULL; + av_buffer_unref(&buf); + return AVERROR(ENOMEM); + } + + return 0; +} + int ff_decode_mastering_display_new(const AVCodecContext *avctx, AVFrame *frame, AVMasteringDisplayMetadata **mdm) { - if (side_data_pref(avctx, frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA)) { + if (side_data_pref(avctx, &frame->side_data, &frame->nb_side_data, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA)) { *mdm = NULL; return 0; } @@ -1871,10 +2183,43 @@ int ff_decode_mastering_display_new(const AVCodecContext *avctx, AVFrame *frame, return *mdm ? 0 : AVERROR(ENOMEM); } +int ff_decode_content_light_new_ext(const AVCodecContext *avctx, + AVFrameSideData ***sd, int *nb_sd, + AVContentLightMetadata **clm) +{ + AVBufferRef *buf; + size_t size; + + if (side_data_pref(avctx, sd, nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL)) { + *clm = NULL; + return 0; + } + + *clm = av_content_light_metadata_alloc(&size); + if (!*clm) + return AVERROR(ENOMEM); + + buf = av_buffer_create((uint8_t *)*clm, size, NULL, NULL, 0); + if (!buf) { + av_freep(clm); + return AVERROR(ENOMEM); + } + + if (!av_frame_side_data_add(sd, nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + &buf, 0)) { + *clm = NULL; + av_buffer_unref(&buf); + return AVERROR(ENOMEM); + } + + return 0; +} + int ff_decode_content_light_new(const AVCodecContext *avctx, AVFrame *frame, AVContentLightMetadata **clm) { - if (side_data_pref(avctx, frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL)) { + if (side_data_pref(avctx, &frame->side_data, &frame->nb_side_data, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL)) { *clm = NULL; return 0; } @@ -1938,7 +2283,8 @@ void ff_decode_flush_buffers(AVCodecContext *avctx) dc->pts_correction_last_pts = dc->pts_correction_last_dts = INT64_MIN; - av_bsf_flush(avci->bsf); + if (avci->bsf) + av_bsf_flush(avci->bsf); dc->nb_draining_errors = 0; dc->draining_started = 0; @@ -1948,3 +2294,19 @@ AVCodecInternal *ff_decode_internal_alloc(void) { return av_mallocz(sizeof(DecodeContext)); } + +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); + + ff_refstruct_replace(&dst_dc->lcevc, src_dc->lcevc); +} + +void ff_decode_internal_uninit(AVCodecContext *avctx) +{ + AVCodecInternal *avci = avctx->internal; + DecodeContext *dc = decode_ctx(avci); + + ff_refstruct_unref(&dc->lcevc); +} diff --git a/libavcodec/decode.h b/libavcodec/decode.h index 4ffbd9db8..2c3719a8d 100644 --- a/libavcodec/decode.h +++ b/libavcodec/decode.h @@ -173,7 +173,16 @@ int ff_frame_new_side_data(const AVCodecContext *avctx, AVFrame *frame, */ int ff_frame_new_side_data_from_buf(const AVCodecContext *avctx, AVFrame *frame, enum AVFrameSideDataType type, - AVBufferRef **buf, AVFrameSideData **sd); + AVBufferRef **buf); + +/** + * Same as `ff_frame_new_side_data_from_buf`, but taking a AVFrameSideData + * array directly instead of an AVFrame. + */ +int ff_frame_new_side_data_from_buf_ext(const AVCodecContext *avctx, + AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type, + AVBufferRef **buf); struct AVMasteringDisplayMetadata; struct AVContentLightMetadata; @@ -187,6 +196,14 @@ struct AVContentLightMetadata; int ff_decode_mastering_display_new(const AVCodecContext *avctx, AVFrame *frame, struct AVMasteringDisplayMetadata **mdm); +/** + * Same as `ff_decode_mastering_display_new`, but taking a AVFrameSideData + * array directly instead of an AVFrame. + */ +int ff_decode_mastering_display_new_ext(const AVCodecContext *avctx, + AVFrameSideData ***sd, int *nb_sd, + struct AVMasteringDisplayMetadata **mdm); + /** * Wrapper around av_content_light_metadata_create_side_data(), which * rejects side data overridden by the demuxer. Returns 0 on success, and a @@ -196,4 +213,11 @@ int ff_decode_mastering_display_new(const AVCodecContext *avctx, AVFrame *frame, int ff_decode_content_light_new(const AVCodecContext *avctx, AVFrame *frame, struct AVContentLightMetadata **clm); +/** + * Same as `ff_decode_content_light_new`, but taking a AVFrameSideData + * array directly instead of an AVFrame. + */ +int ff_decode_content_light_new_ext(const AVCodecContext *avctx, + AVFrameSideData ***sd, int *nb_sd, + struct AVContentLightMetadata **clm); #endif /* AVCODEC_DECODE_H */ diff --git a/libavcodec/defs.h b/libavcodec/defs.h index 00d840ec1..24250f8af 100644 --- a/libavcodec/defs.h +++ b/libavcodec/defs.h @@ -73,6 +73,7 @@ #define AV_PROFILE_AAC_HE_V2 28 #define AV_PROFILE_AAC_LD 22 #define AV_PROFILE_AAC_ELD 38 +#define AV_PROFILE_AAC_USAC 41 #define AV_PROFILE_MPEG2_AAC_LOW 128 #define AV_PROFILE_MPEG2_AAC_HE 131 @@ -159,6 +160,7 @@ #define AV_PROFILE_HEVC_MAIN_10 2 #define AV_PROFILE_HEVC_MAIN_STILL_PICTURE 3 #define AV_PROFILE_HEVC_REXT 4 +#define AV_PROFILE_HEVC_MULTIVIEW_MAIN 6 #define AV_PROFILE_HEVC_SCC 9 #define AV_PROFILE_VVC_MAIN_10 1 diff --git a/libavcodec/dirac.c b/libavcodec/dirac.c index 473630497..7fac7409a 100644 --- a/libavcodec/dirac.c +++ b/libavcodec/dirac.c @@ -28,6 +28,7 @@ #include "config.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "dirac.h" diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c index 24c7df000..76209aebb 100644 --- a/libavcodec/diracdec.c +++ b/libavcodec/diracdec.c @@ -26,6 +26,7 @@ * @author Marco Gerards , David Conrad, Jordi Ortiz */ +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/pixdesc.h" #include "libavutil/thread.h" @@ -36,7 +37,6 @@ #include "golomb.h" #include "dirac_arith.h" #include "dirac_vlc.h" -#include "mpegpicture.h" #include "mpegvideoencdsp.h" #include "dirac_dwt.h" #include "dirac.h" @@ -44,6 +44,8 @@ #include "diracdsp.h" #include "videodsp.h" +#define EDGE_WIDTH 16 + /** * The spec limits this to 3 for frame coding, but in practice can be as high as 6 */ @@ -349,7 +351,7 @@ static int alloc_buffers(DiracContext *s, int stride) return 0; } -static void free_sequence_buffers(DiracContext *s) +static av_cold void free_sequence_buffers(DiracContext *s) { int i, j, k; @@ -401,11 +403,8 @@ static av_cold int dirac_decode_init(AVCodecContext *avctx) for (i = 0; i < MAX_FRAMES; i++) { s->all_frames[i].avframe = av_frame_alloc(); - if (!s->all_frames[i].avframe) { - while (i > 0) - av_frame_free(&s->all_frames[--i].avframe); + if (!s->all_frames[i].avframe) return AVERROR(ENOMEM); - } } ret = ff_thread_once(&dirac_arith_init, ff_dirac_init_arith_tables); if (ret != 0) @@ -414,7 +413,7 @@ static av_cold int dirac_decode_init(AVCodecContext *avctx) return 0; } -static void dirac_decode_flush(AVCodecContext *avctx) +static av_cold void dirac_decode_flush(AVCodecContext *avctx) { DiracContext *s = avctx->priv_data; free_sequence_buffers(s); @@ -427,7 +426,9 @@ static av_cold int dirac_decode_end(AVCodecContext *avctx) DiracContext *s = avctx->priv_data; int i; - dirac_decode_flush(avctx); + // Necessary in case dirac_decode_init() failed + if (s->all_frames[MAX_FRAMES - 1].avframe) + free_sequence_buffers(s); for (i = 0; i < MAX_FRAMES; i++) av_frame_free(&s->all_frames[i].avframe); @@ -2369,4 +2370,5 @@ const FFCodec ff_dirac_decoder = { FF_CODEC_DECODE_CB(dirac_decode_frame), .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_DR1, .flush = dirac_decode_flush, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/dnxhddec.c b/libavcodec/dnxhddec.c index 703d0e341..fe0809a5f 100644 --- a/libavcodec/dnxhddec.c +++ b/libavcodec/dnxhddec.c @@ -24,6 +24,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/pixdesc.h" @@ -654,8 +655,6 @@ decode_coding_unit: if (first_field) { if ((ret = ff_thread_get_buffer(avctx, picture, 0)) < 0) return ret; - picture->pict_type = AV_PICTURE_TYPE_I; - picture->flags |= AV_FRAME_FLAG_KEY; } ctx->buf_size = buf_size - ctx->data_offset; diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c index 2316083b5..b12a2e885 100644 --- a/libavcodec/dnxhdenc.c +++ b/libavcodec/dnxhdenc.c @@ -25,6 +25,7 @@ #include "libavutil/attributes.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" @@ -419,7 +420,7 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) avctx->bits_per_raw_sample = ctx->bit_depth; - ff_blockdsp_init(&ctx->bdsp); + ff_blockdsp_init(&ctx->m.bdsp); ff_fdctdsp_init(&ctx->m.fdsp, avctx); ff_mpv_idct_init(&ctx->m); ff_mpegvideoencdsp_init(&ctx->m.mpvencdsp, avctx); @@ -429,9 +430,6 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) if (ctx->profile != AV_PROFILE_DNXHD) ff_videodsp_init(&ctx->m.vdsp, ctx->bit_depth); - if (!ctx->m.dct_quantize) - ctx->m.dct_quantize = ff_dct_quantize_c; - if (ctx->is_444 || ctx->profile == AV_PROFILE_DNXHR_HQX) { ctx->m.dct_quantize = dnxhd_10bit_dct_quantize_444; ctx->get_pixels_8x4_sym = dnxhd_10bit_get_pixels_8x4_sym; @@ -558,7 +556,7 @@ static int dnxhd_write_header(AVCodecContext *avctx, uint8_t *buf) return 0; } -static av_always_inline void dnxhd_encode_dc(DNXHDEncContext *ctx, int diff) +static av_always_inline void dnxhd_encode_dc(PutBitContext *pb, DNXHDEncContext *ctx, int diff) { int nbits; if (diff < 0) { @@ -567,19 +565,19 @@ static av_always_inline void dnxhd_encode_dc(DNXHDEncContext *ctx, int diff) } else { nbits = av_log2_16bit(2 * diff); } - put_bits(&ctx->m.pb, ctx->cid_table->dc_bits[nbits] + nbits, + put_bits(pb, ctx->cid_table->dc_bits[nbits] + nbits, (ctx->cid_table->dc_codes[nbits] << nbits) + - av_mod_uintp2(diff, nbits)); + av_zero_extend(diff, nbits)); } static av_always_inline -void dnxhd_encode_block(DNXHDEncContext *ctx, int16_t *block, - int last_index, int n) +void dnxhd_encode_block(PutBitContext *pb, DNXHDEncContext *ctx, + int16_t *block, int last_index, int n) { int last_non_zero = 0; int slevel, i, j; - dnxhd_encode_dc(ctx, block[0] - ctx->m.last_dc[n]); + dnxhd_encode_dc(pb, ctx, block[0] - ctx->m.last_dc[n]); ctx->m.last_dc[n] = block[0]; for (i = 1; i <= last_index; i++) { @@ -588,14 +586,14 @@ void dnxhd_encode_block(DNXHDEncContext *ctx, int16_t *block, if (slevel) { int run_level = i - last_non_zero - 1; int rlevel = slevel * (1 << 1) | !!run_level; - put_bits(&ctx->m.pb, ctx->vlc_bits[rlevel], ctx->vlc_codes[rlevel]); + put_bits(pb, ctx->vlc_bits[rlevel], ctx->vlc_codes[rlevel]); if (run_level) - put_bits(&ctx->m.pb, ctx->run_bits[run_level], + put_bits(pb, ctx->run_bits[run_level], ctx->run_codes[run_level]); last_non_zero = i; } } - put_bits(&ctx->m.pb, ctx->vlc_bits[0], ctx->vlc_codes[0]); // EOB + put_bits(pb, ctx->vlc_bits[0], ctx->vlc_codes[0]); // EOB } static av_always_inline @@ -770,10 +768,10 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y) ptr_v + dct_uv_offset, uvlinesize); } else { - ctx->bdsp.clear_block(ctx->blocks[4]); - ctx->bdsp.clear_block(ctx->blocks[5]); - ctx->bdsp.clear_block(ctx->blocks[6]); - ctx->bdsp.clear_block(ctx->blocks[7]); + 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]); } } else { pdsp->get_pixels(ctx->blocks[4], @@ -878,9 +876,10 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, int jobnr, int threadnr) { DNXHDEncContext *ctx = avctx->priv_data; + PutBitContext pb0, *const pb = &pb0; int mb_y = jobnr, mb_x; ctx = ctx->thread[threadnr]; - init_put_bits(&ctx->m.pb, (uint8_t *)arg + ctx->data_offset + ctx->slice_offs[jobnr], + init_put_bits(pb, (uint8_t *)arg + ctx->data_offset + ctx->slice_offs[jobnr], ctx->slice_size[jobnr]); ctx->m.last_dc[0] = @@ -891,8 +890,8 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, int qscale = ctx->mb_qscale[mb]; int i; - put_bits(&ctx->m.pb, 11, qscale); - put_bits(&ctx->m.pb, 1, avctx->pix_fmt == AV_PIX_FMT_YUV444P10); + put_bits(pb, 11, qscale); + put_bits(pb, 1, avctx->pix_fmt == AV_PIX_FMT_YUV444P10); dnxhd_get_blocks(ctx, mb_x, mb_y); @@ -903,13 +902,11 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg, ctx->is_444 ? (((i >> 1) % 3) < 1 ? 0 : 4): 4 & (2*i), qscale, &overflow); - dnxhd_encode_block(ctx, block, last_index, n); + dnxhd_encode_block(pb, ctx, block, last_index, n); } } - if (put_bits_count(&ctx->m.pb) & 31) - put_bits(&ctx->m.pb, 32 - (put_bits_count(&ctx->m.pb) & 31), 0); - flush_put_bits(&ctx->m.pb); - memset(put_bits_ptr(&ctx->m.pb), 0, put_bytes_left(&ctx->m.pb, 0)); + flush_put_bits(pb); + memset(put_bits_ptr(pb), 0, put_bytes_left(pb, 0)); return 0; } @@ -1370,6 +1367,7 @@ const FFCodec ff_dnxhd_encoder = { AV_PIX_FMT_GBRP10, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &dnxhd_class, .defaults = dnxhd_defaults, .p.profiles = NULL_IF_CONFIG_SMALL(ff_dnxhd_profiles), diff --git a/libavcodec/dnxhdenc.h b/libavcodec/dnxhdenc.h index 72077d631..00d486bab 100644 --- a/libavcodec/dnxhdenc.h +++ b/libavcodec/dnxhdenc.h @@ -43,7 +43,6 @@ typedef struct RCEntry { typedef struct DNXHDEncContext { AVClass *class; - BlockDSPContext bdsp; MpegEncContext m; ///< Used for quantization dsp functions int cid; diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c index 31c64fb06..5130a9598 100644 --- a/libavcodec/dovi_rpu.c +++ b/libavcodec/dovi_rpu.c @@ -2,7 +2,7 @@ * Dolby Vision RPU decoder * * Copyright (C) 2021 Jan Ekström - * Copyright (C) 2021 Niklas Haas + * Copyright (C) 2021-2024 Niklas Haas * * This file is part of FFmpeg. * @@ -21,30 +21,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/buffer.h" +#include "libavutil/mem.h" #include "dovi_rpu.h" -#include "golomb.h" -#include "get_bits.h" #include "refstruct.h" -enum { - RPU_COEFF_FIXED = 0, - RPU_COEFF_FLOAT = 1, -}; - -/** - * Private contents of vdr. - */ -typedef struct DOVIVdr { - AVDOVIDataMapping mapping; - AVDOVIColorMetadata color; -} DOVIVdr; - void ff_dovi_ctx_unref(DOVIContext *s) { + ff_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_free(s->rpu_buf); *s = (DOVIContext) { .logctx = s->logctx, @@ -53,68 +41,34 @@ void ff_dovi_ctx_unref(DOVIContext *s) void ff_dovi_ctx_flush(DOVIContext *s) { + ff_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); *s = (DOVIContext) { .logctx = s->logctx, - .dv_profile = s->dv_profile, + .cfg = s->cfg, + /* preserve temporary buffer */ + .rpu_buf = s->rpu_buf, + .rpu_buf_sz = s->rpu_buf_sz, }; } void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0) { s->logctx = s0->logctx; + s->cfg = s0->cfg; + s->header = s0->header; s->mapping = s0->mapping; s->color = s0->color; - s->dv_profile = s0->dv_profile; + ff_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); } -void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg) -{ - if (!cfg) - return; - - s->dv_profile = cfg->dv_profile; -} - -int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame) -{ - AVFrameSideData *sd; - AVBufferRef *buf; - AVDOVIMetadata *dovi; - size_t dovi_size; - - if (!s->mapping || !s->color) - return 0; /* incomplete dovi metadata */ - - dovi = av_dovi_metadata_alloc(&dovi_size); - if (!dovi) - return AVERROR(ENOMEM); - - buf = av_buffer_create((uint8_t *) dovi, dovi_size, NULL, NULL, 0); - if (!buf) { - av_free(dovi); - return AVERROR(ENOMEM); - } - - sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA, buf); - if (!sd) { - av_buffer_unref(&buf); - return AVERROR(ENOMEM); - } - - /* Copy only the parts of these structs known to us at compiler-time. */ -#define COPY(t, a, b, last) memcpy(a, b, offsetof(t, last) + sizeof((b)->last)) - COPY(AVDOVIRpuDataHeader, av_dovi_get_header(dovi), &s->header, disable_residual_flag); - COPY(AVDOVIDataMapping, av_dovi_get_mapping(dovi), s->mapping, nlq[2].linear_deadzone_threshold); - COPY(AVDOVIColorMetadata, av_dovi_get_color(dovi), s->color, source_diagonal); - return 0; -} - -static int guess_profile(const AVDOVIRpuDataHeader *hdr) +int ff_dovi_guess_profile_hevc(const AVDOVIRpuDataHeader *hdr) { switch (hdr->vdr_rpu_profile) { case 0: @@ -136,345 +90,45 @@ static int guess_profile(const AVDOVIRpuDataHeader *hdr) return 0; /* unknown */ } -static inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) -{ - uint64_t ipart; - union { uint32_t u32; float f32; } fpart; - - switch (hdr->coef_data_type) { - case RPU_COEFF_FIXED: - ipart = get_ue_golomb_long(gb); - fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); - return (ipart << hdr->coef_log2_denom) | fpart.u32; - - case RPU_COEFF_FLOAT: - fpart.u32 = get_bits_long(gb, 32); - return fpart.f32 * (1LL << hdr->coef_log2_denom); - } - - return 0; /* unreachable */ -} - -static inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) -{ - int64_t ipart; - union { uint32_t u32; float f32; } fpart; - - switch (hdr->coef_data_type) { - case RPU_COEFF_FIXED: - ipart = get_se_golomb_long(gb); - fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); - return ipart * (1LL << hdr->coef_log2_denom) | fpart.u32; - - case RPU_COEFF_FLOAT: - fpart.u32 = get_bits_long(gb, 32); - return fpart.f32 * (1LL << hdr->coef_log2_denom); - } - - return 0; /* unreachable */ -} - -static inline unsigned get_variable_bits(GetBitContext *gb, int n) -{ - unsigned int value = get_bits(gb, n); - int read_more = get_bits1(gb); - while (read_more) { - value = (value + 1) << n; - value |= get_bits(gb, n); - read_more = get_bits1(gb); - } - return value; -} - -#define VALIDATE(VAR, MIN, MAX) \ - do { \ - if (VAR < MIN || VAR > MAX) { \ - av_log(s->logctx, AV_LOG_ERROR, "RPU validation failed: " \ - #MIN" <= "#VAR" = %d <= "#MAX"\n", (int) VAR); \ - goto fail; \ - } \ - } while (0) - -int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size) -{ - AVDOVIRpuDataHeader *hdr = &s->header; - GetBitContext *gb = &(GetBitContext){0}; - DOVIVdr *vdr; - int ret; - - uint8_t nal_prefix; - uint8_t rpu_type; - uint8_t vdr_seq_info_present; - uint8_t vdr_dm_metadata_present; - uint8_t use_prev_vdr_rpu; - uint8_t use_nlq; - uint8_t profile; - if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) - return ret; - - /* Container header */ - if (s->dv_profile == 10 /* dav1.10 */) { - /* DV inside AV1 re-uses 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: - * emdf_version : f(2) = 0 - * key_id : f(3) = 6 - * emdf_payload_id : f(5) = 31 - * emdf_payload_id_ext : var(5) = 225 - * smploffste : f(1) = 0 - * duratione : f(1) = 0 - * groupide : f(1) = 0 - * codecdatae : f(1) = 0 - * discard_unknown_payload : f(1) = 1 - */ - const unsigned header_magic = 0x01be6841u; - unsigned header, emdf_payload_size; - header = get_bits_long(gb, 27); - VALIDATE(header, header_magic, header_magic); - emdf_payload_size = get_variable_bits(gb, 8); - VALIDATE(emdf_payload_size, 6, 512); - if (emdf_payload_size * 8 > get_bits_left(gb)) - return AVERROR_INVALIDDATA; - } else { - nal_prefix = get_bits(gb, 8); - VALIDATE(nal_prefix, 25, 25); - } - - /* RPU header */ - rpu_type = get_bits(gb, 6); - if (rpu_type != 2) { - av_log(s->logctx, AV_LOG_WARNING, "Unrecognized RPU type " - "%"PRIu8", ignoring\n", rpu_type); - return 0; - } - - hdr->rpu_type = rpu_type; - hdr->rpu_format = get_bits(gb, 11); - - /* Values specific to RPU type 2 */ - hdr->vdr_rpu_profile = get_bits(gb, 4); - hdr->vdr_rpu_level = get_bits(gb, 4); - - vdr_seq_info_present = get_bits1(gb); - if (vdr_seq_info_present) { - hdr->chroma_resampling_explicit_filter_flag = get_bits1(gb); - hdr->coef_data_type = get_bits(gb, 2); - VALIDATE(hdr->coef_data_type, RPU_COEFF_FIXED, RPU_COEFF_FLOAT); - switch (hdr->coef_data_type) { - case RPU_COEFF_FIXED: - hdr->coef_log2_denom = get_ue_golomb(gb); - VALIDATE(hdr->coef_log2_denom, 13, 32); - break; - case RPU_COEFF_FLOAT: - hdr->coef_log2_denom = 32; /* arbitrary, choose maximum precision */ - break; - } - - hdr->vdr_rpu_normalized_idc = get_bits(gb, 2); - hdr->bl_video_full_range_flag = get_bits1(gb); - - if ((hdr->rpu_format & 0x700) == 0) { - int bl_bit_depth_minus8 = get_ue_golomb_31(gb); - int el_bit_depth_minus8 = get_ue_golomb_31(gb); - int vdr_bit_depth_minus8 = get_ue_golomb_31(gb); - VALIDATE(bl_bit_depth_minus8, 0, 8); - VALIDATE(el_bit_depth_minus8, 0, 8); - VALIDATE(vdr_bit_depth_minus8, 0, 8); - hdr->bl_bit_depth = bl_bit_depth_minus8 + 8; - hdr->el_bit_depth = el_bit_depth_minus8 + 8; - hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8; - hdr->spatial_resampling_filter_flag = get_bits1(gb); - skip_bits(gb, 3); /* reserved_zero_3bits */ - hdr->el_spatial_resampling_filter_flag = get_bits1(gb); - hdr->disable_residual_flag = get_bits1(gb); - } - } - - if (!hdr->bl_bit_depth) { - av_log(s->logctx, AV_LOG_ERROR, "Missing RPU VDR sequence info?\n"); - goto fail; - } - - vdr_dm_metadata_present = get_bits1(gb); - use_prev_vdr_rpu = get_bits1(gb); - use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag; - - profile = s->dv_profile ? s->dv_profile : guess_profile(hdr); - if (profile == 5 && use_nlq) { - av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n"); - goto fail; - } - - if (use_prev_vdr_rpu) { - int prev_vdr_rpu_id = get_ue_golomb_31(gb); - VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID); - if (!s->vdr[prev_vdr_rpu_id]) { - av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n", - prev_vdr_rpu_id); - goto fail; - } - vdr = s->vdr[prev_vdr_rpu_id]; - s->mapping = &vdr->mapping; - } else { - 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(DOVIVdr)); - if (!s->vdr[vdr_rpu_id]) - return AVERROR(ENOMEM); - } - - vdr = s->vdr[vdr_rpu_id]; - s->mapping = &vdr->mapping; - - vdr->mapping.vdr_rpu_id = vdr_rpu_id; - vdr->mapping.mapping_color_space = get_ue_golomb_31(gb); - vdr->mapping.mapping_chroma_format_idc = get_ue_golomb_31(gb); - - for (int c = 0; c < 3; c++) { - AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; - int num_pivots_minus_2 = get_ue_golomb_31(gb); - int pivot = 0; - - VALIDATE(num_pivots_minus_2, 0, AV_DOVI_MAX_PIECES - 1); - curve->num_pivots = num_pivots_minus_2 + 2; - for (int i = 0; i < curve->num_pivots; i++) { - pivot += get_bits(gb, hdr->bl_bit_depth); - curve->pivots[i] = av_clip_uint16(pivot); - } - } - - if (use_nlq) { - vdr->mapping.nlq_method_idc = get_bits(gb, 3); - /** - * The patent mentions another legal value, NLQ_MU_LAW, but it's - * not documented anywhere how to parse or apply that type of NLQ. - */ - VALIDATE(vdr->mapping.nlq_method_idc, 0, AV_DOVI_NLQ_LINEAR_DZ); - } else { - vdr->mapping.nlq_method_idc = AV_DOVI_NLQ_NONE; - } - - vdr->mapping.num_x_partitions = get_ue_golomb_long(gb) + 1; - vdr->mapping.num_y_partitions = get_ue_golomb_long(gb) + 1; - /* End of rpu_data_header(), start of vdr_rpu_data_payload() */ - - for (int c = 0; c < 3; c++) { - AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; - for (int i = 0; i < curve->num_pivots - 1; i++) { - int mapping_idc = get_ue_golomb_31(gb); - VALIDATE(mapping_idc, 0, 1); - curve->mapping_idc[i] = mapping_idc; - switch (mapping_idc) { - case AV_DOVI_MAPPING_POLYNOMIAL: { - int poly_order_minus1 = get_ue_golomb_31(gb); - VALIDATE(poly_order_minus1, 0, 1); - curve->poly_order[i] = poly_order_minus1 + 1; - if (poly_order_minus1 == 0) { - int linear_interp_flag = get_bits1(gb); - if (linear_interp_flag) { - /* lack of documentation/samples */ - avpriv_request_sample(s->logctx, "Dolby Vision " - "linear interpolation"); - ff_dovi_ctx_unref(s); - return AVERROR_PATCHWELCOME; - } - } - for (int k = 0; k <= curve->poly_order[i]; k++) - curve->poly_coef[i][k] = get_se_coef(gb, hdr); - break; - } - case AV_DOVI_MAPPING_MMR: { - int mmr_order_minus1 = get_bits(gb, 2); - VALIDATE(mmr_order_minus1, 0, 2); - curve->mmr_order[i] = mmr_order_minus1 + 1; - curve->mmr_constant[i] = get_se_coef(gb, hdr); - for (int j = 0; j < curve->mmr_order[i]; j++) { - for (int k = 0; k < 7; k++) - curve->mmr_coef[i][j][k] = get_se_coef(gb, hdr); - } - break; - } - } - } - } - - if (use_nlq) { - for (int c = 0; c < 3; c++) { - AVDOVINLQParams *nlq = &vdr->mapping.nlq[c]; - nlq->nlq_offset = get_bits(gb, hdr->el_bit_depth); - nlq->vdr_in_max = get_ue_coef(gb, hdr); - switch (vdr->mapping.nlq_method_idc) { - case AV_DOVI_NLQ_LINEAR_DZ: - nlq->linear_deadzone_slope = get_ue_coef(gb, hdr); - nlq->linear_deadzone_threshold = get_ue_coef(gb, hdr); - break; - } - } - } - } - - if (vdr_dm_metadata_present) { - AVDOVIColorMetadata *color; - int affected_dm_id = get_ue_golomb_31(gb); - int current_dm_id = get_ue_golomb_31(gb); - VALIDATE(affected_dm_id, 0, DOVI_MAX_DM_ID); - VALIDATE(current_dm_id, 0, DOVI_MAX_DM_ID); - if (!s->vdr[affected_dm_id]) { - s->vdr[affected_dm_id] = ff_refstruct_allocz(sizeof(DOVIVdr)); - if (!s->vdr[affected_dm_id]) - return AVERROR(ENOMEM); - } - - if (!s->vdr[current_dm_id]) { - av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU DM ID: %u\n", - current_dm_id); - goto fail; - } - - /* Update current pointer based on current_dm_id */ - vdr = s->vdr[current_dm_id]; - s->color = &vdr->color; - - /* Update values of affected_dm_id */ - vdr = s->vdr[affected_dm_id]; - color = &vdr->color; - color->dm_metadata_id = affected_dm_id; - color->scene_refresh_flag = get_ue_golomb_31(gb); - for (int i = 0; i < 9; i++) - color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13); - for (int i = 0; i < 3; i++) { - int denom = profile == 4 ? (1 << 30) : (1 << 28); - unsigned offset = get_bits_long(gb, 32); - if (offset > INT_MAX) { - /* Ensure the result fits inside AVRational */ - offset >>= 1; - denom >>= 1; - } - color->ycc_to_rgb_offset[i] = av_make_q(offset, denom); - } - for (int i = 0; i < 9; i++) - color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14); - - color->signal_eotf = get_bits(gb, 16); - color->signal_eotf_param0 = get_bits(gb, 16); - color->signal_eotf_param1 = get_bits(gb, 16); - color->signal_eotf_param2 = get_bits_long(gb, 32); - color->signal_bit_depth = get_bits(gb, 5); - VALIDATE(color->signal_bit_depth, 8, 16); - color->signal_color_space = get_bits(gb, 2); - color->signal_chroma_format = get_bits(gb, 2); - color->signal_full_range_flag = get_bits(gb, 2); - color->source_min_pq = get_bits(gb, 12); - color->source_max_pq = get_bits(gb, 12); - color->source_diagonal = get_bits(gb, 10); - } - - /* FIXME: verify CRC32, requires implementation of AV_CRC_32_MPEG_2 */ - return 0; - -fail: - ff_dovi_ctx_unref(s); /* don't leak potentially invalid state */ - return AVERROR(EINVAL); -} +const AVDOVIColorMetadata ff_dovi_color_default = { + .dm_metadata_id = 0, + .scene_refresh_flag = 0, + .ycc_to_rgb_matrix = { + { 9575, 8192 }, + { 0, 8192 }, + { 14742, 8192 }, + { 9575, 8192 }, + { 1754, 8192 }, + { 4383, 8192 }, + { 9575, 8192 }, + { 17372, 8192 }, + { 0, 8192 }, + }, + .ycc_to_rgb_offset = { + { 1, 4 }, + { 2, 1 }, + { 2, 1 }, + }, + .rgb_to_lms_matrix = { + { 5845, 16384 }, + { 9702, 16384 }, + { 837, 16384 }, + { 2568, 16384 }, + { 12256, 16384 }, + { 1561, 16384 }, + { 0, 16384 }, + { 679, 16384 }, + { 15705, 16384 }, + }, + .signal_eotf = 39322, + .signal_eotf_param0 = 15867, + .signal_eotf_param1 = 228, + .signal_eotf_param2 = 1383604, + .signal_bit_depth = 14, + .signal_color_space = 0, + .signal_chroma_format = 0, + .signal_full_range_flag = 1, + .source_min_pq = 62, + .source_max_pq = 3696, + .source_diagonal = 42, +}; diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h index 51c5fdbb8..f3ccc27ae 100644 --- a/libavcodec/dovi_rpu.h +++ b/libavcodec/dovi_rpu.h @@ -27,28 +27,66 @@ #include "libavutil/dovi_meta.h" #include "libavutil/frame.h" +#include "avcodec.h" +#include "codec_par.h" + #define DOVI_MAX_DM_ID 15 + +typedef struct DOVIExt { + AVDOVIDmData dm_static[7]; ///< static extension blocks + AVDOVIDmData dm_dynamic[25]; ///< dynamic extension blocks + int num_static; + int num_dynamic; +} DOVIExt; + typedef struct DOVIContext { void *logctx; /** - * Currently active RPU data header, updates on every dovi_rpu_parse(). + * Enable tri-state. For encoding only. FF_DOVI_AUTOMATIC enables Dolby + * Vision only if avctx->decoded_side_data contains an AVDOVIMetadata. + */ +#define FF_DOVI_AUTOMATIC -1 + int enable; + + /** + * Currently active dolby vision configuration, or {0} for none. + * Set by the user when decoding. Generated by ff_dovi_configure() + * when encoding. + * + * Note: sizeof(cfg) is not part of the libavutil ABI, so users should + * never pass &cfg to any other library calls. This is included merely as + * a way to look up the values of fields known at compile time. + */ + AVDOVIDecoderConfigurationRecord cfg; + + /** + * Currently active RPU data header, updates on every ff_dovi_rpu_parse() + * or ff_dovi_rpu_generate(). */ AVDOVIRpuDataHeader header; /** * Currently active data mappings, or NULL. Points into memory owned by the * corresponding rpu/vdr_ref, which becomes invalid on the next call to - * dovi_rpu_parse. + * ff_dovi_rpu_parse() or ff_dovi_rpu_generate(). */ const AVDOVIDataMapping *mapping; const AVDOVIColorMetadata *color; + /** + * Currently active extension blocks, updates on every ff_dovi_rpu_parse() + * or ff_dovi_rpu_generate(). + */ + DOVIExt *ext_blocks; ///< RefStruct, or NULL if no extension blocks + /** * Private fields internal to dovi_rpu.c */ - struct DOVIVdr *vdr[DOVI_MAX_DM_ID+1]; ///< RefStruct references - uint8_t dv_profile; + AVDOVIColorMetadata *dm; ///< RefStruct + AVDOVIDataMapping *vdr[DOVI_MAX_DM_ID+1]; ///< RefStruct references + uint8_t *rpu_buf; ///< temporary buffer + unsigned rpu_buf_sz; } DOVIContext; @@ -60,28 +98,113 @@ void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0); void ff_dovi_ctx_unref(DOVIContext *s); /** - * Partially reset the internal state. Resets per-frame state while preserving - * fields parsed from the configuration record. + * Partially reset the internal state. Resets per-frame state, but preserves + * the stream-wide configuration record. */ void ff_dovi_ctx_flush(DOVIContext *s); /** - * Read the contents of an AVDOVIDecoderConfigurationRecord (usually provided - * by stream side data) and update internal state accordingly. - */ -void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg); - -/** - * Parse the contents of a Dovi RPU NAL and update the parsed values in the - * DOVIContext struct. + * Parse the contents of a Dolby Vision RPU and update the parsed values in the + * DOVIContext struct. This function should receive the decoded unit payload, + * without any T.35 or NAL unit headers. * * Returns 0 or an error code. + * + * Note: `DOVIContext.cfg` should be initialized before calling into this + * function. If not done, the profile will be guessed according to HEVC + * semantics. */ -int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size); +int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, + int err_recognition); + +/** + * Get the decoded AVDOVIMetadata. Ownership passes to the caller. + * + * Returns the size of *out_metadata, a negative error code, or 0 if no + * metadata is available to return. + */ +int ff_dovi_get_metadata(DOVIContext *s, AVDOVIMetadata **out_metadata); /** * Attach the decoded AVDOVIMetadata as side data to an AVFrame. + * Returns 0 or a negative error code. */ 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. + * + * `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 + * results (in particular for HEVC streams with enhancement layers). + * + * 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); + +/** + * Helper wrapper around `ff_dovi_configure_ext` which infers the codec + * parameters from an AVCodecContext. + */ +int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx); + +enum { + FF_DOVI_WRAP_NAL = 1 << 0, ///< wrap inside NAL RBSP + FF_DOVI_WRAP_T35 = 1 << 1, ///< wrap inside T.35+EMDF + FF_DOVI_COMPRESS_RPU = 1 << 2, ///< enable compression for this RPU +}; + +/** + * Synthesize a Dolby Vision RPU reflecting the current state. By default, the + * RPU is not encapsulated (see `flags` for more options). Note that this + * assumes all previous calls to `ff_dovi_rpu_generate` have been + * appropriately signalled, i.e. it will not re-send already transmitted + * redundant data. + * + * Mutates the internal state of DOVIContext to reflect the change. + * Returns 0 or a negative error code. + */ +int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, + int flags, uint8_t **out_rpu, int *out_size); + + +/*************************************************** + * The following section is for internal use only. * + ***************************************************/ + +enum { + RPU_COEFF_FIXED = 0, + RPU_COEFF_FLOAT = 1, +}; + +/** + * Internal helper function to guess the correct DV profile for HEVC. + * + * Returns the profile number or 0 if unknown. + */ +int ff_dovi_guess_profile_hevc(const AVDOVIRpuDataHeader *hdr); + +/* Default values for AVDOVIColorMetadata */ +extern const AVDOVIColorMetadata ff_dovi_color_default; + +static inline int ff_dovi_rpu_extension_is_static(int level) +{ + switch (level) { + case 6: + case 10: + case 32: /* reserved as static by spec */ + case 254: + case 255: + return 1; + default: + return 0; + } +} + #endif /* AVCODEC_DOVI_RPU_H */ diff --git a/libavcodec/dovi_rpudec.c b/libavcodec/dovi_rpudec.c new file mode 100644 index 000000000..878950d66 --- /dev/null +++ b/libavcodec/dovi_rpudec.c @@ -0,0 +1,742 @@ +/* + * Dolby Vision RPU decoder + * + * Copyright (C) 2021 Jan Ekström + * Copyright (C) 2021-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 "libavutil/mem.h" +#include "libavutil/crc.h" + +#include "avcodec.h" +#include "dovi_rpu.h" +#include "golomb.h" +#include "get_bits.h" +#include "refstruct.h" + +int ff_dovi_get_metadata(DOVIContext *s, AVDOVIMetadata **out_metadata) +{ + AVDOVIMetadata *dovi; + size_t dovi_size; + + if (!s->mapping || !s->color) + return 0; /* incomplete dovi metadata */ + + dovi = av_dovi_metadata_alloc(&dovi_size); + if (!dovi) + return AVERROR(ENOMEM); + + /* Copy only the parts of these structs known to us at compiler-time. */ +#define COPY(t, a, b, last) memcpy(a, b, offsetof(t, last) + sizeof((b)->last)) + COPY(AVDOVIRpuDataHeader, av_dovi_get_header(dovi), &s->header, ext_mapping_idc_5_7); + COPY(AVDOVIDataMapping, av_dovi_get_mapping(dovi), s->mapping, nlq_pivots); + COPY(AVDOVIColorMetadata, av_dovi_get_color(dovi), s->color, source_diagonal); + + if (s->ext_blocks) { + const DOVIExt *ext = s->ext_blocks; + size_t ext_sz = FFMIN(sizeof(AVDOVIDmData), dovi->ext_block_size); + for (int i = 0; i < ext->num_static; i++) + memcpy(av_dovi_get_ext(dovi, dovi->num_ext_blocks++), &ext->dm_static[i], ext_sz); + for (int i = 0; i < ext->num_dynamic; i++) + memcpy(av_dovi_get_ext(dovi, dovi->num_ext_blocks++), &ext->dm_dynamic[i], ext_sz); + } + + *out_metadata = dovi; + return dovi_size; +} + +int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame) +{ + AVFrameSideData *sd; + AVDOVIMetadata *dovi; + AVBufferRef *buf; + int size; + + size = ff_dovi_get_metadata(s, &dovi); + if (size <= 0) + return size; + + buf = av_buffer_create((uint8_t *) dovi, size, NULL, NULL, 0); + if (!buf) { + av_free(dovi); + return AVERROR(ENOMEM); + } + + sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA, buf); + if (!sd) { + av_buffer_unref(&buf); + return AVERROR(ENOMEM); + } + + return 0; +} + +static inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) +{ + uint64_t ipart; + union { uint32_t u32; float f32; } fpart; + + switch (hdr->coef_data_type) { + case RPU_COEFF_FIXED: + ipart = get_ue_golomb_long(gb); + fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); + return (ipart << hdr->coef_log2_denom) | fpart.u32; + + case RPU_COEFF_FLOAT: + fpart.u32 = get_bits_long(gb, 32); + return fpart.f32 * (1LL << hdr->coef_log2_denom); + } + + return 0; /* unreachable */ +} + +static inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) +{ + int64_t ipart; + union { uint32_t u32; float f32; } fpart; + + switch (hdr->coef_data_type) { + case RPU_COEFF_FIXED: + ipart = get_se_golomb_long(gb); + fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); + return ipart * (1LL << hdr->coef_log2_denom) | fpart.u32; + + case RPU_COEFF_FLOAT: + fpart.u32 = get_bits_long(gb, 32); + return fpart.f32 * (1LL << hdr->coef_log2_denom); + } + + return 0; /* unreachable */ +} + +static inline unsigned get_variable_bits(GetBitContext *gb, int n) +{ + unsigned int value = get_bits(gb, n); + int read_more = get_bits1(gb); + while (read_more) { + value = (value + 1) << n; + value |= get_bits(gb, n); + read_more = get_bits1(gb); + } + return value; +} + +#define VALIDATE(VAR, MIN, MAX) \ + do { \ + if (VAR < MIN || VAR > MAX) { \ + av_log(s->logctx, AV_LOG_ERROR, "RPU validation failed: " \ + #MIN" <= "#VAR" = %d <= "#MAX"\n", (int) VAR); \ + ff_dovi_ctx_unref(s); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +static int parse_ext_v1(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm) +{ + switch (dm->level) { + case 1: + dm->l1.min_pq = get_bits(gb, 12); + dm->l1.max_pq = get_bits(gb, 12); + dm->l1.avg_pq = get_bits(gb, 12); + break; + case 2: + dm->l2.target_max_pq = get_bits(gb, 12); + dm->l2.trim_slope = get_bits(gb, 12); + dm->l2.trim_offset = get_bits(gb, 12); + dm->l2.trim_power = get_bits(gb, 12); + dm->l2.trim_chroma_weight = get_bits(gb, 12); + dm->l2.trim_saturation_gain = get_bits(gb, 12); + dm->l2.ms_weight = get_sbits(gb, 13); + VALIDATE(dm->l2.ms_weight, -1, 4095); + break; + case 4: + dm->l4.anchor_pq = get_bits(gb, 12); + dm->l4.anchor_power = get_bits(gb, 12); + break; + case 5: + dm->l5.left_offset = get_bits(gb, 13); + dm->l5.right_offset = get_bits(gb, 13); + dm->l5.top_offset = get_bits(gb, 13); + dm->l5.bottom_offset = get_bits(gb, 13); + break; + case 6: + dm->l6.max_luminance = get_bits(gb, 16); + dm->l6.min_luminance = get_bits(gb, 16); + dm->l6.max_cll = get_bits(gb, 16); + dm->l6.max_fall = get_bits(gb, 16); + break; + case 255: + dm->l255.dm_run_mode = get_bits(gb, 8); + dm->l255.dm_run_version = get_bits(gb, 8); + for (int i = 0; i < 4; i++) + 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); + } + + return 0; +} + +static AVCIExy get_cie_xy(GetBitContext *gb) +{ + AVCIExy xy; + const int denom = 32767; + xy.x = av_make_q(get_sbits(gb, 16), denom); + xy.y = av_make_q(get_sbits(gb, 16), denom); + return xy; +} + +static int parse_ext_v2(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm, + int ext_block_length) +{ + switch (dm->level) { + case 3: + dm->l3.min_pq_offset = get_bits(gb, 12); + dm->l3.max_pq_offset = get_bits(gb, 12); + dm->l3.avg_pq_offset = get_bits(gb, 12); + break; + case 8: + dm->l8.target_display_index = get_bits(gb, 8); + dm->l8.trim_slope = get_bits(gb, 12); + dm->l8.trim_offset = get_bits(gb, 12); + dm->l8.trim_power = get_bits(gb, 12); + dm->l8.trim_chroma_weight = get_bits(gb, 12); + dm->l8.trim_saturation_gain = get_bits(gb, 12); + dm->l8.ms_weight = get_bits(gb, 12); + if (ext_block_length < 12) + break; + dm->l8.target_mid_contrast = get_bits(gb, 12); + if (ext_block_length < 13) + break; + dm->l8.clip_trim = get_bits(gb, 12); + if (ext_block_length < 19) + break; + for (int i = 0; i < 6; i++) + dm->l8.saturation_vector_field[i] = get_bits(gb, 8); + if (ext_block_length < 25) + break; + for (int i = 0; i < 6; i++) + dm->l8.hue_vector_field[i] = get_bits(gb, 8); + break; + case 9: + dm->l9.source_primary_index = get_bits(gb, 8); + if (ext_block_length < 17) + break; + dm->l9.source_display_primaries.prim.r = get_cie_xy(gb); + dm->l9.source_display_primaries.prim.g = get_cie_xy(gb); + dm->l9.source_display_primaries.prim.b = get_cie_xy(gb); + dm->l9.source_display_primaries.wp = get_cie_xy(gb); + break; + case 10: + dm->l10.target_display_index = get_bits(gb, 8); + dm->l10.target_max_pq = get_bits(gb, 12); + dm->l10.target_min_pq = get_bits(gb, 12); + dm->l10.target_primary_index = get_bits(gb, 8); + if (ext_block_length < 21) + break; + dm->l10.target_display_primaries.prim.r = get_cie_xy(gb); + dm->l10.target_display_primaries.prim.g = get_cie_xy(gb); + dm->l10.target_display_primaries.prim.b = get_cie_xy(gb); + dm->l10.target_display_primaries.wp = get_cie_xy(gb); + break; + case 11: + dm->l11.content_type = get_bits(gb, 8); + 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); + 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); + } + + return 0; +} + +static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver, + int compression, int err_recognition) +{ + int num_ext_blocks, ext_block_length, start_pos, parsed_bits, ret; + DOVIExt *ext = s->ext_blocks; + + num_ext_blocks = get_ue_golomb_31(gb); + align_get_bits(gb); + + if (num_ext_blocks && !ext) { + ext = s->ext_blocks = ff_refstruct_allocz(sizeof(*s->ext_blocks)); + if (!ext) + return AVERROR(ENOMEM); + } + + while (num_ext_blocks--) { + AVDOVIDmData dummy; + AVDOVIDmData *dm; + uint8_t level; + + ext_block_length = get_ue_golomb_31(gb); + level = get_bits(gb, 8); + start_pos = get_bits_count(gb); + + if (ff_dovi_rpu_extension_is_static(level)) { + if (compression) { + av_log(s->logctx, AV_LOG_WARNING, "Compressed DM RPU contains " + "static extension block level %d\n", level); + if (err_recognition & (AV_EF_AGGRESSIVE | AV_EF_EXPLODE)) + return AVERROR_INVALIDDATA; + dm = &dummy; + } else { + if (ext->num_static >= FF_ARRAY_ELEMS(ext->dm_static)) + return AVERROR_INVALIDDATA; + dm = &ext->dm_static[ext->num_static++]; + } + } else { + if (ext->num_dynamic >= FF_ARRAY_ELEMS(ext->dm_dynamic)) + return AVERROR_INVALIDDATA; + dm = &ext->dm_dynamic[ext->num_dynamic++]; + } + + memset(dm, 0, sizeof(*dm)); + dm->level = level; + 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; + } + + if (ret < 0) + return ret; + + parsed_bits = get_bits_count(gb) - start_pos; + if (parsed_bits > ext_block_length * 8) + return AVERROR_INVALIDDATA; + skip_bits(gb, ext_block_length * 8 - parsed_bits); + } + + return 0; +} + +int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, + int err_recognition) +{ + AVDOVIRpuDataHeader *hdr = &s->header; + GetBitContext *gb = &(GetBitContext){0}; + int ret; + + uint8_t rpu_type; + uint8_t vdr_seq_info_present; + uint8_t vdr_dm_metadata_present; + uint8_t dm_compression = 0; + uint8_t use_prev_vdr_rpu; + uint8_t use_nlq; + uint8_t profile; + uint8_t compression = s->cfg.dv_profile ? s->cfg.dv_md_compression : 0; + + if (rpu_size < 5) + return AVERROR_INVALIDDATA; + + /* Container */ + if (s->cfg.dv_profile == 10 /* dav1.10 */) { + /* DV inside AV1 re-uses 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: + * emdf_version : f(2) = 0 + * key_id : f(3) = 6 + * emdf_payload_id : f(5) = 31 + * emdf_payload_id_ext : var(5) = 225 + * smploffste : f(1) = 0 + * duratione : f(1) = 0 + * groupide : f(1) = 0 + * codecdatae : f(1) = 0 + * discard_unknown_payload : f(1) = 1 + */ + const unsigned header_magic = 0x01be6841u; + unsigned emdf_header, emdf_payload_size, emdf_protection; + if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) + return ret; + emdf_header = get_bits_long(gb, 27); + VALIDATE(emdf_header, header_magic, header_magic); + emdf_payload_size = get_variable_bits(gb, 8); + VALIDATE(emdf_payload_size, 6, 512); + if (emdf_payload_size * 8 > get_bits_left(gb)) + return AVERROR_INVALIDDATA; + + /* The payload is not byte-aligned (off by *one* bit, curse Dolby), + * so copy into a fresh buffer to preserve byte alignment of the + * RPU struct */ + av_fast_padded_malloc(&s->rpu_buf, &s->rpu_buf_sz, emdf_payload_size); + if (!s->rpu_buf) + return AVERROR(ENOMEM); + for (int i = 0; i < emdf_payload_size; i++) + s->rpu_buf[i] = get_bits(gb, 8); + rpu = s->rpu_buf; + rpu_size = emdf_payload_size; + + /* Validate EMDF footer */ + emdf_protection = get_bits(gb, 5 + 12); + VALIDATE(emdf_protection, 0x400, 0x400); + } else { + /* NAL unit with prefix and trailing zeroes */ + 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) + return ret; + + /* RPU header */ + rpu_type = get_bits(gb, 6); + if (rpu_type != 2) { + av_log(s->logctx, AV_LOG_WARNING, "Unrecognized RPU type " + "%"PRIu8", ignoring\n", rpu_type); + return 0; + } + + hdr->rpu_type = rpu_type; + hdr->rpu_format = get_bits(gb, 11); + + /* Values specific to RPU type 2 */ + hdr->vdr_rpu_profile = get_bits(gb, 4); + hdr->vdr_rpu_level = get_bits(gb, 4); + + vdr_seq_info_present = get_bits1(gb); + if (vdr_seq_info_present) { + hdr->chroma_resampling_explicit_filter_flag = get_bits1(gb); + hdr->coef_data_type = get_bits(gb, 2); + VALIDATE(hdr->coef_data_type, RPU_COEFF_FIXED, RPU_COEFF_FLOAT); + switch (hdr->coef_data_type) { + case RPU_COEFF_FIXED: + hdr->coef_log2_denom = get_ue_golomb(gb); + VALIDATE(hdr->coef_log2_denom, 13, 32); + break; + case RPU_COEFF_FLOAT: + hdr->coef_log2_denom = 32; /* arbitrary, choose maximum precision */ + break; + } + + hdr->vdr_rpu_normalized_idc = get_bits(gb, 2); + hdr->bl_video_full_range_flag = get_bits1(gb); + + if ((hdr->rpu_format & 0x700) == 0) { + int bl_bit_depth_minus8 = get_ue_golomb_31(gb); + int el_bit_depth_minus8 = get_ue_golomb_long(gb); + int vdr_bit_depth_minus8 = get_ue_golomb_31(gb); + /* ext_mapping_idc is in the upper 8 bits of el_bit_depth_minus8 */ + int ext_mapping_idc = el_bit_depth_minus8 >> 8; + el_bit_depth_minus8 = el_bit_depth_minus8 & 0xFF; + VALIDATE(bl_bit_depth_minus8, 0, 8); + VALIDATE(el_bit_depth_minus8, 0, 8); + VALIDATE(ext_mapping_idc, 0, 0xFF); + VALIDATE(vdr_bit_depth_minus8, 0, 8); + hdr->bl_bit_depth = bl_bit_depth_minus8 + 8; + hdr->el_bit_depth = el_bit_depth_minus8 + 8; + hdr->ext_mapping_idc_0_4 = ext_mapping_idc & 0x1f; /* 5 bits */ + hdr->ext_mapping_idc_5_7 = ext_mapping_idc >> 5; + hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8; + hdr->spatial_resampling_filter_flag = get_bits1(gb); + dm_compression = get_bits(gb, 3); + hdr->el_spatial_resampling_filter_flag = get_bits1(gb); + hdr->disable_residual_flag = get_bits1(gb); + } else { + avpriv_request_sample(s->logctx, "Unsupported RPU format 0x%x\n", hdr->rpu_format); + ff_dovi_ctx_unref(s); + return AVERROR_PATCHWELCOME; + } + } else { + /* lack of documentation/samples */ + avpriv_request_sample(s->logctx, "Missing RPU VDR sequence info\n"); + ff_dovi_ctx_unref(s); + return AVERROR_PATCHWELCOME; + } + + vdr_dm_metadata_present = get_bits1(gb); + if (dm_compression > 1) { + /* It seems no device supports this */ + av_log(s->logctx, AV_LOG_ERROR, "Dynamic metadata compression is not " + "yet implemented"); + return AVERROR_PATCHWELCOME; + } else if (dm_compression && !vdr_dm_metadata_present) { + av_log(s->logctx, AV_LOG_ERROR, "Nonzero DM metadata compression method " + "but no DM metadata present"); + return AVERROR_INVALIDDATA; + } + + use_prev_vdr_rpu = get_bits1(gb); + use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag; + + profile = s->cfg.dv_profile ? s->cfg.dv_profile : ff_dovi_guess_profile_hevc(hdr); + if (profile == 5 && use_nlq) { + av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n"); + ff_dovi_ctx_unref(s); + return AVERROR_INVALIDDATA; + } + + if (err_recognition & (AV_EF_COMPLIANT | AV_EF_CAREFUL)) { + if (profile < 8 && compression) { + av_log(s->logctx, AV_LOG_ERROR, "Profile %d RPUs should not use " + "metadata compression.", profile); + return AVERROR_INVALIDDATA; + } + + if (use_prev_vdr_rpu && !compression) { + av_log(s->logctx, AV_LOG_ERROR, "Uncompressed RPUs should not have " + "use_prev_vdr_rpu=1\n"); + return AVERROR_INVALIDDATA; + } + + if (dm_compression && !compression) { + av_log(s->logctx, AV_LOG_ERROR, "Uncompressed RPUs should not use " + "dm_compression=%d\n", dm_compression); + return AVERROR_INVALIDDATA; + } + } + + if (use_prev_vdr_rpu) { + int prev_vdr_rpu_id = get_ue_golomb_31(gb); + VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID); + if (!s->vdr[prev_vdr_rpu_id]) + prev_vdr_rpu_id = 0; + if (!s->vdr[prev_vdr_rpu_id]) { + /* FIXME: Technically, the spec says that in this case we should + * synthesize "neutral" vdr metadata, but easier to just error + * out as this corner case is not hit in practice */ + av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n", + prev_vdr_rpu_id); + ff_dovi_ctx_unref(s); + return AVERROR_INVALIDDATA; + } + s->mapping = s->vdr[prev_vdr_rpu_id]; + } else { + AVDOVIDataMapping *mapping; + 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)); + if (!s->vdr[vdr_rpu_id]) { + ff_dovi_ctx_unref(s); + return AVERROR(ENOMEM); + } + } + + s->mapping = mapping = s->vdr[vdr_rpu_id]; + mapping->vdr_rpu_id = vdr_rpu_id; + mapping->mapping_color_space = get_ue_golomb_31(gb); + mapping->mapping_chroma_format_idc = get_ue_golomb_31(gb); + + for (int c = 0; c < 3; c++) { + AVDOVIReshapingCurve *curve = &mapping->curves[c]; + int num_pivots_minus_2 = get_ue_golomb_31(gb); + int pivot = 0; + + VALIDATE(num_pivots_minus_2, 0, AV_DOVI_MAX_PIECES - 1); + curve->num_pivots = num_pivots_minus_2 + 2; + for (int i = 0; i < curve->num_pivots; i++) { + pivot += get_bits(gb, hdr->bl_bit_depth); + curve->pivots[i] = av_clip_uint16(pivot); + } + } + + if (use_nlq) { + int nlq_pivot = 0; + mapping->nlq_method_idc = get_bits(gb, 3); + + for (int i = 0; i < 2; i++) { + nlq_pivot += get_bits(gb, hdr->bl_bit_depth); + mapping->nlq_pivots[i] = av_clip_uint16(nlq_pivot); + } + + /** + * The patent mentions another legal value, NLQ_MU_LAW, but it's + * not documented anywhere how to parse or apply that type of NLQ. + */ + VALIDATE(mapping->nlq_method_idc, 0, AV_DOVI_NLQ_LINEAR_DZ); + } else { + mapping->nlq_method_idc = AV_DOVI_NLQ_NONE; + } + + mapping->num_x_partitions = get_ue_golomb_long(gb) + 1; + mapping->num_y_partitions = get_ue_golomb_long(gb) + 1; + /* End of rpu_data_header(), start of vdr_rpu_data_payload() */ + + for (int c = 0; c < 3; c++) { + AVDOVIReshapingCurve *curve = &mapping->curves[c]; + for (int i = 0; i < curve->num_pivots - 1; i++) { + int mapping_idc = get_ue_golomb_31(gb); + VALIDATE(mapping_idc, 0, 1); + curve->mapping_idc[i] = mapping_idc; + switch (mapping_idc) { + case AV_DOVI_MAPPING_POLYNOMIAL: { + int poly_order_minus1 = get_ue_golomb_31(gb); + VALIDATE(poly_order_minus1, 0, 1); + curve->poly_order[i] = poly_order_minus1 + 1; + if (poly_order_minus1 == 0) { + int linear_interp_flag = get_bits1(gb); + if (linear_interp_flag) { + /* lack of documentation/samples */ + avpriv_request_sample(s->logctx, "Dolby Vision " + "linear interpolation"); + ff_dovi_ctx_unref(s); + return AVERROR_PATCHWELCOME; + } + } + for (int k = 0; k <= curve->poly_order[i]; k++) + curve->poly_coef[i][k] = get_se_coef(gb, hdr); + break; + } + case AV_DOVI_MAPPING_MMR: { + int mmr_order_minus1 = get_bits(gb, 2); + VALIDATE(mmr_order_minus1, 0, 2); + curve->mmr_order[i] = mmr_order_minus1 + 1; + curve->mmr_constant[i] = get_se_coef(gb, hdr); + for (int j = 0; j < curve->mmr_order[i]; j++) { + for (int k = 0; k < 7; k++) + curve->mmr_coef[i][j][k] = get_se_coef(gb, hdr); + } + break; + } + } + } + } + + if (use_nlq) { + for (int c = 0; c < 3; c++) { + AVDOVINLQParams *nlq = &mapping->nlq[c]; + nlq->nlq_offset = get_bits(gb, hdr->el_bit_depth); + nlq->vdr_in_max = get_ue_coef(gb, hdr); + switch (mapping->nlq_method_idc) { + case AV_DOVI_NLQ_LINEAR_DZ: + nlq->linear_deadzone_slope = get_ue_coef(gb, hdr); + nlq->linear_deadzone_threshold = get_ue_coef(gb, hdr); + break; + } + } + } + } + + if (vdr_dm_metadata_present) { + AVDOVIColorMetadata *color; + int affected_dm_id = get_ue_golomb_31(gb); + int current_dm_id = get_ue_golomb_31(gb); + VALIDATE(affected_dm_id, 0, DOVI_MAX_DM_ID); + VALIDATE(current_dm_id, 0, DOVI_MAX_DM_ID); + if (affected_dm_id != current_dm_id) { + /* The spec does not explain these fields at all, and there is + * a lack of samples to understand how they're supposed to work, + * so just assert them being equal for now */ + avpriv_request_sample(s->logctx, "affected/current_dm_metadata_id " + "mismatch? %u != %u\n", affected_dm_id, current_dm_id); + ff_dovi_ctx_unref(s); + return AVERROR_PATCHWELCOME; + } + + if (!s->dm) { + s->dm = ff_refstruct_allocz(sizeof(AVDOVIColorMetadata)); + if (!s->dm) { + ff_dovi_ctx_unref(s); + return AVERROR(ENOMEM); + } + } + + s->color = color = s->dm; + color->dm_metadata_id = affected_dm_id; + color->scene_refresh_flag = get_ue_golomb_31(gb); + if (!dm_compression) { + for (int i = 0; i < 9; i++) + color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13); + for (int i = 0; i < 3; i++) { + int denom = profile == 4 ? (1 << 30) : (1 << 28); + unsigned offset = get_bits_long(gb, 32); + if (offset > INT_MAX) { + /* Ensure the result fits inside AVRational */ + offset >>= 1; + denom >>= 1; + } + color->ycc_to_rgb_offset[i] = av_make_q(offset, denom); + } + for (int i = 0; i < 9; i++) + color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14); + + color->signal_eotf = get_bits(gb, 16); + color->signal_eotf_param0 = get_bits(gb, 16); + color->signal_eotf_param1 = get_bits(gb, 16); + color->signal_eotf_param2 = get_bits_long(gb, 32); + color->signal_bit_depth = get_bits(gb, 5); + VALIDATE(color->signal_bit_depth, 8, 16); + color->signal_color_space = get_bits(gb, 2); + color->signal_chroma_format = get_bits(gb, 2); + color->signal_full_range_flag = get_bits(gb, 2); + color->source_min_pq = get_bits(gb, 12); + color->source_max_pq = get_bits(gb, 12); + color->source_diagonal = get_bits(gb, 10); + } + + /* Parse extension blocks */ + if (s->ext_blocks) { + DOVIExt *ext = s->ext_blocks; + if (!dm_compression) + ext->num_static = 0; + ext->num_dynamic = 0; + } + if ((ret = parse_ext_blocks(s, gb, 1, dm_compression, err_recognition)) < 0) { + ff_dovi_ctx_unref(s); + return ret; + } + + if (get_bits_left(gb) > 48 /* padding + CRC32 + terminator */) { + if ((ret = parse_ext_blocks(s, gb, 2, dm_compression, err_recognition)) < 0) { + ff_dovi_ctx_unref(s); + return ret; + } + } + } else { + s->color = &ff_dovi_color_default; + ff_refstruct_unref(&s->ext_blocks); + } + + return 0; +} diff --git a/libavcodec/dovi_rpuenc.c b/libavcodec/dovi_rpuenc.c new file mode 100644 index 000000000..8113ec44b --- /dev/null +++ b/libavcodec/dovi_rpuenc.c @@ -0,0 +1,937 @@ +/* + * Dolby Vision RPU encoder + * + * 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 "libavutil/avassert.h" +#include "libavutil/crc.h" +#include "libavutil/mem.h" + +#include "avcodec.h" +#include "dovi_rpu.h" +#include "itut35.h" +#include "put_bits.h" +#include "put_golomb.h" +#include "refstruct.h" + +static struct { + uint64_t pps; // maximum pixels per second + int width; // maximum width + int main; // maximum bitrate in main tier + int high; // maximum bitrate in high tier +} dv_levels[] = { + [1] = {1280*720*24, 1280, 20, 50}, + [2] = {1280*720*30, 1280, 20, 50}, + [3] = {1920*1080*24, 1920, 20, 70}, + [4] = {1920*1080*30, 2560, 20, 70}, + [5] = {1920*1080*60, 3840, 20, 70}, + [6] = {3840*2160*24, 3840, 25, 130}, + [7] = {3840*2160*30, 3840, 25, 130}, + [8] = {3840*2160*48, 3840, 40, 130}, + [9] = {3840*2160*60, 3840, 40, 130}, + [10] = {3840*2160*120, 3840, 60, 240}, + [11] = {3840*2160*120, 7680, 60, 240}, + [12] = {7680*4320*60, 7680, 120, 450}, + [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) +{ + AVDOVIDecoderConfigurationRecord *cfg; + const AVDOVIRpuDataHeader *hdr = NULL; + int dv_profile, dv_level, bl_compat_id = -1; + size_t cfg_size; + uint64_t pps; + + if (!s->enable) + goto skip; + + if (metadata) + hdr = av_dovi_get_header(metadata); + + if (s->enable == FF_DOVI_AUTOMATIC && !hdr) + goto skip; + + if (compression == AV_DOVI_COMPRESSION_RESERVED || + compression > AV_DOVI_COMPRESSION_EXTENDED) + return AVERROR(EINVAL); + + switch (codecpar->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: + if (hdr) { + dv_profile = ff_dovi_guess_profile_hevc(hdr); + break; + } + + /* 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)) + dv_profile = 5; + else + dv_profile = 8; + break; + default: + /* No other encoder should be calling this! */ + av_assert0(0); + return AVERROR_BUG; + } + + if (strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { + if (dv_profile == 9) { + if (codecpar->format != AV_PIX_FMT_YUV420P) + dv_profile = 0; + } else { + if (codecpar->format != AV_PIX_FMT_YUV420P10) + dv_profile = 0; + } + } + + switch (dv_profile) { + case 4: /* HEVC with enhancement layer */ + case 7: + if (s->enable > 0) { + av_log(s->logctx, AV_LOG_ERROR, "Coding of Dolby Vision enhancement " + "layers is currently unsupported."); + return AVERROR_PATCHWELCOME; + } else { + goto skip; + } + case 5: /* HEVC with proprietary IPTPQc2 */ + bl_compat_id = 0; + break; + case 10: + /* FIXME: check for proper H.273 tags once those are added */ + if (hdr && hdr->bl_video_full_range_flag) { + /* AV1 with proprietary IPTPQc2 */ + bl_compat_id = 0; + break; + } + /* 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) { + 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) { + bl_compat_id = 4; + } else if (codecpar->color_space == AVCOL_SPC_BT709 && + codecpar->color_primaries == AVCOL_PRI_BT709 && + codecpar->color_trc == AVCOL_TRC_BT709) { + bl_compat_id = 2; + } + } + + if (!dv_profile || bl_compat_id < 0) { + if (s->enable > 0) { + av_log(s->logctx, AV_LOG_ERROR, "Dolby Vision enabled, but could " + "not determine profile and compatibility mode. Double-check " + "colorspace and format settings for compatibility?\n"); + return AVERROR(EINVAL); + } + goto skip; + } + + if (compression != AV_DOVI_COMPRESSION_NONE) { + if (dv_profile < 8 && strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { + av_log(s->logctx, AV_LOG_ERROR, "Dolby Vision metadata compression " + "is not permitted for profiles 7 and earlier. (dv_profile: %d, " + "compression: %d)\n", dv_profile, compression); + return AVERROR(EINVAL); + } else if (compression == AV_DOVI_COMPRESSION_EXTENDED && + strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(s->logctx, AV_LOG_ERROR, "Dolby Vision extended metadata " + "compression is experimental and not supported by " + "devices."); + return AVERROR(EINVAL); + } else if (dv_profile == 8) { + av_log(s->logctx, AV_LOG_WARNING, "Dolby Vision metadata compression " + "for profile 8 is known to be unsupported by many devices, " + "use with caution.\n"); + } + } + + pps = codecpar->width * codecpar->height; + if (codecpar->framerate.num) { + pps = pps * codecpar->framerate.num / codecpar->framerate.den; + } else { + pps *= 25; /* sanity fallback */ + } + + dv_level = 0; + 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) + continue; + /* In theory, we should also test the bitrate when known, and + * distinguish between main and high tier. In practice, just ignore + * the bitrate constraints and hope they work out. This would ideally + * be handled by either the encoder or muxer directly. */ + dv_level = i; + break; + } + + 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); + 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); + dv_level = FF_ARRAY_ELEMS(dv_levels) - 1; + } + } + + cfg = av_dovi_alloc(&cfg_size); + if (!cfg) + return AVERROR(ENOMEM); + + if (!av_packet_side_data_add(&codecpar->coded_side_data, + &codecpar->nb_coded_side_data, + AV_PKT_DATA_DOVI_CONF, cfg, cfg_size, 0)) { + av_free(cfg); + return AVERROR(ENOMEM); + } + + cfg->dv_version_major = 1; + cfg->dv_version_minor = 0; + cfg->dv_profile = dv_profile; + cfg->dv_level = dv_level; + cfg->rpu_present_flag = 1; + cfg->el_present_flag = 0; + cfg->bl_present_flag = 1; + cfg->dv_bl_signal_compatibility_id = bl_compat_id; + cfg->dv_md_compression = compression; + + s->cfg = *cfg; + return 0; + +skip: + s->cfg = (AVDOVIDecoderConfigurationRecord) {0}; + return 0; +} + +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; + + sd = av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + AV_FRAME_DATA_DOVI_METADATA); + if (sd) + 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; +} + +/* Compares only the static DM metadata parts of AVDOVIColorMetadata (excluding + * dm_metadata_id and scene_refresh_flag) */ +static int cmp_dm_level0(const AVDOVIColorMetadata *dm1, + const AVDOVIColorMetadata *dm2) +{ + int ret; + for (int i = 0; i < FF_ARRAY_ELEMS(dm1->ycc_to_rgb_matrix); i++) { + if ((ret = av_cmp_q(dm1->ycc_to_rgb_matrix[i], dm2->ycc_to_rgb_matrix[i]))) + return ret; + } + + for (int i = 0; i < FF_ARRAY_ELEMS(dm1->ycc_to_rgb_offset); i++) { + if ((ret = av_cmp_q(dm1->ycc_to_rgb_offset[i], dm2->ycc_to_rgb_offset[i]))) + return ret; + } + + for (int i = 0; i < FF_ARRAY_ELEMS(dm1->rgb_to_lms_matrix); i++) { + if ((ret = av_cmp_q(dm1->rgb_to_lms_matrix[i], dm2->rgb_to_lms_matrix[i]))) + return ret; + } + + return memcmp(&dm1->signal_eotf, &dm2->signal_eotf, + sizeof(AVDOVIColorMetadata) -offsetof(AVDOVIColorMetadata, signal_eotf)); +} + +/* Tries to re-use the static ext blocks. May reorder `ext->dm_static` */ +static int try_reuse_ext(DOVIExt *ext, const AVDOVIMetadata *metadata) +{ + int i, j, idx = 0; + + for (i = 0; i < metadata->num_ext_blocks; i++) { + const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); + if (!ff_dovi_rpu_extension_is_static(dm->level)) + continue; + + /* Find the first matching ext block and move it to [idx] */ + for (j = idx; j < ext->num_static; j++) { + if (!memcmp(&ext->dm_static[j], dm, sizeof(*dm))) { + if (j != idx) + FFSWAP(AVDOVIDmData, ext->dm_static[j], ext->dm_static[idx]); + idx++; + break; + } + } + + if (j == ext->num_static) { + /* Found no matching ext block */ + return 0; + } + } + + /* If idx is less than ext->num_static, then there are extra unmatched + * ext blocks inside ext->dm_static */ + return idx == ext->num_static; +} + +static inline void put_ue_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr, + uint64_t coef) +{ + union { uint32_t u32; float f32; } fpart; + + 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, + 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); + break; + } +} + +static inline void put_se_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr, + uint64_t coef) +{ + union { uint32_t u32; float f32; } fpart; + + 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, + 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); + break; + } +} + +static int av_q2den(AVRational q, int den) +{ + if (!q.den || q.den == den) + return q.num; + q = av_mul_q(q, av_make_q(den, 1)); + return (q.num + (q.den >> 1)) / q.den; +} + +static void generate_ext_v1(PutBitContext *pb, const AVDOVIDmData *dm) +{ + int ext_block_length, start_pos, pad_bits; + + switch (dm->level) { + case 1: ext_block_length = 5; break; + case 2: ext_block_length = 11; break; + case 4: ext_block_length = 3; break; + case 5: ext_block_length = 7; break; + case 6: ext_block_length = 8; break; + case 255: ext_block_length = 6; break; + default: return; + } + + set_ue_golomb(pb, ext_block_length); + put_bits(pb, 8, dm->level); + start_pos = put_bits_count(pb); + + switch (dm->level) { + case 1: + put_bits(pb, 12, dm->l1.min_pq); + put_bits(pb, 12, dm->l1.max_pq); + put_bits(pb, 12, dm->l1.avg_pq); + break; + case 2: + put_bits(pb, 12, dm->l2.target_max_pq); + put_bits(pb, 12, dm->l2.trim_slope); + put_bits(pb, 12, dm->l2.trim_offset); + put_bits(pb, 12, dm->l2.trim_power); + put_bits(pb, 12, dm->l2.trim_chroma_weight); + put_bits(pb, 12, dm->l2.trim_saturation_gain); + put_sbits(pb, 13, dm->l2.ms_weight); + break; + case 4: + put_bits(pb, 12, dm->l4.anchor_pq); + put_bits(pb, 12, dm->l4.anchor_power); + break; + case 5: + put_bits(pb, 13, dm->l5.left_offset); + put_bits(pb, 13, dm->l5.right_offset); + put_bits(pb, 13, dm->l5.top_offset); + put_bits(pb, 13, dm->l5.bottom_offset); + break; + case 6: + put_bits(pb, 16, dm->l6.max_luminance); + put_bits(pb, 16, dm->l6.min_luminance); + put_bits(pb, 16, dm->l6.max_cll); + put_bits(pb, 16, dm->l6.max_fall); + break; + case 255: + put_bits(pb, 8, dm->l255.dm_run_mode); + put_bits(pb, 8, dm->l255.dm_run_version); + for (int i = 0; i < 4; i++) + put_bits(pb, 8, dm->l255.dm_debug[i]); + break; + } + + pad_bits = ext_block_length * 8 - (put_bits_count(pb) - start_pos); + av_assert1(pad_bits >= 0); + put_bits(pb, pad_bits, 0); +} + +static void put_cie_xy(PutBitContext *pb, AVCIExy xy) +{ + const int denom = 32767; + put_sbits(pb, 16, av_q2den(xy.x, denom)); + put_sbits(pb, 16, av_q2den(xy.y, denom)); +} + +#define ANY6(arr) (arr[0] || arr[1] || arr[2] || arr[3] || arr[4] || arr[5]) +#define ANY_XY(xy) (xy.x.num || xy.y.num) +#define ANY_CSP(csp) (ANY_XY(csp.prim.r) || ANY_XY(csp.prim.g) || \ + ANY_XY(csp.prim.b) || ANY_XY(csp.wp)) + +static void generate_ext_v2(PutBitContext *pb, const AVDOVIDmData *dm) +{ + int ext_block_length, start_pos, pad_bits; + + switch (dm->level) { + case 3: ext_block_length = 5; break; + case 8: + if (ANY6(dm->l8.hue_vector_field)) { + ext_block_length = 25; + } else if (ANY6(dm->l8.saturation_vector_field)) { + ext_block_length = 19; + } else if (dm->l8.clip_trim) { + ext_block_length = 13; + } else if (dm->l8.target_mid_contrast) { + ext_block_length = 12; + } else { + ext_block_length = 10; + } + break; + case 9: + if (ANY_CSP(dm->l9.source_display_primaries)) { + ext_block_length = 17; + } else { + ext_block_length = 1; + } + break; + case 10: + if (ANY_CSP(dm->l10.target_display_primaries)) { + ext_block_length = 21; + } else { + ext_block_length = 5; + } + break; + case 11: ext_block_length = 4; break; + case 254: ext_block_length = 2; break; + default: return; + } + + set_ue_golomb(pb, ext_block_length); + put_bits(pb, 8, dm->level); + start_pos = put_bits_count(pb); + + switch (dm->level) { + case 3: + put_bits(pb, 12, dm->l3.min_pq_offset); + put_bits(pb, 12, dm->l3.max_pq_offset); + put_bits(pb, 12, dm->l3.avg_pq_offset); + break; + case 8: + put_bits(pb, 8, dm->l8.target_display_index); + put_bits(pb, 12, dm->l8.trim_slope); + put_bits(pb, 12, dm->l8.trim_offset); + put_bits(pb, 12, dm->l8.trim_power); + put_bits(pb, 12, dm->l8.trim_chroma_weight); + put_bits(pb, 12, dm->l8.trim_saturation_gain); + put_bits(pb, 12, dm->l8.ms_weight); + if (ext_block_length < 12) + break; + put_bits(pb, 12, dm->l8.target_mid_contrast); + if (ext_block_length < 13) + break; + put_bits(pb, 12, dm->l8.clip_trim); + if (ext_block_length < 19) + break; + for (int i = 0; i < 6; i++) + put_bits(pb, 8, dm->l8.saturation_vector_field[i]); + if (ext_block_length < 25) + break; + for (int i = 0; i < 6; i++) + put_bits(pb, 8, dm->l8.hue_vector_field[i]); + break; + case 9: + put_bits(pb, 8, dm->l9.source_primary_index); + if (ext_block_length < 17) + break; + put_cie_xy(pb, dm->l9.source_display_primaries.prim.r); + put_cie_xy(pb, dm->l9.source_display_primaries.prim.g); + put_cie_xy(pb, dm->l9.source_display_primaries.prim.b); + put_cie_xy(pb, dm->l9.source_display_primaries.wp); + break; + case 10: + put_bits(pb, 8, dm->l10.target_display_index); + put_bits(pb, 12, dm->l10.target_max_pq); + put_bits(pb, 12, dm->l10.target_min_pq); + put_bits(pb, 8, dm->l10.target_primary_index); + if (ext_block_length < 21) + break; + put_cie_xy(pb, dm->l10.target_display_primaries.prim.r); + put_cie_xy(pb, dm->l10.target_display_primaries.prim.g); + put_cie_xy(pb, dm->l10.target_display_primaries.prim.b); + put_cie_xy(pb, dm->l10.target_display_primaries.wp); + break; + case 11: + put_bits(pb, 8, dm->l11.content_type); + 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); + break; + case 254: + put_bits(pb, 8, dm->l254.dm_mode); + put_bits(pb, 8, dm->l254.dm_version_index); + break; + } + + pad_bits = ext_block_length * 8 - (put_bits_count(pb) - start_pos); + av_assert1(pad_bits >= 0); + put_bits(pb, pad_bits, 0); +} + +int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, + int flags, uint8_t **out_rpu, int *out_size) +{ + PutBitContext *pb = &(PutBitContext){0}; + const AVDOVIRpuDataHeader *hdr; + const AVDOVIDataMapping *mapping; + const AVDOVIColorMetadata *color; + int vdr_dm_metadata_present, vdr_rpu_id, use_prev_vdr_rpu, profile, + buffer_size, rpu_size, pad, zero_run, dm_compression; + int num_ext_blocks_v1, num_ext_blocks_v2; + int dv_md_compression = s->cfg.dv_md_compression; + uint32_t crc; + uint8_t *dst; + if (!metadata) { + *out_rpu = NULL; + *out_size = 0; + return 0; + } + + hdr = av_dovi_get_header(metadata); + mapping = av_dovi_get_mapping(metadata); + color = av_dovi_get_color(metadata); + av_assert0(s->cfg.dv_profile); + + if (!(flags & FF_DOVI_COMPRESS_RPU)) + dv_md_compression = AV_DOVI_COMPRESSION_NONE; + else if (dv_md_compression == AV_DOVI_COMPRESSION_RESERVED) + return AVERROR(EINVAL); + + if (hdr->rpu_type != 2) { + av_log(s->logctx, AV_LOG_ERROR, "Unhandled RPU type %"PRIu8"\n", + hdr->rpu_type); + return AVERROR_INVALIDDATA; + } + + if (!(flags & FF_DOVI_COMPRESS_RPU)) + dv_md_compression = AV_DOVI_COMPRESSION_NONE; + + vdr_rpu_id = mapping->vdr_rpu_id; + use_prev_vdr_rpu = 0; + + if (!s->vdr[vdr_rpu_id]) { + s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(AVDOVIDataMapping)); + if (!s->vdr[vdr_rpu_id]) + return AVERROR(ENOMEM); + } + + switch (dv_md_compression) { + case AV_DOVI_COMPRESSION_LIMITED: + /* Limited metadata compression requires vdr_rpi_id == 0 */ + if (vdr_rpu_id != 0) + break; + /* fall through */ + case AV_DOVI_COMPRESSION_EXTENDED: + if (s->vdr[vdr_rpu_id]) + use_prev_vdr_rpu = !memcmp(s->vdr[vdr_rpu_id], mapping, sizeof(*mapping)); + break; + case AV_DOVI_COMPRESSION_RESERVED: + return AVERROR(EINVAL); + } + + if (s->cfg.dv_md_compression != AV_DOVI_COMPRESSION_EXTENDED) { + /* Flush VDRs to avoid leaking old state; maintaining multiple VDR + * 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]); + } + } + + if (metadata->num_ext_blocks && !s->ext_blocks) { + s->ext_blocks = ff_refstruct_allocz(sizeof(*s->ext_blocks)); + if (!s->ext_blocks) + return AVERROR(ENOMEM); + } + + vdr_dm_metadata_present = memcmp(color, &ff_dovi_color_default, sizeof(*color)); + if (metadata->num_ext_blocks) + vdr_dm_metadata_present = 1; + + if (vdr_dm_metadata_present && !s->dm) { + s->dm = ff_refstruct_allocz(sizeof(AVDOVIColorMetadata)); + if (!s->dm) + return AVERROR(ENOMEM); + } + + dm_compression = 0; + if (dv_md_compression != AV_DOVI_COMPRESSION_NONE) { + if (!cmp_dm_level0(s->dm, color) && try_reuse_ext(s->ext_blocks, metadata)) + dm_compression = 1; + } + + num_ext_blocks_v1 = num_ext_blocks_v2 = 0; + for (int i = 0; i < metadata->num_ext_blocks; i++) { + const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); + if (dm_compression && ff_dovi_rpu_extension_is_static(dm->level)) + continue; + + switch (dm->level) { + case 1: + case 2: + case 4: + case 5: + case 6: + case 255: + num_ext_blocks_v1++; + break; + case 3: + case 8: + case 9: + case 10: + case 11: + case 254: + num_ext_blocks_v2++; + break; + default: + av_log(s->logctx, AV_LOG_ERROR, "Invalid ext block level %d\n", + dm->level); + return AVERROR_INVALIDDATA; + } + } + + buffer_size = 12 /* vdr seq info */ + 5 /* CRC32 + terminator */; + buffer_size += num_ext_blocks_v1 * 13; + buffer_size += num_ext_blocks_v2 * 28; + if (!use_prev_vdr_rpu) { + buffer_size += 160; + for (int c = 0; c < 3; c++) { + for (int i = 0; i < mapping->curves[c].num_pivots - 1; i++) { + switch (mapping->curves[c].mapping_idc[i]) { + case AV_DOVI_MAPPING_POLYNOMIAL: buffer_size += 26; break; + case AV_DOVI_MAPPING_MMR: buffer_size += 177; break; + } + } + } + } + if (vdr_dm_metadata_present) + buffer_size += 67; + + av_fast_padded_malloc(&s->rpu_buf, &s->rpu_buf_sz, buffer_size); + if (!s->rpu_buf) + return AVERROR(ENOMEM); + init_put_bits(pb, s->rpu_buf, s->rpu_buf_sz); + + /* RPU header */ + put_bits(pb, 6, hdr->rpu_type); + put_bits(pb, 11, hdr->rpu_format); + put_bits(pb, 4, hdr->vdr_rpu_profile); + put_bits(pb, 4, hdr->vdr_rpu_level); + put_bits(pb, 1, 1); /* vdr_seq_info_present */ + put_bits(pb, 1, hdr->chroma_resampling_explicit_filter_flag); + put_bits(pb, 2, hdr->coef_data_type); + if (hdr->coef_data_type == RPU_COEFF_FIXED) + set_ue_golomb(pb, hdr->coef_log2_denom); + put_bits(pb, 2, hdr->vdr_rpu_normalized_idc); + put_bits(pb, 1, hdr->bl_video_full_range_flag); + if ((hdr->rpu_format & 0x700) == 0) { + int ext_mapping_idc = (hdr->ext_mapping_idc_5_7 << 5) | hdr->ext_mapping_idc_0_4; + set_ue_golomb(pb, hdr->bl_bit_depth - 8); + set_ue_golomb(pb, (ext_mapping_idc << 8) | (hdr->el_bit_depth - 8)); + set_ue_golomb(pb, hdr->vdr_bit_depth - 8); + put_bits(pb, 1, hdr->spatial_resampling_filter_flag); + put_bits(pb, 3, dm_compression); + put_bits(pb, 1, hdr->el_spatial_resampling_filter_flag); + put_bits(pb, 1, hdr->disable_residual_flag); + } + s->header = *hdr; + + put_bits(pb, 1, vdr_dm_metadata_present); + put_bits(pb, 1, use_prev_vdr_rpu); + set_ue_golomb(pb, vdr_rpu_id); + s->mapping = s->vdr[vdr_rpu_id]; + + profile = s->cfg.dv_profile ? s->cfg.dv_profile : ff_dovi_guess_profile_hevc(hdr); + + if (!use_prev_vdr_rpu) { + set_ue_golomb(pb, mapping->mapping_color_space); + set_ue_golomb(pb, mapping->mapping_chroma_format_idc); + for (int c = 0; c < 3; c++) { + const AVDOVIReshapingCurve *curve = &mapping->curves[c]; + int prev = 0; + set_ue_golomb(pb, curve->num_pivots - 2); + for (int i = 0; i < curve->num_pivots; i++) { + put_bits(pb, hdr->bl_bit_depth, curve->pivots[i] - prev); + prev = curve->pivots[i]; + } + } + + if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) { + put_bits(pb, 3, mapping->nlq_method_idc); + put_bits(pb, hdr->bl_bit_depth, mapping->nlq_pivots[0]); + put_bits(pb, hdr->bl_bit_depth, mapping->nlq_pivots[1] - mapping->nlq_pivots[0]); + } + + set_ue_golomb(pb, mapping->num_x_partitions - 1); + set_ue_golomb(pb, mapping->num_y_partitions - 1); + + for (int c = 0; c < 3; c++) { + const AVDOVIReshapingCurve *curve = &mapping->curves[c]; + for (int i = 0; i < curve->num_pivots - 1; i++) { + set_ue_golomb(pb, curve->mapping_idc[i]); + switch (curve->mapping_idc[i]) { + case AV_DOVI_MAPPING_POLYNOMIAL: { + set_ue_golomb(pb, curve->poly_order[i] - 1); + if (curve->poly_order[i] == 1) + put_bits(pb, 1, 0); /* linear_interp_flag */ + for (int k = 0; k <= curve->poly_order[i]; k++) + put_se_coef(pb, hdr, curve->poly_coef[i][k]); + break; + } + case AV_DOVI_MAPPING_MMR: { + put_bits(pb, 2, curve->mmr_order[i] - 1); + put_se_coef(pb, hdr, curve->mmr_constant[i]); + for (int j = 0; j < curve->mmr_order[i]; j++) { + for (int k = 0; k < 7; k++) + put_se_coef(pb, hdr, curve->mmr_coef[i][j][k]); + } + break; + } + } + } + } + + if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) { + for (int c = 0; c < 3; c++) { + const AVDOVINLQParams *nlq = &mapping->nlq[c]; + put_bits(pb, hdr->el_bit_depth, nlq->nlq_offset); + put_ue_coef(pb, hdr, nlq->vdr_in_max); + switch (mapping->nlq_method_idc) { + case AV_DOVI_NLQ_LINEAR_DZ: + put_ue_coef(pb, hdr, nlq->linear_deadzone_slope); + put_ue_coef(pb, hdr, nlq->linear_deadzone_threshold); + break; + } + } + } + + memcpy(s->vdr[vdr_rpu_id], mapping, sizeof(*mapping)); + } + + if (vdr_dm_metadata_present) { + DOVIExt *ext = s->ext_blocks; + const int denom = profile == 4 ? (1 << 30) : (1 << 28); + set_ue_golomb(pb, color->dm_metadata_id); /* affected_dm_id */ + set_ue_golomb(pb, color->dm_metadata_id); /* current_dm_id */ + set_ue_golomb(pb, color->scene_refresh_flag); + if (!dm_compression) { + for (int i = 0; i < 9; i++) + put_sbits(pb, 16, av_q2den(color->ycc_to_rgb_matrix[i], 1 << 13)); + for (int i = 0; i < 3; i++) + put_bits32(pb, av_q2den(color->ycc_to_rgb_offset[i], denom)); + for (int i = 0; i < 9; i++) + put_sbits(pb, 16, av_q2den(color->rgb_to_lms_matrix[i], 1 << 14)); + put_bits(pb, 16, color->signal_eotf); + put_bits(pb, 16, color->signal_eotf_param0); + put_bits(pb, 16, color->signal_eotf_param1); + put_bits32(pb, color->signal_eotf_param2); + put_bits(pb, 5, color->signal_bit_depth); + put_bits(pb, 2, color->signal_color_space); + put_bits(pb, 2, color->signal_chroma_format); + put_bits(pb, 2, color->signal_full_range_flag); + put_bits(pb, 12, color->source_min_pq); + put_bits(pb, 12, color->source_max_pq); + put_bits(pb, 10, color->source_diagonal); + } + + memcpy(s->dm, color, sizeof(*color)); + s->color = s->dm; + + /* Extension blocks */ + set_ue_golomb(pb, num_ext_blocks_v1); + align_put_bits(pb); + for (int i = 0; i < metadata->num_ext_blocks; i++) { + const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); + if (dm_compression && ff_dovi_rpu_extension_is_static(dm->level)) + continue; + generate_ext_v1(pb, dm); + } + + if (num_ext_blocks_v2) { + set_ue_golomb(pb, num_ext_blocks_v2); + align_put_bits(pb); + for (int i = 0; i < metadata->num_ext_blocks; i++) { + const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); + if (dm_compression && ff_dovi_rpu_extension_is_static(dm->level)) + continue; + generate_ext_v2(pb, av_dovi_get_ext(metadata, i)); + } + } + + if (ext) { + size_t ext_sz = FFMIN(sizeof(AVDOVIDmData), metadata->ext_block_size); + ext->num_dynamic = 0; + if (!dm_compression) + ext->num_static = 0; + for (int i = 0; i < metadata->num_ext_blocks; i++) { + const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); + if (!ff_dovi_rpu_extension_is_static(dm->level)) + memcpy(&ext->dm_dynamic[ext->num_dynamic++], dm, ext_sz); + else if (!dm_compression) + memcpy(&ext->dm_static[ext->num_static++], dm, ext_sz); + } + } + } else { + s->color = &ff_dovi_color_default; + ff_refstruct_unref(&s->ext_blocks); + } + + flush_put_bits(pb); + crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, + s->rpu_buf, put_bytes_output(pb))); + put_bits32(pb, crc); + put_bits(pb, 8, 0x80); /* terminator */ + flush_put_bits(pb); + + rpu_size = put_bytes_output(pb); + if (flags & FF_DOVI_WRAP_T35) { + *out_rpu = av_malloc(rpu_size + 15); + if (!*out_rpu) + return AVERROR(ENOMEM); + init_put_bits(pb, *out_rpu, rpu_size + 15); + put_bits(pb, 8, ITU_T_T35_COUNTRY_CODE_US); + put_bits(pb, 16, ITU_T_T35_PROVIDER_CODE_DOLBY); + put_bits32(pb, 0x800); /* provider_oriented_code */ + put_bits(pb, 27, 0x01be6841u); /* fixed EMDF header, see above */ + if (rpu_size > 0xFF) { + av_assert2(rpu_size <= 0x10000); + put_bits(pb, 8, (rpu_size >> 8) - 1); + put_bits(pb, 1, 1); /* read_more */ + put_bits(pb, 8, rpu_size & 0xFF); + put_bits(pb, 1, 0); + } else { + put_bits(pb, 8, rpu_size); + put_bits(pb, 1, 0); + } + ff_copy_bits(pb, s->rpu_buf, rpu_size * 8); + put_bits(pb, 17, 0x400); /* emdf payload id + emdf_protection */ + + pad = pb->bit_left & 7; + put_bits(pb, pad, (1 << pad) - 1); /* pad to next byte with 1 bits */ + flush_put_bits(pb); + *out_size = put_bytes_output(pb); + return 0; + } else if (flags & FF_DOVI_WRAP_NAL) { + *out_rpu = dst = av_malloc(4 + rpu_size * 3 / 2); /* worst case */ + if (!*out_rpu) + return AVERROR(ENOMEM); + *dst++ = 25; /* NAL prefix */ + zero_run = 0; + for (int i = 0; i < rpu_size; i++) { + if (zero_run < 2) { + if (s->rpu_buf[i] == 0) { + zero_run++; + } else { + zero_run = 0; + } + } else { + if ((s->rpu_buf[i] & ~3) == 0) { + /* emulation prevention */ + *dst++ = 3; + } + zero_run = s->rpu_buf[i] == 0; + } + *dst++ = s->rpu_buf[i]; + } + *out_size = dst - *out_rpu; + return 0; + } else { + /* Return intermediate buffer directly */ + *out_rpu = s->rpu_buf; + *out_size = rpu_size; + s->rpu_buf = NULL; + s->rpu_buf_sz = 0; + return 0; + } +} diff --git a/libavcodec/dsd.c b/libavcodec/dsd.c index e039302c9..1093c5e2d 100644 --- a/libavcodec/dsd.c +++ b/libavcodec/dsd.c @@ -68,7 +68,8 @@ static const double htaps[HTAPS] = { 3.423230509967409e-07, 1.244182214744588e-07, 3.130441005359396e-08 }; -static float ctables[CTABLES][256]; +static double ctables_lsbf[CTABLES][256]; +static double ctables_msbf[CTABLES][256]; static av_cold void dsd_ctables_tableinit(void) { @@ -81,8 +82,10 @@ static av_cold void dsd_ctables_tableinit(void) for (t = 0; t < CTABLES; ++t) acc[t] += sign * htaps[t * 8 + m]; } - for (t = 0; t < CTABLES; ++t) - ctables[CTABLES - 1 - t][e] = acc[t]; + for (t = 0; t < CTABLES; ++t) { + ctables_msbf[CTABLES - 1 - t][e] = acc[t]; + ctables_lsbf[CTABLES - 1 - t][ff_reverse[e]] = acc[t]; + } } } @@ -100,13 +103,14 @@ void ff_dsd2pcm_translate(DSDContext* s, size_t samples, int lsbf, unsigned pos, i; uint8_t* p; double sum; + const double (*const ctables)[256] = lsbf ? ctables_lsbf : ctables_msbf; pos = s->pos; memcpy(buf, s->buf, sizeof(buf)); while (samples-- > 0) { - buf[pos] = lsbf ? ff_reverse[*src] : *src; + buf[pos] = *src; src += src_stride; p = buf + ((pos - CTABLES) & FIFOMASK); diff --git a/libavcodec/dsddec.c b/libavcodec/dsddec.c index 396207577..dd1ea8378 100644 --- a/libavcodec/dsddec.c +++ b/libavcodec/dsddec.c @@ -26,7 +26,8 @@ * Direct Stream Digital (DSD) decoder */ -#include "libavcodec/internal.h" +#include "libavutil/mem.h" + #include "avcodec.h" #include "codec_internal.h" #include "decode.h" @@ -55,7 +56,8 @@ static av_cold int decode_init(AVCodecContext *avctx) if (!s) return AVERROR(ENOMEM); - silence = avctx->codec_id == AV_CODEC_ID_DSD_LSBF || avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR ? DSD_SILENCE_REVERSED : DSD_SILENCE; + silence = avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR || + avctx->codec_id == AV_CODEC_ID_DSD_LSBF ? DSD_SILENCE_REVERSED : DSD_SILENCE; for (i = 0; i < avctx->ch_layout.nb_channels; i++) { s[i].pos = 0; memset(s[i].buf, silence, sizeof(s[i].buf)); diff --git a/libavcodec/dsicinvideo.c b/libavcodec/dsicinvideo.c index 000d79e16..10b536d40 100644 --- a/libavcodec/dsicinvideo.c +++ b/libavcodec/dsicinvideo.c @@ -24,6 +24,7 @@ * Delphine Software International CIN video decoder */ +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/dv.c b/libavcodec/dv.c index eb49978ad..194d98256 100644 --- a/libavcodec/dv.c +++ b/libavcodec/dv.c @@ -166,7 +166,7 @@ static inline void dv_calc_mb_coordinates(const AVDVProfile *d, int chan, } } -int ff_dv_init_dynamic_tables(DVwork_chunk *work_chunks, const AVDVProfile *d) +void ff_dv_init_dynamic_tables(DVwork_chunk *work_chunks, const AVDVProfile *d) { int j, i, c, s, p; @@ -185,6 +185,4 @@ int ff_dv_init_dynamic_tables(DVwork_chunk *work_chunks, const AVDVProfile *d) } } } - - return 0; } diff --git a/libavcodec/dv_internal.h b/libavcodec/dv_internal.h index 4b4151c88..05e26a813 100644 --- a/libavcodec/dv_internal.h +++ b/libavcodec/dv_internal.h @@ -32,7 +32,7 @@ typedef struct DVwork_chunk { uint16_t mb_coordinates[5]; } DVwork_chunk; -int ff_dv_init_dynamic_tables(DVwork_chunk *work_chunks, const AVDVProfile *d); +void ff_dv_init_dynamic_tables(DVwork_chunk *work_chunks, const AVDVProfile *d); static inline int dv_work_pool_size(const AVDVProfile *d) { diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c index bcc607d1d..4553c45b3 100644 --- a/libavcodec/dvbsubdec.c +++ b/libavcodec/dvbsubdec.c @@ -26,6 +26,7 @@ #include "decode.h" #include "libavutil/colorspace.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/thread.h" diff --git a/libavcodec/dvdec.c b/libavcodec/dvdec.c index a06e4807e..8297b6d2f 100644 --- a/libavcodec/dvdec.c +++ b/libavcodec/dvdec.c @@ -637,18 +637,12 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, AVFrame *frame, } if (sys != s->sys) { - ret = ff_dv_init_dynamic_tables(s->work_chunks, sys); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error initializing the work tables.\n"); - return ret; - } + ff_dv_init_dynamic_tables(s->work_chunks, sys); dv_init_weight_tables(s, sys); s->sys = sys; } s->frame = frame; - frame->flags |= AV_FRAME_FLAG_KEY; - frame->pict_type = AV_PICTURE_TYPE_I; avctx->pix_fmt = s->sys->pix_fmt; avctx->framerate = av_inv_q(s->sys->time_base); avctx->bit_rate = av_rescale_q(s->sys->frame_size, diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c index a5da0d7b0..f8769353a 100644 --- a/libavcodec/dvdsubdec.c +++ b/libavcodec/dvdsubdec.c @@ -28,6 +28,7 @@ #include "libavutil/attributes.h" #include "libavutil/colorspace.h" #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/bswap.h" diff --git a/libavcodec/dvdsubenc.c b/libavcodec/dvdsubenc.c index 06c2cf5e5..c6110c29f 100644 --- a/libavcodec/dvdsubenc.c +++ b/libavcodec/dvdsubenc.c @@ -25,6 +25,7 @@ #include "libavutil/avassert.h" #include "libavutil/bprint.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" typedef struct { diff --git a/libavcodec/dvenc.c b/libavcodec/dvenc.c index ce2124708..db79497b5 100644 --- a/libavcodec/dvenc.c +++ b/libavcodec/dvenc.c @@ -70,7 +70,6 @@ static av_cold int dvvideo_encode_init(AVCodecContext *avctx) { DVEncContext *s = avctx->priv_data; FDCTDSPContext fdsp; - MECmpContext mecc; PixblockDSPContext pdsp; int ret; @@ -93,25 +92,26 @@ static av_cold int dvvideo_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ret = ff_dv_init_dynamic_tables(s->work_chunks, s->sys); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Error initializing work tables.\n"); - return ret; + ff_dv_init_dynamic_tables(s->work_chunks, s->sys); + + if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) { + MECmpContext mecc; + me_cmp_func ildct_cmp[6]; + + ff_me_cmp_init(&mecc, avctx); + ret = ff_set_cmp(&mecc, ildct_cmp, avctx->ildct_cmp, 0); + if (ret < 0) + return ret; + if (!ildct_cmp[5]) + return AVERROR(EINVAL); + s->ildct_cmp = ildct_cmp[5]; } memset(&fdsp,0, sizeof(fdsp)); - memset(&mecc,0, sizeof(mecc)); memset(&pdsp,0, sizeof(pdsp)); ff_fdctdsp_init(&fdsp, avctx); - ff_me_cmp_init(&mecc, avctx); ff_pixblockdsp_init(&pdsp, avctx); - ret = ff_set_cmp(&mecc, mecc.ildct_cmp, avctx->ildct_cmp); - if (ret < 0) - return AVERROR(EINVAL); - s->get_pixels = pdsp.get_pixels; - s->ildct_cmp = mecc.ildct_cmp[5]; - s->fdct[0] = fdsp.fdct; s->fdct[1] = fdsp.fdct248; @@ -219,7 +219,7 @@ static av_always_inline PutBitContext *dv_encode_ac(EncBlockInfo *bi, if (bits_left) { size -= bits_left; put_bits(pb, bits_left, vlc >> size); - vlc = av_mod_uintp2(vlc, size); + vlc = av_zero_extend(vlc, size); } if (pb + 1 >= pb_end) { bi->partial_bit_count = size; @@ -1251,5 +1251,6 @@ const FFCodec ff_dvvideo_encoder = { AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &dvvideo_encode_class, }; diff --git a/libavcodec/dxa.c b/libavcodec/dxa.c index d33ac3c8b..59e2411d8 100644 --- a/libavcodec/dxa.c +++ b/libavcodec/dxa.c @@ -24,8 +24,8 @@ * DXA Video decoder */ -#include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "bytestream.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/dxtory.c b/libavcodec/dxtory.c index f36420cdd..a9b5d835d 100644 --- a/libavcodec/dxtory.c +++ b/libavcodec/dxtory.c @@ -863,8 +863,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *pic, if (ret) return ret; - pic->pict_type = AV_PICTURE_TYPE_I; - pic->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/dxv.c b/libavcodec/dxv.c index e3107414c..ba2322272 100644 --- a/libavcodec/dxv.c +++ b/libavcodec/dxv.c @@ -23,8 +23,8 @@ #include #include "libavutil/imgutils.h" +#include "libavutil/mem.h" -#include "mathops.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" @@ -1048,8 +1048,6 @@ static int dxv_decode(AVCodecContext *avctx, AVFrame *frame, } /* Frame is ready to be output. */ - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c index 59025633f..22ecd5aca 100644 --- a/libavcodec/dxva2.c +++ b/libavcodec/dxva2.c @@ -26,6 +26,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/time.h" #include "avcodec.h" @@ -117,7 +118,7 @@ static int dxva_get_decoder_configuration(AVCodecContext *avctx, for (i = 0; i < cfg_count; i++) { unsigned score; - UINT ConfigBitstreamRaw; + UINT ConfigBitstreamRaw = 0; GUID guidConfigBitstreamEncryption; #if CONFIG_D3D11VA @@ -268,7 +269,7 @@ static int dxva_get_decoder_guid(AVCodecContext *avctx, void *service, void *sur *decoder_guid = ff_GUID_NULL; for (i = 0; dxva_modes[i].guid; i++) { const dxva_mode *mode = &dxva_modes[i]; - int validate; + int validate = 0; if (!dxva_check_codec_compatibility(avctx, mode)) continue; @@ -805,7 +806,7 @@ int ff_dxva2_commit_buffer(AVCodecContext *avctx, unsigned type, const void *data, unsigned size, unsigned mb_count) { - void *dxva_data; + void *dxva_data = NULL; unsigned dxva_size; int result; HRESULT hr = 0; @@ -827,7 +828,7 @@ int ff_dxva2_commit_buffer(AVCodecContext *avctx, type, (unsigned)hr); return -1; } - if (size <= dxva_size) { + if (dxva_data && size <= dxva_size) { memcpy(dxva_data, data, size); #if CONFIG_D3D11VA @@ -905,7 +906,7 @@ int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame, #endif DECODER_BUFFER_DESC *buffer = NULL, *buffer_slice = NULL; int result, runs = 0; - HRESULT hr; + HRESULT hr = -1; unsigned type; FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); diff --git a/libavcodec/dxva2_av1.c b/libavcodec/dxva2_av1.c index 85d747bca..ea97fcb87 100644 --- a/libavcodec/dxva2_av1.c +++ b/libavcodec/dxva2_av1.c @@ -23,6 +23,7 @@ #include "config_components.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "dxva2_internal.h" @@ -100,7 +101,7 @@ int ff_dxva2_av1_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACont pp->coding.dual_filter = seq->enable_dual_filter; pp->coding.jnt_comp = seq->enable_jnt_comp; pp->coding.screen_content_tools = frame_header->allow_screen_content_tools; - pp->coding.integer_mv = frame_header->force_integer_mv || !(frame_header->frame_type & 1); + pp->coding.integer_mv = h->cur_frame.force_integer_mv; pp->coding.cdef = seq->enable_cdef; pp->coding.restoration = seq->enable_restoration; pp->coding.film_grain = seq->film_grain_params_present && !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN); @@ -137,9 +138,9 @@ int ff_dxva2_av1_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACont int8_t ref_idx = frame_header->ref_frame_idx[i]; AVFrame *ref_frame = h->ref[ref_idx].f; - pp->frame_refs[i].width = ref_frame->width; - pp->frame_refs[i].height = ref_frame->height; - pp->frame_refs[i].Index = ref_frame->buf[0] ? ref_idx : 0xFF; + pp->frame_refs[i].width = ref_frame ? ref_frame->width : 0; + pp->frame_refs[i].height = ref_frame ? ref_frame->height : 0; + pp->frame_refs[i].Index = ref_frame ? ref_idx : 0xFF; /* Global Motion */ pp->frame_refs[i].wminvalid = h->cur_frame.gm_invalid[AV1_REF_FRAME_LAST + i]; @@ -150,7 +151,7 @@ int ff_dxva2_av1_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACont } for (i = 0; i < AV1_NUM_REF_FRAMES; i++) { AVFrame *ref_frame = h->ref[i].f; - if (ref_frame->buf[0]) + if (ref_frame) pp->RefFrameMapTextureIndex[i] = ff_dxva2_get_surface_index(avctx, ctx, ref_frame, 0); } @@ -353,7 +354,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, const AV1DecContext *h = avctx->priv_data; AVDXVAContext *ctx = DXVA_CONTEXT(avctx); struct av1_dxva2_picture_context *ctx_pic = h->cur_frame.hwaccel_picture_private; - void *dxva_data_ptr; + void *dxva_data_ptr = NULL; uint8_t *dxva_data; unsigned dxva_size; unsigned padding; @@ -381,7 +382,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, dxva_data = dxva_data_ptr; - if (ctx_pic->bitstream_size > dxva_size) { + if (!dxva_data || ctx_pic->bitstream_size > dxva_size) { av_log(avctx, AV_LOG_ERROR, "Bitstream size exceeds hardware buffer"); return -1; } diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c index 31d74a716..d01d1e76e 100644 --- a/libavcodec/dxva2_hevc.c +++ b/libavcodec/dxva2_hevc.c @@ -25,8 +25,8 @@ #include "libavutil/avassert.h" #include "dxva2_internal.h" -#include "hevc_data.h" -#include "hevcdec.h" +#include "hevc/data.h" +#include "hevc/hevcdec.h" #include "hwaccel_internal.h" #define MAX_SLICES 256 @@ -61,9 +61,10 @@ void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo DXVA_PicParams_HEVC *pp) { const HEVCContext *h = avctx->priv_data; - const HEVCFrame *current_picture = h->ref; - const HEVCSPS *sps = h->ps.sps; - const HEVCPPS *pps = h->ps.pps; + const HEVCLayerContext *l = &h->layers[h->cur_layer]; + const HEVCFrame *current_picture = h->cur_frame; + const HEVCPPS *pps = h->pps; + const HEVCSPS *sps = pps->sps; int i, j; memset(pp, 0, sizeof(*pp)); @@ -72,7 +73,7 @@ void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo pp->PicHeightInMinCbsY = sps->min_cb_height; pp->wFormatAndSequenceInfoFlags = (sps->chroma_format_idc << 0) | - (sps->separate_colour_plane_flag << 2) | + (sps->separate_colour_plane << 2) | ((sps->bit_depth - 8) << 3) | ((sps->bit_depth - 8) << 6) | ((sps->log2_max_poc_lsb - 4) << 9) | @@ -99,18 +100,18 @@ void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo pp->wNumBitsForShortTermRPSInSlice = h->sh.short_term_ref_pic_set_size; } - pp->dwCodingParamToolFlags = (sps->scaling_list_enable_flag << 0) | - (sps->amp_enabled_flag << 1) | + pp->dwCodingParamToolFlags = (sps->scaling_list_enabled << 0) | + (sps->amp_enabled << 1) | (sps->sao_enabled << 2) | - (sps->pcm_enabled_flag << 3) | - ((sps->pcm_enabled_flag ? (sps->pcm.bit_depth - 1) : 0) << 4) | - ((sps->pcm_enabled_flag ? (sps->pcm.bit_depth_chroma - 1) : 0) << 8) | - ((sps->pcm_enabled_flag ? (sps->pcm.log2_min_pcm_cb_size - 3) : 0) << 12) | - ((sps->pcm_enabled_flag ? (sps->pcm.log2_max_pcm_cb_size - sps->pcm.log2_min_pcm_cb_size) : 0) << 14) | - (sps->pcm.loop_filter_disable_flag << 16) | - (sps->long_term_ref_pics_present_flag << 17) | - (sps->sps_temporal_mvp_enabled_flag << 18) | - (sps->sps_strong_intra_smoothing_enable_flag << 19) | + (sps->pcm_enabled << 3) | + ((sps->pcm_enabled ? (sps->pcm.bit_depth - 1) : 0) << 4) | + ((sps->pcm_enabled ? (sps->pcm.bit_depth_chroma - 1) : 0) << 8) | + ((sps->pcm_enabled ? (sps->pcm.log2_min_pcm_cb_size - 3) : 0) << 12) | + ((sps->pcm_enabled ? (sps->pcm.log2_max_pcm_cb_size - sps->pcm.log2_min_pcm_cb_size) : 0) << 14) | + (sps->pcm_loop_filter_disabled << 16) | + (sps->long_term_ref_pics_present << 17) | + (sps->temporal_mvp_enabled << 18) | + (sps->strong_intra_smoothing_enabled << 19) | (pps->dependent_slice_segments_enabled_flag << 20) | (pps->output_flag_present_flag << 21) | (pps->num_extra_slice_header_bits << 22) | @@ -163,14 +164,14 @@ void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo // fill RefPicList from the DPB for (i = 0, j = 0; i < FF_ARRAY_ELEMS(pp->RefPicList); i++) { const HEVCFrame *frame = NULL; - while (!frame && j < FF_ARRAY_ELEMS(h->DPB)) { - if (&h->DPB[j] != current_picture && (h->DPB[j].flags & (HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF))) - frame = &h->DPB[j]; + while (!frame && j < FF_ARRAY_ELEMS(l->DPB)) { + if (&l->DPB[j] != current_picture && (l->DPB[j].flags & (HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF))) + frame = &l->DPB[j]; j++; } if (frame) { - fill_picture_entry(&pp->RefPicList[i], ff_dxva2_get_surface_index(avctx, ctx, frame->frame, 0), !!(frame->flags & HEVC_FRAME_FLAG_LONG_REF)); + fill_picture_entry(&pp->RefPicList[i], ff_dxva2_get_surface_index(avctx, ctx, frame->f, 0), !!(frame->flags & HEVC_FRAME_FLAG_LONG_REF)); pp->PicOrderCntValList[i] = frame->poc; } else { pp->RefPicList[i].bPicEntry = 0xff; @@ -178,7 +179,7 @@ void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo } } - fill_picture_entry(&pp->CurrPic, ff_dxva2_get_surface_index(avctx, ctx, current_picture->frame, 1), 0); + fill_picture_entry(&pp->CurrPic, ff_dxva2_get_surface_index(avctx, ctx, current_picture->f, 1), 0); #define DO_REF_LIST(ref_idx, ref_list) { \ const RefPicList *rpl = &h->rps[ref_idx]; \ @@ -187,7 +188,7 @@ void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo while (!frame && j < rpl->nb_refs) \ frame = rpl->ref[j++]; \ if (frame && frame->flags & (HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF)) \ - pp->ref_list[i] = get_refpic_index(pp, ff_dxva2_get_surface_index(avctx, ctx, frame->frame, 0)); \ + pp->ref_list[i] = get_refpic_index(pp, ff_dxva2_get_surface_index(avctx, ctx, frame->f, 0)); \ else \ pp->ref_list[i] = 0xff; \ } \ @@ -205,8 +206,8 @@ void ff_dxva2_hevc_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext { const HEVCContext *h = avctx->priv_data; unsigned i, j, pos; - const ScalingList *sl = h->ps.pps->scaling_list_data_present_flag ? - &h->ps.pps->scaling_list : &h->ps.sps->scaling_list; + const ScalingList *sl = h->pps->scaling_list_data_present_flag ? + &h->pps->scaling_list : &h->pps->sps->scaling_list; memset(qm, 0, sizeof(*qm)); for (i = 0; i < 6; i++) { @@ -245,10 +246,10 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, { const HEVCContext *h = avctx->priv_data; AVDXVAContext *ctx = DXVA_CONTEXT(avctx); - const HEVCFrame *current_picture = h->ref; + const HEVCFrame *current_picture = h->cur_frame; struct hevc_dxva2_picture_context *ctx_pic = current_picture->hwaccel_picture_private; DXVA_Slice_HEVC_Short *slice = NULL; - void *dxva_data_ptr; + void *dxva_data_ptr = NULL; uint8_t *dxva_data, *current, *end; unsigned dxva_size; void *slice_data; @@ -278,6 +279,9 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, } #endif + if (!dxva_data_ptr) + return -1; + dxva_data = dxva_data_ptr; current = dxva_data; end = dxva_data + dxva_size; @@ -364,7 +368,7 @@ static int dxva2_hevc_start_frame(AVCodecContext *avctx, { const HEVCContext *h = avctx->priv_data; AVDXVAContext *ctx = DXVA_CONTEXT(avctx); - struct hevc_dxva2_picture_context *ctx_pic = h->ref->hwaccel_picture_private; + struct hevc_dxva2_picture_context *ctx_pic = h->cur_frame->hwaccel_picture_private; if (!DXVA_CONTEXT_VALID(avctx, ctx)) return -1; @@ -387,7 +391,7 @@ static int dxva2_hevc_decode_slice(AVCodecContext *avctx, uint32_t size) { const HEVCContext *h = avctx->priv_data; - const HEVCFrame *current_picture = h->ref; + const HEVCFrame *current_picture = h->cur_frame; struct hevc_dxva2_picture_context *ctx_pic = current_picture->hwaccel_picture_private; unsigned position; @@ -408,14 +412,14 @@ static int dxva2_hevc_decode_slice(AVCodecContext *avctx, static int dxva2_hevc_end_frame(AVCodecContext *avctx) { HEVCContext *h = avctx->priv_data; - struct hevc_dxva2_picture_context *ctx_pic = h->ref->hwaccel_picture_private; + struct hevc_dxva2_picture_context *ctx_pic = h->cur_frame->hwaccel_picture_private; int scale = ctx_pic->pp.dwCodingParamToolFlags & 1; int ret; if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0) return -1; - ret = ff_dxva2_common_end_frame(avctx, h->ref->frame, + ret = ff_dxva2_common_end_frame(avctx, h->cur_frame->f, &ctx_pic->pp, sizeof(ctx_pic->pp), scale ? &ctx_pic->qm : NULL, scale ? sizeof(ctx_pic->qm) : 0, commit_bitstream_and_slice_buffer); diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c index d31a8bb87..d88e78241 100644 --- a/libavcodec/dxva2_mpeg2.c +++ b/libavcodec/dxva2_mpeg2.c @@ -45,17 +45,17 @@ void ff_dxva2_mpeg2_fill_picture_parameters(AVCodecContext *avctx, DXVA_PictureParameters *pp) { const struct MpegEncContext *s = avctx->priv_data; - const Picture *current_picture = s->current_picture_ptr; + const MPVPicture *current_picture = s->cur_pic.ptr; int is_field = s->picture_structure != PICT_FRAME; memset(pp, 0, sizeof(*pp)); pp->wDeblockedPictureIndex = 0; if (s->pict_type != AV_PICTURE_TYPE_I) - pp->wForwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->last_picture.f, 0); + pp->wForwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->last_pic.ptr->f, 0); else pp->wForwardRefPictureIndex = 0xffff; if (s->pict_type == AV_PICTURE_TYPE_B) - pp->wBackwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->next_picture.f, 0); + pp->wBackwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->next_pic.ptr->f, 0); else pp->wBackwardRefPictureIndex = 0xffff; pp->wDecodedPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, current_picture->f, 1); @@ -157,10 +157,10 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, const struct MpegEncContext *s = avctx->priv_data; AVDXVAContext *ctx = DXVA_CONTEXT(avctx); struct dxva2_picture_context *ctx_pic = - s->current_picture_ptr->hwaccel_picture_private; + s->cur_pic.ptr->hwaccel_picture_private; const int is_field = s->picture_structure != PICT_FRAME; const unsigned mb_count = s->mb_width * (s->mb_height >> is_field); - void *dxva_data_ptr; + void *dxva_data_ptr = NULL; uint8_t *dxva_data, *current, *end; unsigned dxva_size; unsigned i; @@ -186,6 +186,9 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, } #endif + if (!dxva_data_ptr) + return -1; + dxva_data = dxva_data_ptr; current = dxva_data; end = dxva_data + dxva_size; @@ -260,7 +263,7 @@ static int dxva2_mpeg2_start_frame(AVCodecContext *avctx, const struct MpegEncContext *s = avctx->priv_data; AVDXVAContext *ctx = DXVA_CONTEXT(avctx); struct dxva2_picture_context *ctx_pic = - s->current_picture_ptr->hwaccel_picture_private; + s->cur_pic.ptr->hwaccel_picture_private; if (!DXVA_CONTEXT_VALID(avctx, ctx)) return -1; @@ -280,7 +283,7 @@ static int dxva2_mpeg2_decode_slice(AVCodecContext *avctx, { const struct MpegEncContext *s = avctx->priv_data; struct dxva2_picture_context *ctx_pic = - s->current_picture_ptr->hwaccel_picture_private; + s->cur_pic.ptr->hwaccel_picture_private; unsigned position; if (ctx_pic->slice_count >= MAX_SLICES) { @@ -302,12 +305,12 @@ static int dxva2_mpeg2_end_frame(AVCodecContext *avctx) { struct MpegEncContext *s = avctx->priv_data; struct dxva2_picture_context *ctx_pic = - s->current_picture_ptr->hwaccel_picture_private; + s->cur_pic.ptr->hwaccel_picture_private; int ret; if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0) return -1; - ret = ff_dxva2_common_end_frame(avctx, s->current_picture_ptr->f, + ret = ff_dxva2_common_end_frame(avctx, s->cur_pic.ptr->f, &ctx_pic->pp, sizeof(ctx_pic->pp), &ctx_pic->qm, sizeof(ctx_pic->qm), commit_bitstream_and_slice_buffer); diff --git a/libavcodec/dxva2_vc1.c b/libavcodec/dxva2_vc1.c index f7513b2b1..bc9ad9648 100644 --- a/libavcodec/dxva2_vc1.c +++ b/libavcodec/dxva2_vc1.c @@ -46,7 +46,7 @@ void ff_dxva2_vc1_fill_picture_parameters(AVCodecContext *avctx, { const VC1Context *v = avctx->priv_data; const MpegEncContext *s = &v->s; - const Picture *current_picture = s->current_picture_ptr; + const MPVPicture *current_picture = s->cur_pic.ptr; int intcomp = 0; // determine if intensity compensation is needed @@ -58,12 +58,12 @@ void ff_dxva2_vc1_fill_picture_parameters(AVCodecContext *avctx, } memset(pp, 0, sizeof(*pp)); - if (s->pict_type != AV_PICTURE_TYPE_I && !v->bi_type) - pp->wForwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->last_picture.f, 0); + if (s->pict_type != AV_PICTURE_TYPE_I && !v->bi_type && s->last_pic.ptr) + pp->wForwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->last_pic.ptr->f, 0); else pp->wForwardRefPictureIndex = 0xffff; - if (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type) - pp->wBackwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->next_picture.f, 0); + if (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type && s->next_pic.ptr) + pp->wBackwardRefPictureIndex = ff_dxva2_get_surface_index(avctx, ctx, s->next_pic.ptr->f, 0); else pp->wBackwardRefPictureIndex = 0xffff; pp->wDecodedPictureIndex = @@ -191,13 +191,13 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, const VC1Context *v = avctx->priv_data; AVDXVAContext *ctx = DXVA_CONTEXT(avctx); const MpegEncContext *s = &v->s; - struct dxva2_picture_context *ctx_pic = s->current_picture_ptr->hwaccel_picture_private; + struct dxva2_picture_context *ctx_pic = s->cur_pic.ptr->hwaccel_picture_private; static const uint8_t start_code[] = { 0, 0, 1, 0x0d }; const unsigned start_code_size = avctx->codec_id == AV_CODEC_ID_VC1 ? sizeof(start_code) : 0; const unsigned mb_count = s->mb_width * (s->mb_height >> v->field_mode); DXVA_SliceInfo *slice = NULL; - void *dxva_data_ptr; + void *dxva_data_ptr = NULL; uint8_t *dxva_data, *current, *end; unsigned dxva_size; unsigned padding; @@ -224,6 +224,9 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, } #endif + if (!dxva_data_ptr) + return -1; + dxva_data = dxva_data_ptr; current = dxva_data; end = dxva_data + dxva_size; @@ -317,7 +320,7 @@ static int dxva2_vc1_start_frame(AVCodecContext *avctx, { const VC1Context *v = avctx->priv_data; AVDXVAContext *ctx = DXVA_CONTEXT(avctx); - struct dxva2_picture_context *ctx_pic = v->s.current_picture_ptr->hwaccel_picture_private; + struct dxva2_picture_context *ctx_pic = v->s.cur_pic.ptr->hwaccel_picture_private; if (!DXVA_CONTEXT_VALID(avctx, ctx)) return -1; @@ -336,7 +339,7 @@ static int dxva2_vc1_decode_slice(AVCodecContext *avctx, uint32_t size) { const VC1Context *v = avctx->priv_data; - const Picture *current_picture = v->s.current_picture_ptr; + const MPVPicture *current_picture = v->s.cur_pic.ptr; struct dxva2_picture_context *ctx_pic = current_picture->hwaccel_picture_private; unsigned position; @@ -364,13 +367,13 @@ static int dxva2_vc1_decode_slice(AVCodecContext *avctx, static int dxva2_vc1_end_frame(AVCodecContext *avctx) { VC1Context *v = avctx->priv_data; - struct dxva2_picture_context *ctx_pic = v->s.current_picture_ptr->hwaccel_picture_private; + struct dxva2_picture_context *ctx_pic = v->s.cur_pic.ptr->hwaccel_picture_private; int ret; if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0) return -1; - ret = ff_dxva2_common_end_frame(avctx, v->s.current_picture_ptr->f, + ret = ff_dxva2_common_end_frame(avctx, v->s.cur_pic.ptr->f, &ctx_pic->pp, sizeof(ctx_pic->pp), NULL, 0, commit_bitstream_and_slice_buffer); diff --git a/libavcodec/dxva2_vp9.c b/libavcodec/dxva2_vp9.c index 1498deb3c..f4ab91c58 100644 --- a/libavcodec/dxva2_vp9.c +++ b/libavcodec/dxva2_vp9.c @@ -79,7 +79,7 @@ int ff_dxva2_vp9_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACont pp->Reserved8Bits = 0; for (i = 0; i < 8; i++) { - if (h->refs[i].f->buf[0]) { + if (h->refs[i].f) { fill_picture_entry(&pp->ref_frame_map[i], ff_dxva2_get_surface_index(avctx, ctx, h->refs[i].f, 0), 0); pp->ref_frame_coded_width[i] = h->refs[i].f->width; pp->ref_frame_coded_height[i] = h->refs[i].f->height; @@ -89,7 +89,7 @@ int ff_dxva2_vp9_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACont for (i = 0; i < 3; i++) { uint8_t refidx = h->h.refidx[i]; - if (h->refs[refidx].f->buf[0]) + if (h->refs[refidx].f) fill_picture_entry(&pp->frame_refs[i], ff_dxva2_get_surface_index(avctx, ctx, h->refs[refidx].f, 0), 0); else pp->frame_refs[i].bPicEntry = 0xFF; @@ -172,7 +172,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, const VP9SharedContext *h = avctx->priv_data; AVDXVAContext *ctx = DXVA_CONTEXT(avctx); struct vp9_dxva2_picture_context *ctx_pic = h->frames[CUR_FRAME].hwaccel_picture_private; - void *dxva_data_ptr; + void *dxva_data_ptr = NULL; uint8_t *dxva_data; unsigned dxva_size; unsigned padding; @@ -200,7 +200,7 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx, dxva_data = dxva_data_ptr; - if (ctx_pic->slice.SliceBytesInBuffer > dxva_size) { + if (!dxva_data || ctx_pic->slice.SliceBytesInBuffer > dxva_size) { av_log(avctx, AV_LOG_ERROR, "Failed to build bitstream"); return -1; } diff --git a/libavcodec/dxvenc.c b/libavcodec/dxvenc.c index 91f4ba761..822943837 100644 --- a/libavcodec/dxvenc.c +++ b/libavcodec/dxvenc.c @@ -23,6 +23,7 @@ #include "libavutil/crc.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "bytestream.h" diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c index 5c71751a0..2b3bffda6 100644 --- a/libavcodec/eac3dec.c +++ b/libavcodec/eac3dec.c @@ -39,8 +39,8 @@ #include "avcodec.h" -#include "aac_ac3_parser.h" #include "ac3.h" +#include "ac3_parser_internal.h" #include "ac3dec.h" #include "ac3dec_data.h" #include "eac3_data.h" @@ -300,7 +300,7 @@ static int ff_eac3_parse_header(AC3DecodeContext *s) dependent streams which are used to add or replace channels. */ if (s->frame_type == EAC3_FRAME_TYPE_RESERVED) { av_log(s->avctx, AV_LOG_ERROR, "Reserved frame type\n"); - return AAC_AC3_PARSE_ERROR_FRAME_TYPE; + return AC3_PARSE_ERROR_FRAME_TYPE; } /* The substream id indicates which substream this frame belongs to. each @@ -312,7 +312,7 @@ static int ff_eac3_parse_header(AC3DecodeContext *s) s->eac3_subsbtreamid_found = 1; avpriv_request_sample(s->avctx, "Additional substreams"); } - return AAC_AC3_PARSE_ERROR_FRAME_TYPE; + return AC3_PARSE_ERROR_FRAME_TYPE; } if (s->bit_alloc_params.sr_code == EAC3_SR_CODE_REDUCED) { diff --git a/libavcodec/eac3enc.c b/libavcodec/eac3enc.c index 527f77e33..8ef3e7e77 100644 --- a/libavcodec/eac3enc.c +++ b/libavcodec/eac3enc.c @@ -27,10 +27,12 @@ #define AC3ENC_FLOAT 1 #include "libavutil/attributes.h" +#include "libavutil/thread.h" #include "ac3enc.h" #include "codec_internal.h" #include "eac3enc.h" #include "eac3_data.h" +#include "put_bits.h" static const AVClass eac3enc_class = { @@ -47,7 +49,10 @@ static const AVClass eac3enc_class = { static int8_t eac3_frame_expstr_index_tab[3][4][4][4][4][4]; -av_cold void ff_eac3_exponent_init(void) +/** + * Initialize E-AC-3 exponent tables. + */ +static av_cold void eac3_exponent_init(void) { int i; @@ -122,132 +127,141 @@ void ff_eac3_set_cpl_states(AC3EncodeContext *s) } } - -void ff_eac3_output_frame_header(AC3EncodeContext *s) +/** + * Write the E-AC-3 frame header to the output bitstream. + */ +static void eac3_output_frame_header(AC3EncodeContext *s, PutBitContext *pb) { int blk, ch; AC3EncOptions *opt = &s->options; - put_bits(&s->pb, 16, 0x0b77); /* sync word */ + put_bits(pb, 16, 0x0b77); /* sync word */ /* BSI header */ - put_bits(&s->pb, 2, 0); /* stream type = independent */ - put_bits(&s->pb, 3, 0); /* substream id = 0 */ - put_bits(&s->pb, 11, (s->frame_size / 2) - 1); /* frame size */ - if (s->bit_alloc.sr_shift) { - put_bits(&s->pb, 2, 0x3); /* fscod2 */ - put_bits(&s->pb, 2, s->bit_alloc.sr_code); /* sample rate code */ - } else { - put_bits(&s->pb, 2, s->bit_alloc.sr_code); /* sample rate code */ - put_bits(&s->pb, 2, s->num_blks_code); /* number of blocks */ - } - put_bits(&s->pb, 3, s->channel_mode); /* audio coding mode */ - put_bits(&s->pb, 1, s->lfe_on); /* LFE channel indicator */ - put_bits(&s->pb, 5, s->bitstream_id); /* bitstream id (EAC3=16) */ - put_bits(&s->pb, 5, -opt->dialogue_level); /* dialogue normalization level */ - put_bits(&s->pb, 1, 0); /* no compression gain */ + put_bits(pb, 2, 0); /* stream type = independent */ + put_bits(pb, 3, 0); /* substream id = 0 */ + put_bits(pb, 11, (s->frame_size / 2) - 1); /* frame size */ + put_bits(pb, 2, s->bit_alloc.sr_code); /* sample rate code */ + put_bits(pb, 2, s->num_blks_code); /* number of blocks */ + put_bits(pb, 3, s->channel_mode); /* audio coding mode */ + put_bits(pb, 1, s->lfe_on); /* LFE channel indicator */ + put_bits(pb, 5, s->bitstream_id); /* bitstream id (EAC3=16) */ + put_bits(pb, 5, -opt->dialogue_level); /* dialogue normalization level */ + put_bits(pb, 1, 0); /* no compression gain */ /* mixing metadata*/ - put_bits(&s->pb, 1, opt->eac3_mixing_metadata); + put_bits(pb, 1, opt->eac3_mixing_metadata); if (opt->eac3_mixing_metadata) { if (s->channel_mode > AC3_CHMODE_STEREO) - put_bits(&s->pb, 2, opt->preferred_stereo_downmix); + put_bits(pb, 2, opt->preferred_stereo_downmix); if (s->has_center) { - put_bits(&s->pb, 3, s->ltrt_center_mix_level); - put_bits(&s->pb, 3, s->loro_center_mix_level); + put_bits(pb, 3, s->ltrt_center_mix_level); + put_bits(pb, 3, s->loro_center_mix_level); } if (s->has_surround) { - put_bits(&s->pb, 3, s->ltrt_surround_mix_level); - put_bits(&s->pb, 3, s->loro_surround_mix_level); + put_bits(pb, 3, s->ltrt_surround_mix_level); + put_bits(pb, 3, s->loro_surround_mix_level); } if (s->lfe_on) - put_bits(&s->pb, 1, 0); - put_bits(&s->pb, 1, 0); /* no program scale */ - put_bits(&s->pb, 1, 0); /* no ext program scale */ - put_bits(&s->pb, 2, 0); /* no mixing parameters */ + put_bits(pb, 1, 0); + put_bits(pb, 1, 0); /* no program scale */ + put_bits(pb, 1, 0); /* no ext program scale */ + put_bits(pb, 2, 0); /* no mixing parameters */ if (s->channel_mode < AC3_CHMODE_STEREO) - put_bits(&s->pb, 1, 0); /* no pan info */ - put_bits(&s->pb, 1, 0); /* no frame mix config info */ + put_bits(pb, 1, 0); /* no pan info */ + put_bits(pb, 1, 0); /* no frame mix config info */ } /* info metadata*/ - put_bits(&s->pb, 1, opt->eac3_info_metadata); + put_bits(pb, 1, opt->eac3_info_metadata); if (opt->eac3_info_metadata) { - put_bits(&s->pb, 3, s->bitstream_mode); - put_bits(&s->pb, 1, opt->copyright); - put_bits(&s->pb, 1, opt->original); + put_bits(pb, 3, s->bitstream_mode); + put_bits(pb, 1, opt->copyright); + put_bits(pb, 1, opt->original); if (s->channel_mode == AC3_CHMODE_STEREO) { - put_bits(&s->pb, 2, opt->dolby_surround_mode); - put_bits(&s->pb, 2, opt->dolby_headphone_mode); + put_bits(pb, 2, opt->dolby_surround_mode); + put_bits(pb, 2, opt->dolby_headphone_mode); } if (s->channel_mode >= AC3_CHMODE_2F2R) - put_bits(&s->pb, 2, opt->dolby_surround_ex_mode); - put_bits(&s->pb, 1, opt->audio_production_info); + put_bits(pb, 2, opt->dolby_surround_ex_mode); + put_bits(pb, 1, opt->audio_production_info); if (opt->audio_production_info) { - put_bits(&s->pb, 5, opt->mixing_level - 80); - put_bits(&s->pb, 2, opt->room_type); - put_bits(&s->pb, 1, opt->ad_converter_type); + put_bits(pb, 5, opt->mixing_level - 80); + put_bits(pb, 2, opt->room_type); + put_bits(pb, 1, opt->ad_converter_type); } - put_bits(&s->pb, 1, 0); + put_bits(pb, 1, 0); } if (s->num_blocks != 6) - put_bits(&s->pb, 1, !(s->avctx->frame_num % 6)); /* converter sync flag */ - put_bits(&s->pb, 1, 0); /* no additional bit stream info */ + put_bits(pb, 1, !(s->avctx->frame_num % 6)); /* converter sync flag */ + put_bits(pb, 1, 0); /* no additional bit stream info */ /* frame header */ if (s->num_blocks == 6) { - put_bits(&s->pb, 1, !s->use_frame_exp_strategy); /* exponent strategy syntax */ - put_bits(&s->pb, 1, 0); /* aht enabled = no */ + put_bits(pb, 1, !s->use_frame_exp_strategy); /* exponent strategy syntax */ + put_bits(pb, 1, 0); /* aht enabled = no */ } - put_bits(&s->pb, 2, 0); /* snr offset strategy = 1 */ - put_bits(&s->pb, 1, 0); /* transient pre-noise processing enabled = no */ - put_bits(&s->pb, 1, 0); /* block switch syntax enabled = no */ - put_bits(&s->pb, 1, 0); /* dither flag syntax enabled = no */ - put_bits(&s->pb, 1, 0); /* bit allocation model syntax enabled = no */ - put_bits(&s->pb, 1, 0); /* fast gain codes enabled = no */ - put_bits(&s->pb, 1, 0); /* dba syntax enabled = no */ - put_bits(&s->pb, 1, 0); /* skip field syntax enabled = no */ - put_bits(&s->pb, 1, 0); /* spx enabled = no */ + put_bits(pb, 2, 0); /* snr offset strategy = 1 */ + put_bits(pb, 1, 0); /* transient pre-noise processing enabled = no */ + put_bits(pb, 1, 0); /* block switch syntax enabled = no */ + put_bits(pb, 1, 0); /* dither flag syntax enabled = no */ + put_bits(pb, 1, 0); /* bit allocation model syntax enabled = no */ + put_bits(pb, 1, 0); /* fast gain codes enabled = no */ + put_bits(pb, 1, 0); /* dba syntax enabled = no */ + put_bits(pb, 1, 0); /* skip field syntax enabled = no */ + put_bits(pb, 1, 0); /* spx enabled = no */ /* coupling strategy use flags */ if (s->channel_mode > AC3_CHMODE_MONO) { - put_bits(&s->pb, 1, s->blocks[0].cpl_in_use); + put_bits(pb, 1, s->blocks[0].cpl_in_use); for (blk = 1; blk < s->num_blocks; blk++) { AC3Block *block = &s->blocks[blk]; - put_bits(&s->pb, 1, block->new_cpl_strategy); + put_bits(pb, 1, block->new_cpl_strategy); if (block->new_cpl_strategy) - put_bits(&s->pb, 1, block->cpl_in_use); + put_bits(pb, 1, block->cpl_in_use); } } /* exponent strategy */ if (s->use_frame_exp_strategy) { for (ch = !s->cpl_on; ch <= s->fbw_channels; ch++) - put_bits(&s->pb, 5, s->frame_exp_strategy[ch]); + put_bits(pb, 5, s->frame_exp_strategy[ch]); } else { for (blk = 0; blk < s->num_blocks; blk++) for (ch = !s->blocks[blk].cpl_in_use; ch <= s->fbw_channels; ch++) - put_bits(&s->pb, 2, s->exp_strategy[ch][blk]); + put_bits(pb, 2, s->exp_strategy[ch][blk]); } if (s->lfe_on) { for (blk = 0; blk < s->num_blocks; blk++) - put_bits(&s->pb, 1, s->exp_strategy[s->lfe_channel][blk]); + put_bits(pb, 1, s->exp_strategy[s->lfe_channel][blk]); } /* E-AC-3 to AC-3 converter exponent strategy (not optional when num blocks == 6) */ if (s->num_blocks != 6) { - put_bits(&s->pb, 1, 0); + put_bits(pb, 1, 0); } else { for (ch = 1; ch <= s->fbw_channels; ch++) { if (s->use_frame_exp_strategy) - put_bits(&s->pb, 5, s->frame_exp_strategy[ch]); + put_bits(pb, 5, s->frame_exp_strategy[ch]); else - put_bits(&s->pb, 5, 0); + put_bits(pb, 5, 0); } } /* snr offsets */ - put_bits(&s->pb, 6, s->coarse_snr_offset); - put_bits(&s->pb, 4, s->fine_snr_offset[1]); + put_bits(pb, 6, s->coarse_snr_offset); + put_bits(pb, 4, s->fine_snr_offset[1]); /* block start info */ if (s->num_blocks > 1) - put_bits(&s->pb, 1, 0); + put_bits(pb, 1, 0); } +static av_cold int eac3_encode_init(AVCodecContext *avctx) +{ + static AVOnce init_static_once = AV_ONCE_INIT; + AC3EncodeContext *s = avctx->priv_data; + + s->eac3 = 1; + s->output_frame_header = eac3_output_frame_header; + + ff_thread_once(&init_static_once, eac3_exponent_init); + + return ff_ac3_float_encode_init(avctx); +} const FFCodec ff_eac3_encoder = { .p.name = "eac3", @@ -256,8 +270,8 @@ const FFCodec ff_eac3_encoder = { .p.id = AV_CODEC_ID_EAC3, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_data_size = sizeof(AC3EncodeContext), - .init = ff_ac3_float_encode_init, - FF_CODEC_ENCODE_CB(ff_ac3_float_encode_frame), + .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 }, diff --git a/libavcodec/eac3enc.h b/libavcodec/eac3enc.h index 7d6155975..0523de411 100644 --- a/libavcodec/eac3enc.h +++ b/libavcodec/eac3enc.h @@ -29,11 +29,6 @@ #include "ac3enc.h" -/** - * Initialize E-AC-3 exponent tables. - */ -void ff_eac3_exponent_init(void); - /** * Determine frame exponent strategy use and indices. */ @@ -46,9 +41,4 @@ void ff_eac3_get_frame_exp_strategy(AC3EncodeContext *s); */ void ff_eac3_set_cpl_states(AC3EncodeContext *s); -/** - * Write the E-AC-3 frame header to the output bitstream. - */ -void ff_eac3_output_frame_header(AC3EncodeContext *s); - #endif /* AVCODEC_EAC3ENC_H */ diff --git a/libavcodec/eacmv.c b/libavcodec/eacmv.c index 43dba20fa..15d3550cb 100644 --- a/libavcodec/eacmv.c +++ b/libavcodec/eacmv.c @@ -194,12 +194,15 @@ static int cmv_decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((ret = av_image_check_size(s->width, s->height, 0, s->avctx)) < 0) return ret; + buf += EA_PREAMBLE_SIZE; + if (!(buf[0]&1) && buf_end - buf < s->width * s->height * (int64_t)(100 - s->avctx->discard_damaged_percentage) / 100) + return AVERROR_INVALIDDATA; + if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) return ret; memcpy(frame->data[1], s->palette, AVPALETTE_SIZE); - buf += EA_PREAMBLE_SIZE; if ((buf[0]&1)) { // subtype cmv_decode_inter(s, frame, buf+2, buf_end); frame->flags &= ~AV_FRAME_FLAG_KEY; diff --git a/libavcodec/eamad.c b/libavcodec/eamad.c index 287575e07..1c3f97653 100644 --- a/libavcodec/eamad.c +++ b/libavcodec/eamad.c @@ -28,6 +28,7 @@ * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_MAD */ +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" diff --git a/libavcodec/eatgq.c b/libavcodec/eatgq.c index 0f0ed3585..c6fcb062d 100644 --- a/libavcodec/eatgq.c +++ b/libavcodec/eatgq.c @@ -178,7 +178,8 @@ static int tgq_decode_mb(TgqContext *s, GetByteContext *gbyte, dc[4] = bytestream2_get_byte(gbyte); dc[5] = bytestream2_get_byte(gbyte); } else if (mode == 6) { - bytestream2_get_buffer(gbyte, dc, 6); + if (bytestream2_get_buffer(gbyte, dc, 6) != 6) + return AVERROR_INVALIDDATA; } else if (mode == 12) { for (i = 0; i < 6; i++) { dc[i] = bytestream2_get_byte(gbyte); @@ -237,8 +238,6 @@ 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; - frame->pict_type = AV_PICTURE_TYPE_I; for (y = 0; y < FFALIGN(avctx->height, 16) >> 4; y++) for (x = 0; x < FFALIGN(avctx->width, 16) >> 4; x++) diff --git a/libavcodec/eatqi.c b/libavcodec/eatqi.c index e4f12b3db..421ed5100 100644 --- a/libavcodec/eatqi.c +++ b/libavcodec/eatqi.c @@ -26,6 +26,7 @@ * @see http://wiki.multimedia.cx/index.php?title=Electronic_Arts_TQI */ +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" diff --git a/libavcodec/elbg.c b/libavcodec/elbg.c index a52ee1e3d..84043af4f 100644 --- a/libavcodec/elbg.c +++ b/libavcodec/elbg.c @@ -28,6 +28,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "elbg.h" #define DELTA_ERR_MAX 0.1 ///< Precision of the ELBG algorithm (as percentage error) diff --git a/libavcodec/encode.c b/libavcodec/encode.c index 7fc9737e9..3baf5b810 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -25,6 +25,7 @@ #include "libavutil/frame.h" #include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/samplefmt.h" @@ -562,7 +563,8 @@ static int encode_preinit_video(AVCodecContext *avctx) { const AVCodec *c = avctx->codec; const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->pix_fmt); - int i; + const enum AVPixelFormat *pix_fmts; + int ret, i, num_pix_fmts; if (!av_get_pix_fmt_name(avctx->pix_fmt)) { av_log(avctx, AV_LOG_ERROR, "Invalid video pixel format: %d\n", @@ -570,28 +572,33 @@ static int encode_preinit_video(AVCodecContext *avctx) return AVERROR(EINVAL); } - if (c->pix_fmts) { - for (i = 0; c->pix_fmts[i] != AV_PIX_FMT_NONE; i++) - if (avctx->pix_fmt == c->pix_fmts[i]) + ret = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, + 0, (const void **) &pix_fmts, &num_pix_fmts); + if (ret < 0) + return ret; + + if (pix_fmts) { + for (i = 0; i < num_pix_fmts; i++) + if (avctx->pix_fmt == pix_fmts[i]) break; - if (c->pix_fmts[i] == AV_PIX_FMT_NONE) { + if (i == num_pix_fmts) { av_log(avctx, AV_LOG_ERROR, "Specified pixel format %s is not supported by the %s encoder.\n", av_get_pix_fmt_name(avctx->pix_fmt), c->name); av_log(avctx, AV_LOG_ERROR, "Supported pixel formats:\n"); - for (int p = 0; c->pix_fmts[p] != AV_PIX_FMT_NONE; p++) { + for (int p = 0; pix_fmts[p] != AV_PIX_FMT_NONE; p++) { av_log(avctx, AV_LOG_ERROR, " %s\n", - av_get_pix_fmt_name(c->pix_fmts[p])); + av_get_pix_fmt_name(pix_fmts[p])); } return AVERROR(EINVAL); } - if (c->pix_fmts[i] == AV_PIX_FMT_YUVJ420P || - c->pix_fmts[i] == AV_PIX_FMT_YUVJ411P || - c->pix_fmts[i] == AV_PIX_FMT_YUVJ422P || - c->pix_fmts[i] == AV_PIX_FMT_YUVJ440P || - c->pix_fmts[i] == AV_PIX_FMT_YUVJ444P) + if (pix_fmts[i] == AV_PIX_FMT_YUVJ420P || + pix_fmts[i] == AV_PIX_FMT_YUVJ411P || + pix_fmts[i] == AV_PIX_FMT_YUVJ422P || + pix_fmts[i] == AV_PIX_FMT_YUVJ440P || + pix_fmts[i] == AV_PIX_FMT_YUVJ444P) avctx->color_range = AVCOL_RANGE_JPEG; } @@ -645,7 +652,10 @@ FF_ENABLE_DEPRECATION_WARNINGS static int encode_preinit_audio(AVCodecContext *avctx) { const AVCodec *c = avctx->codec; - int i; + const enum AVSampleFormat *sample_fmts; + const int *supported_samplerates; + const AVChannelLayout *ch_layouts; + int ret, i, num_sample_fmts, num_samplerates, num_ch_layouts; if (!av_get_sample_fmt_name(avctx->sample_fmt)) { av_log(avctx, AV_LOG_ERROR, "Invalid audio sample format: %d\n", @@ -658,53 +668,68 @@ static int encode_preinit_audio(AVCodecContext *avctx) return AVERROR(EINVAL); } - if (c->sample_fmts) { - for (i = 0; c->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++) { - if (avctx->sample_fmt == c->sample_fmts[i]) + ret = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_SAMPLE_FORMAT, + 0, (const void **) &sample_fmts, + &num_sample_fmts); + if (ret < 0) + return ret; + if (sample_fmts) { + for (i = 0; i < num_sample_fmts; i++) { + if (avctx->sample_fmt == sample_fmts[i]) break; if (avctx->ch_layout.nb_channels == 1 && av_get_planar_sample_fmt(avctx->sample_fmt) == - av_get_planar_sample_fmt(c->sample_fmts[i])) { - avctx->sample_fmt = c->sample_fmts[i]; + av_get_planar_sample_fmt(sample_fmts[i])) { + avctx->sample_fmt = sample_fmts[i]; break; } } - if (c->sample_fmts[i] == AV_SAMPLE_FMT_NONE) { + if (i == num_sample_fmts) { av_log(avctx, AV_LOG_ERROR, "Specified sample format %s is not supported by the %s encoder\n", av_get_sample_fmt_name(avctx->sample_fmt), c->name); av_log(avctx, AV_LOG_ERROR, "Supported sample formats:\n"); - for (int p = 0; c->sample_fmts[p] != AV_SAMPLE_FMT_NONE; p++) { + for (int p = 0; sample_fmts[p] != AV_SAMPLE_FMT_NONE; p++) { av_log(avctx, AV_LOG_ERROR, " %s\n", - av_get_sample_fmt_name(c->sample_fmts[p])); + av_get_sample_fmt_name(sample_fmts[p])); } return AVERROR(EINVAL); } } - if (c->supported_samplerates) { - for (i = 0; c->supported_samplerates[i] != 0; i++) - if (avctx->sample_rate == c->supported_samplerates[i]) + + ret = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_SAMPLE_RATE, + 0, (const void **) &supported_samplerates, + &num_samplerates); + if (ret < 0) + return ret; + if (supported_samplerates) { + for (i = 0; i < num_samplerates; i++) + if (avctx->sample_rate == supported_samplerates[i]) break; - if (c->supported_samplerates[i] == 0) { + if (i == num_samplerates) { av_log(avctx, AV_LOG_ERROR, "Specified sample rate %d is not supported by the %s encoder\n", avctx->sample_rate, c->name); av_log(avctx, AV_LOG_ERROR, "Supported sample rates:\n"); - for (int p = 0; c->supported_samplerates[p]; p++) - av_log(avctx, AV_LOG_ERROR, " %d\n", c->supported_samplerates[p]); + for (int p = 0; supported_samplerates[p]; p++) + av_log(avctx, AV_LOG_ERROR, " %d\n", supported_samplerates[p]); return AVERROR(EINVAL); } } - if (c->ch_layouts) { - for (i = 0; c->ch_layouts[i].nb_channels; i++) { - if (!av_channel_layout_compare(&avctx->ch_layout, &c->ch_layouts[i])) + ret = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_CHANNEL_LAYOUT, + 0, (const void **) &ch_layouts, &num_ch_layouts); + if (ret < 0) + return ret; + if (ch_layouts) { + for (i = 0; i < num_ch_layouts; i++) { + if (!av_channel_layout_compare(&avctx->ch_layout, &ch_layouts[i])) break; } - if (!c->ch_layouts[i].nb_channels) { + if (i == num_ch_layouts) { char buf[512]; int ret = av_channel_layout_describe(&avctx->ch_layout, buf, sizeof(buf)); av_log(avctx, AV_LOG_ERROR, @@ -712,8 +737,8 @@ static int encode_preinit_audio(AVCodecContext *avctx) ret > 0 ? buf : "?", c->name); av_log(avctx, AV_LOG_ERROR, "Supported channel layouts:\n"); - for (int p = 0; c->ch_layouts[p].nb_channels; p++) { - ret = av_channel_layout_describe(&c->ch_layouts[p], buf, sizeof(buf)); + for (int p = 0; ch_layouts[p].nb_channels; p++) { + ret = av_channel_layout_describe(&ch_layouts[p], buf, sizeof(buf)); av_log(avctx, AV_LOG_ERROR, " %s\n", ret > 0 ? buf : "?"); } return AVERROR(EINVAL); @@ -739,6 +764,11 @@ int ff_encode_preinit(AVCodecContext *avctx) return AVERROR(EINVAL); } + if (avctx->bit_rate < 0) { + av_log(avctx, AV_LOG_ERROR, "The encoder bitrate is negative.\n"); + return AVERROR(EINVAL); + } + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE && !(avctx->codec->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE)) { av_log(avctx, AV_LOG_ERROR, "The copy_opaque flag is set, but the " @@ -782,6 +812,29 @@ int ff_encode_preinit(AVCodecContext *avctx) return AVERROR(ENOMEM); } + for (int i = 0; ff_sd_global_map[i].packet < AV_PKT_DATA_NB; i++) { + const enum AVPacketSideDataType type_packet = ff_sd_global_map[i].packet; + const enum AVFrameSideDataType type_frame = ff_sd_global_map[i].frame; + const AVFrameSideData *sd_frame; + AVPacketSideData *sd_packet; + + sd_frame = av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, + type_frame); + if (!sd_frame || + av_packet_side_data_get(avctx->coded_side_data, avctx->nb_coded_side_data, + type_packet)) + + continue; + + sd_packet = av_packet_side_data_new(&avctx->coded_side_data, &avctx->nb_coded_side_data, + type_packet, sd_frame->size, 0); + if (!sd_packet) + return AVERROR(ENOMEM); + + 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) diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index 9d03e5323..6edc2dc15 100644 --- a/libavcodec/error_resilience.c +++ b/libavcodec/error_resilience.c @@ -27,14 +27,14 @@ #include -#include "libavutil/internal.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "error_resilience.h" #include "me_cmp.h" #include "mpegutils.h" #include "mpegvideo.h" -#include "rectangle.h" #include "threadframe.h" +#include "threadprogress.h" /** * @param stride the number of MVs to get to the next row @@ -410,8 +410,12 @@ static void guess_mv(ERContext *s) set_mv_strides(s, &mot_step, &mot_stride); num_avail = 0; - if (s->last_pic.motion_val[0]) - ff_thread_await_progress(s->last_pic.tf, mb_height-1, 0); + if (s->last_pic.motion_val[0]) { + if (s->last_pic.tf) + ff_thread_await_progress(s->last_pic.tf, mb_height-1, 0); + else + ff_thread_progress_await(s->last_pic.progress, mb_height - 1); + } for (i = 0; i < mb_width * mb_height; i++) { const int mb_xy = s->mb_index2xy[i]; int f = 0; @@ -764,7 +768,7 @@ static int is_intra_more_likely(ERContext *s) if (s->avctx->codec_id == AV_CODEC_ID_H264) { // FIXME } else { - ff_thread_await_progress(s->last_pic.tf, mb_y, 0); + ff_thread_progress_await(s->last_pic.progress, mb_y); } is_intra_likely += s->sad(NULL, last_mb_ptr, mb_ptr, linesize[0], 16); @@ -898,6 +902,7 @@ void ff_er_frame_end(ERContext *s, int *decode_error_flags) int threshold = 50; int is_intra_likely; int size = s->b8_stride * 2 * s->mb_height; + int guessed_mb_type; /* We do not support ER of field pictures yet, * though it should not crash if enabled. */ @@ -949,19 +954,10 @@ void ff_er_frame_end(ERContext *s, int *decode_error_flags) s->ref_index[i] = av_calloc(s->mb_stride * s->mb_height, 4 * sizeof(uint8_t)); s->motion_val_base[i] = av_calloc(size + 4, 2 * sizeof(uint16_t)); if (!s->ref_index[i] || !s->motion_val_base[i]) - break; + goto cleanup; s->cur_pic.ref_index[i] = s->ref_index[i]; s->cur_pic.motion_val[i] = s->motion_val_base[i] + 4; } - if (i < 2) { - for (i = 0; i < 2; i++) { - av_freep(&s->ref_index[i]); - av_freep(&s->motion_val_base[i]); - s->cur_pic.ref_index[i] = NULL; - s->cur_pic.motion_val[i] = NULL; - } - return; - } } if (s->avctx->debug & FF_DEBUG_ER) { @@ -1122,16 +1118,15 @@ void ff_er_frame_end(ERContext *s, int *decode_error_flags) is_intra_likely = is_intra_more_likely(s); /* set unknown mb-type to most likely */ + guessed_mb_type = is_intra_likely ? MB_TYPE_INTRA4x4 : + (MB_TYPE_16x16 | (s->avctx->codec_id == AV_CODEC_ID_H264 ? MB_TYPE_L0 : MB_TYPE_FORWARD_MV)); for (i = 0; i < s->mb_num; i++) { const int mb_xy = s->mb_index2xy[i]; int error = s->error_status_table[mb_xy]; if (!((error & ER_DC_ERROR) && (error & ER_MV_ERROR))) continue; - if (is_intra_likely) - s->cur_pic.mb_type[mb_xy] = MB_TYPE_INTRA4x4; - else - s->cur_pic.mb_type[mb_xy] = MB_TYPE_16x16 | MB_TYPE_L0; + s->cur_pic.mb_type[mb_xy] = guessed_mb_type; } // change inter to intra blocks if no reference frames are available @@ -1208,7 +1203,7 @@ void ff_er_frame_end(ERContext *s, int *decode_error_flags) int time_pb = s->pb_time; av_assert0(s->avctx->codec_id != AV_CODEC_ID_H264); - ff_thread_await_progress(s->next_pic.tf, mb_y, 0); + ff_thread_progress_await(s->next_pic.progress, mb_y); s->mv[0][0][0] = s->next_pic.motion_val[0][xy][0] * time_pb / time_pp; s->mv[0][0][1] = s->next_pic.motion_val[0][xy][1] * time_pb / time_pp; @@ -1345,14 +1340,15 @@ void ff_er_frame_end(ERContext *s, int *decode_error_flags) s->mbintra_table[mb_xy] = 1; } + memset(&s->cur_pic, 0, sizeof(ERPicture)); + memset(&s->last_pic, 0, sizeof(ERPicture)); + memset(&s->next_pic, 0, sizeof(ERPicture)); + +cleanup: for (i = 0; i < 2; i++) { av_freep(&s->ref_index[i]); av_freep(&s->motion_val_base[i]); s->cur_pic.ref_index[i] = NULL; s->cur_pic.motion_val[i] = NULL; } - - memset(&s->cur_pic, 0, sizeof(ERPicture)); - memset(&s->last_pic, 0, sizeof(ERPicture)); - memset(&s->next_pic, 0, sizeof(ERPicture)); } diff --git a/libavcodec/error_resilience.h b/libavcodec/error_resilience.h index 1346639c3..a1b9b9ec1 100644 --- a/libavcodec/error_resilience.h +++ b/libavcodec/error_resilience.h @@ -40,6 +40,7 @@ typedef struct ERPicture { AVFrame *f; const struct ThreadFrame *tf; + const struct ThreadProgress *progress; // it is the caller's responsibility to allocate these buffers int16_t (*motion_val[2])[2]; diff --git a/libavcodec/escape124.c b/libavcodec/escape124.c index 357320ef9..b7e26e132 100644 --- a/libavcodec/escape124.c +++ b/libavcodec/escape124.c @@ -20,6 +20,7 @@ */ #define BITSTREAM_READER_LE +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/evc.h b/libavcodec/evc.h index e493455a4..d68dc7499 100644 --- a/libavcodec/evc.h +++ b/libavcodec/evc.h @@ -106,15 +106,15 @@ enum EVCSliceType { }; enum { - // 7.4.3.2: aps_video_parameter_set_id is u(4). - EVC_MAX_APS_COUNT = 32, - // 7.4.3.1: sps_seq_parameter_set_id is in [0, 15]. EVC_MAX_SPS_COUNT = 16, // 7.4.3.2: pps_pic_parameter_set_id is in [0, 63]. EVC_MAX_PPS_COUNT = 64, + // 7.4.3.3: adaptional_parameter_set_id is in [0, 31]. + EVC_MAX_APS_COUNT = 32, + // 7.4.5: slice header slice_pic_parameter_set_id in [0, 63] EVC_MAX_SH_COUNT = 64, diff --git a/libavcodec/evc_ps.c b/libavcodec/evc_ps.c index 19895d404..637572d32 100644 --- a/libavcodec/evc_ps.c +++ b/libavcodec/evc_ps.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "get_bits.h" #include "golomb.h" #include "evc.h" diff --git a/libavcodec/exr.c b/libavcodec/exr.c index cf6295343..4bac0be89 100644 --- a/libavcodec/exr.c +++ b/libavcodec/exr.c @@ -40,6 +40,7 @@ #include "libavutil/imgutils.h" #include "libavutil/intfloat.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/half2float.h" diff --git a/libavcodec/exrenc.c b/libavcodec/exrenc.c index 1b710fc08..71ec07054 100644 --- a/libavcodec/exrenc.c +++ b/libavcodec/exrenc.c @@ -27,10 +27,9 @@ #include #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" -#include "libavutil/pixdesc.h" #include "libavutil/float2half.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/fastaudio.c b/libavcodec/fastaudio.c index f5569f520..33ad26f8a 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/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/faxcompr.c b/libavcodec/faxcompr.c index 41a1eec08..cf744df31 100644 --- a/libavcodec/faxcompr.c +++ b/libavcodec/faxcompr.c @@ -24,6 +24,7 @@ * CCITT Fax Group 3 and 4 decompression * @author Konstantin Shishkov */ +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "avcodec.h" #include "get_bits.h" diff --git a/libavcodec/fdctdsp.c b/libavcodec/fdctdsp.c index f8ba17426..d20558ce8 100644 --- a/libavcodec/fdctdsp.c +++ b/libavcodec/fdctdsp.c @@ -42,7 +42,9 @@ av_cold void ff_fdctdsp_init(FDCTDSPContext *c, AVCodecContext *avctx) c->fdct248 = ff_fdct248_islow_8; } -#if ARCH_PPC +#if ARCH_AARCH64 + ff_fdctdsp_init_aarch64(c, avctx, high_bit_depth); +#elif ARCH_PPC ff_fdctdsp_init_ppc(c, avctx, high_bit_depth); #elif ARCH_X86 ff_fdctdsp_init_x86(c, avctx, high_bit_depth); diff --git a/libavcodec/fdctdsp.h b/libavcodec/fdctdsp.h index 7378eab87..cad99ed7c 100644 --- a/libavcodec/fdctdsp.h +++ b/libavcodec/fdctdsp.h @@ -32,6 +32,8 @@ typedef struct FDCTDSPContext { FF_VISIBILITY_PUSH_HIDDEN void ff_fdctdsp_init(FDCTDSPContext *c, struct AVCodecContext *avctx); +void ff_fdctdsp_init_aarch64(FDCTDSPContext *c, struct AVCodecContext *avctx, + unsigned high_bit_depth); void ff_fdctdsp_init_ppc(FDCTDSPContext *c, struct AVCodecContext *avctx, unsigned high_bit_depth); void ff_fdctdsp_init_x86(FDCTDSPContext *c, struct AVCodecContext *avctx, diff --git a/libavcodec/ffv1.c b/libavcodec/ffv1.c index b6204740e..2b8564c2f 100644 --- a/libavcodec/ffv1.c +++ b/libavcodec/ffv1.c @@ -27,11 +27,11 @@ #include "libavutil/attributes.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "avcodec.h" -#include "rangecoder.h" #include "ffv1.h" -#include "threadframe.h" +#include "refstruct.h" av_cold int ff_ffv1_common_init(AVCodecContext *avctx) { @@ -53,16 +53,33 @@ av_cold int ff_ffv1_common_init(AVCodecContext *avctx) return 0; } -av_cold int ff_ffv1_init_slice_state(const FFV1Context *f, FFV1Context *fs) +static void planes_free(FFRefStructOpaque opaque, void *obj) +{ + PlaneContext *planes = obj; + + for (int i = 0; i < MAX_PLANES; i++) { + PlaneContext *p = &planes[i]; + + av_freep(&p->state); + av_freep(&p->vlc_state); + } +} + +PlaneContext* ff_ffv1_planes_alloc(void) +{ + return ff_refstruct_alloc_ext(sizeof(PlaneContext) * MAX_PLANES, + 0, NULL, planes_free); +} + +av_cold int ff_ffv1_init_slice_state(const FFV1Context *f, + FFV1SliceContext *sc) { int j, i; - fs->plane_count = f->plane_count; - fs->transparency = f->transparency; for (j = 0; j < f->plane_count; j++) { - PlaneContext *const p = &fs->plane[j]; + PlaneContext *const p = &sc->plane[j]; - if (fs->ac != AC_GOLOMB_RICE) { + if (f->ac != AC_GOLOMB_RICE) { if (!p->state) p->state = av_malloc_array(p->context_count, CONTEXT_SIZE * sizeof(uint8_t)); @@ -81,11 +98,11 @@ av_cold int ff_ffv1_init_slice_state(const FFV1Context *f, FFV1Context *fs) } } - if (fs->ac == AC_RANGE_CUSTOM_TAB) { + if (f->ac == AC_RANGE_CUSTOM_TAB) { //FIXME only redo if state_transition changed for (j = 1; j < 256; j++) { - fs->c. one_state[ j] = f->state_transition[j]; - fs->c.zero_state[256 - j] = 256 - fs->c.one_state[j]; + sc->c. one_state[ j] = f->state_transition[j]; + sc->c.zero_state[256 - j] = 256 - sc->c.one_state[j]; } } @@ -96,53 +113,60 @@ av_cold int ff_ffv1_init_slices_state(FFV1Context *f) { int i, ret; for (i = 0; i < f->max_slice_count; i++) { - FFV1Context *fs = f->slice_context[i]; - if ((ret = ff_ffv1_init_slice_state(f, fs)) < 0) + if ((ret = ff_ffv1_init_slice_state(f, &f->slices[i])) < 0) return AVERROR(ENOMEM); } return 0; } +int ff_need_new_slices(int width, int num_h_slices, int chroma_shift) { + int mpw = 1<num_h_slices * f->num_v_slices; + int max_slice_count = f->num_h_slices * f->num_v_slices; av_assert0(max_slice_count > 0); - for (i = 0; i < max_slice_count;) { + f->slices = av_calloc(max_slice_count, sizeof(*f->slices)); + if (!f->slices) + return AVERROR(ENOMEM); + + f->max_slice_count = max_slice_count; + + for (int i = 0; i < max_slice_count; i++) { + 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; - FFV1Context *fs = av_mallocz(sizeof(*fs)); - if (!fs) - goto memfail; + sc->slice_width = sxe - sxs; + sc->slice_height = sye - sys; + sc->slice_x = sxs; + sc->slice_y = sys; + sc->sx = sx; + sc->sy = sy; - f->slice_context[i++] = fs; - memcpy(fs, f, sizeof(*fs)); - memset(fs->rc_stat2, 0, sizeof(fs->rc_stat2)); + sc->sample_buffer = av_malloc_array((f->width + 6), 3 * MAX_PLANES * + sizeof(*sc->sample_buffer)); + sc->sample_buffer32 = av_malloc_array((f->width + 6), 3 * MAX_PLANES * + sizeof(*sc->sample_buffer32)); + if (!sc->sample_buffer || !sc->sample_buffer32) + return AVERROR(ENOMEM); - fs->slice_width = sxe - sxs; - fs->slice_height = sye - sys; - fs->slice_x = sxs; - fs->slice_y = sys; - - fs->sample_buffer = av_malloc_array((fs->width + 6), 3 * MAX_PLANES * - sizeof(*fs->sample_buffer)); - fs->sample_buffer32 = av_malloc_array((fs->width + 6), 3 * MAX_PLANES * - sizeof(*fs->sample_buffer32)); - if (!fs->sample_buffer || !fs->sample_buffer32) - goto memfail; + sc->plane = ff_ffv1_planes_alloc(); + if (!sc->plane) + return AVERROR(ENOMEM); } - f->max_slice_count = max_slice_count; - return 0; -memfail: - f->max_slice_count = i; - return AVERROR(ENOMEM); + return 0; } int ff_ffv1_allocate_initial_states(FFV1Context *f) @@ -160,17 +184,14 @@ int ff_ffv1_allocate_initial_states(FFV1Context *f) return 0; } -void ff_ffv1_clear_slice_state(const FFV1Context *f, FFV1Context *fs) +void ff_ffv1_clear_slice_state(const FFV1Context *f, FFV1SliceContext *sc) { int i, j; for (i = 0; i < f->plane_count; i++) { - PlaneContext *p = &fs->plane[i]; + PlaneContext *p = &sc->plane[i]; - p->interlace_bit_state[0] = 128; - p->interlace_bit_state[1] = 128; - - if (fs->ac != AC_GOLOMB_RICE) { + if (f->ac != AC_GOLOMB_RICE) { if (f->initial_states[p->quant_table_index]) { memcpy(p->state, f->initial_states[p->quant_table_index], CONTEXT_SIZE * p->context_count); @@ -194,29 +215,27 @@ av_cold int ff_ffv1_close(AVCodecContext *avctx) int i, j; for (j = 0; j < s->max_slice_count; j++) { - FFV1Context *fs = s->slice_context[j]; - for (i = 0; i < s->plane_count; i++) { - PlaneContext *p = &fs->plane[i]; + FFV1SliceContext *sc = &s->slices[j]; - av_freep(&p->state); - av_freep(&p->vlc_state); - } - av_freep(&fs->sample_buffer); - av_freep(&fs->sample_buffer32); + av_freep(&sc->sample_buffer); + av_freep(&sc->sample_buffer32); + + ff_refstruct_unref(&sc->plane); } + ff_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++) { - FFV1Context *sf = s->slice_context[i]; - av_freep(&sf->rc_stat2[j]); + FFV1SliceContext *sc = &s->slices[i]; + av_freep(&sc->rc_stat2[j]); } av_freep(&s->rc_stat2[j]); } - for (i = 0; i < s->max_slice_count; i++) - av_freep(&s->slice_context[i]); + av_freep(&s->slices); return 0; } diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index 04869da5c..5c1490771 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -28,13 +28,12 @@ * FF Video Codec 1 (a lossless codec) */ -#include "libavutil/imgutils.h" #include "avcodec.h" #include "get_bits.h" #include "mathops.h" +#include "progressframe.h" #include "put_bits.h" #include "rangecoder.h" -#include "threadframe.h" #ifdef __INTEL_COMPILER #undef av_flatten @@ -45,6 +44,8 @@ #define CONTEXT_SIZE 32 #define MAX_QUANT_TABLES 8 +#define MAX_QUANT_TABLE_SIZE 256 +#define MAX_QUANT_TABLE_MASK (MAX_QUANT_TABLE_SIZE - 1) #define MAX_CONTEXT_INPUTS 5 #define AC_GOLOMB_RICE 0 @@ -60,22 +61,54 @@ typedef struct VlcState { } VlcState; typedef struct PlaneContext { - int16_t quant_table[MAX_CONTEXT_INPUTS][256]; int quant_table_index; int context_count; uint8_t (*state)[CONTEXT_SIZE]; VlcState *vlc_state; - uint8_t interlace_bit_state[2]; } PlaneContext; #define MAX_SLICES 1024 +typedef struct FFV1SliceContext { + int16_t *sample_buffer; + int32_t *sample_buffer32; + + int slice_width; + int slice_height; + int slice_x; + int slice_y; + int sx, sy; + + int run_index; + int slice_coding_mode; + int slice_rct_by_coef; + int slice_rct_ry_coef; + + // RefStruct reference, array of MAX_PLANES elements + PlaneContext *plane; + PutBitContext pb; + RangeCoder c; + + int ac_byte_count; ///< number of bytes used for AC coding + + union { + // decoder-only + struct { + int slice_reset_contexts; + int slice_damaged; + }; + + // encoder-only + struct { + uint64_t rc_stat[256][2]; + uint64_t (*rc_stat2[MAX_QUANT_TABLES])[32][2]; + }; + }; +} FFV1SliceContext; + typedef struct FFV1Context { AVClass *class; AVCodecContext *avctx; - RangeCoder c; - GetBitContext gb; - PutBitContext pb; uint64_t rc_stat[256][2]; uint64_t (*rc_stat2[MAX_QUANT_TABLES])[32][2]; int version; @@ -87,30 +120,21 @@ typedef struct FFV1Context { int flags; int64_t picture_number; int key_frame; - ThreadFrame picture, last_picture; - struct FFV1Context *fsrc; + ProgressFrame picture, last_picture; - AVFrame *cur; const AVFrame *cur_enc_frame; int plane_count; int ac; ///< 1=range coder <-> 0=golomb rice - int ac_byte_count; ///< number of bytes used for AC coding - PlaneContext plane[MAX_PLANES]; - int16_t quant_table[MAX_CONTEXT_INPUTS][256]; - int16_t quant_tables[MAX_QUANT_TABLES][MAX_CONTEXT_INPUTS][256]; + int16_t quant_tables[MAX_QUANT_TABLES][MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE]; int context_count[MAX_QUANT_TABLES]; uint8_t state_transition[256]; uint8_t (*initial_states[MAX_QUANT_TABLES])[32]; - int run_index; int colorspace; - int16_t *sample_buffer; - int32_t *sample_buffer32; int use32bit; int ec; int intra; - int slice_damaged; int key_frame_ok; int context_model; @@ -120,28 +144,36 @@ typedef struct FFV1Context { int gob_count; int quant_table_count; - struct FFV1Context *slice_context[MAX_SLICES]; int slice_count; int max_slice_count; int num_v_slices; int num_h_slices; - int slice_width; - int slice_height; - int slice_x; - int slice_y; - int slice_reset_contexts; - int slice_coding_mode; - int slice_rct_by_coef; - int slice_rct_ry_coef; + + FFV1SliceContext *slices; + /* RefStruct object, per-slice damage flags shared between frame threads. + * + * After a frame thread marks some slice as finished with + * ff_progress_frame_report(), the corresponding array element must not be + * accessed by this thread anymore, as from then on it is owned by the next + * thread. + */ + uint8_t *slice_damaged; + /* Frame damage flag, used to delay announcing progress, since ER is + * applied after all the slices are decoded. + * NOT shared between frame threads. + */ + uint8_t frame_damaged; } FFV1Context; int ff_ffv1_common_init(AVCodecContext *avctx); -int ff_ffv1_init_slice_state(const FFV1Context *f, FFV1Context *fs); +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, FFV1Context *fs); +void ff_ffv1_clear_slice_state(const FFV1Context *f, FFV1SliceContext *sc); int ff_ffv1_close(AVCodecContext *avctx); +int ff_need_new_slices(int width, int num_h_slices, int chroma_shift); static av_always_inline int fold(int diff, int bits) { diff --git a/libavcodec/ffv1_template.c b/libavcodec/ffv1_template.c index c5f61b018..abb90a12e 100644 --- a/libavcodec/ffv1_template.c +++ b/libavcodec/ffv1_template.c @@ -29,25 +29,25 @@ static inline int RENAME(predict)(TYPE *src, TYPE *last) return mid_pred(L, L + T - LT, T); } -static inline int RENAME(get_context)(PlaneContext *p, TYPE *src, - TYPE *last, TYPE *last2) +static inline int RENAME(get_context)(const int16_t quant_table[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE], + TYPE *src, TYPE *last, TYPE *last2) { const int LT = last[-1]; const int T = last[0]; const int RT = last[1]; const int L = src[-1]; - if (p->quant_table[3][127] || p->quant_table[4][127]) { + if (quant_table[3][127] || quant_table[4][127]) { const int TT = last2[0]; const int LL = src[-2]; - return p->quant_table[0][(L - LT) & 0xFF] + - p->quant_table[1][(LT - T) & 0xFF] + - p->quant_table[2][(T - RT) & 0xFF] + - p->quant_table[3][(LL - L) & 0xFF] + - p->quant_table[4][(TT - T) & 0xFF]; + return quant_table[0][(L - LT) & MAX_QUANT_TABLE_MASK] + + quant_table[1][(LT - T) & MAX_QUANT_TABLE_MASK] + + quant_table[2][(T - RT) & MAX_QUANT_TABLE_MASK] + + quant_table[3][(LL - L) & MAX_QUANT_TABLE_MASK] + + quant_table[4][(TT - T) & MAX_QUANT_TABLE_MASK]; } else - return p->quant_table[0][(L - LT) & 0xFF] + - p->quant_table[1][(LT - T) & 0xFF] + - p->quant_table[2][(T - RT) & 0xFF]; + return quant_table[0][(L - LT) & MAX_QUANT_TABLE_MASK] + + quant_table[1][(LT - T) & MAX_QUANT_TABLE_MASK] + + quant_table[2][(T - RT) & MAX_QUANT_TABLE_MASK]; } diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c index 97877b910..79374658e 100644 --- a/libavcodec/ffv1dec.c +++ b/libavcodec/ffv1dec.c @@ -27,7 +27,7 @@ #include "libavutil/avassert.h" #include "libavutil/crc.h" -#include "libavutil/opt.h" +#include "libavutil/mem.h" #include "libavutil/imgutils.h" #include "libavutil/pixdesc.h" #include "avcodec.h" @@ -37,8 +37,9 @@ #include "golomb.h" #include "mathops.h" #include "ffv1.h" +#include "progressframe.h" +#include "refstruct.h" #include "thread.h" -#include "threadframe.h" static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state, int is_signed) @@ -46,7 +47,7 @@ static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state, if (get_rac(c, state + 0)) return 0; else { - int i, e; + int e; unsigned a; e = 0; while (get_rac(c, state + 1 + FFMIN(e, 9))) { // 1..10 @@ -56,7 +57,7 @@ static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state, } a = 1; - for (i = e - 1; i >= 0; i--) + 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 @@ -94,14 +95,13 @@ static inline int get_vlc_symbol(GetBitContext *gb, VlcState *const state, return ret; } -static int is_input_end(FFV1Context *s) +static int is_input_end(RangeCoder *c, GetBitContext *gb, int ac) { - if (s->ac != AC_GOLOMB_RICE) { - RangeCoder *const c = &s->c; + if (ac != AC_GOLOMB_RICE) { if (c->overread > MAX_OVERREAD) return AVERROR_INVALIDDATA; } else { - if (get_bits_left(&s->gb) < 1) + if (get_bits_left(gb) < 1) return AVERROR_INVALIDDATA; } return 0; @@ -117,18 +117,20 @@ static int is_input_end(FFV1Context *s) #define RENAME(name) name ## 32 #include "ffv1dec_template.c" -static int decode_plane(FFV1Context *s, uint8_t *src, - int w, int h, int stride, int plane_index, +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) { + const int ac = f->ac; int x, y; int16_t *sample[2]; - sample[0] = s->sample_buffer + 3; - sample[1] = s->sample_buffer + w + 6 + 3; + sample[0] = sc->sample_buffer + 3; + sample[1] = sc->sample_buffer + w + 6 + 3; - s->run_index = 0; + sc->run_index = 0; - memset(s->sample_buffer, 0, 2 * (w + 6) * sizeof(*s->sample_buffer)); + memset(sc->sample_buffer, 0, 2 * (w + 6) * sizeof(*sc->sample_buffer)); for (y = 0; y < h; y++) { int16_t *temp = sample[0]; // FIXME: try a normal buffer @@ -139,23 +141,23 @@ static int decode_plane(FFV1Context *s, uint8_t *src, sample[1][-1] = sample[0][0]; sample[0][w] = sample[0][w - 1]; - if (s->avctx->bits_per_raw_sample <= 8) { - int ret = decode_line(s, w, sample, plane_index, 8); + if (f->avctx->bits_per_raw_sample <= 8) { + int ret = decode_line(f, sc, gb, w, sample, plane_index, 8, ac); if (ret < 0) return ret; for (x = 0; x < w; x++) src[x*pixel_stride + stride * y] = sample[1][x]; } else { - int ret = decode_line(s, w, sample, plane_index, s->avctx->bits_per_raw_sample); + int ret = decode_line(f, sc, gb, w, sample, plane_index, f->avctx->bits_per_raw_sample, ac); if (ret < 0) return ret; - if (s->packed_at_lsb) { + if (f->packed_at_lsb) { 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 - s->avctx->bits_per_raw_sample) | ((uint16_t **)sample)[1][x] >> (2 * s->avctx->bits_per_raw_sample - 16); + ((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); } } } @@ -163,11 +165,12 @@ static int decode_plane(FFV1Context *s, uint8_t *src, return 0; } -static int decode_slice_header(const FFV1Context *f, FFV1Context *fs) +static int decode_slice_header(const FFV1Context *f, + FFV1SliceContext *sc, AVFrame *frame) { - RangeCoder *c = &fs->c; + RangeCoder *c = &sc->c; uint8_t state[CONTEXT_SIZE]; - unsigned ps, i, context_count; + unsigned ps, context_count; int sx, sy, sw, sh; memset(state, 128, sizeof(state)); @@ -184,28 +187,27 @@ static int decode_slice_header(const FFV1Context *f, FFV1Context *fs) if (sx > f->num_h_slices - sw || sy > f->num_v_slices - sh) return AVERROR_INVALIDDATA; - fs->slice_x = sx * (int64_t)f->width / f->num_h_slices; - fs->slice_y = sy * (int64_t)f->height / f->num_v_slices; - fs->slice_width = (sx + sw) * (int64_t)f->width / f->num_h_slices - fs->slice_x; - fs->slice_height = (sy + sh) * (int64_t)f->height / f->num_v_slices - fs->slice_y; + 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; - av_assert0((unsigned)fs->slice_width <= f->width && - (unsigned)fs->slice_height <= f->height); - av_assert0 ( (unsigned)fs->slice_x + (uint64_t)fs->slice_width <= f->width - && (unsigned)fs->slice_y + (uint64_t)fs->slice_height <= f->height); + av_assert0((unsigned)sc->slice_width <= f->width && + (unsigned)sc->slice_height <= f->height); + av_assert0 ( (unsigned)sc->slice_x + (uint64_t)sc->slice_width <= f->width + && (unsigned)sc->slice_y + (uint64_t)sc->slice_height <= f->height); - if (fs->ac == AC_GOLOMB_RICE && fs->slice_width >= (1<<23)) + if (f->ac == AC_GOLOMB_RICE && sc->slice_width >= (1<<23)) return AVERROR_INVALIDDATA; - for (i = 0; i < f->plane_count; i++) { - PlaneContext * const p = &fs->plane[i]; + for (unsigned i = 0; i < f->plane_count; i++) { + PlaneContext * const p = &sc->plane[i]; int idx = 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; } p->quant_table_index = idx; - memcpy(p->quant_table, f->quant_tables[idx], sizeof(p->quant_table)); context_count = f->context_count[idx]; if (p->context_count < context_count) { @@ -217,32 +219,32 @@ static int decode_slice_header(const FFV1Context *f, FFV1Context *fs) ps = get_symbol(c, state, 0); if (ps == 1) { - f->cur->flags |= AV_FRAME_FLAG_INTERLACED; - f->cur->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; + frame->flags |= AV_FRAME_FLAG_INTERLACED; + frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; } else if (ps == 2) { - f->cur->flags |= AV_FRAME_FLAG_INTERLACED; - f->cur->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST; + frame->flags |= AV_FRAME_FLAG_INTERLACED; + frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST; } else if (ps == 3) { - f->cur->flags &= ~AV_FRAME_FLAG_INTERLACED; + frame->flags &= ~AV_FRAME_FLAG_INTERLACED; } - f->cur->sample_aspect_ratio.num = get_symbol(c, state, 0); - f->cur->sample_aspect_ratio.den = get_symbol(c, state, 0); + frame->sample_aspect_ratio.num = get_symbol(c, state, 0); + frame->sample_aspect_ratio.den = get_symbol(c, state, 0); if (av_image_check_sar(f->width, f->height, - f->cur->sample_aspect_ratio) < 0) { + frame->sample_aspect_ratio) < 0) { av_log(f->avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n", - f->cur->sample_aspect_ratio.num, - f->cur->sample_aspect_ratio.den); - f->cur->sample_aspect_ratio = (AVRational){ 0, 1 }; + frame->sample_aspect_ratio.num, + frame->sample_aspect_ratio.den); + frame->sample_aspect_ratio = (AVRational){ 0, 1 }; } - if (fs->version > 3) { - fs->slice_reset_contexts = get_rac(c, state); - fs->slice_coding_mode = get_symbol(c, state, 0); - if (fs->slice_coding_mode != 1) { - fs->slice_rct_by_coef = get_symbol(c, state, 0); - fs->slice_rct_ry_coef = get_symbol(c, state, 0); - if ((uint64_t)fs->slice_rct_by_coef + (uint64_t)fs->slice_rct_ry_coef > 4) { + if (f->version > 3) { + sc->slice_reset_contexts = get_rac(c, state); + sc->slice_coding_mode = 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); + 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; } @@ -252,125 +254,108 @@ static int decode_slice_header(const FFV1Context *f, FFV1Context *fs) return 0; } +static void slice_set_damaged(FFV1Context *f, FFV1SliceContext *sc) +{ + sc->slice_damaged = 1; + + // only set this for frame threading, as for slice threading its value is + // not used and setting it would be a race + if (f->avctx->active_thread_type & FF_THREAD_FRAME) + f->frame_damaged = 1; +} + static int decode_slice(AVCodecContext *c, void *arg) { - FFV1Context *fs = *(void **)arg; - FFV1Context *f = fs->avctx->priv_data; + 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; - AVFrame * const p = f->cur; - int i, si; + AVFrame * const p = f->picture.f; + const int si = sc - f->slices; + GetBitContext gb; - for( si=0; fs != f->slice_context[si]; si ++) - ; + if (!(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f) + ff_progress_frame_await(&f->last_picture, si); - if(f->fsrc && !(p->flags & AV_FRAME_FLAG_KEY)) - ff_thread_await_progress(&f->last_picture, si, 0); + if (f->slice_damaged[si]) + slice_set_damaged(f, sc); - if(f->fsrc && !(p->flags & AV_FRAME_FLAG_KEY)) { - FFV1Context *fssrc = f->fsrc->slice_context[si]; - FFV1Context *fsdst = f->slice_context[si]; - av_assert1(fsdst->plane_count == fssrc->plane_count); - av_assert1(fsdst == fs); - - if (!(p->flags & AV_FRAME_FLAG_KEY)) - fsdst->slice_damaged |= fssrc->slice_damaged; - - for (i = 0; i < f->plane_count; i++) { - PlaneContext *psrc = &fssrc->plane[i]; - PlaneContext *pdst = &fsdst->plane[i]; - - av_free(pdst->state); - av_free(pdst->vlc_state); - memcpy(pdst, psrc, sizeof(*pdst)); - pdst->state = NULL; - pdst->vlc_state = NULL; - - if (fssrc->ac) { - pdst->state = av_malloc_array(CONTEXT_SIZE, psrc->context_count); - memcpy(pdst->state, psrc->state, CONTEXT_SIZE * psrc->context_count); - } else { - pdst->vlc_state = av_malloc_array(sizeof(*pdst->vlc_state), psrc->context_count); - memcpy(pdst->vlc_state, psrc->vlc_state, sizeof(*pdst->vlc_state) * psrc->context_count); - } - } - } - - fs->slice_rct_by_coef = 1; - fs->slice_rct_ry_coef = 1; + sc->slice_rct_by_coef = 1; + sc->slice_rct_ry_coef = 1; if (f->version > 2) { - if (ff_ffv1_init_slice_state(f, fs) < 0) + if (ff_ffv1_init_slice_state(f, sc) < 0) return AVERROR(ENOMEM); - if (decode_slice_header(f, fs) < 0) { - fs->slice_x = fs->slice_y = fs->slice_height = fs->slice_width = 0; - fs->slice_damaged = 1; + if (decode_slice_header(f, sc, p) < 0) { + sc->slice_x = sc->slice_y = sc->slice_height = sc->slice_width = 0; + slice_set_damaged(f, sc); return AVERROR_INVALIDDATA; } } - if ((ret = ff_ffv1_init_slice_state(f, fs)) < 0) + if ((ret = ff_ffv1_init_slice_state(f, sc)) < 0) return ret; - if ((f->cur->flags & AV_FRAME_FLAG_KEY) || fs->slice_reset_contexts) { - ff_ffv1_clear_slice_state(f, fs); - } else if (fs->slice_damaged) { + if ((p->flags & AV_FRAME_FLAG_KEY) || sc->slice_reset_contexts) { + ff_ffv1_clear_slice_state(f, sc); + } else if (sc->slice_damaged) { return AVERROR_INVALIDDATA; } - width = fs->slice_width; - height = fs->slice_height; - x = fs->slice_x; - y = fs->slice_y; + width = sc->slice_width; + height = sc->slice_height; + x = sc->slice_x; + y = sc->slice_y; - if (fs->ac == AC_GOLOMB_RICE) { + if (f->ac == AC_GOLOMB_RICE) { if (f->version == 3 && f->micro_version > 1 || f->version > 3) - get_rac(&fs->c, (uint8_t[]) { 129 }); - fs->ac_byte_count = f->version > 2 || (!x && !y) ? fs->c.bytestream - fs->c.bytestream_start - 1 : 0; - init_get_bits(&fs->gb, - fs->c.bytestream_start + fs->ac_byte_count, - (fs->c.bytestream_end - fs->c.bytestream_start - fs->ac_byte_count) * 8); + 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, + sc->c.bytestream_start + sc->ac_byte_count, + (sc->c.bytestream_end - sc->c.bytestream_start - sc->ac_byte_count) * 8); } av_assert1(width && height); - if (f->colorspace == 0 && (f->chroma_planes || !fs->transparency)) { + if (f->colorspace == 0 && (f->chroma_planes || !f->transparency)) { 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 int cx = x >> f->chroma_h_shift; const int cy = y >> f->chroma_v_shift; - decode_plane(fs, 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, 1); if (f->chroma_planes) { - decode_plane(fs, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1); - decode_plane(fs, 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); + decode_plane(f, sc, &gb, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1); } - if (fs->transparency) - decode_plane(fs, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], (f->version >= 4 && !f->chroma_planes) ? 1 : 2, 1); + 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); } else if (f->colorspace == 0) { - decode_plane(fs, p->data[0] + ps*x + y*p->linesize[0] , width, height, p->linesize[0], 0, 2); - decode_plane(fs, 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, 2); + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] + 1, width, height, p->linesize[0], 1, 2); } 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], p->data[2] + ps * x + y * p->linesize[2], p->data[3] + ps * x + y * p->linesize[3] }; - decode_rgb_frame32(fs, planes, width, height, p->linesize); + decode_rgb_frame32(f, sc, &gb, planes, width, height, p->linesize); } else { uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0], p->data[1] + ps * x + y * p->linesize[1], p->data[2] + ps * x + y * p->linesize[2], p->data[3] + ps * x + y * p->linesize[3] }; - decode_rgb_frame(fs, planes, width, height, p->linesize); + decode_rgb_frame(f, sc, &gb, planes, width, height, p->linesize); } - if (fs->ac != AC_GOLOMB_RICE && f->version > 2) { + if (f->ac != AC_GOLOMB_RICE && f->version > 2) { int v; - get_rac(&fs->c, (uint8_t[]) { 129 }); - v = fs->c.bytestream_end - fs->c.bytestream - 2 - 5*f->ec; + get_rac(&sc->c, (uint8_t[]) { 129 }); + v = sc->c.bytestream_end - sc->c.bytestream - 2 - 5*!!f->ec; if (v) { av_log(f->avctx, AV_LOG_ERROR, "bytestream end mismatching by %d\n", v); - fs->slice_damaged = 1; + slice_set_damaged(f, sc); } } - ff_thread_report_progress(&f->picture, si, 0); + if ((c->active_thread_type & FF_THREAD_FRAME) && !f->frame_damaged) + ff_progress_frame_report(&f->picture, si); return 0; } @@ -422,19 +407,19 @@ static int read_quant_tables(RangeCoder *c, static int read_extra_header(FFV1Context *f) { - RangeCoder *const c = &f->c; + RangeCoder c; uint8_t state[CONTEXT_SIZE]; - int i, j, k, ret; + 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); + 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); + 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; @@ -445,27 +430,27 @@ static int read_extra_header(FFV1Context *f) return AVERROR_PATCHWELCOME; } if (f->version > 2) { - c->bytestream_end -= 4; - f->micro_version = get_symbol(c, state, 0); + 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); + f->ac = get_symbol(&c, state, 0); if (f->ac == AC_RANGE_CUSTOM_TAB) { - for (i = 1; i < 256; i++) - f->state_transition[i] = get_symbol(c, state, 1) + c->one_state[i]; + 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->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); + 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", @@ -485,15 +470,15 @@ static int read_extra_header(FFV1Context *f) return AVERROR_PATCHWELCOME; } - f->quant_table_count = get_symbol(c, state, 0); + 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 (i = 0; i < f->quant_table_count; i++) { - f->context_count[i] = read_quant_tables(c, f->quant_tables[i]); + 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; @@ -502,20 +487,20 @@ static int read_extra_header(FFV1Context *f) if ((ret = ff_ffv1_allocate_initial_states(f)) < 0) return ret; - for (i = 0; i < f->quant_table_count; i++) - if (get_rac(c, state)) { - for (j = 0; j < f->context_count[i]; j++) - for (k = 0; k < CONTEXT_SIZE; k++) { + 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; + (pred + get_symbol(&c, state2[k], 1)) & 0xFF; } } if (f->version > 2) { - f->ec = get_symbol(c, state, 0); + f->ec = get_symbol(&c, state, 0); if (f->micro_version > 2) - f->intra = get_symbol(c, state, 0); + f->intra = get_symbol(&c, state, 0); } if (f->version > 2) { @@ -550,8 +535,8 @@ static int read_extra_header(FFV1Context *f) static int read_header(FFV1Context *f) { uint8_t state[CONTEXT_SIZE]; - int i, j, context_count = -1; //-1 to avoid warning - RangeCoder *const c = &f->slice_context[0]->c; + int context_count = -1; //-1 to avoid warning + RangeCoder *const c = &f->slices[0].c; memset(state, 128, sizeof(state)); @@ -566,7 +551,7 @@ static int read_header(FFV1Context *f) f->ac = get_symbol(c, state, 0); if (f->ac == AC_RANGE_CUSTOM_TAB) { - for (i = 1; i < 256; i++) { + 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); @@ -765,7 +750,7 @@ static int read_header(FFV1Context *f) ff_dlog(f->avctx, "%d %d %d\n", f->chroma_h_shift, f->chroma_v_shift, f->avctx->pix_fmt); if (f->version < 2) { - context_count = read_quant_tables(c, f->quant_table); + context_count = 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; @@ -790,12 +775,13 @@ static int read_header(FFV1Context *f) return AVERROR_INVALIDDATA; } - for (j = 0; j < f->slice_count; j++) { - FFV1Context *fs = f->slice_context[j]; - fs->ac = f->ac; - fs->packed_at_lsb = f->packed_at_lsb; + ff_refstruct_unref(&f->slice_damaged); + f->slice_damaged = ff_refstruct_allocz(f->slice_count * sizeof(*f->slice_damaged)); + if (!f->slice_damaged) + return AVERROR(ENOMEM); - fs->slice_damaged = 0; + for (int j = 0; j < f->slice_count; j++) { + FFV1SliceContext *sc = &f->slices[j]; if (f->version == 2) { int sx = get_symbol(c, state, 0); @@ -808,19 +794,24 @@ static int read_header(FFV1Context *f) if (sx > f->num_h_slices - sw || sy > f->num_v_slices - sh) return AVERROR_INVALIDDATA; - fs->slice_x = sx * (int64_t)f->width / f->num_h_slices; - fs->slice_y = sy * (int64_t)f->height / f->num_v_slices; - fs->slice_width = (sx + sw) * (int64_t)f->width / f->num_h_slices - fs->slice_x; - fs->slice_height = (sy + sh) * (int64_t)f->height / f->num_v_slices - fs->slice_y; + 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; - av_assert0((unsigned)fs->slice_width <= f->width && - (unsigned)fs->slice_height <= f->height); - av_assert0 ( (unsigned)fs->slice_x + (uint64_t)fs->slice_width <= f->width - && (unsigned)fs->slice_y + (uint64_t)fs->slice_height <= f->height); + av_assert0((unsigned)sc->slice_width <= f->width && + (unsigned)sc->slice_height <= f->height); + av_assert0 ( (unsigned)sc->slice_x + (uint64_t)sc->slice_width <= f->width + && (unsigned)sc->slice_y + (uint64_t)sc->slice_height <= f->height); } - for (i = 0; i < f->plane_count; i++) { - PlaneContext *const p = &fs->plane[i]; + ff_refstruct_unref(&sc->plane); + sc->plane = ff_ffv1_planes_alloc(); + if (!sc->plane) + return AVERROR(ENOMEM); + + for (int i = 0; i < f->plane_count; i++) { + PlaneContext *const p = &sc->plane[i]; if (f->version == 2) { int idx = get_symbol(c, state, 0); @@ -830,19 +821,11 @@ static int read_header(FFV1Context *f) return AVERROR_INVALIDDATA; } p->quant_table_index = idx; - memcpy(p->quant_table, f->quant_tables[idx], - sizeof(p->quant_table)); context_count = f->context_count[idx]; - } else { - memcpy(p->quant_table, f->quant_table, sizeof(p->quant_table)); } if (f->version <= 2) { av_assert0(context_count >= 0); - if (p->context_count < context_count) { - av_freep(&p->state); - av_freep(&p->vlc_state); - } p->context_count = context_count; } } @@ -858,11 +841,6 @@ static av_cold int decode_init(AVCodecContext *avctx) if ((ret = ff_ffv1_common_init(avctx)) < 0) return ret; - f->picture.f = av_frame_alloc(); - f->last_picture.f = av_frame_alloc(); - if (!f->picture.f || !f->last_picture.f) - return AVERROR(ENOMEM); - if (avctx->extradata_size > 0 && (ret = read_extra_header(f)) < 0) return ret; @@ -878,32 +856,23 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, uint8_t *buf = avpkt->data; int buf_size = avpkt->size; FFV1Context *f = avctx->priv_data; - RangeCoder *const c = &f->slice_context[0]->c; - int i, ret; + RangeCoder *const c = &f->slices[0].c; + int ret, key_frame; uint8_t keystate = 128; uint8_t *buf_p; AVFrame *p; - if (f->last_picture.f) - ff_thread_release_ext_buffer(&f->last_picture); - FFSWAP(ThreadFrame, f->picture, f->last_picture); + ff_progress_frame_unref(&f->last_picture); + FFSWAP(ProgressFrame, f->picture, f->last_picture); - f->cur = p = f->picture.f; - - 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; - } 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); - p->pict_type = AV_PICTURE_TYPE_I; //FIXME I vs. P if (get_rac(c, &keystate)) { - p->flags |= AV_FRAME_FLAG_KEY; + key_frame = AV_FRAME_FLAG_KEY; f->key_frame_ok = 0; if ((ret = read_header(f)) < 0) return ret; @@ -914,7 +883,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, "Cannot decode non-keyframe without valid keyframe\n"); return AVERROR_INVALIDDATA; } - p->flags &= ~AV_FRAME_FLAG_KEY; + key_frame = 0; } if (f->ac != AC_GOLOMB_RICE) { @@ -923,6 +892,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, } else { int w = avctx->width; int s = 1 + w / (1<<23); + int i; w /= s; @@ -932,10 +902,23 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, return AVERROR_INVALIDDATA; } - ret = ff_thread_get_ext_buffer(avctx, &f->picture, AV_GET_BUFFER_FLAG_REF); + ret = ff_progress_frame_get_buffer(avctx, &f->picture, + AV_GET_BUFFER_FLAG_REF); 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) | 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; + } + 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); @@ -943,18 +926,20 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, ff_thread_finish_setup(avctx); buf_p = buf + buf_size; - for (i = f->slice_count - 1; i >= 0; i--) { - FFV1Context *fs = f->slice_context[i]; + for (int i = f->slice_count - 1; i >= 0; i--) { + FFV1SliceContext *sc = &f->slices[i]; int trailer = 3 + 5*!!f->ec; int v; + 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_thread_report_progress(&f->picture, INT_MAX, 0); + ff_progress_frame_report(&f->picture, INT_MAX); return AVERROR_INVALIDDATA; } buf_p -= v; @@ -971,7 +956,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, } else { av_log(f->avctx, AV_LOG_ERROR, "\n"); } - fs->slice_damaged = 1; + 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)); @@ -979,53 +964,50 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, } if (i) { - ff_init_range_decoder(&fs->c, buf_p, v); + ff_init_range_decoder(&sc->c, buf_p, v); + ff_build_rac_states(&sc->c, 0.05 * (1LL << 32), 256 - 8); } else - fs->c.bytestream_end = buf_p + v; + sc->c.bytestream_end = buf_p + v; - fs->avctx = avctx; } avctx->execute(avctx, decode_slice, - &f->slice_context[0], + f->slices, NULL, f->slice_count, - sizeof(void*)); + sizeof(*f->slices)); - for (i = f->slice_count - 1; i >= 0; i--) { - FFV1Context *fs = f->slice_context[i]; - int j; - if (fs->slice_damaged && f->last_picture.f->data[0]) { + 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 uint8_t *src[4]; uint8_t *dst[4]; - ff_thread_await_progress(&f->last_picture, INT_MAX, 0); - for (j = 0; j < desc->nb_components; j++) { + ff_progress_frame_await(&f->last_picture, INT_MAX); + for (int j = 0; j < desc->nb_components; j++) { int pixshift = desc->comp[j].depth > 8; int sh = (j == 1 || j == 2) ? f->chroma_h_shift : 0; int sv = (j == 1 || j == 2) ? f->chroma_v_shift : 0; dst[j] = p->data[j] + p->linesize[j] * - (fs->slice_y >> sv) + ((fs->slice_x >> sh) << pixshift); + (sc->slice_y >> sv) + ((sc->slice_x >> sh) << pixshift); src[j] = f->last_picture.f->data[j] + f->last_picture.f->linesize[j] * - (fs->slice_y >> sv) + ((fs->slice_x >> sh) << pixshift); + (sc->slice_y >> sv) + ((sc->slice_x >> sh) << pixshift); } - if (desc->flags & AV_PIX_FMT_FLAG_PAL) { - dst[1] = p->data[1]; - src[1] = f->last_picture.f->data[1]; - } + av_image_copy(dst, p->linesize, src, f->last_picture.f->linesize, avctx->pix_fmt, - fs->slice_width, - fs->slice_height); + sc->slice_width, + sc->slice_height); + + f->slice_damaged[i] = 1; } } - ff_thread_report_progress(&f->picture, INT_MAX, 0); + ff_progress_frame_report(&f->picture, INT_MAX); - if (f->last_picture.f) - ff_thread_release_ext_buffer(&f->last_picture); + ff_progress_frame_unref(&f->last_picture); if ((ret = av_frame_ref(rframe, f->picture.f)) < 0) return ret; @@ -1034,68 +1016,59 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, return buf_size; } -static void copy_fields(FFV1Context *fsdst, const FFV1Context *fssrc, - const FFV1Context *fsrc) -{ - fsdst->version = fsrc->version; - fsdst->micro_version = fsrc->micro_version; - fsdst->chroma_planes = fsrc->chroma_planes; - fsdst->chroma_h_shift = fsrc->chroma_h_shift; - fsdst->chroma_v_shift = fsrc->chroma_v_shift; - fsdst->transparency = fsrc->transparency; - fsdst->plane_count = fsrc->plane_count; - fsdst->ac = fsrc->ac; - fsdst->colorspace = fsrc->colorspace; - - fsdst->ec = fsrc->ec; - fsdst->intra = fsrc->intra; - fsdst->slice_damaged = fssrc->slice_damaged; - fsdst->key_frame_ok = fsrc->key_frame_ok; - - fsdst->packed_at_lsb = fsrc->packed_at_lsb; - fsdst->slice_count = fsrc->slice_count; - if (fsrc->version<3){ - fsdst->slice_x = fssrc->slice_x; - fsdst->slice_y = fssrc->slice_y; - fsdst->slice_width = fssrc->slice_width; - fsdst->slice_height = fssrc->slice_height; - } -} - #if HAVE_THREADS static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { FFV1Context *fsrc = src->priv_data; FFV1Context *fdst = dst->priv_data; - int i, ret; if (dst == src) return 0; - copy_fields(fdst, fsrc, fsrc); + fdst->version = fsrc->version; + fdst->micro_version = fsrc->micro_version; + fdst->chroma_planes = fsrc->chroma_planes; + fdst->chroma_h_shift = fsrc->chroma_h_shift; + fdst->chroma_v_shift = fsrc->chroma_v_shift; + fdst->transparency = fsrc->transparency; + fdst->plane_count = fsrc->plane_count; + fdst->ac = fsrc->ac; + fdst->colorspace = fsrc->colorspace; + + fdst->ec = fsrc->ec; + fdst->intra = fsrc->intra; + fdst->key_frame_ok = fsrc->key_frame_ok; + + fdst->packed_at_lsb = fsrc->packed_at_lsb; + fdst->slice_count = fsrc->slice_count; fdst->use32bit = fsrc->use32bit; memcpy(fdst->state_transition, fsrc->state_transition, sizeof(fdst->state_transition)); - memcpy(fdst->quant_table, fsrc->quant_table, sizeof(fsrc->quant_table)); - for (i = 0; i < fdst->num_h_slices * fdst->num_v_slices; i++) { - FFV1Context *fssrc = fsrc->slice_context[i]; - FFV1Context *fsdst = fdst->slice_context[i]; - copy_fields(fsdst, fssrc, fsrc); + // in version 1 there is a single per-keyframe quant table, so + // we need to propagate it between threads + if (fsrc->version < 2) + memcpy(fdst->quant_tables[0], fsrc->quant_tables[0], sizeof(fsrc->quant_tables[0])); + + for (int i = 0; i < fdst->num_h_slices * fdst->num_v_slices; i++) { + FFV1SliceContext *sc = &fdst->slices[i]; + const FFV1SliceContext *sc0 = &fsrc->slices[i]; + + ff_refstruct_replace(&sc->plane, sc0->plane); + + if (fsrc->version < 3) { + sc->slice_x = sc0->slice_x; + sc->slice_y = sc0->slice_y; + sc->slice_width = sc0->slice_width; + sc->slice_height = sc0->slice_height; + } } - av_assert0(!fdst->plane[0].state); - av_assert0(!fdst->sample_buffer); + + ff_refstruct_replace(&fdst->slice_damaged, fsrc->slice_damaged); av_assert1(fdst->max_slice_count == fsrc->max_slice_count); - - ff_thread_release_ext_buffer(&fdst->picture); - if (fsrc->picture.f->data[0]) { - if ((ret = ff_thread_ref_frame(&fdst->picture, &fsrc->picture)) < 0) - return ret; - } - - fdst->fsrc = fsrc; + ff_progress_frame_replace(&fdst->picture, &fsrc->picture); return 0; } @@ -1105,15 +1078,9 @@ static av_cold int ffv1_decode_close(AVCodecContext *avctx) { FFV1Context *const s = avctx->priv_data; - if (s->picture.f) { - ff_thread_release_ext_buffer(&s->picture); - av_frame_free(&s->picture.f); - } + ff_progress_frame_unref(&s->picture); + ff_progress_frame_unref(&s->last_picture); - if (s->last_picture.f) { - ff_thread_release_ext_buffer(&s->last_picture); - av_frame_free(&s->last_picture.f); - } return ff_ffv1_close(avctx); } @@ -1130,5 +1097,5 @@ 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_ALLOCATE_PROGRESS, + FF_CODEC_CAP_USES_PROGRESSFRAMES, }; diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c index 590ccac02..2da6bd935 100644 --- a/libavcodec/ffv1dec_template.c +++ b/libavcodec/ffv1dec_template.c @@ -22,21 +22,24 @@ #include "ffv1_template.c" -static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w, - TYPE *sample[2], - int plane_index, int bits) +static av_always_inline int +RENAME(decode_line)(FFV1Context *f, FFV1SliceContext *sc, + GetBitContext *gb, + int w, TYPE *sample[2], int plane_index, int bits, + int ac) { - PlaneContext *const p = &s->plane[plane_index]; - RangeCoder *const c = &s->c; + PlaneContext *const p = &sc->plane[plane_index]; + RangeCoder *const c = &sc->c; + const int16_t (*quant_table)[256] = f->quant_tables[p->quant_table_index]; int x; int run_count = 0; int run_mode = 0; - int run_index = s->run_index; + int run_index = sc->run_index; - if (is_input_end(s)) + if (is_input_end(c, gb, ac)) return AVERROR_INVALIDDATA; - if (s->slice_coding_mode == 1) { + if (sc->slice_coding_mode == 1) { int i; for (x = 0; x < w; x++) { int v = 0; @@ -53,11 +56,12 @@ static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w, int diff, context, sign; if (!(x & 1023)) { - if (is_input_end(s)) + if (is_input_end(c, gb, ac)) return AVERROR_INVALIDDATA; } - context = RENAME(get_context)(p, sample[1] + x, sample[0] + x, sample[1] + x); + context = RENAME(get_context)(quant_table, + sample[1] + x, sample[0] + x, sample[1] + x); if (context < 0) { context = -context; sign = 1; @@ -66,7 +70,7 @@ static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w, av_assert2(context < p->context_count); - if (s->ac != AC_GOLOMB_RICE) { + if (ac != AC_GOLOMB_RICE) { diff = get_symbol_inline(c, p->state[context], 1); } else { if (context == 0 && run_mode == 0) @@ -74,13 +78,13 @@ static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w, if (run_mode) { if (run_count == 0 && run_mode == 1) { - if (get_bits1(&s->gb)) { + if (get_bits1(gb)) { run_count = 1 << ff_log2_run[run_index]; if (x + run_count <= w) run_index++; } else { if (ff_log2_run[run_index]) - run_count = get_bits(&s->gb, ff_log2_run[run_index]); + run_count = get_bits(gb, ff_log2_run[run_index]); else run_count = 0; if (run_index) @@ -105,45 +109,48 @@ static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w, if (run_count < 0) { run_mode = 0; run_count = 0; - diff = get_vlc_symbol(&s->gb, &p->vlc_state[context], + diff = get_vlc_symbol(gb, &p->vlc_state[context], bits); if (diff >= 0) diff++; } else diff = 0; } else - diff = get_vlc_symbol(&s->gb, &p->vlc_state[context], bits); + diff = get_vlc_symbol(gb, &p->vlc_state[context], bits); - ff_dlog(s->avctx, "count:%d index:%d, mode:%d, x:%d pos:%d\n", - run_count, run_index, run_mode, x, get_bits_count(&s->gb)); + ff_dlog(f->avctx, "count:%d index:%d, mode:%d, x:%d pos:%d\n", + run_count, run_index, run_mode, x, get_bits_count(gb)); } if (sign) diff = -(unsigned)diff; - sample[1][x] = av_mod_uintp2(RENAME(predict)(sample[1] + x, sample[0] + x) + (SUINT)diff, bits); + sample[1][x] = av_zero_extend(RENAME(predict)(sample[1] + x, sample[0] + x) + (SUINT)diff, bits); } - s->run_index = run_index; + sc->run_index = run_index; return 0; } -static int RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int h, int stride[4]) +static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, + GetBitContext *gb, + uint8_t *src[4], int w, int h, int stride[4]) { int x, y, p; TYPE *sample[4][2]; - int lbd = s->avctx->bits_per_raw_sample <= 8; - int bits = s->avctx->bits_per_raw_sample > 0 ? s->avctx->bits_per_raw_sample : 8; + 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 transparency = s->transparency; + int transparency = f->transparency; + int ac = f->ac; for (x = 0; x < 4; x++) { - sample[x][0] = RENAME(s->sample_buffer) + x * 2 * (w + 6) + 3; - sample[x][1] = RENAME(s->sample_buffer) + (x * 2 + 1) * (w + 6) + 3; + sample[x][0] = RENAME(sc->sample_buffer) + x * 2 * (w + 6) + 3; + sample[x][1] = RENAME(sc->sample_buffer) + (x * 2 + 1) * (w + 6) + 3; } - s->run_index = 0; + sc->run_index = 0; - memset(RENAME(s->sample_buffer), 0, 8 * (w + 6) * sizeof(*RENAME(s->sample_buffer))); + memset(RENAME(sc->sample_buffer), 0, 8 * (w + 6) * sizeof(*RENAME(sc->sample_buffer))); for (y = 0; y < h; y++) { for (p = 0; p < 3 + transparency; p++) { @@ -155,10 +162,10 @@ static int RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int sample[p][1][-1]= sample[p][0][0 ]; sample[p][0][ w]= sample[p][0][w-1]; - if (lbd && s->slice_coding_mode == 0) - ret = RENAME(decode_line)(s, w, sample[p], (p + 1)/2, 9); + if (lbd && sc->slice_coding_mode == 0) + ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, 9, ac); else - ret = RENAME(decode_line)(s, w, sample[p], (p + 1)/2, bits + (s->slice_coding_mode != 1)); + ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, bits + (sc->slice_coding_mode != 1), ac); if (ret < 0) return ret; } @@ -168,10 +175,10 @@ static int RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int int r = sample[2][1][x]; int a = sample[3][1][x]; - if (s->slice_coding_mode != 1) { + if (sc->slice_coding_mode != 1) { b -= offset; r -= offset; - g -= (b * s->slice_rct_by_coef + r * s->slice_rct_ry_coef) >> 2; + g -= (b * sc->slice_rct_by_coef + r * sc->slice_rct_ry_coef) >> 2; b += g; r += g; } diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index e510abf6f..7b8ed7acc 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -28,8 +28,8 @@ #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/crc.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/imgutils.h" #include "libavutil/pixdesc.h" #include "avcodec.h" @@ -38,7 +38,6 @@ #include "put_bits.h" #include "put_golomb.h" #include "rangecoder.h" -#include "mathops.h" #include "ffv1.h" static const int8_t quant5_10bit[256] = { @@ -199,7 +198,7 @@ static av_always_inline av_flatten void put_symbol_inline(RangeCoder *c, } while (0) if (v) { - const int a = FFABS(v); + const unsigned a = is_signed ? FFABS(v) : v; const int e = av_log2(a); put_rac(c, state + 0, 0); if (e <= 9) { @@ -270,38 +269,41 @@ static inline void put_vlc_symbol(PutBitContext *pb, VlcState *const state, #define RENAME(name) name ## 32 #include "ffv1enc_template.c" -static int encode_plane(FFV1Context *s, const uint8_t *src, int w, int h, +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 x, y, i, ret; - const int ring_size = s->context_model ? 3 : 2; + 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]; - s->run_index = 0; + sc->run_index = 0; - memset(s->sample_buffer, 0, ring_size * (w + 6) * sizeof(*s->sample_buffer)); + memset(sc->sample_buffer, 0, ring_size * (w + 6) * sizeof(*sc->sample_buffer)); for (y = 0; y < h; y++) { for (i = 0; i < ring_size; i++) - sample[i] = s->sample_buffer + (w + 6) * ((h + i - y) % ring_size) + 3; + sample[i] = sc->sample_buffer + (w + 6) * ((h + i - y) % ring_size) + 3; sample[0][-1]= sample[1][0 ]; sample[1][ w]= sample[1][w-1]; - if (s->bits_per_raw_sample <= 8) { + if (f->bits_per_raw_sample <= 8) { for (x = 0; x < w; x++) sample[0][x] = src[x * pixel_stride + stride * y]; - if((ret = encode_line(s, w, sample, plane_index, 8)) < 0) + if((ret = encode_line(f, sc, f->avctx, w, sample, plane_index, 8, ac, pass1)) < 0) return ret; } else { - if (s->packed_at_lsb) { + if (f->packed_at_lsb) { for (x = 0; x < w; x++) { sample[0][x] = ((uint16_t*)(src + stride*y))[x]; } } else { for (x = 0; x < w; x++) { - sample[0][x] = ((uint16_t*)(src + stride*y))[x] >> (16 - s->bits_per_raw_sample); + sample[0][x] = ((uint16_t*)(src + stride*y))[x] >> (16 - f->bits_per_raw_sample); } } - if((ret = encode_line(s, w, sample, plane_index, s->bits_per_raw_sample)) < 0) + if((ret = encode_line(f, sc, f->avctx, w, sample, plane_index, f->bits_per_raw_sample, ac, pass1)) < 0) return ret; } } @@ -315,7 +317,7 @@ static void write_quant_table(RangeCoder *c, int16_t *quant_table) uint8_t state[CONTEXT_SIZE]; memset(state, 128, sizeof(state)); - for (i = 1; i < 128; i++) + for (i = 1; i < MAX_QUANT_TABLE_SIZE/2; i++) if (quant_table[i] != quant_table[i - 1]) { put_symbol(c, state, i - last - 1, 0); last = i; @@ -324,7 +326,7 @@ static void write_quant_table(RangeCoder *c, int16_t *quant_table) } static void write_quant_tables(RangeCoder *c, - int16_t quant_table[MAX_CONTEXT_INPUTS][256]) + int16_t quant_table[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE]) { int i; for (i = 0; i < 5; i++) @@ -347,7 +349,7 @@ static void write_header(FFV1Context *f) { uint8_t state[CONTEXT_SIZE]; int i, j; - RangeCoder *const c = &f->slice_context[0]->c; + RangeCoder *const c = &f->slices[0].c; memset(state, 128, sizeof(state)); @@ -367,11 +369,11 @@ static void write_header(FFV1Context *f) put_symbol(c, state, f->chroma_v_shift, 0); put_rac(c, state, f->transparency); - write_quant_tables(c, f->quant_table); + write_quant_tables(c, f->quant_tables[f->context_model]); } else if (f->version < 3) { put_symbol(c, state, f->slice_count, 0); for (i = 0; i < f->slice_count; i++) { - FFV1Context *fs = f->slice_context[i]; + FFV1SliceContext *fs = &f->slices[i]; put_symbol(c, state, (fs->slice_x + 1) * f->num_h_slices / f->width, 0); put_symbol(c, state, @@ -383,8 +385,8 @@ static void write_header(FFV1Context *f) (fs->slice_height + 1) * f->num_v_slices / f->height - 1, 0); for (j = 0; j < f->plane_count; j++) { - put_symbol(c, state, f->plane[j].quant_table_index, 0); - av_assert0(f->plane[j].quant_table_index == f->context_model); + put_symbol(c, state, fs->plane[j].quant_table_index, 0); + av_assert0(fs->plane[j].quant_table_index == f->context_model); } } } @@ -392,7 +394,7 @@ static void write_header(FFV1Context *f) static int write_extradata(FFV1Context *f) { - RangeCoder *const c = &f->c; + RangeCoder c; uint8_t state[CONTEXT_SIZE]; int i, j, k; uint8_t state2[32][CONTEXT_SIZE]; @@ -406,56 +408,56 @@ static int write_extradata(FFV1Context *f) f->avctx->extradata = av_malloc(f->avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!f->avctx->extradata) return AVERROR(ENOMEM); - ff_init_range_encoder(c, f->avctx->extradata, f->avctx->extradata_size); - ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8); + ff_init_range_encoder(&c, f->avctx->extradata, f->avctx->extradata_size); + ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8); - put_symbol(c, state, f->version, 0); + 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; - put_symbol(c, state, f->micro_version, 0); + put_symbol(&c, state, f->micro_version, 0); } - put_symbol(c, state, f->ac, 0); + put_symbol(&c, state, f->ac, 0); if (f->ac == AC_RANGE_CUSTOM_TAB) for (i = 1; i < 256; i++) - put_symbol(c, state, f->state_transition[i] - c->one_state[i], 1); + put_symbol(&c, state, f->state_transition[i] - c.one_state[i], 1); - put_symbol(c, state, f->colorspace, 0); // YUV cs type - put_symbol(c, state, f->bits_per_raw_sample, 0); - put_rac(c, state, f->chroma_planes); - put_symbol(c, state, f->chroma_h_shift, 0); - put_symbol(c, state, f->chroma_v_shift, 0); - put_rac(c, state, f->transparency); - put_symbol(c, state, f->num_h_slices - 1, 0); - put_symbol(c, state, f->num_v_slices - 1, 0); + put_symbol(&c, state, f->colorspace, 0); // YUV cs type + put_symbol(&c, state, f->bits_per_raw_sample, 0); + put_rac(&c, state, f->chroma_planes); + put_symbol(&c, state, f->chroma_h_shift, 0); + put_symbol(&c, state, f->chroma_v_shift, 0); + put_rac(&c, state, f->transparency); + put_symbol(&c, state, f->num_h_slices - 1, 0); + put_symbol(&c, state, f->num_v_slices - 1, 0); - put_symbol(c, state, f->quant_table_count, 0); + put_symbol(&c, state, f->quant_table_count, 0); for (i = 0; i < f->quant_table_count; i++) - write_quant_tables(c, f->quant_tables[i]); + write_quant_tables(&c, f->quant_tables[i]); for (i = 0; i < f->quant_table_count; i++) { if (contains_non_128(f->initial_states[i], f->context_count[i])) { - put_rac(c, state, 1); + put_rac(&c, state, 1); for (j = 0; j < f->context_count[i]; j++) for (k = 0; k < CONTEXT_SIZE; k++) { int pred = j ? f->initial_states[i][j - 1][k] : 128; - put_symbol(c, state2[k], + put_symbol(&c, state2[k], (int8_t)(f->initial_states[i][j][k] - pred), 1); } } else { - put_rac(c, state, 0); + put_rac(&c, state, 0); } } if (f->version > 2) { - put_symbol(c, state, f->ec, 0); - put_symbol(c, state, f->intra = (f->avctx->gop_size < 2), 0); + put_symbol(&c, state, f->ec, 0); + put_symbol(&c, state, f->intra = (f->avctx->gop_size < 2), 0); } - f->avctx->extradata_size = ff_rac_terminate(c, 0); + 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); AV_WL32(f->avctx->extradata + f->avctx->extradata_size, v); f->avctx->extradata_size += 4; @@ -526,6 +528,11 @@ static av_cold int encode_init(AVCodecContext *avctx) avctx->slices > 1) s->version = FFMAX(s->version, 2); + if ((avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) && s->ac == AC_GOLOMB_RICE) { + av_log(avctx, AV_LOG_ERROR, "2 Pass mode is not possible with golomb coding\n"); + return AVERROR(EINVAL); + } + // Unspecified level & slices, we choose version 1.2+ to ensure multithreaded decodability if (avctx->slices == 0 && avctx->level < 0 && avctx->width * avctx->height > 720*576) s->version = FFMAX(s->version, 2); @@ -550,7 +557,7 @@ static av_cold int encode_init(AVCodecContext *avctx) s->version = FFMAX(s->version, 3); if ((s->version == 2 || s->version>3) && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - av_log(avctx, AV_LOG_ERROR, "Version 2 needed for requested features but version 2 is experimental and not enabled\n"); + 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; } @@ -711,7 +718,7 @@ static av_cold int encode_init(AVCodecContext *avctx) s->state_transition[i] = c.one_state[i]; } - for (i = 0; i < 256; i++) { + for (i = 0; i < MAX_QUANT_TABLE_SIZE; i++) { s->quant_table_count = 2; if (s->bits_per_raw_sample <= 8) { s->quant_tables[0][0][i]= quant11[i]; @@ -722,29 +729,21 @@ static av_cold int encode_init(AVCodecContext *avctx) s->quant_tables[1][2][i]= 11*11*quant5 [i]; s->quant_tables[1][3][i]= 5*11*11*quant5 [i]; s->quant_tables[1][4][i]= 5*5*11*11*quant5 [i]; + s->context_count[0] = (11 * 11 * 11 + 1) / 2; + s->context_count[1] = (11 * 11 * 5 * 5 * 5 + 1) / 2; } else { s->quant_tables[0][0][i]= quant9_10bit[i]; - s->quant_tables[0][1][i]= 11*quant9_10bit[i]; - s->quant_tables[0][2][i]= 11*11*quant9_10bit[i]; + s->quant_tables[0][1][i]= 9*quant9_10bit[i]; + s->quant_tables[0][2][i]= 9*9*quant9_10bit[i]; s->quant_tables[1][0][i]= quant9_10bit[i]; - s->quant_tables[1][1][i]= 11*quant9_10bit[i]; - s->quant_tables[1][2][i]= 11*11*quant5_10bit[i]; - s->quant_tables[1][3][i]= 5*11*11*quant5_10bit[i]; - s->quant_tables[1][4][i]= 5*5*11*11*quant5_10bit[i]; + s->quant_tables[1][1][i]= 9*quant9_10bit[i]; + s->quant_tables[1][2][i]= 9*9*quant5_10bit[i]; + s->quant_tables[1][3][i]= 5*9*9*quant5_10bit[i]; + s->quant_tables[1][4][i]= 5*5*9*9*quant5_10bit[i]; + s->context_count[0] = (9 * 9 * 9 + 1) / 2; + s->context_count[1] = (9 * 9 * 5 * 5 * 5 + 1) / 2; } } - s->context_count[0] = (11 * 11 * 11 + 1) / 2; - s->context_count[1] = (11 * 11 * 5 * 5 * 5 + 1) / 2; - memcpy(s->quant_table, s->quant_tables[s->context_model], - sizeof(s->quant_table)); - - for (i = 0; i < s->plane_count; i++) { - PlaneContext *const p = &s->plane[i]; - - memcpy(p->quant_table, s->quant_table, sizeof(p->quant_table)); - p->quant_table_index = s->context_model; - p->context_count = s->context_count[p->quant_table_index]; - } if ((ret = ff_ffv1_allocate_initial_states(s)) < 0) return ret; @@ -866,6 +865,10 @@ static av_cold int encode_init(AVCodecContext *avctx) 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; } @@ -883,6 +886,18 @@ slices_ok: if ((ret = ff_ffv1_init_slice_contexts(s)) < 0) return ret; s->slice_count = s->max_slice_count; + + for (int j = 0; j < s->slice_count; 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]; + } + + ff_build_rac_states(&s->slices[j].c, 0.05 * (1LL << 32), 256 - 8); + } + if ((ret = ff_ffv1_init_slices_state(s)) < 0) return ret; @@ -893,11 +908,11 @@ slices_ok: return AVERROR(ENOMEM); for (i = 0; i < s->quant_table_count; i++) for (j = 0; j < s->max_slice_count; j++) { - FFV1Context *sf = s->slice_context[j]; - av_assert0(!sf->rc_stat2[i]); - sf->rc_stat2[i] = av_mallocz(s->context_count[i] * - sizeof(*sf->rc_stat2[i])); - if (!sf->rc_stat2[i]) + FFV1SliceContext *sc = &s->slices[j]; + av_assert0(!sc->rc_stat2[i]); + sc->rc_stat2[i] = av_mallocz(s->context_count[i] * + sizeof(*sc->rc_stat2[i])); + if (!sc->rc_stat2[i]) return AVERROR(ENOMEM); } } @@ -905,20 +920,20 @@ slices_ok: return 0; } -static void encode_slice_header(FFV1Context *f, FFV1Context *fs) +static void encode_slice_header(FFV1Context *f, FFV1SliceContext *sc) { - RangeCoder *c = &fs->c; + RangeCoder *c = &sc->c; uint8_t state[CONTEXT_SIZE]; int j; memset(state, 128, sizeof(state)); - put_symbol(c, state, (fs->slice_x +1)*f->num_h_slices / f->width , 0); - put_symbol(c, state, (fs->slice_y +1)*f->num_v_slices / f->height , 0); - put_symbol(c, state, (fs->slice_width +1)*f->num_h_slices / f->width -1, 0); - put_symbol(c, state, (fs->slice_height+1)*f->num_v_slices / f->height-1, 0); + put_symbol(c, state, sc->sx, 0); + put_symbol(c, state, sc->sy, 0); + put_symbol(c, state, 0, 0); + put_symbol(c, state, 0, 0); for (j=0; jplane_count; j++) { - put_symbol(c, state, f->plane[j].quant_table_index, 0); - av_assert0(f->plane[j].quant_table_index == f->context_model); + put_symbol(c, state, sc->plane[j].quant_table_index, 0); + av_assert0(sc->plane[j].quant_table_index == f->context_model); } if (!(f->cur_enc_frame->flags & AV_FRAME_FLAG_INTERLACED)) put_symbol(c, state, 3, 0); @@ -927,18 +942,19 @@ static void encode_slice_header(FFV1Context *f, FFV1Context *fs) put_symbol(c, state, f->cur_enc_frame->sample_aspect_ratio.num, 0); put_symbol(c, state, f->cur_enc_frame->sample_aspect_ratio.den, 0); if (f->version > 3) { - put_rac(c, state, fs->slice_coding_mode == 1); - if (fs->slice_coding_mode == 1) - ff_ffv1_clear_slice_state(f, fs); - put_symbol(c, state, fs->slice_coding_mode, 0); - if (fs->slice_coding_mode != 1) { - put_symbol(c, state, fs->slice_rct_by_coef, 0); - put_symbol(c, state, fs->slice_rct_ry_coef, 0); + put_rac(c, state, sc->slice_coding_mode == 1); + if (sc->slice_coding_mode == 1) + ff_ffv1_clear_slice_state(f, sc); + put_symbol(c, state, sc->slice_coding_mode, 0); + if (sc->slice_coding_mode != 1 && f->colorspace == 1) { + put_symbol(c, state, sc->slice_rct_by_coef, 0); + put_symbol(c, state, sc->slice_rct_ry_coef, 0); } } } -static void choose_rct_params(FFV1Context *fs, const uint8_t *src[3], const int stride[3], int w, int h) +static void choose_rct_params(const FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src[3], const int stride[3], int w, int h) { #define NB_Y_COEFF 15 static const int rct_y_coeff[15][2] = { @@ -963,12 +979,15 @@ static void choose_rct_params(FFV1Context *fs, const uint8_t *src[3], const int int stat[NB_Y_COEFF] = {0}; int x, y, i, p, best; int16_t *sample[3]; - int lbd = fs->bits_per_raw_sample <= 8; + int lbd = f->bits_per_raw_sample <= 8; + int packed = !src[1]; + int transparency = f->transparency; + int packed_size = (3 + transparency)*2; for (y = 0; y < h; y++) { int lastr=0, lastg=0, lastb=0; for (p = 0; p < 3; p++) - sample[p] = fs->sample_buffer + p*w; + sample[p] = sc->sample_buffer + p*w; for (x = 0; x < w; x++) { int b, g, r; @@ -978,6 +997,15 @@ static void choose_rct_params(FFV1Context *fs, const uint8_t *src[3], const int b = v & 0xFF; g = (v >> 8) & 0xFF; r = (v >> 16) & 0xFF; + } else if (packed) { + const uint16_t *p = ((const uint16_t*)(src[0] + x*packed_size + stride[0]*y)); + r = p[0]; + g = p[1]; + b = p[2]; + } else if (f->use32bit || 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)); } else { b = *((const uint16_t*)(src[0] + x*2 + stride[0]*y)); g = *((const uint16_t*)(src[1] + x*2 + stride[1]*y)); @@ -1016,46 +1044,46 @@ static void choose_rct_params(FFV1Context *fs, const uint8_t *src[3], const int best = i; } - fs->slice_rct_by_coef = rct_y_coeff[best][1]; - fs->slice_rct_ry_coef = rct_y_coeff[best][0]; + sc->slice_rct_by_coef = rct_y_coeff[best][1]; + sc->slice_rct_ry_coef = rct_y_coeff[best][0]; } static int encode_slice(AVCodecContext *c, void *arg) { - FFV1Context *fs = *(void **)arg; - FFV1Context *f = fs->avctx->priv_data; - int width = fs->slice_width; - int height = fs->slice_height; - int x = fs->slice_x; - int y = fs->slice_y; + FFV1SliceContext *sc = arg; + FFV1Context *f = c->priv_data; + int width = sc->slice_width; + int height = sc->slice_height; + int x = sc->slice_x; + int y = sc->slice_y; const AVFrame *const p = f->cur_enc_frame; const int ps = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step; int ret; - RangeCoder c_bak = fs->c; + RangeCoder c_bak = sc->c; 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}; - fs->slice_coding_mode = 0; - if (f->version > 3) { - choose_rct_params(fs, planes, p->linesize, width, height); + sc->slice_coding_mode = 0; + if (f->version > 3 && f->colorspace == 1) { + choose_rct_params(f, sc, planes, p->linesize, width, height); } else { - fs->slice_rct_by_coef = 1; - fs->slice_rct_ry_coef = 1; + sc->slice_rct_by_coef = 1; + sc->slice_rct_ry_coef = 1; } retry: if (f->key_frame) - ff_ffv1_clear_slice_state(f, fs); + ff_ffv1_clear_slice_state(f, sc); if (f->version > 2) { - encode_slice_header(f, fs); + encode_slice_header(f, sc); } - if (fs->ac == AC_GOLOMB_RICE) { - fs->ac_byte_count = f->version > 2 || (!x && !y) ? ff_rac_terminate(&fs->c, f->version > 2) : 0; - init_put_bits(&fs->pb, - fs->c.bytestream_start + fs->ac_byte_count, - fs->c.bytestream_end - fs->c.bytestream_start - fs->ac_byte_count); + if (f->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) { @@ -1064,32 +1092,39 @@ retry: const int cx = x >> f->chroma_h_shift; const int cy = y >> f->chroma_v_shift; - ret = encode_plane(fs, 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, 1); if (f->chroma_planes) { - ret |= encode_plane(fs, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1); - ret |= encode_plane(fs, 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); + ret |= encode_plane(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1); } - if (fs->transparency) - ret |= encode_plane(fs, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2, 1); + 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(fs, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 2); - ret |= encode_plane(fs, p->data[0] + 1 + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 2); + 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); } else if (f->use32bit) { - ret = encode_rgb_frame32(fs, planes, width, height, p->linesize); + ret = encode_rgb_frame32(f, sc, planes, width, height, p->linesize); } else { - ret = encode_rgb_frame(fs, planes, width, height, p->linesize); + ret = encode_rgb_frame(f, sc, planes, width, height, p->linesize); + } + + if (f->ac != AC_GOLOMB_RICE) { + sc->ac_byte_count = ff_rac_terminate(&sc->c, 1); + } else { + flush_put_bits(&sc->pb); // FIXME: nicer padding + sc->ac_byte_count += put_bytes_output(&sc->pb); } if (ret < 0) { - av_assert0(fs->slice_coding_mode == 0); - if (fs->version < 4 || !fs->ac) { + av_assert0(sc->slice_coding_mode == 0); + if (f->version < 4 || !f->ac) { av_log(c, AV_LOG_ERROR, "Buffer too small\n"); return ret; } av_log(c, AV_LOG_DEBUG, "Coding slice as PCM\n"); - fs->slice_coding_mode = 1; - fs->c = c_bak; + sc->slice_coding_mode = 1; + sc->c = c_bak; goto retry; } @@ -1100,7 +1135,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { FFV1Context *f = avctx->priv_data; - RangeCoder *const c = &f->slice_context[0]->c; + RangeCoder *const c = &f->slices[0].c; uint8_t keystate = 128; uint8_t *buf_p; int i, ret; @@ -1119,16 +1154,16 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, av_assert0(f->slice_count == f->max_slice_count); for (j = 0; j < f->slice_count; j++) { - FFV1Context *fs = f->slice_context[j]; + const FFV1SliceContext *sc = &f->slices[j]; for (i = 0; i < 256; i++) { - f->rc_stat[i][0] += fs->rc_stat[i][0]; - f->rc_stat[i][1] += fs->rc_stat[i][1]; + f->rc_stat[i][0] += sc->rc_stat[i][0]; + f->rc_stat[i][1] += sc->rc_stat[i][1]; } for (i = 0; i < f->quant_table_count; i++) { for (k = 0; k < f->context_count[i]; k++) for (m = 0; m < 32; m++) { - f->rc_stat2[i][k][m][0] += fs->rc_stat2[i][k][m][0]; - f->rc_stat2[i][k][m][1] += fs->rc_stat2[i][k][m][1]; + f->rc_stat2[i][k][m][0] += sc->rc_stat2[i][k][m][0]; + f->rc_stat2[i][k][m][1] += sc->rc_stat2[i][k][m][1]; } } } @@ -1188,34 +1223,27 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, } for (i = 0; i < f->slice_count; i++) { - FFV1Context *fs = f->slice_context[i]; + FFV1SliceContext *sc = &f->slices[i]; uint8_t *start = pkt->data + pkt->size * (int64_t)i / f->slice_count; int len = pkt->size / f->slice_count; if (i) { - ff_init_range_encoder(&fs->c, start, len); + ff_init_range_encoder(&sc->c, start, len); } else { - av_assert0(fs->c.bytestream_end >= fs->c.bytestream_start + len); - av_assert0(fs->c.bytestream < fs->c.bytestream_start + len); - fs->c.bytestream_end = fs->c.bytestream_start + len; + av_assert0(sc->c.bytestream_end >= sc->c.bytestream_start + len); + av_assert0(sc->c.bytestream < sc->c.bytestream_start + len); + sc->c.bytestream_end = sc->c.bytestream_start + len; } } - avctx->execute(avctx, encode_slice, &f->slice_context[0], NULL, - f->slice_count, sizeof(void *)); + avctx->execute(avctx, encode_slice, f->slices, NULL, + f->slice_count, sizeof(*f->slices)); buf_p = pkt->data; for (i = 0; i < f->slice_count; i++) { - FFV1Context *fs = f->slice_context[i]; - int bytes; - - if (fs->ac != AC_GOLOMB_RICE) { - bytes = ff_rac_terminate(&fs->c, 1); - } else { - flush_put_bits(&fs->pb); // FIXME: nicer padding - bytes = fs->ac_byte_count + put_bytes_output(&fs->pb); - } + FFV1SliceContext *sc = &f->slices[i]; + int bytes = sc->ac_byte_count; if (i > 0 || f->version > 2) { av_assert0(bytes < pkt->size / f->slice_count); - memmove(buf_p, fs->c.bytestream_start, bytes); + memmove(buf_p, sc->c.bytestream_start, bytes); av_assert0(bytes < (1 << 24)); AV_WB24(buf_p + bytes, bytes); bytes += 3; @@ -1304,6 +1332,7 @@ const FFCodec ff_ffv1_encoder = { AV_PIX_FMT_NONE }, + .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_template.c b/libavcodec/ffv1enc_template.c index 8953dbe07..bc14926ab 100644 --- a/libavcodec/ffv1enc_template.c +++ b/libavcodec/ffv1enc_template.c @@ -22,30 +22,32 @@ #include "ffv1_template.c" -static av_always_inline int RENAME(encode_line)(FFV1Context *s, int w, - TYPE *sample[3], - int plane_index, int bits) +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 ac, int pass1) { - PlaneContext *const p = &s->plane[plane_index]; - RangeCoder *const c = &s->c; + PlaneContext *const p = &sc->plane[plane_index]; + RangeCoder *const c = &sc->c; int x; - int run_index = s->run_index; + int run_index = sc->run_index; int run_count = 0; int run_mode = 0; - if (s->ac != AC_GOLOMB_RICE) { + if (ac != AC_GOLOMB_RICE) { if (c->bytestream_end - c->bytestream < w * 35) { - av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); + av_log(logctx, AV_LOG_ERROR, "encoded frame too large\n"); return AVERROR_INVALIDDATA; } } else { - if (put_bytes_left(&s->pb, 0) < w * 4) { - av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); + if (put_bytes_left(&sc->pb, 0) < w * 4) { + av_log(logctx, AV_LOG_ERROR, "encoded frame too large\n"); return AVERROR_INVALIDDATA; } } - if (s->slice_coding_mode == 1) { + if (sc->slice_coding_mode == 1) { for (x = 0; x < w; x++) { int i; int v = sample[0][x]; @@ -60,7 +62,8 @@ static av_always_inline int RENAME(encode_line)(FFV1Context *s, int w, for (x = 0; x < w; x++) { int diff, context; - context = RENAME(get_context)(p, sample[0] + x, sample[1] + x, sample[2] + x); + context = RENAME(get_context)(f->quant_tables[p->quant_table_index], + sample[0] + x, sample[1] + x, sample[2] + x); diff = sample[0][x] - RENAME(predict)(sample[0] + x, sample[1] + x); if (context < 0) { @@ -70,10 +73,10 @@ static av_always_inline int RENAME(encode_line)(FFV1Context *s, int w, diff = fold(diff, bits); - if (s->ac != AC_GOLOMB_RICE) { - if (s->flags & AV_CODEC_FLAG_PASS1) { - put_symbol_inline(c, p->state[context], diff, 1, s->rc_stat, - s->rc_stat2[p->quant_table_index][context]); + if (ac != AC_GOLOMB_RICE) { + if (pass1) { + put_symbol_inline(c, p->state[context], diff, 1, sc->rc_stat, + sc->rc_stat2[p->quant_table_index][context]); } else { put_symbol_inline(c, p->state[context], diff, 1, NULL, NULL); } @@ -86,10 +89,10 @@ static av_always_inline int RENAME(encode_line)(FFV1Context *s, int w, while (run_count >= 1 << ff_log2_run[run_index]) { run_count -= 1 << ff_log2_run[run_index]; run_index++; - put_bits(&s->pb, 1, 1); + put_bits(&sc->pb, 1, 1); } - put_bits(&s->pb, 1 + ff_log2_run[run_index], run_count); + put_bits(&sc->pb, 1 + ff_log2_run[run_index], run_count); if (run_index) run_index--; run_count = 0; @@ -101,51 +104,54 @@ static av_always_inline int RENAME(encode_line)(FFV1Context *s, int w, } } - ff_dlog(s->avctx, "count:%d index:%d, mode:%d, x:%d pos:%d\n", + ff_dlog(logctx, "count:%d index:%d, mode:%d, x:%d pos:%d\n", run_count, run_index, run_mode, x, - (int)put_bits_count(&s->pb)); + (int)put_bits_count(&sc->pb)); if (run_mode == 0) - put_vlc_symbol(&s->pb, &p->vlc_state[context], diff, bits); + put_vlc_symbol(&sc->pb, &p->vlc_state[context], diff, bits); } } if (run_mode) { while (run_count >= 1 << ff_log2_run[run_index]) { run_count -= 1 << ff_log2_run[run_index]; run_index++; - put_bits(&s->pb, 1, 1); + put_bits(&sc->pb, 1, 1); } if (run_count) - put_bits(&s->pb, 1, 1); + put_bits(&sc->pb, 1, 1); } - s->run_index = run_index; + sc->run_index = run_index; return 0; } -static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[4], +static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src[4], int w, int h, const int stride[4]) { int x, y, p, i; - const int ring_size = s->context_model ? 3 : 2; + const int ring_size = f->context_model ? 3 : 2; TYPE *sample[4][3]; - int lbd = s->bits_per_raw_sample <= 8; + 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 = s->bits_per_raw_sample > 0 ? s->bits_per_raw_sample : 8; + int bits = f->bits_per_raw_sample > 0 ? f->bits_per_raw_sample : 8; int offset = 1 << bits; - int transparency = s->transparency; + int transparency = f->transparency; int packed_size = (3 + transparency)*2; - s->run_index = 0; + sc->run_index = 0; - memset(RENAME(s->sample_buffer), 0, ring_size * MAX_PLANES * - (w + 6) * sizeof(*RENAME(s->sample_buffer))); + 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(s->sample_buffer) + p*ring_size*(w+6) + ((h+i-y)%ring_size)*(w+6) + 3; + 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); @@ -174,10 +180,10 @@ static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[4], r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); } - if (s->slice_coding_mode != 1) { + if (sc->slice_coding_mode != 1) { b -= g; r -= g; - g += (b * s->slice_rct_by_coef + r * s->slice_rct_ry_coef) >> 2; + g += (b * sc->slice_rct_by_coef + r * sc->slice_rct_ry_coef) >> 2; b += offset; r += offset; } @@ -191,10 +197,11 @@ static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[4], int ret; sample[p][0][-1] = sample[p][1][0 ]; sample[p][1][ w] = sample[p][1][w-1]; - if (lbd && s->slice_coding_mode == 0) - ret = RENAME(encode_line)(s, w, sample[p], (p + 1) / 2, 9); + if (lbd && sc->slice_coding_mode == 0) + ret = RENAME(encode_line)(f, sc, f->avctx, w, sample[p], (p + 1) / 2, 9, ac, pass1); else - ret = RENAME(encode_line)(s, w, sample[p], (p + 1) / 2, bits + (s->slice_coding_mode != 1)); + ret = RENAME(encode_line)(f, sc, f->avctx, w, sample[p], (p + 1) / 2, + bits + (sc->slice_coding_mode != 1), ac, pass1); if (ret < 0) return ret; } diff --git a/libavcodec/ffwavesynth.c b/libavcodec/ffwavesynth.c index b932326fd..022cb50cd 100644 --- a/libavcodec/ffwavesynth.c +++ b/libavcodec/ffwavesynth.c @@ -21,6 +21,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/fic.c b/libavcodec/fic.c index fb9980213..ec26e3154 100644 --- a/libavcodec/fic.c +++ b/libavcodec/fic.c @@ -22,6 +22,7 @@ */ #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "avcodec.h" diff --git a/libavcodec/fitsdec.c b/libavcodec/fitsdec.c index 284e945ba..56df3e4d6 100644 --- a/libavcodec/fitsdec.c +++ b/libavcodec/fitsdec.c @@ -301,9 +301,6 @@ static int fits_decode_frame(AVCodecContext *avctx, AVFrame *p, } } - p->flags |= AV_FRAME_FLAG_KEY; - p->pict_type = AV_PICTURE_TYPE_I; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/flac_parser.c b/libavcodec/flac_parser.c index 99460e7ea..d9c47801f 100644 --- a/libavcodec/flac_parser.c +++ b/libavcodec/flac_parser.c @@ -34,8 +34,7 @@ #include "libavutil/attributes.h" #include "libavutil/crc.h" -#include "bytestream.h" -#include "parser.h" +#include "libavutil/mem.h" #include "flac_parse.h" /** maximum number of adjacent headers that compare CRCs against each other */ diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c index ed2de14d0..ad921a1bd 100644 --- a/libavcodec/flacdec.c +++ b/libavcodec/flacdec.c @@ -35,14 +35,13 @@ #include "libavutil/avassert.h" #include "libavutil/crc.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "codec_internal.h" #include "get_bits.h" -#include "bytestream.h" #include "golomb.h" #include "flac.h" -#include "flacdata.h" #include "flacdsp.h" #include "flac_parse.h" #include "thread.h" @@ -482,7 +481,7 @@ static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order, static int decode_subframe_lpc_33bps(FLACContext *s, int64_t *decoded, int32_t *residual, int pred_order) { - int i, j, ret; + int i, ret; int coeff_prec, qlevel; int coeffs[32]; @@ -510,12 +509,7 @@ static int decode_subframe_lpc_33bps(FLACContext *s, int64_t *decoded, if ((ret = decode_residuals(s, residual, pred_order)) < 0) return ret; - for (i = pred_order; i < s->blocksize; i++, decoded++) { - 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); - } + s->dsp.lpc33(decoded, residual, coeffs, pred_order, qlevel, s->blocksize); return 0; } @@ -603,13 +597,9 @@ static inline int decode_subframe(FLACContext *s, int channel) if (wasted) { if (wasted+bps == 33) { - int i; - for (i = 0; i < s->blocksize; i++) - s->decoded_33bps[i] = (uint64_t)decoded[i] << wasted; + s->dsp.wasted33(s->decoded_33bps, decoded, wasted, s->blocksize); } else if (wasted < 32) { - int i; - for (i = 0; i < s->blocksize; i++) - decoded[i] = (unsigned)decoded[i] << wasted; + s->dsp.wasted32(decoded, wasted, s->blocksize); } } diff --git a/libavcodec/flacdsp.c b/libavcodec/flacdsp.c index 71b4ac44a..f5362bf66 100644 --- a/libavcodec/flacdsp.c +++ b/libavcodec/flacdsp.c @@ -84,10 +84,41 @@ static void flac_lpc_32_c(int32_t *decoded, const int coeffs[32], } +static void flac_lpc_33_c(int64_t *decoded, const int32_t *residual, + const int coeffs[32], int pred_order, + int qlevel, int len) +{ + int i, j; + + for (i = pred_order; i < len; i++, decoded++) { + 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); + } +} + +static void flac_wasted_32_c(int32_t *decoded, int wasted, int len) +{ + for (int i = 0; i < len; i++) + decoded[i] = (unsigned)decoded[i] << wasted; +} + +static void flac_wasted_33_c(int64_t *decoded, const int32_t *residual, + int wasted, int len) +{ + for (int i = 0; i < len; i++) + decoded[i] = (uint64_t)residual[i] << wasted; +} + av_cold void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt, int channels) { c->lpc16 = flac_lpc_16_c; c->lpc32 = flac_lpc_32_c; + c->lpc33 = flac_lpc_33_c; + + c->wasted32 = flac_wasted_32_c; + c->wasted33 = flac_wasted_33_c; switch (fmt) { case AV_SAMPLE_FMT_S32: diff --git a/libavcodec/flacdsp.h b/libavcodec/flacdsp.h index 15149c026..3b7b35a11 100644 --- a/libavcodec/flacdsp.h +++ b/libavcodec/flacdsp.h @@ -30,6 +30,11 @@ typedef struct FLACDSPContext { int qlevel, int len); void (*lpc32)(int32_t *samples, const int coeffs[32], int order, int qlevel, int len); + void (*lpc33)(int64_t *samples, const int32_t *residual, const int coeffs[32], + int pred_order, int qlevel, int len); + 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, diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c index 3dc4dc2e4..3a9578f5c 100644 --- a/libavcodec/flacenc.c +++ b/libavcodec/flacenc.c @@ -24,6 +24,7 @@ #include "libavutil/crc.h" #include "libavutil/intmath.h" #include "libavutil/md5.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" @@ -524,11 +525,10 @@ static void copy_samples(FlacEncodeContext *s, const void *samples) { int i, j, ch; FlacFrame *frame; - int shift = av_get_bytes_per_sample(s->avctx->sample_fmt) * 8 - - s->avctx->bits_per_raw_sample; -#define COPY_SAMPLES(bits) do { \ +#define COPY_SAMPLES(bits, shift0) do { \ const int ## bits ## _t *samples0 = samples; \ + const int shift = shift0; \ frame = &s->frame; \ for (i = 0, j = 0; i < frame->blocksize; i++) \ for (ch = 0; ch < s->channels; ch++, j++) \ @@ -536,9 +536,9 @@ static void copy_samples(FlacEncodeContext *s, const void *samples) } while (0) if (s->avctx->sample_fmt == AV_SAMPLE_FMT_S16) - COPY_SAMPLES(16); + COPY_SAMPLES(16, 0); else - COPY_SAMPLES(32); + COPY_SAMPLES(32, 32 - s->avctx->bits_per_raw_sample); } diff --git a/libavcodec/flashsv.c b/libavcodec/flashsv.c index fe00e529a..d27918c92 100644 --- a/libavcodec/flashsv.c +++ b/libavcodec/flashsv.c @@ -39,6 +39,7 @@ #include #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/flashsv2enc.c b/libavcodec/flashsv2enc.c index 6dcb9102a..6156d00d0 100644 --- a/libavcodec/flashsv2enc.c +++ b/libavcodec/flashsv2enc.c @@ -47,11 +47,11 @@ #include #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" #include "put_bits.h" -#include "bytestream.h" #include "zlib_wrapper.h" #define HAS_IFRAME_IMAGE 0x02 diff --git a/libavcodec/flvdec.c b/libavcodec/flvdec.c index 8baaed06a..f4bfd9941 100644 --- a/libavcodec/flvdec.c +++ b/libavcodec/flvdec.c @@ -24,7 +24,7 @@ #include "flvdec.h" #include "h263dec.h" #include "mpegvideo.h" -#include "mpegvideodata.h" +#include "mpegvideodec.h" int ff_flv_decode_picture_header(MpegEncContext *s) { @@ -118,9 +118,10 @@ const FFCodec ff_flv_decoder = { .p.id = AV_CODEC_ID_FLV1, .priv_data_size = sizeof(MpegEncContext), .init = ff_h263_decode_init, - .close = ff_h263_decode_end, FF_CODEC_DECODE_CB(ff_h263_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .p.max_lowres = 3, }; diff --git a/libavcodec/flvenc.c b/libavcodec/flvenc.c index 6a96cb0f2..40eec07b3 100644 --- a/libavcodec/flvenc.c +++ b/libavcodec/flvenc.c @@ -105,5 +105,6 @@ const FFCodec ff_flv_encoder = { .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}, + .color_ranges = AVCOL_RANGE_MPEG, .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; diff --git a/libavcodec/fmvc.c b/libavcodec/fmvc.c index a9e5afd17..b51b18a9e 100644 --- a/libavcodec/fmvc.c +++ b/libavcodec/fmvc.c @@ -23,6 +23,7 @@ #include #include +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/frame_thread_encoder.c b/libavcodec/frame_thread_encoder.c index cda515811..6af3db722 100644 --- a/libavcodec/frame_thread_encoder.c +++ b/libavcodec/frame_thread_encoder.c @@ -24,10 +24,12 @@ #include "libavutil/avassert.h" #include "libavutil/cpu.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/thread.h" #include "avcodec.h" #include "avcodec_internal.h" +#include "codec_par.h" #include "encode.h" #include "internal.h" #include "pthread_internal.h" @@ -111,8 +113,7 @@ static void * attribute_align_arg worker(void *v){ pthread_mutex_unlock(&c->finished_task_mutex); } end: - ff_codec_close(avctx); - av_freep(&avctx); + avcodec_free_context(&avctx); return NULL; } @@ -121,6 +122,7 @@ av_cold int ff_frame_thread_encoder_init(AVCodecContext *avctx) int i=0; ThreadContext *c; AVCodecContext *thread_avctx = NULL; + AVCodecParameters *par = NULL; int ret; if( !(avctx->thread_type & FF_THREAD_FRAME) @@ -194,18 +196,27 @@ av_cold int ff_frame_thread_encoder_init(AVCodecContext *avctx) } } + par = avcodec_parameters_alloc(); + if (!par) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = avcodec_parameters_from_context(par, avctx); + if (ret < 0) + goto fail; + for(i=0; ithread_count ; i++){ - void *tmpv; thread_avctx = avcodec_alloc_context3(avctx->codec); if (!thread_avctx) { ret = AVERROR(ENOMEM); goto fail; } - tmpv = thread_avctx->priv_data; - *thread_avctx = *avctx; - thread_avctx->priv_data = tmpv; - thread_avctx->internal = NULL; - thread_avctx->hw_frames_ctx = NULL; + + ret = avcodec_parameters_to_context(thread_avctx, par); + if (ret < 0) + goto fail; + ret = av_opt_copy(thread_avctx, avctx); if (ret < 0) goto fail; @@ -217,6 +228,26 @@ av_cold int ff_frame_thread_encoder_init(AVCodecContext *avctx) thread_avctx->thread_count = 1; thread_avctx->active_thread_type &= ~FF_THREAD_FRAME; +#define DUP_MATRIX(m) \ + if (avctx->m) { \ + thread_avctx->m = av_memdup(avctx->m, 64 * sizeof(*avctx->m)); \ + if (!thread_avctx->m) { \ + ret = AVERROR(ENOMEM); \ + goto fail; \ + } \ + } + DUP_MATRIX(intra_matrix); + DUP_MATRIX(chroma_intra_matrix); + DUP_MATRIX(inter_matrix); + +#undef DUP_MATRIX + + thread_avctx->opaque = avctx->opaque; + thread_avctx->get_encode_buffer = avctx->get_encode_buffer; + thread_avctx->execute = avctx->execute; + thread_avctx->execute2 = avctx->execute2; + thread_avctx->stats_in = avctx->stats_in; + if ((ret = avcodec_open2(thread_avctx, avctx->codec, NULL)) < 0) goto fail; av_assert0(!thread_avctx->internal->frame_thread_encoder); @@ -227,12 +258,14 @@ av_cold int ff_frame_thread_encoder_init(AVCodecContext *avctx) } } + avcodec_parameters_free(&par); + avctx->active_thread_type = FF_THREAD_FRAME; return 0; fail: - ff_codec_close(thread_avctx); - av_freep(&thread_avctx); + avcodec_parameters_free(&par); + avcodec_free_context(&thread_avctx); avctx->thread_count = i; av_log(avctx, AV_LOG_ERROR, "ff_frame_thread_encoder_init failed\n"); ff_frame_thread_encoder_free(avctx); diff --git a/libavcodec/fraps.c b/libavcodec/fraps.c index bed244e4e..d7b713c7c 100644 --- a/libavcodec/fraps.c +++ b/libavcodec/fraps.c @@ -35,6 +35,7 @@ #define CACHED_BITSTREAM_READER HAVE_FAST_64BIT #define UNCHECKED_BITSTREAM_READER 1 +#include "libavutil/mem.h" #include "avcodec.h" #include "get_bits.h" #include "huffman.h" @@ -214,9 +215,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *f, } } - f->pict_type = AV_PICTURE_TYPE_I; - f->flags |= AV_FRAME_FLAG_KEY; - avctx->pix_fmt = version & 1 ? is_pal ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUVJ420P; avctx->color_range = version & 1 ? AVCOL_RANGE_UNSPECIFIED : AVCOL_RANGE_JPEG; diff --git a/libavcodec/frwu.c b/libavcodec/frwu.c index 70bc13676..3b52b968f 100644 --- a/libavcodec/frwu.c +++ b/libavcodec/frwu.c @@ -62,9 +62,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->pict_type = AV_PICTURE_TYPE_I; - pic->flags |= AV_FRAME_FLAG_KEY; - for (field = 0; field < 2; field++) { int i; int field_h = (avctx->height + !field) >> 1; diff --git a/libavcodec/ftr_parser.c b/libavcodec/ftr_parser.c index 05e6cfed9..656fd289f 100644 --- a/libavcodec/ftr_parser.c +++ b/libavcodec/ftr_parser.c @@ -25,7 +25,6 @@ */ #include "parser.h" -#include "get_bits.h" #include "adts_header.h" #include "adts_parser.h" #include "mpeg4audio.h" @@ -45,7 +44,6 @@ static int ftr_parse(AVCodecParserContext *s, AVCodecContext *avctx, FTRParseContext *ftr = s->priv_data; uint64_t state = ftr->pc.state64; int next = END_NOT_FOUND; - GetBitContext bits; AACADTSHeaderInfo hdr; int size; @@ -71,10 +69,9 @@ static int ftr_parse(AVCodecParserContext *s, AVCodecContext *avctx, state = (state << 8) | buf[i]; AV_WB64(tmp, state); - init_get_bits(&bits, tmp + 8 - AV_AAC_ADTS_HEADER_SIZE, - AV_AAC_ADTS_HEADER_SIZE * 8); + size = ff_adts_header_parse_buf(tmp + 8 - AV_AAC_ADTS_HEADER_SIZE, &hdr); - if ((size = ff_adts_header_parse(&bits, &hdr)) > 0) { + if (size > 0) { ftr->skip = size - 6; ftr->frame_index += ff_mpeg4audio_channels[hdr.chan_config]; if (ftr->frame_index >= avctx->ch_layout.nb_channels) { diff --git a/libavcodec/g2meet.c b/libavcodec/g2meet.c index 34ff60a3c..f952a06f1 100644 --- a/libavcodec/g2meet.c +++ b/libavcodec/g2meet.c @@ -29,6 +29,7 @@ #include #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" @@ -1051,7 +1052,6 @@ static int kempf_decode_tile(G2MContext *c, int tile_x, int tile_y, { int width, height; int hdr, zsize, npal, tidx = -1, ret; - int i, j; const uint8_t *src_end = src + src_size; uint8_t pal[768], transp[3]; uLongf dlen = (c->tile_width + 1) * c->tile_height; @@ -1070,11 +1070,10 @@ static int kempf_decode_tile(G2MContext *c, int tile_x, int tile_y, hdr = *src++; sub_type = hdr >> 5; if (sub_type == 0) { - int j; memcpy(transp, src, 3); src += 3; - for (j = 0; j < height; j++, dst += c->framebuf_stride) - for (i = 0; i < width; i++) + for (int j = 0; j < height; j++, dst += c->framebuf_stride) + for (int i = 0; i < width; i++) memcpy(dst + i * 3, transp, 3); return 0; } else if (sub_type == 1) { @@ -1092,7 +1091,7 @@ static int kempf_decode_tile(G2MContext *c, int tile_x, int tile_y, memcpy(pal, src, npal * 3); src += npal * 3; if (sub_type != 2) { - for (i = 0; i < npal; i++) { + for (int i = 0; i < npal; i++) { if (!memcmp(pal + i * 3, transp, 3)) { tidx = i; break; @@ -1124,8 +1123,8 @@ static int kempf_decode_tile(G2MContext *c, int tile_x, int tile_y, bstride = FFALIGN(width, 16) >> 3; // blocks are coded LSB and we need normal bitreader for JPEG data bits = 0; - for (i = 0; i < (FFALIGN(height, 16) >> 4); i++) { - for (j = 0; j < (FFALIGN(width, 16) >> 4); j++) { + for (int i = 0; i < (FFALIGN(height, 16) >> 4); i++) { + for (int j = 0; j < (FFALIGN(width, 16) >> 4); j++) { if (!bits) { if (src >= src_end) return AVERROR_INVALIDDATA; diff --git a/libavcodec/g722enc.c b/libavcodec/g722enc.c index 2f19a1b29..19ab0f8b5 100644 --- a/libavcodec/g722enc.c +++ b/libavcodec/g722enc.c @@ -29,6 +29,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" diff --git a/libavcodec/g726.c b/libavcodec/g726.c index 6c5638760..e048cd973 100644 --- a/libavcodec/g726.c +++ b/libavcodec/g726.c @@ -302,7 +302,7 @@ static int16_t g726_encode(G726Context* c, int16_t sig) { uint8_t i; - i = av_mod_uintp2(quant(c, sig/4 - c->se), c->code_size); + i = av_zero_extend(quant(c, sig/4 - c->se), c->code_size); g726_decode(c, i); return i; } diff --git a/libavcodec/g729dec.c b/libavcodec/g729dec.c index 33e1fb9c2..bf10a6dd3 100644 --- a/libavcodec/g729dec.c +++ b/libavcodec/g729dec.c @@ -24,6 +24,7 @@ #include "avcodec.h" #include "libavutil/avutil.h" +#include "libavutil/mem.h" #include "get_bits.h" #include "audiodsp.h" #include "codec_internal.h" @@ -535,7 +536,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if (frame_erasure) { ctx->rand_value = g729_prng(ctx->rand_value); - fc_indexes = av_mod_uintp2(ctx->rand_value, format->fc_indexes_bits); + fc_indexes = av_zero_extend(ctx->rand_value, format->fc_indexes_bits); ctx->rand_value = g729_prng(ctx->rand_value); pulses_signs = ctx->rand_value; diff --git a/libavcodec/gdv.c b/libavcodec/gdv.c index e114f3e80..670597448 100644 --- a/libavcodec/gdv.c +++ b/libavcodec/gdv.c @@ -21,6 +21,7 @@ */ #include "libavutil/common.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/gemdec.c b/libavcodec/gemdec.c index 9e2a50c76..5ece2e2ee 100644 --- a/libavcodec/gemdec.c +++ b/libavcodec/gemdec.c @@ -24,6 +24,7 @@ * GEM Raster image decoder */ +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/get_buffer.c b/libavcodec/get_buffer.c index 9b35fde7c..7e705380f 100644 --- a/libavcodec/get_buffer.c +++ b/libavcodec/get_buffer.c @@ -65,20 +65,15 @@ static void frame_pool_free(FFRefStructOpaque unused, void *obj) static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) { FramePool *pool = avctx->internal->pool; - int i, ret, ch, planes; - - if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) { - int planar = av_sample_fmt_is_planar(frame->format); - ch = frame->ch_layout.nb_channels; - planes = planar ? ch : 1; - } + int i, ret; if (pool && pool->format == frame->format) { if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && pool->width == frame->width && pool->height == frame->height) return 0; - if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && pool->planes == planes && - pool->channels == ch && frame->nb_samples == pool->samples) + if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && + pool->channels == frame->ch_layout.nb_channels && + frame->nb_samples == pool->samples) return 0; } @@ -141,21 +136,25 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) break; } case AVMEDIA_TYPE_AUDIO: { - ret = av_samples_get_buffer_size(&pool->linesize[0], ch, + ret = av_samples_get_buffer_size(&pool->linesize[0], + frame->ch_layout.nb_channels, frame->nb_samples, frame->format, 0); if (ret < 0) goto fail; - pool->pools[0] = av_buffer_pool_init(pool->linesize[0], NULL); + pool->pools[0] = av_buffer_pool_init(pool->linesize[0], + CONFIG_MEMORY_POISONING ? + NULL : + av_buffer_allocz); if (!pool->pools[0]) { ret = AVERROR(ENOMEM); goto fail; } pool->format = frame->format; - pool->planes = planes; - pool->channels = ch; + pool->channels = frame->ch_layout.nb_channels; pool->samples = frame->nb_samples; + pool->planes = av_sample_fmt_is_planar(pool->format) ? pool->channels : 1; break; } default: av_assert0(0); diff --git a/libavcodec/gif.c b/libavcodec/gif.c index 49356236e..c36fa6673 100644 --- a/libavcodec/gif.c +++ b/libavcodec/gif.c @@ -30,6 +30,8 @@ * @see http://www.w3.org/Graphics/GIF/spec-gif89a.txt */ +#include "libavutil/imgutils_internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/gifdec.c b/libavcodec/gifdec.c index a97a6d15f..ae45eb0f6 100644 --- a/libavcodec/gifdec.c +++ b/libavcodec/gifdec.c @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/h261.h b/libavcodec/h261.h index 67c362be9..4279a1267 100644 --- a/libavcodec/h261.h +++ b/libavcodec/h261.h @@ -28,6 +28,7 @@ #ifndef AVCODEC_H261_H #define AVCODEC_H261_H +#include "mpegutils.h" #include "mpegvideo.h" #include "rl.h" @@ -38,17 +39,21 @@ typedef struct H261Context { int mtype; } H261Context; -#define MB_TYPE_H261_FIL 0x800000 +#define MB_TYPE_H261_FIL MB_TYPE_CODEC_SPECIFIC extern const uint8_t ff_h261_mba_code[35]; extern const uint8_t ff_h261_mba_bits[35]; extern const uint8_t ff_h261_mtype_code[10]; extern const uint8_t ff_h261_mtype_bits[10]; -extern const int ff_h261_mtype_map[10]; +extern const uint16_t ff_h261_mtype_map[10]; extern const uint8_t ff_h261_mv_tab[17][2]; extern const uint8_t ff_h261_cbp_tab[63][2]; extern RLTable ff_h261_rl_tcoeff; +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); #endif /* AVCODEC_H261_H */ diff --git a/libavcodec/h261data.c b/libavcodec/h261data.c index a9891edd0..3ee750f98 100644 --- a/libavcodec/h261data.c +++ b/libavcodec/h261data.c @@ -72,7 +72,7 @@ const uint8_t ff_h261_mtype_bits[10] = { 2, 6 }; -const int ff_h261_mtype_map[10] = { +const uint16_t ff_h261_mtype_map[10] = { MB_TYPE_INTRA4x4, MB_TYPE_INTRA4x4 | MB_TYPE_QUANT, MB_TYPE_CBP, @@ -104,7 +104,7 @@ const uint8_t ff_h261_cbp_tab[63][2] = { }; // H.261 VLC table for transform coefficients -static const uint16_t h261_tcoeff_vlc[65][2] = { +const uint16_t ff_h261_tcoeff_vlc[65][2] = { { 0x2, 2 }, { 0x3, 2 }, { 0x4, 4 }, { 0x5, 5 }, { 0x6, 7 }, { 0x26, 8 }, { 0x21, 8 }, { 0xa, 10 }, { 0x1d, 12 }, { 0x18, 12 }, { 0x13, 12 }, { 0x10, 12 }, @@ -124,7 +124,7 @@ static const uint16_t h261_tcoeff_vlc[65][2] = { { 0x1, 6 } // escape }; -static const int8_t h261_tcoeff_level[64] = { +const int8_t ff_h261_tcoeff_level[64] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 1, @@ -135,7 +135,7 @@ static const int8_t h261_tcoeff_level[64] = { 1, 1, 1, 1, 1, 1, 1, 1 }; -static const int8_t h261_tcoeff_run[64] = { +const int8_t ff_h261_tcoeff_run[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, @@ -150,7 +150,7 @@ static const int8_t h261_tcoeff_run[64] = { RLTable ff_h261_rl_tcoeff = { 64, 64, - h261_tcoeff_vlc, - h261_tcoeff_run, - h261_tcoeff_level, + ff_h261_tcoeff_vlc, + ff_h261_tcoeff_run, + ff_h261_tcoeff_level, }; diff --git a/libavcodec/h261dec.c b/libavcodec/h261dec.c index 4fbd5985b..cabca33c8 100644 --- a/libavcodec/h261dec.c +++ b/libavcodec/h261dec.c @@ -67,9 +67,10 @@ static av_cold void h261_decode_init_static(void) VLC_INIT_STATIC_TABLE(h261_mba_vlc, H261_MBA_VLC_BITS, 35, ff_h261_mba_bits, 1, 1, ff_h261_mba_code, 1, 1, 0); - VLC_INIT_STATIC_TABLE(h261_mtype_vlc, H261_MTYPE_VLC_BITS, 10, - ff_h261_mtype_bits, 1, 1, - ff_h261_mtype_code, 1, 1, 0); + VLC_INIT_STATIC_SPARSE_TABLE(h261_mtype_vlc, H261_MTYPE_VLC_BITS, 10, + ff_h261_mtype_bits, 1, 1, + ff_h261_mtype_code, 1, 1, + ff_h261_mtype_map, 2, 2, 0); VLC_INIT_STATIC_TABLE(h261_mv_vlc, H261_MV_VLC_BITS, 17, &ff_h261_mv_tab[0][1], 2, 1, &ff_h261_mv_tab[0][0], 2, 1, 0); @@ -84,17 +85,20 @@ static av_cold int h261_decode_init(AVCodecContext *avctx) static AVOnce init_static_once = AV_ONCE_INIT; H261DecContext *const h = avctx->priv_data; MpegEncContext *const s = &h->s; + int ret; + + avctx->framerate = (AVRational) { 30000, 1001 }; s->private_ctx = &h->common; // set defaults - ff_mpv_decode_init(s, avctx); + ret = ff_mpv_decode_init(s, avctx); + if (ret < 0) + return ret; s->out_format = FMT_H261; s->low_delay = 1; avctx->pix_fmt = AV_PIX_FMT_YUV420P; - h->gob_start_code_skipped = 0; - ff_thread_once(&init_static_once, h261_decode_init_static); return 0; @@ -163,47 +167,6 @@ static int h261_decode_gob_header(H261DecContext *h) return 0; } -/** - * Decode the group of blocks / video packet header. - * @return <0 if no resync found - */ -static int h261_resync(H261DecContext *h) -{ - MpegEncContext *const s = &h->s; - int left, ret; - - if (h->gob_start_code_skipped) { - ret = h261_decode_gob_header(h); - if (ret >= 0) - return 0; - } else { - if (show_bits(&s->gb, 15) == 0) { - ret = h261_decode_gob_header(h); - if (ret >= 0) - return 0; - } - // OK, it is not where it is supposed to be ... - s->gb = s->last_resync_gb; - align_get_bits(&s->gb); - left = get_bits_left(&s->gb); - - for (; left > 15 + 1 + 4 + 5; left -= 8) { - if (show_bits(&s->gb, 15) == 0) { - GetBitContext bak = s->gb; - - ret = h261_decode_gob_header(h); - if (ret >= 0) - return 0; - - s->gb = bak; - } - skip_bits(&s->gb, 8); - } - } - - return -1; -} - /** * Decode skipped macroblocks. * @return 0 @@ -228,17 +191,17 @@ static int h261_decode_mb_skipped(H261DecContext *h, int mba1, int mba2) s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_16X16; - s->current_picture.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0; + 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 = 1; h->common.mtype &= ~MB_TYPE_H261_FIL; - if (s->current_picture.motion_val[0]) { + if (s->cur_pic.motion_val[0]) { int b_stride = 2*s->mb_width + 1; int b_xy = 2 * s->mb_x + (2 * s->mb_y) * b_stride; - s->current_picture.motion_val[0][b_xy][0] = s->mv[0][0][0]; - s->current_picture.motion_val[0][b_xy][1] = s->mv[0][0][1]; + s->cur_pic.motion_val[0][b_xy][0] = s->mv[0][0][0]; + s->cur_pic.motion_val[0][b_xy][1] = s->mv[0][0][1]; } ff_mpv_reconstruct_mb(s, s->block); @@ -247,10 +210,6 @@ static int h261_decode_mb_skipped(H261DecContext *h, int mba1, int mba2) return 0; } -static const int mvmap[17] = { - 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16 -}; - static int decode_mv_component(GetBitContext *gb, int v) { int mv_diff = get_vlc2(gb, h261_mv_vlc, H261_MV_VLC_BITS, 2); @@ -259,9 +218,7 @@ static int decode_mv_component(GetBitContext *gb, int v) if (mv_diff < 0) return v; - mv_diff = mvmap[mv_diff]; - - if (mv_diff && !get_bits1(gb)) + if (mv_diff && get_bits1(gb)) mv_diff = -mv_diff; v += mv_diff; @@ -281,8 +238,9 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded { MpegEncContext *const s = &h->s; int level, i, j, run; - RLTable *rl = &ff_h261_rl_tcoeff; + const RLTable *rl = &ff_h261_rl_tcoeff; const uint8_t *scan_table; + const int qmul = s->qscale << 1, qadd = (s->qscale - 1) | 1; /* For the variable length encoding there are two code tables, one being * used for the first transmitted LEVEL in INTER, INTER + MC and @@ -304,7 +262,7 @@ 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; + block[0] = level * s->y_dc_scale; i = 1; } else if (coded) { // Run Level Code @@ -315,7 +273,8 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded i = 0; if (check & 0x2) { skip_bits(&s->gb, 2); - block[0] = (check & 0x1) ? -1 : 1; + block[0] = qmul + qadd; + block[0] *= (check & 0x1) ? -1 : 1; i = 1; } } else { @@ -345,10 +304,15 @@ static int h261_decode_block(H261DecContext *h, int16_t *block, int n, int coded run = SHOW_UBITS(re, &s->gb, 6) + 1; SKIP_CACHE(re, &s->gb, 6); level = SHOW_SBITS(re, &s->gb, 8); + if (level > 0) + level = level * qmul + qadd; + else if (level < 0) + level = level * qmul - qadd; SKIP_COUNTER(re, &s->gb, 6 + 8); } else if (level == 0) { break; } else { + level = level * qmul + qadd; if (SHOW_UBITS(re, &s->gb, 1)) level = -level; SKIP_COUNTER(re, &s->gb, 1); @@ -411,12 +375,9 @@ static int h261_decode_mb(H261DecContext *h) // Read mtype com->mtype = get_vlc2(&s->gb, h261_mtype_vlc, H261_MTYPE_VLC_BITS, 2); if (com->mtype < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid mtype index %d\n", - com->mtype); + av_log(s->avctx, AV_LOG_ERROR, "Invalid mtype index\n"); return SLICE_ERROR; } - av_assert0(com->mtype < FF_ARRAY_ELEMS(ff_h261_mtype_map)); - com->mtype = ff_h261_mtype_map[com->mtype]; // Read mquant if (IS_QUANT(com->mtype)) @@ -452,22 +413,22 @@ static int h261_decode_mb(H261DecContext *h) cbp = get_vlc2(&s->gb, h261_cbp_vlc, H261_CBP_VLC_BITS, 1) + 1; if (s->mb_intra) { - s->current_picture.mb_type[xy] = MB_TYPE_INTRA; + s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; goto intra; } //set motion vectors s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_16X16; - s->current_picture.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_L0; + s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; s->mv[0][0][0] = h->current_mv_x * 2; // gets divided by 2 in motion compensation s->mv[0][0][1] = h->current_mv_y * 2; - if (s->current_picture.motion_val[0]) { + if (s->cur_pic.motion_val[0]) { int b_stride = 2*s->mb_width + 1; int b_xy = 2 * s->mb_x + (2 * s->mb_y) * b_stride; - s->current_picture.motion_val[0][b_xy][0] = s->mv[0][0][0]; - s->current_picture.motion_val[0][b_xy][1] = s->mv[0][0][1]; + s->cur_pic.motion_val[0][b_xy][0] = s->mv[0][0][0]; + s->cur_pic.motion_val[0][b_xy][1] = s->mv[0][0][1]; } intra: @@ -514,8 +475,6 @@ static int h261_decode_picture_header(H261DecContext *h) /* temporal reference */ skip_bits(&s->gb, 5); /* picture timestamp */ - s->avctx->framerate = (AVRational) { 30000, 1001 }; - /* PTYPE starts here */ skip_bits1(&s->gb); /* split screen off */ skip_bits1(&s->gb); /* camera off */ @@ -643,33 +602,23 @@ static int h261_decode_frame(AVCodecContext *avctx, AVFrame *pict, s->mb_y = 0; while (h->gob_number < (s->mb_height == 18 ? 12 : 5)) { - if (h261_resync(h) < 0) + if (h261_decode_gob_header(h) < 0) break; h261_decode_gob(h); } ff_mpv_frame_end(s); - av_assert0(s->current_picture.f->pict_type == s->current_picture_ptr->f->pict_type); - av_assert0(s->current_picture.f->pict_type == s->pict_type); + av_assert0(s->pict_type == s->cur_pic.ptr->f->pict_type); - if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0) + if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) return ret; - ff_print_debug_info(s, s->current_picture_ptr, pict); + ff_print_debug_info(s, s->cur_pic.ptr, pict); *got_frame = 1; return get_consumed_bytes(s, buf_size); } -static av_cold int h261_decode_end(AVCodecContext *avctx) -{ - H261DecContext *const h = avctx->priv_data; - MpegEncContext *s = &h->s; - - ff_mpv_common_end(s); - return 0; -} - const FFCodec ff_h261_decoder = { .p.name = "h261", CODEC_LONG_NAME("H.261"), @@ -677,8 +626,8 @@ const FFCodec ff_h261_decoder = { .p.id = AV_CODEC_ID_H261, .priv_data_size = sizeof(H261DecContext), .init = h261_decode_init, - .close = h261_decode_end, FF_CODEC_DECODE_CB(h261_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, .p.max_lowres = 3, }; diff --git a/libavcodec/h261enc.c b/libavcodec/h261enc.c index 438ebb63d..f417366e7 100644 --- a/libavcodec/h261enc.c +++ b/libavcodec/h261enc.c @@ -34,11 +34,19 @@ #include "mpegvideo.h" #include "h261.h" #include "h261enc.h" -#include "mpegvideodata.h" #include "mpegvideoenc.h" -static uint8_t uni_h261_rl_len [64*64*2*2]; -#define UNI_ENC_INDEX(last,run,level) ((last)*128*64 + (run)*128 + (level)) +#define H261_MAX_RUN 26 +#define H261_MAX_LEVEL 15 +#define H261_ESC_LEN (6 + 6 + 8) + +static struct VLCLUT { + uint8_t len; + uint16_t code; +} vlc_lut[H261_MAX_RUN + 1][32 /* 0..2 * H261_MAX_LEN are used */]; + +static uint8_t uni_h261_rl_len [64 * 128]; +static uint8_t uni_h261_rl_len_last[64 * 128]; typedef struct H261EncContext { MpegEncContext s; @@ -134,8 +142,8 @@ static void h261_encode_motion(PutBitContext *pb, int val) { int sign, code; if (val == 0) { - code = 0; - put_bits(pb, ff_h261_mv_tab[code][1], ff_h261_mv_tab[code][0]); + // Corresponds to ff_h261_mv_tab[0] + put_bits(pb, 1, 1); } else { if (val > 15) val -= 32; @@ -166,10 +174,8 @@ 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; - int level, run, i, j, last_index, last_non_zero, sign, slevel, code; - RLTable *rl; + int level, run, i, j, last_index, last_non_zero; - rl = &ff_h261_rl_tcoeff; if (s->mb_intra) { /* DC coef */ level = block[0]; @@ -205,30 +211,24 @@ static void h261_encode_block(H261EncContext *h, int16_t *block, int n) level = block[j]; if (level) { run = i - last_non_zero - 1; - sign = 0; - slevel = level; - if (level < 0) { - sign = 1; - level = -level; - } - code = get_rl_index(rl, 0 /*no last in H.261, EOB is used*/, - run, level); - if (run == 0 && level < 16) - code += 1; - put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]); - if (code == rl->n) { - put_bits(&s->pb, 6, run); - av_assert1(slevel != 0); - av_assert1(level <= 127); - put_sbits(&s->pb, 8, slevel); + + if (run <= H261_MAX_RUN && + (unsigned)(level + H261_MAX_LEVEL) <= 2 * H261_MAX_LEVEL && + vlc_lut[run][level + H261_MAX_LEVEL].len) { + put_bits(&s->pb, vlc_lut[run][level + H261_MAX_LEVEL].len, + vlc_lut[run][level + H261_MAX_LEVEL].code); } else { - put_bits(&s->pb, 1, sign); + /* Escape */ + put_bits(&s->pb, 6 + 6, (1 << 6) | run); + av_assert1(level != 0); + av_assert1(FFABS(level) <= 127); + put_sbits(&s->pb, 8, level); } last_non_zero = i; } } if (last_index > -1) - put_bits(&s->pb, rl->table_vlc[0][1], rl->table_vlc[0][0]); // EOB + put_bits(&s->pb, 2, 0x2); // EOB } void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], @@ -253,7 +253,6 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], if ((cbp | mvd) == 0) { /* skip macroblock */ - s->skip_count++; s->mb_skip_run++; s->last_mv[0][0][0] = 0; s->last_mv[0][0][1] = 0; @@ -322,51 +321,26 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64], } } -static av_cold void init_uni_h261_rl_tab(const RLTable *rl, uint8_t *len_tab) -{ - int slevel, run, 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_ENC_INDEX(last, run, slevel+64); - int level= slevel < 0 ? -slevel : slevel; - int len, code; - - len_tab[index]= 100; - - /* ESC0 */ - code= get_rl_index(rl, 0, run, level); - len= rl->table_vlc[code][1] + 1; - if(last) - len += 2; - - if(code!=rl->n && len < len_tab[index]){ - len_tab [index]= len; - } - /* ESC */ - len = rl->table_vlc[rl->n][1]; - if(last) - len += 2; - - if(len < len_tab[index]){ - len_tab [index]= len; - } - } - } - } -} - static av_cold void h261_encode_init_static(void) { - static uint8_t h261_rl_table_store[2][2 * MAX_RUN + MAX_LEVEL + 3]; + 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)); - ff_rl_init(&ff_h261_rl_tcoeff, h261_rl_table_store); - init_uni_h261_rl_tab(&ff_h261_rl_tcoeff, uni_h261_rl_len); + // The following loop is over the ordinary elements, not EOB or escape. + for (size_t i = 1; i < FF_ARRAY_ELEMS(ff_h261_tcoeff_vlc) - 1; i++) { + unsigned run = ff_h261_tcoeff_run[i]; + unsigned level = ff_h261_tcoeff_level[i]; + unsigned len = ff_h261_tcoeff_vlc[i][1] + 1 /* sign */; + unsigned code = ff_h261_tcoeff_vlc[i][0]; + + vlc_lut[run][H261_MAX_LEVEL + level] = (struct VLCLUT){ len, code << 1 }; + vlc_lut[run][H261_MAX_LEVEL - level] = (struct VLCLUT){ len, (code << 1) | 1 }; + + uni_h261_rl_len [UNI_AC_ENC_INDEX(run, 64 + level)] = len; + uni_h261_rl_len [UNI_AC_ENC_INDEX(run, 64 - level)] = len; + 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; + } } av_cold int ff_h261_encode_init(MpegEncContext *s) @@ -389,12 +363,10 @@ av_cold int ff_h261_encode_init(MpegEncContext *s) s->min_qcoeff = -127; s->max_qcoeff = 127; - s->y_dc_scale_table = - s->c_dc_scale_table = ff_mpeg1_dc_scale_table; - s->ac_esc_length = 6+6+8; + s->ac_esc_length = H261_ESC_LEN; 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 + 128*64; + 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; @@ -413,5 +385,6 @@ const FFCodec ff_h261_encoder = { .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; diff --git a/libavcodec/h263.c b/libavcodec/h263.c index b30ffaf87..19eb3ba52 100644 --- a/libavcodec/h263.c +++ b/libavcodec/h263.c @@ -56,8 +56,6 @@ void ff_h263_update_motion_val(MpegEncContext * s){ const int wrap = s->b8_stride; const int xy = s->block_index[0]; - s->current_picture.mbskip_table[mb_xy] = s->mb_skipped; - if(s->mv_type != MV_TYPE_8X8){ int motion_x, motion_y; if (s->mb_intra) { @@ -75,30 +73,21 @@ void ff_h263_update_motion_val(MpegEncContext * s){ s->p_field_mv_table[i][0][mb_xy][0]= s->mv[0][i][0]; s->p_field_mv_table[i][0][mb_xy][1]= s->mv[0][i][1]; } - s->current_picture.ref_index[0][4*mb_xy ] = - s->current_picture.ref_index[0][4*mb_xy + 1] = s->field_select[0][0]; - s->current_picture.ref_index[0][4*mb_xy + 2] = - s->current_picture.ref_index[0][4*mb_xy + 3] = s->field_select[0][1]; + s->cur_pic.ref_index[0][4*mb_xy ] = + s->cur_pic.ref_index[0][4*mb_xy + 1] = s->field_select[0][0]; + s->cur_pic.ref_index[0][4*mb_xy + 2] = + s->cur_pic.ref_index[0][4*mb_xy + 3] = s->field_select[0][1]; } /* no update if 8X8 because it has been done during parsing */ - s->current_picture.motion_val[0][xy][0] = motion_x; - s->current_picture.motion_val[0][xy][1] = motion_y; - s->current_picture.motion_val[0][xy + 1][0] = motion_x; - s->current_picture.motion_val[0][xy + 1][1] = motion_y; - s->current_picture.motion_val[0][xy + wrap][0] = motion_x; - s->current_picture.motion_val[0][xy + wrap][1] = motion_y; - s->current_picture.motion_val[0][xy + 1 + wrap][0] = motion_x; - s->current_picture.motion_val[0][xy + 1 + wrap][1] = motion_y; - } - - if(s->encoding){ //FIXME encoding MUST be cleaned up - if (s->mv_type == MV_TYPE_8X8) - s->current_picture.mb_type[mb_xy] = MB_TYPE_L0 | MB_TYPE_8x8; - else if(s->mb_intra) - s->current_picture.mb_type[mb_xy] = MB_TYPE_INTRA; - else - s->current_picture.mb_type[mb_xy] = MB_TYPE_L0 | MB_TYPE_16x16; + s->cur_pic.motion_val[0][xy][0] = motion_x; + s->cur_pic.motion_val[0][xy][1] = motion_y; + s->cur_pic.motion_val[0][xy + 1][0] = motion_x; + s->cur_pic.motion_val[0][xy + 1][1] = motion_y; + s->cur_pic.motion_val[0][xy + wrap][0] = motion_x; + s->cur_pic.motion_val[0][xy + wrap][1] = motion_y; + s->cur_pic.motion_val[0][xy + 1 + wrap][0] = motion_x; + s->cur_pic.motion_val[0][xy + 1 + wrap][1] = motion_y; } } @@ -115,7 +104,7 @@ void ff_h263_loop_filter(MpegEncContext * s){ Diag Top Left Center */ - if (!IS_SKIP(s->current_picture.mb_type[xy])) { + if (!IS_SKIP(s->cur_pic.mb_type[xy])) { qp_c= s->qscale; s->h263dsp.h263_v_loop_filter(dest_y + 8 * linesize, linesize, qp_c); s->h263dsp.h263_v_loop_filter(dest_y + 8 * linesize + 8, linesize, qp_c); @@ -125,10 +114,10 @@ void ff_h263_loop_filter(MpegEncContext * s){ if(s->mb_y){ int qp_dt, qp_tt, qp_tc; - if (IS_SKIP(s->current_picture.mb_type[xy - s->mb_stride])) + if (IS_SKIP(s->cur_pic.mb_type[xy - s->mb_stride])) qp_tt=0; else - qp_tt = s->current_picture.qscale_table[xy - s->mb_stride]; + qp_tt = s->cur_pic.qscale_table[xy - s->mb_stride]; if(qp_c) qp_tc= qp_c; @@ -148,10 +137,10 @@ void ff_h263_loop_filter(MpegEncContext * s){ s->h263dsp.h263_h_loop_filter(dest_y - 8 * linesize + 8, linesize, qp_tt); if(s->mb_x){ - if (qp_tt || IS_SKIP(s->current_picture.mb_type[xy - 1 - s->mb_stride])) + if (qp_tt || IS_SKIP(s->cur_pic.mb_type[xy - 1 - s->mb_stride])) qp_dt= qp_tt; else - qp_dt = s->current_picture.qscale_table[xy - 1 - s->mb_stride]; + qp_dt = s->cur_pic.qscale_table[xy - 1 - s->mb_stride]; if(qp_dt){ const int chroma_qp= s->chroma_qscale_table[qp_dt]; @@ -170,10 +159,10 @@ void ff_h263_loop_filter(MpegEncContext * s){ if(s->mb_x){ int qp_lc; - if (qp_c || IS_SKIP(s->current_picture.mb_type[xy - 1])) + if (qp_c || IS_SKIP(s->cur_pic.mb_type[xy - 1])) qp_lc= qp_c; else - qp_lc = s->current_picture.qscale_table[xy - 1]; + qp_lc = s->cur_pic.qscale_table[xy - 1]; if(qp_lc){ s->h263dsp.h263_h_loop_filter(dest_y, linesize, qp_lc); @@ -195,7 +184,7 @@ int16_t *ff_h263_pred_motion(MpegEncContext * s, int block, int dir, static const int off[4]= {2, 1, 1, -1}; wrap = s->b8_stride; - mot_val = s->current_picture.motion_val[dir] + s->block_index[block]; + mot_val = s->cur_pic.motion_val[dir] + s->block_index[block]; A = mot_val[ - 1]; /* special case for first (slice) line */ diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index 910df7585..5eefdc460 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -42,7 +42,6 @@ #include "mpeg4video.h" #include "mpeg4videodec.h" #include "mpeg4videodefs.h" -#include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "msmpeg4dec.h" @@ -96,12 +95,18 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) s->out_format = FMT_H263; // set defaults - ff_mpv_decode_init(s, avctx); + ret = ff_mpv_decode_init(s, avctx); + if (ret < 0) + return ret; - s->quant_precision = 5; s->decode_mb = ff_h263_decode_mb; s->low_delay = 1; + // 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; + /* select sub codec */ switch (avctx->codec->id) { case AV_CODEC_ID_H263: @@ -109,28 +114,33 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) avctx->chroma_sample_location = AVCHROMA_LOC_CENTER; 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; - s->msmpeg4_version = 1; + s->msmpeg4_version = MSMP4_V1; break; case AV_CODEC_ID_MSMPEG4V2: s->h263_pred = 1; - s->msmpeg4_version = 2; + s->msmpeg4_version = MSMP4_V2; break; case AV_CODEC_ID_MSMPEG4V3: s->h263_pred = 1; - s->msmpeg4_version = 3; + s->msmpeg4_version = MSMP4_V3; break; case AV_CODEC_ID_WMV1: s->h263_pred = 1; - s->msmpeg4_version = 4; + s->msmpeg4_version = MSMP4_WMV1; break; case AV_CODEC_ID_WMV2: s->h263_pred = 1; - s->msmpeg4_version = 5; + 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; @@ -160,14 +170,6 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx) return 0; } -av_cold int ff_h263_decode_end(AVCodecContext *avctx) -{ - MpegEncContext *s = avctx->priv_data; - - ff_mpv_common_end(s); - return 0; -} - /** * Return the number of bytes consumed for building the current frame. */ @@ -234,7 +236,7 @@ static int decode_slice(MpegEncContext *s) for (; s->mb_y < s->mb_height; s->mb_y++) { /* per-row end of slice checks */ - if (s->msmpeg4_version) { + 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); @@ -243,7 +245,7 @@ static int decode_slice(MpegEncContext *s) } } - if (s->msmpeg4_version == 1) { + if (s->msmpeg4_version == MSMP4_V1) { s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 128; @@ -382,12 +384,12 @@ static int decode_slice(MpegEncContext *s) } // handle formats which don't have unique end markers - if (s->msmpeg4_version || (s->workaround_bugs & FF_BUG_NO_PADDING)) { // FIXME perhaps solve this more cleanly + 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); int max_extra = 7; /* no markers in M$ crap */ - if (s->msmpeg4_version && s->pict_type == AV_PICTURE_TYPE_I) + if (s->msmpeg4_version != MSMP4_UNUSED && s->pict_type == AV_PICTURE_TYPE_I) max_extra += 17; /* buggy padding but the frame should still end approximately at @@ -429,26 +431,27 @@ int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *pict, MpegEncContext *s = avctx->priv_data; int ret; int slice_ret = 0; + int bak_width, bak_height; /* no supplementary picture */ if (buf_size == 0) { /* special case for last picture */ - if (s->low_delay == 0 && s->next_picture_ptr) { - if ((ret = av_frame_ref(pict, s->next_picture_ptr->f)) < 0) + if (s->low_delay == 0 && s->next_pic.ptr) { + if ((ret = av_frame_ref(pict, s->next_pic.ptr->f)) < 0) return ret; - s->next_picture_ptr = NULL; + ff_mpv_unref_picture(&s->next_pic); *got_frame = 1; - } else if (s->skipped_last_frame && s->current_picture_ptr) { + } 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->current_picture_ptr->f)) < 0) + 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; - s->current_picture_ptr = NULL; + ff_mpv_unref_picture(&s->cur_pic); *got_frame = 1; } @@ -480,11 +483,16 @@ retry: if (ret < 0) return ret; + bak_width = s->width; + bak_height = s->height; + /* let's go :-) */ - if (CONFIG_WMV2_DECODER && s->msmpeg4_version == 5) { + if (CONFIG_WMV2_DECODER && s->msmpeg4_version == MSMP4_WMV2) { ret = ff_wmv2_decode_picture_header(s); - } else if (CONFIG_MSMPEG4DEC && s->msmpeg4_version) { +#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); @@ -497,11 +505,12 @@ retry: } if (ret < 0 || ret == FRAME_SKIPPED) { - if ( s->width != avctx->coded_width - || s->height != avctx->coded_height) { + 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 = avctx->coded_width; - s->height= avctx->coded_height; + s->width = bak_width; + s->height= bak_height; + } } if (ret == FRAME_SKIPPED) @@ -528,6 +537,11 @@ retry: goto retry; if (s->studio_profile != (s->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; + } } /* After H.263 & MPEG-4 header decode we have the height, width, @@ -562,7 +576,7 @@ retry: s->gob_index = H263_GOB_HEIGHT(s->height); /* skip B-frames if we don't have reference frames */ - if (!s->last_picture_ptr && + if (!s->last_pic.ptr && (s->pict_type == AV_PICTURE_TYPE_B || s->droppable)) return get_consumed_bytes(s, buf_size); if ((avctx->skip_frame >= AVDISCARD_NONREF && @@ -590,13 +604,15 @@ retry: /* 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 && s->msmpeg4_version == 5) { +#if CONFIG_WMV2_DECODER + if (s->msmpeg4_version == MSMP4_WMV2) { ret = ff_wmv2_decode_secondary_picture_header(s); if (ret < 0) return ret; if (ret == 1) goto frame_end; } +#endif /* decode each macroblock */ s->mb_x = 0; @@ -604,7 +620,7 @@ retry: slice_ret = decode_slice(s); while (s->mb_y < s->mb_height) { - if (s->msmpeg4_version) { + 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) break; @@ -616,14 +632,14 @@ retry: s->er.error_occurred = 1; } - if (s->msmpeg4_version < 4 && s->h263_pred) + if (s->msmpeg4_version < MSMP4_WMV1 && s->h263_pred) ff_mpeg4_clean_buffers(s); if (decode_slice(s) < 0) slice_ret = AVERROR_INVALIDDATA; } - if (s->msmpeg4_version && s->msmpeg4_version < 4 && + if (s->msmpeg4_version != MSMP4_UNUSED && s->msmpeg4_version < MSMP4_WMV1 && s->pict_type == AV_PICTURE_TYPE_I) if (!CONFIG_MSMPEG4DEC || ff_msmpeg4_decode_ext_header(s, buf_size) < 0) @@ -648,21 +664,20 @@ frame_end: if (!s->divx_packed && avctx->hwaccel) ff_thread_finish_setup(avctx); - av_assert1(s->current_picture.f->pict_type == s->current_picture_ptr->f->pict_type); - av_assert1(s->current_picture.f->pict_type == s->pict_type); + 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->current_picture_ptr->f)) < 0) + if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) return ret; - ff_print_debug_info(s, s->current_picture_ptr, pict); - ff_mpv_export_qp_table(s, pict, s->current_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG1); - } else if (s->last_picture_ptr) { - if ((ret = av_frame_ref(pict, s->last_picture_ptr->f)) < 0) + 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) return ret; - ff_print_debug_info(s, s->last_picture_ptr, pict); - ff_mpv_export_qp_table(s, pict, s->last_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG1); + 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); } - if (s->last_picture_ptr || s->low_delay) { + if (s->last_pic.ptr || s->low_delay) { if ( pict->format == AV_PIX_FMT_YUV420P && (s->codec_tag == AV_RL32("GEOV") || s->codec_tag == AV_RL32("GEOX"))) { for (int p = 0; p < 3; p++) { @@ -704,11 +719,12 @@ const FFCodec ff_h263_decoder = { .p.id = AV_CODEC_ID_H263, .priv_data_size = sizeof(MpegEncContext), .init = ff_h263_decode_init, - .close = ff_h263_decode_end, FF_CODEC_DECODE_CB(ff_h263_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .flush = ff_mpeg_flush, .p.max_lowres = 3, .hw_configs = h263_hw_config_list, @@ -721,11 +737,12 @@ const FFCodec ff_h263p_decoder = { .p.id = AV_CODEC_ID_H263P, .priv_data_size = sizeof(MpegEncContext), .init = ff_h263_decode_init, - .close = ff_h263_decode_end, FF_CODEC_DECODE_CB(ff_h263_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, - .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .flush = ff_mpeg_flush, .p.max_lowres = 3, .hw_configs = h263_hw_config_list, diff --git a/libavcodec/h263dec.h b/libavcodec/h263dec.h index 89c5fcf58..633d4aa57 100644 --- a/libavcodec/h263dec.h +++ b/libavcodec/h263dec.h @@ -23,6 +23,11 @@ #include "mpegvideo.h" #include "vlc.h" +/** + * Return value for header parsers if frame is not coded. + * */ +#define FRAME_SKIPPED 100 + // 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 @@ -42,7 +47,6 @@ int ff_h263_decode_motion(MpegEncContext * s, int pred, int f_code); int ff_h263_decode_init(AVCodecContext *avctx); int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt); -int ff_h263_decode_end(AVCodecContext *avctx); void ff_h263_decode_init_vlc(void); int ff_h263_decode_picture_header(MpegEncContext *s); int ff_h263_decode_gob_header(MpegEncContext *s); diff --git a/libavcodec/h263dsp.c b/libavcodec/h263dsp.c index 8fa2d3c29..6a1335349 100644 --- a/libavcodec/h263dsp.c +++ b/libavcodec/h263dsp.c @@ -119,7 +119,9 @@ av_cold void ff_h263dsp_init(H263DSPContext *ctx) ctx->h263_h_loop_filter = h263_h_loop_filter_c; ctx->h263_v_loop_filter = h263_v_loop_filter_c; -#if ARCH_X86 +#if ARCH_RISCV + ff_h263dsp_init_riscv(ctx); +#elif ARCH_X86 ff_h263dsp_init_x86(ctx); #elif ARCH_MIPS ff_h263dsp_init_mips(ctx); diff --git a/libavcodec/h263dsp.h b/libavcodec/h263dsp.h index 1abea3ca8..2dccd2339 100644 --- a/libavcodec/h263dsp.h +++ b/libavcodec/h263dsp.h @@ -29,6 +29,7 @@ typedef struct H263DSPContext { } H263DSPContext; void ff_h263dsp_init(H263DSPContext *ctx); +void ff_h263dsp_init_riscv(H263DSPContext *ctx); void ff_h263dsp_init_x86(H263DSPContext *ctx); void ff_h263dsp_init_mips(H263DSPContext *ctx); diff --git a/libavcodec/h263enc.h b/libavcodec/h263enc.h index e45475686..784500ca7 100644 --- a/libavcodec/h263enc.h +++ b/libavcodec/h263enc.h @@ -32,42 +32,16 @@ void ff_h263_encode_mb(MpegEncContext *s, int motion_x, int motion_y); void ff_h263_encode_mba(MpegEncContext *s); -void ff_init_qscale_tab(MpegEncContext *s); void ff_clean_h263_qscales(MpegEncContext *s); void ff_h263_encode_motion(PutBitContext *pb, int val, int f_code); - - -static inline int h263_get_motion_length(int val, int f_code) -{ - int bit_size, code, sign; - - if (val == 0) { - return 1; /* ff_mvtab[0][1] */ - } else { - bit_size = f_code - 1; - /* modulo encoding */ - val = sign_extend(val, 6 + bit_size); - sign = val >> 31; - val = (val ^ sign) - sign; /* val = FFABS(val) */ - val--; - code = (val >> bit_size) + 1; - - return ff_mvtab[code][1] + 1 + bit_size; - } -} +void ff_h263_update_mb(MpegEncContext *s); static inline void ff_h263_encode_motion_vector(MpegEncContext * s, int x, int y, int f_code) { - if (s->avctx->flags2 & AV_CODEC_FLAG2_NO_OUTPUT) { - skip_put_bits(&s->pb, - h263_get_motion_length(x, f_code) + - h263_get_motion_length(y, f_code)); - } else { - ff_h263_encode_motion(&s->pb, x, f_code); - ff_h263_encode_motion(&s->pb, y, f_code); - } + ff_h263_encode_motion(&s->pb, x, f_code); + ff_h263_encode_motion(&s->pb, y, f_code); } static inline int get_p_cbp(MpegEncContext * s, diff --git a/libavcodec/h2645_parse.c b/libavcodec/h2645_parse.c index 9f66f079c..82816999e 100644 --- a/libavcodec/h2645_parse.c +++ b/libavcodec/h2645_parse.c @@ -27,11 +27,12 @@ #include "libavutil/mem.h" #include "bytestream.h" -#include "hevc.h" #include "h264.h" #include "h2645_parse.h" #include "vvc.h" +#include "hevc/hevc.h" + int ff_h2645_extract_rbsp(const uint8_t *src, int length, H2645RBSP *rbsp, H2645NAL *nal, int small_padding) { @@ -462,16 +463,16 @@ fail: } int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, - void *logctx, int is_nalff, int nal_length_size, - enum AVCodecID codec_id, int small_padding, int use_ref) + void *logctx, int nal_length_size, + enum AVCodecID codec_id, int flags) { GetByteContext bc; int consumed, ret = 0; - int next_avc = is_nalff ? 0 : length; - int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE; + int next_avc = (flags & H2645_FLAG_IS_NALFF) ? 0 : length; + int64_t padding = (flags & H2645_FLAG_SMALL_PADDING) ? 0 : MAX_MBPAIR_SIZE; bytestream2_init(&bc, buf, length); - alloc_rbsp_buffer(&pkt->rbsp, length + padding, use_ref); + alloc_rbsp_buffer(&pkt->rbsp, length + padding, !!(flags & H2645_FLAG_USE_REF)); if (!pkt->rbsp.rbsp_buffer) return AVERROR(ENOMEM); @@ -548,11 +549,12 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, } nal = &pkt->nals[pkt->nb_nals]; - consumed = ff_h2645_extract_rbsp(bc.buffer, extract_length, &pkt->rbsp, nal, small_padding); + consumed = ff_h2645_extract_rbsp(bc.buffer, extract_length, &pkt->rbsp, nal, + !!(flags & H2645_FLAG_SMALL_PADDING)); if (consumed < 0) return consumed; - if (is_nalff && (extract_length != consumed) && extract_length) + if ((flags & H2645_FLAG_IS_NALFF) && (extract_length != consumed) && extract_length) av_log(logctx, AV_LOG_DEBUG, "NALFF: Consumed only %d bytes instead of %d\n", consumed, extract_length); @@ -579,9 +581,11 @@ 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_HEVC) + else if (codec_id == AV_CODEC_ID_HEVC) { ret = hevc_parse_nal_header(nal, logctx); - else + if (nal->nuh_layer_id == 63) + continue; + } else ret = h264_parse_nal_header(nal, logctx); if (ret < 0) { av_log(logctx, AV_LOG_WARNING, "Invalid NAL unit %d, skipping.\n", diff --git a/libavcodec/h2645_parse.h b/libavcodec/h2645_parse.h index 128dea09e..e27ccf752 100644 --- a/libavcodec/h2645_parse.h +++ b/libavcodec/h2645_parse.h @@ -93,6 +93,12 @@ typedef struct H2645Packet { int ff_h2645_extract_rbsp(const uint8_t *src, int length, H2645RBSP *rbsp, H2645NAL *nal, int small_padding); +enum { + H2645_FLAG_IS_NALFF = (1 << 0), + H2645_FLAG_SMALL_PADDING = (1 << 1), + H2645_FLAG_USE_REF = (1 << 2), +}; + /** * Split an input packet into NAL units. * @@ -103,13 +109,14 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length, H2645RBSP *rbsp, * packet's H2645RBSP. * * If the packet's rbsp_buffer_ref is not NULL, the underlying AVBuffer must - * own rbsp_buffer. If not and rbsp_buffer is not NULL, use_ref must be 0. - * If use_ref is set, rbsp_buffer will be reference-counted and owned by - * the underlying AVBuffer of rbsp_buffer_ref. + * own rbsp_buffer. If not and rbsp_buffer is not NULL, H2645_FLAG_USE_REF + * must not be set in flags. + * If H2645_FLAG_USE_REF is set in flags, rbsp_buffer will be reference-counted + * and owned by the underlying AVBuffer of rbsp_buffer_ref. */ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, - void *logctx, int is_nalff, int nal_length_size, - enum AVCodecID codec_id, int small_padding, int use_ref); + void *logctx, int nal_length_size, + enum AVCodecID codec_id, int flags); /** * Free all the allocated memory in the packet. diff --git a/libavcodec/h2645_sei.c b/libavcodec/h2645_sei.c index 3b58d22d6..62369dd37 100644 --- a/libavcodec/h2645_sei.c +++ b/libavcodec/h2645_sei.c @@ -26,11 +26,12 @@ #include "config_components.h" #include "libavutil/ambient_viewing_environment.h" +#include "libavutil/buffer.h" #include "libavutil/display.h" #include "libavutil/hdr_dynamic_metadata.h" #include "libavutil/film_grain_params.h" #include "libavutil/mastering_display_metadata.h" -#include "libavutil/pixdesc.h" +#include "libavutil/mem.h" #include "libavutil/stereo3d.h" #include "atsc_a53.h" @@ -41,6 +42,7 @@ #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) @@ -99,6 +101,20 @@ static int decode_registered_user_data_dynamic_hdr_vivid(HEVCSEIDynamicHDRVivid } #endif +static int decode_registered_user_data_lcevc(HEVCSEILCEVC *s, + GetByteContext *gb) +{ + int size = bytestream2_get_bytes_left(gb); + + av_buffer_unref(&s->info); + s->info = av_buffer_alloc(size); + if (!s->info) + return AVERROR(ENOMEM); + + bytestream2_get_bufferu(gb, s->info->data, size); + return 0; +} + static int decode_registered_user_data_afd(H2645SEIAFD *h, GetByteContext *gb) { int flag; @@ -142,6 +158,7 @@ static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb, } 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", @@ -173,6 +190,13 @@ static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb, } 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; @@ -472,7 +496,11 @@ 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: - return decode_film_grain_characteristics(&h->film_grain_characteristics, codec_id, gb); + ff_refstruct_unref(&h->film_grain_characteristics); + h->film_grain_characteristics = ff_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); case SEI_TYPE_FRAME_PACKING_ARRANGEMENT: return decode_frame_packing_arrangement(&h->frame_packing, gb, codec_id); case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS: @@ -501,6 +529,10 @@ int ff_h2645_sei_ctx_replace(H2645SEI *dst, const H2645SEI *src) av_buffer_unref(&dst->unregistered.buf_ref[i]); dst->unregistered.nb_buf_ref = 0; + ret = av_buffer_replace(&dst->lcevc.info, src->lcevc.info); + if (ret < 0) + return ret; + if (src->unregistered.nb_buf_ref) { ret = av_reallocp_array(&dst->unregistered.buf_ref, src->unregistered.nb_buf_ref, @@ -516,6 +548,17 @@ int ff_h2645_sei_ctx_replace(H2645SEI *dst, const H2645SEI *src) } } + for (unsigned i = 0; i < FF_ARRAY_ELEMS(dst->aom_film_grain.sets); i++) { + ret = av_buffer_replace(&dst->aom_film_grain.sets[i], + src->aom_film_grain.sets[i]); + if (ret < 0) + return ret; + } + dst->aom_film_grain.enable = src->aom_film_grain.enable; + + ff_refstruct_replace(&dst->film_grain_characteristics, + src->film_grain_characteristics); + return 0; } @@ -529,6 +572,146 @@ static int is_frame_packing_type_valid(SEIFpaType type, enum AVCodecID codec_id) type >= SEI_FPA_TYPE_SIDE_BY_SIDE; } +static int h2645_sei_to_side_data(AVCodecContext *avctx, H2645SEI *sei, + AVFrameSideData ***sd, int *nb_sd) +{ + int ret; + + for (unsigned i = 0; i < sei->unregistered.nb_buf_ref; i++) { + H2645SEIUnregistered *unreg = &sei->unregistered; + + if (unreg->buf_ref[i]) { + AVFrameSideData *entry = + av_frame_side_data_add(sd, nb_sd, AV_FRAME_DATA_SEI_UNREGISTERED, + &unreg->buf_ref[i], 0); + if (!entry) + av_buffer_unref(&unreg->buf_ref[i]); + } + } + sei->unregistered.nb_buf_ref = 0; + + if (sei->ambient_viewing_environment.present) { + H2645SEIAmbientViewingEnvironment *env = &sei->ambient_viewing_environment; + AVBufferRef *buf; + size_t size; + + AVAmbientViewingEnvironment *dst_env = + av_ambient_viewing_environment_alloc(&size); + if (!dst_env) + return AVERROR(ENOMEM); + + buf = av_buffer_create((uint8_t *)dst_env, size, NULL, NULL, 0); + if (!buf) { + av_free(dst_env); + return AVERROR(ENOMEM); + } + + ret = ff_frame_new_side_data_from_buf_ext(avctx, sd, nb_sd, + AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT, &buf); + + if (ret < 0) + return ret; + + dst_env->ambient_illuminance = av_make_q(env->ambient_illuminance, 10000); + dst_env->ambient_light_x = av_make_q(env->ambient_light_x, 50000); + dst_env->ambient_light_y = av_make_q(env->ambient_light_y, 50000); + } + + if (sei->mastering_display.present) { + // HEVC uses a g,b,r ordering, which we convert to a more natural r,g,b + const int mapping[3] = {2, 0, 1}; + const int chroma_den = 50000; + const int luma_den = 10000; + int i; + AVMasteringDisplayMetadata *metadata; + + ret = ff_decode_mastering_display_new_ext(avctx, sd, nb_sd, &metadata); + if (ret < 0) + return ret; + + if (metadata) { + metadata->has_luminance = 1; + metadata->has_primaries = 1; + + for (i = 0; i < 3; i++) { + const int j = mapping[i]; + metadata->display_primaries[i][0].num = sei->mastering_display.display_primaries[j][0]; + metadata->display_primaries[i][0].den = chroma_den; + metadata->has_primaries &= sei->mastering_display.display_primaries[j][0] >= 5 && + sei->mastering_display.display_primaries[j][0] <= 37000; + + metadata->display_primaries[i][1].num = sei->mastering_display.display_primaries[j][1]; + metadata->display_primaries[i][1].den = chroma_den; + metadata->has_primaries &= sei->mastering_display.display_primaries[j][1] >= 5 && + sei->mastering_display.display_primaries[j][1] <= 42000; + } + metadata->white_point[0].num = sei->mastering_display.white_point[0]; + metadata->white_point[0].den = chroma_den; + metadata->has_primaries &= sei->mastering_display.white_point[0] >= 5 && + sei->mastering_display.white_point[0] <= 37000; + + metadata->white_point[1].num = sei->mastering_display.white_point[1]; + metadata->white_point[1].den = chroma_den; + metadata->has_primaries &= sei->mastering_display.white_point[1] >= 5 && + sei->mastering_display.white_point[1] <= 42000; + + metadata->max_luminance.num = sei->mastering_display.max_luminance; + metadata->max_luminance.den = luma_den; + metadata->has_luminance &= sei->mastering_display.max_luminance >= 50000 && + sei->mastering_display.max_luminance <= 100000000; + + metadata->min_luminance.num = sei->mastering_display.min_luminance; + metadata->min_luminance.den = luma_den; + metadata->has_luminance &= sei->mastering_display.min_luminance <= 50000 && + sei->mastering_display.min_luminance < + sei->mastering_display.max_luminance; + + /* Real (blu-ray) releases in the wild come with minimum luminance + * values of 0.000 cd/m2, so permit this edge case */ + if (avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT) + metadata->has_luminance &= sei->mastering_display.min_luminance >= 1; + + if (metadata->has_luminance || metadata->has_primaries) + av_log(avctx, AV_LOG_DEBUG, "Mastering Display Metadata:\n"); + if (metadata->has_primaries) { + av_log(avctx, AV_LOG_DEBUG, + "r(%5.4f,%5.4f) g(%5.4f,%5.4f) b(%5.4f %5.4f) wp(%5.4f, %5.4f)\n", + av_q2d(metadata->display_primaries[0][0]), + av_q2d(metadata->display_primaries[0][1]), + av_q2d(metadata->display_primaries[1][0]), + av_q2d(metadata->display_primaries[1][1]), + av_q2d(metadata->display_primaries[2][0]), + av_q2d(metadata->display_primaries[2][1]), + av_q2d(metadata->white_point[0]), av_q2d(metadata->white_point[1])); + } + if (metadata->has_luminance) { + av_log(avctx, AV_LOG_DEBUG, + "min_luminance=%f, max_luminance=%f\n", + av_q2d(metadata->min_luminance), av_q2d(metadata->max_luminance)); + } + } + } + + if (sei->content_light.present) { + AVContentLightMetadata *metadata; + + ret = ff_decode_content_light_new_ext(avctx, sd, nb_sd, &metadata); + if (ret < 0) + return ret; + + if (metadata) { + metadata->MaxCLL = sei->content_light.max_content_light_level; + metadata->MaxFALL = sei->content_light.max_pic_average_light_level; + + av_log(avctx, AV_LOG_DEBUG, "Content Light Level Metadata:\n"); + av_log(avctx, AV_LOG_DEBUG, "MaxCLL=%d, MaxFALL=%d\n", + metadata->MaxCLL, metadata->MaxFALL); + } + } + + return 0; +} + int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, enum AVCodecID codec_id, AVCodecContext *avctx, const H2645VUI *vui, @@ -624,19 +807,9 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; } - for (unsigned i = 0; i < sei->unregistered.nb_buf_ref; i++) { - H2645SEIUnregistered *unreg = &sei->unregistered; - - if (unreg->buf_ref[i]) { - AVFrameSideData *sd = av_frame_new_side_data_from_buf(frame, - AV_FRAME_DATA_SEI_UNREGISTERED, - unreg->buf_ref[i]); - if (!sd) - av_buffer_unref(&unreg->buf_ref[i]); - unreg->buf_ref[i] = NULL; - } - } - sei->unregistered.nb_buf_ref = 0; + ret = h2645_sei_to_side_data(avctx, sei, &frame->side_data, &frame->nb_side_data); + if (ret < 0) + return ret; if (sei->afd.present) { AVFrameSideData *sd = av_frame_new_side_data(frame, AV_FRAME_DATA_AFD, @@ -648,8 +821,15 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, } } - if (sei->film_grain_characteristics.present) { - H2645SEIFilmGrainCharacteristics *fgc = &sei->film_grain_characteristics; + if (sei->lcevc.info) { + HEVCSEILCEVC *lcevc = &sei->lcevc; + ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_LCEVC, &lcevc->info); + if (ret < 0) + return ret; + } + + if (sei->film_grain_characteristics && sei->film_grain_characteristics->present) { + H2645SEIFilmGrainCharacteristics *fgc = sei->film_grain_characteristics; AVFilmGrainParams *fgp = av_film_grain_params_create_side_data(frame); AVFilmGrainH274Params *h274; @@ -726,88 +906,15 @@ FF_ENABLE_DEPRECATION_WARNINGS return ret; #endif - if (sei->ambient_viewing_environment.present) { - H2645SEIAmbientViewingEnvironment *env = - &sei->ambient_viewing_environment; - - AVAmbientViewingEnvironment *dst_env = - av_ambient_viewing_environment_create_side_data(frame); - if (!dst_env) - return AVERROR(ENOMEM); - - dst_env->ambient_illuminance = av_make_q(env->ambient_illuminance, 10000); - dst_env->ambient_light_x = av_make_q(env->ambient_light_x, 50000); - dst_env->ambient_light_y = av_make_q(env->ambient_light_y, 50000); - } - - if (sei->mastering_display.present) { - // HEVC uses a g,b,r ordering, which we convert to a more natural r,g,b - const int mapping[3] = {2, 0, 1}; - const int chroma_den = 50000; - const int luma_den = 10000; - int i; - AVMasteringDisplayMetadata *metadata; - - ret = ff_decode_mastering_display_new(avctx, frame, &metadata); - if (ret < 0) - return ret; - - if (metadata) { - for (i = 0; i < 3; i++) { - const int j = mapping[i]; - metadata->display_primaries[i][0].num = sei->mastering_display.display_primaries[j][0]; - metadata->display_primaries[i][0].den = chroma_den; - metadata->display_primaries[i][1].num = sei->mastering_display.display_primaries[j][1]; - metadata->display_primaries[i][1].den = chroma_den; - } - metadata->white_point[0].num = sei->mastering_display.white_point[0]; - metadata->white_point[0].den = chroma_den; - metadata->white_point[1].num = sei->mastering_display.white_point[1]; - metadata->white_point[1].den = chroma_den; - - metadata->max_luminance.num = sei->mastering_display.max_luminance; - metadata->max_luminance.den = luma_den; - metadata->min_luminance.num = sei->mastering_display.min_luminance; - metadata->min_luminance.den = luma_den; - metadata->has_luminance = 1; - metadata->has_primaries = 1; - - av_log(avctx, AV_LOG_DEBUG, "Mastering Display Metadata:\n"); - av_log(avctx, AV_LOG_DEBUG, - "r(%5.4f,%5.4f) g(%5.4f,%5.4f) b(%5.4f %5.4f) wp(%5.4f, %5.4f)\n", - av_q2d(metadata->display_primaries[0][0]), - av_q2d(metadata->display_primaries[0][1]), - av_q2d(metadata->display_primaries[1][0]), - av_q2d(metadata->display_primaries[1][1]), - av_q2d(metadata->display_primaries[2][0]), - av_q2d(metadata->display_primaries[2][1]), - av_q2d(metadata->white_point[0]), av_q2d(metadata->white_point[1])); - av_log(avctx, AV_LOG_DEBUG, - "min_luminance=%f, max_luminance=%f\n", - av_q2d(metadata->min_luminance), av_q2d(metadata->max_luminance)); - } - } - - if (sei->content_light.present) { - AVContentLightMetadata *metadata; - - ret = ff_decode_content_light_new(avctx, frame, &metadata); - if (ret < 0) - return ret; - - if (metadata) { - metadata->MaxCLL = sei->content_light.max_content_light_level; - metadata->MaxFALL = sei->content_light.max_pic_average_light_level; - - av_log(avctx, AV_LOG_DEBUG, "Content Light Level Metadata:\n"); - av_log(avctx, AV_LOG_DEBUG, "MaxCLL=%d, MaxFALL=%d\n", - metadata->MaxCLL, metadata->MaxFALL); - } - } - return 0; } +int ff_h2645_sei_to_context(AVCodecContext *avctx, H2645SEI *sei) +{ + return h2645_sei_to_side_data(avctx, sei, &avctx->decoded_side_data, + &avctx->nb_decoded_side_data); +} + void ff_h2645_sei_reset(H2645SEI *s) { av_buffer_unref(&s->a53_caption.buf_ref); @@ -818,9 +925,12 @@ void ff_h2645_sei_reset(H2645SEI *s) av_freep(&s->unregistered.buf_ref); av_buffer_unref(&s->dynamic_hdr_plus.info); av_buffer_unref(&s->dynamic_hdr_vivid.info); + av_buffer_unref(&s->lcevc.info); s->ambient_viewing_environment.present = 0; s->mastering_display.present = 0; s->content_light.present = 0; - s->aom_film_grain.enable = 0; + + ff_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 b9a6c7587..abc49760d 100644 --- a/libavcodec/h2645_sei.h +++ b/libavcodec/h2645_sei.h @@ -50,6 +50,10 @@ typedef struct HEVCSEIDynamicHDRVivid { AVBufferRef *info; } HEVCSEIDynamicHDRVivid; +typedef struct HEVCSEILCEVC { + AVBufferRef *info; +} HEVCSEILCEVC; + typedef struct H2645SEIUnregistered { AVBufferRef **buf_ref; unsigned nb_buf_ref; @@ -126,15 +130,18 @@ typedef struct H2645SEI { H2645SEIAFD afd; HEVCSEIDynamicHDRPlus dynamic_hdr_plus; //< HEVC only HEVCSEIDynamicHDRVivid dynamic_hdr_vivid; //< HEVC only + HEVCSEILCEVC lcevc; H2645SEIUnregistered unregistered; H2645SEIFramePacking frame_packing; H2645SEIDisplayOrientation display_orientation; H2645SEIAlternativeTransfer alternative_transfer; - H2645SEIFilmGrainCharacteristics film_grain_characteristics; H2645SEIAmbientViewingEnvironment ambient_viewing_environment; H2645SEIMasteringDisplay mastering_display; H2645SEIContentLight content_light; AVFilmGrainAFGS1Params aom_film_grain; + + // Dynamic allocations due to large size. + H2645SEIFilmGrainCharacteristics *film_grain_characteristics; } H2645SEI; enum { @@ -168,4 +175,6 @@ int ff_h2645_sei_to_frame(AVFrame *frame, H2645SEI *sei, unsigned bit_depth_luma, unsigned bit_depth_chroma, int seed); +int ff_h2645_sei_to_context(AVCodecContext *avctx, H2645SEI *sei); + #endif /* AVCODEC_H2645_SEI_H */ diff --git a/libavcodec/h264_parse.c b/libavcodec/h264_parse.c index 3378650fd..c6f9b3cea 100644 --- a/libavcodec/h264_parse.c +++ b/libavcodec/h264_parse.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "bytestream.h" #include "get_bits.h" #include "golomb.h" @@ -367,9 +368,10 @@ static int decode_extradata_ps(const uint8_t *data, int size, H264ParamSets *ps, int is_avc, void *logctx) { H2645Packet pkt = { 0 }; + int flags = (H2645_FLAG_IS_NALFF * !!is_avc) | H2645_FLAG_SMALL_PADDING; int i, ret = 0; - ret = ff_h2645_packet_split(&pkt, data, size, logctx, is_avc, 2, AV_CODEC_ID_H264, 1, 0); + ret = ff_h2645_packet_split(&pkt, data, size, logctx, 2, AV_CODEC_ID_H264, flags); if (ret < 0) { ret = 0; goto fail; @@ -468,7 +470,7 @@ int ff_h264_decode_extradata(const uint8_t *data, int size, H264ParamSets *ps, int ret; if (!data || size <= 0) - return -1; + return AVERROR(EINVAL); if (data[0] == 1) { int i, cnt, nalsize; diff --git a/libavcodec/h264_parse.h b/libavcodec/h264_parse.h index 4ee863df6..3481451c1 100644 --- a/libavcodec/h264_parse.h +++ b/libavcodec/h264_parse.h @@ -33,7 +33,7 @@ #include "get_bits.h" #include "h264_ps.h" -#define MB_TYPE_REF0 MB_TYPE_ACPRED // dirty but it fits in 16 bit +#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 diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index 9bc7b2098..5eb285506 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -38,8 +38,7 @@ static void pic_as_field(H264Ref *pic, const int parity) { - int i; - for (i = 0; i < FF_ARRAY_ELEMS(pic->data); ++i) { + for (int i = 0; i < FF_ARRAY_ELEMS(pic->data); ++i) { if (parity == PICT_BOTTOM_FIELD) pic->data[i] += pic->linesize[i]; pic->reference = parity; @@ -104,13 +103,12 @@ static int build_def_list(H264Ref *def, int def_len, static int add_sorted(H264Picture **sorted, H264Picture * const *src, int len, int limit, int dir) { - int i, best_poc; int out_i = 0; for (;;) { - best_poc = dir ? INT_MIN : INT_MAX; + int best_poc = dir ? INT_MIN : INT_MAX; - for (i = 0; i < len; i++) { + for (int i = 0; i < len; i++) { const int poc = src[i]->poc; if (((poc > limit) ^ dir) && ((poc < best_poc) ^ dir)) { best_poc = poc; @@ -134,12 +132,11 @@ static int mismatches_ref(const H264Context *h, const H264Picture *pic) static void h264_initialise_ref_list(H264Context *h, H264SliceContext *sl) { - int i, len; - int j; + int len; if (sl->slice_type_nos == AV_PICTURE_TYPE_B) { H264Picture *sorted[32]; - int cur_poc, list; + int cur_poc; int lens[2]; if (FIELD_PICTURE(h)) @@ -147,7 +144,7 @@ static void h264_initialise_ref_list(H264Context *h, H264SliceContext *sl) else cur_poc = h->cur_pic_ptr->poc; - for (list = 0; list < 2; list++) { + for (int list = 0; list < 2; list++) { len = add_sorted(sorted, h->short_ref, h->short_ref_count, cur_poc, 1 ^ list); len += add_sorted(sorted + len, h->short_ref, h->short_ref_count, cur_poc, 0 ^ list); av_assert0(len <= 32); @@ -165,6 +162,7 @@ static void h264_initialise_ref_list(H264Context *h, H264SliceContext *sl) } if (lens[0] == lens[1] && lens[1] > 1) { + int i; for (i = 0; i < lens[0] && sl->ref_list[0][i].parent->f->buf[0]->buffer == sl->ref_list[1][i].parent->f->buf[0]->buffer; i++); @@ -184,14 +182,14 @@ static void h264_initialise_ref_list(H264Context *h, H264SliceContext *sl) memset(&sl->ref_list[0][len], 0, sizeof(H264Ref) * (sl->ref_count[0] - len)); } #ifdef TRACE - for (i = 0; i < sl->ref_count[0]; i++) { + for (int i = 0; i < sl->ref_count[0]; i++) { ff_tlog(h->avctx, "List0: %s fn:%d 0x%p\n", (sl->ref_list[0][i].parent ? (sl->ref_list[0][i].parent->long_ref ? "LT" : "ST") : "??"), sl->ref_list[0][i].pic_id, sl->ref_list[0][i].data[0]); } if (sl->slice_type_nos == AV_PICTURE_TYPE_B) { - for (i = 0; i < sl->ref_count[1]; i++) { + for (int i = 0; i < sl->ref_count[1]; i++) { ff_tlog(h->avctx, "List1: %s fn:%d 0x%p\n", (sl->ref_list[1][i].parent ? (sl->ref_list[1][i].parent->long_ref ? "LT" : "ST") : "??"), sl->ref_list[1][i].pic_id, @@ -200,8 +198,8 @@ static void h264_initialise_ref_list(H264Context *h, H264SliceContext *sl) } #endif - for (j = 0; j<1+(sl->slice_type_nos == AV_PICTURE_TYPE_B); j++) { - for (i = 0; i < sl->ref_count[j]; i++) { + for (int j = 0; j < 1 + (sl->slice_type_nos == AV_PICTURE_TYPE_B); j++) { + for (int i = 0; i < sl->ref_count[j]; i++) { if (sl->ref_list[j][i].parent) { if (mismatches_ref(h, sl->ref_list[j][i].parent)) { av_log(h->avctx, AV_LOG_ERROR, "Discarding mismatching reference\n"); @@ -210,7 +208,7 @@ static void h264_initialise_ref_list(H264Context *h, H264SliceContext *sl) } } } - for (i = 0; i < sl->list_count; i++) + for (int i = 0; i < sl->list_count; i++) h->default_ref[i] = sl->ref_list[i][0]; } @@ -219,10 +217,9 @@ static void h264_initialise_ref_list(H264Context *h, H264SliceContext *sl) */ static void print_short_term(const H264Context *h) { - uint32_t i; if (h->avctx->debug & FF_DEBUG_MMCO) { av_log(h->avctx, AV_LOG_DEBUG, "short term list:\n"); - for (i = 0; i < h->short_ref_count; i++) { + for (uint32_t i = 0; i < h->short_ref_count; i++) { H264Picture *pic = h->short_ref[i]; av_log(h->avctx, AV_LOG_DEBUG, "%"PRIu32" fn:%d poc:%d %p\n", i, pic->frame_num, pic->poc, pic->f->data[0]); @@ -235,10 +232,9 @@ static void print_short_term(const H264Context *h) */ static void print_long_term(const H264Context *h) { - uint32_t i; if (h->avctx->debug & FF_DEBUG_MMCO) { av_log(h->avctx, AV_LOG_DEBUG, "long term list:\n"); - for (i = 0; i < 16; i++) { + for (uint32_t i = 0; i < 16; i++) { H264Picture *pic = h->long_ref[i]; if (pic) { av_log(h->avctx, AV_LOG_DEBUG, "%"PRIu32" fn:%d poc:%d %p\n", @@ -273,22 +269,21 @@ static int pic_num_extract(const H264Context *h, int pic_num, int *structure) static void h264_fill_mbaff_ref_list(H264SliceContext *sl) { - int list, i, j; - for (list = 0; list < sl->list_count; list++) { - for (i = 0; i < sl->ref_count[list]; i++) { + for (int list = 0; list < sl->list_count; list++) { + for (int i = 0; i < sl->ref_count[list]; i++) { const H264Ref *frame = &sl->ref_list[list][i]; H264Ref *field = &sl->ref_list[list][16 + 2 * i]; field[0] = *frame; - for (j = 0; j < 3; j++) + for (int j = 0; j < 3; j++) field[0].linesize[j] <<= 1; field[0].reference = PICT_TOP_FIELD; field[0].poc = field[0].parent->field_poc[0]; field[1] = field[0]; - for (j = 0; j < 3; j++) + for (int j = 0; j < 3; j++) field[1].data[j] += frame->parent->f->linesize[j]; field[1].reference = PICT_BOTTOM_FIELD; field[1].poc = field[1].parent->field_poc[1]; @@ -298,21 +293,19 @@ static void h264_fill_mbaff_ref_list(H264SliceContext *sl) int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) { - int list, index, pic_structure; - print_short_term(h); print_long_term(h); h264_initialise_ref_list(h, sl); - for (list = 0; list < sl->list_count; list++) { + for (int list = 0; list < sl->list_count; list++) { int pred = sl->curr_pic_num; - for (index = 0; index < sl->nb_ref_modifications[list]; index++) { + for (int index = 0; index < sl->nb_ref_modifications[list]; index++) { unsigned int modification_of_pic_nums_idc = sl->ref_modifications[list][index].op; unsigned int val = sl->ref_modifications[list][index].val; unsigned int pic_id; - int i; + int i, pic_structure; H264Picture *ref = NULL; switch (modification_of_pic_nums_idc) { @@ -396,13 +389,13 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) } } } - for (list = 0; list < sl->list_count; list++) { - for (index = 0; index < sl->ref_count[list]; index++) { + for (int list = 0; list < sl->list_count; list++) { + 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)) { - int i; av_log(h->avctx, AV_LOG_ERROR, "Missing reference picture, default is %d\n", h->default_ref[list].poc); - for (i = 0; i < FF_ARRAY_ELEMS(h->last_pocs); i++) + + for (int i = 0; i < FF_ARRAY_ELEMS(h->last_pocs); i++) h->last_pocs[i] = INT_MIN; if (h->default_ref[list].parent && !(!FIELD_PICTURE(h) && (h->default_ref[list].reference&3) != 3)) @@ -433,16 +426,14 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) int ff_h264_decode_ref_pic_list_reordering(H264SliceContext *sl, void *logctx) { - int list, index; - sl->nb_ref_modifications[0] = 0; sl->nb_ref_modifications[1] = 0; - for (list = 0; list < sl->list_count; list++) { + for (int list = 0; list < sl->list_count; list++) { if (!get_bits1(&sl->gb)) // ref_pic_list_modification_flag_l[01] continue; - for (index = 0; ; index++) { + for (int index = 0; ; index++) { unsigned int op = get_ue_golomb_31(&sl->gb); if (op == 3) @@ -479,11 +470,10 @@ int ff_h264_decode_ref_pic_list_reordering(H264SliceContext *sl, void *logctx) */ static inline int unreference_pic(H264Context *h, H264Picture *pic, int refmask) { - int i; if (pic->reference &= refmask) { return 0; } else { - for(i = 0; h->delayed_pic[i]; i++) + for (int i = 0; h->delayed_pic[i]; i++) if(pic == h->delayed_pic[i]){ pic->reference = DELAYED_PIC_REF; break; @@ -502,9 +492,7 @@ static inline int unreference_pic(H264Context *h, H264Picture *pic, int refmask) */ static H264Picture *find_short(H264Context *h, int frame_num, int *idx) { - int i; - - for (i = 0; i < h->short_ref_count; i++) { + for (int i = 0; i < h->short_ref_count; i++) { H264Picture *pic = h->short_ref[i]; if (h->avctx->debug & FF_DEBUG_MMCO) av_log(h->avctx, AV_LOG_DEBUG, "%d %d %p\n", i, pic->frame_num, pic); @@ -575,11 +563,8 @@ static H264Picture *remove_long(H264Context *h, int i, int ref_mask) void ff_h264_remove_all_refs(H264Context *h) { - int i; - - for (i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) remove_long(h, i, 0); - } assert(h->long_ref_count == 0); if (h->short_ref_count && !h->last_pic_for_ec.f->data[0]) { @@ -587,7 +572,7 @@ void ff_h264_remove_all_refs(H264Context *h) ff_h264_ref_picture(&h->last_pic_for_ec, h->short_ref[0]); } - for (i = 0; i < h->short_ref_count; i++) { + for (int i = 0; i < h->short_ref_count; i++) { unreference_pic(h, h->short_ref[i], 0); h->short_ref[i] = NULL; } @@ -622,10 +607,8 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) { MMCO *mmco = h->mmco; int mmco_count; - int i, av_uninit(j); int pps_ref_count[2] = {0}; int current_ref_assigned = 0, err = 0; - H264Picture *av_uninit(pic); if (!h->ps.sps) { av_log(h->avctx, AV_LOG_ERROR, "SPS is unset\n"); @@ -640,16 +623,18 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) if ((h->avctx->debug & FF_DEBUG_MMCO) && mmco_count == 0) av_log(h->avctx, AV_LOG_DEBUG, "no mmco here\n"); - for (i = 0; i < mmco_count; i++) { - int av_uninit(structure), av_uninit(frame_num); + for (int i = 0; i < mmco_count; i++) { if (h->avctx->debug & FF_DEBUG_MMCO) av_log(h->avctx, AV_LOG_DEBUG, "mmco:%d %d %d\n", h->mmco[i].opcode, h->mmco[i].short_pic_num, h->mmco[i].long_arg); - if (mmco[i].opcode == MMCO_SHORT2UNUSED || - mmco[i].opcode == MMCO_SHORT2LONG) { - frame_num = pic_num_extract(h, mmco[i].short_pic_num, &structure); - pic = find_short(h, frame_num, &j); + switch (mmco[i].opcode) { + case MMCO_SHORT2UNUSED: + case MMCO_SHORT2LONG: { + int structure, j; + int frame_num = pic_num_extract(h, mmco[i].short_pic_num, &structure); + H264Picture *pic = find_short(h, frame_num, &j); + if (!pic) { if (mmco[i].opcode != MMCO_SHORT2LONG || !h->long_ref[mmco[i].long_arg] || @@ -659,16 +644,12 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) } continue; } - } - - switch (mmco[i].opcode) { - case MMCO_SHORT2UNUSED: - if (h->avctx->debug & FF_DEBUG_MMCO) - av_log(h->avctx, AV_LOG_DEBUG, "mmco: unref short %d count %d\n", - h->mmco[i].short_pic_num, h->short_ref_count); - remove_short(h, frame_num, structure ^ PICT_FRAME); - break; - case MMCO_SHORT2LONG: + if (mmco[i].opcode == MMCO_SHORT2UNUSED) { + if (h->avctx->debug & FF_DEBUG_MMCO) + av_log(h->avctx, AV_LOG_DEBUG, "mmco: unref short %d count %d\n", + h->mmco[i].short_pic_num, h->short_ref_count); + remove_short(h, frame_num, structure ^ PICT_FRAME); + } else { if (h->long_ref[mmco[i].long_arg] != pic) remove_long(h, mmco[i].long_arg, 0); @@ -678,15 +659,18 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) h->long_ref[mmco[i].long_arg]->long_ref = 1; h->long_ref_count++; } + } break; - case MMCO_LONG2UNUSED: - j = pic_num_extract(h, mmco[i].long_arg, &structure); - pic = h->long_ref[j]; + } + case MMCO_LONG2UNUSED: { + int structure, j = pic_num_extract(h, mmco[i].long_arg, &structure); + H264Picture *pic = h->long_ref[j]; if (pic) { remove_long(h, j, structure ^ PICT_FRAME); } else if (h->avctx->debug & FF_DEBUG_MMCO) av_log(h->avctx, AV_LOG_DEBUG, "mmco: unref long failure\n"); break; + } case MMCO_LONG: // Comment below left from previous code as it is an interesting note. /* First field in pair is in short term list or @@ -702,7 +686,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) /* make sure the current picture is not already assigned as a long ref */ if (h->cur_pic_ptr->long_ref) { - for (j = 0; j < FF_ARRAY_ELEMS(h->long_ref); j++) { + for (int j = 0; j < FF_ARRAY_ELEMS(h->long_ref); j++) { if (h->long_ref[j] == h->cur_pic_ptr) { if (j != mmco[i].long_arg) av_log(h->avctx, AV_LOG_ERROR, "mmco: cannot assign current picture to 2 long term references\n"); @@ -726,21 +710,19 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) case MMCO_SET_MAX_LONG: assert(mmco[i].long_arg <= 16); // just remove the long term which index is greater than new max - for (j = mmco[i].long_arg; j < 16; j++) { + for (int j = mmco[i].long_arg; j < 16; j++) remove_long(h, j, 0); - } break; case MMCO_RESET: while (h->short_ref_count) { remove_short(h, h->short_ref[0]->frame_num, 0); } - for (j = 0; j < 16; j++) { + for (int j = 0; j < 16; j++) remove_long(h, j, 0); - } h->poc.frame_num = h->cur_pic_ptr->frame_num = 0; h->mmco_reset = 1; h->cur_pic_ptr->mmco_reset = 1; - for (j = 0; j < FF_ARRAY_ELEMS(h->last_pocs); j++) + for (int j = 0; j < FF_ARRAY_ELEMS(h->last_pocs); j++) h->last_pocs[j] = INT_MIN; break; default: av_assert0(0); @@ -764,7 +746,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) "(first field is long term)\n"); err = AVERROR_INVALIDDATA; } else { - pic = remove_short(h, h->cur_pic_ptr->frame_num, 0); + H264Picture *pic = remove_short(h, h->cur_pic_ptr->frame_num, 0); if (pic) { av_log(h->avctx, AV_LOG_ERROR, "illegal short term buffer state detected\n"); err = AVERROR_INVALIDDATA; @@ -793,6 +775,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) err = AVERROR_INVALIDDATA; if (h->long_ref_count && !h->short_ref_count) { + int i; for (i = 0; i < 16; ++i) if (h->long_ref[i]) break; @@ -800,15 +783,15 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) assert(i < 16); remove_long(h, i, 0); } else { - pic = h->short_ref[h->short_ref_count - 1]; + H264Picture *pic = h->short_ref[h->short_ref_count - 1]; remove_short(h, pic->frame_num, 0); } } - for (i = 0; ishort_ref_count; i++) { - pic = h->short_ref[i]; + for (int i = 0; i < h->short_ref_count; i++) { + H264Picture *pic = h->short_ref[i]; if (pic->invalid_gap) { - int d = av_mod_uintp2(h->cur_pic_ptr->frame_num - pic->frame_num, h->ps.sps->log2_max_frame_num); + int d = av_zero_extend(h->cur_pic_ptr->frame_num - pic->frame_num, h->ps.sps->log2_max_frame_num); if (d > h->ps.sps->ref_frame_count) remove_short(h, pic->frame_num, 0); } @@ -817,7 +800,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) print_short_term(h); print_long_term(h); - for (i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) { + for (int i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) { if (h->ps.pps_list[i]) { const PPS *pps = h->ps.pps_list[i]; pps_ref_count[0] = FFMAX(pps_ref_count[0], pps->ref_count[0]); @@ -845,7 +828,6 @@ out: int ff_h264_decode_ref_pic_marking(H264SliceContext *sl, GetBitContext *gb, const H2645NAL *nal, void *logctx) { - int i; MMCO *mmco = sl->mmco; int nb_mmco = 0; @@ -860,6 +842,7 @@ int ff_h264_decode_ref_pic_marking(H264SliceContext *sl, GetBitContext *gb, } else { sl->explicit_ref_marking = get_bits1(gb); if (sl->explicit_ref_marking) { + int i; for (i = 0; i < FF_ARRAY_ELEMS(sl->mmco); i++) { MMCOOpcode opcode = get_ue_golomb_31(gb); diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 8d6dc7794..15a523220 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -55,7 +55,6 @@ void ff_h264_sei_uninit(H264SEIContext *h) h->picture_timing.present = 0; h->buffering_period.present = 0; h->common.frame_packing.present = 0; - h->common.film_grain_characteristics.present = 0; h->common.display_orientation.present = 0; h->common.afd.present = 0; diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 752735cc5..84595b1a8 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -28,6 +28,7 @@ #include "config_components.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/timecode.h" #include "decode.h" @@ -387,7 +388,6 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->width_from_caller = h1->width_from_caller; h->height_from_caller = h1->height_from_caller; - h->coded_picture_number = h1->coded_picture_number; h->first_field = h1->first_field; h->picture_structure = h1->picture_structure; h->mb_aff_frame = h1->mb_aff_frame; @@ -482,7 +482,7 @@ static int h264_frame_start(H264Context *h) if (!ff_thread_can_start_frame(h->avctx)) { av_log(h->avctx, AV_LOG_ERROR, "Attempt to start a frame outside SETUP state\n"); - return -1; + return AVERROR_BUG; } release_unused_pictures(h, 1); @@ -516,7 +516,10 @@ static int h264_frame_start(H264Context *h) pic->f->crop_top = h->crop_top; pic->f->crop_bottom = h->crop_bottom; - pic->needs_fg = h->sei.common.film_grain_characteristics.present && !h->avctx->hwaccel && + pic->needs_fg = + h->sei.common.film_grain_characteristics && + h->sei.common.film_grain_characteristics->present && + !h->avctx->hwaccel && !(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN); if ((ret = alloc_picture(h, pic)) < 0) @@ -1637,8 +1640,8 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl, h->valid_recovery_point = 1; if ( h->recovery_frame < 0 - || av_mod_uintp2(h->recovery_frame - h->poc.frame_num, h->ps.sps->log2_max_frame_num) > sei_recovery_frame_cnt) { - h->recovery_frame = av_mod_uintp2(h->poc.frame_num + sei_recovery_frame_cnt, h->ps.sps->log2_max_frame_num); + || av_zero_extend(h->recovery_frame - h->poc.frame_num, h->ps.sps->log2_max_frame_num) > sei_recovery_frame_cnt) { + h->recovery_frame = av_zero_extend(h->poc.frame_num + sei_recovery_frame_cnt, h->ps.sps->log2_max_frame_num); if (!h->valid_recovery_point) h->recovery_frame = h->poc.frame_num; diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index b4973fce2..0154fe17b 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -32,6 +32,7 @@ #include "libavutil/avassert.h" #include "libavutil/emms.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/thread.h" #include "libavutil/video_enc_params.h" @@ -611,8 +612,8 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) h->is_avc = 1; } - ret = ff_h2645_packet_split(&h->pkt, buf, buf_size, avctx, h->is_avc, h->nal_length_size, - avctx->codec_id, 0, 0); + ret = ff_h2645_packet_split(&h->pkt, buf, buf_size, avctx, h->nal_length_size, + avctx->codec_id, !!h->is_avc * H2645_FLAG_IS_NALFF); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error splitting the input into NAL units.\n"); @@ -978,7 +979,7 @@ static int finalize_frame(H264Context *h, AVFrame *dst, H264Picture *out, int *g *got_frame = 1; if (CONFIG_MPEGVIDEODEC) { - ff_print_debug_info2(h->avctx, dst, NULL, + ff_print_debug_info2(h->avctx, dst, out->mb_type, out->qscale_table, out->motion_val, @@ -993,30 +994,38 @@ static int send_next_delayed_frame(H264Context *h, AVFrame *dst_frame, int *got_frame, int buf_index) { int ret, i, out_idx; - H264Picture *out = h->delayed_pic[0]; + H264Picture *out; h->cur_pic_ptr = NULL; h->first_field = 0; - out_idx = 0; - for (i = 1; - h->delayed_pic[i] && - !(h->delayed_pic[i]->f->flags & AV_FRAME_FLAG_KEY) && - !h->delayed_pic[i]->mmco_reset; - i++) - if (h->delayed_pic[i]->poc < out->poc) { - out = h->delayed_pic[i]; - out_idx = i; + while (h->delayed_pic[0]) { + out = h->delayed_pic[0]; + out_idx = 0; + for (i = 1; + h->delayed_pic[i] && + !(h->delayed_pic[i]->f->flags & AV_FRAME_FLAG_KEY) && + !h->delayed_pic[i]->mmco_reset; + i++) + if (h->delayed_pic[i]->poc < out->poc) { + out = h->delayed_pic[i]; + out_idx = i; + } + + for (i = out_idx; h->delayed_pic[i]; i++) + h->delayed_pic[i] = h->delayed_pic[i + 1]; + + if (out) { + h->frame_recovered |= out->recovered; + out->recovered |= h->frame_recovered & FRAME_RECOVERED_SEI; + + out->reference &= ~DELAYED_PIC_REF; + ret = finalize_frame(h, dst_frame, out, got_frame); + if (ret < 0) + return ret; + if (*got_frame) + break; } - - for (i = out_idx; h->delayed_pic[i]; i++) - h->delayed_pic[i] = h->delayed_pic[i + 1]; - - if (out) { - out->reference &= ~DELAYED_PIC_REF; - ret = finalize_frame(h, dst_frame, out, got_frame); - if (ret < 0) - return ret; } return buf_index; @@ -1155,7 +1164,7 @@ const FFCodec ff_h264_decoder = { NULL }, .caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING | - FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP, + FF_CODEC_CAP_INIT_CLEANUP, .flush = h264_decode_flush, UPDATE_THREAD_CONTEXT(ff_h264_update_thread_context), UPDATE_THREAD_CONTEXT_FOR_USER(ff_h264_update_thread_context_for_user), diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 447c2499d..ccd7583bf 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -93,6 +93,14 @@ #define IS_REF0(a) ((a) & MB_TYPE_REF0) #define IS_8x8DCT(a) ((a) & MB_TYPE_8x8DCT) +#define IS_SUB_8X8(a) ((a) & MB_TYPE_16x16) // note reused +#define IS_SUB_8X4(a) ((a) & MB_TYPE_16x8) // note reused +#define IS_SUB_4X8(a) ((a) & MB_TYPE_8x16) // note reused +#define IS_SUB_4X4(a) ((a) & MB_TYPE_8x8) // note reused +#define IS_DIR(a, part, list) ((a) & (MB_TYPE_P0L0 << ((part) + 2 * (list)))) + +// does this mb use listX, note does not work if subMBs +#define USES_LIST(a, list) ((a) & ((MB_TYPE_P0L0 | MB_TYPE_P1L0) << (2 * (list)))) /** * Memory management control operation. @@ -356,7 +364,6 @@ typedef struct H264Context { int chroma_x_shift, chroma_y_shift; int droppable; - int coded_picture_number; int context_initialized; int flags; diff --git a/libavcodec/h264dsp.c b/libavcodec/h264dsp.c index 4d2ee10ba..1ba936be1 100644 --- a/libavcodec/h264dsp.c +++ b/libavcodec/h264dsp.c @@ -158,6 +158,8 @@ av_cold void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, ff_h264dsp_init_arm(c, bit_depth, chroma_format_idc); #elif ARCH_PPC 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 ff_h264dsp_init_x86(c, bit_depth, chroma_format_idc); #elif ARCH_MIPS diff --git a/libavcodec/h264dsp.h b/libavcodec/h264dsp.h index e0880c4d8..4a9cb1568 100644 --- a/libavcodec/h264dsp.h +++ b/libavcodec/h264dsp.h @@ -125,6 +125,8 @@ void ff_h264dsp_init_arm(H264DSPContext *c, const int bit_depth, const int chroma_format_idc); void ff_h264dsp_init_ppc(H264DSPContext *c, const int bit_depth, const int chroma_format_idc); +void ff_h264dsp_init_riscv(H264DSPContext *c, const int bit_depth, + const int chroma_format_idc); void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth, const int chroma_format_idc); void ff_h264dsp_init_mips(H264DSPContext *c, const int bit_depth, diff --git a/libavcodec/hap.c b/libavcodec/hap.c index 1a330c9c9..ac4032ce1 100644 --- a/libavcodec/hap.c +++ b/libavcodec/hap.c @@ -23,6 +23,7 @@ * @file * Hap utilities */ +#include "libavutil/mem.h" #include "hap.h" int ff_hap_set_chunk_count(HapContext *ctx, int count, int first_in_frame) diff --git a/libavcodec/hapdec.c b/libavcodec/hapdec.c index 6066cb814..70bf592f2 100644 --- a/libavcodec/hapdec.c +++ b/libavcodec/hapdec.c @@ -34,6 +34,7 @@ #include #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" @@ -309,6 +310,7 @@ static int hap_decode(AVCodecContext *avctx, AVFrame *frame, ret = av_reallocp(&ctx->tex_buf, ctx->tex_size); if (ret < 0) return ret; + memset(ctx->tex_buf, 0, ctx->tex_size); avctx->execute2(avctx, decompress_chunks_thread, NULL, ctx->chunk_results, ctx->chunk_count); @@ -329,8 +331,6 @@ static int hap_decode(AVCodecContext *avctx, AVFrame *frame, } /* Frame is ready to be output */ - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/hapenc.c b/libavcodec/hapenc.c index 3f74098d1..8dc12a851 100644 --- a/libavcodec/hapenc.c +++ b/libavcodec/hapenc.c @@ -34,7 +34,7 @@ #include "libavutil/frame.h" #include "libavutil/imgutils.h" -#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" diff --git a/libavcodec/hcadec.c b/libavcodec/hcadec.c index 88146c7cd..e8f877c3c 100644 --- a/libavcodec/hcadec.c +++ b/libavcodec/hcadec.c @@ -18,6 +18,7 @@ #include "libavutil/crc.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/tx.h" diff --git a/libavcodec/hcom.c b/libavcodec/hcom.c index 9284cd11c..d08033099 100644 --- a/libavcodec/hcom.c +++ b/libavcodec/hcom.c @@ -19,6 +19,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/hdrdec.c b/libavcodec/hdrdec.c index 9b6395bb6..b7ade48e3 100644 --- a/libavcodec/hdrdec.c +++ b/libavcodec/hdrdec.c @@ -212,9 +212,6 @@ convert: } } - p->flags |= AV_FRAME_FLAG_KEY; - p->pict_type = AV_PICTURE_TYPE_I; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/hdrenc.c b/libavcodec/hdrenc.c index 54682d0a7..a7bf36946 100644 --- a/libavcodec/hdrenc.c +++ b/libavcodec/hdrenc.c @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/hevc/Makefile b/libavcodec/hevc/Makefile new file mode 100644 index 000000000..93ed4213f --- /dev/null +++ b/libavcodec/hevc/Makefile @@ -0,0 +1,28 @@ +clean:: + $(RM) $(CLEANSUFFIXES:%=libavcodec/hevc/%) + +OBJS-$(CONFIG_HEVC_DECODER) += \ + hevc/cabac.o \ + hevc/data.o \ + hevc/dsp.o \ + hevc/filter.o \ + hevc/hevcdec.o \ + hevc/mvs.o \ + hevc/pred.o \ + hevc/refs.o \ + +OBJS-$(CONFIG_HEVC_PARSER) += \ + hevc/parser.o \ + + +OBJS-$(CONFIG_HEVCPARSE) += \ + hevc/data.o \ + hevc/parse.o \ + hevc/ps.o \ + + +OBJS-$(CONFIG_HEVC_SEI) += \ + hevc/sei.o \ + + +libavcodec/hevc/%.o: CPPFLAGS += -I$(SRC_PATH)/libavcodec/ diff --git a/libavcodec/hevc_cabac.c b/libavcodec/hevc/cabac.c similarity index 88% rename from libavcodec/hevc_cabac.c rename to libavcodec/hevc/cabac.c index 63ffb3d37..892dd1c21 100644 --- a/libavcodec/hevc_cabac.c +++ b/libavcodec/hevc/cabac.c @@ -25,7 +25,7 @@ #include "libavutil/common.h" #include "cabac_functions.h" -#include "hevc_data.h" +#include "data.h" #include "hevc.h" #include "hevcdec.h" @@ -399,25 +399,25 @@ static const uint8_t diag_scan8x8_inv[8][8] = { { 28, 36, 43, 49, 54, 58, 61, 63, }, }; -void ff_hevc_save_states(HEVCLocalContext *lc, int ctb_addr_ts) +void ff_hevc_save_states(HEVCLocalContext *lc, const HEVCPPS *pps, + int ctb_addr_ts) { - const HEVCContext *const s = lc->parent; - - if (s->ps.pps->entropy_coding_sync_enabled_flag && - (ctb_addr_ts % s->ps.sps->ctb_width == 2 || - (s->ps.sps->ctb_width == 2 && - ctb_addr_ts % s->ps.sps->ctb_width == 0))) { + const HEVCSPS *const sps = pps->sps; + if (pps->entropy_coding_sync_enabled_flag && + (ctb_addr_ts % sps->ctb_width == 2 || + (sps->ctb_width == 2 && + ctb_addr_ts % sps->ctb_width == 0))) { memcpy(lc->common_cabac_state->state, lc->cabac_state, HEVC_CONTEXTS); - if (s->ps.sps->persistent_rice_adaptation_enabled_flag) { + if (sps->persistent_rice_adaptation_enabled) { memcpy(lc->common_cabac_state->stat_coeff, lc->stat_coeff, HEVC_STAT_COEFFS); } } } -static void load_states(HEVCLocalContext *lc, const HEVCContext *s) +static void load_states(HEVCLocalContext *lc, const HEVCSPS *sps) { memcpy(lc->cabac_state, lc->common_cabac_state->state, HEVC_CONTEXTS); - if (s->ps.sps->persistent_rice_adaptation_enabled_flag) { + if (sps->persistent_rice_adaptation_enabled) { memcpy(lc->stat_coeff, lc->common_cabac_state->stat_coeff, HEVC_STAT_COEFFS); } } @@ -427,16 +427,6 @@ static int cabac_reinit(HEVCLocalContext *lc) return skip_bytes(&lc->cc, 0) == NULL ? AVERROR_INVALIDDATA : 0; } -static int cabac_init_decoder(HEVCLocalContext *lc) -{ - GetBitContext *gb = &lc->gb; - skip_bits(gb, 1); - align_get_bits(gb); - return ff_init_cabac_decoder(&lc->cc, - gb->buffer + get_bits_count(gb) / 8, - (get_bits_left(gb) + 7) / 8); -} - static void cabac_init_state(HEVCLocalContext *lc, const HEVCContext *s) { int init_type = 2 - s->sh.slice_type; @@ -461,57 +451,60 @@ static void cabac_init_state(HEVCLocalContext *lc, const HEVCContext *s) lc->stat_coeff[i] = 0; } -int ff_hevc_cabac_init(HEVCLocalContext *lc, int ctb_addr_ts) +int ff_hevc_cabac_init(HEVCLocalContext *lc, const HEVCPPS *pps, + int ctb_addr_ts, const uint8_t *data, size_t size, + int is_wpp) { const HEVCContext *const s = lc->parent; + const HEVCSPS *const sps = pps->sps; - if (ctb_addr_ts == s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]) { - int ret = cabac_init_decoder(lc); + if (ctb_addr_ts == pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]) { + int ret = ff_init_cabac_decoder(&lc->cc, data, size); if (ret < 0) return ret; if (s->sh.dependent_slice_segment_flag == 0 || - (s->ps.pps->tiles_enabled_flag && - s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[ctb_addr_ts - 1])) + (pps->tiles_enabled_flag && + pps->tile_id[ctb_addr_ts] != pps->tile_id[ctb_addr_ts - 1])) cabac_init_state(lc, s); if (!s->sh.first_slice_in_pic_flag && - s->ps.pps->entropy_coding_sync_enabled_flag) { - if (ctb_addr_ts % s->ps.sps->ctb_width == 0) { - if (s->ps.sps->ctb_width == 1) + pps->entropy_coding_sync_enabled_flag) { + if (ctb_addr_ts % sps->ctb_width == 0) { + if (sps->ctb_width == 1) cabac_init_state(lc, s); else if (s->sh.dependent_slice_segment_flag == 1) - load_states(lc, s); + load_states(lc, sps); } } } else { - if (s->ps.pps->tiles_enabled_flag && - s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[ctb_addr_ts - 1]) { + if (pps->tiles_enabled_flag && + pps->tile_id[ctb_addr_ts] != pps->tile_id[ctb_addr_ts - 1]) { int ret; - if (s->threads_number == 1) + if (!is_wpp) ret = cabac_reinit(lc); else { - ret = cabac_init_decoder(lc); + ret = ff_init_cabac_decoder(&lc->cc, data, size); } if (ret < 0) return ret; cabac_init_state(lc, s); } - if (s->ps.pps->entropy_coding_sync_enabled_flag) { - if (ctb_addr_ts % s->ps.sps->ctb_width == 0) { + if (pps->entropy_coding_sync_enabled_flag) { + if (ctb_addr_ts % sps->ctb_width == 0) { int ret; get_cabac_terminate(&lc->cc); - if (s->threads_number == 1) + if (!is_wpp) ret = cabac_reinit(lc); else { - ret = cabac_init_decoder(lc); + ret = ff_init_cabac_decoder(&lc->cc, data, size); } if (ret < 0) return ret; - if (s->ps.sps->ctb_width == 1) + if (sps->ctb_width == 1) cabac_init_state(lc, s); else - load_states(lc, s); + load_states(lc, sps); } } } @@ -545,10 +538,10 @@ int ff_hevc_sao_band_position_decode(HEVCLocalContext *lc) return value; } -int ff_hevc_sao_offset_abs_decode(HEVCLocalContext *lc) +int ff_hevc_sao_offset_abs_decode(HEVCLocalContext *lc, int bit_depth) { int i = 0; - int length = (1 << (FFMIN(lc->parent->ps.sps->bit_depth, 10) - 5)) - 1; + int length = (1 << (FFMIN(bit_depth, 10) - 5)) - 1; while (i < length && get_cabac_bypass(&lc->cc)) i++; @@ -577,18 +570,15 @@ int ff_hevc_cu_transquant_bypass_flag_decode(HEVCLocalContext *lc) return GET_CABAC(CU_TRANSQUANT_BYPASS_FLAG_OFFSET); } -int ff_hevc_skip_flag_decode(HEVCLocalContext *lc, int x0, int y0, int x_cb, int y_cb) +int ff_hevc_skip_flag_decode(HEVCLocalContext *lc, uint8_t *skip_flag, + int x0, int y0, int x_cb, int y_cb, int min_cb_width) { - const HEVCContext *const s = lc->parent; - int min_cb_width = s->ps.sps->min_cb_width; int inc = 0; - int x0b = av_mod_uintp2(x0, s->ps.sps->log2_ctb_size); - int y0b = av_mod_uintp2(y0, s->ps.sps->log2_ctb_size); - if (lc->ctb_left_flag || x0b) - inc = !!SAMPLE_CTB(s->skip_flag, x_cb - 1, y_cb); - if (lc->ctb_up_flag || y0b) - inc += !!SAMPLE_CTB(s->skip_flag, x_cb, y_cb - 1); + if (lc->ctb_left_flag || x0) + inc = !!SAMPLE_CTB(skip_flag, x_cb - 1, y_cb); + if (lc->ctb_up_flag || y0) + inc += !!SAMPLE_CTB(skip_flag, x_cb, y_cb - 1); return GET_CABAC(SKIP_FLAG_OFFSET + inc); } @@ -630,9 +620,9 @@ int ff_hevc_cu_chroma_qp_offset_flag(HEVCLocalContext *lc) return GET_CABAC(CU_CHROMA_QP_OFFSET_FLAG_OFFSET); } -int ff_hevc_cu_chroma_qp_offset_idx(HEVCLocalContext *lc) +int ff_hevc_cu_chroma_qp_offset_idx(HEVCLocalContext *lc, int chroma_qp_offset_list_len_minus1) { - int c_max= FFMAX(5, lc->parent->ps.pps->chroma_qp_offset_list_len_minus1); + int c_max= FFMAX(5, chroma_qp_offset_list_len_minus1); int i = 0; while (i < c_max && GET_CABAC(CU_CHROMA_QP_OFFSET_IDX_OFFSET)) @@ -646,20 +636,20 @@ int ff_hevc_pred_mode_decode(HEVCLocalContext *lc) return GET_CABAC(PRED_MODE_FLAG_OFFSET); } -int ff_hevc_split_coding_unit_flag_decode(HEVCLocalContext *lc, int ct_depth, int x0, int y0) +int ff_hevc_split_coding_unit_flag_decode(HEVCLocalContext *lc, uint8_t *tab_ct_depth, + const HEVCSPS *sps, + int ct_depth, int x0, int y0) { - const HEVCContext *const s = lc->parent; - const HEVCSPS *const sps = s->ps.sps; int inc = 0, depth_left = 0, depth_top = 0; - int x0b = av_mod_uintp2(x0, sps->log2_ctb_size); - int y0b = av_mod_uintp2(y0, sps->log2_ctb_size); + int x0b = av_zero_extend(x0, sps->log2_ctb_size); + int y0b = av_zero_extend(y0, sps->log2_ctb_size); int x_cb = x0 >> sps->log2_min_cb_size; int y_cb = y0 >> sps->log2_min_cb_size; if (lc->ctb_left_flag || x0b) - depth_left = s->tab_ct_depth[(y_cb) * sps->min_cb_width + x_cb - 1]; + depth_left = tab_ct_depth[(y_cb) * sps->min_cb_width + x_cb - 1]; if (lc->ctb_up_flag || y0b) - depth_top = s->tab_ct_depth[(y_cb - 1) * sps->min_cb_width + x_cb]; + depth_top = tab_ct_depth[(y_cb - 1) * sps->min_cb_width + x_cb]; inc += (depth_left > ct_depth); inc += (depth_top > ct_depth); @@ -667,11 +657,11 @@ int ff_hevc_split_coding_unit_flag_decode(HEVCLocalContext *lc, int ct_depth, in return GET_CABAC(SPLIT_CODING_UNIT_FLAG_OFFSET + inc); } -int ff_hevc_part_mode_decode(HEVCLocalContext *lc, int log2_cb_size) +int ff_hevc_part_mode_decode(HEVCLocalContext *lc, const HEVCSPS *sps, int log2_cb_size) { if (GET_CABAC(PART_MODE_OFFSET)) // 1 return PART_2Nx2N; - if (log2_cb_size == lc->parent->ps.sps->log2_min_cb_size) { + if (log2_cb_size == sps->log2_min_cb_size) { if (lc->cu.pred_mode == MODE_INTRA) // 0 return PART_NxN; if (GET_CABAC(PART_MODE_OFFSET + 1)) // 01 @@ -683,7 +673,7 @@ int ff_hevc_part_mode_decode(HEVCLocalContext *lc, int log2_cb_size) return PART_NxN; // 000 } - if (!lc->parent->ps.sps->amp_enabled_flag) { + if (!sps->amp_enabled) { if (GET_CABAC(PART_MODE_OFFSET + 1)) // 01 return PART_2NxN; return PART_Nx2N; @@ -988,7 +978,8 @@ static av_always_inline int coeff_sign_flag_decode(HEVCLocalContext *lc, uint8_t return ret; } -void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, +void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps, + int x0, int y0, int log2_trafo_size, enum ScanType scan_idx, int c_idx) { @@ -998,6 +989,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, y_c = (y_cg << 2) + scan_y_off[n]; \ } while (0) const HEVCContext *const s = lc->parent; + const HEVCSPS *const sps = pps->sps; int transform_skip_flag = 0; int last_significant_coeff_x, last_significant_coeff_y; @@ -1011,11 +1003,11 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, const uint8_t *scan_x_cg, *scan_y_cg, *scan_x_off, *scan_y_off; - ptrdiff_t stride = s->frame->linesize[c_idx]; - int hshift = s->ps.sps->hshift[c_idx]; - int vshift = s->ps.sps->vshift[c_idx]; - uint8_t *dst = &s->frame->data[c_idx][(y0 >> vshift) * stride + - ((x0 >> hshift) << s->ps.sps->pixel_shift)]; + ptrdiff_t stride = s->cur_frame->f->linesize[c_idx]; + int hshift = sps->hshift[c_idx]; + int vshift = sps->vshift[c_idx]; + uint8_t *dst = &s->cur_frame->f->data[c_idx][(y0 >> vshift) * stride + + ((x0 >> hshift) << sps->pixel_shift)]; int16_t *coeffs = (int16_t*)(c_idx ? lc->edge_emu_buffer2 : lc->edge_emu_buffer); uint8_t significant_coeff_group_flag[8][8] = {{0}}; int explicit_rdpcm_flag = 0; @@ -1050,25 +1042,25 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, }; int qp_y = lc->qp_y; - if (s->ps.pps->transform_skip_enabled_flag && - log2_trafo_size <= s->ps.pps->log2_max_transform_skip_block_size) { + if (pps->transform_skip_enabled_flag && + log2_trafo_size <= pps->log2_max_transform_skip_block_size) { transform_skip_flag = hevc_transform_skip_flag_decode(lc, c_idx); } if (c_idx == 0) { - qp = qp_y + s->ps.sps->qp_bd_offset; + qp = qp_y + sps->qp_bd_offset; } else { int qp_i, offset; if (c_idx == 1) - offset = s->ps.pps->cb_qp_offset + s->sh.slice_cb_qp_offset + + offset = pps->cb_qp_offset + s->sh.slice_cb_qp_offset + lc->tu.cu_qp_offset_cb; else - offset = s->ps.pps->cr_qp_offset + s->sh.slice_cr_qp_offset + + offset = pps->cr_qp_offset + s->sh.slice_cr_qp_offset + lc->tu.cu_qp_offset_cr; - qp_i = av_clip(qp_y + offset, - s->ps.sps->qp_bd_offset, 57); - if (s->ps.sps->chroma_format_idc == 1) { + qp_i = av_clip(qp_y + offset, - sps->qp_bd_offset, 57); + if (sps->chroma_format_idc == 1) { if (qp_i < 30) qp = qp_i; else if (qp_i > 43) @@ -1082,18 +1074,18 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, qp = qp_i; } - qp += s->ps.sps->qp_bd_offset; + qp += sps->qp_bd_offset; } - shift = s->ps.sps->bit_depth + log2_trafo_size - 5; + shift = sps->bit_depth + log2_trafo_size - 5; add = 1 << (shift-1); scale = level_scale[rem6[qp]] << (div6[qp]); scale_m = 16; // default when no custom scaling lists. dc_scale = 16; - if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) { - const ScalingList *sl = s->ps.pps->scaling_list_data_present_flag ? - &s->ps.pps->scaling_list : &s->ps.sps->scaling_list; + if (sps->scaling_list_enabled && !(transform_skip_flag && log2_trafo_size > 2)) { + const ScalingList *sl = pps->scaling_list_data_present_flag ? + &pps->scaling_list : &sps->scaling_list; int matrix_id = lc->cu.pred_mode != MODE_INTRA; matrix_id = 3 * matrix_id + c_idx; @@ -1109,7 +1101,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, dc_scale = 0; } - if (lc->cu.pred_mode == MODE_INTER && s->ps.sps->explicit_rdpcm_enabled_flag && + if (lc->cu.pred_mode == MODE_INTER && sps->explicit_rdpcm_enabled && (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) { explicit_rdpcm_flag = explicit_rdpcm_flag_decode(lc, c_idx); if (explicit_rdpcm_flag) { @@ -1240,7 +1232,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, }; const uint8_t *ctx_idx_map_p; int scf_offset = 0; - if (s->ps.sps->transform_skip_context_enabled_flag && + if (sps->transform_skip_context_enabled && (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) { ctx_idx_map_p = &ctx_idx_map[4 * 16]; if (c_idx == 0) { @@ -1281,7 +1273,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, } } if (implicit_non_zero_coeff == 0) { - if (s->ps.sps->transform_skip_context_enabled_flag && + if (sps->transform_skip_context_enabled && (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) { if (c_idx == 0) { scf_offset = 42; @@ -1326,7 +1318,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, // initialize first elem of coeff_bas_level_greater1_flag int ctx_set = (i > 0 && c_idx == 0) ? 2 : 0; - if (s->ps.sps->persistent_rice_adaptation_enabled_flag) { + if (sps->persistent_rice_adaptation_enabled) { if (!transform_skip_flag && !lc->cu.cu_transquant_bypass_flag) sb_type = 2 * (c_idx == 0 ? 1 : 0); else @@ -1355,7 +1347,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, if (lc->cu.cu_transquant_bypass_flag || (lc->cu.pred_mode == MODE_INTRA && - s->ps.sps->implicit_rdpcm_enabled_flag && transform_skip_flag && + sps->implicit_rdpcm_enabled && transform_skip_flag && (pred_mode_intra == 10 || pred_mode_intra == 26 )) || explicit_rdpcm_flag) sign_hidden = 0; @@ -1365,7 +1357,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, if (first_greater1_coeff_idx != -1) { coeff_abs_level_greater1_flag[first_greater1_coeff_idx] += coeff_abs_level_greater2_flag_decode(lc, c_idx, ctx_set); } - if (!s->ps.pps->sign_data_hiding_flag || !sign_hidden ) { + if (!pps->sign_data_hiding_flag || !sign_hidden ) { coeff_sign_flag = coeff_sign_flag_decode(lc, nb_significant_coeff_flag) << (16 - nb_significant_coeff_flag); } else { coeff_sign_flag = coeff_sign_flag_decode(lc, nb_significant_coeff_flag - 1) << (16 - (nb_significant_coeff_flag - 1)); @@ -1381,8 +1373,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, trans_coeff_level += last_coeff_abs_level_remaining; if (trans_coeff_level > (3 << c_rice_param)) - c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4); - if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) { + c_rice_param = sps->persistent_rice_adaptation_enabled ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4); + if (sps->persistent_rice_adaptation_enabled && !rice_init) { int c_rice_p_init = lc->stat_coeff[sb_type] / 4; if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init)) lc->stat_coeff[sb_type]++; @@ -1397,8 +1389,8 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, trans_coeff_level = 1 + last_coeff_abs_level_remaining; if (trans_coeff_level > (3 << c_rice_param)) - c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4); - if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) { + c_rice_param = sps->persistent_rice_adaptation_enabled ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4); + if (sps->persistent_rice_adaptation_enabled && !rice_init) { int c_rice_p_init = lc->stat_coeff[sb_type] / 4; if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init)) lc->stat_coeff[sb_type]++; @@ -1408,7 +1400,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, rice_init = 1; } } - if (s->ps.pps->sign_data_hiding_flag && sign_hidden) { + if (pps->sign_data_hiding_flag && sign_hidden) { sum_abs += trans_coeff_level; if (n == first_nz_pos_in_cg && (sum_abs&1)) trans_coeff_level = -trans_coeff_level; @@ -1417,7 +1409,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, trans_coeff_level = -trans_coeff_level; coeff_sign_flag <<= 1; if(!lc->cu.cu_transquant_bypass_flag) { - if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) { + if (sps->scaling_list_enabled && !(transform_skip_flag && log2_trafo_size > 2)) { if(y_c || x_c || log2_trafo_size < 4) { switch(log2_trafo_size) { case 3: pos = (y_c << 3) + x_c; break; @@ -1445,15 +1437,15 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, } if (lc->cu.cu_transquant_bypass_flag) { - if (explicit_rdpcm_flag || (s->ps.sps->implicit_rdpcm_enabled_flag && + if (explicit_rdpcm_flag || (sps->implicit_rdpcm_enabled && (pred_mode_intra == 10 || pred_mode_intra == 26))) { - int mode = s->ps.sps->implicit_rdpcm_enabled_flag ? (pred_mode_intra == 26) : explicit_rdpcm_dir_flag; + int mode = sps->implicit_rdpcm_enabled ? (pred_mode_intra == 26) : explicit_rdpcm_dir_flag; s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode); } } else { if (transform_skip_flag) { - int rot = s->ps.sps->transform_skip_rotation_enabled_flag && + int rot = sps->transform_skip_rotation_enabled && log2_trafo_size == 2 && lc->cu.pred_mode == MODE_INTRA; if (rot) { @@ -1463,7 +1455,7 @@ void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, s->hevcdsp.dequant(coeffs, log2_trafo_size); - if (explicit_rdpcm_flag || (s->ps.sps->implicit_rdpcm_enabled_flag && + if (explicit_rdpcm_flag || (sps->implicit_rdpcm_enabled && lc->cu.pred_mode == MODE_INTRA && (pred_mode_intra == 10 || pred_mode_intra == 26))) { int mode = explicit_rdpcm_flag ? explicit_rdpcm_dir_flag : (pred_mode_intra == 26); diff --git a/libavcodec/hevc_data.c b/libavcodec/hevc/data.c similarity index 98% rename from libavcodec/hevc_data.c rename to libavcodec/hevc/data.c index 1633a41c1..8a4f74c3c 100644 --- a/libavcodec/hevc_data.c +++ b/libavcodec/hevc/data.c @@ -20,7 +20,7 @@ #include -#include "hevc_data.h" +#include "data.h" const uint8_t ff_hevc_diag_scan4x4_x[16] = { 0, 0, 1, 0, diff --git a/libavcodec/hevc_data.h b/libavcodec/hevc/data.h similarity index 100% rename from libavcodec/hevc_data.h rename to libavcodec/hevc/data.h diff --git a/libavcodec/hevcdsp.c b/libavcodec/hevc/dsp.c similarity index 99% rename from libavcodec/hevcdsp.c rename to libavcodec/hevc/dsp.c index 630fdc012..60f059292 100644 --- a/libavcodec/hevcdsp.c +++ b/libavcodec/hevc/dsp.c @@ -22,7 +22,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "hevcdsp.h" +#include "dsp.h" static const int8_t transform[32][32] = { { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, @@ -110,19 +110,19 @@ DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filters)[4][16] = { }; #define BIT_DEPTH 8 -#include "hevcdsp_template.c" +#include "dsp_template.c" #undef BIT_DEPTH #define BIT_DEPTH 9 -#include "hevcdsp_template.c" +#include "dsp_template.c" #undef BIT_DEPTH #define BIT_DEPTH 10 -#include "hevcdsp_template.c" +#include "dsp_template.c" #undef BIT_DEPTH #define BIT_DEPTH 12 -#include "hevcdsp_template.c" +#include "dsp_template.c" #undef BIT_DEPTH void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth) diff --git a/libavcodec/hevcdsp.h b/libavcodec/hevc/dsp.h similarity index 98% rename from libavcodec/hevcdsp.h rename to libavcodec/hevc/dsp.h index a5933dcac..02b8e0e8e 100644 --- a/libavcodec/hevcdsp.h +++ b/libavcodec/hevc/dsp.h @@ -22,12 +22,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_HEVCDSP_H -#define AVCODEC_HEVCDSP_H +#ifndef AVCODEC_HEVC_DSP_H +#define AVCODEC_HEVC_DSP_H #include "libavutil/mem_internal.h" -#include "get_bits.h" +#include "libavcodec/get_bits.h" #define MAX_PB_SIZE 64 @@ -137,4 +137,4 @@ 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); -#endif /* AVCODEC_HEVCDSP_H */ +#endif /* AVCODEC_HEVC_DSP_H */ diff --git a/libavcodec/hevcdsp_template.c b/libavcodec/hevc/dsp_template.c similarity index 99% rename from libavcodec/hevcdsp_template.c rename to libavcodec/hevc/dsp_template.c index 121c44c40..a0f79c267 100644 --- a/libavcodec/hevcdsp_template.c +++ b/libavcodec/hevc/dsp_template.c @@ -24,7 +24,7 @@ #include "hevcdec.h" #include "bit_depth_template.c" -#include "hevcdsp.h" +#include "dsp.h" #include "h26x/h2656_sao_template.c" #include "h26x/h2656_inter_template.c" @@ -302,8 +302,8 @@ IDCT_DC(32) //////////////////////////////////////////////////////////////////////////////// #define ff_hevc_pel_filters ff_hevc_qpel_filters #define DECL_HV_FILTER(f) \ - const uint8_t *hf = ff_hevc_ ## f ## _filters[mx]; \ - const uint8_t *vf = ff_hevc_ ## f ## _filters[my]; + const int8_t *hf = ff_hevc_ ## f ## _filters[mx]; \ + const int8_t *vf = ff_hevc_ ## f ## _filters[my]; #define FW_PUT(p, f, t) \ static void FUNC(put_hevc_## f)(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, \ diff --git a/libavcodec/hevc_filter.c b/libavcodec/hevc/filter.c similarity index 58% rename from libavcodec/hevc_filter.c rename to libavcodec/hevc/filter.c index 0c45310ea..68ae0e9ef 100644 --- a/libavcodec/hevc_filter.c +++ b/libavcodec/hevc/filter.c @@ -26,7 +26,7 @@ #include "libavutil/internal.h" #include "hevcdec.h" -#include "threadframe.h" +#include "progressframe.h" #define LUMA 0 #define CB 1 @@ -44,7 +44,8 @@ static const uint8_t betatable[52] = { 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64 // QP 38...51 }; -static int chroma_tc(const HEVCContext *s, int qp_y, int c_idx, int tc_offset) +static int chroma_tc(const HEVCPPS *pps, const HEVCSPS *sps, + int qp_y, int c_idx, int tc_offset) { static const int qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 @@ -53,12 +54,12 @@ static int chroma_tc(const HEVCContext *s, int qp_y, int c_idx, int tc_offset) // slice qp offset is not used for deblocking if (c_idx == 1) - offset = s->ps.pps->cb_qp_offset; + offset = pps->cb_qp_offset; else - offset = s->ps.pps->cr_qp_offset; + offset = pps->cr_qp_offset; qp_i = av_clip(qp_y + offset, 0, 57); - if (s->ps.sps->chroma_format_idc == 1) { + if (sps->chroma_format_idc == 1) { if (qp_i < 30) qp = qp_i; else if (qp_i > 43) @@ -74,16 +75,18 @@ static int chroma_tc(const HEVCContext *s, int qp_y, int c_idx, int tc_offset) } static int get_qPy_pred(HEVCLocalContext *lc, const HEVCContext *s, + const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, int xBase, int yBase, int log2_cb_size) { - int ctb_size_mask = (1 << s->ps.sps->log2_ctb_size) - 1; - int MinCuQpDeltaSizeMask = (1 << (s->ps.sps->log2_ctb_size - - s->ps.pps->diff_cu_qp_delta_depth)) - 1; + int ctb_size_mask = (1 << sps->log2_ctb_size) - 1; + int MinCuQpDeltaSizeMask = (1 << (sps->log2_ctb_size - + pps->diff_cu_qp_delta_depth)) - 1; int xQgBase = xBase - (xBase & MinCuQpDeltaSizeMask); int yQgBase = yBase - (yBase & MinCuQpDeltaSizeMask); - int min_cb_width = s->ps.sps->min_cb_width; - int x_cb = xQgBase >> s->ps.sps->log2_min_cb_size; - int y_cb = yQgBase >> s->ps.sps->log2_min_cb_size; + int min_cb_width = sps->min_cb_width; + int x_cb = xQgBase >> sps->log2_min_cb_size; + int y_cb = yQgBase >> sps->log2_min_cb_size; int availableA = (xBase & ctb_size_mask) && (xQgBase & ctb_size_mask); int availableB = (yBase & ctb_size_mask) && @@ -102,39 +105,42 @@ static int get_qPy_pred(HEVCLocalContext *lc, const HEVCContext *s, if (availableA == 0) qPy_a = qPy_pred; else - qPy_a = s->qp_y_tab[(x_cb - 1) + y_cb * min_cb_width]; + qPy_a = l->qp_y_tab[(x_cb - 1) + y_cb * min_cb_width]; // qPy_b if (availableB == 0) qPy_b = qPy_pred; else - qPy_b = s->qp_y_tab[x_cb + (y_cb - 1) * min_cb_width]; + qPy_b = l->qp_y_tab[x_cb + (y_cb - 1) * min_cb_width]; - av_assert2(qPy_a >= -s->ps.sps->qp_bd_offset && qPy_a < 52); - av_assert2(qPy_b >= -s->ps.sps->qp_bd_offset && qPy_b < 52); + av_assert2(qPy_a >= -sps->qp_bd_offset && qPy_a < 52); + av_assert2(qPy_b >= -sps->qp_bd_offset && qPy_b < 52); return (qPy_a + qPy_b + 1) >> 1; } -void ff_hevc_set_qPy(HEVCLocalContext *lc, int xBase, int yBase, int log2_cb_size) +void ff_hevc_set_qPy(HEVCLocalContext *lc, + const HEVCLayerContext *l, const HEVCPPS *pps, + int xBase, int yBase, int log2_cb_size) { + const HEVCSPS *const sps = pps->sps; const HEVCContext *const s = lc->parent; - int qp_y = get_qPy_pred(lc, s, xBase, yBase, log2_cb_size); + int qp_y = get_qPy_pred(lc, s, l, pps, sps, xBase, yBase, log2_cb_size); if (lc->tu.cu_qp_delta != 0) { - int off = s->ps.sps->qp_bd_offset; + int off = sps->qp_bd_offset; lc->qp_y = FFUMOD(qp_y + lc->tu.cu_qp_delta + 52 + 2 * off, 52 + off) - off; } else lc->qp_y = qp_y; } -static int get_qPy(const HEVCContext *s, int xC, int yC) +static int get_qPy(const HEVCSPS *sps, const int8_t *qp_y_tab, int xC, int yC) { - int log2_min_cb_size = s->ps.sps->log2_min_cb_size; + int log2_min_cb_size = sps->log2_min_cb_size; int x = xC >> log2_min_cb_size; int y = yC >> log2_min_cb_size; - return s->qp_y_tab[x + y * s->ps.sps->min_cb_width]; + return qp_y_tab[x + y * sps->min_cb_width]; } static void copy_CTB(uint8_t *dst, const uint8_t *src, int width, int height, @@ -198,48 +204,55 @@ static void copy_vert(uint8_t *dst, const uint8_t *src, } } -static void copy_CTB_to_hv(const HEVCContext *s, const uint8_t *src, +static void copy_CTB_to_hv(const HEVCLayerContext *l, const HEVCSPS *sps, + const uint8_t *src, ptrdiff_t stride_src, int x, int y, int width, int height, int c_idx, int x_ctb, int y_ctb) { - int sh = s->ps.sps->pixel_shift; - int w = s->ps.sps->width >> s->ps.sps->hshift[c_idx]; - int h = s->ps.sps->height >> s->ps.sps->vshift[c_idx]; + int sh = sps->pixel_shift; + int w = sps->width >> sps->hshift[c_idx]; + int h = sps->height >> sps->vshift[c_idx]; /* copy horizontal edges */ - memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb) * w + x) << sh), + memcpy(l->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb) * w + x) << sh), src, width << sh); - memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 1) * w + x) << sh), + memcpy(l->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 1) * w + x) << sh), src + stride_src * (height - 1), width << sh); /* copy vertical edges */ - copy_vert(s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb) * h + y) << sh), src, sh, height, 1 << sh, stride_src); + copy_vert(l->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb) * h + y) << sh), src, sh, height, 1 << sh, stride_src); - copy_vert(s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 1) * h + y) << sh), src + ((width - 1) << sh), sh, height, 1 << sh, stride_src); + copy_vert(l->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 1) * h + y) << sh), src + ((width - 1) << sh), sh, height, 1 << sh, stride_src); } -static void restore_tqb_pixels(const HEVCContext *s, +static void restore_tqb_pixels(const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, uint8_t *src1, const uint8_t *dst1, ptrdiff_t stride_src, ptrdiff_t stride_dst, int x0, int y0, int width, int height, int c_idx) { - if ( s->ps.pps->transquant_bypass_enable_flag || - (s->ps.sps->pcm.loop_filter_disable_flag && s->ps.sps->pcm_enabled_flag)) { + if (pps->transquant_bypass_enable_flag || + (sps->pcm_loop_filter_disabled && sps->pcm_enabled)) { int x, y; - int min_pu_size = 1 << s->ps.sps->log2_min_pu_size; - int hshift = s->ps.sps->hshift[c_idx]; - int vshift = s->ps.sps->vshift[c_idx]; - int x_min = ((x0 ) >> s->ps.sps->log2_min_pu_size); - int y_min = ((y0 ) >> s->ps.sps->log2_min_pu_size); - int x_max = ((x0 + width ) >> s->ps.sps->log2_min_pu_size); - int y_max = ((y0 + height) >> s->ps.sps->log2_min_pu_size); - int len = (min_pu_size >> hshift) << s->ps.sps->pixel_shift; + int min_pu_size = 1 << sps->log2_min_pu_size; + int hshift = sps->hshift[c_idx]; + int vshift = sps->vshift[c_idx]; + int x_min = ((x0 ) >> sps->log2_min_pu_size); + int y_min = ((y0 ) >> sps->log2_min_pu_size); + int x_max = ((x0 + width ) >> sps->log2_min_pu_size); + int y_max = ((y0 + height) >> sps->log2_min_pu_size); + int len = (min_pu_size >> hshift) << sps->pixel_shift; for (y = y_min; y < y_max; y++) { for (x = x_min; x < x_max; x++) { - if (s->is_pcm[y * s->ps.sps->min_pu_width + x]) { + if (l->is_pcm[y * sps->min_pu_width + x]) { int n; - uint8_t *src = src1 + (((y << s->ps.sps->log2_min_pu_size) - y0) >> vshift) * stride_src + ((((x << s->ps.sps->log2_min_pu_size) - x0) >> hshift) << s->ps.sps->pixel_shift); - const uint8_t *dst = dst1 + (((y << s->ps.sps->log2_min_pu_size) - y0) >> vshift) * stride_dst + ((((x << s->ps.sps->log2_min_pu_size) - x0) >> hshift) << s->ps.sps->pixel_shift); + uint8_t *src = src1 + + (((y << sps->log2_min_pu_size) - y0) >> vshift) * stride_src + + ((((x << sps->log2_min_pu_size) - x0) >> hshift) << sps->pixel_shift); + const uint8_t *dst = dst1 + + (((y << sps->log2_min_pu_size) - y0) >> vshift) * stride_dst + + ((((x << sps->log2_min_pu_size) - x0) >> hshift) << sps->pixel_shift); + for (n = 0; n < (min_pu_size >> vshift); n++) { memcpy(src, dst, len); src += stride_src; @@ -251,25 +264,28 @@ static void restore_tqb_pixels(const HEVCContext *s, } } -#define CTB(tab, x, y) ((tab)[(y) * s->ps.sps->ctb_width + (x)]) +#define CTB(tab, x, y) ((tab)[(y) * sps->ctb_width + (x)]) -static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCContext *s, int x, int y) +static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCContext *s, + const HEVCPPS *pps, const HEVCSPS *sps, + int x, int y) { static const uint8_t sao_tab[8] = { 0, 1, 2, 2, 3, 3, 4, 4 }; int c_idx; int edges[4]; // 0 left 1 top 2 right 3 bottom - int x_ctb = x >> s->ps.sps->log2_ctb_size; - int y_ctb = y >> s->ps.sps->log2_ctb_size; - int ctb_addr_rs = y_ctb * s->ps.sps->ctb_width + x_ctb; - int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs]; - SAOParams *sao = &CTB(s->sao, x_ctb, y_ctb); + int x_ctb = x >> sps->log2_ctb_size; + int y_ctb = y >> sps->log2_ctb_size; + int ctb_addr_rs = y_ctb * sps->ctb_width + x_ctb; + int ctb_addr_ts = pps->ctb_addr_rs_to_ts[ctb_addr_rs]; + SAOParams *sao = &CTB(l->sao, x_ctb, y_ctb); // flags indicating unfilterable edges uint8_t vert_edge[] = { 0, 0 }; uint8_t horiz_edge[] = { 0, 0 }; uint8_t diag_edge[] = { 0, 0, 0, 0 }; - uint8_t lfase = CTB(s->filter_slice_edges, x_ctb, y_ctb); - uint8_t no_tile_filter = s->ps.pps->tiles_enabled_flag && - !s->ps.pps->loop_filter_across_tiles_enabled_flag; + uint8_t lfase = CTB(l->filter_slice_edges, x_ctb, y_ctb); + uint8_t no_tile_filter = pps->tiles_enabled_flag && + !pps->loop_filter_across_tiles_enabled_flag; uint8_t restore = no_tile_filter || !lfase; uint8_t left_tile_edge = 0; uint8_t right_tile_edge = 0; @@ -278,66 +294,66 @@ static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCContext *s, int x, in edges[0] = x_ctb == 0; edges[1] = y_ctb == 0; - edges[2] = x_ctb == s->ps.sps->ctb_width - 1; - edges[3] = y_ctb == s->ps.sps->ctb_height - 1; + edges[2] = x_ctb == sps->ctb_width - 1; + edges[3] = y_ctb == sps->ctb_height - 1; if (restore) { if (!edges[0]) { - left_tile_edge = no_tile_filter && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs-1]]; - vert_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb)) || left_tile_edge; + left_tile_edge = no_tile_filter && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs-1]]; + vert_edge[0] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb - 1, y_ctb)) || left_tile_edge; } if (!edges[2]) { - right_tile_edge = no_tile_filter && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs+1]]; - vert_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb)) || right_tile_edge; + right_tile_edge = no_tile_filter && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs+1]]; + vert_edge[1] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb + 1, y_ctb)) || right_tile_edge; } if (!edges[1]) { - up_tile_edge = no_tile_filter && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->ps.sps->ctb_width]]; - horiz_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) || up_tile_edge; + up_tile_edge = no_tile_filter && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs - sps->ctb_width]]; + horiz_edge[0] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb, y_ctb - 1)) || up_tile_edge; } if (!edges[3]) { - bottom_tile_edge = no_tile_filter && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs + s->ps.sps->ctb_width]]; - horiz_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb + 1)) || bottom_tile_edge; + bottom_tile_edge = no_tile_filter && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs + sps->ctb_width]]; + horiz_edge[1] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb, y_ctb + 1)) || bottom_tile_edge; } if (!edges[0] && !edges[1]) { - diag_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge || up_tile_edge; + diag_edge[0] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge || up_tile_edge; } if (!edges[1] && !edges[2]) { - diag_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb - 1)) || right_tile_edge || up_tile_edge; + diag_edge[1] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb + 1, y_ctb - 1)) || right_tile_edge || up_tile_edge; } if (!edges[2] && !edges[3]) { - diag_edge[2] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb + 1)) || right_tile_edge || bottom_tile_edge; + diag_edge[2] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb + 1, y_ctb + 1)) || right_tile_edge || bottom_tile_edge; } if (!edges[0] && !edges[3]) { - diag_edge[3] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb + 1)) || left_tile_edge || bottom_tile_edge; + diag_edge[3] = (!lfase && CTB(l->tab_slice_address, x_ctb, y_ctb) != CTB(l->tab_slice_address, x_ctb - 1, y_ctb + 1)) || left_tile_edge || bottom_tile_edge; } } - for (c_idx = 0; c_idx < (s->ps.sps->chroma_format_idc ? 3 : 1); c_idx++) { - int x0 = x >> s->ps.sps->hshift[c_idx]; - int y0 = y >> s->ps.sps->vshift[c_idx]; - ptrdiff_t stride_src = s->frame->linesize[c_idx]; - int ctb_size_h = (1 << (s->ps.sps->log2_ctb_size)) >> s->ps.sps->hshift[c_idx]; - int ctb_size_v = (1 << (s->ps.sps->log2_ctb_size)) >> s->ps.sps->vshift[c_idx]; - int width = FFMIN(ctb_size_h, (s->ps.sps->width >> s->ps.sps->hshift[c_idx]) - x0); - int height = FFMIN(ctb_size_v, (s->ps.sps->height >> s->ps.sps->vshift[c_idx]) - y0); + for (c_idx = 0; c_idx < (sps->chroma_format_idc ? 3 : 1); c_idx++) { + int x0 = x >> sps->hshift[c_idx]; + int y0 = y >> sps->vshift[c_idx]; + ptrdiff_t stride_src = s->cur_frame->f->linesize[c_idx]; + int ctb_size_h = (1 << (sps->log2_ctb_size)) >> sps->hshift[c_idx]; + int ctb_size_v = (1 << (sps->log2_ctb_size)) >> sps->vshift[c_idx]; + int width = FFMIN(ctb_size_h, (sps->width >> sps->hshift[c_idx]) - x0); + int height = FFMIN(ctb_size_v, (sps->height >> sps->vshift[c_idx]) - y0); int tab = sao_tab[(FFALIGN(width, 8) >> 3) - 1]; - uint8_t *src = &s->frame->data[c_idx][y0 * stride_src + (x0 << s->ps.sps->pixel_shift)]; + uint8_t *src = &s->cur_frame->f->data[c_idx][y0 * stride_src + (x0 << sps->pixel_shift)]; ptrdiff_t stride_dst; uint8_t *dst; switch (sao->type_idx[c_idx]) { case SAO_BAND: - copy_CTB_to_hv(s, src, stride_src, x0, y0, width, height, c_idx, + copy_CTB_to_hv(l, sps, src, stride_src, x0, y0, width, height, c_idx, x_ctb, y_ctb); - if (s->ps.pps->transquant_bypass_enable_flag || - (s->ps.sps->pcm.loop_filter_disable_flag && s->ps.sps->pcm_enabled_flag)) { + if (pps->transquant_bypass_enable_flag || + (sps->pcm_loop_filter_disabled && sps->pcm_enabled)) { dst = lc->edge_emu_buffer; stride_dst = 2*MAX_PB_SIZE; - copy_CTB(dst, src, width << s->ps.sps->pixel_shift, height, stride_dst, stride_src); + copy_CTB(dst, src, width << sps->pixel_shift, height, stride_dst, stride_src); s->hevcdsp.sao_band_filter[tab](src, dst, stride_src, stride_dst, sao->offset_val[c_idx], sao->band_position[c_idx], width, height); - restore_tqb_pixels(s, src, dst, stride_src, stride_dst, + restore_tqb_pixels(l, pps, sps, src, dst, stride_src, stride_dst, x, y, width, height, c_idx); } else { s->hevcdsp.sao_band_filter[tab](src, src, stride_src, stride_src, @@ -348,13 +364,13 @@ static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCContext *s, int x, in break; case SAO_EDGE: { - int w = s->ps.sps->width >> s->ps.sps->hshift[c_idx]; - int h = s->ps.sps->height >> s->ps.sps->vshift[c_idx]; + int w = sps->width >> sps->hshift[c_idx]; + int h = sps->height >> sps->vshift[c_idx]; int left_edge = edges[0]; int top_edge = edges[1]; int right_edge = edges[2]; int bottom_edge = edges[3]; - int sh = s->ps.sps->pixel_shift; + int sh = sps->pixel_shift; int left_pixels, right_pixels; stride_dst = 2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE; @@ -369,20 +385,20 @@ static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCContext *s, int x, in dst1 = dst - stride_dst - (left << sh); src1[0] = src - stride_src - (left << sh); - src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb - 1) * w + x0 - left) << sh); + src1[1] = l->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb - 1) * w + x0 - left) << sh); pos = 0; if (left) { - src_idx = (CTB(s->sao, x_ctb-1, y_ctb-1).type_idx[c_idx] == + src_idx = (CTB(l->sao, x_ctb-1, y_ctb-1).type_idx[c_idx] == SAO_APPLIED); copy_pixel(dst1, src1[src_idx], sh); pos += (1 << sh); } - src_idx = (CTB(s->sao, x_ctb, y_ctb-1).type_idx[c_idx] == + src_idx = (CTB(l->sao, x_ctb, y_ctb-1).type_idx[c_idx] == SAO_APPLIED); memcpy(dst1 + pos, src1[src_idx] + pos, width << sh); if (right) { pos += width << sh; - src_idx = (CTB(s->sao, x_ctb+1, y_ctb-1).type_idx[c_idx] == + src_idx = (CTB(l->sao, x_ctb+1, y_ctb-1).type_idx[c_idx] == SAO_APPLIED); copy_pixel(dst1 + pos, src1[src_idx] + pos, sh); } @@ -396,29 +412,29 @@ static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCContext *s, int x, in dst1 = dst + height * stride_dst - (left << sh); src1[0] = src + height * stride_src - (left << sh); - src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 2) * w + x0 - left) << sh); + src1[1] = l->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 2) * w + x0 - left) << sh); pos = 0; if (left) { - src_idx = (CTB(s->sao, x_ctb-1, y_ctb+1).type_idx[c_idx] == + src_idx = (CTB(l->sao, x_ctb-1, y_ctb+1).type_idx[c_idx] == SAO_APPLIED); copy_pixel(dst1, src1[src_idx], sh); pos += (1 << sh); } - src_idx = (CTB(s->sao, x_ctb, y_ctb+1).type_idx[c_idx] == + src_idx = (CTB(l->sao, x_ctb, y_ctb+1).type_idx[c_idx] == SAO_APPLIED); memcpy(dst1 + pos, src1[src_idx] + pos, width << sh); if (right) { pos += width << sh; - src_idx = (CTB(s->sao, x_ctb+1, y_ctb+1).type_idx[c_idx] == + src_idx = (CTB(l->sao, x_ctb+1, y_ctb+1).type_idx[c_idx] == SAO_APPLIED); copy_pixel(dst1 + pos, src1[src_idx] + pos, sh); } } left_pixels = 0; if (!left_edge) { - if (CTB(s->sao, x_ctb-1, y_ctb).type_idx[c_idx] == SAO_APPLIED) { + if (CTB(l->sao, x_ctb-1, y_ctb).type_idx[c_idx] == SAO_APPLIED) { copy_vert(dst - (1 << sh), - s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb - 1) * h + y0) << sh), + l->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb - 1) * h + y0) << sh), sh, height, stride_dst, 1 << sh); } else { left_pixels = 1; @@ -426,9 +442,9 @@ static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCContext *s, int x, in } right_pixels = 0; if (!right_edge) { - if (CTB(s->sao, x_ctb+1, y_ctb).type_idx[c_idx] == SAO_APPLIED) { + if (CTB(l->sao, x_ctb+1, y_ctb).type_idx[c_idx] == SAO_APPLIED) { copy_vert(dst + (width << sh), - s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 2) * h + y0) << sh), + l->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 2) * h + y0) << sh), sh, height, stride_dst, 1 << sh); } else { right_pixels = 1; @@ -440,7 +456,7 @@ static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCContext *s, int x, in (width + left_pixels + right_pixels) << sh, height, stride_dst, stride_src); - copy_CTB_to_hv(s, src, stride_src, x0, y0, width, height, c_idx, + copy_CTB_to_hv(l, sps, src, stride_src, x0, y0, width, height, c_idx, x_ctb, y_ctb); s->hevcdsp.sao_edge_filter[tab](src, dst, stride_src, sao->offset_val[c_idx], sao->eo_class[c_idx], width, height); @@ -452,7 +468,7 @@ static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCContext *s, int x, in vert_edge, horiz_edge, diag_edge); - restore_tqb_pixels(s, src, dst, stride_src, stride_dst, + restore_tqb_pixels(l, pps, sps, src, dst, stride_src, stride_dst, x, y, width, height, c_idx); sao->type_idx[c_idx] = SAO_APPLIED; break; @@ -461,9 +477,9 @@ static void sao_filter_CTB(HEVCLocalContext *lc, const HEVCContext *s, int x, in } } -static int get_pcm(const HEVCContext *s, int x, int y) +static int get_pcm(const HEVCSPS *sps, const uint8_t *is_pcm, int x, int y) { - int log2_min_pu_size = s->ps.sps->log2_min_pu_size; + int log2_min_pu_size = sps->log2_min_pu_size; int x_pu, y_pu; if (x < 0 || y < 0) @@ -472,9 +488,9 @@ static int get_pcm(const HEVCContext *s, int x, int y) x_pu = x >> log2_min_pu_size; y_pu = y >> log2_min_pu_size; - if (x_pu >= s->ps.sps->min_pu_width || y_pu >= s->ps.sps->min_pu_height) + if (x_pu >= sps->min_pu_width || y_pu >= sps->min_pu_height) return 2; - return s->is_pcm[y_pu * s->ps.sps->min_pu_width + x_pu]; + return is_pcm[y_pu * sps->min_pu_width + x_pu]; } #define TC_CALC(qp, bs) \ @@ -482,8 +498,13 @@ static int get_pcm(const HEVCContext *s, int x, int y) (tc_offset & -2), \ 0, MAX_QP + DEFAULT_INTRA_TC_OFFSET)] -static void deblocking_filter_CTB(const HEVCContext *s, int x0, int y0) +static void deblocking_filter_CTB(const HEVCContext *s, const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, + int x0, int y0) { + uint8_t **data = s->cur_frame->f->data; + int *linesize = s->cur_frame->f->linesize; + uint8_t *src; int x, y; int chroma, beta; @@ -491,64 +512,63 @@ static void deblocking_filter_CTB(const HEVCContext *s, int x0, int y0) uint8_t no_p[2] = { 0 }; uint8_t no_q[2] = { 0 }; - int log2_ctb_size = s->ps.sps->log2_ctb_size; + int log2_ctb_size = sps->log2_ctb_size; int x_end, x_end2, y_end; int ctb_size = 1 << log2_ctb_size; int ctb = (x0 >> log2_ctb_size) + - (y0 >> log2_ctb_size) * s->ps.sps->ctb_width; - int cur_tc_offset = s->deblock[ctb].tc_offset; - int cur_beta_offset = s->deblock[ctb].beta_offset; + (y0 >> log2_ctb_size) * sps->ctb_width; + int cur_tc_offset = l->deblock[ctb].tc_offset; + int cur_beta_offset = l->deblock[ctb].beta_offset; int left_tc_offset, left_beta_offset; int tc_offset, beta_offset; - int pcmf = (s->ps.sps->pcm_enabled_flag && - s->ps.sps->pcm.loop_filter_disable_flag) || - s->ps.pps->transquant_bypass_enable_flag; + int pcmf = (sps->pcm_enabled && + sps->pcm_loop_filter_disabled) || + pps->transquant_bypass_enable_flag; if (x0) { - left_tc_offset = s->deblock[ctb - 1].tc_offset; - left_beta_offset = s->deblock[ctb - 1].beta_offset; + left_tc_offset = l->deblock[ctb - 1].tc_offset; + left_beta_offset = l->deblock[ctb - 1].beta_offset; } else { left_tc_offset = 0; left_beta_offset = 0; } x_end = x0 + ctb_size; - if (x_end > s->ps.sps->width) - x_end = s->ps.sps->width; + if (x_end > sps->width) + x_end = sps->width; y_end = y0 + ctb_size; - if (y_end > s->ps.sps->height) - y_end = s->ps.sps->height; + if (y_end > sps->height) + y_end = sps->height; tc_offset = cur_tc_offset; beta_offset = cur_beta_offset; x_end2 = x_end; - if (x_end2 != s->ps.sps->width) + if (x_end2 != sps->width) x_end2 -= 8; for (y = y0; y < y_end; y += 8) { // vertical filtering luma for (x = x0 ? x0 : 8; x < x_end; x += 8) { - const int bs0 = s->vertical_bs[(x + y * s->bs_width) >> 2]; - const int bs1 = s->vertical_bs[(x + (y + 4) * s->bs_width) >> 2]; + const int bs0 = l->vertical_bs[(x + y * l->bs_width) >> 2]; + const int bs1 = l->vertical_bs[(x + (y + 4) * l->bs_width) >> 2]; if (bs0 || bs1) { - const int qp = (get_qPy(s, x - 1, y) + get_qPy(s, x, y) + 1) >> 1; + const int qp = (get_qPy(sps, l->qp_y_tab, x - 1, y) + + get_qPy(sps, l->qp_y_tab, x, y) + 1) >> 1; beta = betatable[av_clip(qp + beta_offset, 0, MAX_QP)]; tc[0] = bs0 ? TC_CALC(qp, bs0) : 0; tc[1] = bs1 ? TC_CALC(qp, bs1) : 0; - src = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << s->ps.sps->pixel_shift)]; + src = &data[LUMA][y * linesize[LUMA] + (x << sps->pixel_shift)]; if (pcmf) { - no_p[0] = get_pcm(s, x - 1, y); - no_p[1] = get_pcm(s, x - 1, y + 4); - no_q[0] = get_pcm(s, x, y); - no_q[1] = get_pcm(s, x, y + 4); - s->hevcdsp.hevc_v_loop_filter_luma_c(src, - s->frame->linesize[LUMA], + no_p[0] = get_pcm(sps, l->is_pcm, x - 1, y); + no_p[1] = get_pcm(sps, l->is_pcm, x - 1, y + 4); + no_q[0] = get_pcm(sps, l->is_pcm, x, y); + no_q[1] = get_pcm(sps, l->is_pcm, x, y + 4); + s->hevcdsp.hevc_v_loop_filter_luma_c(src, linesize[LUMA], beta, tc, no_p, no_q); } else - s->hevcdsp.hevc_v_loop_filter_luma(src, - s->frame->linesize[LUMA], + s->hevcdsp.hevc_v_loop_filter_luma(src, linesize[LUMA], beta, tc, no_p, no_q); } } @@ -558,10 +578,11 @@ static void deblocking_filter_CTB(const HEVCContext *s, int x0, int y0) // horizontal filtering luma for (x = x0 ? x0 - 8 : 0; x < x_end2; x += 8) { - const int bs0 = s->horizontal_bs[( x + y * s->bs_width) >> 2]; - const int bs1 = s->horizontal_bs[((x + 4) + y * s->bs_width) >> 2]; + const int bs0 = l->horizontal_bs[( x + y * l->bs_width) >> 2]; + const int bs1 = l->horizontal_bs[((x + 4) + y * l->bs_width) >> 2]; if (bs0 || bs1) { - const int qp = (get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1; + const int qp = (get_qPy(sps, l->qp_y_tab, x, y - 1) + + get_qPy(sps, l->qp_y_tab, x, y) + 1) >> 1; tc_offset = x >= x0 ? cur_tc_offset : left_tc_offset; beta_offset = x >= x0 ? cur_beta_offset : left_beta_offset; @@ -569,52 +590,50 @@ static void deblocking_filter_CTB(const HEVCContext *s, int x0, int y0) beta = betatable[av_clip(qp + beta_offset, 0, MAX_QP)]; tc[0] = bs0 ? TC_CALC(qp, bs0) : 0; tc[1] = bs1 ? TC_CALC(qp, bs1) : 0; - src = &s->frame->data[LUMA][y * s->frame->linesize[LUMA] + (x << s->ps.sps->pixel_shift)]; + src = &data[LUMA][y * linesize[LUMA] + (x << sps->pixel_shift)]; if (pcmf) { - no_p[0] = get_pcm(s, x, y - 1); - no_p[1] = get_pcm(s, x + 4, y - 1); - no_q[0] = get_pcm(s, x, y); - no_q[1] = get_pcm(s, x + 4, y); - s->hevcdsp.hevc_h_loop_filter_luma_c(src, - s->frame->linesize[LUMA], + no_p[0] = get_pcm(sps, l->is_pcm, x, y - 1); + no_p[1] = get_pcm(sps, l->is_pcm, x + 4, y - 1); + no_q[0] = get_pcm(sps, l->is_pcm, x, y); + no_q[1] = get_pcm(sps, l->is_pcm, x + 4, y); + s->hevcdsp.hevc_h_loop_filter_luma_c(src, linesize[LUMA], beta, tc, no_p, no_q); } else - s->hevcdsp.hevc_h_loop_filter_luma(src, - s->frame->linesize[LUMA], + s->hevcdsp.hevc_h_loop_filter_luma(src, linesize[LUMA], beta, tc, no_p, no_q); } } } - if (s->ps.sps->chroma_format_idc) { + if (sps->chroma_format_idc) { for (chroma = 1; chroma <= 2; chroma++) { - int h = 1 << s->ps.sps->hshift[chroma]; - int v = 1 << s->ps.sps->vshift[chroma]; + int h = 1 << sps->hshift[chroma]; + int v = 1 << sps->vshift[chroma]; // vertical filtering chroma for (y = y0; y < y_end; y += (8 * v)) { for (x = x0 ? x0 : 8 * h; x < x_end; x += (8 * h)) { - const int bs0 = s->vertical_bs[(x + y * s->bs_width) >> 2]; - const int bs1 = s->vertical_bs[(x + (y + (4 * v)) * s->bs_width) >> 2]; + const int bs0 = l->vertical_bs[(x + y * l->bs_width) >> 2]; + const int bs1 = l->vertical_bs[(x + (y + (4 * v)) * l->bs_width) >> 2]; if ((bs0 == 2) || (bs1 == 2)) { - const int qp0 = (get_qPy(s, x - 1, y) + get_qPy(s, x, y) + 1) >> 1; - const int qp1 = (get_qPy(s, x - 1, y + (4 * v)) + get_qPy(s, x, y + (4 * v)) + 1) >> 1; + const int qp0 = (get_qPy(sps, l->qp_y_tab, x - 1, y) + + get_qPy(sps, l->qp_y_tab, x, y) + 1) >> 1; + const int qp1 = (get_qPy(sps, l->qp_y_tab, x - 1, y + (4 * v)) + + get_qPy(sps, l->qp_y_tab, x, y + (4 * v)) + 1) >> 1; - c_tc[0] = (bs0 == 2) ? chroma_tc(s, qp0, chroma, tc_offset) : 0; - c_tc[1] = (bs1 == 2) ? chroma_tc(s, qp1, chroma, tc_offset) : 0; - src = &s->frame->data[chroma][(y >> s->ps.sps->vshift[chroma]) * s->frame->linesize[chroma] + ((x >> s->ps.sps->hshift[chroma]) << s->ps.sps->pixel_shift)]; + c_tc[0] = (bs0 == 2) ? chroma_tc(pps, sps, qp0, chroma, tc_offset) : 0; + c_tc[1] = (bs1 == 2) ? chroma_tc(pps, sps, qp1, chroma, tc_offset) : 0; + src = &data[chroma][(y >> sps->vshift[chroma]) * linesize[chroma] + ((x >> sps->hshift[chroma]) << sps->pixel_shift)]; if (pcmf) { - no_p[0] = get_pcm(s, x - 1, y); - no_p[1] = get_pcm(s, x - 1, y + (4 * v)); - no_q[0] = get_pcm(s, x, y); - no_q[1] = get_pcm(s, x, y + (4 * v)); - s->hevcdsp.hevc_v_loop_filter_chroma_c(src, - s->frame->linesize[chroma], + no_p[0] = get_pcm(sps, l->is_pcm, x - 1, y); + no_p[1] = get_pcm(sps, l->is_pcm, x - 1, y + (4 * v)); + no_q[0] = get_pcm(sps, l->is_pcm, x, y); + no_q[1] = get_pcm(sps, l->is_pcm, x, y + (4 * v)); + s->hevcdsp.hevc_v_loop_filter_chroma_c(src, linesize[chroma], c_tc, no_p, no_q); } else - s->hevcdsp.hevc_v_loop_filter_chroma(src, - s->frame->linesize[chroma], + s->hevcdsp.hevc_v_loop_filter_chroma(src, linesize[chroma], c_tc, no_p, no_q); } } @@ -625,29 +644,29 @@ static void deblocking_filter_CTB(const HEVCContext *s, int x0, int y0) // horizontal filtering chroma tc_offset = x0 ? left_tc_offset : cur_tc_offset; x_end2 = x_end; - if (x_end != s->ps.sps->width) + if (x_end != sps->width) x_end2 = x_end - 8 * h; for (x = x0 ? x0 - 8 * h : 0; x < x_end2; x += (8 * h)) { - const int bs0 = s->horizontal_bs[( x + y * s->bs_width) >> 2]; - const int bs1 = s->horizontal_bs[((x + 4 * h) + y * s->bs_width) >> 2]; + const int bs0 = l->horizontal_bs[( x + y * l->bs_width) >> 2]; + const int bs1 = l->horizontal_bs[((x + 4 * h) + y * l->bs_width) >> 2]; if ((bs0 == 2) || (bs1 == 2)) { - const int qp0 = bs0 == 2 ? (get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1 : 0; - const int qp1 = bs1 == 2 ? (get_qPy(s, x + (4 * h), y - 1) + get_qPy(s, x + (4 * h), y) + 1) >> 1 : 0; + const int qp0 = bs0 == 2 ? (get_qPy(sps, l->qp_y_tab, x, y - 1) + + get_qPy(sps, l->qp_y_tab, x, y) + 1) >> 1 : 0; + const int qp1 = bs1 == 2 ? (get_qPy(sps, l->qp_y_tab, x + (4 * h), y - 1) + + get_qPy(sps, l->qp_y_tab, x + (4 * h), y) + 1) >> 1 : 0; - c_tc[0] = bs0 == 2 ? chroma_tc(s, qp0, chroma, tc_offset) : 0; - c_tc[1] = bs1 == 2 ? chroma_tc(s, qp1, chroma, cur_tc_offset) : 0; - src = &s->frame->data[chroma][(y >> s->ps.sps->vshift[1]) * s->frame->linesize[chroma] + ((x >> s->ps.sps->hshift[1]) << s->ps.sps->pixel_shift)]; + c_tc[0] = bs0 == 2 ? chroma_tc(pps, sps, qp0, chroma, tc_offset) : 0; + c_tc[1] = bs1 == 2 ? chroma_tc(pps, sps, qp1, chroma, cur_tc_offset) : 0; + src = &data[chroma][(y >> sps->vshift[1]) * linesize[chroma] + ((x >> sps->hshift[1]) << sps->pixel_shift)]; if (pcmf) { - no_p[0] = get_pcm(s, x, y - 1); - no_p[1] = get_pcm(s, x + (4 * h), y - 1); - no_q[0] = get_pcm(s, x, y); - no_q[1] = get_pcm(s, x + (4 * h), y); - s->hevcdsp.hevc_h_loop_filter_chroma_c(src, - s->frame->linesize[chroma], + no_p[0] = get_pcm(sps, l->is_pcm, x, y - 1); + no_p[1] = get_pcm(sps, l->is_pcm, x + (4 * h), y - 1); + no_q[0] = get_pcm(sps, l->is_pcm, x, y); + no_q[1] = get_pcm(sps, l->is_pcm, x + (4 * h), y); + s->hevcdsp.hevc_h_loop_filter_chroma_c(src, linesize[chroma], c_tc, no_p, no_q); } else - s->hevcdsp.hevc_h_loop_filter_chroma(src, - s->frame->linesize[chroma], + s->hevcdsp.hevc_h_loop_filter_chroma(src, linesize[chroma], c_tc, no_p, no_q); } } @@ -661,8 +680,8 @@ static int boundary_strength(const HEVCContext *s, const MvField *curr, const Mv { if (curr->pred_flag == PF_BI && neigh->pred_flag == PF_BI) { // same L0 and L1 - if (s->ref->refPicList[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]] && - s->ref->refPicList[0].list[curr->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]] && + if (s->cur_frame->refPicList[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]] && + s->cur_frame->refPicList[0].list[curr->ref_idx[0]] == s->cur_frame->refPicList[1].list[curr->ref_idx[1]] && neigh_refPicList[0].list[neigh->ref_idx[0]] == neigh_refPicList[1].list[neigh->ref_idx[1]]) { if ((FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 || FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4) && @@ -671,15 +690,15 @@ static int boundary_strength(const HEVCContext *s, const MvField *curr, const Mv return 1; else return 0; - } else if (neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[0].list[curr->ref_idx[0]] && - neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) { + } else if (neigh_refPicList[0].list[neigh->ref_idx[0]] == s->cur_frame->refPicList[0].list[curr->ref_idx[0]] && + neigh_refPicList[1].list[neigh->ref_idx[1]] == s->cur_frame->refPicList[1].list[curr->ref_idx[1]]) { if (FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 || FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4) return 1; else return 0; - } else if (neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[0].list[curr->ref_idx[0]] && - neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) { + } else if (neigh_refPicList[1].list[neigh->ref_idx[1]] == s->cur_frame->refPicList[0].list[curr->ref_idx[0]] && + neigh_refPicList[0].list[neigh->ref_idx[0]] == s->cur_frame->refPicList[1].list[curr->ref_idx[1]]) { if (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 || FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 4) return 1; @@ -694,10 +713,10 @@ static int boundary_strength(const HEVCContext *s, const MvField *curr, const Mv if (curr->pred_flag & 1) { A = curr->mv[0]; - ref_A = s->ref->refPicList[0].list[curr->ref_idx[0]]; + ref_A = s->cur_frame->refPicList[0].list[curr->ref_idx[0]]; } else { A = curr->mv[1]; - ref_A = s->ref->refPicList[1].list[curr->ref_idx[1]]; + ref_A = s->cur_frame->refPicList[1].list[curr->ref_idx[1]]; } if (neigh->pred_flag & 1) { @@ -720,15 +739,17 @@ static int boundary_strength(const HEVCContext *s, const MvField *curr, const Mv return 1; } -void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, - int log2_trafo_size) +void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCPPS *pps, + int x0, int y0, int log2_trafo_size) { + const HEVCSPS *const sps = pps->sps; const HEVCContext *s = lc->parent; - const MvField *tab_mvf = s->ref->tab_mvf; - int log2_min_pu_size = s->ps.sps->log2_min_pu_size; - int log2_min_tu_size = s->ps.sps->log2_min_tb_size; - int min_pu_width = s->ps.sps->min_pu_width; - int min_tu_width = s->ps.sps->min_tb_width; + const MvField *tab_mvf = s->cur_frame->tab_mvf; + int log2_min_pu_size = sps->log2_min_pu_size; + int log2_min_tu_size = sps->log2_min_tb_size; + int min_pu_width = sps->min_pu_width; + int min_tu_width = sps->min_tb_width; int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width + (x0 >> log2_min_pu_size)].pred_flag == PF_INTRA; int boundary_upper, boundary_left; @@ -738,16 +759,16 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, if (boundary_upper && ((!s->sh.slice_loop_filter_across_slices_enabled_flag && lc->boundary_flags & BOUNDARY_UPPER_SLICE && - (y0 % (1 << s->ps.sps->log2_ctb_size)) == 0) || - (!s->ps.pps->loop_filter_across_tiles_enabled_flag && + (y0 % (1 << sps->log2_ctb_size)) == 0) || + (!pps->loop_filter_across_tiles_enabled_flag && lc->boundary_flags & BOUNDARY_UPPER_TILE && - (y0 % (1 << s->ps.sps->log2_ctb_size)) == 0))) + (y0 % (1 << sps->log2_ctb_size)) == 0))) boundary_upper = 0; if (boundary_upper) { const RefPicList *rpl_top = (lc->boundary_flags & BOUNDARY_UPPER_SLICE) ? - ff_hevc_get_ref_list(s, s->ref, x0, y0 - 1) : - s->ref->refPicList; + ff_hevc_get_ref_list(s->cur_frame, x0, y0 - 1) : + s->cur_frame->refPicList; int yp_pu = (y0 - 1) >> log2_min_pu_size; int yq_pu = y0 >> log2_min_pu_size; int yp_tu = (y0 - 1) >> log2_min_tu_size; @@ -758,8 +779,8 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, int x_tu = (x0 + i) >> log2_min_tu_size; const MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu]; const MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu]; - uint8_t top_cbf_luma = s->cbf_luma[yp_tu * min_tu_width + x_tu]; - uint8_t curr_cbf_luma = s->cbf_luma[yq_tu * min_tu_width + x_tu]; + uint8_t top_cbf_luma = l->cbf_luma[yp_tu * min_tu_width + x_tu]; + uint8_t curr_cbf_luma = l->cbf_luma[yq_tu * min_tu_width + x_tu]; if (curr->pred_flag == PF_INTRA || top->pred_flag == PF_INTRA) bs = 2; @@ -767,7 +788,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, bs = 1; else bs = boundary_strength(s, curr, top, rpl_top); - s->horizontal_bs[((x0 + i) + y0 * s->bs_width) >> 2] = bs; + l->horizontal_bs[((x0 + i) + y0 * l->bs_width) >> 2] = bs; } } @@ -776,16 +797,16 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, if (boundary_left && ((!s->sh.slice_loop_filter_across_slices_enabled_flag && lc->boundary_flags & BOUNDARY_LEFT_SLICE && - (x0 % (1 << s->ps.sps->log2_ctb_size)) == 0) || - (!s->ps.pps->loop_filter_across_tiles_enabled_flag && + (x0 % (1 << sps->log2_ctb_size)) == 0) || + (!pps->loop_filter_across_tiles_enabled_flag && lc->boundary_flags & BOUNDARY_LEFT_TILE && - (x0 % (1 << s->ps.sps->log2_ctb_size)) == 0))) + (x0 % (1 << sps->log2_ctb_size)) == 0))) boundary_left = 0; if (boundary_left) { const RefPicList *rpl_left = (lc->boundary_flags & BOUNDARY_LEFT_SLICE) ? - ff_hevc_get_ref_list(s, s->ref, x0 - 1, y0) : - s->ref->refPicList; + ff_hevc_get_ref_list(s->cur_frame, x0 - 1, y0) : + s->cur_frame->refPicList; int xp_pu = (x0 - 1) >> log2_min_pu_size; int xq_pu = x0 >> log2_min_pu_size; int xp_tu = (x0 - 1) >> log2_min_tu_size; @@ -796,8 +817,8 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, int y_tu = (y0 + i) >> log2_min_tu_size; const MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu]; const MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu]; - uint8_t left_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xp_tu]; - uint8_t curr_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xq_tu]; + uint8_t left_cbf_luma = l->cbf_luma[y_tu * min_tu_width + xp_tu]; + uint8_t curr_cbf_luma = l->cbf_luma[y_tu * min_tu_width + xq_tu]; if (curr->pred_flag == PF_INTRA || left->pred_flag == PF_INTRA) bs = 2; @@ -805,12 +826,12 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, bs = 1; else bs = boundary_strength(s, curr, left, rpl_left); - s->vertical_bs[(x0 + (y0 + i) * s->bs_width) >> 2] = bs; + l->vertical_bs[(x0 + (y0 + i) * l->bs_width) >> 2] = bs; } } if (log2_trafo_size > log2_min_pu_size && !is_intra) { - const RefPicList *rpl = s->ref->refPicList; + const RefPicList *rpl = s->cur_frame->refPicList; // bs for TU internal horizontal PU boundaries for (j = 8; j < (1 << log2_trafo_size); j += 8) { @@ -823,7 +844,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, const MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu]; bs = boundary_strength(s, curr, top, rpl); - s->horizontal_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs; + l->horizontal_bs[((x0 + i) + (y0 + j) * l->bs_width) >> 2] = bs; } } @@ -838,7 +859,7 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, const MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu]; bs = boundary_strength(s, curr, left, rpl); - s->vertical_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs; + l->vertical_bs[((x0 + i) + (y0 + j) * l->bs_width) >> 2] = bs; } } } @@ -848,10 +869,13 @@ void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, #undef CB #undef CR -void ff_hevc_hls_filter(HEVCLocalContext *lc, int x, int y, int ctb_size) +void ff_hevc_hls_filter(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCPPS *pps, + int x, int y, int ctb_size) { + const HEVCSPS *const sps = pps->sps; const HEVCContext *const s = lc->parent; - int x_end = x >= s->ps.sps->width - ctb_size; + int x_end = x >= sps->width - ctb_size; int skip = 0; if (s->avctx->skip_loop_filter >= AVDISCARD_ALL || (s->avctx->skip_loop_filter >= AVDISCARD_NONKEY && !IS_IDR(s)) || @@ -864,35 +888,37 @@ void ff_hevc_hls_filter(HEVCLocalContext *lc, int x, int y, int ctb_size) skip = 1; if (!skip) - deblocking_filter_CTB(s, x, y); - if (s->ps.sps->sao_enabled && !skip) { - int y_end = y >= s->ps.sps->height - ctb_size; + deblocking_filter_CTB(s, l, pps, sps, x, y); + if (sps->sao_enabled && !skip) { + int y_end = y >= sps->height - ctb_size; if (y && x) - sao_filter_CTB(lc, s, x - ctb_size, y - ctb_size); + sao_filter_CTB(lc, l, s, pps, sps, x - ctb_size, y - ctb_size); if (x && y_end) - sao_filter_CTB(lc, s, x - ctb_size, y); + sao_filter_CTB(lc, l, s, pps, sps, x - ctb_size, y); if (y && x_end) { - sao_filter_CTB(lc, s, x, y - ctb_size); - if (s->threads_type & FF_THREAD_FRAME ) - ff_thread_report_progress(&s->ref->tf, y, 0); + sao_filter_CTB(lc, l, s, pps, sps, x, y - ctb_size); + if (s->avctx->active_thread_type & FF_THREAD_FRAME ) + ff_progress_frame_report(&s->cur_frame->tf, y); } if (x_end && y_end) { - sao_filter_CTB(lc, s, x , y); - if (s->threads_type & FF_THREAD_FRAME ) - ff_thread_report_progress(&s->ref->tf, y + ctb_size, 0); + sao_filter_CTB(lc, l, s, pps, sps, x , y); + if (s->avctx->active_thread_type & FF_THREAD_FRAME ) + ff_progress_frame_report(&s->cur_frame->tf, y + ctb_size); } - } else if (s->threads_type & FF_THREAD_FRAME && x_end) - ff_thread_report_progress(&s->ref->tf, y + ctb_size - 4, 0); + } else if (s->avctx->active_thread_type & FF_THREAD_FRAME && x_end) + ff_progress_frame_report(&s->cur_frame->tf, y + ctb_size - 4); } -void ff_hevc_hls_filters(HEVCLocalContext *lc, int x_ctb, int y_ctb, int ctb_size) +void ff_hevc_hls_filters(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCPPS *pps, + int x_ctb, int y_ctb, int ctb_size) { - int x_end = x_ctb >= lc->parent->ps.sps->width - ctb_size; - int y_end = y_ctb >= lc->parent->ps.sps->height - ctb_size; + int x_end = x_ctb >= pps->sps->width - ctb_size; + int y_end = y_ctb >= pps->sps->height - ctb_size; if (y_ctb && x_ctb) - ff_hevc_hls_filter(lc, x_ctb - ctb_size, y_ctb - ctb_size, ctb_size); + ff_hevc_hls_filter(lc, l, pps, x_ctb - ctb_size, y_ctb - ctb_size, ctb_size); if (y_ctb && x_end) - ff_hevc_hls_filter(lc, x_ctb, y_ctb - ctb_size, ctb_size); + ff_hevc_hls_filter(lc, l, pps, x_ctb, y_ctb - ctb_size, ctb_size); if (x_ctb && y_end) - ff_hevc_hls_filter(lc, x_ctb - ctb_size, y_ctb, ctb_size); + ff_hevc_hls_filter(lc, l, pps, x_ctb - ctb_size, y_ctb, ctb_size); } diff --git a/libavcodec/hevc.h b/libavcodec/hevc/hevc.h similarity index 94% rename from libavcodec/hevc.h rename to libavcodec/hevc/hevc.h index 6b454a75c..8bd59142d 100644 --- a/libavcodec/hevc.h +++ b/libavcodec/hevc/hevc.h @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_HEVC_H -#define AVCODEC_HEVC_H +#ifndef AVCODEC_HEVC_HEVC_H +#define AVCODEC_HEVC_HEVC_H /** * Table 7-1 – NAL unit type codes and NAL unit type classes in @@ -100,11 +100,14 @@ enum HEVCSliceType { enum { // 7.4.3.1: vps_max_layers_minus1 is in [0, 62]. - HEVC_MAX_LAYERS = 63, + HEVC_MAX_LAYERS = 63, // 7.4.3.1: vps_max_sub_layers_minus1 is in [0, 6]. - HEVC_MAX_SUB_LAYERS = 7, + HEVC_MAX_SUB_LAYERS = 7, // 7.4.3.1: vps_num_layer_sets_minus1 is in [0, 1023]. - HEVC_MAX_LAYER_SETS = 1024, + HEVC_MAX_LAYER_SETS = 1024, + // 7.4.3.1: vps_max_layer_id is in [0, 63]. + HEVC_MAX_LAYER_ID = 63, + HEVC_MAX_NUH_LAYER_ID = 62, // 7.4.2.1: vps_video_parameter_set_id is u(4). HEVC_MAX_VPS_COUNT = 16, @@ -160,4 +163,4 @@ enum { }; -#endif /* AVCODEC_HEVC_H */ +#endif /* AVCODEC_HEVC_HEVC_H */ diff --git a/libavcodec/hevcdec.c b/libavcodec/hevc/hevcdec.c similarity index 58% rename from libavcodec/hevcdec.c rename to libavcodec/hevc/hevcdec.c index 425020436..6f0ae1255 100644 --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevc/hevcdec.c @@ -31,26 +31,30 @@ #include "libavutil/film_grain_params.h" #include "libavutil/internal.h" #include "libavutil/md5.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" +#include "libavutil/stereo3d.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 "hevc.h" -#include "hevc_parse.h" +#include "parse.h" #include "hevcdec.h" #include "hwaccel_internal.h" #include "hwconfig.h" #include "internal.h" #include "profiles.h" +#include "progressframe.h" #include "refstruct.h" #include "thread.h" -#include "threadframe.h" +#include "threadprogress.h" static const uint8_t hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 }; @@ -64,35 +68,36 @@ static const uint8_t hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, */ /* free everything allocated by pic_arrays_init() */ -static void pic_arrays_free(HEVCContext *s) +static void pic_arrays_free(HEVCLayerContext *l) { - av_freep(&s->sao); - av_freep(&s->deblock); + av_freep(&l->sao); + av_freep(&l->deblock); - av_freep(&s->skip_flag); - av_freep(&s->tab_ct_depth); + av_freep(&l->skip_flag); + av_freep(&l->tab_ct_depth); - av_freep(&s->tab_ipm); - av_freep(&s->cbf_luma); - av_freep(&s->is_pcm); + av_freep(&l->tab_ipm); + av_freep(&l->cbf_luma); + av_freep(&l->is_pcm); - av_freep(&s->qp_y_tab); - av_freep(&s->tab_slice_address); - av_freep(&s->filter_slice_edges); + av_freep(&l->qp_y_tab); + av_freep(&l->tab_slice_address); + av_freep(&l->filter_slice_edges); - av_freep(&s->horizontal_bs); - av_freep(&s->vertical_bs); + av_freep(&l->horizontal_bs); + av_freep(&l->vertical_bs); - av_freep(&s->sh.entry_point_offset); - av_freep(&s->sh.size); - av_freep(&s->sh.offset); + for (int i = 0; i < 3; i++) { + av_freep(&l->sao_pixel_buffer_h[i]); + av_freep(&l->sao_pixel_buffer_v[i]); + } - ff_refstruct_pool_uninit(&s->tab_mvf_pool); - ff_refstruct_pool_uninit(&s->rpl_tab_pool); + ff_refstruct_pool_uninit(&l->tab_mvf_pool); + ff_refstruct_pool_uninit(&l->rpl_tab_pool); } /* allocate arrays that depend on frame dimensions */ -static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps) +static int pic_arrays_init(HEVCLayerContext *l, const HEVCSPS *sps) { int log2_min_cb_size = sps->log2_min_cb_size; int width = sps->width; @@ -102,51 +107,70 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps) int ctb_count = sps->ctb_width * sps->ctb_height; int min_pu_size = sps->min_pu_width * sps->min_pu_height; - s->bs_width = (width >> 2) + 1; - s->bs_height = (height >> 2) + 1; + l->bs_width = (width >> 2) + 1; + l->bs_height = (height >> 2) + 1; - s->sao = av_calloc(ctb_count, sizeof(*s->sao)); - s->deblock = av_calloc(ctb_count, sizeof(*s->deblock)); - if (!s->sao || !s->deblock) + l->sao = av_calloc(ctb_count, sizeof(*l->sao)); + l->deblock = av_calloc(ctb_count, sizeof(*l->deblock)); + if (!l->sao || !l->deblock) goto fail; - s->skip_flag = av_malloc_array(sps->min_cb_height, sps->min_cb_width); - s->tab_ct_depth = av_malloc_array(sps->min_cb_height, sps->min_cb_width); - if (!s->skip_flag || !s->tab_ct_depth) + l->skip_flag = av_malloc_array(sps->min_cb_height, sps->min_cb_width); + l->tab_ct_depth = av_malloc_array(sps->min_cb_height, sps->min_cb_width); + if (!l->skip_flag || !l->tab_ct_depth) goto fail; - s->cbf_luma = av_malloc_array(sps->min_tb_width, sps->min_tb_height); - s->tab_ipm = av_mallocz(min_pu_size); - s->is_pcm = av_malloc_array(sps->min_pu_width + 1, sps->min_pu_height + 1); - if (!s->tab_ipm || !s->cbf_luma || !s->is_pcm) + l->cbf_luma = av_malloc_array(sps->min_tb_width, sps->min_tb_height); + l->tab_ipm = av_mallocz(min_pu_size); + l->is_pcm = av_malloc_array(sps->min_pu_width + 1, sps->min_pu_height + 1); + if (!l->tab_ipm || !l->cbf_luma || !l->is_pcm) goto fail; - s->filter_slice_edges = av_mallocz(ctb_count); - s->tab_slice_address = av_malloc_array(pic_size_in_ctb, - sizeof(*s->tab_slice_address)); - s->qp_y_tab = av_malloc_array(pic_size_in_ctb, - sizeof(*s->qp_y_tab)); - if (!s->qp_y_tab || !s->filter_slice_edges || !s->tab_slice_address) + l->filter_slice_edges = av_mallocz(ctb_count); + l->tab_slice_address = av_malloc_array(pic_size_in_ctb, + sizeof(*l->tab_slice_address)); + l->qp_y_tab = av_calloc(pic_size_in_ctb, + sizeof(*l->qp_y_tab)); + if (!l->qp_y_tab || !l->filter_slice_edges || !l->tab_slice_address) goto fail; - s->horizontal_bs = av_calloc(s->bs_width, s->bs_height); - s->vertical_bs = av_calloc(s->bs_width, s->bs_height); - if (!s->horizontal_bs || !s->vertical_bs) + l->horizontal_bs = av_calloc(l->bs_width, l->bs_height); + l->vertical_bs = av_calloc(l->bs_width, l->bs_height); + if (!l->horizontal_bs || !l->vertical_bs) goto fail; - s->tab_mvf_pool = ff_refstruct_pool_alloc(min_pu_size * sizeof(MvField), 0); - s->rpl_tab_pool = ff_refstruct_pool_alloc(ctb_count * sizeof(RefPicListTab), 0); - if (!s->tab_mvf_pool || !s->rpl_tab_pool) + 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); + if (!l->tab_mvf_pool || !l->rpl_tab_pool) goto fail; + if (sps->sao_enabled) { + int c_count = (sps->chroma_format_idc != 0) ? 3 : 1; + + for (int c_idx = 0; c_idx < c_count; c_idx++) { + int w = sps->width >> sps->hshift[c_idx]; + int h = sps->height >> sps->vshift[c_idx]; + l->sao_pixel_buffer_h[c_idx] = + av_malloc((w * 2 * sps->ctb_height) << + sps->pixel_shift); + l->sao_pixel_buffer_v[c_idx] = + av_malloc((h * 2 * sps->ctb_width) << + sps->pixel_shift); + if (!l->sao_pixel_buffer_h[c_idx] || + !l->sao_pixel_buffer_v[c_idx]) + goto fail; + } + } + return 0; fail: - pic_arrays_free(s); + pic_arrays_free(l); return AVERROR(ENOMEM); } -static int pred_weight_table(HEVCContext *s, GetBitContext *gb) +static int pred_weight_table(SliceHeader *sh, void *logctx, + const HEVCSPS *sps, GetBitContext *gb) { int i = 0; int j = 0; @@ -158,40 +182,40 @@ static int pred_weight_table(HEVCContext *s, GetBitContext *gb) luma_log2_weight_denom = get_ue_golomb_long(gb); if (luma_log2_weight_denom < 0 || luma_log2_weight_denom > 7) { - av_log(s->avctx, AV_LOG_ERROR, "luma_log2_weight_denom %d is invalid\n", luma_log2_weight_denom); + av_log(logctx, AV_LOG_ERROR, "luma_log2_weight_denom %d is invalid\n", luma_log2_weight_denom); return AVERROR_INVALIDDATA; } - s->sh.luma_log2_weight_denom = av_clip_uintp2(luma_log2_weight_denom, 3); - if (s->ps.sps->chroma_format_idc != 0) { + sh->luma_log2_weight_denom = av_clip_uintp2(luma_log2_weight_denom, 3); + if (sps->chroma_format_idc != 0) { int64_t chroma_log2_weight_denom = luma_log2_weight_denom + (int64_t)get_se_golomb(gb); if (chroma_log2_weight_denom < 0 || chroma_log2_weight_denom > 7) { - av_log(s->avctx, AV_LOG_ERROR, "chroma_log2_weight_denom %"PRId64" is invalid\n", chroma_log2_weight_denom); + av_log(logctx, AV_LOG_ERROR, "chroma_log2_weight_denom %"PRId64" is invalid\n", chroma_log2_weight_denom); return AVERROR_INVALIDDATA; } - s->sh.chroma_log2_weight_denom = chroma_log2_weight_denom; + sh->chroma_log2_weight_denom = chroma_log2_weight_denom; } - for (i = 0; i < s->sh.nb_refs[L0]; i++) { + for (i = 0; i < sh->nb_refs[L0]; i++) { luma_weight_l0_flag[i] = get_bits1(gb); if (!luma_weight_l0_flag[i]) { - s->sh.luma_weight_l0[i] = 1 << s->sh.luma_log2_weight_denom; - s->sh.luma_offset_l0[i] = 0; + sh->luma_weight_l0[i] = 1 << sh->luma_log2_weight_denom; + sh->luma_offset_l0[i] = 0; } } - if (s->ps.sps->chroma_format_idc != 0) { - for (i = 0; i < s->sh.nb_refs[L0]; i++) + 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 < s->sh.nb_refs[L0]; i++) + for (i = 0; i < sh->nb_refs[L0]; i++) chroma_weight_l0_flag[i] = 0; } - for (i = 0; i < s->sh.nb_refs[L0]; i++) { + for (i = 0; i < sh->nb_refs[L0]; i++) { if (luma_weight_l0_flag[i]) { int delta_luma_weight_l0 = get_se_golomb(gb); if ((int8_t)delta_luma_weight_l0 != delta_luma_weight_l0) return AVERROR_INVALIDDATA; - s->sh.luma_weight_l0[i] = (1 << s->sh.luma_log2_weight_denom) + delta_luma_weight_l0; - s->sh.luma_offset_l0[i] = get_se_golomb(gb); + sh->luma_weight_l0[i] = (1 << sh->luma_log2_weight_denom) + delta_luma_weight_l0; + sh->luma_offset_l0[i] = get_se_golomb(gb); } if (chroma_weight_l0_flag[i]) { for (j = 0; j < 2; j++) { @@ -203,39 +227,39 @@ static int pred_weight_table(HEVCContext *s, GetBitContext *gb) return AVERROR_INVALIDDATA; } - s->sh.chroma_weight_l0[i][j] = (1 << s->sh.chroma_log2_weight_denom) + delta_chroma_weight_l0; - s->sh.chroma_offset_l0[i][j] = av_clip((delta_chroma_offset_l0 - ((128 * s->sh.chroma_weight_l0[i][j]) - >> s->sh.chroma_log2_weight_denom) + 128), -128, 127); + sh->chroma_weight_l0[i][j] = (1 << sh->chroma_log2_weight_denom) + delta_chroma_weight_l0; + sh->chroma_offset_l0[i][j] = av_clip((delta_chroma_offset_l0 - ((128 * sh->chroma_weight_l0[i][j]) + >> sh->chroma_log2_weight_denom) + 128), -128, 127); } } else { - s->sh.chroma_weight_l0[i][0] = 1 << s->sh.chroma_log2_weight_denom; - s->sh.chroma_offset_l0[i][0] = 0; - s->sh.chroma_weight_l0[i][1] = 1 << s->sh.chroma_log2_weight_denom; - s->sh.chroma_offset_l0[i][1] = 0; + sh->chroma_weight_l0[i][0] = 1 << sh->chroma_log2_weight_denom; + sh->chroma_offset_l0[i][0] = 0; + sh->chroma_weight_l0[i][1] = 1 << sh->chroma_log2_weight_denom; + sh->chroma_offset_l0[i][1] = 0; } } - if (s->sh.slice_type == HEVC_SLICE_B) { - for (i = 0; i < s->sh.nb_refs[L1]; i++) { + if (sh->slice_type == HEVC_SLICE_B) { + for (i = 0; i < sh->nb_refs[L1]; i++) { luma_weight_l1_flag[i] = get_bits1(gb); if (!luma_weight_l1_flag[i]) { - s->sh.luma_weight_l1[i] = 1 << s->sh.luma_log2_weight_denom; - s->sh.luma_offset_l1[i] = 0; + sh->luma_weight_l1[i] = 1 << sh->luma_log2_weight_denom; + sh->luma_offset_l1[i] = 0; } } - if (s->ps.sps->chroma_format_idc != 0) { - for (i = 0; i < s->sh.nb_refs[L1]; i++) + 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 < s->sh.nb_refs[L1]; i++) + for (i = 0; i < sh->nb_refs[L1]; i++) chroma_weight_l1_flag[i] = 0; } - for (i = 0; i < s->sh.nb_refs[L1]; i++) { + for (i = 0; i < sh->nb_refs[L1]; i++) { if (luma_weight_l1_flag[i]) { int delta_luma_weight_l1 = get_se_golomb(gb); if ((int8_t)delta_luma_weight_l1 != delta_luma_weight_l1) return AVERROR_INVALIDDATA; - s->sh.luma_weight_l1[i] = (1 << s->sh.luma_log2_weight_denom) + delta_luma_weight_l1; - s->sh.luma_offset_l1[i] = get_se_golomb(gb); + sh->luma_weight_l1[i] = (1 << sh->luma_log2_weight_denom) + delta_luma_weight_l1; + sh->luma_offset_l1[i] = get_se_golomb(gb); } if (chroma_weight_l1_flag[i]) { for (j = 0; j < 2; j++) { @@ -247,31 +271,31 @@ static int pred_weight_table(HEVCContext *s, GetBitContext *gb) return AVERROR_INVALIDDATA; } - s->sh.chroma_weight_l1[i][j] = (1 << s->sh.chroma_log2_weight_denom) + delta_chroma_weight_l1; - s->sh.chroma_offset_l1[i][j] = av_clip((delta_chroma_offset_l1 - ((128 * s->sh.chroma_weight_l1[i][j]) - >> s->sh.chroma_log2_weight_denom) + 128), -128, 127); + sh->chroma_weight_l1[i][j] = (1 << sh->chroma_log2_weight_denom) + delta_chroma_weight_l1; + sh->chroma_offset_l1[i][j] = av_clip((delta_chroma_offset_l1 - ((128 * sh->chroma_weight_l1[i][j]) + >> sh->chroma_log2_weight_denom) + 128), -128, 127); } } else { - s->sh.chroma_weight_l1[i][0] = 1 << s->sh.chroma_log2_weight_denom; - s->sh.chroma_offset_l1[i][0] = 0; - s->sh.chroma_weight_l1[i][1] = 1 << s->sh.chroma_log2_weight_denom; - s->sh.chroma_offset_l1[i][1] = 0; + sh->chroma_weight_l1[i][0] = 1 << sh->chroma_log2_weight_denom; + sh->chroma_offset_l1[i][0] = 0; + sh->chroma_weight_l1[i][1] = 1 << sh->chroma_log2_weight_denom; + sh->chroma_offset_l1[i][1] = 0; } } } return 0; } -static int decode_lt_rps(HEVCContext *s, LongTermRPS *rps, GetBitContext *gb) +static int decode_lt_rps(const HEVCSPS *sps, LongTermRPS *rps, + GetBitContext *gb, int cur_poc, int poc_lsb) { - const HEVCSPS *sps = s->ps.sps; int max_poc_lsb = 1 << sps->log2_max_poc_lsb; int prev_delta_msb = 0; unsigned int nb_sps = 0, nb_sh; int i; rps->nb_refs = 0; - if (!sps->long_term_ref_pics_present_flag) + if (!sps->long_term_ref_pics_present) return 0; if (sps->num_long_term_ref_pics_sps > 0) @@ -294,7 +318,7 @@ static int decode_lt_rps(HEVCContext *s, LongTermRPS *rps, GetBitContext *gb) lt_idx_sps = get_bits(gb, av_ceil_log2(sps->num_long_term_ref_pics_sps)); rps->poc[i] = sps->lt_ref_pic_poc_lsb_sps[lt_idx_sps]; - rps->used[i] = sps->used_by_curr_pic_lt_sps_flag[lt_idx_sps]; + rps->used[i] = !!(sps->used_by_curr_pic_lt & (1U << lt_idx_sps)); } else { rps->poc[i] = get_bits(gb, sps->log2_max_poc_lsb); rps->used[i] = get_bits1(gb); @@ -308,7 +332,7 @@ static int decode_lt_rps(HEVCContext *s, LongTermRPS *rps, GetBitContext *gb) if (i && i != nb_sps) delta += prev_delta_msb; - poc = rps->poc[i] + s->poc - delta * max_poc_lsb - s->sh.pic_order_cnt_lsb; + poc = rps->poc[i] + cur_poc - delta * max_poc_lsb - poc_lsb; if (poc != (int32_t)poc) return AVERROR_INVALIDDATA; rps->poc[i] = poc; @@ -322,8 +346,7 @@ static int decode_lt_rps(HEVCContext *s, LongTermRPS *rps, GetBitContext *gb) static void export_stream_params(HEVCContext *s, const HEVCSPS *sps) { AVCodecContext *avctx = s->avctx; - const HEVCParamSets *ps = &s->ps; - const HEVCVPS *vps = ps->vps_list[sps->vps_id]; + const HEVCVPS *vps = sps->vps; const HEVCWindow *ow = &sps->output_window; unsigned int num = 0, den = 0; @@ -371,7 +394,7 @@ static void export_stream_params(HEVCContext *s, const HEVCSPS *sps) den = sps->vui.vui_time_scale; } - if (num != 0 && den != 0) + if (num > 0 && den > 0) av_reduce(&avctx->framerate.den, &avctx->framerate.num, num, den, 1 << 30); } @@ -389,13 +412,116 @@ static int export_stream_params_from_sei(HEVCContext *s) avctx->color_trc = s->sei.common.alternative_transfer.preferred_transfer_characteristics; } - if (s->sei.common.film_grain_characteristics.present || + 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; return 0; } +static int export_multilayer(HEVCContext *s, const HEVCVPS *vps) +{ + const HEVCSEITDRDI *tdrdi = &s->sei.tdrdi; + + av_freep(&s->view_ids_available); + s->nb_view_ids_available = 0; + av_freep(&s->view_pos_available); + s->nb_view_pos_available = 0; + + // don't export anything in the trivial case (1 layer, view id=0) + if (vps->nb_layers < 2 && !vps->view_id[0]) + return 0; + + s->view_ids_available = av_calloc(vps->nb_layers, sizeof(*s->view_ids_available)); + if (!s->view_ids_available) + return AVERROR(ENOMEM); + + if (tdrdi->num_ref_displays) { + s->view_pos_available = av_calloc(vps->nb_layers, sizeof(*s->view_pos_available)); + if (!s->view_pos_available) + return AVERROR(ENOMEM); + } + + for (int i = 0; i < vps->nb_layers; i++) { + s->view_ids_available[i] = vps->view_id[i]; + + if (s->view_pos_available) { + s->view_pos_available[i] = vps->view_id[i] == tdrdi->left_view_id[0] ? + AV_STEREO3D_VIEW_LEFT : + vps->view_id[i] == tdrdi->right_view_id[0] ? + AV_STEREO3D_VIEW_RIGHT : AV_STEREO3D_VIEW_UNSPEC; + } + } + s->nb_view_ids_available = vps->nb_layers; + s->nb_view_pos_available = s->view_pos_available ? vps->nb_layers : 0; + + return 0; +} + +static int setup_multilayer(HEVCContext *s, const HEVCVPS *vps) +{ + unsigned layers_active_output = 0, highest_layer; + + s->layers_active_output = 1; + s->layers_active_decode = 1; + + // nothing requested - decode base layer only + if (!s->nb_view_ids) + return 0; + + if (s->nb_view_ids == 1 && s->view_ids[0] == -1) { + layers_active_output = (1 << vps->nb_layers) - 1; + } else { + for (int i = 0; i < s->nb_view_ids; i++) { + int view_id = s->view_ids[i]; + int layer_idx = -1; + + if (view_id < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Invalid view ID requested: %d\n", view_id); + return AVERROR(EINVAL); + } + + for (int j = 0; j < vps->nb_layers; j++) { + if (vps->view_id[j] == view_id) { + layer_idx = j; + break; + } + } + if (layer_idx < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "View ID %d not present in VPS\n", view_id); + return AVERROR(EINVAL); + } + layers_active_output |= 1 << layer_idx; + } + } + + if (!layers_active_output) { + av_log(s->avctx, AV_LOG_ERROR, "No layers selected\n"); + return AVERROR_BUG; + } + + highest_layer = ff_log2(layers_active_output); + if (highest_layer >= FF_ARRAY_ELEMS(s->layers)) { + av_log(s->avctx, AV_LOG_ERROR, + "Too many layers requested: %u\n", layers_active_output); + return AVERROR(EINVAL); + } + + /* Assume a higher layer depends on all the lower ones. + * This is enforced in VPS parsing currently, this logic will need + * to be changed if we want to support more complex dependency structures. + */ + s->layers_active_decode = (1 << (highest_layer + 1)) - 1; + s->layers_active_output = layers_active_output; + + av_log(s->avctx, AV_LOG_DEBUG, "decode/output layers: %x/%x\n", + s->layers_active_decode, s->layers_active_output); + + return 0; +} + static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) { #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \ @@ -407,6 +533,7 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) CONFIG_HEVC_VDPAU_HWACCEL + \ CONFIG_HEVC_VULKAN_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts; + int ret; switch (sps->pix_fmt) { case AV_PIX_FMT_YUV420P: @@ -526,147 +653,104 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) *fmt++ = sps->pix_fmt; *fmt = AV_PIX_FMT_NONE; - return ff_get_format(s->avctx, pix_fmts); + // export multilayer information from active VPS to the caller, + // so it is available in get_format() + ret = export_multilayer(s, sps->vps); + if (ret < 0) + return ret; + + ret = ff_get_format(s->avctx, pix_fmts); + if (ret < 0) + return ret; + s->avctx->pix_fmt = ret; + + // set up multilayer decoding, if requested by caller + ret = setup_multilayer(s, sps->vps); + if (ret < 0) + return ret; + + return 0; } -static int set_sps(HEVCContext *s, const HEVCSPS *sps, - enum AVPixelFormat pix_fmt) +static int set_sps(HEVCContext *s, HEVCLayerContext *l, const HEVCSPS *sps) { - int ret, i; + int ret; - pic_arrays_free(s); - s->ps.sps = NULL; - s->ps.vps = NULL; + pic_arrays_free(l); + ff_refstruct_unref(&l->sps); + ff_refstruct_unref(&s->vps); if (!sps) return 0; - ret = pic_arrays_init(s, sps); + ret = pic_arrays_init(l, sps); if (ret < 0) goto fail; - export_stream_params(s, sps); - - s->avctx->pix_fmt = pix_fmt; - ff_hevc_pred_init(&s->hpc, sps->bit_depth); ff_hevc_dsp_init (&s->hevcdsp, sps->bit_depth); ff_videodsp_init (&s->vdsp, sps->bit_depth); - for (i = 0; i < 3; i++) { - av_freep(&s->sao_pixel_buffer_h[i]); - av_freep(&s->sao_pixel_buffer_v[i]); - } - - if (sps->sao_enabled && !s->avctx->hwaccel) { - int c_count = (sps->chroma_format_idc != 0) ? 3 : 1; - int c_idx; - - for(c_idx = 0; c_idx < c_count; c_idx++) { - int w = sps->width >> sps->hshift[c_idx]; - int h = sps->height >> sps->vshift[c_idx]; - s->sao_pixel_buffer_h[c_idx] = - av_malloc((w * 2 * sps->ctb_height) << - sps->pixel_shift); - s->sao_pixel_buffer_v[c_idx] = - av_malloc((h * 2 * sps->ctb_width) << - sps->pixel_shift); - if (!s->sao_pixel_buffer_h[c_idx] || - !s->sao_pixel_buffer_v[c_idx]) - goto fail; - } - } - - s->ps.sps = sps; - s->ps.vps = s->ps.vps_list[s->ps.sps->vps_id]; + l->sps = ff_refstruct_ref_c(sps); + s->vps = ff_refstruct_ref_c(sps->vps); return 0; fail: - pic_arrays_free(s); - for (i = 0; i < 3; i++) { - av_freep(&s->sao_pixel_buffer_h[i]); - av_freep(&s->sao_pixel_buffer_v[i]); - } - s->ps.sps = NULL; + pic_arrays_free(l); + ff_refstruct_unref(&l->sps); return ret; } -static int hls_slice_header(HEVCContext *s) +static int hls_slice_header(SliceHeader *sh, const HEVCContext *s, GetBitContext *gb) { - GetBitContext *gb = &s->HEVClc->gb; - SliceHeader *sh = &s->sh; + const HEVCPPS *pps; + const HEVCSPS *sps; + const HEVCVPS *vps; + unsigned pps_id, layer_idx; int i, ret; // Coded parameters sh->first_slice_in_pic_flag = get_bits1(gb); - if (s->ref && sh->first_slice_in_pic_flag) { - av_log(s->avctx, AV_LOG_ERROR, "Two slices reporting being the first in the same frame.\n"); - return 1; // This slice will be skipped later, do not corrupt state - } - if ((IS_IDR(s) || IS_BLA(s)) && sh->first_slice_in_pic_flag) { - s->seq_decode = (s->seq_decode + 1) & HEVC_SEQUENCE_COUNTER_MASK; - s->max_ra = INT_MAX; - if (IS_IDR(s)) - ff_hevc_clear_refs(s); - } sh->no_output_of_prior_pics_flag = 0; if (IS_IRAP(s)) sh->no_output_of_prior_pics_flag = get_bits1(gb); - sh->pps_id = get_ue_golomb_long(gb); - if (sh->pps_id >= HEVC_MAX_PPS_COUNT || !s->ps.pps_list[sh->pps_id]) { - av_log(s->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", sh->pps_id); + pps_id = get_ue_golomb_long(gb); + if (pps_id >= HEVC_MAX_PPS_COUNT || !s->ps.pps_list[pps_id]) { + av_log(s->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", pps_id); return AVERROR_INVALIDDATA; } - if (!sh->first_slice_in_pic_flag && - s->ps.pps != s->ps.pps_list[sh->pps_id]) { + if (!sh->first_slice_in_pic_flag && s->ps.pps_list[pps_id] != s->pps) { av_log(s->avctx, AV_LOG_ERROR, "PPS changed between slices.\n"); return AVERROR_INVALIDDATA; } - s->ps.pps = s->ps.pps_list[sh->pps_id]; + sh->pps_id = pps_id; + + pps = s->ps.pps_list[pps_id]; + sps = pps->sps; + vps = sps->vps; + layer_idx = vps->layer_idx[s->nuh_layer_id]; + if (s->nal_unit_type == HEVC_NAL_CRA_NUT && s->last_eos == 1) sh->no_output_of_prior_pics_flag = 1; - if (s->ps.sps != s->ps.sps_list[s->ps.pps->sps_id]) { - const HEVCSPS *sps = s->ps.sps_list[s->ps.pps->sps_id]; - enum AVPixelFormat pix_fmt; - - ff_hevc_clear_refs(s); - - ret = set_sps(s, sps, sps->pix_fmt); - if (ret < 0) - return ret; - - pix_fmt = get_format(s, sps); - if (pix_fmt < 0) - return pix_fmt; - s->avctx->pix_fmt = pix_fmt; - - s->seq_decode = (s->seq_decode + 1) & HEVC_SEQUENCE_COUNTER_MASK; - s->max_ra = INT_MAX; - } - - ret = export_stream_params_from_sei(s); - if (ret < 0) - return ret; - sh->dependent_slice_segment_flag = 0; if (!sh->first_slice_in_pic_flag) { int slice_address_length; - if (s->ps.pps->dependent_slice_segments_enabled_flag) + if (pps->dependent_slice_segments_enabled_flag) sh->dependent_slice_segment_flag = get_bits1(gb); if (sh->dependent_slice_segment_flag && !s->slice_initialized) { av_log(s->avctx, AV_LOG_ERROR, "Independent slice segment missing.\n"); return AVERROR_INVALIDDATA; } - slice_address_length = av_ceil_log2(s->ps.sps->ctb_width * - s->ps.sps->ctb_height); + slice_address_length = av_ceil_log2(sps->ctb_width * + sps->ctb_height); sh->slice_segment_addr = get_bitsz(gb, slice_address_length); - if (sh->slice_segment_addr >= s->ps.sps->ctb_width * s->ps.sps->ctb_height) { + if (sh->slice_segment_addr >= sps->ctb_width * sps->ctb_height) { av_log(s->avctx, AV_LOG_ERROR, "Invalid slice segment address: %u.\n", sh->slice_segment_addr); @@ -675,18 +759,13 @@ static int hls_slice_header(HEVCContext *s) if (!sh->dependent_slice_segment_flag) { sh->slice_addr = sh->slice_segment_addr; - s->slice_idx++; } } else { sh->slice_segment_addr = sh->slice_addr = 0; - s->slice_idx = 0; - s->slice_initialized = 0; } if (!sh->dependent_slice_segment_flag) { - s->slice_initialized = 0; - - for (i = 0; i < s->ps.pps->num_extra_slice_header_bits; i++) + for (i = 0; i < pps->num_extra_slice_header_bits; i++) skip_bits(gb, 1); // slice_reserved_undetermined_flag[] sh->slice_type = get_ue_golomb_long(gb); @@ -698,37 +777,44 @@ static int hls_slice_header(HEVCContext *s) return AVERROR_INVALIDDATA; } if (IS_IRAP(s) && sh->slice_type != HEVC_SLICE_I && - !s->ps.pps->pps_curr_pic_ref_enabled_flag) { + !pps->pps_curr_pic_ref_enabled_flag && + s->nuh_layer_id == 0) { av_log(s->avctx, AV_LOG_ERROR, "Inter slices in an IRAP frame.\n"); return AVERROR_INVALIDDATA; } // when flag is not present, picture is inferred to be output sh->pic_output_flag = 1; - if (s->ps.pps->output_flag_present_flag) + if (pps->output_flag_present_flag) sh->pic_output_flag = get_bits1(gb); - if (s->ps.sps->separate_colour_plane_flag) + if (sps->separate_colour_plane) sh->colour_plane_id = get_bits(gb, 2); - if (!IS_IDR(s)) { - int poc, pos; + if (!IS_IDR(s) || + (s->nuh_layer_id > 0 && + !(vps->poc_lsb_not_present & (1 << layer_idx)))) { + int poc; - sh->pic_order_cnt_lsb = get_bits(gb, s->ps.sps->log2_max_poc_lsb); - poc = ff_hevc_compute_poc(s->ps.sps, s->pocTid0, sh->pic_order_cnt_lsb, s->nal_unit_type); - if (!sh->first_slice_in_pic_flag && poc != s->poc) { + sh->pic_order_cnt_lsb = get_bits(gb, sps->log2_max_poc_lsb); + poc = ff_hevc_compute_poc(sps, s->poc_tid0, sh->pic_order_cnt_lsb, s->nal_unit_type); + if (!sh->first_slice_in_pic_flag && poc != sh->poc) { av_log(s->avctx, AV_LOG_WARNING, - "Ignoring POC change between slices: %d -> %d\n", s->poc, poc); + "Ignoring POC change between slices: %d -> %d\n", poc, sh->poc); if (s->avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_INVALIDDATA; - poc = s->poc; + poc = sh->poc; } - s->poc = poc; + sh->poc = poc; + } + + if (!IS_IDR(s)) { + int pos; sh->short_term_ref_pic_set_sps_flag = get_bits1(gb); pos = get_bits_left(gb); if (!sh->short_term_ref_pic_set_sps_flag) { - ret = ff_hevc_decode_short_term_rps(gb, s->avctx, &sh->slice_rps, s->ps.sps, 1); + ret = ff_hevc_decode_short_term_rps(gb, s->avctx, &sh->slice_rps, sps, 1); if (ret < 0) return ret; @@ -736,19 +822,19 @@ static int hls_slice_header(HEVCContext *s) } else { int numbits, rps_idx; - if (!s->ps.sps->nb_st_rps) { + if (!sps->nb_st_rps) { av_log(s->avctx, AV_LOG_ERROR, "No ref lists in the SPS.\n"); return AVERROR_INVALIDDATA; } - numbits = av_ceil_log2(s->ps.sps->nb_st_rps); + numbits = av_ceil_log2(sps->nb_st_rps); rps_idx = numbits > 0 ? get_bits(gb, numbits) : 0; - sh->short_term_rps = &s->ps.sps->st_rps[rps_idx]; + sh->short_term_rps = &sps->st_rps[rps_idx]; } sh->short_term_ref_pic_set_size = pos - get_bits_left(gb); pos = get_bits_left(gb); - ret = decode_lt_rps(s, &sh->long_term_rps, gb); + ret = decode_lt_rps(sps, &sh->long_term_rps, gb, sh->poc, sh->pic_order_cnt_lsb); if (ret < 0) { av_log(s->avctx, AV_LOG_WARNING, "Invalid long term RPS.\n"); if (s->avctx->err_recognition & AV_EF_EXPLODE) @@ -756,12 +842,12 @@ static int hls_slice_header(HEVCContext *s) } sh->long_term_ref_pic_set_size = pos - get_bits_left(gb); - if (s->ps.sps->sps_temporal_mvp_enabled_flag) + if (sps->temporal_mvp_enabled) sh->slice_temporal_mvp_enabled_flag = get_bits1(gb); else sh->slice_temporal_mvp_enabled_flag = 0; } else { - s->poc = 0; + sh->poc = 0; sh->pic_order_cnt_lsb = 0; sh->short_term_ref_pic_set_sps_flag = 0; sh->short_term_ref_pic_set_size = 0; @@ -770,20 +856,26 @@ static int hls_slice_header(HEVCContext *s) sh->slice_temporal_mvp_enabled_flag = 0; } - /* 8.3.1 */ - if (sh->first_slice_in_pic_flag && s->temporal_id == 0 && - s->nal_unit_type != HEVC_NAL_TRAIL_N && - s->nal_unit_type != HEVC_NAL_TSA_N && - s->nal_unit_type != HEVC_NAL_STSA_N && - s->nal_unit_type != HEVC_NAL_RADL_N && - s->nal_unit_type != HEVC_NAL_RADL_R && - s->nal_unit_type != HEVC_NAL_RASL_N && - s->nal_unit_type != HEVC_NAL_RASL_R) - s->pocTid0 = s->poc; + sh->inter_layer_pred = 0; + if (s->nuh_layer_id > 0) { + int num_direct_ref_layers = vps->num_direct_ref_layers[layer_idx]; - if (s->ps.sps->sao_enabled) { + if (vps->default_ref_layers_active) + sh->inter_layer_pred = !!num_direct_ref_layers; + else if (num_direct_ref_layers) { + sh->inter_layer_pred = get_bits1(gb); + + if (sh->inter_layer_pred && num_direct_ref_layers > 1) { + av_log(s->avctx, AV_LOG_ERROR, + "NumDirectRefLayers>1 not supported\n"); + return AVERROR_PATCHWELCOME; + } + } + } + + if (sps->sao_enabled) { sh->slice_sample_adaptive_offset_flag[0] = get_bits1(gb); - if (s->ps.sps->chroma_format_idc) { + if (sps->chroma_format_idc) { sh->slice_sample_adaptive_offset_flag[1] = sh->slice_sample_adaptive_offset_flag[2] = get_bits1(gb); } @@ -797,9 +889,9 @@ static int hls_slice_header(HEVCContext *s) if (sh->slice_type == HEVC_SLICE_P || sh->slice_type == HEVC_SLICE_B) { int nb_refs; - sh->nb_refs[L0] = s->ps.pps->num_ref_idx_l0_default_active; + sh->nb_refs[L0] = pps->num_ref_idx_l0_default_active; if (sh->slice_type == HEVC_SLICE_B) - sh->nb_refs[L1] = s->ps.pps->num_ref_idx_l1_default_active; + sh->nb_refs[L1] = pps->num_ref_idx_l1_default_active; if (get_bits1(gb)) { // num_ref_idx_active_override_flag sh->nb_refs[L0] = get_ue_golomb_31(gb) + 1; @@ -814,13 +906,13 @@ static int hls_slice_header(HEVCContext *s) sh->rpl_modification_flag[0] = 0; sh->rpl_modification_flag[1] = 0; - nb_refs = ff_hevc_frame_nb_refs(s); + nb_refs = ff_hevc_frame_nb_refs(sh, pps, layer_idx); if (!nb_refs) { av_log(s->avctx, AV_LOG_ERROR, "Zero refs for a frame with P or B slices.\n"); return AVERROR_INVALIDDATA; } - if (s->ps.pps->lists_modification_present_flag && nb_refs > 1) { + if (pps->lists_modification_present_flag && nb_refs > 1) { sh->rpl_modification_flag[0] = get_bits1(gb); if (sh->rpl_modification_flag[0]) { for (i = 0; i < sh->nb_refs[L0]; i++) @@ -838,7 +930,7 @@ static int hls_slice_header(HEVCContext *s) if (sh->slice_type == HEVC_SLICE_B) sh->mvd_l1_zero_flag = get_bits1(gb); - if (s->ps.pps->cabac_init_present_flag) + if (pps->cabac_init_present_flag) sh->cabac_init_flag = get_bits1(gb); else sh->cabac_init_flag = 0; @@ -860,9 +952,9 @@ static int hls_slice_header(HEVCContext *s) } } - if ((s->ps.pps->weighted_pred_flag && sh->slice_type == HEVC_SLICE_P) || - (s->ps.pps->weighted_bipred_flag && sh->slice_type == HEVC_SLICE_B)) { - int ret = pred_weight_table(s, gb); + if ((pps->weighted_pred_flag && sh->slice_type == HEVC_SLICE_P) || + (pps->weighted_bipred_flag && sh->slice_type == HEVC_SLICE_B)) { + int ret = pred_weight_table(sh, s->avctx, sps, gb); if (ret < 0) return ret; } @@ -876,17 +968,17 @@ static int hls_slice_header(HEVCContext *s) } // Syntax in 7.3.6.1 - if (s->ps.sps->motion_vector_resolution_control_idc == 2) + if (sps->motion_vector_resolution_control_idc == 2) sh->use_integer_mv_flag = get_bits1(gb); else // Inferred to be equal to motion_vector_resolution_control_idc if not present - sh->use_integer_mv_flag = s->ps.sps->motion_vector_resolution_control_idc; + sh->use_integer_mv_flag = sps->motion_vector_resolution_control_idc; } sh->slice_qp_delta = get_se_golomb(gb); - if (s->ps.pps->pic_slice_level_chroma_qp_offsets_present_flag) { + if (pps->pic_slice_level_chroma_qp_offsets_present_flag) { sh->slice_cb_qp_offset = get_se_golomb(gb); sh->slice_cr_qp_offset = get_se_golomb(gb); if (sh->slice_cb_qp_offset < -12 || sh->slice_cb_qp_offset > 12 || @@ -899,21 +991,21 @@ static int hls_slice_header(HEVCContext *s) sh->slice_cr_qp_offset = 0; } - if (s->ps.pps->pps_slice_act_qp_offsets_present_flag) { + if (pps->pps_slice_act_qp_offsets_present_flag) { sh->slice_act_y_qp_offset = get_se_golomb(gb); sh->slice_act_cb_qp_offset = get_se_golomb(gb); sh->slice_act_cr_qp_offset = get_se_golomb(gb); } - if (s->ps.pps->chroma_qp_offset_list_enabled_flag) + if (pps->chroma_qp_offset_list_enabled_flag) sh->cu_chroma_qp_offset_enabled_flag = get_bits1(gb); else sh->cu_chroma_qp_offset_enabled_flag = 0; - if (s->ps.pps->deblocking_filter_control_present_flag) { + if (pps->deblocking_filter_control_present_flag) { int deblocking_filter_override_flag = 0; - if (s->ps.pps->deblocking_filter_override_enabled_flag) + if (pps->deblocking_filter_override_enabled_flag) deblocking_filter_override_flag = get_bits1(gb); if (deblocking_filter_override_flag) { @@ -932,9 +1024,9 @@ static int hls_slice_header(HEVCContext *s) sh->tc_offset = tc_offset_div2 * 2; } } else { - sh->disable_deblocking_filter_flag = s->ps.pps->disable_dbf; - sh->beta_offset = s->ps.pps->beta_offset; - sh->tc_offset = s->ps.pps->tc_offset; + sh->disable_deblocking_filter_flag = pps->disable_dbf; + sh->beta_offset = pps->beta_offset; + sh->tc_offset = pps->tc_offset; } } else { sh->disable_deblocking_filter_flag = 0; @@ -942,18 +1034,18 @@ static int hls_slice_header(HEVCContext *s) sh->tc_offset = 0; } - if (s->ps.pps->seq_loop_filter_across_slices_enabled_flag && + if (pps->seq_loop_filter_across_slices_enabled_flag && (sh->slice_sample_adaptive_offset_flag[0] || sh->slice_sample_adaptive_offset_flag[1] || !sh->disable_deblocking_filter_flag)) { sh->slice_loop_filter_across_slices_enabled_flag = get_bits1(gb); } else { - sh->slice_loop_filter_across_slices_enabled_flag = s->ps.pps->seq_loop_filter_across_slices_enabled_flag; + sh->slice_loop_filter_across_slices_enabled_flag = pps->seq_loop_filter_across_slices_enabled_flag; } } sh->num_entry_point_offsets = 0; - if (s->ps.pps->tiles_enabled_flag || s->ps.pps->entropy_coding_sync_enabled_flag) { + if (pps->tiles_enabled_flag || pps->entropy_coding_sync_enabled_flag) { unsigned num_entry_point_offsets = get_ue_golomb_long(gb); // It would be possible to bound this tighter but this here is simpler if (num_entry_point_offsets > get_bits_left(gb)) { @@ -975,8 +1067,8 @@ static int hls_slice_header(HEVCContext *s) av_freep(&sh->offset); av_freep(&sh->size); sh->entry_point_offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(unsigned)); - sh->offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(int)); - sh->size = av_malloc_array(sh->num_entry_point_offsets, sizeof(int)); + sh->offset = av_malloc_array(sh->num_entry_point_offsets + 1, sizeof(int)); + sh->size = av_malloc_array(sh->num_entry_point_offsets + 1, sizeof(int)); if (!sh->entry_point_offset || !sh->offset || !sh->size) { sh->num_entry_point_offsets = 0; av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate memory\n"); @@ -986,16 +1078,10 @@ static int hls_slice_header(HEVCContext *s) unsigned val = get_bits_long(gb, offset_len); sh->entry_point_offset[i] = val + 1; // +1; // +1 to get the size } - if (s->threads_number > 1 && (s->ps.pps->num_tile_rows > 1 || s->ps.pps->num_tile_columns > 1)) { - s->enable_parallel_tiles = 0; // TODO: you can enable tiles in parallel here - s->threads_number = 1; - } else - s->enable_parallel_tiles = 0; - } else - s->enable_parallel_tiles = 0; + } } - if (s->ps.pps->slice_header_extension_present_flag) { + if (pps->slice_header_extension_present_flag) { unsigned int length = get_ue_golomb_long(gb); if (length*8LL > get_bits_left(gb)) { av_log(s->avctx, AV_LOG_ERROR, "too many slice_header_extension_data_bytes\n"); @@ -1005,21 +1091,29 @@ static int hls_slice_header(HEVCContext *s) skip_bits(gb, 8); // slice_header_extension_data_byte } + ret = get_bits1(gb); + if (!ret) { + 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; + // Inferred parameters - sh->slice_qp = 26U + s->ps.pps->pic_init_qp_minus26 + sh->slice_qp_delta; + sh->slice_qp = 26U + pps->pic_init_qp_minus26 + sh->slice_qp_delta; if (sh->slice_qp > 51 || - sh->slice_qp < -s->ps.sps->qp_bd_offset) { + sh->slice_qp < -sps->qp_bd_offset) { av_log(s->avctx, AV_LOG_ERROR, "The slice_qp %d is outside the valid range " "[%d, 51].\n", sh->slice_qp, - -s->ps.sps->qp_bd_offset); + -sps->qp_bd_offset); return AVERROR_INVALIDDATA; } sh->slice_ctb_addr_rs = sh->slice_segment_addr; - if (!s->sh.slice_ctb_addr_rs && s->sh.dependent_slice_segment_flag) { + if (sh->dependent_slice_segment_flag && + (!sh->slice_ctb_addr_rs || !pps->ctb_addr_rs_to_ts[sh->slice_ctb_addr_rs])) { av_log(s->avctx, AV_LOG_ERROR, "Impossible slice segment.\n"); return AVERROR_INVALIDDATA; } @@ -1030,38 +1124,31 @@ static int hls_slice_header(HEVCContext *s) return AVERROR_INVALIDDATA; } - s->HEVClc->first_qp_group = !s->sh.dependent_slice_segment_flag; - - if (!s->ps.pps->cu_qp_delta_enabled_flag) - s->HEVClc->qp_y = s->sh.slice_qp; - - s->slice_initialized = 1; - s->HEVClc->tu.cu_qp_offset_cb = 0; - s->HEVClc->tu.cu_qp_offset_cr = 0; - return 0; } -#define CTB(tab, x, y) ((tab)[(y) * s->ps.sps->ctb_width + (x)]) +#define CTB(tab, x, y) ((tab)[(y) * sps->ctb_width + (x)]) #define SET_SAO(elem, value) \ do { \ if (!sao_merge_up_flag && !sao_merge_left_flag) \ sao->elem = value; \ else if (sao_merge_left_flag) \ - sao->elem = CTB(s->sao, rx-1, ry).elem; \ + sao->elem = CTB(l->sao, rx-1, ry).elem; \ else if (sao_merge_up_flag) \ - sao->elem = CTB(s->sao, rx, ry-1).elem; \ + sao->elem = CTB(l->sao, rx, ry-1).elem; \ else \ sao->elem = 0; \ } while (0) -static void hls_sao_param(HEVCLocalContext *lc, int rx, int ry) +static void hls_sao_param(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, + int rx, int ry) { const HEVCContext *const s = lc->parent; int sao_merge_left_flag = 0; int sao_merge_up_flag = 0; - SAOParams *sao = &CTB(s->sao, rx, ry); + SAOParams *sao = &CTB(l->sao, rx, ry); int c_idx, i; if (s->sh.slice_sample_adaptive_offset_flag[0] || @@ -1076,9 +1163,9 @@ static void hls_sao_param(HEVCLocalContext *lc, int rx, int ry) } } - for (c_idx = 0; c_idx < (s->ps.sps->chroma_format_idc ? 3 : 1); c_idx++) { - int log2_sao_offset_scale = c_idx == 0 ? s->ps.pps->log2_sao_offset_scale_luma : - s->ps.pps->log2_sao_offset_scale_chroma; + for (c_idx = 0; c_idx < (sps->chroma_format_idc ? 3 : 1); c_idx++) { + int log2_sao_offset_scale = c_idx == 0 ? pps->log2_sao_offset_scale_luma : + pps->log2_sao_offset_scale_chroma; if (!s->sh.slice_sample_adaptive_offset_flag[c_idx]) { sao->type_idx[c_idx] = SAO_NOT_APPLIED; @@ -1096,7 +1183,7 @@ static void hls_sao_param(HEVCLocalContext *lc, int rx, int ry) continue; for (i = 0; i < 4; i++) - SET_SAO(offset_abs[c_idx][i], ff_hevc_sao_offset_abs_decode(lc)); + SET_SAO(offset_abs[c_idx][i], ff_hevc_sao_offset_abs_decode(lc, sps->bit_depth)); if (sao->type_idx[c_idx] == SAO_BAND) { for (i = 0; i < 4; i++) { @@ -1146,49 +1233,52 @@ static int hls_cross_component_pred(HEVCLocalContext *lc, int idx) return 0; } -static int hls_transform_unit(HEVCLocalContext *lc, int x0, int y0, +static int hls_transform_unit(HEVCLocalContext *lc, + const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, + int x0, int y0, int xBase, int yBase, int cb_xBase, int cb_yBase, int log2_cb_size, int log2_trafo_size, int blk_idx, int cbf_luma, int *cbf_cb, int *cbf_cr) { const HEVCContext *const s = lc->parent; - const int log2_trafo_size_c = log2_trafo_size - s->ps.sps->hshift[1]; + const int log2_trafo_size_c = log2_trafo_size - sps->hshift[1]; int i; if (lc->cu.pred_mode == MODE_INTRA) { int trafo_size = 1 << log2_trafo_size; - ff_hevc_set_neighbour_available(lc, x0, y0, trafo_size, trafo_size); + ff_hevc_set_neighbour_available(lc, x0, y0, trafo_size, trafo_size, sps->log2_ctb_size); - s->hpc.intra_pred[log2_trafo_size - 2](lc, x0, y0, 0); + s->hpc.intra_pred[log2_trafo_size - 2](lc, pps, x0, y0, 0); } if (cbf_luma || cbf_cb[0] || cbf_cr[0] || - (s->ps.sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) { + (sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) { int scan_idx = SCAN_DIAG; int scan_idx_c = SCAN_DIAG; int cbf_chroma = cbf_cb[0] || cbf_cr[0] || - (s->ps.sps->chroma_format_idc == 2 && + (sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1])); - if (s->ps.pps->cu_qp_delta_enabled_flag && !lc->tu.is_cu_qp_delta_coded) { + if (pps->cu_qp_delta_enabled_flag && !lc->tu.is_cu_qp_delta_coded) { lc->tu.cu_qp_delta = ff_hevc_cu_qp_delta_abs(lc); if (lc->tu.cu_qp_delta != 0) if (ff_hevc_cu_qp_delta_sign_flag(lc) == 1) lc->tu.cu_qp_delta = -lc->tu.cu_qp_delta; lc->tu.is_cu_qp_delta_coded = 1; - if (lc->tu.cu_qp_delta < -(26 + s->ps.sps->qp_bd_offset / 2) || - lc->tu.cu_qp_delta > (25 + s->ps.sps->qp_bd_offset / 2)) { + if (lc->tu.cu_qp_delta < -(26 + sps->qp_bd_offset / 2) || + lc->tu.cu_qp_delta > (25 + sps->qp_bd_offset / 2)) { av_log(s->avctx, AV_LOG_ERROR, "The cu_qp_delta %d is outside the valid range " "[%d, %d].\n", lc->tu.cu_qp_delta, - -(26 + s->ps.sps->qp_bd_offset / 2), - (25 + s->ps.sps->qp_bd_offset / 2)); + -(26 + sps->qp_bd_offset / 2), + (25 + sps->qp_bd_offset / 2)); return AVERROR_INVALIDDATA; } - ff_hevc_set_qPy(lc, cb_xBase, cb_yBase, log2_cb_size); + ff_hevc_set_qPy(lc, l, pps, cb_xBase, cb_yBase, log2_cb_size); } if (s->sh.cu_chroma_qp_offset_enabled_flag && cbf_chroma && @@ -1196,13 +1286,13 @@ static int hls_transform_unit(HEVCLocalContext *lc, int x0, int y0, int cu_chroma_qp_offset_flag = ff_hevc_cu_chroma_qp_offset_flag(lc); if (cu_chroma_qp_offset_flag) { int cu_chroma_qp_offset_idx = 0; - if (s->ps.pps->chroma_qp_offset_list_len_minus1 > 0) { - cu_chroma_qp_offset_idx = ff_hevc_cu_chroma_qp_offset_idx(lc); + if (pps->chroma_qp_offset_list_len_minus1 > 0) { + cu_chroma_qp_offset_idx = ff_hevc_cu_chroma_qp_offset_idx(lc, pps->chroma_qp_offset_list_len_minus1); av_log(s->avctx, AV_LOG_ERROR, "cu_chroma_qp_offset_idx not yet tested.\n"); } - lc->tu.cu_qp_offset_cb = s->ps.pps->cb_qp_offset_list[cu_chroma_qp_offset_idx]; - lc->tu.cu_qp_offset_cr = s->ps.pps->cr_qp_offset_list[cu_chroma_qp_offset_idx]; + lc->tu.cu_qp_offset_cb = pps->cb_qp_offset_list[cu_chroma_qp_offset_idx]; + lc->tu.cu_qp_offset_cr = pps->cr_qp_offset_list[cu_chroma_qp_offset_idx]; } else { lc->tu.cu_qp_offset_cb = 0; lc->tu.cu_qp_offset_cr = 0; @@ -1231,36 +1321,37 @@ static int hls_transform_unit(HEVCLocalContext *lc, int x0, int y0, lc->tu.cross_pf = 0; if (cbf_luma) - ff_hevc_hls_residual_coding(lc, x0, y0, log2_trafo_size, scan_idx, 0); - if (s->ps.sps->chroma_format_idc && (log2_trafo_size > 2 || s->ps.sps->chroma_format_idc == 3)) { - int trafo_size_h = 1 << (log2_trafo_size_c + s->ps.sps->hshift[1]); - int trafo_size_v = 1 << (log2_trafo_size_c + s->ps.sps->vshift[1]); - lc->tu.cross_pf = (s->ps.pps->cross_component_prediction_enabled_flag && cbf_luma && + ff_hevc_hls_residual_coding(lc, pps, x0, y0, log2_trafo_size, scan_idx, 0); + if (sps->chroma_format_idc && (log2_trafo_size > 2 || sps->chroma_format_idc == 3)) { + int trafo_size_h = 1 << (log2_trafo_size_c + sps->hshift[1]); + int trafo_size_v = 1 << (log2_trafo_size_c + sps->vshift[1]); + lc->tu.cross_pf = (pps->cross_component_prediction_enabled_flag && cbf_luma && (lc->cu.pred_mode == MODE_INTER || (lc->tu.chroma_mode_c == 4))); if (lc->tu.cross_pf) { hls_cross_component_pred(lc, 0); } - for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) { + for (i = 0; i < (sps->chroma_format_idc == 2 ? 2 : 1); i++) { if (lc->cu.pred_mode == MODE_INTRA) { - ff_hevc_set_neighbour_available(lc, x0, y0 + (i << log2_trafo_size_c), trafo_size_h, trafo_size_v); - s->hpc.intra_pred[log2_trafo_size_c - 2](lc, x0, y0 + (i << log2_trafo_size_c), 1); + ff_hevc_set_neighbour_available(lc, x0, y0 + (i << log2_trafo_size_c), + trafo_size_h, trafo_size_v, sps->log2_ctb_size); + s->hpc.intra_pred[log2_trafo_size_c - 2](lc, pps, x0, y0 + (i << log2_trafo_size_c), 1); } if (cbf_cb[i]) - ff_hevc_hls_residual_coding(lc, x0, y0 + (i << log2_trafo_size_c), + ff_hevc_hls_residual_coding(lc, pps, x0, y0 + (i << log2_trafo_size_c), log2_trafo_size_c, scan_idx_c, 1); else if (lc->tu.cross_pf) { - ptrdiff_t stride = s->frame->linesize[1]; - int hshift = s->ps.sps->hshift[1]; - int vshift = s->ps.sps->vshift[1]; + ptrdiff_t stride = s->cur_frame->f->linesize[1]; + int hshift = sps->hshift[1]; + int vshift = sps->vshift[1]; const int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer; int16_t *coeffs = (int16_t*)lc->edge_emu_buffer2; int size = 1 << log2_trafo_size_c; - uint8_t *dst = &s->frame->data[1][(y0 >> vshift) * stride + - ((x0 >> hshift) << s->ps.sps->pixel_shift)]; + uint8_t *dst = &s->cur_frame->f->data[1][(y0 >> vshift) * stride + + ((x0 >> hshift) << sps->pixel_shift)]; for (i = 0; i < (size * size); i++) { coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3); } @@ -1271,81 +1362,82 @@ static int hls_transform_unit(HEVCLocalContext *lc, int x0, int y0, if (lc->tu.cross_pf) { hls_cross_component_pred(lc, 1); } - for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) { + for (i = 0; i < (sps->chroma_format_idc == 2 ? 2 : 1); i++) { if (lc->cu.pred_mode == MODE_INTRA) { ff_hevc_set_neighbour_available(lc, x0, y0 + (i << log2_trafo_size_c), - trafo_size_h, trafo_size_v); - s->hpc.intra_pred[log2_trafo_size_c - 2](lc, x0, y0 + (i << log2_trafo_size_c), 2); + trafo_size_h, trafo_size_v, sps->log2_ctb_size); + s->hpc.intra_pred[log2_trafo_size_c - 2](lc, pps, x0, y0 + (i << log2_trafo_size_c), 2); } if (cbf_cr[i]) - ff_hevc_hls_residual_coding(lc, x0, y0 + (i << log2_trafo_size_c), + ff_hevc_hls_residual_coding(lc, pps, x0, y0 + (i << log2_trafo_size_c), log2_trafo_size_c, scan_idx_c, 2); else if (lc->tu.cross_pf) { - ptrdiff_t stride = s->frame->linesize[2]; - int hshift = s->ps.sps->hshift[2]; - int vshift = s->ps.sps->vshift[2]; + ptrdiff_t stride = s->cur_frame->f->linesize[2]; + int hshift = sps->hshift[2]; + int vshift = sps->vshift[2]; const int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer; int16_t *coeffs = (int16_t*)lc->edge_emu_buffer2; int size = 1 << log2_trafo_size_c; - uint8_t *dst = &s->frame->data[2][(y0 >> vshift) * stride + - ((x0 >> hshift) << s->ps.sps->pixel_shift)]; + uint8_t *dst = &s->cur_frame->f->data[2][(y0 >> vshift) * stride + + ((x0 >> hshift) << sps->pixel_shift)]; for (i = 0; i < (size * size); i++) { coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3); } s->hevcdsp.add_residual[log2_trafo_size_c-2](dst, coeffs, stride); } } - } else if (s->ps.sps->chroma_format_idc && blk_idx == 3) { + } else if (sps->chroma_format_idc && blk_idx == 3) { int trafo_size_h = 1 << (log2_trafo_size + 1); - int trafo_size_v = 1 << (log2_trafo_size + s->ps.sps->vshift[1]); - for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) { + int trafo_size_v = 1 << (log2_trafo_size + sps->vshift[1]); + for (i = 0; i < (sps->chroma_format_idc == 2 ? 2 : 1); i++) { if (lc->cu.pred_mode == MODE_INTRA) { ff_hevc_set_neighbour_available(lc, xBase, yBase + (i << log2_trafo_size), - trafo_size_h, trafo_size_v); - s->hpc.intra_pred[log2_trafo_size - 2](lc, xBase, yBase + (i << log2_trafo_size), 1); + trafo_size_h, trafo_size_v, sps->log2_ctb_size); + s->hpc.intra_pred[log2_trafo_size - 2](lc, pps, xBase, yBase + (i << log2_trafo_size), 1); } if (cbf_cb[i]) - ff_hevc_hls_residual_coding(lc, xBase, yBase + (i << log2_trafo_size), + ff_hevc_hls_residual_coding(lc, pps, xBase, yBase + (i << log2_trafo_size), log2_trafo_size, scan_idx_c, 1); } - for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) { + for (i = 0; i < (sps->chroma_format_idc == 2 ? 2 : 1); i++) { if (lc->cu.pred_mode == MODE_INTRA) { ff_hevc_set_neighbour_available(lc, xBase, yBase + (i << log2_trafo_size), - trafo_size_h, trafo_size_v); - s->hpc.intra_pred[log2_trafo_size - 2](lc, xBase, yBase + (i << log2_trafo_size), 2); + trafo_size_h, trafo_size_v, sps->log2_ctb_size); + s->hpc.intra_pred[log2_trafo_size - 2](lc, pps, xBase, yBase + (i << log2_trafo_size), 2); } if (cbf_cr[i]) - ff_hevc_hls_residual_coding(lc, xBase, yBase + (i << log2_trafo_size), + ff_hevc_hls_residual_coding(lc, pps, xBase, yBase + (i << log2_trafo_size), log2_trafo_size, scan_idx_c, 2); } } - } else if (s->ps.sps->chroma_format_idc && lc->cu.pred_mode == MODE_INTRA) { - if (log2_trafo_size > 2 || s->ps.sps->chroma_format_idc == 3) { - int trafo_size_h = 1 << (log2_trafo_size_c + s->ps.sps->hshift[1]); - int trafo_size_v = 1 << (log2_trafo_size_c + s->ps.sps->vshift[1]); - ff_hevc_set_neighbour_available(lc, x0, y0, trafo_size_h, trafo_size_v); - s->hpc.intra_pred[log2_trafo_size_c - 2](lc, x0, y0, 1); - s->hpc.intra_pred[log2_trafo_size_c - 2](lc, x0, y0, 2); - if (s->ps.sps->chroma_format_idc == 2) { + } else if (sps->chroma_format_idc && lc->cu.pred_mode == MODE_INTRA) { + if (log2_trafo_size > 2 || sps->chroma_format_idc == 3) { + int trafo_size_h = 1 << (log2_trafo_size_c + sps->hshift[1]); + int trafo_size_v = 1 << (log2_trafo_size_c + sps->vshift[1]); + ff_hevc_set_neighbour_available(lc, x0, y0, trafo_size_h, trafo_size_v, + sps->log2_ctb_size); + s->hpc.intra_pred[log2_trafo_size_c - 2](lc, pps, x0, y0, 1); + s->hpc.intra_pred[log2_trafo_size_c - 2](lc, pps, x0, y0, 2); + if (sps->chroma_format_idc == 2) { ff_hevc_set_neighbour_available(lc, x0, y0 + (1 << log2_trafo_size_c), - trafo_size_h, trafo_size_v); - s->hpc.intra_pred[log2_trafo_size_c - 2](lc, x0, y0 + (1 << log2_trafo_size_c), 1); - s->hpc.intra_pred[log2_trafo_size_c - 2](lc, x0, y0 + (1 << log2_trafo_size_c), 2); + trafo_size_h, trafo_size_v, sps->log2_ctb_size); + s->hpc.intra_pred[log2_trafo_size_c - 2](lc, pps, x0, y0 + (1 << log2_trafo_size_c), 1); + s->hpc.intra_pred[log2_trafo_size_c - 2](lc, pps, x0, y0 + (1 << log2_trafo_size_c), 2); } } else if (blk_idx == 3) { int trafo_size_h = 1 << (log2_trafo_size + 1); - int trafo_size_v = 1 << (log2_trafo_size + s->ps.sps->vshift[1]); + int trafo_size_v = 1 << (log2_trafo_size + sps->vshift[1]); ff_hevc_set_neighbour_available(lc, xBase, yBase, - trafo_size_h, trafo_size_v); - s->hpc.intra_pred[log2_trafo_size - 2](lc, xBase, yBase, 1); - s->hpc.intra_pred[log2_trafo_size - 2](lc, xBase, yBase, 2); - if (s->ps.sps->chroma_format_idc == 2) { + trafo_size_h, trafo_size_v, sps->log2_ctb_size); + s->hpc.intra_pred[log2_trafo_size - 2](lc, pps, xBase, yBase, 1); + s->hpc.intra_pred[log2_trafo_size - 2](lc, pps, xBase, yBase, 2); + if (sps->chroma_format_idc == 2) { ff_hevc_set_neighbour_available(lc, xBase, yBase + (1 << log2_trafo_size), - trafo_size_h, trafo_size_v); - s->hpc.intra_pred[log2_trafo_size - 2](lc, xBase, yBase + (1 << log2_trafo_size), 1); - s->hpc.intra_pred[log2_trafo_size - 2](lc, xBase, yBase + (1 << log2_trafo_size), 2); + trafo_size_h, trafo_size_v, sps->log2_ctb_size); + s->hpc.intra_pred[log2_trafo_size - 2](lc, pps, xBase, yBase + (1 << log2_trafo_size), 1); + s->hpc.intra_pred[log2_trafo_size - 2](lc, pps, xBase, yBase + (1 << log2_trafo_size), 2); } } } @@ -1353,22 +1445,26 @@ static int hls_transform_unit(HEVCLocalContext *lc, int x0, int y0, return 0; } -static void set_deblocking_bypass(const HEVCContext *s, int x0, int y0, int log2_cb_size) +static void set_deblocking_bypass(uint8_t *is_pcm, const HEVCSPS *sps, + int x0, int y0, int log2_cb_size) { int cb_size = 1 << log2_cb_size; - int log2_min_pu_size = s->ps.sps->log2_min_pu_size; + int log2_min_pu_size = sps->log2_min_pu_size; - int min_pu_width = s->ps.sps->min_pu_width; - int x_end = FFMIN(x0 + cb_size, s->ps.sps->width); - int y_end = FFMIN(y0 + cb_size, s->ps.sps->height); + int min_pu_width = sps->min_pu_width; + int x_end = FFMIN(x0 + cb_size, sps->width); + int y_end = FFMIN(y0 + cb_size, sps->height); int i, j; for (j = (y0 >> log2_min_pu_size); j < (y_end >> log2_min_pu_size); j++) for (i = (x0 >> log2_min_pu_size); i < (x_end >> log2_min_pu_size); i++) - s->is_pcm[i + j * min_pu_width] = 2; + is_pcm[i + j * min_pu_width] = 2; } -static int hls_transform_tree(HEVCLocalContext *lc, int x0, int y0, +static int hls_transform_tree(HEVCLocalContext *lc, + const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, + int x0, int y0, int xBase, int yBase, int cb_xBase, int cb_yBase, int log2_cb_size, int log2_trafo_size, int trafo_depth, int blk_idx, @@ -1388,7 +1484,7 @@ static int hls_transform_tree(HEVCLocalContext *lc, int x0, int y0, if (lc->cu.intra_split_flag) { if (trafo_depth == 1) { lc->tu.intra_pred_mode = lc->pu.intra_pred_mode[blk_idx]; - if (s->ps.sps->chroma_format_idc == 3) { + if (sps->chroma_format_idc == 3) { lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[blk_idx]; lc->tu.chroma_mode_c = lc->pu.chroma_mode_c[blk_idx]; } else { @@ -1402,33 +1498,33 @@ static int hls_transform_tree(HEVCLocalContext *lc, int x0, int y0, lc->tu.chroma_mode_c = lc->pu.chroma_mode_c[0]; } - if (log2_trafo_size <= s->ps.sps->log2_max_trafo_size && - log2_trafo_size > s->ps.sps->log2_min_tb_size && + if (log2_trafo_size <= sps->log2_max_trafo_size && + log2_trafo_size > sps->log2_min_tb_size && trafo_depth < lc->cu.max_trafo_depth && !(lc->cu.intra_split_flag && trafo_depth == 0)) { split_transform_flag = ff_hevc_split_transform_flag_decode(lc, log2_trafo_size); } else { - int inter_split = s->ps.sps->max_transform_hierarchy_depth_inter == 0 && + int inter_split = sps->max_transform_hierarchy_depth_inter == 0 && lc->cu.pred_mode == MODE_INTER && lc->cu.part_mode != PART_2Nx2N && trafo_depth == 0; - split_transform_flag = log2_trafo_size > s->ps.sps->log2_max_trafo_size || + split_transform_flag = log2_trafo_size > sps->log2_max_trafo_size || (lc->cu.intra_split_flag && trafo_depth == 0) || inter_split; } - if (s->ps.sps->chroma_format_idc && (log2_trafo_size > 2 || s->ps.sps->chroma_format_idc == 3)) { + if (sps->chroma_format_idc && (log2_trafo_size > 2 || sps->chroma_format_idc == 3)) { if (trafo_depth == 0 || cbf_cb[0]) { cbf_cb[0] = ff_hevc_cbf_cb_cr_decode(lc, trafo_depth); - if (s->ps.sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) { + if (sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) { cbf_cb[1] = ff_hevc_cbf_cb_cr_decode(lc, trafo_depth); } } if (trafo_depth == 0 || cbf_cr[0]) { cbf_cr[0] = ff_hevc_cbf_cb_cr_decode(lc, trafo_depth); - if (s->ps.sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) { + if (sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) { cbf_cr[1] = ff_hevc_cbf_cb_cr_decode(lc, trafo_depth); } } @@ -1441,7 +1537,8 @@ static int hls_transform_tree(HEVCLocalContext *lc, int x0, int y0, #define SUBDIVIDE(x, y, idx) \ do { \ - ret = hls_transform_tree(lc, x, y, x0, y0, cb_xBase, cb_yBase, log2_cb_size,\ + ret = hls_transform_tree(lc, l, pps, sps, \ + x, y, x0, y0, cb_xBase, cb_yBase, log2_cb_size, \ log2_trafo_size - 1, trafo_depth + 1, idx, \ cbf_cb, cbf_cr); \ if (ret < 0) \ @@ -1455,18 +1552,19 @@ do { #undef SUBDIVIDE } else { - int min_tu_size = 1 << s->ps.sps->log2_min_tb_size; - int log2_min_tu_size = s->ps.sps->log2_min_tb_size; - int min_tu_width = s->ps.sps->min_tb_width; + int min_tu_size = 1 << sps->log2_min_tb_size; + int log2_min_tu_size = sps->log2_min_tb_size; + int min_tu_width = sps->min_tb_width; int cbf_luma = 1; if (lc->cu.pred_mode == MODE_INTRA || trafo_depth != 0 || cbf_cb[0] || cbf_cr[0] || - (s->ps.sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) { + (sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) { cbf_luma = ff_hevc_cbf_luma_decode(lc, trafo_depth); } - ret = hls_transform_unit(lc, x0, y0, xBase, yBase, cb_xBase, cb_yBase, + ret = hls_transform_unit(lc, l, pps, sps, + x0, y0, xBase, yBase, cb_xBase, cb_yBase, log2_cb_size, log2_trafo_size, blk_idx, cbf_luma, cbf_cb, cbf_cr); if (ret < 0) @@ -1478,55 +1576,57 @@ do { for (j = 0; j < (1 << log2_trafo_size); j += min_tu_size) { int x_tu = (x0 + j) >> log2_min_tu_size; int y_tu = (y0 + i) >> log2_min_tu_size; - s->cbf_luma[y_tu * min_tu_width + x_tu] = 1; + l->cbf_luma[y_tu * min_tu_width + x_tu] = 1; } } if (!s->sh.disable_deblocking_filter_flag) { - ff_hevc_deblocking_boundary_strengths(lc, x0, y0, log2_trafo_size); - if (s->ps.pps->transquant_bypass_enable_flag && + ff_hevc_deblocking_boundary_strengths(lc, l, pps, x0, y0, log2_trafo_size); + if (pps->transquant_bypass_enable_flag && lc->cu.cu_transquant_bypass_flag) - set_deblocking_bypass(s, x0, y0, log2_trafo_size); + set_deblocking_bypass(l->is_pcm, sps, x0, y0, log2_trafo_size); } } return 0; } -static int hls_pcm_sample(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size) +static int hls_pcm_sample(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCPPS *pps, int x0, int y0, int log2_cb_size) { const HEVCContext *const s = lc->parent; + const HEVCSPS *const sps = pps->sps; GetBitContext gb; int cb_size = 1 << log2_cb_size; - ptrdiff_t stride0 = s->frame->linesize[0]; - ptrdiff_t stride1 = s->frame->linesize[1]; - ptrdiff_t stride2 = s->frame->linesize[2]; - uint8_t *dst0 = &s->frame->data[0][y0 * stride0 + (x0 << s->ps.sps->pixel_shift)]; - uint8_t *dst1 = &s->frame->data[1][(y0 >> s->ps.sps->vshift[1]) * stride1 + ((x0 >> s->ps.sps->hshift[1]) << s->ps.sps->pixel_shift)]; - uint8_t *dst2 = &s->frame->data[2][(y0 >> s->ps.sps->vshift[2]) * stride2 + ((x0 >> s->ps.sps->hshift[2]) << s->ps.sps->pixel_shift)]; + 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 * s->ps.sps->pcm.bit_depth + - (((cb_size >> s->ps.sps->hshift[1]) * (cb_size >> s->ps.sps->vshift[1])) + - ((cb_size >> s->ps.sps->hshift[2]) * (cb_size >> s->ps.sps->vshift[2]))) * - s->ps.sps->pcm.bit_depth_chroma; + int length = cb_size * cb_size * sps->pcm.bit_depth + + (((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; const uint8_t *pcm = skip_bytes(&lc->cc, (length + 7) >> 3); int ret; if (!s->sh.disable_deblocking_filter_flag) - ff_hevc_deblocking_boundary_strengths(lc, x0, y0, log2_cb_size); + ff_hevc_deblocking_boundary_strengths(lc, l, pps, x0, y0, log2_cb_size); ret = init_get_bits(&gb, pcm, length); if (ret < 0) return ret; - s->hevcdsp.put_pcm(dst0, stride0, cb_size, cb_size, &gb, s->ps.sps->pcm.bit_depth); - if (s->ps.sps->chroma_format_idc) { + s->hevcdsp.put_pcm(dst0, stride0, cb_size, cb_size, &gb, sps->pcm.bit_depth); + if (sps->chroma_format_idc) { s->hevcdsp.put_pcm(dst1, stride1, - cb_size >> s->ps.sps->hshift[1], - cb_size >> s->ps.sps->vshift[1], - &gb, s->ps.sps->pcm.bit_depth_chroma); + cb_size >> sps->hshift[1], + cb_size >> sps->vshift[1], + &gb, sps->pcm.bit_depth_chroma); s->hevcdsp.put_pcm(dst2, stride2, - cb_size >> s->ps.sps->hshift[2], - cb_size >> s->ps.sps->vshift[2], - &gb, s->ps.sps->pcm.bit_depth_chroma); + cb_size >> sps->hshift[2], + cb_size >> sps->vshift[2], + &gb, sps->pcm.bit_depth_chroma); } return 0; @@ -1548,32 +1648,34 @@ static int hls_pcm_sample(HEVCLocalContext *lc, int x0, int y0, int log2_cb_size * @param luma_offset additive offset applied to the luma prediction value */ -static void luma_mc_uni(HEVCLocalContext *lc, uint8_t *dst, ptrdiff_t dststride, +static void luma_mc_uni(HEVCLocalContext *lc, + const HEVCPPS *pps, const HEVCSPS *sps, + uint8_t *dst, ptrdiff_t dststride, const AVFrame *ref, const Mv *mv, int x_off, int y_off, int block_w, int block_h, int luma_weight, int luma_offset) { const HEVCContext *const s = lc->parent; const uint8_t *src = ref->data[0]; ptrdiff_t srcstride = ref->linesize[0]; - int pic_width = s->ps.sps->width; - int pic_height = s->ps.sps->height; + int pic_width = sps->width; + int pic_height = sps->height; int mx = mv->x & 3; int my = mv->y & 3; - int weight_flag = (s->sh.slice_type == HEVC_SLICE_P && s->ps.pps->weighted_pred_flag) || - (s->sh.slice_type == HEVC_SLICE_B && s->ps.pps->weighted_bipred_flag); + int weight_flag = (s->sh.slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) || + (s->sh.slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag); int idx = hevc_pel_weight[block_w]; x_off += mv->x >> 2; y_off += mv->y >> 2; - src += y_off * srcstride + (x_off * (1 << s->ps.sps->pixel_shift)); + src += y_off * srcstride + (x_off * (1 << sps->pixel_shift)); if (x_off < QPEL_EXTRA_BEFORE || y_off < QPEL_EXTRA_AFTER || x_off >= pic_width - block_w - QPEL_EXTRA_AFTER || y_off >= pic_height - block_h - QPEL_EXTRA_AFTER || - ref == s->frame) { - const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift; - int offset = QPEL_EXTRA_BEFORE * srcstride + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift); - int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift); + ref == s->cur_frame->f) { + const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << sps->pixel_shift; + int offset = QPEL_EXTRA_BEFORE * srcstride + (QPEL_EXTRA_BEFORE << sps->pixel_shift); + int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << sps->pixel_shift); s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src - offset, edge_emu_stride, srcstride, @@ -1610,7 +1712,9 @@ static void luma_mc_uni(HEVCLocalContext *lc, uint8_t *dst, ptrdiff_t dststride, * @param mv1 motion vector1 (relative to block position) to get pixel data from * @param current_mv current motion vector structure */ - static void luma_mc_bi(HEVCLocalContext *lc, uint8_t *dst, ptrdiff_t dststride, +static void luma_mc_bi(HEVCLocalContext *lc, + const HEVCPPS *pps, const HEVCSPS *sps, + uint8_t *dst, ptrdiff_t dststride, const AVFrame *ref0, const Mv *mv0, int x_off, int y_off, int block_w, int block_h, const AVFrame *ref1, const Mv *mv1, struct MvField *current_mv) @@ -1618,29 +1722,29 @@ static void luma_mc_uni(HEVCLocalContext *lc, uint8_t *dst, ptrdiff_t dststride, const HEVCContext *const s = lc->parent; ptrdiff_t src0stride = ref0->linesize[0]; ptrdiff_t src1stride = ref1->linesize[0]; - int pic_width = s->ps.sps->width; - int pic_height = s->ps.sps->height; + int pic_width = sps->width; + int pic_height = sps->height; int mx0 = mv0->x & 3; int my0 = mv0->y & 3; int mx1 = mv1->x & 3; int my1 = mv1->y & 3; - int weight_flag = (s->sh.slice_type == HEVC_SLICE_P && s->ps.pps->weighted_pred_flag) || - (s->sh.slice_type == HEVC_SLICE_B && s->ps.pps->weighted_bipred_flag); + int weight_flag = (s->sh.slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) || + (s->sh.slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag); int x_off0 = x_off + (mv0->x >> 2); int y_off0 = y_off + (mv0->y >> 2); int x_off1 = x_off + (mv1->x >> 2); int y_off1 = y_off + (mv1->y >> 2); int idx = hevc_pel_weight[block_w]; - const uint8_t *src0 = ref0->data[0] + y_off0 * src0stride + (int)((unsigned)x_off0 << s->ps.sps->pixel_shift); - const uint8_t *src1 = ref1->data[0] + y_off1 * src1stride + (int)((unsigned)x_off1 << s->ps.sps->pixel_shift); + const uint8_t *src0 = ref0->data[0] + y_off0 * src0stride + (int)((unsigned)x_off0 << sps->pixel_shift); + const uint8_t *src1 = ref1->data[0] + y_off1 * src1stride + (int)((unsigned)x_off1 << sps->pixel_shift); if (x_off0 < QPEL_EXTRA_BEFORE || y_off0 < QPEL_EXTRA_AFTER || x_off0 >= pic_width - block_w - QPEL_EXTRA_AFTER || y_off0 >= pic_height - block_h - QPEL_EXTRA_AFTER) { - const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift; - int offset = QPEL_EXTRA_BEFORE * src0stride + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift); - int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift); + const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << sps->pixel_shift; + int offset = QPEL_EXTRA_BEFORE * src0stride + (QPEL_EXTRA_BEFORE << sps->pixel_shift); + int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << sps->pixel_shift); s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src0 - offset, edge_emu_stride, src0stride, @@ -1655,9 +1759,9 @@ static void luma_mc_uni(HEVCLocalContext *lc, uint8_t *dst, ptrdiff_t dststride, if (x_off1 < QPEL_EXTRA_BEFORE || y_off1 < QPEL_EXTRA_AFTER || x_off1 >= pic_width - block_w - QPEL_EXTRA_AFTER || y_off1 >= pic_height - block_h - QPEL_EXTRA_AFTER) { - const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift; - int offset = QPEL_EXTRA_BEFORE * src1stride + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift); - int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->ps.sps->pixel_shift); + const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << sps->pixel_shift; + int offset = QPEL_EXTRA_BEFORE * src1stride + (QPEL_EXTRA_BEFORE << sps->pixel_shift); + int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << sps->pixel_shift); s->vdsp.emulated_edge_mc(lc->edge_emu_buffer2, src1 - offset, edge_emu_stride, src1stride, @@ -1702,38 +1806,40 @@ static void luma_mc_uni(HEVCLocalContext *lc, uint8_t *dst, ptrdiff_t dststride, * @param chroma_offset additive offset applied to the chroma prediction value */ -static void chroma_mc_uni(HEVCLocalContext *lc, uint8_t *dst0, +static void chroma_mc_uni(HEVCLocalContext *lc, + const HEVCPPS *pps, const HEVCSPS *sps, + uint8_t *dst0, ptrdiff_t dststride, const uint8_t *src0, ptrdiff_t srcstride, int reflist, int x_off, int y_off, int block_w, int block_h, const struct MvField *current_mv, int chroma_weight, int chroma_offset) { const HEVCContext *const s = lc->parent; - int pic_width = s->ps.sps->width >> s->ps.sps->hshift[1]; - int pic_height = s->ps.sps->height >> s->ps.sps->vshift[1]; + int pic_width = sps->width >> sps->hshift[1]; + int pic_height = sps->height >> sps->vshift[1]; const Mv *mv = ¤t_mv->mv[reflist]; - int weight_flag = (s->sh.slice_type == HEVC_SLICE_P && s->ps.pps->weighted_pred_flag) || - (s->sh.slice_type == HEVC_SLICE_B && s->ps.pps->weighted_bipred_flag); + int weight_flag = (s->sh.slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) || + (s->sh.slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag); int idx = hevc_pel_weight[block_w]; - int hshift = s->ps.sps->hshift[1]; - int vshift = s->ps.sps->vshift[1]; - intptr_t mx = av_mod_uintp2(mv->x, 2 + hshift); - intptr_t my = av_mod_uintp2(mv->y, 2 + vshift); + int hshift = sps->hshift[1]; + int vshift = sps->vshift[1]; + intptr_t mx = av_zero_extend(mv->x, 2 + hshift); + intptr_t my = av_zero_extend(mv->y, 2 + vshift); intptr_t _mx = mx << (1 - hshift); intptr_t _my = my << (1 - vshift); - int emu = src0 == s->frame->data[1] || src0 == s->frame->data[2]; + int emu = src0 == s->cur_frame->f->data[1] || src0 == s->cur_frame->f->data[2]; x_off += mv->x >> (2 + hshift); y_off += mv->y >> (2 + vshift); - src0 += y_off * srcstride + (x_off * (1 << s->ps.sps->pixel_shift)); + src0 += y_off * srcstride + (x_off * (1 << sps->pixel_shift)); if (x_off < EPEL_EXTRA_BEFORE || y_off < EPEL_EXTRA_AFTER || x_off >= pic_width - block_w - EPEL_EXTRA_AFTER || y_off >= pic_height - block_h - EPEL_EXTRA_AFTER || emu) { - const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift; - int offset0 = EPEL_EXTRA_BEFORE * (srcstride + (1 << s->ps.sps->pixel_shift)); + const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << sps->pixel_shift; + int offset0 = EPEL_EXTRA_BEFORE * (srcstride + (1 << sps->pixel_shift)); int buf_offset0 = EPEL_EXTRA_BEFORE * - (edge_emu_stride + (1 << s->ps.sps->pixel_shift)); + (edge_emu_stride + (1 << sps->pixel_shift)); s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src0 - offset0, edge_emu_stride, srcstride, block_w + EPEL_EXTRA, block_h + EPEL_EXTRA, @@ -1770,7 +1876,9 @@ static void chroma_mc_uni(HEVCLocalContext *lc, uint8_t *dst0, * @param current_mv current motion vector structure * @param cidx chroma component(cb, cr) */ -static void chroma_mc_bi(HEVCLocalContext *lc, uint8_t *dst0, ptrdiff_t dststride, +static void chroma_mc_bi(HEVCLocalContext *lc, + const HEVCPPS *pps, const HEVCSPS *sps, + uint8_t *dst0, ptrdiff_t dststride, const AVFrame *ref0, const AVFrame *ref1, int x_off, int y_off, int block_w, int block_h, const MvField *current_mv, int cidx) { @@ -1779,19 +1887,19 @@ static void chroma_mc_bi(HEVCLocalContext *lc, uint8_t *dst0, ptrdiff_t dststrid const uint8_t *src2 = ref1->data[cidx+1]; ptrdiff_t src1stride = ref0->linesize[cidx+1]; ptrdiff_t src2stride = ref1->linesize[cidx+1]; - int weight_flag = (s->sh.slice_type == HEVC_SLICE_P && s->ps.pps->weighted_pred_flag) || - (s->sh.slice_type == HEVC_SLICE_B && s->ps.pps->weighted_bipred_flag); - int pic_width = s->ps.sps->width >> s->ps.sps->hshift[1]; - int pic_height = s->ps.sps->height >> s->ps.sps->vshift[1]; + int weight_flag = (s->sh.slice_type == HEVC_SLICE_P && pps->weighted_pred_flag) || + (s->sh.slice_type == HEVC_SLICE_B && pps->weighted_bipred_flag); + int pic_width = sps->width >> sps->hshift[1]; + int pic_height = sps->height >> sps->vshift[1]; const Mv *const mv0 = ¤t_mv->mv[0]; const Mv *const mv1 = ¤t_mv->mv[1]; - int hshift = s->ps.sps->hshift[1]; - int vshift = s->ps.sps->vshift[1]; + int hshift = sps->hshift[1]; + int vshift = sps->vshift[1]; - intptr_t mx0 = av_mod_uintp2(mv0->x, 2 + hshift); - intptr_t my0 = av_mod_uintp2(mv0->y, 2 + vshift); - intptr_t mx1 = av_mod_uintp2(mv1->x, 2 + hshift); - intptr_t my1 = av_mod_uintp2(mv1->y, 2 + vshift); + intptr_t mx0 = av_zero_extend(mv0->x, 2 + hshift); + intptr_t my0 = av_zero_extend(mv0->y, 2 + vshift); + intptr_t mx1 = av_zero_extend(mv1->x, 2 + hshift); + intptr_t my1 = av_zero_extend(mv1->y, 2 + vshift); intptr_t _mx0 = mx0 << (1 - hshift); intptr_t _my0 = my0 << (1 - vshift); intptr_t _mx1 = mx1 << (1 - hshift); @@ -1802,16 +1910,16 @@ static void chroma_mc_bi(HEVCLocalContext *lc, uint8_t *dst0, ptrdiff_t dststrid int x_off1 = x_off + (mv1->x >> (2 + hshift)); int y_off1 = y_off + (mv1->y >> (2 + vshift)); int idx = hevc_pel_weight[block_w]; - src1 += y_off0 * src1stride + (int)((unsigned)x_off0 << s->ps.sps->pixel_shift); - src2 += y_off1 * src2stride + (int)((unsigned)x_off1 << s->ps.sps->pixel_shift); + src1 += y_off0 * src1stride + (int)((unsigned)x_off0 << sps->pixel_shift); + src2 += y_off1 * src2stride + (int)((unsigned)x_off1 << sps->pixel_shift); if (x_off0 < EPEL_EXTRA_BEFORE || y_off0 < EPEL_EXTRA_AFTER || x_off0 >= pic_width - block_w - EPEL_EXTRA_AFTER || y_off0 >= pic_height - block_h - EPEL_EXTRA_AFTER) { - const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift; - int offset1 = EPEL_EXTRA_BEFORE * (src1stride + (1 << s->ps.sps->pixel_shift)); + const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << sps->pixel_shift; + int offset1 = EPEL_EXTRA_BEFORE * (src1stride + (1 << sps->pixel_shift)); int buf_offset1 = EPEL_EXTRA_BEFORE * - (edge_emu_stride + (1 << s->ps.sps->pixel_shift)); + (edge_emu_stride + (1 << sps->pixel_shift)); s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src1 - offset1, edge_emu_stride, src1stride, @@ -1827,10 +1935,10 @@ static void chroma_mc_bi(HEVCLocalContext *lc, uint8_t *dst0, ptrdiff_t dststrid if (x_off1 < EPEL_EXTRA_BEFORE || y_off1 < EPEL_EXTRA_AFTER || x_off1 >= pic_width - block_w - EPEL_EXTRA_AFTER || y_off1 >= pic_height - block_h - EPEL_EXTRA_AFTER) { - const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->ps.sps->pixel_shift; - int offset1 = EPEL_EXTRA_BEFORE * (src2stride + (1 << s->ps.sps->pixel_shift)); + const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << sps->pixel_shift; + int offset1 = EPEL_EXTRA_BEFORE * (src2stride + (1 << sps->pixel_shift)); int buf_offset1 = EPEL_EXTRA_BEFORE * - (edge_emu_stride + (1 << s->ps.sps->pixel_shift)); + (edge_emu_stride + (1 << sps->pixel_shift)); s->vdsp.emulated_edge_mc(lc->edge_emu_buffer2, src2 - offset1, edge_emu_stride, src2stride, @@ -1846,11 +1954,11 @@ static void chroma_mc_bi(HEVCLocalContext *lc, uint8_t *dst0, ptrdiff_t dststrid s->hevcdsp.put_hevc_epel[idx][!!my0][!!mx0](lc->tmp, src1, src1stride, block_h, _mx0, _my0, block_w); if (!weight_flag) - s->hevcdsp.put_hevc_epel_bi[idx][!!my1][!!mx1](dst0, s->frame->linesize[cidx+1], + s->hevcdsp.put_hevc_epel_bi[idx][!!my1][!!mx1](dst0, s->cur_frame->f->linesize[cidx+1], src2, src2stride, lc->tmp, block_h, _mx1, _my1, block_w); else - s->hevcdsp.put_hevc_epel_bi_w[idx][!!my1][!!mx1](dst0, s->frame->linesize[cidx+1], + s->hevcdsp.put_hevc_epel_bi_w[idx][!!my1][!!mx1](dst0, s->cur_frame->f->linesize[cidx+1], src2, src2stride, lc->tmp, block_h, s->sh.chroma_log2_weight_denom, @@ -1864,14 +1972,16 @@ static void chroma_mc_bi(HEVCLocalContext *lc, uint8_t *dst0, ptrdiff_t dststrid static void hevc_await_progress(const HEVCContext *s, const HEVCFrame *ref, const Mv *mv, int y0, int height) { - if (s->threads_type == FF_THREAD_FRAME ) { + if (s->avctx->active_thread_type == FF_THREAD_FRAME ) { int y = FFMAX(0, (mv->y >> 2) + y0 + height + 9); - ff_thread_await_progress(&ref->tf, y, 0); + ff_progress_frame_await(&ref->tf, y); } } -static void hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, int x0, int y0, int nPbW, +static void hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, + const HEVCPPS *pps, const HEVCSPS *sps, + int x0, int y0, int nPbW, int nPbH, int log2_cb_size, int part_idx, int merge_idx, MvField *mv) { @@ -1879,7 +1989,7 @@ static void hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, int x0, int y0, int nPbW enum InterPredIdc inter_pred_idc = PRED_L0; int mvp_flag; - ff_hevc_set_neighbour_available(lc, x0, y0, nPbW, nPbH); + ff_hevc_set_neighbour_available(lc, x0, y0, nPbW, nPbH, sps->log2_ctb_size); mv->pred_flag = 0; if (s->sh.slice_type == HEVC_SLICE_B) inter_pred_idc = ff_hevc_inter_pred_idc_decode(lc, nPbW, nPbH); @@ -1891,7 +2001,7 @@ static void hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, int x0, int y0, int nPbW mv->pred_flag = PF_L0; ff_hevc_hls_mvd_coding(lc, x0, y0, 0); mvp_flag = ff_hevc_mvp_lx_flag_decode(lc); - ff_hevc_luma_mv_mvp_mode(lc, x0, y0, nPbW, nPbH, log2_cb_size, + ff_hevc_luma_mv_mvp_mode(lc, pps, x0, y0, nPbW, nPbH, log2_cb_size, part_idx, merge_idx, mv, mvp_flag, 0); mv->mv[0].x += lc->pu.mvd.x; mv->mv[0].y += lc->pu.mvd.y; @@ -1909,40 +2019,43 @@ static void hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, int x0, int y0, int nPbW mv->pred_flag += PF_L1; mvp_flag = ff_hevc_mvp_lx_flag_decode(lc); - ff_hevc_luma_mv_mvp_mode(lc, x0, y0, nPbW, nPbH, log2_cb_size, + ff_hevc_luma_mv_mvp_mode(lc, pps, x0, y0, nPbW, nPbH, log2_cb_size, part_idx, merge_idx, mv, mvp_flag, 1); mv->mv[1].x += lc->pu.mvd.x; mv->mv[1].y += lc->pu.mvd.y; } } -static void hls_prediction_unit(HEVCLocalContext *lc, int x0, int y0, - int nPbW, int nPbH, +static void hls_prediction_unit(HEVCLocalContext *lc, + const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, + int x0, int y0, int nPbW, int nPbH, int log2_cb_size, int partIdx, int idx) { #define POS(c_idx, x, y) \ - &s->frame->data[c_idx][((y) >> s->ps.sps->vshift[c_idx]) * s->frame->linesize[c_idx] + \ - (((x) >> s->ps.sps->hshift[c_idx]) << s->ps.sps->pixel_shift)] + &s->cur_frame->f->data[c_idx][((y) >> sps->vshift[c_idx]) * linesize[c_idx] + \ + (((x) >> sps->hshift[c_idx]) << sps->pixel_shift)] const HEVCContext *const s = lc->parent; int merge_idx = 0; struct MvField current_mv = {{{ 0 }}}; - int min_pu_width = s->ps.sps->min_pu_width; + int min_pu_width = sps->min_pu_width; - MvField *tab_mvf = s->ref->tab_mvf; - const RefPicList *refPicList = s->ref->refPicList; + MvField *tab_mvf = s->cur_frame->tab_mvf; + 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 *dst1 = POS(1, x0, y0); uint8_t *dst2 = POS(2, x0, y0); - int log2_min_cb_size = s->ps.sps->log2_min_cb_size; - int min_cb_width = s->ps.sps->min_cb_width; + int log2_min_cb_size = sps->log2_min_cb_size; + int min_cb_width = sps->min_cb_width; int x_cb = x0 >> log2_min_cb_size; int y_cb = y0 >> log2_min_cb_size; int x_pu, y_pu; int i, j; - int skip_flag = SAMPLE_CTB(s->skip_flag, x_cb, y_cb); + int skip_flag = SAMPLE_CTB(l->skip_flag, x_cb, y_cb); if (!skip_flag) lc->pu.merge_flag = ff_hevc_merge_flag_decode(lc); @@ -1953,87 +2066,87 @@ static void hls_prediction_unit(HEVCLocalContext *lc, int x0, int y0, else merge_idx = 0; - ff_hevc_luma_mv_merge_mode(lc, x0, y0, nPbW, nPbH, log2_cb_size, + ff_hevc_luma_mv_merge_mode(lc, pps, x0, y0, nPbW, nPbH, log2_cb_size, partIdx, merge_idx, ¤t_mv); } else { - hevc_luma_mv_mvp_mode(lc, x0, y0, nPbW, nPbH, log2_cb_size, + hevc_luma_mv_mvp_mode(lc, pps, sps, x0, y0, nPbW, nPbH, log2_cb_size, partIdx, merge_idx, ¤t_mv); } - x_pu = x0 >> s->ps.sps->log2_min_pu_size; - y_pu = y0 >> s->ps.sps->log2_min_pu_size; + x_pu = x0 >> sps->log2_min_pu_size; + y_pu = y0 >> sps->log2_min_pu_size; - for (j = 0; j < nPbH >> s->ps.sps->log2_min_pu_size; j++) - for (i = 0; i < nPbW >> s->ps.sps->log2_min_pu_size; i++) + for (j = 0; j < nPbH >> sps->log2_min_pu_size; j++) + for (i = 0; i < nPbW >> sps->log2_min_pu_size; i++) tab_mvf[(y_pu + j) * min_pu_width + x_pu + i] = current_mv; if (current_mv.pred_flag & PF_L0) { ref0 = refPicList[0].ref[current_mv.ref_idx[0]]; - if (!ref0 || !ref0->frame) + if (!ref0 || !ref0->f) return; hevc_await_progress(s, ref0, ¤t_mv.mv[0], y0, nPbH); } if (current_mv.pred_flag & PF_L1) { ref1 = refPicList[1].ref[current_mv.ref_idx[1]]; - if (!ref1 || !ref1->frame) + if (!ref1 || !ref1->f) return; hevc_await_progress(s, ref1, ¤t_mv.mv[1], y0, nPbH); } if (current_mv.pred_flag == PF_L0) { - int x0_c = x0 >> s->ps.sps->hshift[1]; - int y0_c = y0 >> s->ps.sps->vshift[1]; - int nPbW_c = nPbW >> s->ps.sps->hshift[1]; - int nPbH_c = nPbH >> s->ps.sps->vshift[1]; + int x0_c = x0 >> sps->hshift[1]; + int y0_c = y0 >> sps->vshift[1]; + int nPbW_c = nPbW >> sps->hshift[1]; + int nPbH_c = nPbH >> sps->vshift[1]; - luma_mc_uni(lc, dst0, s->frame->linesize[0], ref0->frame, + luma_mc_uni(lc, pps, sps, dst0, linesize[0], ref0->f, ¤t_mv.mv[0], x0, y0, nPbW, nPbH, s->sh.luma_weight_l0[current_mv.ref_idx[0]], s->sh.luma_offset_l0[current_mv.ref_idx[0]]); - if (s->ps.sps->chroma_format_idc) { - chroma_mc_uni(lc, dst1, s->frame->linesize[1], ref0->frame->data[1], ref0->frame->linesize[1], + if (sps->chroma_format_idc) { + chroma_mc_uni(lc, pps, sps, dst1, linesize[1], ref0->f->data[1], ref0->f->linesize[1], 0, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0]); - chroma_mc_uni(lc, dst2, s->frame->linesize[2], ref0->frame->data[2], ref0->frame->linesize[2], + chroma_mc_uni(lc, pps, sps, dst2, linesize[2], ref0->f->data[2], ref0->f->linesize[2], 0, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, s->sh.chroma_weight_l0[current_mv.ref_idx[0]][1], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][1]); } } else if (current_mv.pred_flag == PF_L1) { - int x0_c = x0 >> s->ps.sps->hshift[1]; - int y0_c = y0 >> s->ps.sps->vshift[1]; - int nPbW_c = nPbW >> s->ps.sps->hshift[1]; - int nPbH_c = nPbH >> s->ps.sps->vshift[1]; + int x0_c = x0 >> sps->hshift[1]; + int y0_c = y0 >> sps->vshift[1]; + int nPbW_c = nPbW >> sps->hshift[1]; + int nPbH_c = nPbH >> sps->vshift[1]; - luma_mc_uni(lc, dst0, s->frame->linesize[0], ref1->frame, + luma_mc_uni(lc, pps, sps, dst0, linesize[0], ref1->f, ¤t_mv.mv[1], x0, y0, nPbW, nPbH, s->sh.luma_weight_l1[current_mv.ref_idx[1]], s->sh.luma_offset_l1[current_mv.ref_idx[1]]); - if (s->ps.sps->chroma_format_idc) { - chroma_mc_uni(lc, dst1, s->frame->linesize[1], ref1->frame->data[1], ref1->frame->linesize[1], + if (sps->chroma_format_idc) { + chroma_mc_uni(lc, pps, sps, dst1, linesize[1], ref1->f->data[1], ref1->f->linesize[1], 1, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, s->sh.chroma_weight_l1[current_mv.ref_idx[1]][0], s->sh.chroma_offset_l1[current_mv.ref_idx[1]][0]); - chroma_mc_uni(lc, dst2, s->frame->linesize[2], ref1->frame->data[2], ref1->frame->linesize[2], + chroma_mc_uni(lc, pps, sps, dst2, linesize[2], ref1->f->data[2], ref1->f->linesize[2], 1, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, s->sh.chroma_weight_l1[current_mv.ref_idx[1]][1], s->sh.chroma_offset_l1[current_mv.ref_idx[1]][1]); } } else if (current_mv.pred_flag == PF_BI) { - int x0_c = x0 >> s->ps.sps->hshift[1]; - int y0_c = y0 >> s->ps.sps->vshift[1]; - int nPbW_c = nPbW >> s->ps.sps->hshift[1]; - int nPbH_c = nPbH >> s->ps.sps->vshift[1]; + int x0_c = x0 >> sps->hshift[1]; + int y0_c = y0 >> sps->vshift[1]; + int nPbW_c = nPbW >> sps->hshift[1]; + int nPbH_c = nPbH >> sps->vshift[1]; - luma_mc_bi(lc, dst0, s->frame->linesize[0], ref0->frame, + luma_mc_bi(lc, pps, sps, dst0, linesize[0], ref0->f, ¤t_mv.mv[0], x0, y0, nPbW, nPbH, - ref1->frame, ¤t_mv.mv[1], ¤t_mv); + ref1->f, ¤t_mv.mv[1], ¤t_mv); - if (s->ps.sps->chroma_format_idc) { - chroma_mc_bi(lc, dst1, s->frame->linesize[1], ref0->frame, ref1->frame, + if (sps->chroma_format_idc) { + chroma_mc_bi(lc, pps, sps, dst1, linesize[1], ref0->f, ref1->f, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, 0); - chroma_mc_bi(lc, dst2, s->frame->linesize[2], ref0->frame, ref1->frame, + chroma_mc_bi(lc, pps, sps, dst2, linesize[2], ref0->f, ref1->f, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, 1); } } @@ -2042,25 +2155,27 @@ static void hls_prediction_unit(HEVCLocalContext *lc, int x0, int y0, /** * 8.4.1 */ -static int luma_intra_pred_mode(HEVCLocalContext *lc, int x0, int y0, int pu_size, +static int luma_intra_pred_mode(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCSPS *sps, + int x0, int y0, int pu_size, int prev_intra_luma_pred_flag) { const HEVCContext *const s = lc->parent; - int x_pu = x0 >> s->ps.sps->log2_min_pu_size; - int y_pu = y0 >> s->ps.sps->log2_min_pu_size; - int min_pu_width = s->ps.sps->min_pu_width; - int size_in_pus = pu_size >> s->ps.sps->log2_min_pu_size; - int x0b = av_mod_uintp2(x0, s->ps.sps->log2_ctb_size); - int y0b = av_mod_uintp2(y0, s->ps.sps->log2_ctb_size); + int x_pu = x0 >> sps->log2_min_pu_size; + int y_pu = y0 >> sps->log2_min_pu_size; + int min_pu_width = sps->min_pu_width; + int size_in_pus = pu_size >> sps->log2_min_pu_size; + int x0b = av_zero_extend(x0, sps->log2_ctb_size); + int y0b = av_zero_extend(y0, sps->log2_ctb_size); int cand_up = (lc->ctb_up_flag || y0b) ? - s->tab_ipm[(y_pu - 1) * min_pu_width + x_pu] : INTRA_DC; + l->tab_ipm[(y_pu - 1) * min_pu_width + x_pu] : INTRA_DC; int cand_left = (lc->ctb_left_flag || x0b) ? - s->tab_ipm[y_pu * min_pu_width + x_pu - 1] : INTRA_DC; + l->tab_ipm[y_pu * min_pu_width + x_pu - 1] : INTRA_DC; - int y_ctb = (y0 >> (s->ps.sps->log2_ctb_size)) << (s->ps.sps->log2_ctb_size); + int y_ctb = (y0 >> (sps->log2_ctb_size)) << (sps->log2_ctb_size); - MvField *tab_mvf = s->ref->tab_mvf; + MvField *tab_mvf = s->cur_frame->tab_mvf; int intra_pred_mode; int candidate[3]; int i, j; @@ -2111,7 +2226,7 @@ static int luma_intra_pred_mode(HEVCLocalContext *lc, int x0, int y0, int pu_siz if (!size_in_pus) size_in_pus = 1; for (i = 0; i < size_in_pus; i++) { - memset(&s->tab_ipm[(y_pu + i) * min_pu_width + x_pu], + memset(&l->tab_ipm[(y_pu + i) * min_pu_width + x_pu], intra_pred_mode, size_in_pus); for (j = 0; j < size_in_pus; j++) { @@ -2122,16 +2237,17 @@ static int luma_intra_pred_mode(HEVCLocalContext *lc, int x0, int y0, int pu_siz return intra_pred_mode; } -static av_always_inline void set_ct_depth(const HEVCContext *s, int x0, int y0, +static av_always_inline void set_ct_depth(const HEVCSPS *sps, uint8_t *tab_ct_depth, + int x0, int y0, int log2_cb_size, int ct_depth) { - int length = (1 << log2_cb_size) >> s->ps.sps->log2_min_cb_size; - int x_cb = x0 >> s->ps.sps->log2_min_cb_size; - int y_cb = y0 >> s->ps.sps->log2_min_cb_size; + int length = (1 << log2_cb_size) >> sps->log2_min_cb_size; + int x_cb = x0 >> sps->log2_min_cb_size; + int y_cb = y0 >> sps->log2_min_cb_size; int y; for (y = 0; y < length; y++) - memset(&s->tab_ct_depth[(y_cb + y) * s->ps.sps->min_cb_width + x_cb], + memset(&tab_ct_depth[(y_cb + y) * sps->min_cb_width + x_cb], ct_depth, length); } @@ -2139,10 +2255,11 @@ static const uint8_t tab_mode_idx[] = { 0, 1, 2, 2, 2, 2, 3, 5, 7, 8, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 23, 24, 24, 25, 25, 26, 27, 27, 28, 28, 29, 29, 30, 31}; -static void intra_prediction_unit(HEVCLocalContext *lc, int x0, int y0, +static void intra_prediction_unit(HEVCLocalContext *lc, + const HEVCLayerContext *l, const HEVCSPS *sps, + int x0, int y0, int log2_cb_size) { - const HEVCContext *const s = lc->parent; static const uint8_t intra_chroma_table[4] = { 0, 26, 10, 1 }; uint8_t prev_intra_luma_pred_flag[4]; int split = lc->cu.part_mode == PART_NxN; @@ -2163,12 +2280,13 @@ static void intra_prediction_unit(HEVCLocalContext *lc, int x0, int y0, lc->pu.rem_intra_luma_pred_mode = ff_hevc_rem_intra_luma_pred_mode_decode(lc); lc->pu.intra_pred_mode[2 * i + j] = - luma_intra_pred_mode(lc, x0 + pb_size * j, y0 + pb_size * i, pb_size, + luma_intra_pred_mode(lc, l, sps, + x0 + pb_size * j, y0 + pb_size * i, pb_size, prev_intra_luma_pred_flag[2 * i + j]); } } - if (s->ps.sps->chroma_format_idc == 3) { + if (sps->chroma_format_idc == 3) { for (i = 0; i < side; i++) { for (j = 0; j < side; j++) { lc->pu.chroma_mode_c[2 * i + j] = chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(lc); @@ -2182,7 +2300,7 @@ static void intra_prediction_unit(HEVCLocalContext *lc, int x0, int y0, } } } - } else if (s->ps.sps->chroma_format_idc == 2) { + } else if (sps->chroma_format_idc == 2) { int mode_idx; lc->pu.chroma_mode_c[0] = chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(lc); if (chroma_mode != 4) { @@ -2194,7 +2312,7 @@ static void intra_prediction_unit(HEVCLocalContext *lc, int x0, int y0, mode_idx = lc->pu.intra_pred_mode[0]; } lc->pu.intra_pred_mode_c[0] = tab_mode_idx[mode_idx]; - } else if (s->ps.sps->chroma_format_idc != 0) { + } else if (sps->chroma_format_idc != 0) { chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(lc); if (chroma_mode != 4) { if (lc->pu.intra_pred_mode[0] == intra_chroma_table[chroma_mode]) @@ -2208,38 +2326,43 @@ static void intra_prediction_unit(HEVCLocalContext *lc, int x0, int y0, } static void intra_prediction_unit_default_value(HEVCLocalContext *lc, + const HEVCLayerContext *l, + const HEVCSPS *sps, int x0, int y0, int log2_cb_size) { const HEVCContext *const s = lc->parent; int pb_size = 1 << log2_cb_size; - int size_in_pus = pb_size >> s->ps.sps->log2_min_pu_size; - int min_pu_width = s->ps.sps->min_pu_width; - MvField *tab_mvf = s->ref->tab_mvf; - int x_pu = x0 >> s->ps.sps->log2_min_pu_size; - int y_pu = y0 >> s->ps.sps->log2_min_pu_size; + int size_in_pus = pb_size >> sps->log2_min_pu_size; + int min_pu_width = sps->min_pu_width; + MvField *tab_mvf = s->cur_frame->tab_mvf; + int x_pu = x0 >> sps->log2_min_pu_size; + int y_pu = y0 >> sps->log2_min_pu_size; int j, k; if (size_in_pus == 0) size_in_pus = 1; for (j = 0; j < size_in_pus; j++) - memset(&s->tab_ipm[(y_pu + j) * min_pu_width + x_pu], INTRA_DC, size_in_pus); + memset(&l->tab_ipm[(y_pu + j) * min_pu_width + x_pu], INTRA_DC, size_in_pus); if (lc->cu.pred_mode == MODE_INTRA) for (j = 0; j < size_in_pus; j++) for (k = 0; k < size_in_pus; k++) tab_mvf[(y_pu + j) * min_pu_width + x_pu + k].pred_flag = PF_INTRA; } -static int hls_coding_unit(HEVCLocalContext *lc, const HEVCContext *s, int x0, int y0, int log2_cb_size) +static int hls_coding_unit(HEVCLocalContext *lc, const HEVCContext *s, + const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, + int x0, int y0, int log2_cb_size) { int cb_size = 1 << log2_cb_size; - int log2_min_cb_size = s->ps.sps->log2_min_cb_size; + int log2_min_cb_size = sps->log2_min_cb_size; int length = cb_size >> log2_min_cb_size; - int min_cb_width = s->ps.sps->min_cb_width; + int min_cb_width = sps->min_cb_width; int x_cb = x0 >> log2_min_cb_size; int y_cb = y0 >> log2_min_cb_size; int idx = log2_cb_size - 2; - int qp_block_mask = (1<<(s->ps.sps->log2_ctb_size - s->ps.pps->diff_cu_qp_delta_depth)) - 1; + int qp_block_mask = (1 << (sps->log2_ctb_size - pps->diff_cu_qp_delta_depth)) - 1; int x, y, ret; lc->cu.x = x0; @@ -2248,103 +2371,125 @@ static int hls_coding_unit(HEVCLocalContext *lc, const HEVCContext *s, int x0, i lc->cu.part_mode = PART_2Nx2N; lc->cu.intra_split_flag = 0; - SAMPLE_CTB(s->skip_flag, x_cb, y_cb) = 0; + SAMPLE_CTB(l->skip_flag, x_cb, y_cb) = 0; for (x = 0; x < 4; x++) lc->pu.intra_pred_mode[x] = 1; - if (s->ps.pps->transquant_bypass_enable_flag) { + if (pps->transquant_bypass_enable_flag) { lc->cu.cu_transquant_bypass_flag = ff_hevc_cu_transquant_bypass_flag_decode(lc); if (lc->cu.cu_transquant_bypass_flag) - set_deblocking_bypass(s, x0, y0, log2_cb_size); + set_deblocking_bypass(l->is_pcm, sps, x0, y0, log2_cb_size); } else lc->cu.cu_transquant_bypass_flag = 0; if (s->sh.slice_type != HEVC_SLICE_I) { - uint8_t skip_flag = ff_hevc_skip_flag_decode(lc, x0, y0, x_cb, y_cb); + const int x0b = av_zero_extend(x0, sps->log2_ctb_size); + const int y0b = av_zero_extend(y0, sps->log2_ctb_size); + uint8_t skip_flag = ff_hevc_skip_flag_decode(lc, l->skip_flag, + x0b, y0b, x_cb, y_cb, + min_cb_width); x = y_cb * min_cb_width + x_cb; for (y = 0; y < length; y++) { - memset(&s->skip_flag[x], skip_flag, length); + memset(&l->skip_flag[x], skip_flag, length); x += min_cb_width; } lc->cu.pred_mode = skip_flag ? MODE_SKIP : MODE_INTER; } else { x = y_cb * min_cb_width + x_cb; for (y = 0; y < length; y++) { - memset(&s->skip_flag[x], 0, length); + memset(&l->skip_flag[x], 0, length); x += min_cb_width; } } - if (SAMPLE_CTB(s->skip_flag, x_cb, y_cb)) { - hls_prediction_unit(lc, x0, y0, cb_size, cb_size, log2_cb_size, 0, idx); - intra_prediction_unit_default_value(lc, x0, y0, log2_cb_size); + if (SAMPLE_CTB(l->skip_flag, x_cb, y_cb)) { + hls_prediction_unit(lc, l, pps, sps, + x0, y0, cb_size, cb_size, log2_cb_size, 0, idx); + intra_prediction_unit_default_value(lc, l, sps, x0, y0, log2_cb_size); if (!s->sh.disable_deblocking_filter_flag) - ff_hevc_deblocking_boundary_strengths(lc, x0, y0, log2_cb_size); + ff_hevc_deblocking_boundary_strengths(lc, l, pps, x0, y0, log2_cb_size); } else { int pcm_flag = 0; if (s->sh.slice_type != HEVC_SLICE_I) lc->cu.pred_mode = ff_hevc_pred_mode_decode(lc); if (lc->cu.pred_mode != MODE_INTRA || - log2_cb_size == s->ps.sps->log2_min_cb_size) { - lc->cu.part_mode = ff_hevc_part_mode_decode(lc, log2_cb_size); + log2_cb_size == sps->log2_min_cb_size) { + lc->cu.part_mode = ff_hevc_part_mode_decode(lc, sps, log2_cb_size); lc->cu.intra_split_flag = lc->cu.part_mode == PART_NxN && lc->cu.pred_mode == MODE_INTRA; } if (lc->cu.pred_mode == MODE_INTRA) { - if (lc->cu.part_mode == PART_2Nx2N && s->ps.sps->pcm_enabled_flag && - log2_cb_size >= s->ps.sps->pcm.log2_min_pcm_cb_size && - log2_cb_size <= s->ps.sps->pcm.log2_max_pcm_cb_size) { + if (lc->cu.part_mode == PART_2Nx2N && sps->pcm_enabled && + log2_cb_size >= sps->pcm.log2_min_pcm_cb_size && + log2_cb_size <= sps->pcm.log2_max_pcm_cb_size) { pcm_flag = ff_hevc_pcm_flag_decode(lc); } if (pcm_flag) { - intra_prediction_unit_default_value(lc, x0, y0, log2_cb_size); - ret = hls_pcm_sample(lc, x0, y0, log2_cb_size); - if (s->ps.sps->pcm.loop_filter_disable_flag) - set_deblocking_bypass(s, x0, y0, log2_cb_size); + intra_prediction_unit_default_value(lc, l, sps, x0, y0, log2_cb_size); + ret = hls_pcm_sample(lc, l, pps, x0, y0, log2_cb_size); + if (sps->pcm_loop_filter_disabled) + set_deblocking_bypass(l->is_pcm, sps, x0, y0, log2_cb_size); if (ret < 0) return ret; } else { - intra_prediction_unit(lc, x0, y0, log2_cb_size); + intra_prediction_unit(lc, l, sps, x0, y0, log2_cb_size); } } else { - intra_prediction_unit_default_value(lc, x0, y0, log2_cb_size); + intra_prediction_unit_default_value(lc, l, sps, x0, y0, log2_cb_size); switch (lc->cu.part_mode) { case PART_2Nx2N: - hls_prediction_unit(lc, x0, y0, cb_size, cb_size, log2_cb_size, 0, idx); + hls_prediction_unit(lc, l, pps, sps, + x0, y0, cb_size, cb_size, log2_cb_size, 0, idx); break; case PART_2NxN: - hls_prediction_unit(lc, x0, y0, cb_size, cb_size / 2, log2_cb_size, 0, idx); - hls_prediction_unit(lc, x0, y0 + cb_size / 2, cb_size, cb_size / 2, log2_cb_size, 1, idx); + hls_prediction_unit(lc, l, pps, sps, + x0, y0, cb_size, cb_size / 2, log2_cb_size, 0, idx); + hls_prediction_unit(lc, l, pps, sps, + x0, y0 + cb_size / 2, cb_size, cb_size / 2, log2_cb_size, 1, idx); break; case PART_Nx2N: - hls_prediction_unit(lc, x0, y0, cb_size / 2, cb_size, log2_cb_size, 0, idx - 1); - hls_prediction_unit(lc, x0 + cb_size / 2, y0, cb_size / 2, cb_size, log2_cb_size, 1, idx - 1); + hls_prediction_unit(lc, l, pps, sps, + x0, y0, cb_size / 2, cb_size, log2_cb_size, 0, idx - 1); + hls_prediction_unit(lc, l, pps, sps, + x0 + cb_size / 2, y0, cb_size / 2, cb_size, log2_cb_size, 1, idx - 1); break; case PART_2NxnU: - hls_prediction_unit(lc, x0, y0, cb_size, cb_size / 4, log2_cb_size, 0, idx); - hls_prediction_unit(lc, x0, y0 + cb_size / 4, cb_size, cb_size * 3 / 4, log2_cb_size, 1, idx); + hls_prediction_unit(lc, l, pps, sps, + x0, y0, cb_size, cb_size / 4, log2_cb_size, 0, idx); + hls_prediction_unit(lc, l, pps, sps, + x0, y0 + cb_size / 4, cb_size, cb_size * 3 / 4, log2_cb_size, 1, idx); break; case PART_2NxnD: - hls_prediction_unit(lc, x0, y0, cb_size, cb_size * 3 / 4, log2_cb_size, 0, idx); - hls_prediction_unit(lc, x0, y0 + cb_size * 3 / 4, cb_size, cb_size / 4, log2_cb_size, 1, idx); + hls_prediction_unit(lc, l, pps, sps, + x0, y0, cb_size, cb_size * 3 / 4, log2_cb_size, 0, idx); + hls_prediction_unit(lc, l, pps, sps, + x0, y0 + cb_size * 3 / 4, cb_size, cb_size / 4, log2_cb_size, 1, idx); break; case PART_nLx2N: - hls_prediction_unit(lc, x0, y0, cb_size / 4, cb_size, log2_cb_size, 0, idx - 2); - hls_prediction_unit(lc, x0 + cb_size / 4, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 1, idx - 2); + hls_prediction_unit(lc, l, pps, sps, + x0, y0, cb_size / 4, cb_size, log2_cb_size, 0, idx - 2); + hls_prediction_unit(lc, l, pps, sps, + x0 + cb_size / 4, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 1, idx - 2); break; case PART_nRx2N: - hls_prediction_unit(lc, x0, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 0, idx - 2); - hls_prediction_unit(lc, x0 + cb_size * 3 / 4, y0, cb_size / 4, cb_size, log2_cb_size, 1, idx - 2); + hls_prediction_unit(lc, l, pps, sps, + x0, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 0, idx - 2); + hls_prediction_unit(lc, l, pps, sps, + x0 + cb_size * 3 / 4, y0, cb_size / 4, cb_size, log2_cb_size, 1, idx - 2); break; case PART_NxN: - hls_prediction_unit(lc, x0, y0, cb_size / 2, cb_size / 2, log2_cb_size, 0, idx - 1); - hls_prediction_unit(lc, x0 + cb_size / 2, y0, cb_size / 2, cb_size / 2, log2_cb_size, 1, idx - 1); - hls_prediction_unit(lc, x0, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 2, idx - 1); - hls_prediction_unit(lc, x0 + cb_size / 2, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 3, idx - 1); + hls_prediction_unit(lc, l, pps, sps, + x0, y0, cb_size / 2, cb_size / 2, log2_cb_size, 0, idx - 1); + hls_prediction_unit(lc, l, pps, sps, + x0 + cb_size / 2, y0, cb_size / 2, cb_size / 2, log2_cb_size, 1, idx - 1); + hls_prediction_unit(lc, l, pps, sps, + x0, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 2, idx - 1); + hls_prediction_unit(lc, l, pps, sps, + x0 + cb_size / 2, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 3, idx - 1); break; } } @@ -2359,26 +2504,26 @@ static int hls_coding_unit(HEVCLocalContext *lc, const HEVCContext *s, int x0, i if (rqt_root_cbf) { const static int cbf[2] = { 0 }; lc->cu.max_trafo_depth = lc->cu.pred_mode == MODE_INTRA ? - s->ps.sps->max_transform_hierarchy_depth_intra + lc->cu.intra_split_flag : - s->ps.sps->max_transform_hierarchy_depth_inter; - ret = hls_transform_tree(lc, x0, y0, x0, y0, x0, y0, + sps->max_transform_hierarchy_depth_intra + lc->cu.intra_split_flag : + sps->max_transform_hierarchy_depth_inter; + ret = hls_transform_tree(lc, l, pps, sps, x0, y0, x0, y0, x0, y0, log2_cb_size, log2_cb_size, 0, 0, cbf, cbf); if (ret < 0) return ret; } else { if (!s->sh.disable_deblocking_filter_flag) - ff_hevc_deblocking_boundary_strengths(lc, x0, y0, log2_cb_size); + ff_hevc_deblocking_boundary_strengths(lc, l, pps, x0, y0, log2_cb_size); } } } - if (s->ps.pps->cu_qp_delta_enabled_flag && lc->tu.is_cu_qp_delta_coded == 0) - ff_hevc_set_qPy(lc, x0, y0, log2_cb_size); + if (pps->cu_qp_delta_enabled_flag && lc->tu.is_cu_qp_delta_coded == 0) + ff_hevc_set_qPy(lc, l, pps, x0, y0, log2_cb_size); x = y_cb * min_cb_width + x_cb; for (y = 0; y < length; y++) { - memset(&s->qp_y_tab[x], lc->qp_y, length); + memset(&l->qp_y_tab[x], lc->qp_y, length); x += min_cb_width; } @@ -2387,12 +2532,15 @@ static int hls_coding_unit(HEVCLocalContext *lc, const HEVCContext *s, int x0, i lc->qPy_pred = lc->qp_y; } - set_ct_depth(s, x0, y0, log2_cb_size, lc->ct_depth); + set_ct_depth(sps, l->tab_ct_depth, x0, y0, log2_cb_size, lc->ct_depth); return 0; } -static int hls_coding_quadtree(HEVCLocalContext *lc, int x0, int y0, +static int hls_coding_quadtree(HEVCLocalContext *lc, + const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, + int x0, int y0, int log2_cb_size, int cb_depth) { const HEVCContext *const s = lc->parent; @@ -2401,49 +2549,54 @@ static int hls_coding_quadtree(HEVCLocalContext *lc, int x0, int y0, int split_cu; lc->ct_depth = cb_depth; - if (x0 + cb_size <= s->ps.sps->width && - y0 + cb_size <= s->ps.sps->height && - log2_cb_size > s->ps.sps->log2_min_cb_size) { - split_cu = ff_hevc_split_coding_unit_flag_decode(lc, cb_depth, x0, y0); + if (x0 + cb_size <= sps->width && + y0 + cb_size <= sps->height && + log2_cb_size > sps->log2_min_cb_size) { + split_cu = ff_hevc_split_coding_unit_flag_decode(lc, l->tab_ct_depth, + sps, cb_depth, x0, y0); } else { - split_cu = (log2_cb_size > s->ps.sps->log2_min_cb_size); + split_cu = (log2_cb_size > sps->log2_min_cb_size); } - if (s->ps.pps->cu_qp_delta_enabled_flag && - log2_cb_size >= s->ps.sps->log2_ctb_size - s->ps.pps->diff_cu_qp_delta_depth) { + if (pps->cu_qp_delta_enabled_flag && + log2_cb_size >= sps->log2_ctb_size - pps->diff_cu_qp_delta_depth) { lc->tu.is_cu_qp_delta_coded = 0; lc->tu.cu_qp_delta = 0; } if (s->sh.cu_chroma_qp_offset_enabled_flag && - log2_cb_size >= s->ps.sps->log2_ctb_size - s->ps.pps->diff_cu_chroma_qp_offset_depth) { + log2_cb_size >= sps->log2_ctb_size - pps->diff_cu_chroma_qp_offset_depth) { lc->tu.is_cu_chroma_qp_offset_coded = 0; } if (split_cu) { - int qp_block_mask = (1<<(s->ps.sps->log2_ctb_size - s->ps.pps->diff_cu_qp_delta_depth)) - 1; + int qp_block_mask = (1 << (sps->log2_ctb_size - pps->diff_cu_qp_delta_depth)) - 1; const int cb_size_split = cb_size >> 1; const int x1 = x0 + cb_size_split; const int y1 = y0 + cb_size_split; int more_data = 0; - more_data = hls_coding_quadtree(lc, x0, y0, log2_cb_size - 1, cb_depth + 1); + more_data = hls_coding_quadtree(lc, l, pps, sps, + x0, y0, log2_cb_size - 1, cb_depth + 1); if (more_data < 0) return more_data; - if (more_data && x1 < s->ps.sps->width) { - more_data = hls_coding_quadtree(lc, x1, y0, log2_cb_size - 1, cb_depth + 1); + if (more_data && x1 < sps->width) { + more_data = hls_coding_quadtree(lc, l, pps, sps, + x1, y0, log2_cb_size - 1, cb_depth + 1); if (more_data < 0) return more_data; } - if (more_data && y1 < s->ps.sps->height) { - more_data = hls_coding_quadtree(lc, x0, y1, log2_cb_size - 1, cb_depth + 1); + if (more_data && y1 < sps->height) { + more_data = hls_coding_quadtree(lc, l, pps, sps, + x0, y1, log2_cb_size - 1, cb_depth + 1); if (more_data < 0) return more_data; } - if (more_data && x1 < s->ps.sps->width && - y1 < s->ps.sps->height) { - more_data = hls_coding_quadtree(lc, x1, y1, log2_cb_size - 1, cb_depth + 1); + if (more_data && x1 < sps->width && + y1 < sps->height) { + more_data = hls_coding_quadtree(lc, l, pps, sps, + x1, y1, log2_cb_size - 1, cb_depth + 1); if (more_data < 0) return more_data; } @@ -2453,20 +2606,20 @@ static int hls_coding_quadtree(HEVCLocalContext *lc, int x0, int y0, lc->qPy_pred = lc->qp_y; if (more_data) - return ((x1 + cb_size_split) < s->ps.sps->width || - (y1 + cb_size_split) < s->ps.sps->height); + return ((x1 + cb_size_split) < sps->width || + (y1 + cb_size_split) < sps->height); else return 0; } else { - ret = hls_coding_unit(lc, s, x0, y0, log2_cb_size); + ret = hls_coding_unit(lc, s, l, pps, sps, x0, y0, log2_cb_size); if (ret < 0) return ret; if ((!((x0 + cb_size) % - (1 << (s->ps.sps->log2_ctb_size))) || - (x0 + cb_size >= s->ps.sps->width)) && + (1 << (sps->log2_ctb_size))) || + (x0 + cb_size >= sps->width)) && (!((y0 + cb_size) % - (1 << (s->ps.sps->log2_ctb_size))) || - (y0 + cb_size >= s->ps.sps->height))) { + (1 << (sps->log2_ctb_size))) || + (y0 + cb_size >= sps->height))) { int end_of_slice_flag = ff_hevc_end_of_slice_flag_decode(lc); return !end_of_slice_flag; } else { @@ -2477,165 +2630,164 @@ static int hls_coding_quadtree(HEVCLocalContext *lc, int x0, int y0, return 0; } -static void hls_decode_neighbour(HEVCLocalContext *lc, int x_ctb, int y_ctb, - int ctb_addr_ts) +static void hls_decode_neighbour(HEVCLocalContext *lc, + const HEVCLayerContext *l, + const HEVCPPS *pps, const HEVCSPS *sps, + int x_ctb, int y_ctb, int ctb_addr_ts) { const HEVCContext *const s = lc->parent; - int ctb_size = 1 << s->ps.sps->log2_ctb_size; - int ctb_addr_rs = s->ps.pps->ctb_addr_ts_to_rs[ctb_addr_ts]; + int ctb_size = 1 << sps->log2_ctb_size; + int ctb_addr_rs = pps->ctb_addr_ts_to_rs[ctb_addr_ts]; int ctb_addr_in_slice = ctb_addr_rs - s->sh.slice_addr; - s->tab_slice_address[ctb_addr_rs] = s->sh.slice_addr; + l->tab_slice_address[ctb_addr_rs] = s->sh.slice_addr; - if (s->ps.pps->entropy_coding_sync_enabled_flag) { + if (pps->entropy_coding_sync_enabled_flag) { if (x_ctb == 0 && (y_ctb & (ctb_size - 1)) == 0) lc->first_qp_group = 1; - lc->end_of_tiles_x = s->ps.sps->width; - } else if (s->ps.pps->tiles_enabled_flag) { - if (ctb_addr_ts && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[ctb_addr_ts - 1]) { - int idxX = s->ps.pps->col_idxX[x_ctb >> s->ps.sps->log2_ctb_size]; - lc->end_of_tiles_x = x_ctb + (s->ps.pps->column_width[idxX] << s->ps.sps->log2_ctb_size); + lc->end_of_tiles_x = sps->width; + } else if (pps->tiles_enabled_flag) { + if (ctb_addr_ts && pps->tile_id[ctb_addr_ts] != pps->tile_id[ctb_addr_ts - 1]) { + int idxX = pps->col_idxX[x_ctb >> sps->log2_ctb_size]; + lc->end_of_tiles_x = x_ctb + (pps->column_width[idxX] << sps->log2_ctb_size); lc->first_qp_group = 1; } } else { - lc->end_of_tiles_x = s->ps.sps->width; + lc->end_of_tiles_x = sps->width; } - lc->end_of_tiles_y = FFMIN(y_ctb + ctb_size, s->ps.sps->height); + lc->end_of_tiles_y = FFMIN(y_ctb + ctb_size, sps->height); lc->boundary_flags = 0; - if (s->ps.pps->tiles_enabled_flag) { - if (x_ctb > 0 && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs - 1]]) + if (pps->tiles_enabled_flag) { + if (x_ctb > 0 && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs - 1]]) lc->boundary_flags |= BOUNDARY_LEFT_TILE; - if (x_ctb > 0 && s->tab_slice_address[ctb_addr_rs] != s->tab_slice_address[ctb_addr_rs - 1]) + if (x_ctb > 0 && l->tab_slice_address[ctb_addr_rs] != l->tab_slice_address[ctb_addr_rs - 1]) lc->boundary_flags |= BOUNDARY_LEFT_SLICE; - if (y_ctb > 0 && s->ps.pps->tile_id[ctb_addr_ts] != s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->ps.sps->ctb_width]]) + if (y_ctb > 0 && pps->tile_id[ctb_addr_ts] != pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs - sps->ctb_width]]) lc->boundary_flags |= BOUNDARY_UPPER_TILE; - if (y_ctb > 0 && s->tab_slice_address[ctb_addr_rs] != s->tab_slice_address[ctb_addr_rs - s->ps.sps->ctb_width]) + if (y_ctb > 0 && l->tab_slice_address[ctb_addr_rs] != l->tab_slice_address[ctb_addr_rs - sps->ctb_width]) lc->boundary_flags |= BOUNDARY_UPPER_SLICE; } else { if (ctb_addr_in_slice <= 0) lc->boundary_flags |= BOUNDARY_LEFT_SLICE; - if (ctb_addr_in_slice < s->ps.sps->ctb_width) + if (ctb_addr_in_slice < sps->ctb_width) lc->boundary_flags |= BOUNDARY_UPPER_SLICE; } lc->ctb_left_flag = ((x_ctb > 0) && (ctb_addr_in_slice > 0) && !(lc->boundary_flags & BOUNDARY_LEFT_TILE)); - lc->ctb_up_flag = ((y_ctb > 0) && (ctb_addr_in_slice >= s->ps.sps->ctb_width) && !(lc->boundary_flags & BOUNDARY_UPPER_TILE)); - lc->ctb_up_right_flag = ((y_ctb > 0) && (ctb_addr_in_slice+1 >= s->ps.sps->ctb_width) && (s->ps.pps->tile_id[ctb_addr_ts] == s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs+1 - s->ps.sps->ctb_width]])); - lc->ctb_up_left_flag = ((x_ctb > 0) && (y_ctb > 0) && (ctb_addr_in_slice-1 >= s->ps.sps->ctb_width) && (s->ps.pps->tile_id[ctb_addr_ts] == s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs-1 - s->ps.sps->ctb_width]])); + lc->ctb_up_flag = ((y_ctb > 0) && (ctb_addr_in_slice >= sps->ctb_width) && !(lc->boundary_flags & BOUNDARY_UPPER_TILE)); + lc->ctb_up_right_flag = ((y_ctb > 0) && (ctb_addr_in_slice+1 >= sps->ctb_width) && (pps->tile_id[ctb_addr_ts] == pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs+1 - sps->ctb_width]])); + lc->ctb_up_left_flag = ((x_ctb > 0) && (y_ctb > 0) && (ctb_addr_in_slice-1 >= sps->ctb_width) && (pps->tile_id[ctb_addr_ts] == pps->tile_id[pps->ctb_addr_rs_to_ts[ctb_addr_rs-1 - sps->ctb_width]])); } -static int hls_decode_entry(AVCodecContext *avctxt, void *arg) +static int hls_decode_entry(HEVCContext *s, GetBitContext *gb) { - HEVCContext *s = avctxt->priv_data; - HEVCLocalContext *const lc = s->HEVClc; - int ctb_size = 1 << s->ps.sps->log2_ctb_size; + HEVCLocalContext *const lc = &s->local_ctx[0]; + const HEVCLayerContext *const l = &s->layers[s->cur_layer]; + 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; + int ctb_size = 1 << sps->log2_ctb_size; int more_data = 1; int x_ctb = 0; int y_ctb = 0; - int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]; + int ctb_addr_ts = pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]; int ret; - if (!ctb_addr_ts && s->sh.dependent_slice_segment_flag) { - av_log(s->avctx, AV_LOG_ERROR, "Impossible initial tile.\n"); - return AVERROR_INVALIDDATA; - } + while (more_data && ctb_addr_ts < sps->ctb_size) { + int ctb_addr_rs = pps->ctb_addr_ts_to_rs[ctb_addr_ts]; - if (s->sh.dependent_slice_segment_flag) { - int prev_rs = s->ps.pps->ctb_addr_ts_to_rs[ctb_addr_ts - 1]; - if (s->tab_slice_address[prev_rs] != s->sh.slice_addr) { - av_log(s->avctx, AV_LOG_ERROR, "Previous slice segment missing\n"); - return AVERROR_INVALIDDATA; - } - } + x_ctb = (ctb_addr_rs % ((sps->width + ctb_size - 1) >> sps->log2_ctb_size)) << sps->log2_ctb_size; + y_ctb = (ctb_addr_rs / ((sps->width + ctb_size - 1) >> sps->log2_ctb_size)) << sps->log2_ctb_size; + hls_decode_neighbour(lc, l, pps, sps, x_ctb, y_ctb, ctb_addr_ts); - while (more_data && ctb_addr_ts < s->ps.sps->ctb_size) { - int ctb_addr_rs = s->ps.pps->ctb_addr_ts_to_rs[ctb_addr_ts]; - - x_ctb = (ctb_addr_rs % ((s->ps.sps->width + ctb_size - 1) >> s->ps.sps->log2_ctb_size)) << s->ps.sps->log2_ctb_size; - y_ctb = (ctb_addr_rs / ((s->ps.sps->width + ctb_size - 1) >> s->ps.sps->log2_ctb_size)) << s->ps.sps->log2_ctb_size; - hls_decode_neighbour(lc, x_ctb, y_ctb, ctb_addr_ts); - - ret = ff_hevc_cabac_init(lc, ctb_addr_ts); + ret = ff_hevc_cabac_init(lc, pps, ctb_addr_ts, slice_data, slice_size, 0); if (ret < 0) { - s->tab_slice_address[ctb_addr_rs] = -1; + l->tab_slice_address[ctb_addr_rs] = -1; return ret; } - hls_sao_param(lc, x_ctb >> s->ps.sps->log2_ctb_size, y_ctb >> s->ps.sps->log2_ctb_size); + hls_sao_param(lc, l, pps, sps, + x_ctb >> sps->log2_ctb_size, y_ctb >> sps->log2_ctb_size); - s->deblock[ctb_addr_rs].beta_offset = s->sh.beta_offset; - s->deblock[ctb_addr_rs].tc_offset = s->sh.tc_offset; - s->filter_slice_edges[ctb_addr_rs] = s->sh.slice_loop_filter_across_slices_enabled_flag; + l->deblock[ctb_addr_rs].beta_offset = s->sh.beta_offset; + l->deblock[ctb_addr_rs].tc_offset = s->sh.tc_offset; + l->filter_slice_edges[ctb_addr_rs] = s->sh.slice_loop_filter_across_slices_enabled_flag; - more_data = hls_coding_quadtree(lc, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0); + more_data = hls_coding_quadtree(lc, l, pps, sps, x_ctb, y_ctb, sps->log2_ctb_size, 0); if (more_data < 0) { - s->tab_slice_address[ctb_addr_rs] = -1; + l->tab_slice_address[ctb_addr_rs] = -1; return more_data; } ctb_addr_ts++; - ff_hevc_save_states(lc, ctb_addr_ts); - ff_hevc_hls_filters(lc, x_ctb, y_ctb, ctb_size); + ff_hevc_save_states(lc, pps, ctb_addr_ts); + ff_hevc_hls_filters(lc, l, pps, x_ctb, y_ctb, ctb_size); } - if (x_ctb + ctb_size >= s->ps.sps->width && - y_ctb + ctb_size >= s->ps.sps->height) - ff_hevc_hls_filter(lc, x_ctb, y_ctb, ctb_size); + if (x_ctb + ctb_size >= sps->width && + y_ctb + ctb_size >= sps->height) + ff_hevc_hls_filter(lc, l, pps, x_ctb, y_ctb, ctb_size); return ctb_addr_ts; } -static int hls_slice_data(HEVCContext *s) +static int hls_decode_entry_wpp(AVCodecContext *avctx, void *hevc_lclist, + int job, int thread) { - int ret = 0; - - s->avctx->execute(s->avctx, hls_decode_entry, NULL, &ret , 1, 0); - return ret; -} -static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *hevc_lclist, - int job, int self_id) -{ - HEVCLocalContext *lc = ((HEVCLocalContext**)hevc_lclist)[self_id]; + HEVCLocalContext *lc = &((HEVCLocalContext*)hevc_lclist)[thread]; const HEVCContext *const s = lc->parent; - int ctb_size = 1 << s->ps.sps->log2_ctb_size; + const HEVCLayerContext *const l = &s->layers[s->cur_layer]; + const HEVCPPS *const pps = s->pps; + const HEVCSPS *const sps = pps->sps; + int ctb_size = 1 << sps->log2_ctb_size; int more_data = 1; int ctb_row = job; - int ctb_addr_rs = s->sh.slice_ctb_addr_rs + ctb_row * ((s->ps.sps->width + ctb_size - 1) >> s->ps.sps->log2_ctb_size); - int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs]; - int thread = ctb_row % s->threads_number; + int ctb_addr_rs = s->sh.slice_ctb_addr_rs + ctb_row * ((sps->width + ctb_size - 1) >> sps->log2_ctb_size); + int ctb_addr_ts = pps->ctb_addr_rs_to_ts[ctb_addr_rs]; + + const uint8_t *data = s->data + s->sh.offset[ctb_row]; + const size_t data_size = s->sh.size[ctb_row]; + + int progress = 0; + int ret; - if(ctb_row) { - ret = init_get_bits8(&lc->gb, s->data + s->sh.offset[ctb_row - 1], s->sh.size[ctb_row - 1]); - if (ret < 0) - goto error; - ff_init_cabac_decoder(&lc->cc, s->data + s->sh.offset[(ctb_row)-1], s->sh.size[ctb_row - 1]); - } + if (ctb_row) + ff_init_cabac_decoder(&lc->cc, data, data_size); - while(more_data && ctb_addr_ts < s->ps.sps->ctb_size) { - int x_ctb = (ctb_addr_rs % s->ps.sps->ctb_width) << s->ps.sps->log2_ctb_size; - int y_ctb = (ctb_addr_rs / s->ps.sps->ctb_width) << s->ps.sps->log2_ctb_size; + while(more_data && ctb_addr_ts < sps->ctb_size) { + int x_ctb = (ctb_addr_rs % sps->ctb_width) << sps->log2_ctb_size; + int y_ctb = (ctb_addr_rs / sps->ctb_width) << sps->log2_ctb_size; - hls_decode_neighbour(lc, x_ctb, y_ctb, ctb_addr_ts); + hls_decode_neighbour(lc, l, pps, sps, x_ctb, y_ctb, ctb_addr_ts); - ff_thread_await_progress2(s->avctx, ctb_row, thread, SHIFT_CTB_WPP); + if (ctb_row) + ff_thread_progress_await(&s->wpp_progress[ctb_row - 1], + progress + SHIFT_CTB_WPP + 1); /* atomic_load's prototype requires a pointer to non-const atomic variable * (due to implementations via mutexes, where reads involve writes). * Of course, casting const away here is nevertheless safe. */ if (atomic_load((atomic_int*)&s->wpp_err)) { - ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return 0; } - ret = ff_hevc_cabac_init(lc, ctb_addr_ts); + ret = ff_hevc_cabac_init(lc, pps, ctb_addr_ts, data, data_size, 1); if (ret < 0) goto error; - hls_sao_param(lc, x_ctb >> s->ps.sps->log2_ctb_size, y_ctb >> s->ps.sps->log2_ctb_size); - more_data = hls_coding_quadtree(lc, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0); + hls_sao_param(lc, l, pps, sps, + x_ctb >> sps->log2_ctb_size, y_ctb >> sps->log2_ctb_size); + + l->deblock[ctb_addr_rs].beta_offset = s->sh.beta_offset; + l->deblock[ctb_addr_rs].tc_offset = s->sh.tc_offset; + l->filter_slice_edges[ctb_addr_rs] = s->sh.slice_loop_filter_across_slices_enabled_flag; + + more_data = hls_coding_quadtree(lc, l, pps, sps, x_ctb, y_ctb, sps->log2_ctb_size, 0); if (more_data < 0) { ret = more_data; @@ -2644,70 +2796,109 @@ static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *hevc_lclist, ctb_addr_ts++; - ff_hevc_save_states(lc, ctb_addr_ts); - ff_thread_report_progress2(s->avctx, ctb_row, thread, 1); - ff_hevc_hls_filters(lc, x_ctb, y_ctb, ctb_size); + ff_hevc_save_states(lc, pps, ctb_addr_ts); + ff_thread_progress_report(&s->wpp_progress[ctb_row], ++progress); + ff_hevc_hls_filters(lc, l, pps, x_ctb, y_ctb, ctb_size); - if (!more_data && (x_ctb+ctb_size) < s->ps.sps->width && ctb_row != s->sh.num_entry_point_offsets) { + if (!more_data && (x_ctb+ctb_size) < sps->width && ctb_row != s->sh.num_entry_point_offsets) { /* Casting const away here is safe, because it is an atomic operation. */ atomic_store((atomic_int*)&s->wpp_err, 1); - ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return 0; } - if ((x_ctb+ctb_size) >= s->ps.sps->width && (y_ctb+ctb_size) >= s->ps.sps->height ) { - ff_hevc_hls_filter(lc, x_ctb, y_ctb, ctb_size); - ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP); + if ((x_ctb+ctb_size) >= sps->width && (y_ctb+ctb_size) >= sps->height ) { + ff_hevc_hls_filter(lc, l, pps, x_ctb, y_ctb, ctb_size); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return ctb_addr_ts; } - ctb_addr_rs = s->ps.pps->ctb_addr_ts_to_rs[ctb_addr_ts]; + ctb_addr_rs = pps->ctb_addr_ts_to_rs[ctb_addr_ts]; x_ctb+=ctb_size; - if(x_ctb >= s->ps.sps->width) { + if(x_ctb >= sps->width) { break; } } - ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return 0; error: - s->tab_slice_address[ctb_addr_rs] = -1; + l->tab_slice_address[ctb_addr_rs] = -1; /* Casting const away here is safe, because it is an atomic operation. */ atomic_store((atomic_int*)&s->wpp_err, 1); - ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP); + ff_thread_progress_report(&s->wpp_progress[ctb_row], INT_MAX); return ret; } +static int wpp_progress_init(HEVCContext *s, unsigned count) +{ + if (s->nb_wpp_progress < count) { + void *tmp = av_realloc_array(s->wpp_progress, count, + sizeof(*s->wpp_progress)); + if (!tmp) + return AVERROR(ENOMEM); + + s->wpp_progress = tmp; + memset(s->wpp_progress + s->nb_wpp_progress, 0, + (count - s->nb_wpp_progress) * sizeof(*s->wpp_progress)); + + for (int i = s->nb_wpp_progress; i < count; i++) { + int ret = ff_thread_progress_init(&s->wpp_progress[i], 1); + if (ret < 0) + return ret; + s->nb_wpp_progress = i + 1; + } + } + + for (int i = 0; i < count; i++) + ff_thread_progress_reset(&s->wpp_progress[i]); + + return 0; +} + static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) { + const HEVCPPS *const pps = s->pps; + const HEVCSPS *const sps = pps->sps; const uint8_t *data = nal->data; int length = nal->size; - HEVCLocalContext *lc = s->HEVClc; int *ret; int64_t offset; int64_t startheader, cmpt = 0; int i, j, res = 0; - if (s->sh.slice_ctb_addr_rs + s->sh.num_entry_point_offsets * s->ps.sps->ctb_width >= s->ps.sps->ctb_width * s->ps.sps->ctb_height) { + if (s->sh.slice_ctb_addr_rs + s->sh.num_entry_point_offsets * sps->ctb_width >= sps->ctb_width * sps->ctb_height) { av_log(s->avctx, AV_LOG_ERROR, "WPP ctb addresses are wrong (%d %d %d %d)\n", s->sh.slice_ctb_addr_rs, s->sh.num_entry_point_offsets, - s->ps.sps->ctb_width, s->ps.sps->ctb_height + sps->ctb_width, sps->ctb_height ); return AVERROR_INVALIDDATA; } - for (i = 1; i < s->threads_number; i++) { - if (s->HEVClcList[i]) - continue; - s->HEVClcList[i] = av_mallocz(sizeof(HEVCLocalContext)); - if (!s->HEVClcList[i]) + if (s->avctx->thread_count > s->nb_local_ctx) { + HEVCLocalContext *tmp = av_malloc_array(s->avctx->thread_count, sizeof(*s->local_ctx)); + + if (!tmp) return AVERROR(ENOMEM); - s->HEVClcList[i]->logctx = s->avctx; - s->HEVClcList[i]->parent = s; - s->HEVClcList[i]->common_cabac_state = &s->cabac; + + memcpy(tmp, s->local_ctx, sizeof(*s->local_ctx) * s->nb_local_ctx); + av_free(s->local_ctx); + s->local_ctx = tmp; + + for (unsigned i = s->nb_local_ctx; i < s->avctx->thread_count; i++) { + tmp = &s->local_ctx[i]; + + memset(tmp, 0, sizeof(*tmp)); + + tmp->logctx = s->avctx; + tmp->parent = s; + tmp->common_cabac_state = &s->cabac; + } + + s->nb_local_ctx = s->avctx->thread_count; } - offset = (lc->gb.index >> 3); + offset = s->sh.data_offset; for (j = 0, cmpt = 0, startheader = offset + s->sh.entry_point_offset[0]; j < nal->skipped_bytes; j++) { if (nal->skipped_bytes_pos[j] >= offset && nal->skipped_bytes_pos[j] < startheader) { @@ -2725,29 +2916,31 @@ static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) cmpt++; } } - s->sh.size[i - 1] = s->sh.entry_point_offset[i] - cmpt; - s->sh.offset[i - 1] = offset; + s->sh.size[i] = s->sh.entry_point_offset[i] - cmpt; + s->sh.offset[i] = offset; } - if (s->sh.num_entry_point_offsets != 0) { - offset += s->sh.entry_point_offset[s->sh.num_entry_point_offsets - 1] - cmpt; - if (length < offset) { - av_log(s->avctx, AV_LOG_ERROR, "entry_point_offset table is corrupted\n"); - return AVERROR_INVALIDDATA; - } - s->sh.size[s->sh.num_entry_point_offsets - 1] = length - offset; - s->sh.offset[s->sh.num_entry_point_offsets - 1] = offset; + offset += s->sh.entry_point_offset[s->sh.num_entry_point_offsets - 1] - cmpt; + if (length < offset) { + av_log(s->avctx, AV_LOG_ERROR, "entry_point_offset table is corrupted\n"); + return AVERROR_INVALIDDATA; } + s->sh.size [s->sh.num_entry_point_offsets] = length - offset; + s->sh.offset[s->sh.num_entry_point_offsets] = offset; + + s->sh.offset[0] = s->sh.data_offset; + s->sh.size[0] = s->sh.offset[1] - s->sh.offset[0]; + s->data = data; - for (i = 1; i < s->threads_number; i++) { - s->HEVClcList[i]->first_qp_group = 1; - s->HEVClcList[i]->qp_y = s->HEVClc->qp_y; + for (i = 1; i < s->nb_local_ctx; i++) { + s->local_ctx[i].first_qp_group = 1; + s->local_ctx[i].qp_y = s->local_ctx[0].qp_y; } atomic_store(&s->wpp_err, 0); - res = ff_slice_thread_allocz_entries(s->avctx, s->sh.num_entry_point_offsets + 1); + res = wpp_progress_init(s, s->sh.num_entry_point_offsets + 1); if (res < 0) return res; @@ -2755,8 +2948,8 @@ static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) if (!ret) return AVERROR(ENOMEM); - if (s->ps.pps->entropy_coding_sync_enabled_flag) - s->avctx->execute2(s->avctx, hls_decode_entry_wpp, s->HEVClcList, ret, s->sh.num_entry_point_offsets + 1); + if (pps->entropy_coding_sync_enabled_flag) + s->avctx->execute2(s->avctx, hls_decode_entry_wpp, s->local_ctx, ret, s->sh.num_entry_point_offsets + 1); for (i = 0; i <= s->sh.num_entry_point_offsets; i++) res += ret[i]; @@ -2765,9 +2958,64 @@ static int hls_slice_data_wpp(HEVCContext *s, const H2645NAL *nal) return res; } +static int decode_slice_data(HEVCContext *s, const HEVCLayerContext *l, + const H2645NAL *nal, GetBitContext *gb) +{ + const HEVCPPS *pps = s->pps; + int ret; + + if (!s->sh.first_slice_in_pic_flag) + s->slice_idx += !s->sh.dependent_slice_segment_flag; + + if (!s->sh.dependent_slice_segment_flag && s->sh.slice_type != HEVC_SLICE_I) { + ret = ff_hevc_slice_rpl(s); + if (ret < 0) { + av_log(s->avctx, AV_LOG_WARNING, + "Error constructing the reference lists for the current slice.\n"); + return ret; + } + } + + s->slice_initialized = 1; + + if (s->avctx->hwaccel) + return FF_HW_CALL(s->avctx, decode_slice, nal->raw_data, nal->raw_size); + + if (s->avctx->profile == AV_PROFILE_HEVC_SCC) { + av_log(s->avctx, AV_LOG_ERROR, + "SCC profile is not yet implemented in hevc native decoder.\n"); + return AVERROR_PATCHWELCOME; + } + + if (s->sh.dependent_slice_segment_flag) { + int ctb_addr_ts = pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs]; + int prev_rs = pps->ctb_addr_ts_to_rs[ctb_addr_ts - 1]; + if (l->tab_slice_address[prev_rs] != s->sh.slice_addr) { + av_log(s->avctx, AV_LOG_ERROR, "Previous slice segment missing\n"); + return AVERROR_INVALIDDATA; + } + } + + s->local_ctx[0].first_qp_group = !s->sh.dependent_slice_segment_flag; + + if (!pps->cu_qp_delta_enabled_flag) + s->local_ctx[0].qp_y = s->sh.slice_qp; + + s->local_ctx[0].tu.cu_qp_offset_cb = 0; + s->local_ctx[0].tu.cu_qp_offset_cr = 0; + + if (s->avctx->active_thread_type == FF_THREAD_SLICE && + s->sh.num_entry_point_offsets > 0 && + pps->num_tile_rows == 1 && pps->num_tile_columns == 1) + return hls_slice_data_wpp(s, nal); + + return hls_decode_entry(s, gb); +} + static int set_side_data(HEVCContext *s) { - AVFrame *out = s->ref->frame; + const HEVCSPS *sps = s->cur_frame->pps->sps; + AVFrame *out = s->cur_frame->f; int ret; // Decrement the mastering display and content light level flag when IRAP @@ -2782,9 +3030,9 @@ static int set_side_data(HEVCContext *s) } ret = ff_h2645_sei_to_frame(out, &s->sei.common, AV_CODEC_ID_HEVC, s->avctx, - &s->ps.sps->vui.common, - s->ps.sps->bit_depth, s->ps.sps->bit_depth_chroma, - s->ref->poc /* no poc_offset in HEVC */); + &sps->vui.common, + sps->bit_depth, sps->bit_depth_chroma, + s->cur_frame->poc /* no poc_offset in HEVC */); if (ret < 0) return ret; @@ -2822,7 +3070,7 @@ static int set_side_data(HEVCContext *s) if (!info_ref) return AVERROR(ENOMEM); - ret = ff_frame_new_side_data_from_buf(s->avctx, out, AV_FRAME_DATA_DYNAMIC_HDR_PLUS, &info_ref, NULL); + ret = ff_frame_new_side_data_from_buf(s->avctx, out, AV_FRAME_DATA_DYNAMIC_HDR_PLUS, &info_ref); if (ret < 0) return ret; } @@ -2852,44 +3100,176 @@ static int set_side_data(HEVCContext *s) return 0; } -static int hevc_frame_start(HEVCContext *s) +static int find_finish_setup_nal(const HEVCContext *s) { - HEVCLocalContext *lc = s->HEVClc; - int pic_size_in_ctb = ((s->ps.sps->width >> s->ps.sps->log2_min_cb_size) + 1) * - ((s->ps.sps->height >> s->ps.sps->log2_min_cb_size) + 1); + int nal_idx = 0; + + for (int i = nal_idx; i < s->pkt.nb_nals; i++) { + const H2645NAL *nal = &s->pkt.nals[i]; + const int layer_id = nal->nuh_layer_id; + GetBitContext gb = nal->gb; + + if (layer_id > HEVC_MAX_NUH_LAYER_ID || s->vps->layer_idx[layer_id] < 0 || + !(s->layers_active_decode & (1 << s->vps->layer_idx[layer_id]))) + continue; + + switch (nal->type) { + 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_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: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + if (!get_bits1(&gb)) // first_slice_segment_in_pic_flag + continue; + case HEVC_NAL_VPS: + case HEVC_NAL_SPS: + case HEVC_NAL_PPS: + nal_idx = i; + break; + } + } + + return nal_idx; +} + +static int hevc_frame_start(HEVCContext *s, HEVCLayerContext *l, + unsigned nal_idx) +{ + const HEVCPPS *const pps = s->ps.pps_list[s->sh.pps_id]; + const HEVCSPS *const sps = pps->sps; + int pic_size_in_ctb = ((sps->width >> sps->log2_min_cb_size) + 1) * + ((sps->height >> sps->log2_min_cb_size) + 1); + int new_sequence = (l == &s->layers[0]) && + (IS_IDR(s) || IS_BLA(s) || s->last_eos); + int prev_layers_active_decode = s->layers_active_decode; + int prev_layers_active_output = s->layers_active_output; int ret; - memset(s->horizontal_bs, 0, s->bs_width * s->bs_height); - memset(s->vertical_bs, 0, s->bs_width * s->bs_height); - memset(s->cbf_luma, 0, s->ps.sps->min_tb_width * s->ps.sps->min_tb_height); - memset(s->is_pcm, 0, (s->ps.sps->min_pu_width + 1) * (s->ps.sps->min_pu_height + 1)); - memset(s->tab_slice_address, -1, pic_size_in_ctb * sizeof(*s->tab_slice_address)); + if (sps->vps != s->vps && l != &s->layers[0]) { + av_log(s->avctx, AV_LOG_ERROR, "VPS changed in a non-base layer\n"); + set_sps(s, l, NULL); + return AVERROR_INVALIDDATA; + } - s->is_decoded = 0; + ff_refstruct_replace(&s->pps, pps); + if (l->sps != sps) { + const HEVCSPS *sps_base = s->layers[0].sps; + enum AVPixelFormat pix_fmt = sps->pix_fmt; + + if (l != &s->layers[0]) { + if (!sps_base) { + av_log(s->avctx, AV_LOG_ERROR, + "Access unit starts with a non-base layer frame\n"); + return AVERROR_INVALIDDATA; + } + + // Files produced by Vision Pro lack VPS extension VUI, + // so the secondary layer has no range information. + // This check avoids failing in such a case. + if (sps_base->pix_fmt == AV_PIX_FMT_YUVJ420P && + sps->pix_fmt == AV_PIX_FMT_YUV420P && + !sps->vui.common.video_signal_type_present_flag) + pix_fmt = sps_base->pix_fmt; + + if (pix_fmt != sps_base->pix_fmt || + sps->width != sps_base->width || + sps->height != sps_base->height) { + av_log(s->avctx, AV_LOG_ERROR, + "Base/non-base layer SPS have unsupported parameter combination\n"); + return AVERROR(ENOSYS); + } + } + + ff_hevc_clear_refs(l); + + ret = set_sps(s, l, sps); + if (ret < 0) + return ret; + + if (l == &s->layers[0]) { + export_stream_params(s, sps); + + ret = get_format(s, sps); + if (ret < 0) { + set_sps(s, l, NULL); + return ret; + } + + new_sequence = 1; + } + } + + memset(l->horizontal_bs, 0, l->bs_width * l->bs_height); + memset(l->vertical_bs, 0, l->bs_width * l->bs_height); + memset(l->cbf_luma, 0, sps->min_tb_width * sps->min_tb_height); + memset(l->is_pcm, 0, (sps->min_pu_width + 1) * (sps->min_pu_height + 1)); + memset(l->tab_slice_address, -1, pic_size_in_ctb * sizeof(*l->tab_slice_address)); + + if (IS_IDR(s)) + ff_hevc_clear_refs(l); + + s->slice_idx = 0; s->first_nal_type = s->nal_unit_type; + s->poc = s->sh.poc; - s->no_rasl_output_flag = IS_IDR(s) || IS_BLA(s) || (s->nal_unit_type == HEVC_NAL_CRA_NUT && s->last_eos); + 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); - if (s->ps.pps->tiles_enabled_flag) - lc->end_of_tiles_x = s->ps.pps->column_width[0] << s->ps.sps->log2_ctb_size; + /* 8.3.1 */ + if (s->temporal_id == 0 && + s->nal_unit_type != HEVC_NAL_TRAIL_N && + s->nal_unit_type != HEVC_NAL_TSA_N && + s->nal_unit_type != HEVC_NAL_STSA_N && + s->nal_unit_type != HEVC_NAL_RADL_N && + s->nal_unit_type != HEVC_NAL_RADL_R && + s->nal_unit_type != HEVC_NAL_RASL_N && + s->nal_unit_type != HEVC_NAL_RASL_R) + s->poc_tid0 = s->poc; - ret = ff_hevc_set_new_ref(s, &s->frame, s->poc); + if (pps->tiles_enabled_flag) + s->local_ctx[0].end_of_tiles_x = pps->column_width[0] << sps->log2_ctb_size; + + if (new_sequence) { + ret = ff_hevc_output_frames(s, prev_layers_active_decode, prev_layers_active_output, + 0, 0, s->sh.no_output_of_prior_pics_flag); + if (ret < 0) + return ret; + } + + ret = export_stream_params_from_sei(s); + if (ret < 0) + return ret; + + ret = ff_hevc_set_new_ref(s, l, s->poc); if (ret < 0) goto fail; - ret = ff_hevc_frame_rps(s); + ret = ff_hevc_frame_rps(s, l); if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error constructing the frame RPS.\n"); goto fail; } if (IS_IRAP(s)) - s->ref->frame->flags |= AV_FRAME_FLAG_KEY; + s->cur_frame->f->flags |= AV_FRAME_FLAG_KEY; else - s->ref->frame->flags &= ~AV_FRAME_FLAG_KEY; + s->cur_frame->f->flags &= ~AV_FRAME_FLAG_KEY; - s->ref->needs_fg = (s->sei.common.film_grain_characteristics.present || - s->sei.common.aom_film_grain.enable) && + s->cur_frame->needs_fg = ((s->sei.common.film_grain_characteristics && + s->sei.common.film_grain_characteristics->present) || + s->sei.common.aom_film_grain.enable) && !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) && !s->avctx->hwaccel; @@ -2897,352 +3277,59 @@ static int hevc_frame_start(HEVCContext *s) if (ret < 0) goto fail; - if (s->ref->needs_fg && - (s->sei.common.film_grain_characteristics.present && - !ff_h274_film_grain_params_supported(s->sei.common.film_grain_characteristics.model_id, - s->ref->frame->format) - || !av_film_grain_params_select(s->ref->frame))) { + if (s->cur_frame->needs_fg && + (s->sei.common.film_grain_characteristics && s->sei.common.film_grain_characteristics->present && + !ff_h274_film_grain_params_supported(s->sei.common.film_grain_characteristics->model_id, + s->cur_frame->f->format) || + !av_film_grain_params_select(s->cur_frame->f))) { av_log_once(s->avctx, AV_LOG_WARNING, AV_LOG_DEBUG, &s->film_grain_warning_shown, "Unsupported film grain parameters. Ignoring film grain.\n"); - s->ref->needs_fg = 0; + s->cur_frame->needs_fg = 0; } - if (s->ref->needs_fg) { - s->ref->frame_grain->format = s->ref->frame->format; - s->ref->frame_grain->width = s->ref->frame->width; - s->ref->frame_grain->height = s->ref->frame->height; - if ((ret = ff_thread_get_buffer(s->avctx, s->ref->frame_grain, 0)) < 0) + if (s->cur_frame->needs_fg) { + s->cur_frame->frame_grain->format = s->cur_frame->f->format; + s->cur_frame->frame_grain->width = s->cur_frame->f->width; + s->cur_frame->frame_grain->height = s->cur_frame->f->height; + if ((ret = ff_thread_get_buffer(s->avctx, s->cur_frame->frame_grain, 0)) < 0) + goto fail; + + ret = av_frame_copy_props(s->cur_frame->frame_grain, s->cur_frame->f); + if (ret < 0) goto fail; } - s->frame->pict_type = 3 - s->sh.slice_type; + s->cur_frame->f->pict_type = 3 - s->sh.slice_type; - if (!IS_IRAP(s)) - ff_hevc_bump_frame(s); - - av_frame_unref(s->output_frame); - ret = ff_hevc_output_frame(s, s->output_frame, 0); + ret = ff_hevc_output_frames(s, s->layers_active_decode, s->layers_active_output, + sps->temporal_layer[sps->max_sub_layers - 1].num_reorder_pics, + sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering, 0); if (ret < 0) goto fail; - if (!s->avctx->hwaccel) + if (s->avctx->hwaccel) { + ret = FF_HW_CALL(s->avctx, start_frame, NULL, 0); + if (ret < 0) + goto fail; + } + + // after starting the base-layer frame we know which layers will be decoded, + // so we can now figure out which NALUs to wait for before we can call + // ff_thread_finish_setup() + if (l == &s->layers[0]) + s->finish_setup_nal_idx = find_finish_setup_nal(s); + + if (nal_idx >= s->finish_setup_nal_idx) ff_thread_finish_setup(s->avctx); return 0; fail: - if (s->ref) - ff_hevc_unref_frame(s->ref, ~0); - s->ref = s->collocated_ref = NULL; - return ret; -} - -static int hevc_frame_end(HEVCContext *s) -{ - HEVCFrame *out = s->ref; - const AVFilmGrainParams *fgp; - av_unused int ret; - - if (out->needs_fg) { - av_assert0(out->frame_grain->buf[0]); - fgp = av_film_grain_params_select(out->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(out->frame_grain, out->frame, - &s->h274db, fgp); - break; - case AV_FILM_GRAIN_PARAMS_AV1: - ret = ff_aom_apply_film_grain(out->frame_grain, out->frame, fgp); - break; - } - av_assert1(ret >= 0); - } - - return 0; -} - -static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal) -{ - HEVCLocalContext *lc = s->HEVClc; - GetBitContext *gb = &lc->gb; - int ctb_addr_ts, ret; - - *gb = nal->gb; - s->nal_unit_type = nal->type; - s->temporal_id = nal->temporal_id; - - switch (s->nal_unit_type) { - case HEVC_NAL_VPS: - if (FF_HW_HAS_CB(s->avctx, decode_params)) { - ret = FF_HW_CALL(s->avctx, decode_params, - nal->type, nal->raw_data, nal->raw_size); - if (ret < 0) - goto fail; - } - ret = ff_hevc_decode_nal_vps(gb, s->avctx, &s->ps); - if (ret < 0) - goto fail; - break; - case HEVC_NAL_SPS: - if (FF_HW_HAS_CB(s->avctx, decode_params)) { - ret = FF_HW_CALL(s->avctx, decode_params, - nal->type, nal->raw_data, nal->raw_size); - if (ret < 0) - goto fail; - } - ret = ff_hevc_decode_nal_sps(gb, s->avctx, &s->ps, - s->apply_defdispwin); - if (ret < 0) - goto fail; - break; - case HEVC_NAL_PPS: - if (FF_HW_HAS_CB(s->avctx, decode_params)) { - ret = FF_HW_CALL(s->avctx, decode_params, - nal->type, nal->raw_data, nal->raw_size); - if (ret < 0) - goto fail; - } - ret = ff_hevc_decode_nal_pps(gb, s->avctx, &s->ps); - if (ret < 0) - goto fail; - break; - case HEVC_NAL_SEI_PREFIX: - case HEVC_NAL_SEI_SUFFIX: - if (FF_HW_HAS_CB(s->avctx, decode_params)) { - ret = FF_HW_CALL(s->avctx, decode_params, - nal->type, nal->raw_data, nal->raw_size); - if (ret < 0) - goto fail; - } - ret = ff_hevc_decode_nal_sei(gb, s->avctx, &s->sei, &s->ps, s->nal_unit_type); - if (ret < 0) - goto fail; - 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_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: - case HEVC_NAL_RADL_N: - case HEVC_NAL_RADL_R: - case HEVC_NAL_RASL_N: - case HEVC_NAL_RASL_R: - ret = hls_slice_header(s); - 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; - } - if (ret == 1) { - ret = AVERROR_INVALIDDATA; - goto fail; - } - - - if ( - (s->avctx->skip_frame >= AVDISCARD_BIDIR && s->sh.slice_type == HEVC_SLICE_B) || - (s->avctx->skip_frame >= AVDISCARD_NONINTRA && s->sh.slice_type != HEVC_SLICE_I) || - (s->avctx->skip_frame >= AVDISCARD_NONKEY && !IS_IRAP(s))) { - break; - } - - if (s->sh.first_slice_in_pic_flag) { - if (s->max_ra == INT_MAX) { - if (s->nal_unit_type == HEVC_NAL_CRA_NUT || IS_BLA(s)) { - s->max_ra = s->poc; - } else { - if (IS_IDR(s)) - s->max_ra = INT_MIN; - } - } - - if ((s->nal_unit_type == HEVC_NAL_RASL_R || s->nal_unit_type == HEVC_NAL_RASL_N) && - s->poc <= s->max_ra) { - s->is_decoded = 0; - break; - } else { - if (s->nal_unit_type == HEVC_NAL_RASL_R && s->poc > s->max_ra) - s->max_ra = INT_MIN; - } - - s->overlap ++; - ret = hevc_frame_start(s); - if (ret < 0) - return ret; - } else if (!s->ref) { - av_log(s->avctx, AV_LOG_ERROR, "First slice in a frame missing.\n"); - goto fail; - } - - if (s->nal_unit_type != s->first_nal_type) { - av_log(s->avctx, AV_LOG_ERROR, - "Non-matching NAL types of the VCL NALUs: %d %d\n", - s->first_nal_type, s->nal_unit_type); - return AVERROR_INVALIDDATA; - } - - if (!s->sh.dependent_slice_segment_flag && - s->sh.slice_type != HEVC_SLICE_I) { - ret = ff_hevc_slice_rpl(s); - if (ret < 0) { - av_log(s->avctx, AV_LOG_WARNING, - "Error constructing the reference lists for the current slice.\n"); - goto fail; - } - } - - if (s->sh.first_slice_in_pic_flag && s->avctx->hwaccel) { - ret = FF_HW_CALL(s->avctx, start_frame, NULL, 0); - if (ret < 0) - goto fail; - } - - if (s->avctx->hwaccel) { - ret = FF_HW_CALL(s->avctx, decode_slice, nal->raw_data, nal->raw_size); - if (ret < 0) - goto fail; - } else { - if (s->avctx->profile == AV_PROFILE_HEVC_SCC) { - av_log(s->avctx, AV_LOG_ERROR, - "SCC profile is not yet implemented in hevc native decoder.\n"); - ret = AVERROR_PATCHWELCOME; - goto fail; - } - - if (s->threads_number > 1 && s->sh.num_entry_point_offsets > 0) - ctb_addr_ts = hls_slice_data_wpp(s, nal); - else - ctb_addr_ts = hls_slice_data(s); - if (ctb_addr_ts >= (s->ps.sps->ctb_width * s->ps.sps->ctb_height)) { - ret = hevc_frame_end(s); - if (ret < 0) - goto fail; - s->is_decoded = 1; - } - - if (ctb_addr_ts < 0) { - ret = ctb_addr_ts; - goto fail; - } - } - break; - case HEVC_NAL_EOS_NUT: - case HEVC_NAL_EOB_NUT: - s->seq_decode = (s->seq_decode + 1) & HEVC_SEQUENCE_COUNTER_MASK; - s->max_ra = INT_MAX; - break; - case HEVC_NAL_AUD: - case HEVC_NAL_FD_NUT: - case HEVC_NAL_UNSPEC62: - break; - default: - av_log(s->avctx, AV_LOG_INFO, - "Skipping NAL unit %d\n", s->nal_unit_type); - } - - return 0; -fail: - if (s->avctx->err_recognition & AV_EF_EXPLODE) - return ret; - return 0; -} - -static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) -{ - int i, ret = 0; - int eos_at_start = 1; - - s->ref = s->collocated_ref = NULL; - s->last_eos = s->eos; - s->eos = 0; - s->overlap = 0; - - /* split the input packet into NAL units, so we know the upper bound on the - * number of slices in the frame */ - ret = ff_h2645_packet_split(&s->pkt, buf, length, s->avctx, s->is_nalff, - s->nal_length_size, s->avctx->codec_id, 1, 0); - if (ret < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "Error splitting the input into NAL units.\n"); - return ret; - } - - for (i = 0; i < s->pkt.nb_nals; i++) { - if (s->pkt.nals[i].type == HEVC_NAL_EOB_NUT || - s->pkt.nals[i].type == HEVC_NAL_EOS_NUT) { - if (eos_at_start) { - s->last_eos = 1; - } else { - s->eos = 1; - } - } else { - eos_at_start = 0; - } - } - - /* - * Check for RPU delimiter. - * - * Dolby Vision RPUs masquerade as unregistered NALs of type 62. - * - * We have to do this check here an create the rpu buffer, since RPUs are appended - * to the end of an AU; they are the last non-EOB/EOS NAL in the AU. - */ - if (s->pkt.nb_nals > 1 && s->pkt.nals[s->pkt.nb_nals - 1].type == HEVC_NAL_UNSPEC62 && - s->pkt.nals[s->pkt.nb_nals - 1].size > 2 && !s->pkt.nals[s->pkt.nb_nals - 1].nuh_layer_id - && !s->pkt.nals[s->pkt.nb_nals - 1].temporal_id) { - H2645NAL *nal = &s->pkt.nals[s->pkt.nb_nals - 1]; - if (s->rpu_buf) { - av_buffer_unref(&s->rpu_buf); - av_log(s->avctx, AV_LOG_WARNING, "Multiple Dolby Vision RPUs found in one AU. Skipping previous.\n"); - } - - s->rpu_buf = av_buffer_alloc(nal->raw_size - 2); - if (!s->rpu_buf) - return AVERROR(ENOMEM); - 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); - if (ret < 0) { - av_buffer_unref(&s->rpu_buf); - av_log(s->avctx, AV_LOG_WARNING, "Error parsing DOVI NAL unit.\n"); - /* ignore */ - } - } - - /* decode the NAL units */ - for (i = 0; i < s->pkt.nb_nals; i++) { - H2645NAL *nal = &s->pkt.nals[i]; - - if (s->avctx->skip_frame >= AVDISCARD_ALL || - (s->avctx->skip_frame >= AVDISCARD_NONREF - && ff_hevc_nal_is_nonref(nal->type)) || nal->nuh_layer_id > 0) - continue; - - ret = decode_nal_unit(s, nal); - if (ret >= 0 && s->overlap > 2) - ret = AVERROR_INVALIDDATA; - if (ret < 0) { - av_log(s->avctx, AV_LOG_WARNING, - "Error parsing NAL unit #%d.\n", i); - goto fail; - } - } - -fail: - if (s->ref && s->threads_type == FF_THREAD_FRAME) - ff_thread_report_progress(&s->ref->tf, INT_MAX, 0); - + if (l->cur_frame) + 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; } @@ -3313,6 +3400,308 @@ static int verify_md5(HEVCContext *s, AVFrame *frame) s->poc, msg_buf); return err; + } + +static int hevc_frame_end(HEVCContext *s, HEVCLayerContext *l) +{ + HEVCFrame *out = l->cur_frame; + const AVFilmGrainParams *fgp; + av_unused int ret; + + if (out->needs_fg) { + av_assert0(out->frame_grain->buf[0]); + fgp = av_film_grain_params_select(out->f); + 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(out->frame_grain, out->f, + &s->h274db, fgp); + break; + case AV_FILM_GRAIN_PARAMS_AV1: + ret = ff_aom_apply_film_grain(out->frame_grain, out->f, fgp); + break; + } + av_assert1(ret >= 0); + } + + if (s->avctx->hwaccel) { + ret = FF_HW_SIMPLE_CALL(s->avctx, end_frame); + if (ret < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "hardware accelerator failed to decode picture\n"); + return ret; + } + } else { + if (s->avctx->err_recognition & AV_EF_CRCCHECK && + s->sei.picture_hash.is_md5) { + ret = verify_md5(s, out->f); + if (ret < 0 && s->avctx->err_recognition & AV_EF_EXPLODE) + return ret; + } + } + s->sei.picture_hash.is_md5 = 0; + + av_log(s->avctx, AV_LOG_DEBUG, "Decoded frame with POC %zu/%d.\n", + l - s->layers, s->poc); + + return 0; +} + +static int decode_slice(HEVCContext *s, unsigned nal_idx, GetBitContext *gb) +{ + const int layer_idx = s->vps ? s->vps->layer_idx[s->nuh_layer_id] : 0; + HEVCLayerContext *l; + int ret; + + // skip layers not requested to be decoded + // layers_active_decode can only change while decoding a base-layer frame, + // so we can check it for non-base layers + if (layer_idx < 0 || + (s->nuh_layer_id > 0 && !(s->layers_active_decode & (1 << layer_idx)))) + return 0; + + ret = hls_slice_header(&s->sh, s, gb); + 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; + } + + if ((s->avctx->skip_frame >= AVDISCARD_BIDIR && s->sh.slice_type == HEVC_SLICE_B) || + (s->avctx->skip_frame >= AVDISCARD_NONINTRA && s->sh.slice_type != HEVC_SLICE_I) || + (s->avctx->skip_frame >= AVDISCARD_NONKEY && !IS_IRAP(s)) || + ((s->nal_unit_type == HEVC_NAL_RASL_R || s->nal_unit_type == HEVC_NAL_RASL_N) && + s->no_rasl_output_flag)) { + return 0; + } + + // switching to a new layer, mark previous layer's frame (if any) as done + if (s->cur_layer != layer_idx && + s->layers[s->cur_layer].cur_frame && + s->avctx->active_thread_type == FF_THREAD_FRAME) + ff_progress_frame_report(&s->layers[s->cur_layer].cur_frame->tf, INT_MAX); + + s->cur_layer = layer_idx; + l = &s->layers[s->cur_layer]; + + if (s->sh.first_slice_in_pic_flag) { + if (l->cur_frame) { + av_log(s->avctx, AV_LOG_ERROR, "Two slices reporting being the first in the same frame.\n"); + return AVERROR_INVALIDDATA; + } + + ret = hevc_frame_start(s, l, nal_idx); + if (ret < 0) + return ret; + } else if (!l->cur_frame) { + av_log(s->avctx, AV_LOG_ERROR, "First slice in a frame missing.\n"); + return AVERROR_INVALIDDATA; + } + + if (s->nal_unit_type != s->first_nal_type) { + av_log(s->avctx, AV_LOG_ERROR, + "Non-matching NAL types of the VCL NALUs: %d %d\n", + s->first_nal_type, s->nal_unit_type); + return AVERROR_INVALIDDATA; + } + + ret = decode_slice_data(s, l, &s->pkt.nals[nal_idx], gb); + if (ret < 0) + return ret; + + return 0; +} + +static int decode_nal_unit(HEVCContext *s, unsigned nal_idx) +{ + H2645NAL *nal = &s->pkt.nals[nal_idx]; + GetBitContext gb = nal->gb; + int ret; + + s->nal_unit_type = nal->type; + s->nuh_layer_id = nal->nuh_layer_id; + s->temporal_id = nal->temporal_id; + + if (FF_HW_HAS_CB(s->avctx, decode_params) && + (s->nal_unit_type == HEVC_NAL_VPS || + s->nal_unit_type == HEVC_NAL_SPS || + s->nal_unit_type == HEVC_NAL_PPS || + s->nal_unit_type == HEVC_NAL_SEI_PREFIX || + s->nal_unit_type == HEVC_NAL_SEI_SUFFIX)) { + ret = FF_HW_CALL(s->avctx, decode_params, + nal->type, nal->raw_data, nal->raw_size); + if (ret < 0) + goto fail; + } + + switch (s->nal_unit_type) { + case HEVC_NAL_VPS: + ret = ff_hevc_decode_nal_vps(&gb, s->avctx, &s->ps); + if (ret < 0) + goto fail; + break; + case HEVC_NAL_SPS: + ret = ff_hevc_decode_nal_sps(&gb, s->avctx, &s->ps, + nal->nuh_layer_id, s->apply_defdispwin); + if (ret < 0) + goto fail; + break; + case HEVC_NAL_PPS: + ret = ff_hevc_decode_nal_pps(&gb, s->avctx, &s->ps); + if (ret < 0) + goto fail; + break; + case HEVC_NAL_SEI_PREFIX: + case HEVC_NAL_SEI_SUFFIX: + ret = ff_hevc_decode_nal_sei(&gb, s->avctx, &s->sei, &s->ps, s->nal_unit_type); + if (ret < 0) + goto fail; + 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_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: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + ret = decode_slice(s, nal_idx, &gb); + if (ret < 0) + goto fail; + break; + case HEVC_NAL_EOS_NUT: + case HEVC_NAL_EOB_NUT: + case HEVC_NAL_AUD: + case HEVC_NAL_FD_NUT: + case HEVC_NAL_UNSPEC62: + break; + default: + av_log(s->avctx, AV_LOG_INFO, + "Skipping NAL unit %d\n", s->nal_unit_type); + } + + return 0; +fail: + if (ret == AVERROR_INVALIDDATA && + !(s->avctx->err_recognition & AV_EF_EXPLODE)) { + av_log(s->avctx, AV_LOG_WARNING, + "Skipping invalid undecodable NALU: %d\n", s->nal_unit_type); + return 0; + } + return ret; +} + +static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) +{ + int i, ret = 0; + int eos_at_start = 1; + int flags = (H2645_FLAG_IS_NALFF * !!s->is_nalff) | H2645_FLAG_SMALL_PADDING; + + s->cur_frame = s->collocated_ref = NULL; + s->last_eos = s->eos; + s->eos = 0; + s->slice_initialized = 0; + + for (int i = 0; i < FF_ARRAY_ELEMS(s->layers); i++) { + HEVCLayerContext *l = &s->layers[i]; + l->cur_frame = NULL; + } + + /* split the input packet into NAL units, so we know the upper bound on the + * number of slices in the frame */ + ret = ff_h2645_packet_split(&s->pkt, buf, length, s->avctx, + s->nal_length_size, s->avctx->codec_id, flags); + if (ret < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "Error splitting the input into NAL units.\n"); + return ret; + } + + for (i = 0; i < s->pkt.nb_nals; i++) { + if (s->pkt.nals[i].type == HEVC_NAL_EOB_NUT || + s->pkt.nals[i].type == HEVC_NAL_EOS_NUT) { + if (eos_at_start) { + s->last_eos = 1; + } else { + s->eos = 1; + } + } else { + eos_at_start = 0; + } + } + + /* + * Check for RPU delimiter. + * + * Dolby Vision RPUs masquerade as unregistered NALs of type 62. + * + * We have to do this check here an create the rpu buffer, since RPUs are appended + * to the end of an AU; they are the last non-EOB/EOS NAL in the AU. + */ + if (s->pkt.nb_nals > 1 && s->pkt.nals[s->pkt.nb_nals - 1].type == HEVC_NAL_UNSPEC62 && + s->pkt.nals[s->pkt.nb_nals - 1].size > 2 && !s->pkt.nals[s->pkt.nb_nals - 1].nuh_layer_id + && !s->pkt.nals[s->pkt.nb_nals - 1].temporal_id) { + H2645NAL *nal = &s->pkt.nals[s->pkt.nb_nals - 1]; + if (s->rpu_buf) { + av_buffer_unref(&s->rpu_buf); + av_log(s->avctx, AV_LOG_WARNING, "Multiple Dolby Vision RPUs found in one AU. Skipping previous.\n"); + } + + s->rpu_buf = av_buffer_alloc(nal->raw_size - 2); + if (!s->rpu_buf) + return AVERROR(ENOMEM); + 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, + s->avctx->err_recognition); + if (ret < 0) { + av_buffer_unref(&s->rpu_buf); + av_log(s->avctx, AV_LOG_WARNING, "Error parsing DOVI NAL unit.\n"); + /* ignore */ + } + } + + /* decode the NAL units */ + for (i = 0; i < s->pkt.nb_nals; i++) { + H2645NAL *nal = &s->pkt.nals[i]; + + if (s->avctx->skip_frame >= AVDISCARD_ALL || + (s->avctx->skip_frame >= AVDISCARD_NONREF && ff_hevc_nal_is_nonref(nal->type))) + continue; + + ret = decode_nal_unit(s, i); + if (ret < 0) { + av_log(s->avctx, AV_LOG_WARNING, + "Error parsing NAL unit #%d.\n", i); + goto fail; + } + } + +fail: + for (int i = 0; i < FF_ARRAY_ELEMS(s->layers); i++) { + HEVCLayerContext *l = &s->layers[i]; + + if (!l->cur_frame) + continue; + + if (ret >= 0) + ret = hevc_frame_end(s, l); + + if (s->avctx->active_thread_type == FF_THREAD_FRAME) + ff_progress_frame_report(&l->cur_frame->tf, INT_MAX); + } + + return ret; } static int hevc_decode_extradata(HEVCContext *s, uint8_t *buf, int length, int first) @@ -3330,6 +3719,11 @@ static int hevc_decode_extradata(HEVCContext *s, uint8_t *buf, int length, int f if (first && s->ps.sps_list[i]) { const HEVCSPS *sps = s->ps.sps_list[i]; export_stream_params(s, sps); + + ret = export_multilayer(s, sps->vps); + if (ret < 0) + return ret; + break; } } @@ -3342,22 +3736,33 @@ static int hevc_decode_extradata(HEVCContext *s, uint8_t *buf, int length, int f return 0; } -static int hevc_decode_frame(AVCodecContext *avctx, AVFrame *rframe, - int *got_output, AVPacket *avpkt) +static int hevc_receive_frame(AVCodecContext *avctx, AVFrame *frame) { + HEVCContext *s = avctx->priv_data; + AVCodecInternal *avci = avctx->internal; + AVPacket *avpkt = avci->in_pkt; + int ret; uint8_t *sd; size_t sd_size; - HEVCContext *s = avctx->priv_data; - if (!avpkt->size) { - ret = ff_hevc_output_frame(s, rframe, 1); + s->pkt_dts = AV_NOPTS_VALUE; + + if (ff_container_fifo_can_read(s->output_fifo)) + goto do_output; + + av_packet_unref(avpkt); + ret = ff_decode_get_packet(avctx, avpkt); + if (ret == AVERROR_EOF) { + ret = ff_hevc_output_frames(s, s->layers_active_decode, + s->layers_active_output, 0, 0, 0); if (ret < 0) return ret; + goto do_output; + } else if (ret < 0) + return ret; - *got_output = ret; - return 0; - } + s->pkt_dts = avpkt->dts; sd = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &sd_size); if (sd && sd_size > 0) { @@ -3367,69 +3772,46 @@ static int hevc_decode_frame(AVCodecContext *avctx, AVFrame *rframe, } sd = av_packet_get_side_data(avpkt, AV_PKT_DATA_DOVI_CONF, &sd_size); - if (sd && sd_size > 0) { - int old = s->dovi_ctx.dv_profile; - - ff_dovi_update_cfg(&s->dovi_ctx, (AVDOVIDecoderConfigurationRecord *) sd); + if (sd && sd_size >= sizeof(s->dovi_ctx.cfg)) { + int old = s->dovi_ctx.cfg.dv_profile; + s->dovi_ctx.cfg = *(AVDOVIDecoderConfigurationRecord *) sd; if (old) av_log(avctx, AV_LOG_DEBUG, "New DOVI configuration record from input packet (profile %d -> %u).\n", - old, s->dovi_ctx.dv_profile); + old, s->dovi_ctx.cfg.dv_profile); } - s->ref = s->collocated_ref = NULL; ret = decode_nal_units(s, avpkt->data, avpkt->size); if (ret < 0) return ret; - if (avctx->hwaccel) { - if (s->ref && (ret = FF_HW_SIMPLE_CALL(avctx, end_frame)) < 0) { - av_log(avctx, AV_LOG_ERROR, - "hardware accelerator failed to decode picture\n"); - ff_hevc_unref_frame(s->ref, ~0); - return ret; - } - } else { - /* verify the SEI checksum */ - if (avctx->err_recognition & AV_EF_CRCCHECK && s->ref && s->is_decoded && - s->sei.picture_hash.is_md5) { - ret = verify_md5(s, s->ref->frame); - if (ret < 0 && avctx->err_recognition & AV_EF_EXPLODE) { - ff_hevc_unref_frame(s->ref, ~0); - return ret; - } - } - } - s->sei.picture_hash.is_md5 = 0; +do_output: + if (ff_container_fifo_read(s->output_fifo, frame) >= 0) { + if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) + av_frame_remove_side_data(frame, AV_FRAME_DATA_FILM_GRAIN_PARAMS); - if (s->is_decoded) { - av_log(avctx, AV_LOG_DEBUG, "Decoded frame with POC %d.\n", s->poc); - s->is_decoded = 0; + return 0; } - if (s->output_frame->buf[0]) { - av_frame_move_ref(rframe, s->output_frame); - *got_output = 1; - } - - return avpkt->size; + return avci->draining ? AVERROR_EOF : AVERROR(EAGAIN); } -static int hevc_ref_frame(HEVCFrame *dst, HEVCFrame *src) +static int hevc_ref_frame(HEVCFrame *dst, const HEVCFrame *src) { int ret; - ret = ff_thread_ref_frame(&dst->tf, &src->tf); - if (ret < 0) - return ret; + ff_progress_frame_ref(&dst->tf, &src->tf); if (src->needs_fg) { ret = av_frame_ref(dst->frame_grain, src->frame_grain); - if (ret < 0) + if (ret < 0) { + ff_hevc_unref_frame(dst, ~0); return ret; + } 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); @@ -3438,7 +3820,8 @@ static int hevc_ref_frame(HEVCFrame *dst, HEVCFrame *src) dst->poc = src->poc; dst->ctb_count = src->ctb_count; dst->flags = src->flags; - dst->sequence = src->sequence; + + dst->base_layer_frame = src->base_layer_frame; ff_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); @@ -3449,40 +3832,41 @@ static int hevc_ref_frame(HEVCFrame *dst, HEVCFrame *src) static av_cold int hevc_decode_free(AVCodecContext *avctx) { HEVCContext *s = avctx->priv_data; - int i; - pic_arrays_free(s); + for (int i = 0; i < FF_ARRAY_ELEMS(s->layers); i++) { + pic_arrays_free(&s->layers[i]); + ff_refstruct_unref(&s->layers[i].sps); + } + + ff_refstruct_unref(&s->vps); + ff_refstruct_unref(&s->pps); ff_dovi_ctx_unref(&s->dovi_ctx); av_buffer_unref(&s->rpu_buf); av_freep(&s->md5_ctx); - for (i = 0; i < 3; i++) { - av_freep(&s->sao_pixel_buffer_h[i]); - av_freep(&s->sao_pixel_buffer_v[i]); - } - av_frame_free(&s->output_frame); + ff_container_fifo_free(&s->output_fifo); - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - ff_hevc_unref_frame(&s->DPB[i], ~0); - av_frame_free(&s->DPB[i].frame); - av_frame_free(&s->DPB[i].frame_grain); + for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) { + HEVCLayerContext *l = &s->layers[layer]; + for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + ff_hevc_unref_frame(&l->DPB[i], ~0); + av_frame_free(&l->DPB[i].frame_grain); + } } ff_hevc_ps_uninit(&s->ps); + for (int i = 0; i < s->nb_wpp_progress; i++) + ff_thread_progress_destroy(&s->wpp_progress[i]); + av_freep(&s->wpp_progress); + av_freep(&s->sh.entry_point_offset); av_freep(&s->sh.offset); av_freep(&s->sh.size); - if (s->HEVClcList) { - for (i = 1; i < s->threads_number; i++) { - av_freep(&s->HEVClcList[i]); - } - } - av_freep(&s->HEVClc); - av_freep(&s->HEVClcList); + av_freep(&s->local_ctx); ff_h2645_packet_uninit(&s->pkt); @@ -3494,36 +3878,31 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) static av_cold int hevc_init_context(AVCodecContext *avctx) { HEVCContext *s = avctx->priv_data; - int i; s->avctx = avctx; - s->HEVClc = av_mallocz(sizeof(HEVCLocalContext)); - s->HEVClcList = av_mallocz(sizeof(HEVCLocalContext*) * s->threads_number); - if (!s->HEVClc || !s->HEVClcList) + s->local_ctx = av_mallocz(sizeof(*s->local_ctx)); + if (!s->local_ctx) return AVERROR(ENOMEM); - s->HEVClc->parent = s; - s->HEVClc->logctx = avctx; - s->HEVClc->common_cabac_state = &s->cabac; - s->HEVClcList[0] = s->HEVClc; + s->nb_local_ctx = 1; - s->output_frame = av_frame_alloc(); - if (!s->output_frame) + s->local_ctx[0].parent = s; + s->local_ctx[0].logctx = avctx; + s->local_ctx[0].common_cabac_state = &s->cabac; + + s->output_fifo = ff_container_fifo_alloc_avframe(0); + if (!s->output_fifo) return AVERROR(ENOMEM); - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - s->DPB[i].frame = av_frame_alloc(); - if (!s->DPB[i].frame) - return AVERROR(ENOMEM); - s->DPB[i].tf.f = s->DPB[i].frame; - - s->DPB[i].frame_grain = av_frame_alloc(); - if (!s->DPB[i].frame_grain) - return AVERROR(ENOMEM); + for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) { + HEVCLayerContext *l = &s->layers[layer]; + for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + l->DPB[i].frame_grain = av_frame_alloc(); + if (!l->DPB[i].frame_grain) + return AVERROR(ENOMEM); + } } - s->max_ra = INT_MAX; - s->md5_ctx = av_md5_alloc(); if (!s->md5_ctx) return AVERROR(ENOMEM); @@ -3544,19 +3923,27 @@ static int hevc_update_thread_context(AVCodecContext *dst, { HEVCContext *s = dst->priv_data; HEVCContext *s0 = src->priv_data; - int i, ret; + int ret; - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - ff_hevc_unref_frame(&s->DPB[i], ~0); - if (s0->DPB[i].frame->buf[0]) { - ret = hevc_ref_frame(&s->DPB[i], &s0->DPB[i]); + for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) { + HEVCLayerContext *l = &s->layers[layer]; + const HEVCLayerContext *l0 = &s0->layers[layer]; + for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + ff_hevc_unref_frame(&l->DPB[i], ~0); + if (l0->DPB[i].f) { + ret = hevc_ref_frame(&l->DPB[i], &l0->DPB[i]); + if (ret < 0) + return ret; + } + } + + if (l->sps != l0->sps) { + ret = set_sps(s, l, l0->sps); if (ret < 0) return ret; } } - if (s->ps.sps != s0->ps.sps) - s->ps.sps = NULL; 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]); @@ -3566,28 +3953,31 @@ static int hevc_update_thread_context(AVCodecContext *dst, 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]); - if (s->ps.sps != s0->ps.sps) - if ((ret = set_sps(s, s0->ps.sps, src->pix_fmt)) < 0) - return ret; + // PPS do not persist between frames + ff_refstruct_unref(&s->pps); - s->seq_decode = s0->seq_decode; - s->seq_output = s0->seq_output; - s->pocTid0 = s0->pocTid0; - s->max_ra = s0->max_ra; + s->poc_tid0 = s0->poc_tid0; s->eos = s0->eos; s->no_rasl_output_flag = s0->no_rasl_output_flag; s->is_nalff = s0->is_nalff; s->nal_length_size = s0->nal_length_size; - - s->threads_number = s0->threads_number; - s->threads_type = s0->threads_type; + s->layers_active_decode = s0->layers_active_decode; + s->layers_active_output = s0->layers_active_output; s->film_grain_warning_shown = s0->film_grain_warning_shown; - if (s0->eos) { - s->seq_decode = (s->seq_decode + 1) & HEVC_SEQUENCE_COUNTER_MASK; - s->max_ra = INT_MAX; + if (s->nb_view_ids != s0->nb_view_ids || + memcmp(s->view_ids, s0->view_ids, sizeof(*s->view_ids) * s->nb_view_ids)) { + av_freep(&s->view_ids); + s->nb_view_ids = 0; + + if (s0->nb_view_ids) { + s->view_ids = av_memdup(s0->view_ids, s0->nb_view_ids * sizeof(*s0->view_ids)); + if (!s->view_ids) + return AVERROR(ENOMEM); + s->nb_view_ids = s0->nb_view_ids; + } } ret = ff_h2645_sei_ctx_replace(&s->sei.common, &s0->sei.common); @@ -3615,11 +4005,7 @@ static int hevc_update_thread_context(AVCodecContext *dst, 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.common.aom_film_grain = s0->sei.common.aom_film_grain; - - ret = export_stream_params_from_sei(s); - if (ret < 0) - return ret; + s->sei.tdrdi = s0->sei.tdrdi; return 0; } @@ -3630,24 +4016,10 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx) HEVCContext *s = avctx->priv_data; int ret; - if (avctx->active_thread_type & FF_THREAD_SLICE) { - s->threads_number = avctx->thread_count; - ret = ff_slice_thread_init_progress(avctx); - if (ret < 0) - return ret; - } else - s->threads_number = 1; - - if((avctx->active_thread_type & FF_THREAD_FRAME) && avctx->thread_count > 1) - s->threads_type = FF_THREAD_FRAME; - else - s->threads_type = FF_THREAD_SLICE; - ret = hevc_init_context(avctx); if (ret < 0) return ret; - s->enable_parallel_tiles = 0; s->sei.picture_timing.picture_struct = 0; s->eos = 1; @@ -3661,11 +4033,15 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx) if (ret < 0) { return ret; } + + ret = ff_h2645_sei_to_context(avctx, &s->sei.common); + if (ret < 0) + return ret; } sd = ff_get_coded_side_data(avctx, AV_PKT_DATA_DOVI_CONF); - if (sd && sd->size > 0) - ff_dovi_update_cfg(&s->dovi_ctx, (AVDOVIDecoderConfigurationRecord *) sd->data); + if (sd && sd->size >= sizeof(s->dovi_ctx.cfg)) + s->dovi_ctx.cfg = *(AVDOVIDecoderConfigurationRecord *) sd->data; } return 0; @@ -3678,7 +4054,6 @@ static void hevc_decode_flush(AVCodecContext *avctx) ff_hevc_reset_sei(&s->sei); ff_dovi_ctx_flush(&s->dovi_ctx); av_buffer_unref(&s->rpu_buf); - s->max_ra = INT_MAX; s->eos = 1; if (FF_HW_HAS_CB(avctx, flush)) @@ -3693,6 +4068,19 @@ static const AVOption options[] = { AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, PAR }, { "strict-displaywin", "stricly 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, + .min = -1, .max = INT_MAX, .flags = PAR }, + { "view_ids_available", "Array of available view IDs is exported here", + .offset = OFFSET(view_ids_available), .type = AV_OPT_TYPE_UINT | AV_OPT_TYPE_FLAG_ARRAY, + .flags = PAR | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, + { "view_pos_available", "Array of view positions for view_ids_available is exported here, as AVStereo3DView", + .offset = OFFSET(view_pos_available), .type = AV_OPT_TYPE_UINT | AV_OPT_TYPE_FLAG_ARRAY, + .flags = PAR | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY, .unit = "view_pos" }, + { "unspecified", .type = AV_OPT_TYPE_CONST, .default_val = { .i64 = AV_STEREO3D_VIEW_UNSPEC }, .unit = "view_pos" }, + { "left", .type = AV_OPT_TYPE_CONST, .default_val = { .i64 = AV_STEREO3D_VIEW_LEFT }, .unit = "view_pos" }, + { "right", .type = AV_OPT_TYPE_CONST, .default_val = { .i64 = AV_STEREO3D_VIEW_RIGHT }, .unit = "view_pos" }, + { NULL }, }; @@ -3712,13 +4100,14 @@ const FFCodec ff_hevc_decoder = { .p.priv_class = &hevc_decoder_class, .init = hevc_decode_init, .close = hevc_decode_free, - FF_CODEC_DECODE_CB(hevc_decode_frame), + FF_CODEC_RECEIVE_FRAME_CB(hevc_receive_frame), .flush = hevc_decode_flush, UPDATE_THREAD_CONTEXT(hevc_update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, .caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING | - FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP, + FF_CODEC_CAP_USES_PROGRESSFRAMES | + FF_CODEC_CAP_INIT_CLEANUP, .p.profiles = NULL_IF_CONFIG_SMALL(ff_hevc_profiles), .hw_configs = (const AVCodecHWConfigInternal *const []) { #if CONFIG_HEVC_DXVA2_HWACCEL diff --git a/libavcodec/hevcdec.h b/libavcodec/hevc/hevcdec.h similarity index 71% rename from libavcodec/hevcdec.h rename to libavcodec/hevc/hevcdec.h index e65a6180c..473709b4e 100644 --- a/libavcodec/hevcdec.h +++ b/libavcodec/hevc/hevcdec.h @@ -20,28 +20,29 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_HEVCDEC_H -#define AVCODEC_HEVCDEC_H +#ifndef AVCODEC_HEVC_HEVCDEC_H +#define AVCODEC_HEVC_HEVCDEC_H #include #include "libavutil/buffer.h" #include "libavutil/mem_internal.h" -#include "avcodec.h" -#include "bswapdsp.h" -#include "cabac.h" -#include "dovi_rpu.h" -#include "get_bits.h" -#include "hevcpred.h" -#include "h2645_parse.h" +#include "libavcodec/avcodec.h" +#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" + +#include "dsp.h" #include "hevc.h" -#include "hevc_ps.h" -#include "hevc_sei.h" -#include "hevcdsp.h" -#include "h274.h" -#include "threadframe.h" -#include "videodsp.h" +#include "pred.h" +#include "ps.h" +#include "sei.h" #define SHIFT_CTB_WPP 2 @@ -83,6 +84,8 @@ enum RPSType { ST_FOLL, LT_CURR, LT_FOLL, + INTER_LAYER0, + INTER_LAYER1, NB_RPS_TYPE, }; @@ -208,11 +211,13 @@ typedef struct SliceHeader { enum HEVCSliceType slice_type; int pic_order_cnt_lsb; + int poc; uint8_t first_slice_in_pic_flag; uint8_t dependent_slice_segment_flag; uint8_t pic_output_flag; uint8_t colour_plane_id; + uint8_t inter_layer_pred; ///< RPS coded in the slice header itself is stored here int short_term_ref_pic_set_sps_flag; @@ -277,6 +282,7 @@ typedef struct SliceHeader { int16_t chroma_offset_l1[16][2]; int slice_ctb_addr_rs; + unsigned data_offset; } SliceHeader; typedef struct CodingUnit { @@ -346,15 +352,16 @@ typedef struct DBParams { #define HEVC_FRAME_FLAG_OUTPUT (1 << 0) #define HEVC_FRAME_FLAG_SHORT_REF (1 << 1) #define HEVC_FRAME_FLAG_LONG_REF (1 << 2) -#define HEVC_FRAME_FLAG_BUMPING (1 << 3) - -#define HEVC_SEQUENCE_COUNTER_MASK 0xff -#define HEVC_SEQUENCE_COUNTER_INVALID (HEVC_SEQUENCE_COUNTER_MASK + 1) +#define HEVC_FRAME_FLAG_UNAVAILABLE (1 << 3) typedef struct HEVCFrame { - AVFrame *frame; + union { + struct { + AVFrame *f; + }; + ProgressFrame tf; + }; AVFrame *frame_grain; - ThreadFrame tf; int needs_fg; /* 1 if grain needs to be applied by the decoder */ MvField *tab_mvf; ///< RefStruct reference RefPicList *refPicList; @@ -362,16 +369,15 @@ typedef struct HEVCFrame { int ctb_count; int poc; + const HEVCPPS *pps; ///< RefStruct reference RefPicListTab *rpl; ///< RefStruct reference int nb_rpl_elems; void *hwaccel_picture_private; ///< RefStruct reference - /** - * A sequence counter, so that old frames are output first - * after a POC reset - */ - uint16_t sequence; + // for secondary-layer frames, this is the DPB index of the base-layer frame + // from the same AU, if it exists, otherwise -1 + int base_layer_frame; /** * A combination of HEVC_FRAME_FLAG_* @@ -389,7 +395,6 @@ typedef struct HEVCLocalContext { void *logctx; const struct HEVCContext *parent; - GetBitContext gb; CABACContext cc; /** @@ -435,58 +440,91 @@ typedef struct HEVCLocalContext { /* properties of the boundary of the current CTB for the purposes * of the deblocking filter */ int boundary_flags; + + // an array of these structs is used for per-thread state - pad its size + // to avoid false sharing + char padding[128]; } HEVCLocalContext; +typedef struct HEVCLayerContext { + HEVCFrame DPB[32]; + HEVCFrame *cur_frame; + + const HEVCSPS *sps; // RefStruct reference + + int bs_width; + int bs_height; + + SAOParams *sao; + DBParams *deblock; + + // CU + uint8_t *skip_flag; + uint8_t *tab_ct_depth; + + // PU + uint8_t *cbf_luma; // cbf_luma of colocated TU + uint8_t *tab_ipm; + uint8_t *is_pcm; + + // CTB-level flags affecting loop filter operation + uint8_t *filter_slice_edges; + + int32_t *tab_slice_address; + + int8_t *qp_y_tab; + + uint8_t *horizontal_bs; + uint8_t *vertical_bs; + + uint8_t *sao_pixel_buffer_h[3]; + uint8_t *sao_pixel_buffer_v[3]; + + struct FFRefStructPool *tab_mvf_pool; + struct FFRefStructPool *rpl_tab_pool; +} HEVCLayerContext; + typedef struct HEVCContext { const AVClass *c; // needed by private avoptions AVCodecContext *avctx; - HEVCLocalContext **HEVClcList; - HEVCLocalContext *HEVClc; + HEVCLocalContext *local_ctx; + unsigned nb_local_ctx; - uint8_t threads_type; - uint8_t threads_number; - - int width; - int height; + // per-layer decoding state, addressed by VPS layer indices + HEVCLayerContext layers[HEVC_VPS_MAX_LAYERS]; + // VPS index of the layer currently being decoded + unsigned cur_layer; + // bitmask of layer indices that are active for decoding/output + unsigned layers_active_decode; + unsigned layers_active_output; /** 1 if the independent slice segment header was successfully parsed */ uint8_t slice_initialized; - AVFrame *frame; - AVFrame *output_frame; - uint8_t *sao_pixel_buffer_h[3]; - uint8_t *sao_pixel_buffer_v[3]; + struct ContainerFifo *output_fifo; HEVCParamSets ps; HEVCSEI sei; struct AVMD5 *md5_ctx; - struct FFRefStructPool *tab_mvf_pool; - struct FFRefStructPool *rpl_tab_pool; - ///< candidate references for the current frame - RefPicList rps[5]; + RefPicList rps[NB_RPS_TYPE]; + const HEVCVPS *vps; ///< RefStruct reference + const HEVCPPS *pps; ///< RefStruct reference SliceHeader sh; - SAOParams *sao; - DBParams *deblock; enum HEVCNALUnitType nal_unit_type; int temporal_id; ///< temporal_id_plus1 - 1 - HEVCFrame *ref; + HEVCFrame *cur_frame; HEVCFrame *collocated_ref; - HEVCFrame DPB[32]; int poc; - int pocTid0; + int poc_tid0; int slice_idx; ///< number of the slice being currently decoded int eos; ///< current packet contains an EOS/EOB NAL int last_eos; ///< last packet contains an EOS/EOB NAL - int max_ra; - int bs_width; - int bs_height; - int overlap; - int is_decoded; + // NoRaslOutputFlag associated with the last IRAP frame int no_rasl_output_flag; HEVCPredContext hpc; @@ -494,39 +532,17 @@ typedef struct HEVCContext { VideoDSPContext vdsp; BswapDSPContext bdsp; H274FilmGrainDatabase h274db; - int8_t *qp_y_tab; - uint8_t *horizontal_bs; - uint8_t *vertical_bs; - - int32_t *tab_slice_address; - - // CU - uint8_t *skip_flag; - uint8_t *tab_ct_depth; - // PU - uint8_t *tab_ipm; - - uint8_t *cbf_luma; // cbf_luma of colocated TU - uint8_t *is_pcm; - - // CTB-level flags affecting loop filter operation - uint8_t *filter_slice_edges; /** used on BE to byteswap the lines for checksumming */ uint8_t *checksum_buf; int checksum_buf_size; - /** - * Sequence counters for decoded and output frames, so that old - * frames are output first after a POC reset - */ - uint16_t seq_decode; - uint16_t seq_output; - /** The target for the common_cabac_state of the local contexts. */ HEVCCABACState cabac; - int enable_parallel_tiles; + struct ThreadProgress *wpp_progress; + unsigned nb_wpp_progress; + atomic_int wpp_err; const uint8_t *data; @@ -534,16 +550,32 @@ typedef struct HEVCContext { H2645Packet pkt; // type of the first VCL NAL of the current frame enum HEVCNALUnitType first_nal_type; + // index in pkt.nals of the NAL unit after which we can call + // ff_thread_finish_setup() + unsigned finish_setup_nal_idx; int is_nalff; ///< this flag is != 0 if bitstream is encapsulated ///< as a format defined in 14496-15 int apply_defdispwin; + // multi-layer AVOptions + int *view_ids; + unsigned nb_view_ids; + + unsigned *view_ids_available; + unsigned nb_view_ids_available; + + unsigned *view_pos_available; + unsigned nb_view_pos_available; + int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4) int nuh_layer_id; int film_grain_warning_shown; + // dts of the packet currently being decoded + int64_t pkt_dts; + AVBufferRef *rpu_buf; ///< 0 or 1 Dolby Vision RPUs. DOVIContext dovi_ctx; ///< Dolby Vision decoding context } HEVCContext; @@ -551,42 +583,45 @@ typedef struct HEVCContext { /** * Mark all frames in DPB as unused for reference. */ -void ff_hevc_clear_refs(HEVCContext *s); +void ff_hevc_clear_refs(HEVCLayerContext *l); /** * Drop all frames currently in DPB. */ void ff_hevc_flush_dpb(HEVCContext *s); -const RefPicList *ff_hevc_get_ref_list(const HEVCContext *s, const HEVCFrame *frame, - int x0, int y0); +const RefPicList *ff_hevc_get_ref_list(const HEVCFrame *frame, int x0, int y0); /** * Construct the reference picture sets for the current frame. */ -int ff_hevc_frame_rps(HEVCContext *s); +int ff_hevc_frame_rps(HEVCContext *s, HEVCLayerContext *l); /** * Construct the reference picture list(s) for the current slice. */ int ff_hevc_slice_rpl(HEVCContext *s); -void ff_hevc_save_states(HEVCLocalContext *lc, int ctb_addr_ts); -int ff_hevc_cabac_init(HEVCLocalContext *lc, int ctb_addr_ts); +void ff_hevc_save_states(HEVCLocalContext *lc, const HEVCPPS *pps, + int ctb_addr_ts); +int ff_hevc_cabac_init(HEVCLocalContext *lc, const HEVCPPS *pps, + int ctb_addr_ts, const uint8_t *data, size_t size, + int is_wpp); int ff_hevc_sao_merge_flag_decode(HEVCLocalContext *lc); int ff_hevc_sao_type_idx_decode(HEVCLocalContext *lc); int ff_hevc_sao_band_position_decode(HEVCLocalContext *lc); -int ff_hevc_sao_offset_abs_decode(HEVCLocalContext *lc); +int ff_hevc_sao_offset_abs_decode(HEVCLocalContext *lc, int bit_depth); int ff_hevc_sao_offset_sign_decode(HEVCLocalContext *lc); int ff_hevc_sao_eo_class_decode(HEVCLocalContext *lc); int ff_hevc_end_of_slice_flag_decode(HEVCLocalContext *lc); int ff_hevc_cu_transquant_bypass_flag_decode(HEVCLocalContext *lc); -int ff_hevc_skip_flag_decode(HEVCLocalContext *lc, int x0, int y0, - int x_cb, int y_cb); +int ff_hevc_skip_flag_decode(HEVCLocalContext *lc, uint8_t *skip_flag, + int x0, int y0, int x_cb, int y_cb, int min_cb_width); int ff_hevc_pred_mode_decode(HEVCLocalContext *lc); -int ff_hevc_split_coding_unit_flag_decode(HEVCLocalContext *lc, int ct_depth, - int x0, int y0); -int ff_hevc_part_mode_decode(HEVCLocalContext *lc, int log2_cb_size); +int ff_hevc_split_coding_unit_flag_decode(HEVCLocalContext *lc, uint8_t *tab_ct_depth, + const HEVCSPS *sps, + int ct_depth, int x0, int y0); +int ff_hevc_part_mode_decode(HEVCLocalContext *lc, const HEVCSPS *sps, int log2_cb_size); int ff_hevc_pcm_flag_decode(HEVCLocalContext *lc); int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCLocalContext *lc); int ff_hevc_mpm_idx_decode(HEVCLocalContext *lc); @@ -607,9 +642,10 @@ int ff_hevc_res_scale_sign_flag(HEVCLocalContext *lc, int idx); /** * Get the number of candidate references for the current frame. */ -int ff_hevc_frame_nb_refs(const HEVCContext *s); +int ff_hevc_frame_nb_refs(const SliceHeader *sh, const HEVCPPS *pps, + unsigned layer_idx); -int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc); +int ff_hevc_set_new_ref(HEVCContext *s, HEVCLayerContext *l, int poc); static av_always_inline int ff_hevc_nal_is_nonref(enum HEVCNALUnitType type) { @@ -629,35 +665,50 @@ static av_always_inline int ff_hevc_nal_is_nonref(enum HEVCNALUnitType type) } /** - * Find next frame in output order and put a reference to it in frame. - * @return 1 if a frame was output, 0 otherwise + * Find frames in the DPB that are ready for output and either write them to the + * output FIFO or drop their output flag, depending on the value of discard. + * + * @param max_output maximum number of AUs with an output-pending frame in at + * least one layer that can be present in the DPB before output + * is triggered + * @param max_dpb maximum number of any frames that can be present in the DPB + * for any layer before output is triggered */ -int ff_hevc_output_frame(HEVCContext *s, AVFrame *frame, int flush); - -void ff_hevc_bump_frame(HEVCContext *s); +int ff_hevc_output_frames(HEVCContext *s, + unsigned layers_active_decode, unsigned layers_active_output, + unsigned max_output, unsigned max_dpb, int discard); void ff_hevc_unref_frame(HEVCFrame *frame, int flags); void ff_hevc_set_neighbour_available(HEVCLocalContext *lc, int x0, int y0, - int nPbW, int nPbH); -void ff_hevc_luma_mv_merge_mode(HEVCLocalContext *lc, int x0, int y0, + int nPbW, int nPbH, int log2_ctb_size); +void ff_hevc_luma_mv_merge_mode(HEVCLocalContext *lc, const HEVCPPS *pps, + int x0, int y0, int nPbW, int nPbH, int log2_cb_size, int part_idx, int merge_idx, MvField *mv); -void ff_hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, int x0, int y0, +void ff_hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, const HEVCPPS *pps, + int x0, int y0, int nPbW, int nPbH, int log2_cb_size, int part_idx, int merge_idx, MvField *mv, int mvp_lx_flag, int LX); -void ff_hevc_hls_filter(HEVCLocalContext *lc, int x, int y, int ctb_size); -void ff_hevc_hls_filters(HEVCLocalContext *lc, int x_ctb, int y_ctb, int ctb_size); -void ff_hevc_set_qPy(HEVCLocalContext *lc, int xBase, int yBase, - int log2_cb_size); -void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, int x0, int y0, - int log2_trafo_size); +void ff_hevc_hls_filter(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCPPS *pps, + int x, int y, int ctb_size); +void ff_hevc_hls_filters(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCPPS *pps, + int x_ctb, int y_ctb, int ctb_size); +void ff_hevc_set_qPy(HEVCLocalContext *lc, + const HEVCLayerContext *l, const HEVCPPS *pps, + int xBase, int yBase, int log2_cb_size); +void ff_hevc_deblocking_boundary_strengths(HEVCLocalContext *lc, const HEVCLayerContext *l, + const HEVCPPS *pps, + int x0, int y0, int log2_trafo_size); int ff_hevc_cu_qp_delta_sign_flag(HEVCLocalContext *lc); int ff_hevc_cu_qp_delta_abs(HEVCLocalContext *lc); int ff_hevc_cu_chroma_qp_offset_flag(HEVCLocalContext *lc); -int ff_hevc_cu_chroma_qp_offset_idx(HEVCLocalContext *lc); -void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, int x0, int y0, +int ff_hevc_cu_chroma_qp_offset_idx(HEVCLocalContext *lc, int chroma_qp_offset_list_len_minus1); +void ff_hevc_hls_residual_coding(HEVCLocalContext *lc, const HEVCPPS *pps, + int x0, int y0, int log2_trafo_size, enum ScanType scan_idx, int c_idx); @@ -667,4 +718,4 @@ 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]; -#endif /* AVCODEC_HEVCDEC_H */ +#endif /* AVCODEC_HEVC_HEVCDEC_H */ diff --git a/libavcodec/hevc_mvs.c b/libavcodec/hevc/mvs.c similarity index 82% rename from libavcodec/hevc_mvs.c rename to libavcodec/hevc/mvs.c index 0a8cc2c43..55f115ad0 100644 --- a/libavcodec/hevc_mvs.c +++ b/libavcodec/hevc/mvs.c @@ -23,7 +23,7 @@ #include "hevc.h" #include "hevcdec.h" -#include "threadframe.h" +#include "progressframe.h" static const uint8_t l0_l1_cand_idx[12][2] = { { 0, 1, }, @@ -41,17 +41,16 @@ static const uint8_t l0_l1_cand_idx[12][2] = { }; void ff_hevc_set_neighbour_available(HEVCLocalContext *lc, int x0, int y0, - int nPbW, int nPbH) + int nPbW, int nPbH, int log2_ctb_size) { - const HEVCContext *const s = lc->parent; - int x0b = av_mod_uintp2(x0, s->ps.sps->log2_ctb_size); - int y0b = av_mod_uintp2(y0, s->ps.sps->log2_ctb_size); + int x0b = av_zero_extend(x0, log2_ctb_size); + int y0b = av_zero_extend(y0, log2_ctb_size); lc->na.cand_up = (lc->ctb_up_flag || y0b); lc->na.cand_left = (lc->ctb_left_flag || x0b); lc->na.cand_up_left = (x0b || y0b) ? lc->na.cand_left && lc->na.cand_up : lc->ctb_up_left_flag; lc->na.cand_up_right_sap = - (x0b + nPbW == 1 << s->ps.sps->log2_ctb_size) ? + (x0b + nPbW == 1 << log2_ctb_size) ? lc->ctb_up_right_flag && !y0b : lc->na.cand_up; lc->na.cand_up_right = lc->na.cand_up_right_sap @@ -62,31 +61,32 @@ void ff_hevc_set_neighbour_available(HEVCLocalContext *lc, int x0, int y0, /* * 6.4.1 Derivation process for z-scan order block availability */ -static av_always_inline int z_scan_block_avail(const HEVCContext *s, int xCurr, int yCurr, - int xN, int yN) +static av_always_inline int +z_scan_block_avail(const HEVCPPS *pps, const HEVCSPS *sps, + int xCurr, int yCurr, int xN, int yN) { #define MIN_TB_ADDR_ZS(x, y) \ - s->ps.pps->min_tb_addr_zs[(y) * (s->ps.sps->tb_mask+2) + (x)] + pps->min_tb_addr_zs[(y) * (sps->tb_mask+2) + (x)] - int xCurr_ctb = xCurr >> s->ps.sps->log2_ctb_size; - int yCurr_ctb = yCurr >> s->ps.sps->log2_ctb_size; - int xN_ctb = xN >> s->ps.sps->log2_ctb_size; - int yN_ctb = yN >> s->ps.sps->log2_ctb_size; + int xCurr_ctb = xCurr >> sps->log2_ctb_size; + int yCurr_ctb = yCurr >> sps->log2_ctb_size; + int xN_ctb = xN >> sps->log2_ctb_size; + int yN_ctb = yN >> sps->log2_ctb_size; if( yN_ctb < yCurr_ctb || xN_ctb < xCurr_ctb ) return 1; else { - int Curr = MIN_TB_ADDR_ZS((xCurr >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask, - (yCurr >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask); - int N = MIN_TB_ADDR_ZS((xN >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask, - (yN >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask); + int Curr = MIN_TB_ADDR_ZS((xCurr >> sps->log2_min_tb_size) & sps->tb_mask, + (yCurr >> sps->log2_min_tb_size) & sps->tb_mask); + int N = MIN_TB_ADDR_ZS((xN >> sps->log2_min_tb_size) & sps->tb_mask, + (yN >> sps->log2_min_tb_size) & sps->tb_mask); return N <= Curr; } } //check if the two luma locations belong to the same motion estimation region -static av_always_inline int is_diff_mer(const HEVCContext *s, int xN, int yN, int xP, int yP) +static av_always_inline int is_diff_mer(const HEVCPPS *pps, int xN, int yN, int xP, int yP) { - uint8_t plevel = s->ps.pps->log2_parallel_merge_level; + uint8_t plevel = pps->log2_parallel_merge_level; return xN >> plevel == xP >> plevel && yN >> plevel == yP >> plevel; @@ -165,7 +165,7 @@ static int derive_temporal_colocated_mvs(const HEVCContext *s, MvField temp_col, int refIdxLx, Mv *mvLXCol, int X, int colPic, const RefPicList *refPicList_col) { - const RefPicList *refPicList = s->ref->refPicList; + const RefPicList *refPicList = s->cur_frame->refPicList; if (temp_col.pred_flag == PF_INTRA) return 0; @@ -205,25 +205,26 @@ static int derive_temporal_colocated_mvs(const HEVCContext *s, MvField temp_col, tab_mvf[(y) * min_pu_width + x] #define TAB_MVF_PU(v) \ - TAB_MVF(((x ## v) >> s->ps.sps->log2_min_pu_size), \ - ((y ## v) >> s->ps.sps->log2_min_pu_size)) + TAB_MVF(((x ## v) >> sps->log2_min_pu_size), \ + ((y ## v) >> sps->log2_min_pu_size)) #define DERIVE_TEMPORAL_COLOCATED_MVS \ derive_temporal_colocated_mvs(s, temp_col, \ refIdxLx, mvLXCol, X, colPic, \ - ff_hevc_get_ref_list(s, ref, x, y)) + ff_hevc_get_ref_list(ref, x, y)) /* * 8.5.3.1.7 temporal luma motion vector prediction */ -static int temporal_luma_motion_vector(const HEVCContext *s, int x0, int y0, +static int temporal_luma_motion_vector(const HEVCContext *s, const HEVCSPS *sps, + int x0, int y0, int nPbW, int nPbH, int refIdxLx, Mv *mvLXCol, int X) { const MvField *tab_mvf; MvField temp_col; int x, y, x_pu, y_pu; - int min_pu_width = s->ps.sps->min_pu_width; + int min_pu_width = sps->min_pu_width; int availableFlagLXCol = 0; int colPic; @@ -242,15 +243,15 @@ static int temporal_luma_motion_vector(const HEVCContext *s, int x0, int y0, y = y0 + nPbH; if (tab_mvf && - (y0 >> s->ps.sps->log2_ctb_size) == (y >> s->ps.sps->log2_ctb_size) && - y < s->ps.sps->height && - x < s->ps.sps->width) { + (y0 >> sps->log2_ctb_size) == (y >> sps->log2_ctb_size) && + y < sps->height && + x < sps->width) { x &= ~15; y &= ~15; - if (s->threads_type == FF_THREAD_FRAME) - ff_thread_await_progress(&ref->tf, y, 0); - x_pu = x >> s->ps.sps->log2_min_pu_size; - y_pu = y >> s->ps.sps->log2_min_pu_size; + if (s->avctx->active_thread_type == FF_THREAD_FRAME) + ff_progress_frame_await(&ref->tf, y); + x_pu = x >> sps->log2_min_pu_size; + y_pu = y >> sps->log2_min_pu_size; temp_col = TAB_MVF(x_pu, y_pu); availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS; } @@ -261,10 +262,10 @@ static int temporal_luma_motion_vector(const HEVCContext *s, int x0, int y0, y = y0 + (nPbH >> 1); x &= ~15; y &= ~15; - if (s->threads_type == FF_THREAD_FRAME) - ff_thread_await_progress(&ref->tf, y, 0); - x_pu = x >> s->ps.sps->log2_min_pu_size; - y_pu = y >> s->ps.sps->log2_min_pu_size; + if (s->avctx->active_thread_type == FF_THREAD_FRAME) + ff_progress_frame_await(&ref->tf, y); + x_pu = x >> sps->log2_min_pu_size; + y_pu = y >> sps->log2_min_pu_size; temp_col = TAB_MVF(x_pu, y_pu); availableFlagLXCol = DERIVE_TEMPORAL_COLOCATED_MVS; } @@ -275,7 +276,7 @@ static int temporal_luma_motion_vector(const HEVCContext *s, int x0, int y0, (cand && !(TAB_MVF_PU(v).pred_flag == PF_INTRA)) #define PRED_BLOCK_AVAILABLE(v) \ - z_scan_block_avail(s, x0, y0, x ## v, y ## v) + z_scan_block_avail(pps, sps, x0, y0, x ## v, y ## v) #define COMPARE_MV_REFIDX(a, b) \ compare_mv_ref_idx(TAB_MVF_PU(a), TAB_MVF_PU(b)) @@ -284,6 +285,7 @@ static int temporal_luma_motion_vector(const HEVCContext *s, int x0, int y0, * 8.5.3.1.2 Derivation process for spatial merging candidates */ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCContext *s, + const HEVCPPS *pps, const HEVCSPS *sps, int x0, int y0, int nPbW, int nPbH, int log2_cb_size, @@ -291,10 +293,10 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont int merge_idx, struct MvField mergecandlist[]) { - const RefPicList *refPicList = s->ref->refPicList; - const MvField *tab_mvf = s->ref->tab_mvf; + const RefPicList *refPicList = s->cur_frame->refPicList; + const MvField *tab_mvf = s->cur_frame->tab_mvf; - const int min_pu_width = s->ps.sps->min_pu_width; + const int min_pu_width = sps->min_pu_width; const int cand_bottom_left = lc->na.cand_bottom_left; const int cand_left = lc->na.cand_left; @@ -336,7 +338,7 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont (lc->cu.part_mode == PART_Nx2N || lc->cu.part_mode == PART_nLx2N || lc->cu.part_mode == PART_nRx2N) || - is_diff_mer(s, xA1, yA1, x0, y0)) { + is_diff_mer(pps, xA1, yA1, x0, y0)) { is_available_a1 = 0; } else { is_available_a1 = AVAILABLE(cand_left, A1); @@ -352,7 +354,7 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont (lc->cu.part_mode == PART_2NxN || lc->cu.part_mode == PART_2NxnU || lc->cu.part_mode == PART_2NxnD) || - is_diff_mer(s, xB1, yB1, x0, y0)) { + is_diff_mer(pps, xB1, yB1, x0, y0)) { is_available_b1 = 0; } else { is_available_b1 = AVAILABLE(cand_up, B1); @@ -367,9 +369,9 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont // above right spatial merge candidate is_available_b0 = AVAILABLE(cand_up_right, B0) && - xB0 < s->ps.sps->width && + xB0 < sps->width && PRED_BLOCK_AVAILABLE(B0) && - !is_diff_mer(s, xB0, yB0, x0, y0); + !is_diff_mer(pps, xB0, yB0, x0, y0); if (is_available_b0 && !(is_available_b1 && COMPARE_MV_REFIDX(B0, B1))) { @@ -381,9 +383,9 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont // left bottom spatial merge candidate is_available_a0 = AVAILABLE(cand_bottom_left, A0) && - yA0 < s->ps.sps->height && + yA0 < sps->height && PRED_BLOCK_AVAILABLE(A0) && - !is_diff_mer(s, xA0, yA0, x0, y0); + !is_diff_mer(pps, xA0, yA0, x0, y0); if (is_available_a0 && !(is_available_a1 && COMPARE_MV_REFIDX(A0, A1))) { @@ -395,7 +397,7 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont // above left spatial merge candidate is_available_b2 = AVAILABLE(cand_up_left, B2) && - !is_diff_mer(s, xB2, yB2, x0, y0); + !is_diff_mer(pps, xB2, yB2, x0, y0); if (is_available_b2 && !(is_available_a1 && COMPARE_MV_REFIDX(B2, A1)) && @@ -411,10 +413,10 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont if (s->sh.slice_temporal_mvp_enabled_flag && nb_merge_cand < s->sh.max_num_merge_cand) { Mv mv_l0_col = { 0 }, mv_l1_col = { 0 }; - int available_l0 = temporal_luma_motion_vector(s, x0, y0, nPbW, nPbH, + int available_l0 = temporal_luma_motion_vector(s, sps, x0, y0, nPbW, nPbH, 0, &mv_l0_col, 0); int available_l1 = (s->sh.slice_type == HEVC_SLICE_B) ? - temporal_luma_motion_vector(s, x0, y0, nPbW, nPbH, + temporal_luma_motion_vector(s, sps, x0, y0, nPbW, nPbH, 0, &mv_l1_col, 1) : 0; if (available_l0 || available_l1) { @@ -477,10 +479,12 @@ static void derive_spatial_merge_candidates(HEVCLocalContext *lc, const HEVCCont /* * 8.5.3.1.1 Derivation process of luma Mvs for merge mode */ -void ff_hevc_luma_mv_merge_mode(HEVCLocalContext *lc, int x0, int y0, int nPbW, +void ff_hevc_luma_mv_merge_mode(HEVCLocalContext *lc, const HEVCPPS *pps, + int x0, int y0, int nPbW, int nPbH, int log2_cb_size, int part_idx, int merge_idx, MvField *mv) { + const HEVCSPS *const sps = pps->sps; const HEVCContext *const s = lc->parent; int singleMCLFlag = 0; int nCS = 1 << log2_cb_size; @@ -488,7 +492,7 @@ void ff_hevc_luma_mv_merge_mode(HEVCLocalContext *lc, int x0, int y0, int nPbW, int nPbW2 = nPbW; int nPbH2 = nPbH; - if (s->ps.pps->log2_parallel_merge_level > 2 && nCS == 8) { + if (pps->log2_parallel_merge_level > 2 && nCS == 8) { singleMCLFlag = 1; x0 = lc->cu.x; y0 = lc->cu.y; @@ -497,8 +501,8 @@ void ff_hevc_luma_mv_merge_mode(HEVCLocalContext *lc, int x0, int y0, int nPbW, part_idx = 0; } - ff_hevc_set_neighbour_available(lc, x0, y0, nPbW, nPbH); - derive_spatial_merge_candidates(lc, s, x0, y0, nPbW, nPbH, log2_cb_size, + ff_hevc_set_neighbour_available(lc, x0, y0, nPbW, nPbH, sps->log2_ctb_size); + derive_spatial_merge_candidates(lc, s, pps, sps, x0, y0, nPbW, nPbH, log2_cb_size, singleMCLFlag, part_idx, merge_idx, mergecand_list); @@ -514,8 +518,8 @@ static av_always_inline void dist_scale(const HEVCContext *s, Mv *mv, int min_pu_width, int x, int y, int elist, int ref_idx_curr, int ref_idx) { - const RefPicList *refPicList = s->ref->refPicList; - const MvField *tab_mvf = s->ref->tab_mvf; + const RefPicList *refPicList = s->cur_frame->refPicList; + const MvField *tab_mvf = s->cur_frame->tab_mvf; int ref_pic_elist = refPicList[elist].list[TAB_MVF(x, y).ref_idx[elist]]; int ref_pic_curr = refPicList[ref_idx_curr].list[ref_idx]; @@ -527,13 +531,14 @@ static av_always_inline void dist_scale(const HEVCContext *s, Mv *mv, } } -static int mv_mp_mode_mx(const HEVCContext *s, int x, int y, int pred_flag_index, +static int mv_mp_mode_mx(const HEVCContext *s, const HEVCSPS *sps, + int x, int y, int pred_flag_index, Mv *mv, int ref_idx_curr, int ref_idx) { - const MvField *tab_mvf = s->ref->tab_mvf; - int min_pu_width = s->ps.sps->min_pu_width; + const MvField *tab_mvf = s->cur_frame->tab_mvf; + int min_pu_width = sps->min_pu_width; - const RefPicList *refPicList = s->ref->refPicList; + const RefPicList *refPicList = s->cur_frame->refPicList; if (((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) && refPicList[pred_flag_index].list[TAB_MVF(x, y).ref_idx[pred_flag_index]] == refPicList[ref_idx_curr].list[ref_idx]) { @@ -543,13 +548,14 @@ static int mv_mp_mode_mx(const HEVCContext *s, int x, int y, int pred_flag_index return 0; } -static int mv_mp_mode_mx_lt(const HEVCContext *s, int x, int y, int pred_flag_index, +static int mv_mp_mode_mx_lt(const HEVCContext *s, const HEVCSPS *sps, + int x, int y, int pred_flag_index, Mv *mv, int ref_idx_curr, int ref_idx) { - const MvField *tab_mvf = s->ref->tab_mvf; - int min_pu_width = s->ps.sps->min_pu_width; + const MvField *tab_mvf = s->cur_frame->tab_mvf; + int min_pu_width = sps->min_pu_width; - const RefPicList *refPicList = s->ref->refPicList; + const RefPicList *refPicList = s->cur_frame->refPicList; if ((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) { int currIsLongTerm = refPicList[ref_idx_curr].isLongTerm[ref_idx]; @@ -569,29 +575,31 @@ static int mv_mp_mode_mx_lt(const HEVCContext *s, int x, int y, int pred_flag_in } #define MP_MX(v, pred, mx) \ - mv_mp_mode_mx(s, \ - (x ## v) >> s->ps.sps->log2_min_pu_size, \ - (y ## v) >> s->ps.sps->log2_min_pu_size, \ + mv_mp_mode_mx(s, sps, \ + (x ## v) >> sps->log2_min_pu_size, \ + (y ## v) >> sps->log2_min_pu_size, \ pred, &mx, ref_idx_curr, ref_idx) #define MP_MX_LT(v, pred, mx) \ - mv_mp_mode_mx_lt(s, \ - (x ## v) >> s->ps.sps->log2_min_pu_size, \ - (y ## v) >> s->ps.sps->log2_min_pu_size, \ + mv_mp_mode_mx_lt(s, sps, \ + (x ## v) >> sps->log2_min_pu_size, \ + (y ## v) >> sps->log2_min_pu_size, \ pred, &mx, ref_idx_curr, ref_idx) -void ff_hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, int x0, int y0, int nPbW, +void ff_hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, const HEVCPPS *pps, + int x0, int y0, int nPbW, int nPbH, int log2_cb_size, int part_idx, int merge_idx, MvField *mv, int mvp_lx_flag, int LX) { + const HEVCSPS *const sps = pps->sps; const HEVCContext *const s = lc->parent; - const MvField *const tab_mvf = s->ref->tab_mvf; + const MvField *const tab_mvf = s->cur_frame->tab_mvf; int isScaledFlag_L0 = 0; int availableFlagLXA0 = 1; int availableFlagLXB0 = 1; int numMVPCandLX = 0; - int min_pu_width = s->ps.sps->min_pu_width; + int min_pu_width = sps->min_pu_width; int xA0, yA0; int is_available_a0; @@ -627,7 +635,7 @@ void ff_hevc_luma_mv_mvp_mode(HEVCLocalContext *lc, int x0, int y0, int nPbW, yA0 = y0 + nPbH; is_available_a0 = AVAILABLE(cand_bottom_left, A0) && - yA0 < s->ps.sps->height && + yA0 < sps->height && PRED_BLOCK_AVAILABLE(A0); //left spatial merge candidate @@ -682,7 +690,7 @@ b_candidates: yB0 = y0 - 1; is_available_b0 = AVAILABLE(cand_up_right, B0) && - xB0 < s->ps.sps->width && + xB0 < sps->width && PRED_BLOCK_AVAILABLE(B0); // above spatial merge candidate @@ -764,7 +772,7 @@ scalef: if (numMVPCandLX < 2 && s->sh.slice_temporal_mvp_enabled_flag && mvp_lx_flag == numMVPCandLX) { Mv mv_col; - int available_col = temporal_luma_motion_vector(s, x0, y0, nPbW, + int available_col = temporal_luma_motion_vector(s, sps, x0, y0, nPbW, nPbH, ref_idx, &mv_col, LX); if (available_col) diff --git a/libavcodec/hevc_parse.c b/libavcodec/hevc/parse.c similarity index 94% rename from libavcodec/hevc_parse.c rename to libavcodec/hevc/parse.c index 7bc28fd08..29f21a596 100644 --- a/libavcodec/hevc_parse.c +++ b/libavcodec/hevc/parse.c @@ -19,7 +19,7 @@ #include "bytestream.h" #include "h2645_parse.h" #include "hevc.h" -#include "hevc_parse.h" +#include "parse.h" static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets *ps, HEVCSEI *sei, int is_nalff, int nal_length_size, @@ -27,19 +27,17 @@ static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets { int i; int ret = 0; + int flags = (H2645_FLAG_IS_NALFF * !!is_nalff) | H2645_FLAG_SMALL_PADDING; H2645Packet pkt = { 0 }; - ret = ff_h2645_packet_split(&pkt, buf, buf_size, logctx, is_nalff, - nal_length_size, AV_CODEC_ID_HEVC, 1, 0); + ret = ff_h2645_packet_split(&pkt, buf, buf_size, logctx, + nal_length_size, AV_CODEC_ID_HEVC, flags); if (ret < 0) { goto done; } for (i = 0; i < pkt.nb_nals; i++) { H2645NAL *nal = &pkt.nals[i]; - if (nal->nuh_layer_id > 0) - continue; - /* ignore everything except parameter sets and VCL NALUs */ switch (nal->type) { case HEVC_NAL_VPS: @@ -48,7 +46,8 @@ static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets goto done; break; case HEVC_NAL_SPS: - ret = ff_hevc_decode_nal_sps(&nal->gb, logctx, ps, apply_defdispwin); + ret = ff_hevc_decode_nal_sps(&nal->gb, logctx, ps, + nal->nuh_layer_id, apply_defdispwin); if (ret < 0) goto done; break; diff --git a/libavcodec/hevc_parse.h b/libavcodec/hevc/parse.h similarity index 96% rename from libavcodec/hevc_parse.h rename to libavcodec/hevc/parse.h index 4ab96ab1c..b3bcbde50 100644 --- a/libavcodec/hevc_parse.h +++ b/libavcodec/hevc/parse.h @@ -26,8 +26,8 @@ #include -#include "hevc_ps.h" -#include "hevc_sei.h" +#include "ps.h" +#include "sei.h" int ff_hevc_decode_extradata(const uint8_t *data, int size, HEVCParamSets *ps, HEVCSEI *sei, int *is_nalff, int *nal_length_size, diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc/parser.c similarity index 84% rename from libavcodec/hevc_parser.c rename to libavcodec/hevc/parser.c index 99a4272fa..16b40e2b1 100644 --- a/libavcodec/hevc_parser.c +++ b/libavcodec/hevc/parser.c @@ -21,12 +21,13 @@ */ #include "libavutil/common.h" +#include "libavutil/mem.h" #include "golomb.h" #include "hevc.h" -#include "hevc_parse.h" -#include "hevc_ps.h" -#include "hevc_sei.h" +#include "parse.h" +#include "ps.h" +#include "sei.h" #include "h2645_parse.h" #include "parser.h" @@ -57,6 +58,8 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, HEVCParamSets *ps = &ctx->ps; HEVCSEI *sei = &ctx->sei; GetBitContext *gb = &nal->gb; + const HEVCPPS *pps; + const HEVCSPS *sps; const HEVCWindow *ow; int i, num = 0, den = 0; @@ -77,35 +80,28 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, av_log(avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", pps_id); return AVERROR_INVALIDDATA; } - ps->pps = ps->pps_list[pps_id]; + pps = ps->pps_list[pps_id]; + sps = pps->sps; - if (ps->pps->sps_id >= HEVC_MAX_SPS_COUNT || !ps->sps_list[ps->pps->sps_id]) { - av_log(avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", ps->pps->sps_id); - return AVERROR_INVALIDDATA; - } - if (ps->sps != ps->sps_list[ps->pps->sps_id]) { - ps->sps = ps->sps_list[ps->pps->sps_id]; - ps->vps = ps->vps_list[ps->sps->vps_id]; - } - ow = &ps->sps->output_window; + ow = &sps->output_window; - s->coded_width = ps->sps->width; - s->coded_height = ps->sps->height; - s->width = ps->sps->width - ow->left_offset - ow->right_offset; - s->height = ps->sps->height - ow->top_offset - ow->bottom_offset; - s->format = ps->sps->pix_fmt; - avctx->profile = ps->sps->ptl.general_ptl.profile_idc; - avctx->level = ps->sps->ptl.general_ptl.level_idc; + s->coded_width = sps->width; + s->coded_height = sps->height; + s->width = sps->width - ow->left_offset - ow->right_offset; + s->height = sps->height - ow->top_offset - ow->bottom_offset; + s->format = sps->pix_fmt; + avctx->profile = sps->ptl.general_ptl.profile_idc; + avctx->level = sps->ptl.general_ptl.level_idc; - if (ps->vps->vps_timing_info_present_flag) { - num = ps->vps->vps_num_units_in_tick; - den = ps->vps->vps_time_scale; - } else if (ps->sps->vui.vui_timing_info_present_flag) { - num = ps->sps->vui.vui_num_units_in_tick; - den = ps->sps->vui.vui_time_scale; + if (sps->vps->vps_timing_info_present_flag) { + num = sps->vps->vps_num_units_in_tick; + den = sps->vps->vps_time_scale; + } else if (sps->vui.vui_timing_info_present_flag) { + num = sps->vui.vui_num_units_in_tick; + den = sps->vui.vui_time_scale; } - if (num != 0 && den != 0) + if (num > 0 && den > 0) av_reduce(&avctx->framerate.den, &avctx->framerate.num, num, den, 1 << 30); @@ -113,15 +109,15 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, unsigned int slice_segment_addr; int slice_address_length; - if (ps->pps->dependent_slice_segments_enabled_flag) + if (pps->dependent_slice_segments_enabled_flag) dependent_slice_segment_flag = get_bits1(gb); else dependent_slice_segment_flag = 0; - slice_address_length = av_ceil_log2_c(ps->sps->ctb_width * - ps->sps->ctb_height); + slice_address_length = av_ceil_log2_c(sps->ctb_width * + sps->ctb_height); slice_segment_addr = get_bitsz(gb, slice_address_length); - if (slice_segment_addr >= ps->sps->ctb_width * ps->sps->ctb_height) { + if (slice_segment_addr >= sps->ctb_width * sps->ctb_height) { av_log(avctx, AV_LOG_ERROR, "Invalid slice segment address: %u.\n", slice_segment_addr); return AVERROR_INVALIDDATA; @@ -132,7 +128,7 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, if (dependent_slice_segment_flag) return 0; /* break; */ - for (i = 0; i < ps->pps->num_extra_slice_header_bits; i++) + for (i = 0; i < pps->num_extra_slice_header_bits; i++) skip_bits(gb, 1); // slice_reserved_undetermined_flag[] slice_type = get_ue_golomb_31(gb); @@ -146,16 +142,16 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, slice_type == HEVC_SLICE_P ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I; - if (ps->pps->output_flag_present_flag) + if (pps->output_flag_present_flag) skip_bits1(gb); // pic_output_flag - if (ps->sps->separate_colour_plane_flag) + if (sps->separate_colour_plane) skip_bits(gb, 2); // colour_plane_id if (!IS_IDR_NAL(nal)) { - int pic_order_cnt_lsb = get_bits(gb, ps->sps->log2_max_poc_lsb); + int pic_order_cnt_lsb = get_bits(gb, sps->log2_max_poc_lsb); s->output_picture_number = ctx->poc = - ff_hevc_compute_poc(ps->sps, ctx->pocTid0, pic_order_cnt_lsb, nal->type); + ff_hevc_compute_poc(sps, ctx->pocTid0, pic_order_cnt_lsb, nal->type); } else s->output_picture_number = ctx->poc = 0; @@ -186,6 +182,7 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, HEVCParserContext *ctx = s->priv_data; HEVCParamSets *ps = &ctx->ps; HEVCSEI *sei = &ctx->sei; + int flags = (H2645_FLAG_IS_NALFF * !!ctx->is_avc) | H2645_FLAG_SMALL_PADDING; int ret, i; /* set some sane default values */ @@ -195,8 +192,8 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, ff_hevc_reset_sei(sei); - ret = ff_h2645_packet_split(&ctx->pkt, buf, buf_size, avctx, ctx->is_avc, - ctx->nal_length_size, AV_CODEC_ID_HEVC, 1, 0); + ret = ff_h2645_packet_split(&ctx->pkt, buf, buf_size, avctx, + ctx->nal_length_size, AV_CODEC_ID_HEVC, flags); if (ret < 0) return ret; @@ -212,7 +209,7 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, ff_hevc_decode_nal_vps(gb, avctx, ps); break; case HEVC_NAL_SPS: - ff_hevc_decode_nal_sps(gb, avctx, ps, 1); + ff_hevc_decode_nal_sps(gb, avctx, ps, nal->nuh_layer_id, 1); break; case HEVC_NAL_PPS: ff_hevc_decode_nal_pps(gb, avctx, ps); @@ -265,7 +262,7 @@ static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf, int i; for (i = 0; i < buf_size; i++) { - int nut; + int nut, layer_id; pc->state64 = (pc->state64 << 8) | buf[i]; @@ -273,6 +270,11 @@ static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf, continue; nut = (pc->state64 >> 2 * 8 + 1) & 0x3F; + + layer_id = (pc->state64 >> 11) & 0x3F; + if (layer_id > 0) + continue; + // Beginning of access unit if ((nut >= HEVC_NAL_VPS && nut <= HEVC_NAL_EOB_NUT) || nut == HEVC_NAL_SEI_PREFIX || (nut >= 41 && nut <= 44) || (nut >= 48 && nut <= 55)) { diff --git a/libavcodec/hevcpred.c b/libavcodec/hevc/pred.c similarity index 93% rename from libavcodec/hevcpred.c rename to libavcodec/hevc/pred.c index 16b012f46..8d588382f 100644 --- a/libavcodec/hevcpred.c +++ b/libavcodec/hevc/pred.c @@ -22,22 +22,22 @@ #include "hevcdec.h" -#include "hevcpred.h" +#include "pred.h" #define BIT_DEPTH 8 -#include "hevcpred_template.c" +#include "pred_template.c" #undef BIT_DEPTH #define BIT_DEPTH 9 -#include "hevcpred_template.c" +#include "pred_template.c" #undef BIT_DEPTH #define BIT_DEPTH 10 -#include "hevcpred_template.c" +#include "pred_template.c" #undef BIT_DEPTH #define BIT_DEPTH 12 -#include "hevcpred_template.c" +#include "pred_template.c" #undef BIT_DEPTH void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth) diff --git a/libavcodec/hevcpred.h b/libavcodec/hevc/pred.h similarity index 86% rename from libavcodec/hevcpred.h rename to libavcodec/hevc/pred.h index b1b1dc4f3..1ac8f9666 100644 --- a/libavcodec/hevcpred.h +++ b/libavcodec/hevc/pred.h @@ -20,16 +20,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_HEVCPRED_H -#define AVCODEC_HEVCPRED_H +#ifndef AVCODEC_HEVC_PRED_H +#define AVCODEC_HEVC_PRED_H #include #include struct HEVCLocalContext; +struct HEVCPPS; typedef struct HEVCPredContext { - void (*intra_pred[4])(struct HEVCLocalContext *lc, int x0, int y0, int c_idx); + void (*intra_pred[4])(struct HEVCLocalContext *lc, + const struct HEVCPPS *pps, int x0, int y0, int c_idx); void (*pred_planar[4])(uint8_t *src, const uint8_t *top, const uint8_t *left, ptrdiff_t stride); @@ -43,4 +45,4 @@ typedef struct HEVCPredContext { void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth); void ff_hevc_pred_init_mips(HEVCPredContext *hpc, int bit_depth); -#endif /* AVCODEC_HEVCPRED_H */ +#endif /* AVCODEC_HEVC_PRED_H */ diff --git a/libavcodec/hevcpred_template.c b/libavcodec/hevc/pred_template.c similarity index 87% rename from libavcodec/hevcpred_template.c rename to libavcodec/hevc/pred_template.c index 46bd80652..b4c2fcf50 100644 --- a/libavcodec/hevcpred_template.c +++ b/libavcodec/hevc/pred_template.c @@ -23,23 +23,25 @@ #include "libavutil/pixdesc.h" #include "bit_depth_template.c" -#include "hevcpred.h" +#include "pred.h" #define POS(x, y) src[(x) + stride * (y)] -static av_always_inline void FUNC(intra_pred)(HEVCLocalContext *lc, int x0, int y0, +static av_always_inline void FUNC(intra_pred)(HEVCLocalContext *lc, + const HEVCPPS *pps, + int x0, int y0, int log2_size, int c_idx) { #define PU(x) \ - ((x) >> s->ps.sps->log2_min_pu_size) + ((x) >> sps->log2_min_pu_size) #define MVF(x, y) \ - (s->ref->tab_mvf[(x) + (y) * min_pu_width]) + (s->cur_frame->tab_mvf[(x) + (y) * min_pu_width]) #define MVF_PU(x, y) \ MVF(PU(x0 + ((x) * (1 << hshift))), PU(y0 + ((y) * (1 << vshift)))) #define IS_INTRA(x, y) \ (MVF_PU(x, y).pred_flag == PF_INTRA) #define MIN_TB_ADDR_ZS(x, y) \ - s->ps.pps->min_tb_addr_zs[(y) * (s->ps.sps->tb_mask+2) + (x)] + pps->min_tb_addr_zs[(y) * (sps->tb_mask+2) + (x)] #define EXTEND(ptr, val, len) \ do { \ pixel4 pix = PIXEL_SPLAT_X4(val); \ @@ -70,27 +72,28 @@ do { \ else \ a = PIXEL_SPLAT_X4(ptr[i + 3]) + const HEVCSPS *const sps = pps->sps; const HEVCContext *const s = lc->parent; int i; - int hshift = s->ps.sps->hshift[c_idx]; - int vshift = s->ps.sps->vshift[c_idx]; + int hshift = sps->hshift[c_idx]; + int vshift = sps->vshift[c_idx]; int size = (1 << log2_size); int size_in_luma_h = size << hshift; - int size_in_tbs_h = size_in_luma_h >> s->ps.sps->log2_min_tb_size; + int size_in_tbs_h = size_in_luma_h >> sps->log2_min_tb_size; int size_in_luma_v = size << vshift; - int size_in_tbs_v = size_in_luma_v >> s->ps.sps->log2_min_tb_size; + int size_in_tbs_v = size_in_luma_v >> sps->log2_min_tb_size; int x = x0 >> hshift; int y = y0 >> vshift; - int x_tb = (x0 >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask; - int y_tb = (y0 >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask; - int spin = c_idx && !size_in_tbs_v && ((2 * y0) & (1 << s->ps.sps->log2_min_tb_size)); + int x_tb = (x0 >> sps->log2_min_tb_size) & sps->tb_mask; + int y_tb = (y0 >> sps->log2_min_tb_size) & sps->tb_mask; + int spin = c_idx && !size_in_tbs_v && ((2 * y0) & (1 << sps->log2_min_tb_size)); int cur_tb_addr = MIN_TB_ADDR_ZS(x_tb, y_tb); - ptrdiff_t stride = s->frame->linesize[c_idx] / sizeof(pixel); - pixel *src = (pixel*)s->frame->data[c_idx] + x + y * stride; + ptrdiff_t stride = s->cur_frame->f->linesize[c_idx] / sizeof(pixel); + pixel *src = (pixel*)s->cur_frame->f->data[c_idx] + x + y * stride; - int min_pu_width = s->ps.sps->min_pu_width; + int min_pu_width = sps->min_pu_width; enum IntraPredMode mode = c_idx ? lc->tu.intra_pred_mode_c : lc->tu.intra_pred_mode; @@ -104,28 +107,28 @@ do { \ pixel *top = top_array + 1; pixel *filtered_left = filtered_left_array + 1; pixel *filtered_top = filtered_top_array + 1; - int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > MIN_TB_ADDR_ZS( x_tb - 1, (y_tb + size_in_tbs_v + spin) & s->ps.sps->tb_mask); + int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > MIN_TB_ADDR_ZS( x_tb - 1, (y_tb + size_in_tbs_v + spin) & sps->tb_mask); int cand_left = lc->na.cand_left; int cand_up_left = lc->na.cand_up_left; int cand_up = lc->na.cand_up; - int cand_up_right = lc->na.cand_up_right && !spin && cur_tb_addr > MIN_TB_ADDR_ZS((x_tb + size_in_tbs_h) & s->ps.sps->tb_mask, y_tb - 1); + int cand_up_right = lc->na.cand_up_right && !spin && cur_tb_addr > MIN_TB_ADDR_ZS((x_tb + size_in_tbs_h) & sps->tb_mask, y_tb - 1); - int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma_v, s->ps.sps->height) - + int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma_v, sps->height) - (y0 + size_in_luma_v)) >> vshift; - int top_right_size = (FFMIN(x0 + 2 * size_in_luma_h, s->ps.sps->width) - + int top_right_size = (FFMIN(x0 + 2 * size_in_luma_h, sps->width) - (x0 + size_in_luma_h)) >> hshift; - if (s->ps.pps->constrained_intra_pred_flag == 1) { + if (pps->constrained_intra_pred_flag == 1) { int size_in_luma_pu_v = PU(size_in_luma_v); int size_in_luma_pu_h = PU(size_in_luma_h); - int on_pu_edge_x = !av_mod_uintp2(x0, s->ps.sps->log2_min_pu_size); - int on_pu_edge_y = !av_mod_uintp2(y0, s->ps.sps->log2_min_pu_size); + int on_pu_edge_x = !av_zero_extend(x0, sps->log2_min_pu_size); + int on_pu_edge_y = !av_zero_extend(y0, sps->log2_min_pu_size); if (!size_in_luma_pu_h) size_in_luma_pu_h++; if (cand_bottom_left == 1 && on_pu_edge_x) { int x_left_pu = PU(x0 - 1); int y_bottom_pu = PU(y0 + size_in_luma_v); - int max = FFMIN(size_in_luma_pu_v, s->ps.sps->min_pu_height - y_bottom_pu); + int max = FFMIN(size_in_luma_pu_v, sps->min_pu_height - y_bottom_pu); cand_bottom_left = 0; for (i = 0; i < max; i += 2) cand_bottom_left |= (MVF(x_left_pu, y_bottom_pu + i).pred_flag == PF_INTRA); @@ -133,7 +136,7 @@ do { \ if (cand_left == 1 && on_pu_edge_x) { int x_left_pu = PU(x0 - 1); int y_left_pu = PU(y0); - int max = FFMIN(size_in_luma_pu_v, s->ps.sps->min_pu_height - y_left_pu); + int max = FFMIN(size_in_luma_pu_v, sps->min_pu_height - y_left_pu); cand_left = 0; for (i = 0; i < max; i += 2) cand_left |= (MVF(x_left_pu, y_left_pu + i).pred_flag == PF_INTRA); @@ -146,7 +149,7 @@ do { \ if (cand_up == 1 && on_pu_edge_y) { int x_top_pu = PU(x0); int y_top_pu = PU(y0 - 1); - int max = FFMIN(size_in_luma_pu_h, s->ps.sps->min_pu_width - x_top_pu); + int max = FFMIN(size_in_luma_pu_h, sps->min_pu_width - x_top_pu); cand_up = 0; for (i = 0; i < max; i += 2) cand_up |= (MVF(x_top_pu + i, y_top_pu).pred_flag == PF_INTRA); @@ -154,7 +157,7 @@ do { \ if (cand_up_right == 1 && on_pu_edge_y) { int y_top_pu = PU(y0 - 1); int x_right_pu = PU(x0 + size_in_luma_h); - int max = FFMIN(size_in_luma_pu_h, s->ps.sps->min_pu_width - x_right_pu); + int max = FFMIN(size_in_luma_pu_h, sps->min_pu_width - x_right_pu); cand_up_right = 0; for (i = 0; i < max; i += 2) cand_up_right |= (MVF(x_right_pu + i, y_top_pu).pred_flag == PF_INTRA); @@ -184,20 +187,20 @@ do { \ size - bottom_left_size); } - if (s->ps.pps->constrained_intra_pred_flag == 1) { + if (pps->constrained_intra_pred_flag == 1) { if (cand_bottom_left || cand_left || cand_up_left || cand_up || cand_up_right) { - int size_max_x = x0 + ((2 * size) << hshift) < s->ps.sps->width ? - 2 * size : (s->ps.sps->width - x0) >> hshift; - int size_max_y = y0 + ((2 * size) << vshift) < s->ps.sps->height ? - 2 * size : (s->ps.sps->height - y0) >> vshift; + int size_max_x = x0 + ((2 * size) << hshift) < sps->width ? + 2 * size : (sps->width - x0) >> hshift; + int size_max_y = y0 + ((2 * size) << vshift) < sps->height ? + 2 * size : (sps->height - y0) >> vshift; int j = size + (cand_bottom_left? bottom_left_size: 0) -1; if (!cand_up_right) { - size_max_x = x0 + ((size) << hshift) < s->ps.sps->width ? - size : (s->ps.sps->width - x0) >> hshift; + size_max_x = x0 + ((size) << hshift) < sps->width ? + size : (sps->width - x0) >> hshift; } if (!cand_bottom_left) { - size_max_y = y0 + (( size) << vshift) < s->ps.sps->height ? - size : (s->ps.sps->height - y0) >> vshift; + size_max_y = y0 + (( size) << vshift) < sps->height ? + size : (sps->height - y0) >> vshift; } if (cand_bottom_left || cand_left || cand_up_left) { while (j > -1 && !IS_INTRA(-1, j)) @@ -285,14 +288,14 @@ do { \ top[-1] = left[-1]; // Filtering process - if (!s->ps.sps->intra_smoothing_disabled_flag && (c_idx == 0 || s->ps.sps->chroma_format_idc == 3)) { + if (!sps->intra_smoothing_disabled && (c_idx == 0 || sps->chroma_format_idc == 3)) { if (mode != INTRA_DC && size != 4){ int intra_hor_ver_dist_thresh[] = { 7, 1, 0 }; int min_dist_vert_hor = FFMIN(FFABS((int)(mode - 26U)), FFABS((int)(mode - 10U))); if (min_dist_vert_hor > intra_hor_ver_dist_thresh[log2_size - 3]) { int threshold = 1 << (BIT_DEPTH - 5); - if (s->ps.sps->sps_strong_intra_smoothing_enable_flag && c_idx == 0 && + if (sps->strong_intra_smoothing_enabled && c_idx == 0 && log2_size == 5 && FFABS(top[-1] + top[63] - 2 * top[31]) < threshold && FFABS(left[-1] + left[63] - 2 * left[31]) < threshold) { @@ -343,9 +346,10 @@ do { \ } #define INTRA_PRED(size) \ -static void FUNC(intra_pred_ ## size)(HEVCLocalContext *lc, int x0, int y0, int c_idx) \ +static void FUNC(intra_pred_ ## size)(HEVCLocalContext *lc, const HEVCPPS *pps, \ + int x0, int y0, int c_idx) \ { \ - FUNC(intra_pred)(lc, x0, y0, size, c_idx); \ + FUNC(intra_pred)(lc, pps, x0, y0, size, c_idx); \ } INTRA_PRED(2) diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc/ps.c similarity index 74% rename from libavcodec/hevc_ps.c rename to libavcodec/hevc/ps.c index 6475d86d7..f18b88489 100644 --- a/libavcodec/hevc_ps.c +++ b/libavcodec/hevc/ps.c @@ -24,10 +24,12 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "golomb.h" #include "h2645_vui.h" -#include "hevc_data.h" -#include "hevc_ps.h" +#include "data.h" +#include "ps.h" +#include "profiles.h" #include "refstruct.h" static const uint8_t default_scaling_list_intra[] = { @@ -60,26 +62,15 @@ static const uint8_t hevc_sub_height_c[] = { 1, 2, 1, 1 }; -static void remove_pps(HEVCParamSets *s, int id) -{ - if (s->pps == s->pps_list[id]) - s->pps = NULL; - ff_refstruct_unref(&s->pps_list[id]); -} - static void remove_sps(HEVCParamSets *s, int id) { int i; if (s->sps_list[id]) { - if (s->sps == s->sps_list[id]) - s->sps = NULL; - /* 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) - remove_pps(s, i); + ff_refstruct_unref(&s->pps_list[i]); - av_assert0(!(s->sps_list[id] && s->sps == s->sps_list[id])); ff_refstruct_unref(&s->sps_list[id]); } } @@ -88,9 +79,6 @@ static void remove_vps(HEVCParamSets *s, int id) { int i; if (s->vps_list[id]) { - if (s->vps == s->vps_list[id]) - s->vps = NULL; - 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); @@ -106,6 +94,7 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, int k = 0; int i; + rps->used = 0; rps->rps_predict = 0; if (rps != sps->st_rps && sps->nb_st_rps) @@ -113,6 +102,7 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, if (rps->rps_predict) { const ShortTermRPS *rps_ridx; + uint8_t used[32] = { 0 }; int delta_rps; if (is_slice_header) { @@ -138,13 +128,13 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, } delta_rps = (1 - (rps->delta_rps_sign << 1)) * rps->abs_delta_rps; for (i = 0; i <= rps_ridx->num_delta_pocs; i++) { - int used = rps->used[k] = get_bits1(gb); + used[k] = get_bits1(gb); - rps->use_delta_flag = 0; - if (!used) - rps->use_delta_flag = get_bits1(gb); + rps->use_delta = 0; + if (!used[k]) + rps->use_delta = get_bits1(gb); - if (used || rps->use_delta_flag) { + if (used[k] || rps->use_delta) { if (i < rps_ridx->num_delta_pocs) delta_poc = delta_rps + rps_ridx->delta_poc[i]; else @@ -156,7 +146,7 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, } } - if (k >= FF_ARRAY_ELEMS(rps->used)) { + if (k >= FF_ARRAY_ELEMS(used)) { av_log(avctx, AV_LOG_ERROR, "Invalid num_delta_pocs: %d\n", k); return AVERROR_INVALIDDATA; @@ -166,37 +156,41 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, rps->num_negative_pics = k0; // sort in increasing order (smallest first) if (rps->num_delta_pocs != 0) { - int used, tmp; + int u, tmp; for (i = 1; i < rps->num_delta_pocs; i++) { delta_poc = rps->delta_poc[i]; - used = rps->used[i]; + u = used[i]; for (k = i - 1; k >= 0; k--) { tmp = rps->delta_poc[k]; if (delta_poc < tmp) { rps->delta_poc[k + 1] = tmp; - rps->used[k + 1] = rps->used[k]; + used[k + 1] = used[k]; rps->delta_poc[k] = delta_poc; - rps->used[k] = used; + used[k] = u; } } } } if ((rps->num_negative_pics >> 1) != 0) { - int used; + int u; k = rps->num_negative_pics - 1; // flip the negative values to largest first for (i = 0; i < rps->num_negative_pics >> 1; i++) { delta_poc = rps->delta_poc[i]; - used = rps->used[i]; + u = used[i]; rps->delta_poc[i] = rps->delta_poc[k]; - rps->used[i] = rps->used[k]; + used[i] = used[k]; rps->delta_poc[k] = delta_poc; - rps->used[k] = used; + used[k] = u; k--; } } + + for (unsigned i = 0; i < FF_ARRAY_ELEMS(used); i++) + rps->used |= (uint32_t)used[i] << i; } else { - unsigned int prev, nb_positive_pics; + unsigned int nb_positive_pics; + rps->num_negative_pics = get_ue_golomb_long(gb); nb_positive_pics = get_ue_golomb_long(gb); @@ -208,9 +202,10 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, rps->num_delta_pocs = rps->num_negative_pics + nb_positive_pics; if (rps->num_delta_pocs) { - prev = 0; + int prev = 0; + for (i = 0; i < rps->num_negative_pics; i++) { - delta_poc = rps->delta_poc_s0[i] = get_ue_golomb_long(gb) + 1; + delta_poc = get_ue_golomb_long(gb) + 1; if (delta_poc < 1 || delta_poc > 32768) { av_log(avctx, AV_LOG_ERROR, "Invalid value of delta_poc: %d\n", @@ -219,11 +214,11 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, } prev -= delta_poc; rps->delta_poc[i] = prev; - rps->used[i] = get_bits1(gb); + rps->used |= get_bits1(gb) * (1 << i); } prev = 0; for (i = 0; i < nb_positive_pics; i++) { - delta_poc = rps->delta_poc_s1[i] = get_ue_golomb_long(gb) + 1; + delta_poc = get_ue_golomb_long(gb) + 1; if (delta_poc < 1 || delta_poc > 32768) { av_log(avctx, AV_LOG_ERROR, "Invalid value of delta_poc: %d\n", @@ -232,7 +227,7 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, } prev += delta_poc; rps->delta_poc[rps->num_negative_pics + i] = prev; - rps->used[rps->num_negative_pics + i] = get_bits1(gb); + rps->used |= get_bits1(gb) * (1 << (rps->num_negative_pics + i)); } } } @@ -243,6 +238,7 @@ 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) @@ -251,18 +247,16 @@ static int decode_profile_tier_level(GetBitContext *gb, AVCodecContext *avctx, ptl->profile_space = get_bits(gb, 2); ptl->tier_flag = get_bits1(gb); ptl->profile_idc = get_bits(gb, 5); - if (ptl->profile_idc == AV_PROFILE_HEVC_MAIN) - av_log(avctx, AV_LOG_DEBUG, "Main profile bitstream\n"); - else if (ptl->profile_idc == AV_PROFILE_HEVC_MAIN_10) - av_log(avctx, AV_LOG_DEBUG, "Main 10 profile bitstream\n"); - else if (ptl->profile_idc == AV_PROFILE_HEVC_MAIN_STILL_PICTURE) - av_log(avctx, AV_LOG_DEBUG, "Main Still Picture profile bitstream\n"); - else if (ptl->profile_idc == AV_PROFILE_HEVC_REXT) - av_log(avctx, AV_LOG_DEBUG, "Range Extension profile bitstream\n"); - else if (ptl->profile_idc == AV_PROFILE_HEVC_SCC) - av_log(avctx, AV_LOG_DEBUG, "Screen Content Coding Extension profile bitstream\n"); - else - av_log(avctx, AV_LOG_WARNING, "Unknown HEVC profile: %d\n", ptl->profile_idc); + +#if !CONFIG_SMALL + 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"); for (i = 0; i < 32; i++) { ptl->profile_compatibility_flag[i] = get_bits1(gb); @@ -317,11 +311,17 @@ static int decode_profile_tier_level(GetBitContext *gb, AVCodecContext *avctx, } static int parse_ptl(GetBitContext *gb, AVCodecContext *avctx, - PTL *ptl, int max_num_sub_layers) + int profile_present, PTL *ptl, int max_num_sub_layers) { - int i; - if (decode_profile_tier_level(gb, avctx, &ptl->general_ptl) < 0 || - get_bits_left(gb) < 8 + (8*2 * (max_num_sub_layers - 1 > 0))) { + int i, status = 0; + + if (profile_present) { + status = decode_profile_tier_level(gb, avctx, &ptl->general_ptl); + } else { + memset(&ptl->general_ptl, 0, sizeof(ptl->general_ptl)); + } + + if (status < 0 || get_bits_left(gb) < 8 + (8*2 * (max_num_sub_layers - 1 > 0))) { av_log(avctx, AV_LOG_ERROR, "PTL information too short\n"); return -1; } @@ -442,18 +442,269 @@ static int decode_hrd(GetBitContext *gb, int common_inf_present, return 0; } -static void uninit_vps(FFRefStructOpaque opaque, void *obj) +static void hevc_vps_free(FFRefStructOpaque opaque, void *obj) { HEVCVPS *vps = obj; av_freep(&vps->hdr); + av_freep(&vps->data); } -static int compare_vps(const HEVCVPS *vps1, const HEVCVPS *vps2) +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, + HEVC_DEP_TYPE_BOTH = 2, +}; + +static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps, + uint64_t layer1_id_included) { - if (!memcmp(vps1, vps2, offsetof(HEVCVPS, hdr))) - return !vps1->vps_num_hrd_parameters || - !memcmp(vps1->hdr, vps2->hdr, vps1->vps_num_hrd_parameters * sizeof(*vps1->hdr)); + PTL ptl_dummy; + uint8_t max_sub_layers[HEVC_MAX_LAYERS]; + + int splitting_flag, dimension_id_len, view_id_len, num_add_olss, + 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) { + av_log(avctx, AV_LOG_VERBOSE, "Ignoring VPS extensions with a single layer\n"); + return 0; + } + + if (vps->vps_max_layers > 2) { + av_log(avctx, AV_LOG_ERROR, + "VPS has %d layers, only 2 layers are supported\n", + vps->vps_max_layers); + return AVERROR_PATCHWELCOME; + } + if (vps->vps_num_layer_sets > 2) { + av_log(avctx, AV_LOG_ERROR, + "VPS has %d layer sets, only 2 layer sets are supported\n", + vps->vps_num_layer_sets); + return AVERROR_PATCHWELCOME; + } + + align_get_bits(gb); + + /** + * For stereoscopic MV-HEVC, the following simplifying assumptions are made: + * + * - vps_max_layers = 2 (one base layer, one multiview layer) + * - vps_num_layer_sets = 2 (one output layer set for each view) + * - NumScalabilityTypes = 1 (only HEVC_SCALABILITY_MULTIVIEW) + * - direct_dependency_flag[1][0] = 1 (second layer depends on first) + * - num_add_olss = 0 (no extra output layer sets) + * - default_output_layer_idc = 0 (1:1 mapping between OLSs and layers) + * - layer_id_included_flag[1] = {1, 1} (consequence of layer dependencies) + * - vps_num_rep_formats_minus1 = 0 (all layers have the same size) + * + * Which results in the following derived variables: + * - ViewOrderIdx = {0, 1} + * - NumViews = 2 + * - DependencyFlag[1][0] = 1 + * - NumDirectRefLayers = {0, 1} + * - NumRefLayers = {0, 1} + * - NumPredictedLayers = {1, 0} + * - NumIndependentLayers = 1 + * - NumLayersInTreePartition = {2} + * - NumLayerSets = 2 + * - NumOutputLayerSets = 2 + * - OlsIdxToLsIdx = {0, 1} + * - LayerIdxInVps = {0, 1} + * - NumLayersInIdList = {1, 2} + * - NumNecessaryLayers = {1, 2} + * - NecessaryLayerFlag = {{1, 0}, {1, 1}} + * - NumOutputLayersInOutputLayerSet = {1, 2} + * - OutputLayerFlag = {{1, 0}, {1, 1}} + */ + vps->nb_layers = 2; + + 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; + } + } + + if (!splitting_flag) + dimension_id_len = get_bits(gb, 3) + 1; + + if (get_bits1(gb)) { /* vps_nuh_layer_id_present_flag */ + int layer_id_in_nuh = get_bits(gb, 6); + if (layer_id_in_nuh >= FF_ARRAY_ELEMS(vps->layer_idx)) { + av_log(avctx, AV_LOG_ERROR, "Invalid layer_id_in_nuh[1]: %d\n", + layer_id_in_nuh); + return AVERROR_INVALIDDATA; + } + vps->layer_idx[layer_id_in_nuh] = 1; + vps->layer_id_in_nuh[1] = layer_id_in_nuh; + } else { + vps->layer_idx[1] = 1; + vps->layer_id_in_nuh[1] = 1; + } + + 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); + return AVERROR_PATCHWELCOME; + } + } + + view_id_len = get_bits(gb, 4); + if (view_id_len) + for (int i = 0; i < 2 /* NumViews */; 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; + + 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 (get_bits1(gb) /* max_tid_ref_present_flag */) + skip_bits(gb, 3); // max_tid_il_ref_pics_plus1 + + vps->default_ref_layers_active = get_bits1(gb); + + nb_ptl = get_ue_golomb(gb) + 1; + /* idx [0] is signalled in base VPS, idx [1] is signalled at the + * start of VPS extension, indices 2+ are signalled here; + * we ignore all but the first one anyway */ + for (int i = 2; i < nb_ptl; i++) { + int profile_present = get_bits1(gb); + if (parse_ptl(gb, avctx, profile_present, &ptl_dummy, vps->vps_max_sub_layers) < 0) + return AVERROR_INVALIDDATA; + } + + num_add_olss = get_ue_golomb(gb); + if (num_add_olss != 0) { + /* Since we don't implement support for independent output layer sets + * and auxiliary layers, this should never nonzero */ + av_log(avctx, AV_LOG_ERROR, "Unexpected num_add_olss: %d\n", num_add_olss); + return AVERROR_PATCHWELCOME; + } + + default_output_layer_idc = get_bits(gb, 2); + if (default_output_layer_idc != 0) { + av_log(avctx, AV_LOG_WARNING, "Unsupported default_output_layer_idc: %d\n", + default_output_layer_idc); + return AVERROR_PATCHWELCOME; + } + + /* Consequence of established layer dependencies */ + if (layer1_id_included != ((1 << vps->layer_id_in_nuh[0]) | + (1 << vps->layer_id_in_nuh[1]))) { + av_log(avctx, AV_LOG_ERROR, "Dependent layer not included in layer ID?\n"); + return AVERROR_PATCHWELCOME; + } + + vps->num_output_layer_sets = 2; + vps->ols[1] = 3; + + 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) { + av_log(avctx, AV_LOG_ERROR, "Invalid PTL index: %d\n", ptl_idx); + return AVERROR_INVALIDDATA; + } + } + + if (get_ue_golomb_31(gb) != 0 /* vps_num_rep_formats_minus1 */) { + av_log(avctx, AV_LOG_ERROR, "Unexpected extra rep formats\n"); + return AVERROR_INVALIDDATA; + } + + vps->rep_format.pic_width_in_luma_samples = get_bits(gb, 16); + vps->rep_format.pic_height_in_luma_samples = get_bits(gb, 16); + + if (!get_bits1(gb) /* chroma_and_bit_depth_vps_present_flag */) { + av_log(avctx, AV_LOG_ERROR, + "chroma_and_bit_depth_vps_present_flag=0 in first rep_format\n"); + return AVERROR_INVALIDDATA; + } + vps->rep_format.chroma_format_idc = get_bits(gb, 2); + if (vps->rep_format.chroma_format_idc == 3) + vps->rep_format.separate_colour_plane_flag = get_bits1(gb); + vps->rep_format.bit_depth_luma = get_bits(gb, 4) + 8; + vps->rep_format.bit_depth_chroma = get_bits(gb, 4) + 8; + if (vps->rep_format.bit_depth_luma > 16 || + vps->rep_format.bit_depth_chroma > 16 || + vps->rep_format.bit_depth_luma != vps->rep_format.bit_depth_chroma) { + av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth: %"PRIu8" %"PRIu8"\n", + vps->rep_format.bit_depth_luma, vps->rep_format.bit_depth_chroma); + return AVERROR_PATCHWELCOME; + } + + if (get_bits1(gb) /* conformance_window_vps_flag */) { + int vert_mult = hevc_sub_height_c[vps->rep_format.chroma_format_idc]; + int horiz_mult = hevc_sub_width_c[vps->rep_format.chroma_format_idc]; + vps->rep_format.conf_win_left_offset = get_ue_golomb(gb) * horiz_mult; + vps->rep_format.conf_win_right_offset = get_ue_golomb(gb) * horiz_mult; + vps->rep_format.conf_win_top_offset = get_ue_golomb(gb) * vert_mult; + vps->rep_format.conf_win_bottom_offset = get_ue_golomb(gb) * vert_mult; + } + + vps->max_one_active_ref_layer = get_bits1(gb); + vps->poc_lsb_aligned = get_bits1(gb); + + sub_layer_flag_info_present_flag = get_bits1(gb); + for (int j = 0; j < FFMAX(max_sub_layers[0], max_sub_layers[1]); j++) { + int sub_layer_dpb_info_present_flag = 1; + if (j > 0 && sub_layer_flag_info_present_flag) + sub_layer_dpb_info_present_flag = get_bits1(gb); + if (sub_layer_dpb_info_present_flag) { + for (int k = 0; k < av_popcount64(vps->ols[1]); k++) + vps->dpb_size.max_dec_pic_buffering = get_ue_golomb_long(gb) + 1; + vps->dpb_size.max_num_reorder_pics = get_ue_golomb_long(gb); + vps->dpb_size.max_latency_increase = get_ue_golomb_long(gb) - 1; + } + } + + direct_dep_type_len = get_ue_golomb_31(gb) + 2; + if (direct_dep_type_len > 32) { + av_log(avctx, AV_LOG_ERROR, "Invalid direct_dep_type_len: %d\n", + direct_dep_type_len); + 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; + } + + non_vui_extension_length = get_ue_golomb(gb); + if (non_vui_extension_length > 4096) { + av_log(avctx, AV_LOG_ERROR, "vps_non_vui_extension_length too large: %u\n", + non_vui_extension_length); + return AVERROR_INVALIDDATA; + } + skip_bits_long(gb, non_vui_extension_length * 8); + + if (get_bits1(gb)) // vps_vui_present_flag + av_log(avctx, AV_LOG_WARNING, "VPS VUI not supported\n"); return 0; } @@ -461,28 +712,33 @@ static int compare_vps(const HEVCVPS *vps1, const HEVCVPS *vps2) int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, HEVCParamSets *ps) { - int i,j; - int vps_id = 0; - ptrdiff_t nal_size; - HEVCVPS *vps = ff_refstruct_alloc_ext(sizeof(*vps), 0, NULL, uninit_vps); + int i; + int vps_id = get_bits(gb, 4); + ptrdiff_t nal_size = gb->buffer_end - gb->buffer; + int ret = AVERROR_INVALIDDATA; + uint64_t layer1_id_included = 0; + HEVCVPS *vps; + if (ps->vps_list[vps_id]) { + const HEVCVPS *vps1 = ps->vps_list[vps_id]; + if (vps1->data_size == nal_size && + !memcmp(vps1->data, gb->buffer, vps1->data_size)) + return 0; + } + + vps = ff_refstruct_alloc_ext(sizeof(*vps), 0, NULL, hevc_vps_free); if (!vps) return AVERROR(ENOMEM); av_log(avctx, AV_LOG_DEBUG, "Decoding VPS\n"); - nal_size = gb->buffer_end - gb->buffer; - if (nal_size > sizeof(vps->data)) { - av_log(avctx, AV_LOG_WARNING, "Truncating likely oversized VPS " - "(%"PTRDIFF_SPECIFIER" > %"SIZE_SPECIFIER")\n", - nal_size, sizeof(vps->data)); - vps->data_size = sizeof(vps->data); - } else { - vps->data_size = nal_size; + vps->data_size = nal_size; + vps->data = av_memdup(gb->buffer, nal_size); + if (!vps->data) { + ret = AVERROR(ENOMEM); + goto err; } - memcpy(vps->data, gb->buffer, vps->data_size); - - vps_id = vps->vps_id = get_bits(gb, 4); + 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"); @@ -504,7 +760,7 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, goto err; } - if (parse_ptl(gb, avctx, &vps->ptl, vps->vps_max_sub_layers) < 0) + if (parse_ptl(gb, avctx, 1, &vps->ptl, vps->vps_max_sub_layers) < 0) goto err; vps->vps_sub_layer_ordering_info_present_flag = get_bits1(gb); @@ -536,9 +792,14 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, goto err; } - for (i = 1; i < vps->vps_num_layer_sets; i++) - for (j = 0; j <= vps->vps_max_layer_id; j++) - skip_bits(gb, 1); // layer_id_included_flag[i][j] + vps->num_output_layer_sets = 1; + vps->ols[0] = 1; + + // we support at most 2 layers, so ignore the others + if (vps->vps_num_layer_sets > 1) + layer1_id_included = get_bits64(gb, vps->vps_max_layer_id + 1); // layer_id_included_flag + if (vps->vps_num_layer_sets > 2) + skip_bits_long(gb, (vps->vps_num_layer_sets - 2) * (vps->vps_max_layer_id + 1)); vps->vps_timing_info_present_flag = get_bits1(gb); if (vps->vps_timing_info_present_flag) { @@ -570,7 +831,21 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, vps->vps_max_sub_layers); } } - get_bits1(gb); /* vps_extension_flag */ + + vps->nb_layers = 1; + vps->layer_idx[0] = 0; + for (int i = 1; i < FF_ARRAY_ELEMS(vps->layer_idx); i++) + vps->layer_idx[i] = -1; + + if (vps->vps_max_layers > 1 && get_bits1(gb)) { /* vps_extension_flag */ + int ret = decode_vps_ext(gb, avctx, vps, layer1_id_included); + if (ret == AVERROR_PATCHWELCOME) { + vps->nb_layers = 1; + av_log(avctx, AV_LOG_WARNING, "Ignoring unsupported VPS extension\n"); + ret = 0; + } else if (ret < 0) + goto err; + } if (get_bits_left(gb) < 0) { av_log(avctx, AV_LOG_ERROR, @@ -579,19 +854,14 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, goto err; } - if (ps->vps_list[vps_id] && - compare_vps(ps->vps_list[vps_id], vps)) { - ff_refstruct_unref(&vps); - } else { - remove_vps(ps, vps_id); - ps->vps_list[vps_id] = vps; - } + remove_vps(ps, vps_id); + ps->vps_list[vps_id] = vps; return 0; err: ff_refstruct_unref(&vps); - return AVERROR_INVALIDDATA; + return ret; } static void decode_vui(GetBitContext *gb, AVCodecContext *avctx, @@ -878,35 +1148,51 @@ static int map_pixel_format(AVCodecContext *avctx, HEVCSPS *sps) } int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, - int apply_defdispwin, const HEVCVPS * const *vps_list, - AVCodecContext *avctx) + unsigned nuh_layer_id, int apply_defdispwin, + const HEVCVPS * const *vps_list, AVCodecContext *avctx) { HEVCWindow *ow; int ret = 0; - int bit_depth_chroma, start, num_comps; + int bit_depth_chroma, num_comps, multi_layer_ext; int i; // Coded parameters sps->vps_id = get_bits(gb, 4); - if (vps_list && !vps_list[sps->vps_id]) { - av_log(avctx, AV_LOG_ERROR, "VPS %d does not exist\n", - sps->vps_id); - return AVERROR_INVALIDDATA; + if (vps_list) { + if (!vps_list[sps->vps_id]) { + av_log(avctx, AV_LOG_ERROR, "VPS %d does not exist\n", + sps->vps_id); + return AVERROR_INVALIDDATA; + } + sps->vps = ff_refstruct_ref_c(vps_list[sps->vps_id]); } sps->max_sub_layers = get_bits(gb, 3) + 1; + multi_layer_ext = nuh_layer_id > 0 && + sps->max_sub_layers == HEVC_MAX_SUB_LAYERS + 1; + if (multi_layer_ext) { + if (!sps->vps) + return AVERROR(EINVAL); + + sps->max_sub_layers = sps->vps->vps_max_sub_layers; + } if (sps->max_sub_layers > HEVC_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; } - sps->temporal_id_nesting_flag = get_bits(gb, 1); + if (!multi_layer_ext) { + sps->temporal_id_nesting = get_bits(gb, 1); - if ((ret = parse_ptl(gb, avctx, &sps->ptl, sps->max_sub_layers)) < 0) - return ret; + if ((ret = parse_ptl(gb, avctx, 1, &sps->ptl, sps->max_sub_layers)) < 0) + return ret; + } else { + sps->temporal_id_nesting = sps->max_sub_layers > 1 ? + sps->vps->vps_max_sub_layers : 1; + } *sps_id = get_ue_golomb_long(gb); if (*sps_id >= HEVC_MAX_SPS_COUNT) { @@ -914,70 +1200,94 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, return AVERROR_INVALIDDATA; } - sps->chroma_format_idc = get_ue_golomb_long(gb); - if (sps->chroma_format_idc > 3U) { - av_log(avctx, AV_LOG_ERROR, "chroma_format_idc %d is invalid\n", sps->chroma_format_idc); - return AVERROR_INVALIDDATA; - } + if (multi_layer_ext) { + const RepFormat *rf = &sps->vps->rep_format; - if (sps->chroma_format_idc == 3) - sps->separate_colour_plane_flag = get_bits1(gb); - - if (sps->separate_colour_plane_flag) - sps->chroma_format_idc = 0; - - sps->width = get_ue_golomb_long(gb); - sps->height = get_ue_golomb_long(gb); - if ((ret = av_image_check_size(sps->width, - sps->height, 0, avctx)) < 0) - return ret; - - sps->conformance_window_flag = get_bits1(gb); - if (sps->conformance_window_flag) { - int vert_mult = hevc_sub_height_c[sps->chroma_format_idc]; - int horiz_mult = hevc_sub_width_c[sps->chroma_format_idc]; - sps->pic_conf_win.left_offset = get_ue_golomb_long(gb) * horiz_mult; - sps->pic_conf_win.right_offset = get_ue_golomb_long(gb) * horiz_mult; - sps->pic_conf_win.top_offset = get_ue_golomb_long(gb) * vert_mult; - sps->pic_conf_win.bottom_offset = get_ue_golomb_long(gb) * vert_mult; - - if (avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) { - av_log(avctx, AV_LOG_DEBUG, - "discarding sps conformance window, " - "original values are l:%u r:%u t:%u b:%u\n", - sps->pic_conf_win.left_offset, - sps->pic_conf_win.right_offset, - sps->pic_conf_win.top_offset, - sps->pic_conf_win.bottom_offset); - - sps->pic_conf_win.left_offset = - sps->pic_conf_win.right_offset = - sps->pic_conf_win.top_offset = - sps->pic_conf_win.bottom_offset = 0; + 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"); + return AVERROR_PATCHWELCOME; } - sps->output_window = sps->pic_conf_win; + + sps->separate_colour_plane = rf->separate_colour_plane_flag; + sps->chroma_format_idc = sps->separate_colour_plane ? 0 : + rf->chroma_format_idc; + sps->bit_depth = rf->bit_depth_luma; + sps->width = rf->pic_width_in_luma_samples; + sps->height = rf->pic_height_in_luma_samples; + + sps->pic_conf_win.left_offset = rf->conf_win_left_offset; + sps->pic_conf_win.right_offset = rf->conf_win_right_offset; + sps->pic_conf_win.top_offset = rf->conf_win_top_offset; + sps->pic_conf_win.bottom_offset = rf->conf_win_bottom_offset; + + } else { + sps->chroma_format_idc = get_ue_golomb_long(gb); + if (sps->chroma_format_idc > 3U) { + av_log(avctx, AV_LOG_ERROR, "chroma_format_idc %d is invalid\n", sps->chroma_format_idc); + return AVERROR_INVALIDDATA; + } + + if (sps->chroma_format_idc == 3) + sps->separate_colour_plane = get_bits1(gb); + + if (sps->separate_colour_plane) + sps->chroma_format_idc = 0; + + sps->width = get_ue_golomb_long(gb); + sps->height = get_ue_golomb_long(gb); + if ((ret = av_image_check_size(sps->width, + sps->height, 0, avctx)) < 0) + return ret; + + sps->conformance_window = get_bits1(gb); + if (sps->conformance_window) { + int vert_mult = hevc_sub_height_c[sps->chroma_format_idc]; + int horiz_mult = hevc_sub_width_c[sps->chroma_format_idc]; + sps->pic_conf_win.left_offset = get_ue_golomb_long(gb) * horiz_mult; + sps->pic_conf_win.right_offset = get_ue_golomb_long(gb) * horiz_mult; + sps->pic_conf_win.top_offset = get_ue_golomb_long(gb) * vert_mult; + sps->pic_conf_win.bottom_offset = get_ue_golomb_long(gb) * vert_mult; + + if (avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) { + av_log(avctx, AV_LOG_DEBUG, + "discarding sps conformance window, " + "original values are l:%u r:%u t:%u b:%u\n", + sps->pic_conf_win.left_offset, + sps->pic_conf_win.right_offset, + sps->pic_conf_win.top_offset, + sps->pic_conf_win.bottom_offset); + + sps->pic_conf_win.left_offset = + sps->pic_conf_win.right_offset = + sps->pic_conf_win.top_offset = + sps->pic_conf_win.bottom_offset = 0; + } + } + + sps->bit_depth = get_ue_golomb_31(gb) + 8; + if (sps->bit_depth > 16) { + av_log(avctx, AV_LOG_ERROR, "Luma bit depth (%d) is out of range\n", + sps->bit_depth); + return AVERROR_INVALIDDATA; + } + bit_depth_chroma = get_ue_golomb_31(gb) + 8; + if (bit_depth_chroma > 16) { + av_log(avctx, AV_LOG_ERROR, "Chroma bit depth (%d) is out of range\n", + bit_depth_chroma); + return AVERROR_INVALIDDATA; + } + if (sps->chroma_format_idc && bit_depth_chroma != sps->bit_depth) { + av_log(avctx, AV_LOG_ERROR, + "Luma bit depth (%d) is different from chroma bit depth (%d), " + "this is unsupported.\n", + sps->bit_depth, bit_depth_chroma); + return AVERROR_INVALIDDATA; + } + sps->bit_depth_chroma = bit_depth_chroma; } - sps->bit_depth = get_ue_golomb_31(gb) + 8; - if (sps->bit_depth > 16) { - av_log(avctx, AV_LOG_ERROR, "Luma bit depth (%d) is out of range\n", - sps->bit_depth); - return AVERROR_INVALIDDATA; - } - bit_depth_chroma = get_ue_golomb_31(gb) + 8; - if (bit_depth_chroma > 16) { - av_log(avctx, AV_LOG_ERROR, "Chroma bit depth (%d) is out of range\n", - bit_depth_chroma); - return AVERROR_INVALIDDATA; - } - if (sps->chroma_format_idc && bit_depth_chroma != sps->bit_depth) { - av_log(avctx, AV_LOG_ERROR, - "Luma bit depth (%d) is different from chroma bit depth (%d), " - "this is unsupported.\n", - sps->bit_depth, bit_depth_chroma); - return AVERROR_INVALIDDATA; - } - sps->bit_depth_chroma = bit_depth_chroma; + sps->output_window = sps->pic_conf_win; ret = map_pixel_format(avctx, sps); if (ret < 0) @@ -990,33 +1300,43 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, return AVERROR_INVALIDDATA; } - sps->sublayer_ordering_info_flag = get_bits1(gb); - start = sps->sublayer_ordering_info_flag ? 0 : sps->max_sub_layers - 1; - for (i = start; i < sps->max_sub_layers; i++) { - sps->temporal_layer[i].max_dec_pic_buffering = get_ue_golomb_long(gb) + 1; - sps->temporal_layer[i].num_reorder_pics = get_ue_golomb_long(gb); - sps->temporal_layer[i].max_latency_increase = get_ue_golomb_long(gb) - 1; - if (sps->temporal_layer[i].max_dec_pic_buffering > (unsigned)HEVC_MAX_DPB_SIZE) { - av_log(avctx, AV_LOG_ERROR, "sps_max_dec_pic_buffering_minus1 out of range: %d\n", - sps->temporal_layer[i].max_dec_pic_buffering - 1U); - return AVERROR_INVALIDDATA; - } - if (sps->temporal_layer[i].num_reorder_pics > sps->temporal_layer[i].max_dec_pic_buffering - 1) { - av_log(avctx, AV_LOG_WARNING, "sps_max_num_reorder_pics out of range: %d\n", - sps->temporal_layer[i].num_reorder_pics); - if (avctx->err_recognition & AV_EF_EXPLODE || - sps->temporal_layer[i].num_reorder_pics > HEVC_MAX_DPB_SIZE - 1) { + if (!multi_layer_ext) { + int start; + + sps->sublayer_ordering_info = get_bits1(gb); + start = sps->sublayer_ordering_info ? 0 : sps->max_sub_layers - 1; + for (i = start; i < sps->max_sub_layers; i++) { + sps->temporal_layer[i].max_dec_pic_buffering = get_ue_golomb_long(gb) + 1; + sps->temporal_layer[i].num_reorder_pics = get_ue_golomb_long(gb); + sps->temporal_layer[i].max_latency_increase = get_ue_golomb_long(gb) - 1; + if (sps->temporal_layer[i].max_dec_pic_buffering > (unsigned)HEVC_MAX_DPB_SIZE) { + av_log(avctx, AV_LOG_ERROR, "sps_max_dec_pic_buffering_minus1 out of range: %d\n", + sps->temporal_layer[i].max_dec_pic_buffering - 1U); return AVERROR_INVALIDDATA; } - sps->temporal_layer[i].max_dec_pic_buffering = sps->temporal_layer[i].num_reorder_pics + 1; + if (sps->temporal_layer[i].num_reorder_pics > sps->temporal_layer[i].max_dec_pic_buffering - 1) { + av_log(avctx, AV_LOG_WARNING, "sps_max_num_reorder_pics out of range: %d\n", + sps->temporal_layer[i].num_reorder_pics); + if (avctx->err_recognition & AV_EF_EXPLODE || + sps->temporal_layer[i].num_reorder_pics > HEVC_MAX_DPB_SIZE - 1) { + return AVERROR_INVALIDDATA; + } + sps->temporal_layer[i].max_dec_pic_buffering = sps->temporal_layer[i].num_reorder_pics + 1; + } } - } - if (!sps->sublayer_ordering_info_flag) { - for (i = 0; i < start; i++) { - sps->temporal_layer[i].max_dec_pic_buffering = sps->temporal_layer[start].max_dec_pic_buffering; - sps->temporal_layer[i].num_reorder_pics = sps->temporal_layer[start].num_reorder_pics; - sps->temporal_layer[i].max_latency_increase = sps->temporal_layer[start].max_latency_increase; + if (!sps->sublayer_ordering_info) { + for (i = 0; i < start; i++) { + sps->temporal_layer[i].max_dec_pic_buffering = sps->temporal_layer[start].max_dec_pic_buffering; + sps->temporal_layer[i].num_reorder_pics = sps->temporal_layer[start].num_reorder_pics; + sps->temporal_layer[i].max_latency_increase = sps->temporal_layer[start].max_latency_increase; + } + } + } else { + for (int i = 0; i < sps->max_sub_layers; i++) { + sps->temporal_layer[i].max_dec_pic_buffering = sps->vps->dpb_size.max_dec_pic_buffering; + sps->temporal_layer[i].num_reorder_pics = sps->vps->dpb_size.max_num_reorder_pics; + sps->temporal_layer[i].max_latency_increase = sps->vps->dpb_size.max_latency_increase; } } @@ -1051,10 +1371,15 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->max_transform_hierarchy_depth_inter = get_ue_golomb_long(gb); sps->max_transform_hierarchy_depth_intra = get_ue_golomb_long(gb); - sps->scaling_list_enable_flag = get_bits1(gb); - if (sps->scaling_list_enable_flag) { + sps->scaling_list_enabled = get_bits1(gb); + if (sps->scaling_list_enabled) { set_default_scaling_list_data(&sps->scaling_list); + if (multi_layer_ext && get_bits1(gb)) { // sps_infer_scaling_list_flag + av_log(avctx, AV_LOG_ERROR, "sps_infer_scaling_list_flag=1 not supported\n"); + return AVERROR_PATCHWELCOME; + } + if (get_bits1(gb)) { ret = scaling_list_data(gb, avctx, &sps->scaling_list, sps); if (ret < 0) @@ -1062,11 +1387,11 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, } } - sps->amp_enabled_flag = get_bits1(gb); - sps->sao_enabled = get_bits1(gb); + sps->amp_enabled = get_bits1(gb); + sps->sao_enabled = get_bits1(gb); - sps->pcm_enabled_flag = get_bits1(gb); - if (sps->pcm_enabled_flag) { + sps->pcm_enabled = get_bits1(gb); + if (sps->pcm_enabled) { sps->pcm.bit_depth = get_bits(gb, 4) + 1; sps->pcm.bit_depth_chroma = get_bits(gb, 4) + 1; sps->pcm.log2_min_pcm_cb_size = get_ue_golomb_long(gb) + 3; @@ -1079,7 +1404,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, return AVERROR_INVALIDDATA; } - sps->pcm.loop_filter_disable_flag = get_bits1(gb); + sps->pcm_loop_filter_disabled = get_bits1(gb); } sps->nb_st_rps = get_ue_golomb_long(gb); @@ -1094,68 +1419,67 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, return ret; } - sps->long_term_ref_pics_present_flag = get_bits1(gb); - if (sps->long_term_ref_pics_present_flag) { + sps->long_term_ref_pics_present = get_bits1(gb); + if (sps->long_term_ref_pics_present) { sps->num_long_term_ref_pics_sps = get_ue_golomb_long(gb); if (sps->num_long_term_ref_pics_sps > HEVC_MAX_LONG_TERM_REF_PICS) { av_log(avctx, AV_LOG_ERROR, "Too many long term ref pics: %d.\n", sps->num_long_term_ref_pics_sps); return AVERROR_INVALIDDATA; } + + sps->used_by_curr_pic_lt = 0; for (i = 0; i < sps->num_long_term_ref_pics_sps; i++) { sps->lt_ref_pic_poc_lsb_sps[i] = get_bits(gb, sps->log2_max_poc_lsb); - sps->used_by_curr_pic_lt_sps_flag[i] = get_bits1(gb); + sps->used_by_curr_pic_lt |= get_bits1(gb) << i; } } - sps->sps_temporal_mvp_enabled_flag = get_bits1(gb); - sps->sps_strong_intra_smoothing_enable_flag = get_bits1(gb); + sps->temporal_mvp_enabled = get_bits1(gb); + sps->strong_intra_smoothing_enabled = get_bits1(gb); sps->vui.common.sar = (AVRational){0, 1}; sps->vui_present = get_bits1(gb); if (sps->vui_present) decode_vui(gb, avctx, apply_defdispwin, sps); - sps->sps_extension_present_flag = get_bits1(gb); - if (sps->sps_extension_present_flag) { - sps->sps_range_extension_flag = get_bits1(gb); - sps->sps_multilayer_extension_flag = get_bits1(gb); - sps->sps_3d_extension_flag = get_bits1(gb); - sps->sps_scc_extension_flag = get_bits1(gb); + sps->extension_present = get_bits1(gb); + if (sps->extension_present) { + sps->range_extension = get_bits1(gb); + sps->multilayer_extension = get_bits1(gb); + sps->sps_3d_extension = get_bits1(gb); + sps->scc_extension = get_bits1(gb); skip_bits(gb, 4); // sps_extension_4bits - if (sps->sps_range_extension_flag) { - sps->transform_skip_rotation_enabled_flag = get_bits1(gb); - sps->transform_skip_context_enabled_flag = get_bits1(gb); - sps->implicit_rdpcm_enabled_flag = get_bits1(gb); + if (sps->range_extension) { + sps->transform_skip_rotation_enabled = get_bits1(gb); + sps->transform_skip_context_enabled = get_bits1(gb); + sps->implicit_rdpcm_enabled = get_bits1(gb); + sps->explicit_rdpcm_enabled = get_bits1(gb); - sps->explicit_rdpcm_enabled_flag = get_bits1(gb); - - sps->extended_precision_processing_flag = get_bits1(gb); - if (sps->extended_precision_processing_flag) + sps->extended_precision_processing = get_bits1(gb); + if (sps->extended_precision_processing) av_log(avctx, AV_LOG_WARNING, "extended_precision_processing_flag not yet implemented\n"); - sps->intra_smoothing_disabled_flag = get_bits1(gb); - sps->high_precision_offsets_enabled_flag = get_bits1(gb); - if (sps->high_precision_offsets_enabled_flag) + sps->intra_smoothing_disabled = get_bits1(gb); + sps->high_precision_offsets_enabled = get_bits1(gb); + if (sps->high_precision_offsets_enabled) av_log(avctx, AV_LOG_WARNING, "high_precision_offsets_enabled_flag not yet implemented\n"); - sps->persistent_rice_adaptation_enabled_flag = get_bits1(gb); + sps->persistent_rice_adaptation_enabled = get_bits1(gb); - sps->cabac_bypass_alignment_enabled_flag = get_bits1(gb); - if (sps->cabac_bypass_alignment_enabled_flag) + sps->cabac_bypass_alignment_enabled = get_bits1(gb); + if (sps->cabac_bypass_alignment_enabled) av_log(avctx, AV_LOG_WARNING, "cabac_bypass_alignment_enabled_flag not yet implemented\n"); } - if (sps->sps_multilayer_extension_flag) { + if (sps->multilayer_extension) { skip_bits1(gb); // inter_view_mv_vert_constraint_flag - av_log(avctx, AV_LOG_WARNING, - "sps_multilayer_extension_flag not yet implemented\n"); } - if (sps->sps_3d_extension_flag) { + if (sps->sps_3d_extension) { for (i = 0; i <= 1; i++) { skip_bits1(gb); // iv_di_mc_enabled_flag skip_bits1(gb); // iv_mv_scal_enabled_flag @@ -1179,15 +1503,15 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, "sps_3d_extension_flag not yet implemented\n"); } - if (sps->sps_scc_extension_flag) { - sps->sps_curr_pic_ref_enabled_flag = get_bits1(gb); - sps->palette_mode_enabled_flag = get_bits1(gb); - if (sps->palette_mode_enabled_flag) { + if (sps->scc_extension) { + sps->curr_pic_ref_enabled = get_bits1(gb); + sps->palette_mode_enabled = get_bits1(gb); + if (sps->palette_mode_enabled) { sps->palette_max_size = get_ue_golomb(gb); sps->delta_palette_max_predictor_size = get_ue_golomb(gb); - sps->sps_palette_predictor_initializers_present_flag = get_bits1(gb); + sps->palette_predictor_initializers_present = get_bits1(gb); - if (sps->sps_palette_predictor_initializers_present_flag) { + if (sps->palette_predictor_initializers_present) { sps->sps_num_palette_predictor_initializers = get_ue_golomb(gb) + 1; if (sps->sps_num_palette_predictor_initializers > HEVC_MAX_PALETTE_PREDICTOR_SIZE) { av_log(avctx, AV_LOG_ERROR, @@ -1204,7 +1528,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, } } sps->motion_vector_resolution_control_idc = get_bits(gb, 2); - sps->intra_boundary_filtering_disabled_flag = get_bits1(gb); + sps->intra_boundary_filtering_disabled = get_bits1(gb); } } if (apply_defdispwin) { @@ -1262,8 +1586,8 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->qp_bd_offset = 6 * (sps->bit_depth - 8); - if (av_mod_uintp2(sps->width, sps->log2_min_cb_size) || - av_mod_uintp2(sps->height, sps->log2_min_cb_size)) { + if (av_zero_extend(sps->width, sps->log2_min_cb_size) || + av_zero_extend(sps->height, sps->log2_min_cb_size)) { av_log(avctx, AV_LOG_ERROR, "Invalid coded frame dimensions.\n"); return AVERROR_INVALIDDATA; } @@ -1294,37 +1618,46 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, return 0; } -int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, - HEVCParamSets *ps, int apply_defdispwin) +static void hevc_sps_free(FFRefStructOpaque opaque, void *obj) { - HEVCSPS *sps = ff_refstruct_allocz(sizeof(*sps)); + HEVCSPS *sps = obj; + + ff_refstruct_unref(&sps->vps); + + av_freep(&sps->data); +} + +static int compare_sps(const HEVCSPS *sps1, const HEVCSPS *sps2) +{ + return sps1->data_size == sps2->data_size && + !memcmp(sps1->data, sps2->data, sps1->data_size); +} + +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); unsigned int sps_id; int ret; - ptrdiff_t nal_size; if (!sps) return AVERROR(ENOMEM); av_log(avctx, AV_LOG_DEBUG, "Decoding SPS\n"); - nal_size = gb->buffer_end - gb->buffer; - if (nal_size > sizeof(sps->data)) { - av_log(avctx, AV_LOG_WARNING, "Truncating likely oversized SPS " - "(%"PTRDIFF_SPECIFIER" > %"SIZE_SPECIFIER")\n", - nal_size, sizeof(sps->data)); - sps->data_size = sizeof(sps->data); - } else { - sps->data_size = nal_size; + sps->data_size = gb->buffer_end - gb->buffer; + sps->data = av_memdup(gb->buffer, sps->data_size); + if (!sps->data) { + ret = AVERROR(ENOMEM); + goto err; } - memcpy(sps->data, gb->buffer, sps->data_size); ret = ff_hevc_parse_sps(sps, gb, &sps_id, - apply_defdispwin, + nuh_layer_id, apply_defdispwin, ps->vps_list, avctx); - if (ret < 0) { - ff_refstruct_unref(&sps); - return ret; - } + if (ret < 0) + goto err; if (avctx->debug & FF_DEBUG_BITSTREAM) { av_log(avctx, AV_LOG_DEBUG, @@ -1340,7 +1673,7 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, * original one. * otherwise drop all PPSes that depend on it */ if (ps->sps_list[sps_id] && - !memcmp(ps->sps_list[sps_id], sps, sizeof(*sps))) { + compare_sps(ps->sps_list[sps_id], sps)) { ff_refstruct_unref(&sps); } else { remove_sps(ps, sps_id); @@ -1348,12 +1681,17 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, } return 0; +err: + ff_refstruct_unref(&sps); + return ret; } static void hevc_pps_free(FFRefStructOpaque unused, void *obj) { HEVCPPS *pps = obj; + ff_refstruct_unref(&pps->sps); + av_freep(&pps->column_width); av_freep(&pps->row_height); av_freep(&pps->col_bd); @@ -1364,6 +1702,7 @@ static void hevc_pps_free(FFRefStructOpaque unused, void *obj) av_freep(&pps->tile_pos_rs); av_freep(&pps->tile_id); av_freep(&pps->min_tb_addr_zs_tab); + av_freep(&pps->data); } static void colour_mapping_octants(GetBitContext *gb, HEVCPPS *pps, int inp_depth, @@ -1762,27 +2101,35 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, const HEVCSPS *sps = NULL; const HEVCVPS *vps = NULL; int i, ret = 0; - unsigned int pps_id = 0; - ptrdiff_t nal_size; + ptrdiff_t nal_size = gb->buffer_end - gb->buffer; + unsigned int pps_id = get_ue_golomb_long(gb); unsigned log2_parallel_merge_level_minus2; - - HEVCPPS *pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, hevc_pps_free); - - if (!pps) - return AVERROR(ENOMEM); + HEVCPPS *pps; av_log(avctx, AV_LOG_DEBUG, "Decoding PPS\n"); - nal_size = gb->buffer_end - gb->buffer; - if (nal_size > sizeof(pps->data)) { - av_log(avctx, AV_LOG_WARNING, "Truncating likely oversized PPS " - "(%"PTRDIFF_SPECIFIER" > %"SIZE_SPECIFIER")\n", - nal_size, sizeof(pps->data)); - pps->data_size = sizeof(pps->data); - } else { - pps->data_size = nal_size; + if (pps_id >= HEVC_MAX_PPS_COUNT) { + av_log(avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", pps_id); + return AVERROR_INVALIDDATA; + } + + if (ps->pps_list[pps_id]) { + const HEVCPPS *pps1 = ps->pps_list[pps_id]; + if (pps1->data_size == nal_size && + !memcmp(pps1->data, gb->buffer, pps1->data_size)) + return 0; + } + + pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, hevc_pps_free); + if (!pps) + return AVERROR(ENOMEM); + + pps->data_size = nal_size; + pps->data = av_memdup(gb->buffer, nal_size); + if (!pps->data) { + ret = AVERROR_INVALIDDATA; + goto err; } - memcpy(pps->data, gb->buffer, pps->data_size); // Default values pps->loop_filter_across_tiles_enabled_flag = 1; @@ -1795,12 +2142,7 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, pps->log2_max_transform_skip_block_size = 2; // Coded parameters - pps_id = pps->pps_id = get_ue_golomb_long(gb); - if (pps_id >= HEVC_MAX_PPS_COUNT) { - av_log(avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", pps_id); - ret = AVERROR_INVALIDDATA; - goto err; - } + pps->pps_id = pps_id; pps->sps_id = get_ue_golomb_long(gb); if (pps->sps_id >= HEVC_MAX_SPS_COUNT) { av_log(avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", pps->sps_id); @@ -1815,6 +2157,8 @@ 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->dependent_slice_segments_enabled_flag = get_bits1(gb); pps->output_flag_present_flag = get_bits1(gb); pps->num_extra_slice_header_bits = get_bits(gb, 3); @@ -2013,7 +2357,7 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, "Overread PPS by %d bits\n", -get_bits_left(gb)); } - remove_pps(ps, pps_id); + ff_refstruct_unref(&ps->pps_list[pps_id]); ps->pps_list[pps_id] = pps; return 0; @@ -2033,10 +2377,6 @@ void ff_hevc_ps_uninit(HEVCParamSets *ps) ff_refstruct_unref(&ps->sps_list[i]); for (i = 0; i < FF_ARRAY_ELEMS(ps->pps_list); i++) ff_refstruct_unref(&ps->pps_list[i]); - - ps->sps = NULL; - ps->pps = NULL; - ps->vps = NULL; } int ff_hevc_compute_poc(const HEVCSPS *sps, int pocTid0, int poc_lsb, int nal_unit_type) diff --git a/libavcodec/hevc_ps.h b/libavcodec/hevc/ps.h similarity index 77% rename from libavcodec/hevc_ps.h rename to libavcodec/hevc/ps.h index 0d8eaf2b3..6f5b1f875 100644 --- a/libavcodec/hevc_ps.h +++ b/libavcodec/hevc/ps.h @@ -26,11 +26,14 @@ #include "libavutil/pixfmt.h" #include "libavutil/rational.h" -#include "avcodec.h" -#include "get_bits.h" -#include "h2645_vui.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/get_bits.h" +#include "libavcodec/h2645_vui.h" + #include "hevc.h" +#define HEVC_VPS_MAX_LAYERS 2 + typedef struct HEVCSublayerHdrParams { uint32_t bit_rate_value_minus1[HEVC_MAX_CPB_CNT]; uint32_t cpb_size_value_minus1[HEVC_MAX_CPB_CNT]; @@ -70,18 +73,19 @@ typedef struct HEVCHdrParams { } HEVCHdrParams; typedef struct ShortTermRPS { - uint8_t rps_predict; - unsigned int delta_idx; - uint8_t use_delta_flag; - uint8_t delta_rps_sign; - unsigned int abs_delta_rps; - unsigned int num_negative_pics; - int num_delta_pocs; - int rps_idx_num_delta_pocs; - int32_t delta_poc_s0[32]; - int32_t delta_poc_s1[32]; int32_t delta_poc[32]; - uint8_t used[32]; + uint32_t used; + + uint8_t delta_idx; + uint8_t num_negative_pics; + uint8_t num_delta_pocs; + uint8_t rps_idx_num_delta_pocs; + + uint16_t abs_delta_rps; + unsigned delta_rps_sign:1; + + unsigned rps_predict:1; + unsigned use_delta:1; } ShortTermRPS; typedef struct HEVCWindow { @@ -151,6 +155,19 @@ typedef struct PTL { uint8_t sub_layer_level_present_flag[HEVC_MAX_SUB_LAYERS]; } PTL; +typedef struct RepFormat { + uint16_t pic_width_in_luma_samples; + uint16_t pic_height_in_luma_samples; + uint8_t chroma_format_idc; + uint8_t separate_colour_plane_flag; + uint8_t bit_depth_luma; ///< bit_depth_vps_luma_minus8 + 8 + uint8_t bit_depth_chroma; ///< bit_depth_vps_chroma_minus8 + 8 + uint16_t conf_win_left_offset; + uint16_t conf_win_right_offset; + uint16_t conf_win_top_offset; + uint16_t conf_win_bottom_offset; +} RepFormat; + typedef struct HEVCVPS { unsigned int vps_id; @@ -172,11 +189,57 @@ typedef struct HEVCVPS { int vps_num_ticks_poc_diff_one; ///< vps_num_ticks_poc_diff_one_minus1 + 1 int vps_num_hrd_parameters; - uint8_t data[4096]; - int data_size; - /* Put this at the end of the structure to make it easier to calculate the - * size before this pointer, which is used for memcmp */ HEVCHdrParams *hdr; + + /* VPS extension */ + + /* Number of layers this VPS was parsed for, between 1 and + * min(HEVC_VPS_MAX_LAYERS, vps_max_layers). + * + * Note that vps_max_layers contains the layer count declared in the + * bitstream, while nb_layers contains the number of layers exported to + * users of this API (which may be smaller as we only support a subset of + * multilayer extensions). + * + * Arrays below documented as [layer_idx] have nb_layers valid entries. + */ + int nb_layers; + + // 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. + int8_t layer_idx[HEVC_MAX_NUH_LAYER_ID + 1]; + + uint8_t layer_id_in_nuh[HEVC_VPS_MAX_LAYERS]; + + uint8_t default_ref_layers_active; + uint8_t max_one_active_ref_layer; + uint8_t poc_lsb_aligned; + // bitmask of poc_lsb_not_present[layer_idx] + uint8_t poc_lsb_not_present; + + struct { + unsigned max_dec_pic_buffering; // max_vps_dec_pic_buffering_minus1 + 1 + unsigned max_num_reorder_pics; // max_vps_num_reorder_pics + unsigned max_latency_increase; // max_vps_latency_increase_plus1 - 1 + } dpb_size; + + // ViewId[layer_idx] + uint16_t view_id[HEVC_VPS_MAX_LAYERS]; + + // NumOutputLayerSets + uint8_t num_output_layer_sets; + // Bitmasks specifying output layer sets. i-th bit set means layer with VPS + // index i is present in the layer set. + uint64_t ols[HEVC_VPS_MAX_LAYERS]; + + // NumDirectRefLayers[layer_idx] + uint8_t num_direct_ref_layers[HEVC_VPS_MAX_LAYERS]; + + RepFormat rep_format; + + uint8_t *data; + int data_size; } HEVCVPS; typedef struct ScalingList { @@ -189,11 +252,9 @@ typedef struct ScalingList { typedef struct HEVCSPS { unsigned vps_id; int chroma_format_idc; - uint8_t separate_colour_plane_flag; HEVCWindow output_window; - uint8_t conformance_window_flag; HEVCWindow pic_conf_win; HEVCHdrParams hdr; @@ -204,34 +265,25 @@ typedef struct HEVCSPS { enum AVPixelFormat pix_fmt; unsigned int log2_max_poc_lsb; - int pcm_enabled_flag; - uint8_t sublayer_ordering_info_flag; int max_sub_layers; struct { int max_dec_pic_buffering; int num_reorder_pics; int max_latency_increase; } temporal_layer[HEVC_MAX_SUB_LAYERS]; - uint8_t temporal_id_nesting_flag; int vui_present; VUI vui; PTL ptl; - uint8_t sps_extension_present_flag; - uint8_t scaling_list_enable_flag; ScalingList scaling_list; unsigned int nb_st_rps; ShortTermRPS st_rps[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; - uint8_t amp_enabled_flag; - uint8_t sao_enabled; - - uint8_t long_term_ref_pics_present_flag; uint16_t lt_ref_pic_poc_lsb_sps[HEVC_MAX_LONG_TERM_REF_PICS]; - uint8_t used_by_curr_pic_lt_sps_flag[HEVC_MAX_LONG_TERM_REF_PICS]; + uint32_t used_by_curr_pic_lt; uint8_t num_long_term_ref_pics_sps; struct { @@ -239,10 +291,7 @@ typedef struct HEVCSPS { uint8_t bit_depth_chroma; unsigned int log2_min_pcm_cb_size; unsigned int log2_max_pcm_cb_size; - uint8_t loop_filter_disable_flag; } pcm; - uint8_t sps_temporal_mvp_enabled_flag; - uint8_t sps_strong_intra_smoothing_enable_flag; unsigned int log2_min_cb_size; unsigned int log2_diff_max_min_coding_block_size; @@ -255,30 +304,44 @@ typedef struct HEVCSPS { int max_transform_hierarchy_depth_inter; int max_transform_hierarchy_depth_intra; - int sps_range_extension_flag; - int transform_skip_rotation_enabled_flag; - int transform_skip_context_enabled_flag; - int implicit_rdpcm_enabled_flag; - int explicit_rdpcm_enabled_flag; - int extended_precision_processing_flag; - int intra_smoothing_disabled_flag; - int high_precision_offsets_enabled_flag; - int persistent_rice_adaptation_enabled_flag; - int cabac_bypass_alignment_enabled_flag; + uint8_t separate_colour_plane; + uint8_t conformance_window; + uint8_t pcm_enabled; + uint8_t pcm_loop_filter_disabled; + uint8_t sublayer_ordering_info; + uint8_t temporal_id_nesting; + uint8_t extension_present; + uint8_t scaling_list_enabled; + uint8_t amp_enabled; + uint8_t sao_enabled; + uint8_t long_term_ref_pics_present; + uint8_t temporal_mvp_enabled; + uint8_t strong_intra_smoothing_enabled; + uint8_t range_extension; + uint8_t transform_skip_rotation_enabled; + uint8_t transform_skip_context_enabled; + uint8_t implicit_rdpcm_enabled; + uint8_t explicit_rdpcm_enabled; + uint8_t extended_precision_processing; + uint8_t intra_smoothing_disabled; + uint8_t high_precision_offsets_enabled; + uint8_t persistent_rice_adaptation_enabled; + uint8_t cabac_bypass_alignment_enabled; - int sps_multilayer_extension_flag; - int sps_3d_extension_flag; + uint8_t multilayer_extension; + uint8_t sps_3d_extension; + + uint8_t scc_extension; + uint8_t curr_pic_ref_enabled; + uint8_t palette_mode_enabled; + uint8_t palette_predictor_initializers_present; + uint8_t intra_boundary_filtering_disabled; - int sps_scc_extension_flag; - int sps_curr_pic_ref_enabled_flag; - int palette_mode_enabled_flag; int palette_max_size; int delta_palette_max_predictor_size; - int sps_palette_predictor_initializers_present_flag; int sps_num_palette_predictor_initializers; int sps_palette_predictor_initializer[3][HEVC_MAX_PALETTE_PREDICTOR_SIZE]; int motion_vector_resolution_control_idc; - int intra_boundary_filtering_disabled_flag; ///< coded frame dimension in various units int width; @@ -299,8 +362,10 @@ typedef struct HEVCSPS { int qp_bd_offset; - uint8_t data[4096]; + uint8_t *data; int data_size; + + const HEVCVPS *vps; ///< RefStruct reference } HEVCSPS; typedef struct HEVCPPS { @@ -434,19 +499,16 @@ typedef struct HEVCPPS { int *min_tb_addr_zs; ///< MinTbAddrZS int *min_tb_addr_zs_tab;///< MinTbAddrZS - uint8_t data[4096]; + uint8_t *data; int data_size; + + const HEVCSPS *sps; ///< RefStruct reference } HEVCPPS; typedef struct HEVCParamSets { const HEVCVPS *vps_list[HEVC_MAX_VPS_COUNT]; ///< RefStruct references const HEVCSPS *sps_list[HEVC_MAX_SPS_COUNT]; ///< RefStruct references const HEVCPPS *pps_list[HEVC_MAX_PPS_COUNT]; ///< RefStruct references - - /* currently active parameter sets */ - const HEVCVPS *vps; - const HEVCSPS *sps; - const HEVCPPS *pps; } HEVCParamSets; /** @@ -459,13 +521,14 @@ typedef struct HEVCParamSets { * to an existing VPS */ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, - int apply_defdispwin, const HEVCVPS * const *vps_list, - AVCodecContext *avctx); + unsigned nuh_layer_id, int apply_defdispwin, + const HEVCVPS * const *vps_list, AVCodecContext *avctx); int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx, HEVCParamSets *ps); int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, - HEVCParamSets *ps, int apply_defdispwin); + HEVCParamSets *ps, unsigned nuh_layer_id, + int apply_defdispwin); int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, HEVCParamSets *ps); diff --git a/libavcodec/hevc_ps_enc.c b/libavcodec/hevc/ps_enc.c similarity index 99% rename from libavcodec/hevc_ps_enc.c rename to libavcodec/hevc/ps_enc.c index 72641b2ff..7fbcb3ba4 100644 --- a/libavcodec/hevc_ps_enc.c +++ b/libavcodec/hevc/ps_enc.c @@ -19,7 +19,7 @@ */ #include "put_golomb.h" -#include "hevc_ps.h" +#include "ps.h" #include "put_bits.h" static void write_ptl_layer(PutBitContext *pb, PTLCommon *ptl) diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c new file mode 100644 index 000000000..6ba667e9f --- /dev/null +++ b/libavcodec/hevc/refs.c @@ -0,0 +1,588 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2012 - 2013 Gildas Cocherel + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/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" + +void ff_hevc_unref_frame(HEVCFrame *frame, int flags) +{ + frame->flags &= ~flags; + 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); + + ff_refstruct_unref(&frame->rpl); + frame->nb_rpl_elems = 0; + ff_refstruct_unref(&frame->rpl_tab); + frame->refPicList = NULL; + + ff_refstruct_unref(&frame->hwaccel_picture_private); + } +} + +const RefPicList *ff_hevc_get_ref_list(const HEVCFrame *ref, int x0, int y0) +{ + const HEVCSPS *sps = ref->pps->sps; + int x_cb = x0 >> sps->log2_ctb_size; + int y_cb = y0 >> sps->log2_ctb_size; + int pic_width_cb = sps->ctb_width; + int ctb_addr_ts = ref->pps->ctb_addr_rs_to_ts[y_cb * pic_width_cb + x_cb]; + return &ref->rpl_tab[ctb_addr_ts]->refPicList[0]; +} + +void ff_hevc_clear_refs(HEVCLayerContext *l) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) + ff_hevc_unref_frame(&l->DPB[i], + HEVC_FRAME_FLAG_SHORT_REF | + HEVC_FRAME_FLAG_LONG_REF); +} + +void ff_hevc_flush_dpb(HEVCContext *s) +{ + for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) { + HEVCLayerContext *l = &s->layers[layer]; + for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) + ff_hevc_unref_frame(&l->DPB[i], ~0); + } +} + +static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) +{ + const HEVCVPS *vps = l->sps->vps; + const int view_id = vps->view_id[s->cur_layer]; + int i, j, ret; + for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + HEVCFrame *frame = &l->DPB[i]; + if (frame->f) + continue; + + ret = ff_progress_frame_alloc(s->avctx, &frame->tf); + if (ret < 0) + return NULL; + + // Add LCEVC SEI metadata here, as it's needed in get_buffer() + if (s->sei.common.lcevc.info) { + HEVCSEILCEVC *lcevc = &s->sei.common.lcevc; + ret = ff_frame_new_side_data_from_buf(s->avctx, frame->tf.f, + AV_FRAME_DATA_LCEVC, &lcevc->info); + if (ret < 0) + goto fail; + } + + // add view ID side data if it's nontrivial + if (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, + AV_FRAME_DATA_VIEW_ID, + sizeof(int), 0); + if (!sd) + goto fail; + *(int*)sd->data = view_id; + + if (tdrdi->num_ref_displays) { + AVStereo3D *stereo_3d; + + stereo_3d = av_stereo3d_create_side_data(frame->f); + if (!stereo_3d) + goto fail; + + stereo_3d->type = AV_STEREO3D_FRAMESEQUENCE; + if (tdrdi->left_view_id[0] == view_id) + stereo_3d->view = AV_STEREO3D_VIEW_LEFT; + else if (tdrdi->right_view_id[0] == view_id) + stereo_3d->view = AV_STEREO3D_VIEW_RIGHT; + else + stereo_3d->view = AV_STEREO3D_VIEW_UNSPEC; + } + } + + ret = ff_progress_frame_get_buffer(s->avctx, &frame->tf, + AV_GET_BUFFER_FLAG_REF); + if (ret < 0) + return NULL; + + frame->rpl = ff_refstruct_allocz(s->pkt.nb_nals * sizeof(*frame->rpl)); + if (!frame->rpl) + goto fail; + frame->nb_rpl_elems = s->pkt.nb_nals; + + frame->tab_mvf = ff_refstruct_pool_get(l->tab_mvf_pool); + if (!frame->tab_mvf) + goto fail; + + frame->rpl_tab = ff_refstruct_pool_get(l->rpl_tab_pool); + if (!frame->rpl_tab) + goto fail; + frame->ctb_count = l->sps->ctb_width * l->sps->ctb_height; + for (j = 0; j < frame->ctb_count; j++) + frame->rpl_tab[j] = frame->rpl; + + if (s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) + frame->f->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; + if ((s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) || + (s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD)) + frame->f->flags |= AV_FRAME_FLAG_INTERLACED; + + ret = ff_hwaccel_frame_priv_alloc(s->avctx, &frame->hwaccel_picture_private); + if (ret < 0) + goto fail; + + frame->pps = ff_refstruct_ref_c(s->pps); + + return frame; +fail: + ff_hevc_unref_frame(frame, ~0); + return NULL; + } + av_log(s->avctx, AV_LOG_ERROR, "Error allocating frame, DPB full.\n"); + return NULL; +} + +int ff_hevc_set_new_ref(HEVCContext *s, HEVCLayerContext *l, int poc) +{ + HEVCFrame *ref; + int i; + + /* check that this POC doesn't already exist */ + for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + HEVCFrame *frame = &l->DPB[i]; + + if (frame->f && frame->poc == poc) { + av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: %d.\n", + poc); + return AVERROR_INVALIDDATA; + } + } + + ref = alloc_frame(s, l); + if (!ref) + return AVERROR(ENOMEM); + + s->cur_frame = ref; + l->cur_frame = ref; + s->collocated_ref = NULL; + + 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) + ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF; + else + ref->flags = HEVC_FRAME_FLAG_SHORT_REF; + + ref->poc = poc; + ref->f->crop_left = l->sps->output_window.left_offset; + ref->f->crop_right = l->sps->output_window.right_offset; + ref->f->crop_top = l->sps->output_window.top_offset; + ref->f->crop_bottom = l->sps->output_window.bottom_offset; + + return 0; +} + +static void unref_missing_refs(HEVCLayerContext *l) +{ + for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + HEVCFrame *frame = &l->DPB[i]; + if (frame->flags & HEVC_FRAME_FLAG_UNAVAILABLE) { + ff_hevc_unref_frame(frame, ~0); + } + } +} + +int ff_hevc_output_frames(HEVCContext *s, + unsigned layers_active_decode, unsigned layers_active_output, + unsigned max_output, unsigned max_dpb, int discard) +{ + while (1) { + int nb_dpb[HEVC_VPS_MAX_LAYERS] = { 0 }; + int nb_output = 0; + int min_poc = INT_MAX; + int min_layer = -1; + int min_idx, ret = 0; + + for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) { + HEVCLayerContext *l = &s->layers[layer]; + + if (!(layers_active_decode & (1 << layer))) + continue; + + for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + HEVCFrame *frame = &l->DPB[i]; + if (frame->flags & HEVC_FRAME_FLAG_OUTPUT) { + // nb_output counts AUs with an output-pending frame + // in at least one layer + if (!(frame->base_layer_frame >= 0 && + (s->layers[0].DPB[frame->base_layer_frame].flags & HEVC_FRAME_FLAG_OUTPUT))) + nb_output++; + if (min_layer < 0 || frame->poc < min_poc) { + min_poc = frame->poc; + min_idx = i; + min_layer = layer; + } + } + nb_dpb[layer] += !!frame->flags; + } + } + + if (nb_output > max_output || + (nb_output && + (nb_dpb[0] > max_dpb || nb_dpb[1] > max_dpb))) { + HEVCFrame *frame = &s->layers[min_layer].DPB[min_idx]; + AVFrame *f = frame->needs_fg ? frame->frame_grain : frame->f; + int output = !discard && (layers_active_output & (1 << min_layer)); + + if (output) { + f->pkt_dts = s->pkt_dts; + ret = ff_container_fifo_write(s->output_fifo, f); + } + ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT); + if (ret < 0) + return ret; + + av_log(s->avctx, AV_LOG_DEBUG, "%s frame with POC %d/%d.\n", + output ? "Output" : "Discarded", min_layer, frame->poc); + continue; + } + return 0; + } +} + +static int init_slice_rpl(HEVCContext *s) +{ + HEVCFrame *frame = s->cur_frame; + int ctb_count = frame->ctb_count; + int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[s->sh.slice_segment_addr]; + int i; + + if (s->slice_idx >= frame->nb_rpl_elems) + return AVERROR_INVALIDDATA; + + for (i = ctb_addr_ts; i < ctb_count; i++) + frame->rpl_tab[i] = frame->rpl + s->slice_idx; + + frame->refPicList = (RefPicList *)frame->rpl_tab[ctb_addr_ts]; + + return 0; +} + +int ff_hevc_slice_rpl(HEVCContext *s) +{ + SliceHeader *sh = &s->sh; + + uint8_t nb_list = sh->slice_type == HEVC_SLICE_B ? 2 : 1; + uint8_t list_idx; + int i, j, ret; + + ret = init_slice_rpl(s); + if (ret < 0) + return ret; + + if (!(s->rps[ST_CURR_BEF].nb_refs + s->rps[ST_CURR_AFT].nb_refs + + s->rps[LT_CURR].nb_refs + + s->rps[INTER_LAYER0].nb_refs + s->rps[INTER_LAYER1].nb_refs) && + !s->pps->pps_curr_pic_ref_enabled_flag) { + av_log(s->avctx, AV_LOG_ERROR, "Zero refs in the frame RPS.\n"); + return AVERROR_INVALIDDATA; + } + + for (list_idx = 0; list_idx < nb_list; list_idx++) { + RefPicList rpl_tmp = { { 0 } }; + RefPicList *rpl = &s->cur_frame->refPicList[list_idx]; + + /* The order of the elements is + * ST_CURR_BEF - INTER_LAYER0 - ST_CURR_AFT - LT_CURR - INTER_LAYER1 for the L0 and + * ST_CURR_AFT - INTER_LAYER1 - ST_CURR_BEF - LT_CURR - INTER_LAYER0 for the L1 */ + int cand_lists[] = { list_idx ? ST_CURR_AFT : ST_CURR_BEF, + list_idx ? INTER_LAYER1 : INTER_LAYER0, + list_idx ? ST_CURR_BEF : ST_CURR_AFT, + LT_CURR, + list_idx ? INTER_LAYER0 : INTER_LAYER1 + }; + + /* concatenate the candidate lists for the current frame */ + while (rpl_tmp.nb_refs < sh->nb_refs[list_idx]) { + for (i = 0; i < FF_ARRAY_ELEMS(cand_lists); i++) { + RefPicList *rps = &s->rps[cand_lists[i]]; + for (j = 0; j < rps->nb_refs && rpl_tmp.nb_refs < HEVC_MAX_REFS; j++) { + rpl_tmp.list[rpl_tmp.nb_refs] = rps->list[j]; + rpl_tmp.ref[rpl_tmp.nb_refs] = rps->ref[j]; + // multiview inter-layer refs are treated as long-term here, + // cf. G.8.1.3 + rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = cand_lists[i] == LT_CURR || + cand_lists[i] == INTER_LAYER0 || + cand_lists[i] == INTER_LAYER1; + rpl_tmp.nb_refs++; + } + } + // Construct RefPicList0, RefPicList1 (8-8, 8-10) + if (s->pps->pps_curr_pic_ref_enabled_flag && rpl_tmp.nb_refs < HEVC_MAX_REFS) { + rpl_tmp.list[rpl_tmp.nb_refs] = s->cur_frame->poc; + rpl_tmp.ref[rpl_tmp.nb_refs] = s->cur_frame; + rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = 1; + rpl_tmp.nb_refs++; + } + } + + /* reorder the references if necessary */ + if (sh->rpl_modification_flag[list_idx]) { + for (i = 0; i < sh->nb_refs[list_idx]; i++) { + int idx = sh->list_entry_lx[list_idx][i]; + + if (idx >= rpl_tmp.nb_refs) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid reference index.\n"); + return AVERROR_INVALIDDATA; + } + + rpl->list[i] = rpl_tmp.list[idx]; + rpl->ref[i] = rpl_tmp.ref[idx]; + rpl->isLongTerm[i] = rpl_tmp.isLongTerm[idx]; + rpl->nb_refs++; + } + } else { + memcpy(rpl, &rpl_tmp, sizeof(*rpl)); + rpl->nb_refs = FFMIN(rpl->nb_refs, sh->nb_refs[list_idx]); + } + + // 8-9 + if (s->pps->pps_curr_pic_ref_enabled_flag && + !sh->rpl_modification_flag[list_idx] && + rpl_tmp.nb_refs > sh->nb_refs[L0]) { + rpl->list[sh->nb_refs[L0] - 1] = s->cur_frame->poc; + rpl->ref[sh->nb_refs[L0] - 1] = s->cur_frame; + } + + if (sh->collocated_list == list_idx && + sh->collocated_ref_idx < rpl->nb_refs) + s->collocated_ref = rpl->ref[sh->collocated_ref_idx]; + } + + return 0; +} + +static HEVCFrame *find_ref_idx(HEVCContext *s, HEVCLayerContext *l, + int poc, uint8_t use_msb) +{ + int mask = use_msb ? ~0 : (1 << l->sps->log2_max_poc_lsb) - 1; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + HEVCFrame *ref = &l->DPB[i]; + if (ref->f) { + if ((ref->poc & mask) == poc && (use_msb || ref->poc != s->poc)) + return ref; + } + } + + if (s->nal_unit_type != HEVC_NAL_CRA_NUT && !IS_BLA(s)) + av_log(s->avctx, AV_LOG_ERROR, + "Could not find ref with POC %d\n", poc); + return NULL; +} + +static void mark_ref(HEVCFrame *frame, int flag) +{ + frame->flags &= ~(HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF); + frame->flags |= flag; +} + +static HEVCFrame *generate_missing_ref(HEVCContext *s, HEVCLayerContext *l, int poc) +{ + HEVCFrame *frame; + int i, y; + + frame = alloc_frame(s, l); + if (!frame) + return NULL; + + if (!s->avctx->hwaccel) { + if (!l->sps->pixel_shift) { + for (i = 0; frame->f->data[i]; i++) + memset(frame->f->data[i], 1 << (l->sps->bit_depth - 1), + frame->f->linesize[i] * AV_CEIL_RSHIFT(l->sps->height, l->sps->vshift[i])); + } else { + for (i = 0; frame->f->data[i]; i++) + for (y = 0; y < (l->sps->height >> l->sps->vshift[i]); y++) { + uint8_t *dst = frame->f->data[i] + y * frame->f->linesize[i]; + AV_WN16(dst, 1 << (l->sps->bit_depth - 1)); + av_memcpy_backptr(dst + 2, 2, 2*(l->sps->width >> l->sps->hshift[i]) - 2); + } + } + } + + frame->poc = poc; + frame->flags = HEVC_FRAME_FLAG_UNAVAILABLE; + + if (s->avctx->active_thread_type == FF_THREAD_FRAME) + ff_progress_frame_report(&frame->tf, INT_MAX); + + return frame; +} + +/* add a reference with the given poc to the list and mark it as used in DPB */ +static int add_candidate_ref(HEVCContext *s, HEVCLayerContext *l, + RefPicList *list, + int poc, int ref_flag, uint8_t use_msb) +{ + HEVCFrame *ref = find_ref_idx(s, l, poc, use_msb); + + if (ref == s->cur_frame || list->nb_refs >= HEVC_MAX_REFS) + return AVERROR_INVALIDDATA; + + if (!ref) { + ref = generate_missing_ref(s, l, poc); + if (!ref) + return AVERROR(ENOMEM); + } + + list->list[list->nb_refs] = ref->poc; + list->ref[list->nb_refs] = ref; + list->nb_refs++; + + mark_ref(ref, ref_flag); + return 0; +} + +int ff_hevc_frame_rps(HEVCContext *s, HEVCLayerContext *l) +{ + const ShortTermRPS *short_rps = s->sh.short_term_rps; + const LongTermRPS *long_rps = &s->sh.long_term_rps; + RefPicList *rps = s->rps; + int i, ret = 0; + + unref_missing_refs(l); + + /* clear the reference flags on all frames except the current one */ + for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + HEVCFrame *frame = &l->DPB[i]; + + if (frame == s->cur_frame) + continue; + + mark_ref(frame, 0); + } + + for (i = 0; i < NB_RPS_TYPE; i++) + rps[i].nb_refs = 0; + + if (!short_rps) + goto inter_layer; + + /* add the short refs */ + for (i = 0; i < short_rps->num_delta_pocs; i++) { + int poc = s->poc + short_rps->delta_poc[i]; + int list; + + if (!(short_rps->used & (1 << i))) + list = ST_FOLL; + else if (i < short_rps->num_negative_pics) + list = ST_CURR_BEF; + else + list = ST_CURR_AFT; + + ret = add_candidate_ref(s, l, &rps[list], poc, + HEVC_FRAME_FLAG_SHORT_REF, 1); + if (ret < 0) + goto fail; + } + + /* add the long refs */ + for (i = 0; i < long_rps->nb_refs; i++) { + int poc = long_rps->poc[i]; + int list = long_rps->used[i] ? LT_CURR : LT_FOLL; + + ret = add_candidate_ref(s, l, &rps[list], poc, + HEVC_FRAME_FLAG_LONG_REF, long_rps->poc_msb_present[i]); + if (ret < 0) + goto fail; + } + +inter_layer: + /* add inter-layer refs */ + if (s->sh.inter_layer_pred) { + HEVCLayerContext *l0 = &s->layers[0]; + + av_assert0(l != l0); + + /* Given the assumption of at most two layers, refPicSet0Flag is + * always 1, so only RefPicSetInterLayer0 can ever contain a frame. */ + if (l0->cur_frame) { + // inter-layer refs are treated as short-term here, cf. F.8.1.6 + ret = add_candidate_ref(s, l0, &rps[INTER_LAYER0], l0->cur_frame->poc, + HEVC_FRAME_FLAG_SHORT_REF, 1); + if (ret < 0) + goto fail; + } + } + +fail: + /* release any frames that are now unused */ + for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) + ff_hevc_unref_frame(&l->DPB[i], 0); + + return ret; +} + +int ff_hevc_frame_nb_refs(const SliceHeader *sh, const HEVCPPS *pps, + unsigned layer_idx) +{ + int ret = 0; + int i; + const ShortTermRPS *rps = sh->short_term_rps; + const LongTermRPS *long_rps = &sh->long_term_rps; + + if (rps) { + for (i = 0; i < rps->num_negative_pics; i++) + ret += !!(rps->used & (1 << i)); + for (; i < rps->num_delta_pocs; i++) + ret += !!(rps->used & (1 << i)); + } + + if (long_rps) { + 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); + ret++; + } + + if (pps->pps_curr_pic_ref_enabled_flag) + ret++; + + return ret; +} diff --git a/libavcodec/hevc_sei.c b/libavcodec/hevc/sei.c similarity index 78% rename from libavcodec/hevc_sei.c rename to libavcodec/hevc/sei.c index abdb52acd..e11a33773 100644 --- a/libavcodec/hevc_sei.c +++ b/libavcodec/hevc/sei.c @@ -24,8 +24,8 @@ #include "bytestream.h" #include "golomb.h" -#include "hevc_ps.h" -#include "hevc_sei.h" +#include "ps.h" +#include "sei.h" static int decode_nal_sei_decoded_picture_hash(HEVCSEIPictureHash *s, GetByteContext *gb) @@ -56,7 +56,7 @@ static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb, const HEVCSPS *sps = ps->sps_list[s->active_seq_parameter_set_id]; if (!sps) - return(AVERROR(ENOMEM)); + return AVERROR_INVALIDDATA; if (sps->vui.frame_field_info_present_flag) { int pic_struct = get_bits(gb, 4); @@ -150,6 +150,59 @@ static int decode_nal_sei_timecode(HEVCSEITimeCode *s, GetBitContext *gb) return 0; } +static int decode_nal_sei_3d_reference_displays_info(HEVCSEITDRDI *s, GetBitContext *gb) +{ + s->prec_ref_display_width = get_ue_golomb(gb); + if (s->prec_ref_display_width > 31) + return AVERROR_INVALIDDATA; + s->ref_viewing_distance_flag = get_bits1(gb); + if (s->ref_viewing_distance_flag) { + s->prec_ref_viewing_dist = get_ue_golomb(gb); + if (s->prec_ref_viewing_dist > 31) + return AVERROR_INVALIDDATA; + } + s->num_ref_displays = get_ue_golomb(gb); + if (s->num_ref_displays > 31) + return AVERROR_INVALIDDATA; + s->num_ref_displays += 1; + + for (int i = 0; i < s->num_ref_displays; i++) { + int length; + s->left_view_id[i] = get_ue_golomb(gb); + s->right_view_id[i] = get_ue_golomb(gb); + s->exponent_ref_display_width[i] = get_bits(gb, 6); + if (s->exponent_ref_display_width[i] > 62) + return AVERROR_INVALIDDATA; + else if (!s->exponent_ref_display_width[i]) + length = FFMAX(0, (int)s->prec_ref_display_width - 30); + else + length = FFMAX(0, (int)s->exponent_ref_display_width[i] + + (int)s->prec_ref_display_width - 31); + s->mantissa_ref_display_width[i] = get_bits_long(gb, length); + if (s->ref_viewing_distance_flag) { + s->exponent_ref_viewing_distance[i] = get_bits(gb, 6); + if (s->exponent_ref_viewing_distance[i] > 62) + return AVERROR_INVALIDDATA; + else if (!s->exponent_ref_viewing_distance[i]) + length = FFMAX(0, (int)s->prec_ref_viewing_dist - 30); + else + length = FFMAX(0, (int)s->exponent_ref_viewing_distance[i] + + (int)s->prec_ref_viewing_dist - 31); + s->mantissa_ref_viewing_distance[i] = get_bits_long(gb, length); + } + s->additional_shift_present_flag[i] = get_bits1(gb); + if (s->additional_shift_present_flag[i]) { + s->num_sample_shift[i] = get_bits(gb, 10); + if (s->num_sample_shift[i] > 1023) + return AVERROR_INVALIDDATA; + s->num_sample_shift[i] -= 512; + } + } + s->three_dimensional_reference_displays_extension_flag = get_bits1(gb); + + return 0; +} + static int decode_nal_sei_prefix(GetBitContext *gb, GetByteContext *gbyte, void *logctx, HEVCSEI *s, const HEVCParamSets *ps, int type) @@ -163,6 +216,8 @@ static int decode_nal_sei_prefix(GetBitContext *gb, GetByteContext *gbyte, return decode_nal_sei_active_parameter_sets(s, gb, logctx); case SEI_TYPE_TIME_CODE: return decode_nal_sei_timecode(&s->timecode, gb); + case SEI_TYPE_THREE_DIMENSIONAL_REFERENCE_DISPLAYS_INFO: + return decode_nal_sei_3d_reference_displays_info(&s->tdrdi, gb); default: { int ret = ff_h2645_sei_message_decode(&s->common, type, AV_CODEC_ID_HEVC, gb, gbyte, logctx); diff --git a/libavcodec/hevc_sei.h b/libavcodec/hevc/sei.h similarity index 81% rename from libavcodec/hevc_sei.h rename to libavcodec/hevc/sei.h index a23a64ec4..806540fac 100644 --- a/libavcodec/hevc_sei.h +++ b/libavcodec/hevc/sei.h @@ -25,10 +25,11 @@ #include "libavutil/buffer.h" -#include "get_bits.h" +#include "libavcodec/get_bits.h" +#include "libavcodec/h2645_sei.h" +#include "libavcodec/sei.h" + #include "hevc.h" -#include "h2645_sei.h" -#include "sei.h" typedef enum { @@ -78,12 +79,29 @@ typedef struct HEVCSEITimeCode { int32_t time_offset_value[3]; } HEVCSEITimeCode; +typedef struct HEVCSEITDRDI { + uint8_t prec_ref_display_width; + uint8_t ref_viewing_distance_flag; + uint8_t prec_ref_viewing_dist; + uint8_t num_ref_displays; + uint16_t left_view_id[32]; + uint16_t right_view_id[32]; + uint8_t exponent_ref_display_width[32]; + uint8_t mantissa_ref_display_width[32]; + uint8_t exponent_ref_viewing_distance[32]; + uint8_t mantissa_ref_viewing_distance[32]; + uint8_t additional_shift_present_flag[32]; + int16_t num_sample_shift[32]; + uint8_t three_dimensional_reference_displays_extension_flag; +} HEVCSEITDRDI; + typedef struct HEVCSEI { H2645SEI common; HEVCSEIPictureHash picture_hash; HEVCSEIPictureTiming picture_timing; int active_seq_parameter_set_id; HEVCSEITimeCode timecode; + HEVCSEITDRDI tdrdi; } HEVCSEI; struct HEVCParamSets; diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c deleted file mode 100644 index 54e3d40e1..000000000 --- a/libavcodec/hevc_refs.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * HEVC video decoder - * - * Copyright (C) 2012 - 2013 Guillaume Martres - * Copyright (C) 2012 - 2013 Gildas Cocherel - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "libavutil/avassert.h" - -#include "decode.h" -#include "thread.h" -#include "hevc.h" -#include "hevcdec.h" -#include "refstruct.h" -#include "threadframe.h" - -void ff_hevc_unref_frame(HEVCFrame *frame, int flags) -{ - /* frame->frame can be NULL if context init failed */ - if (!frame->frame || !frame->frame->buf[0]) - return; - - frame->flags &= ~flags; - if (!frame->flags) { - ff_thread_release_ext_buffer(&frame->tf); - av_frame_unref(frame->frame_grain); - frame->needs_fg = 0; - - ff_refstruct_unref(&frame->tab_mvf); - - ff_refstruct_unref(&frame->rpl); - frame->nb_rpl_elems = 0; - ff_refstruct_unref(&frame->rpl_tab); - frame->refPicList = NULL; - - ff_refstruct_unref(&frame->hwaccel_picture_private); - } -} - -const RefPicList *ff_hevc_get_ref_list(const HEVCContext *s, - const HEVCFrame *ref, int x0, int y0) -{ - int x_cb = x0 >> s->ps.sps->log2_ctb_size; - int y_cb = y0 >> s->ps.sps->log2_ctb_size; - int pic_width_cb = s->ps.sps->ctb_width; - int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[y_cb * pic_width_cb + x_cb]; - return &ref->rpl_tab[ctb_addr_ts]->refPicList[0]; -} - -void ff_hevc_clear_refs(HEVCContext *s) -{ - int i; - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) - ff_hevc_unref_frame(&s->DPB[i], - HEVC_FRAME_FLAG_SHORT_REF | - HEVC_FRAME_FLAG_LONG_REF); -} - -void ff_hevc_flush_dpb(HEVCContext *s) -{ - int i; - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) - ff_hevc_unref_frame(&s->DPB[i], ~0); -} - -static HEVCFrame *alloc_frame(HEVCContext *s) -{ - int i, j, ret; - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *frame = &s->DPB[i]; - if (frame->frame->buf[0]) - continue; - - ret = ff_thread_get_ext_buffer(s->avctx, &frame->tf, - AV_GET_BUFFER_FLAG_REF); - if (ret < 0) - return NULL; - - frame->rpl = ff_refstruct_allocz(s->pkt.nb_nals * sizeof(*frame->rpl)); - if (!frame->rpl) - goto fail; - frame->nb_rpl_elems = s->pkt.nb_nals; - - frame->tab_mvf = ff_refstruct_pool_get(s->tab_mvf_pool); - if (!frame->tab_mvf) - goto fail; - - frame->rpl_tab = ff_refstruct_pool_get(s->rpl_tab_pool); - if (!frame->rpl_tab) - goto fail; - frame->ctb_count = s->ps.sps->ctb_width * s->ps.sps->ctb_height; - for (j = 0; j < frame->ctb_count; j++) - frame->rpl_tab[j] = frame->rpl; - - if (s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) - frame->frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; - if ((s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) || - (s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD)) - frame->frame->flags |= AV_FRAME_FLAG_INTERLACED; - - ret = ff_hwaccel_frame_priv_alloc(s->avctx, &frame->hwaccel_picture_private); - if (ret < 0) - goto fail; - - return frame; -fail: - ff_hevc_unref_frame(frame, ~0); - return NULL; - } - av_log(s->avctx, AV_LOG_ERROR, "Error allocating frame, DPB full.\n"); - return NULL; -} - -int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc) -{ - HEVCFrame *ref; - int i; - - /* check that this POC doesn't already exist */ - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *frame = &s->DPB[i]; - - if (frame->frame->buf[0] && frame->sequence == s->seq_decode && - frame->poc == poc) { - av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: %d.\n", - poc); - return AVERROR_INVALIDDATA; - } - } - - ref = alloc_frame(s); - if (!ref) - return AVERROR(ENOMEM); - - *frame = ref->frame; - s->ref = ref; - s->collocated_ref = NULL; - - if (s->sh.pic_output_flag) - ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF; - else - ref->flags = HEVC_FRAME_FLAG_SHORT_REF; - - ref->poc = poc; - ref->sequence = s->seq_decode; - ref->frame->crop_left = s->ps.sps->output_window.left_offset; - ref->frame->crop_right = s->ps.sps->output_window.right_offset; - ref->frame->crop_top = s->ps.sps->output_window.top_offset; - ref->frame->crop_bottom = s->ps.sps->output_window.bottom_offset; - - return 0; -} - -static void unref_missing_refs(HEVCContext *s) -{ - for (int i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *frame = &s->DPB[i]; - if (frame->sequence == HEVC_SEQUENCE_COUNTER_INVALID) { - ff_hevc_unref_frame(frame, ~0); - } - } -} - -int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush) -{ - if (IS_IRAP(s) && s->no_rasl_output_flag == 1) { - const static int mask = HEVC_FRAME_FLAG_BUMPING | HEVC_FRAME_FLAG_OUTPUT; - for (int i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *frame = &s->DPB[i]; - if ((frame->flags & mask) == HEVC_FRAME_FLAG_OUTPUT && - frame->sequence != s->seq_decode) { - if (s->sh.no_output_of_prior_pics_flag == 1) - ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT); - else - frame->flags |= HEVC_FRAME_FLAG_BUMPING; - } - } - } - do { - int nb_output = 0; - int min_poc = INT_MAX; - int i, min_idx, ret; - - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *frame = &s->DPB[i]; - if ((frame->flags & HEVC_FRAME_FLAG_OUTPUT) && - frame->sequence == s->seq_output) { - nb_output++; - if (frame->poc < min_poc || nb_output == 1) { - min_poc = frame->poc; - min_idx = i; - } - } - } - - /* wait for more frames before output */ - if (!flush && s->seq_output == s->seq_decode && s->ps.sps && - nb_output <= s->ps.sps->temporal_layer[s->ps.sps->max_sub_layers - 1].num_reorder_pics) - return 0; - - if (nb_output) { - HEVCFrame *frame = &s->DPB[min_idx]; - - ret = av_frame_ref(out, frame->needs_fg ? frame->frame_grain : frame->frame); - if (frame->flags & HEVC_FRAME_FLAG_BUMPING) - ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_BUMPING); - else - ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT); - if (ret < 0) - return ret; - - if (frame->needs_fg && (ret = av_frame_copy_props(out, frame->frame)) < 0) - return ret; - - if (!(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) - av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS); - - av_log(s->avctx, AV_LOG_DEBUG, - "Output frame with POC %d.\n", frame->poc); - return 1; - } - - if (s->seq_output != s->seq_decode) - s->seq_output = (s->seq_output + 1) & HEVC_SEQUENCE_COUNTER_MASK; - else - break; - } while (1); - - return 0; -} - -void ff_hevc_bump_frame(HEVCContext *s) -{ - int dpb = 0; - int min_poc = INT_MAX; - int i; - - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *frame = &s->DPB[i]; - if ((frame->flags) && - frame->sequence == s->seq_output && - frame->poc != s->poc) { - dpb++; - } - } - - if (s->ps.sps && dpb >= s->ps.sps->temporal_layer[s->ps.sps->max_sub_layers - 1].max_dec_pic_buffering) { - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *frame = &s->DPB[i]; - if ((frame->flags) && - frame->sequence == s->seq_output && - frame->poc != s->poc) { - if (frame->flags == HEVC_FRAME_FLAG_OUTPUT && frame->poc < min_poc) { - min_poc = frame->poc; - } - } - } - - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *frame = &s->DPB[i]; - if (frame->flags & HEVC_FRAME_FLAG_OUTPUT && - frame->sequence == s->seq_output && - frame->poc <= min_poc) { - frame->flags |= HEVC_FRAME_FLAG_BUMPING; - } - } - - dpb--; - } -} - -static int init_slice_rpl(HEVCContext *s) -{ - HEVCFrame *frame = s->ref; - int ctb_count = frame->ctb_count; - int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_segment_addr]; - int i; - - if (s->slice_idx >= frame->nb_rpl_elems) - return AVERROR_INVALIDDATA; - - for (i = ctb_addr_ts; i < ctb_count; i++) - frame->rpl_tab[i] = frame->rpl + s->slice_idx; - - frame->refPicList = (RefPicList *)frame->rpl_tab[ctb_addr_ts]; - - return 0; -} - -int ff_hevc_slice_rpl(HEVCContext *s) -{ - SliceHeader *sh = &s->sh; - - uint8_t nb_list = sh->slice_type == HEVC_SLICE_B ? 2 : 1; - uint8_t list_idx; - int i, j, ret; - - ret = init_slice_rpl(s); - if (ret < 0) - return ret; - - if (!(s->rps[ST_CURR_BEF].nb_refs + s->rps[ST_CURR_AFT].nb_refs + - s->rps[LT_CURR].nb_refs) && !s->ps.pps->pps_curr_pic_ref_enabled_flag) { - av_log(s->avctx, AV_LOG_ERROR, "Zero refs in the frame RPS.\n"); - return AVERROR_INVALIDDATA; - } - - for (list_idx = 0; list_idx < nb_list; list_idx++) { - RefPicList rpl_tmp = { { 0 } }; - RefPicList *rpl = &s->ref->refPicList[list_idx]; - - /* The order of the elements is - * ST_CURR_BEF - ST_CURR_AFT - LT_CURR for the L0 and - * ST_CURR_AFT - ST_CURR_BEF - LT_CURR for the L1 */ - int cand_lists[3] = { list_idx ? ST_CURR_AFT : ST_CURR_BEF, - list_idx ? ST_CURR_BEF : ST_CURR_AFT, - LT_CURR }; - - /* concatenate the candidate lists for the current frame */ - while (rpl_tmp.nb_refs < sh->nb_refs[list_idx]) { - for (i = 0; i < FF_ARRAY_ELEMS(cand_lists); i++) { - RefPicList *rps = &s->rps[cand_lists[i]]; - for (j = 0; j < rps->nb_refs && rpl_tmp.nb_refs < HEVC_MAX_REFS; j++) { - rpl_tmp.list[rpl_tmp.nb_refs] = rps->list[j]; - rpl_tmp.ref[rpl_tmp.nb_refs] = rps->ref[j]; - rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = i == 2; - rpl_tmp.nb_refs++; - } - } - // Construct RefPicList0, RefPicList1 (8-8, 8-10) - if (s->ps.pps->pps_curr_pic_ref_enabled_flag && rpl_tmp.nb_refs < HEVC_MAX_REFS) { - rpl_tmp.list[rpl_tmp.nb_refs] = s->ref->poc; - rpl_tmp.ref[rpl_tmp.nb_refs] = s->ref; - rpl_tmp.isLongTerm[rpl_tmp.nb_refs] = 1; - rpl_tmp.nb_refs++; - } - } - - /* reorder the references if necessary */ - if (sh->rpl_modification_flag[list_idx]) { - for (i = 0; i < sh->nb_refs[list_idx]; i++) { - int idx = sh->list_entry_lx[list_idx][i]; - - if (idx >= rpl_tmp.nb_refs) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid reference index.\n"); - return AVERROR_INVALIDDATA; - } - - rpl->list[i] = rpl_tmp.list[idx]; - rpl->ref[i] = rpl_tmp.ref[idx]; - rpl->isLongTerm[i] = rpl_tmp.isLongTerm[idx]; - rpl->nb_refs++; - } - } else { - memcpy(rpl, &rpl_tmp, sizeof(*rpl)); - rpl->nb_refs = FFMIN(rpl->nb_refs, sh->nb_refs[list_idx]); - } - - // 8-9 - if (s->ps.pps->pps_curr_pic_ref_enabled_flag && - !sh->rpl_modification_flag[list_idx] && - rpl_tmp.nb_refs > sh->nb_refs[L0]) { - rpl->list[sh->nb_refs[L0] - 1] = s->ref->poc; - rpl->ref[sh->nb_refs[L0] - 1] = s->ref; - } - - if (sh->collocated_list == list_idx && - sh->collocated_ref_idx < rpl->nb_refs) - s->collocated_ref = rpl->ref[sh->collocated_ref_idx]; - } - - return 0; -} - -static HEVCFrame *find_ref_idx(HEVCContext *s, int poc, uint8_t use_msb) -{ - int mask = use_msb ? ~0 : (1 << s->ps.sps->log2_max_poc_lsb) - 1; - int i; - - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *ref = &s->DPB[i]; - if (ref->frame->buf[0] && ref->sequence == s->seq_decode) { - if ((ref->poc & mask) == poc && (use_msb || ref->poc != s->poc)) - return ref; - } - } - - if (s->nal_unit_type != HEVC_NAL_CRA_NUT && !IS_BLA(s)) - av_log(s->avctx, AV_LOG_ERROR, - "Could not find ref with POC %d\n", poc); - return NULL; -} - -static void mark_ref(HEVCFrame *frame, int flag) -{ - frame->flags &= ~(HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF); - frame->flags |= flag; -} - -static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc) -{ - HEVCFrame *frame; - int i, y; - - frame = alloc_frame(s); - if (!frame) - return NULL; - - if (!s->avctx->hwaccel) { - if (!s->ps.sps->pixel_shift) { - for (i = 0; frame->frame->data[i]; i++) - memset(frame->frame->data[i], 1 << (s->ps.sps->bit_depth - 1), - frame->frame->linesize[i] * AV_CEIL_RSHIFT(s->ps.sps->height, s->ps.sps->vshift[i])); - } else { - for (i = 0; frame->frame->data[i]; i++) - for (y = 0; y < (s->ps.sps->height >> s->ps.sps->vshift[i]); y++) { - uint8_t *dst = frame->frame->data[i] + y * frame->frame->linesize[i]; - AV_WN16(dst, 1 << (s->ps.sps->bit_depth - 1)); - av_memcpy_backptr(dst + 2, 2, 2*(s->ps.sps->width >> s->ps.sps->hshift[i]) - 2); - } - } - } - - frame->poc = poc; - frame->sequence = HEVC_SEQUENCE_COUNTER_INVALID; - frame->flags = 0; - - if (s->threads_type == FF_THREAD_FRAME) - ff_thread_report_progress(&frame->tf, INT_MAX, 0); - - return frame; -} - -/* add a reference with the given poc to the list and mark it as used in DPB */ -static int add_candidate_ref(HEVCContext *s, RefPicList *list, - int poc, int ref_flag, uint8_t use_msb) -{ - HEVCFrame *ref = find_ref_idx(s, poc, use_msb); - - if (ref == s->ref || list->nb_refs >= HEVC_MAX_REFS) - return AVERROR_INVALIDDATA; - - if (!ref) { - ref = generate_missing_ref(s, poc); - if (!ref) - return AVERROR(ENOMEM); - } - - list->list[list->nb_refs] = ref->poc; - list->ref[list->nb_refs] = ref; - list->nb_refs++; - - mark_ref(ref, ref_flag); - return 0; -} - -int ff_hevc_frame_rps(HEVCContext *s) -{ - const ShortTermRPS *short_rps = s->sh.short_term_rps; - const LongTermRPS *long_rps = &s->sh.long_term_rps; - RefPicList *rps = s->rps; - int i, ret = 0; - - if (!short_rps) { - rps[0].nb_refs = rps[1].nb_refs = 0; - return 0; - } - - unref_missing_refs(s); - - /* clear the reference flags on all frames except the current one */ - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - HEVCFrame *frame = &s->DPB[i]; - - if (frame == s->ref) - continue; - - mark_ref(frame, 0); - } - - for (i = 0; i < NB_RPS_TYPE; i++) - rps[i].nb_refs = 0; - - /* add the short refs */ - for (i = 0; i < short_rps->num_delta_pocs; i++) { - int poc = s->poc + short_rps->delta_poc[i]; - int list; - - if (!short_rps->used[i]) - list = ST_FOLL; - else if (i < short_rps->num_negative_pics) - list = ST_CURR_BEF; - else - list = ST_CURR_AFT; - - ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_SHORT_REF, 1); - if (ret < 0) - goto fail; - } - - /* add the long refs */ - for (i = 0; i < long_rps->nb_refs; i++) { - int poc = long_rps->poc[i]; - int list = long_rps->used[i] ? LT_CURR : LT_FOLL; - - ret = add_candidate_ref(s, &rps[list], poc, HEVC_FRAME_FLAG_LONG_REF, long_rps->poc_msb_present[i]); - if (ret < 0) - goto fail; - } - -fail: - /* release any frames that are now unused */ - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) - ff_hevc_unref_frame(&s->DPB[i], 0); - - return ret; -} - -int ff_hevc_frame_nb_refs(const HEVCContext *s) -{ - int ret = 0; - int i; - const ShortTermRPS *rps = s->sh.short_term_rps; - const LongTermRPS *long_rps = &s->sh.long_term_rps; - - if (rps) { - for (i = 0; i < rps->num_negative_pics; i++) - ret += !!rps->used[i]; - for (; i < rps->num_delta_pocs; i++) - ret += !!rps->used[i]; - } - - if (long_rps) { - for (i = 0; i < long_rps->nb_refs; i++) - ret += !!long_rps->used[i]; - } - - if (s->ps.pps->pps_curr_pic_ref_enabled_flag) - ret++; - - return ret; -} diff --git a/libavcodec/hpeldsp.c b/libavcodec/hpeldsp.c index 1ec76e7a4..80494c974 100644 --- a/libavcodec/hpeldsp.c +++ b/libavcodec/hpeldsp.c @@ -357,8 +357,6 @@ av_cold void ff_hpeldsp_init(HpelDSPContext *c, int flags) #if ARCH_AARCH64 ff_hpeldsp_init_aarch64(c, flags); -#elif ARCH_ALPHA - ff_hpeldsp_init_alpha(c, flags); #elif ARCH_ARM ff_hpeldsp_init_arm(c, flags); #elif ARCH_PPC diff --git a/libavcodec/hq_hqa.c b/libavcodec/hq_hqa.c index 096fb65dc..738ed9868 100644 --- a/libavcodec/hq_hqa.c +++ b/libavcodec/hq_hqa.c @@ -366,9 +366,6 @@ static int hq_hqa_decode_frame(AVCodecContext *avctx, AVFrame *pic, return ret; } - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/hqx.c b/libavcodec/hqx.c index 51099aa68..ee6c5a662 100644 --- a/libavcodec/hqx.c +++ b/libavcodec/hqx.c @@ -504,9 +504,6 @@ static int hqx_decode_frame(AVCodecContext *avctx, AVFrame *frame, avctx->execute2(avctx, decode_slice_thread, NULL, NULL, 16); - ctx->pic->flags |= AV_FRAME_FLAG_KEY; - ctx->pic->pict_type = AV_PICTURE_TYPE_I; - *got_picture_ptr = 1; return avpkt->size; diff --git a/libavcodec/huffyuv.c b/libavcodec/huffyuv.c index aaba313bf..f22c5ebc5 100644 --- a/libavcodec/huffyuv.c +++ b/libavcodec/huffyuv.c @@ -28,12 +28,12 @@ * huffyuv codec for libavcodec. */ +#include #include -#include "libavutil/attributes.h" #include "libavutil/error.h" #include "libavutil/log.h" -#include "libavutil/mem.h" +#include "libavutil/macros.h" #include "huffyuv.h" @@ -49,7 +49,7 @@ int ff_huffyuv_generate_bits_table(uint32_t *dst, const uint8_t *len_table, int for (int i = FF_ARRAY_ELEMS(lens) - 1; i > 0; i--) { if ((lens[i] + codes[i]) & 1) { av_log(NULL, AV_LOG_ERROR, "Error generating huffman table\n"); - return -1; + return AVERROR_INVALIDDATA; } codes[i - 1] = (lens[i] + codes[i]) >> 1; } @@ -59,26 +59,3 @@ int ff_huffyuv_generate_bits_table(uint32_t *dst, const uint8_t *len_table, int } return 0; } - -av_cold int ff_huffyuv_alloc_temp(uint8_t *temp[3], uint16_t *temp16[3], int width) -{ - int i; - - for (i=0; i<3; i++) { - temp[i] = av_malloc(4 * width + 16); - if (!temp[i]) - return AVERROR(ENOMEM); - temp16[i] = (uint16_t*)temp[i]; - } - return 0; -} - -av_cold void ff_huffyuv_common_end(uint8_t *temp[3], uint16_t *temp16[3]) -{ - int i; - - for(i = 0; i < 3; i++) { - av_freep(&temp[i]); - temp16[i] = NULL; - } -} diff --git a/libavcodec/huffyuv.h b/libavcodec/huffyuv.h index 22a766611..62866b7a4 100644 --- a/libavcodec/huffyuv.h +++ b/libavcodec/huffyuv.h @@ -55,8 +55,6 @@ typedef enum Predictor { MEDIAN, } Predictor; -void ff_huffyuv_common_end(uint8_t *temp[3], uint16_t *temp16[3]); -int ff_huffyuv_alloc_temp(uint8_t *temp[3], uint16_t *temp16[3], int width); int ff_huffyuv_generate_bits_table(uint32_t *dst, const uint8_t *len_table, int n); #endif /* AVCODEC_HUFFYUV_H */ diff --git a/libavcodec/huffyuvdec.c b/libavcodec/huffyuvdec.c index ce6d4d4c5..c98904d49 100644 --- a/libavcodec/huffyuvdec.c +++ b/libavcodec/huffyuvdec.c @@ -36,6 +36,7 @@ #include "avcodec.h" #include "bswapdsp.h" +#include "bytestream.h" #include "codec_internal.h" #include "get_bits.h" #include "huffyuv.h" @@ -44,6 +45,7 @@ #include "thread.h" #include "libavutil/emms.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #define VLC_BITS 12 @@ -69,8 +71,10 @@ typedef struct HYuvDecContext { int context; int last_slice_end; - uint8_t *temp[3]; - uint16_t *temp16[3]; ///< identical to temp but 16bit type + union { + uint8_t *temp[3]; + uint16_t *temp16[3]; + }; uint8_t len[4][MAX_VLC_N]; uint32_t bits[4][MAX_VLC_N]; uint32_t pix_bgr_map[1< n || get_bits_left(gb) < 0) { - av_log(NULL, AV_LOG_ERROR, "Error reading huffman table\n"); - return AVERROR_INVALIDDATA; + if (bytestream2_get_bytes_left(gb) <= 0) + goto error; + repeat = bytestream2_peek_byteu(gb) >> 5; + val = bytestream2_get_byteu(gb) & 0x1F; + if (repeat == 0) { + if (bytestream2_get_bytes_left(gb) <= 0) + goto error; + repeat = bytestream2_get_byteu(gb); } + if (i + repeat > n) + goto error; while (repeat--) dst[i++] = val; } return 0; + +error: + av_log(NULL, AV_LOG_ERROR, "Error reading huffman table\n"); + return AVERROR_INVALIDDATA; } static int generate_joint_tables(HYuvDecContext *s) @@ -250,12 +257,11 @@ out: static int read_huffman_tables(HYuvDecContext *s, const uint8_t *src, int length) { - GetBitContext gb; + GetByteContext gb; int i, ret; int count = 3; - if ((ret = init_get_bits(&gb, src, length * 8)) < 0) - return ret; + bytestream2_init(&gb, src, length); if (s->version > 2) count = 1 + s->alpha + 2*s->chroma; @@ -274,23 +280,23 @@ static int read_huffman_tables(HYuvDecContext *s, const uint8_t *src, int length if ((ret = generate_joint_tables(s)) < 0) return ret; - return (get_bits_count(&gb) + 7) / 8; + return bytestream2_tell(&gb); } static int read_old_huffman_tables(HYuvDecContext *s) { - GetBitContext gb; + GetByteContext gb; int i, ret; - init_get_bits(&gb, classic_shift_luma, - classic_shift_luma_table_size * 8); - if ((ret = read_len_table(s->len[0], &gb, 256)) < 0) - return ret; + bytestream2_init(&gb, classic_shift_luma, + sizeof(classic_shift_luma)); + ret = read_len_table(s->len[0], &gb, 256); + av_assert1(ret >= 0); - init_get_bits(&gb, classic_shift_chroma, - classic_shift_chroma_table_size * 8); - if ((ret = read_len_table(s->len[1], &gb, 256)) < 0) - return ret; + bytestream2_init(&gb, classic_shift_chroma, + sizeof(classic_shift_chroma)); + ret = read_len_table(s->len[1], &gb, 256); + av_assert1(ret >= 0); for (i = 0; i < 256; i++) s->bits[0][i] = classic_add_luma[i]; @@ -322,7 +328,9 @@ static av_cold int decode_end(AVCodecContext *avctx) HYuvDecContext *s = avctx->priv_data; int i; - ff_huffyuv_common_end(s->temp, s->temp16); + for (int i = 0; i < 3; i++) + av_freep(&s->temp[i]); + av_freep(&s->bitstream_buffer); for (i = 0; i < 8; i++) @@ -345,7 +353,6 @@ static av_cold int decode_init(AVCodecContext *avctx) ff_bswapdsp_init(&s->bdsp); ff_huffyuvdsp_init(&s->hdsp, avctx->pix_fmt); ff_llviddsp_init(&s->llviddsp); - memset(s->vlc, 0, 4 * sizeof(VLC)); s->interlaced = avctx->height > 288; s->bgr32 = 1; @@ -599,8 +606,11 @@ static av_cold int decode_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } - if ((ret = ff_huffyuv_alloc_temp(s->temp, s->temp16, avctx->width)) < 0) - return ret; + for (int i = 0; i < 3; i++) { + s->temp[i] = av_malloc(4 * avctx->width + 16); + if (!s->temp[i]) + return AVERROR(ENOMEM); + } return 0; } @@ -773,6 +783,8 @@ static void decode_gray_bitstream(HYuvDecContext *s, int count) for (i = 0; i < count && BITS_LEFT(re, &s->gb) > 0; i++) { READ_2PIX(s->temp[0][2 * i], s->temp[0][2 * i + 1], 0); } + for (; i < count; i++) + s->temp[0][2 * i] = s->temp[0][2 * i + 1] = 0; } else { for (i = 0; i < count; i++) { READ_2PIX(s->temp[0][2 * i], s->temp[0][2 * i + 1], 0); diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c index 494ca7e60..5e8b5c0dd 100644 --- a/libavcodec/huffyuvenc.c +++ b/libavcodec/huffyuvenc.c @@ -40,6 +40,7 @@ #include "lossless_videoencdsp.h" #include "put_bits.h" #include "libavutil/emms.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -64,8 +65,10 @@ typedef struct HYuvEncContext { int context; int picture_number; - uint8_t *temp[3]; - uint16_t *temp16[3]; ///< identical to temp but 16bit type + union { + uint8_t *temp[3]; + uint16_t *temp16[3]; + }; uint64_t stats[4][MAX_VLC_N]; uint8_t len[4][MAX_VLC_N]; uint32_t bits[4][MAX_VLC_N]; @@ -229,9 +232,9 @@ static int store_huffman_tables(HYuvEncContext *s, uint8_t *buf) if ((ret = ff_huff_gen_len_table(s->len[i], s->stats[i], s->vlc_n, 0)) < 0) return ret; - if (ff_huffyuv_generate_bits_table(s->bits[i], s->len[i], s->vlc_n) < 0) { - return -1; - } + ret = ff_huffyuv_generate_bits_table(s->bits[i], s->len[i], s->vlc_n); + if (ret < 0) + return ret; size += store_table(s, s->len[i], buf + size); } @@ -429,12 +432,14 @@ static av_cold int encode_init(AVCodecContext *avctx) s->stats[i][j]= 0; } - ret = ff_huffyuv_alloc_temp(s->temp, s->temp16, avctx->width); - if (ret < 0) - return ret; - s->picture_number=0; + for (int i = 0; i < 3; i++) { + s->temp[i] = av_malloc(4 * avctx->width + 16); + if (!s->temp[i]) + return AVERROR(ENOMEM); + } + return 0; } static int encode_422_bitstream(HYuvEncContext *s, int offset, int count) @@ -494,7 +499,7 @@ static int encode_422_bitstream(HYuvEncContext *s, int offset, int count) static int encode_plane_bitstream(HYuvEncContext *s, int width, int plane) { - int i, count = width/2; + int count = width/2; if (put_bytes_left(&s->pb, 0) < count * s->bps / 2) { av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); @@ -541,112 +546,52 @@ static int encode_plane_bitstream(HYuvEncContext *s, int width, int plane) put_bits(&s->pb, s->len[plane][y1>>2], s->bits[plane][y1>>2]);\ put_bits(&s->pb, 2, y1&3); - if (s->bps <= 8) { - if (s->flags & AV_CODEC_FLAG_PASS1) { - for (i = 0; i < count; i++) { - LOAD2; - STAT2; - } - if (width&1) { - LOADEND; - STATEND; - } - } - if (s->avctx->flags2 & AV_CODEC_FLAG2_NO_OUTPUT) - return 0; +#define ENCODE_PLANE(LOAD, LOADEND, WRITE, WRITEEND, STAT, STATEND) \ +do { \ + if (s->flags & AV_CODEC_FLAG_PASS1) { \ + for (int i = 0; i < count; i++) { \ + LOAD; \ + STAT; \ + } \ + if (width & 1) { \ + LOADEND; \ + STATEND; \ + } \ + } \ + if (s->avctx->flags2 & AV_CODEC_FLAG2_NO_OUTPUT) \ + return 0; \ + \ + if (s->context) { \ + for (int i = 0; i < count; i++) { \ + LOAD; \ + STAT; \ + WRITE; \ + } \ + if (width & 1) { \ + LOADEND; \ + STATEND; \ + WRITEEND; \ + } \ + } else { \ + for (int i = 0; i < count; i++) { \ + LOAD; \ + WRITE; \ + } \ + if (width & 1) { \ + LOADEND; \ + WRITEEND; \ + } \ + } \ +} while (0) - if (s->context) { - for (i = 0; i < count; i++) { - LOAD2; - STAT2; - WRITE2; - } - if (width&1) { - LOADEND; - STATEND; - WRITEEND; - } - } else { - for (i = 0; i < count; i++) { - LOAD2; - WRITE2; - } - if (width&1) { - LOADEND; - WRITEEND; - } - } + if (s->bps <= 8) { + ENCODE_PLANE(LOAD2, LOADEND, WRITE2, WRITEEND, STAT2, STATEND); } else if (s->bps <= 14) { int mask = s->n - 1; - if (s->flags & AV_CODEC_FLAG_PASS1) { - for (i = 0; i < count; i++) { - LOAD2_14; - STAT2; - } - if (width&1) { - LOADEND_14; - STATEND; - } - } - if (s->avctx->flags2 & AV_CODEC_FLAG2_NO_OUTPUT) - return 0; - if (s->context) { - for (i = 0; i < count; i++) { - LOAD2_14; - STAT2; - WRITE2; - } - if (width&1) { - LOADEND_14; - STATEND; - WRITEEND; - } - } else { - for (i = 0; i < count; i++) { - LOAD2_14; - WRITE2; - } - if (width&1) { - LOADEND_14; - WRITEEND; - } - } + ENCODE_PLANE(LOAD2_14, LOADEND_14, WRITE2, WRITEEND, STAT2, STATEND); } else { - if (s->flags & AV_CODEC_FLAG_PASS1) { - for (i = 0; i < count; i++) { - LOAD2_16; - STAT2_16; - } - if (width&1) { - LOADEND_16; - STATEND_16; - } - } - if (s->avctx->flags2 & AV_CODEC_FLAG2_NO_OUTPUT) - return 0; - - if (s->context) { - for (i = 0; i < count; i++) { - LOAD2_16; - STAT2_16; - WRITE2_16; - } - if (width&1) { - LOADEND_16; - STATEND_16; - WRITEEND_16; - } - } else { - for (i = 0; i < count; i++) { - LOAD2_16; - WRITE2_16; - } - if (width&1) { - LOADEND_16; - WRITEEND_16; - } - } + ENCODE_PLANE(LOAD2_16, LOADEND_16, WRITE2_16, WRITEEND_16, STAT2_16, STATEND_16); } #undef LOAD2 #undef STAT2 @@ -750,16 +695,15 @@ static inline int encode_bgra_bitstream(HYuvEncContext *s, int count, int planes } static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, - const AVFrame *pict, int *got_packet) + const AVFrame *p, int *got_packet) { HYuvEncContext *s = avctx->priv_data; const int width = avctx->width; const int width2 = avctx->width >> 1; const int height = avctx->height; - const int fake_ystride = s->interlaced ? pict->linesize[0]*2 : pict->linesize[0]; - const int fake_ustride = s->interlaced ? pict->linesize[1]*2 : pict->linesize[1]; - const int fake_vstride = s->interlaced ? pict->linesize[2]*2 : pict->linesize[2]; - const AVFrame * const p = pict; + const int fake_ystride = (1 + s->interlaced) * p->linesize[0]; + const int fake_ustride = (1 + s->interlaced) * p->linesize[1]; + const int fake_vstride = (1 + s->interlaced) * p->linesize[2]; int i, j, size = 0, ret; if ((ret = ff_alloc_packet(avctx, pkt, width * height * 3 * 4 + FF_INPUT_BUFFER_MIN_SIZE)) < 0) @@ -1034,47 +978,35 @@ static av_cold int encode_end(AVCodecContext *avctx) { HYuvEncContext *s = avctx->priv_data; - ff_huffyuv_common_end(s->temp, s->temp16); - av_freep(&avctx->stats_out); + for (int i = 0; i < 3; i++) + av_freep(&s->temp[i]); + return 0; } #define OFFSET(x) offsetof(HYuvEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM -#define COMMON_OPTIONS \ - { "non_deterministic", "Allow multithreading for e.g. context=1 at the expense of determinism", \ - OFFSET(non_determ), AV_OPT_TYPE_BOOL, { .i64 = 0 }, \ - 0, 1, VE }, \ - { "pred", "Prediction method", OFFSET(predictor), AV_OPT_TYPE_INT, { .i64 = LEFT }, LEFT, MEDIAN, VE, .unit = "pred" }, \ - { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LEFT }, INT_MIN, INT_MAX, VE, .unit = "pred" }, \ - { "plane", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PLANE }, INT_MIN, INT_MAX, VE, .unit = "pred" }, \ - { "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MEDIAN }, INT_MIN, INT_MAX, VE, .unit = "pred" }, \ - -static const AVOption normal_options[] = { - COMMON_OPTIONS - { NULL }, -}; - -static const AVOption ff_options[] = { - COMMON_OPTIONS +static const AVOption options[] = { + /* ffvhuff-only options */ { "context", "Set per-frame huffman tables", OFFSET(context), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, + /* Common options */ + { "non_deterministic", "Allow multithreading for e.g. context=1 at the expense of determinism", + OFFSET(non_determ), AV_OPT_TYPE_BOOL, { .i64 = 0 }, + 0, 1, VE }, + { "pred", "Prediction method", OFFSET(predictor), AV_OPT_TYPE_INT, { .i64 = LEFT }, LEFT, MEDIAN, VE, .unit = "pred" }, + { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LEFT }, INT_MIN, INT_MAX, VE, .unit = "pred" }, + { "plane", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PLANE }, INT_MIN, INT_MAX, VE, .unit = "pred" }, + { "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MEDIAN }, INT_MIN, INT_MAX, VE, .unit = "pred" }, { NULL }, }; static const AVClass normal_class = { .class_name = "huffyuv", .item_name = av_default_item_name, - .option = normal_options, - .version = LIBAVUTIL_VERSION_INT, -}; - -static const AVClass ff_class = { - .class_name = "ffvhuff", - .item_name = av_default_item_name, - .option = ff_options, + .option = options + 1, .version = LIBAVUTIL_VERSION_INT, }; @@ -1094,10 +1026,18 @@ const FFCodec ff_huffyuv_encoder = { AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #if CONFIG_FFVHUFF_ENCODER +static const AVClass ff_class = { + .class_name = "ffvhuff", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + const FFCodec ff_ffvhuff_encoder = { .p.name = "ffvhuff", CODEC_LONG_NAME("Huffyuv FFmpeg variant"), @@ -1127,6 +1067,7 @@ const FFCodec ff_ffvhuff_encoder = { AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; #endif diff --git a/libavcodec/huffyuvencdsp.c b/libavcodec/huffyuvencdsp.c index 36e8f6130..27428635a 100644 --- a/libavcodec/huffyuvencdsp.c +++ b/libavcodec/huffyuvencdsp.c @@ -18,16 +18,32 @@ #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/intreadwrite.h" #include "huffyuvencdsp.h" #include "mathops.h" +#if HAVE_FAST_64BIT +#define BITS 64 +typedef uint64_t uint_native; +#else +#define BITS 32 +typedef uint32_t uint_native; +#endif +#define RN AV_JOIN(AV_RN, BITS) +#define RNA AV_JOIN(AV_JOIN(AV_RN, BITS), A) +#define WNA AV_JOIN(AV_JOIN(AV_WN, BITS), A) + +// 0x7f7f7f7f or 0x7f7f7f7f7f7f7f7f or whatever, depending on the cpu's native arithmetic size +#define pb_7f (~(uint_native)0 / 255 * 0x7f) +#define pb_80 (~(uint_native)0 / 255 * 0x80) + // 0x00010001 or 0x0001000100010001 or whatever, depending on the cpu's native arithmetic size -#define pw_1 (ULONG_MAX / UINT16_MAX) +#define pw_1 ((uint_native)-1 / UINT16_MAX) static void diff_int16_c(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w){ long i; #if !HAVE_FAST_UNALIGNED - if((long)src2 & (sizeof(long)-1)){ + if ((uintptr_t)src2 & (sizeof(uint_native) - 1)) { for(i=0; i+3> 1) * pw_1; - unsigned long pw_msb = pw_lsb + pw_1; + uint_native pw_lsb = (mask >> 1) * pw_1; + uint_native pw_msb = pw_lsb + pw_1; - for (i = 0; i <= w - (int)sizeof(long)/2; i += sizeof(long)/2) { - long a = *(long*)(src1+i); - long b = *(long*)(src2+i); - *(long*)(dst+i) = ((a|pw_msb) - (b&pw_lsb)) ^ ((a^b^pw_msb)&pw_msb); + for (i = 0; i <= w - (int)sizeof(uint_native)/2; i += sizeof(uint_native)/2) { + uint_native a = RNA(src1 + i); + uint_native b = RN (src2 + i); + WNA(dst + i, ((a | pw_msb) - (b & pw_lsb)) ^ ((a^b^pw_msb) & pw_msb)); } } for (; iinput_image); + av_frame_free(&pic->recon_image); + + av_buffer_unref(&pic->opaque_ref); + av_freep(&pic->codec_priv); + av_freep(&pic->priv); + av_free(pic); + + return 0; +} + +static void hw_base_encode_add_ref(FFHWBaseEncodePicture *pic, + FFHWBaseEncodePicture *target, + int is_ref, int in_dpb, int prev) +{ + int refs = 0; + + if (is_ref) { + av_assert0(pic != target); + av_assert0(pic->nb_refs[0] < MAX_PICTURE_REFERENCES && + pic->nb_refs[1] < MAX_PICTURE_REFERENCES); + if (target->display_order < pic->display_order) + pic->refs[0][pic->nb_refs[0]++] = target; + else + pic->refs[1][pic->nb_refs[1]++] = target; + ++refs; + } + + if (in_dpb) { + av_assert0(pic->nb_dpb_pics < MAX_DPB_SIZE); + pic->dpb[pic->nb_dpb_pics++] = target; + ++refs; + } + + if (prev) { + av_assert0(!pic->prev); + pic->prev = target; + ++refs; + } + + target->ref_count[0] += refs; + target->ref_count[1] += refs; +} + +static void hw_base_encode_remove_refs(FFHWBaseEncodePicture *pic, int level) +{ + int i; + + if (pic->ref_removed[level]) + return; + + for (i = 0; i < pic->nb_refs[0]; i++) { + av_assert0(pic->refs[0][i]); + --pic->refs[0][i]->ref_count[level]; + av_assert0(pic->refs[0][i]->ref_count[level] >= 0); + } + + for (i = 0; i < pic->nb_refs[1]; i++) { + av_assert0(pic->refs[1][i]); + --pic->refs[1][i]->ref_count[level]; + av_assert0(pic->refs[1][i]->ref_count[level] >= 0); + } + + for (i = 0; i < pic->nb_dpb_pics; i++) { + av_assert0(pic->dpb[i]); + --pic->dpb[i]->ref_count[level]; + av_assert0(pic->dpb[i]->ref_count[level] >= 0); + } + + av_assert0(pic->prev || pic->type == FF_HW_PICTURE_TYPE_IDR); + if (pic->prev) { + --pic->prev->ref_count[level]; + av_assert0(pic->prev->ref_count[level] >= 0); + } + + pic->ref_removed[level] = 1; +} + +static void hw_base_encode_set_b_pictures(FFHWBaseEncodeContext *ctx, + FFHWBaseEncodePicture *start, + FFHWBaseEncodePicture *end, + FFHWBaseEncodePicture *prev, + int current_depth, + FFHWBaseEncodePicture **last) +{ + FFHWBaseEncodePicture *pic, *next, *ref; + int i, len; + + av_assert0(start && end && start != end && start->next != end); + + // If we are at the maximum depth then encode all pictures as + // non-referenced B-pictures. Also do this if there is exactly one + // picture left, since there will be nothing to reference it. + if (current_depth == ctx->max_b_depth || start->next->next == end) { + for (pic = start->next; pic; pic = pic->next) { + if (pic == end) + break; + pic->type = FF_HW_PICTURE_TYPE_B; + pic->b_depth = current_depth; + + hw_base_encode_add_ref(pic, start, 1, 1, 0); + hw_base_encode_add_ref(pic, end, 1, 1, 0); + hw_base_encode_add_ref(pic, prev, 0, 0, 1); + + for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0]) + hw_base_encode_add_ref(pic, ref, 0, 1, 0); + } + *last = prev; + + } else { + // Split the current list at the midpoint with a referenced + // B-picture, then descend into each side separately. + len = 0; + for (pic = start->next; pic != end; pic = pic->next) + ++len; + for (pic = start->next, i = 1; 2 * i < len; pic = pic->next, i++); + + pic->type = FF_HW_PICTURE_TYPE_B; + pic->b_depth = current_depth; + + pic->is_reference = 1; + + hw_base_encode_add_ref(pic, pic, 0, 1, 0); + hw_base_encode_add_ref(pic, start, 1, 1, 0); + hw_base_encode_add_ref(pic, end, 1, 1, 0); + hw_base_encode_add_ref(pic, prev, 0, 0, 1); + + for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0]) + hw_base_encode_add_ref(pic, ref, 0, 1, 0); + + if (i > 1) + hw_base_encode_set_b_pictures(ctx, start, pic, pic, + current_depth + 1, &next); + else + next = pic; + + hw_base_encode_set_b_pictures(ctx, pic, end, next, + current_depth + 1, last); + } +} + +static void hw_base_encode_add_next_prev(FFHWBaseEncodeContext *ctx, + FFHWBaseEncodePicture *pic) +{ + int i; + + if (!pic) + return; + + if (pic->type == FF_HW_PICTURE_TYPE_IDR) { + for (i = 0; i < ctx->nb_next_prev; i++) { + --ctx->next_prev[i]->ref_count[0]; + ctx->next_prev[i] = NULL; + } + ctx->next_prev[0] = pic; + ++pic->ref_count[0]; + ctx->nb_next_prev = 1; + + return; + } + + if (ctx->nb_next_prev < MAX_PICTURE_REFERENCES) { + 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++) + ctx->next_prev[i] = ctx->next_prev[i + 1]; + ctx->next_prev[i] = pic; + ++pic->ref_count[0]; + } +} + +static int hw_base_encode_pick_next(AVCodecContext *avctx, + FFHWBaseEncodeContext *ctx, + FFHWBaseEncodePicture **pic_out) +{ + FFHWBaseEncodePicture *pic = NULL, *prev = NULL, *next, *start; + int i, b_counter, closed_gop_end; + + // If there are any B-frames already queued, the next one to encode + // is the earliest not-yet-issued frame for which all references are + // available. + for (pic = ctx->pic_start; pic; pic = pic->next) { + if (pic->encode_issued) + continue; + if (pic->type != FF_HW_PICTURE_TYPE_B) + continue; + for (i = 0; i < pic->nb_refs[0]; i++) { + if (!pic->refs[0][i]->encode_issued) + break; + } + if (i != pic->nb_refs[0]) + continue; + + for (i = 0; i < pic->nb_refs[1]; i++) { + if (!pic->refs[1][i]->encode_issued) + break; + } + if (i == pic->nb_refs[1]) + break; + } + + if (pic) { + av_log(avctx, AV_LOG_DEBUG, "Pick B-picture at depth %d to " + "encode next.\n", pic->b_depth); + *pic_out = pic; + return 0; + } + + // Find the B-per-Pth available picture to become the next picture + // on the top layer. + start = NULL; + b_counter = 0; + closed_gop_end = ctx->closed_gop || + ctx->idr_counter == ctx->gop_per_idr; + for (pic = ctx->pic_start; pic; pic = next) { + next = pic->next; + if (pic->encode_issued) { + start = pic; + continue; + } + // If the next available picture is force-IDR, encode it to start + // a new GOP immediately. + if (pic->force_idr) + break; + if (b_counter == ctx->b_per_p) + break; + // If this picture ends a closed GOP or starts a new GOP then it + // needs to be in the top layer. + if (ctx->gop_counter + b_counter + closed_gop_end >= ctx->gop_size) + break; + // If the picture after this one is force-IDR, we need to encode + // this one in the top layer. + if (next && next->force_idr) + break; + ++b_counter; + } + + // At the end of the stream the last picture must be in the top layer. + if (!pic && ctx->end_of_stream) { + --b_counter; + pic = ctx->pic_end; + if (pic->encode_complete) + return AVERROR_EOF; + else if (pic->encode_issued) + return AVERROR(EAGAIN); + } + + if (!pic) { + av_log(avctx, AV_LOG_DEBUG, "Pick nothing to encode next - " + "need more input for reference pictures.\n"); + return AVERROR(EAGAIN); + } + if (ctx->input_order <= ctx->decode_delay && !ctx->end_of_stream) { + av_log(avctx, AV_LOG_DEBUG, "Pick nothing to encode next - " + "need more input for timestamps.\n"); + return AVERROR(EAGAIN); + } + + if (pic->force_idr) { + av_log(avctx, AV_LOG_DEBUG, "Pick forced IDR-picture to " + "encode next.\n"); + pic->type = FF_HW_PICTURE_TYPE_IDR; + ctx->idr_counter = 1; + ctx->gop_counter = 1; + + } else if (ctx->gop_counter + b_counter >= ctx->gop_size) { + if (ctx->idr_counter == ctx->gop_per_idr) { + av_log(avctx, AV_LOG_DEBUG, "Pick new-GOP IDR-picture to " + "encode next.\n"); + pic->type = FF_HW_PICTURE_TYPE_IDR; + ctx->idr_counter = 1; + } else { + av_log(avctx, AV_LOG_DEBUG, "Pick new-GOP I-picture to " + "encode next.\n"); + pic->type = FF_HW_PICTURE_TYPE_I; + ++ctx->idr_counter; + } + ctx->gop_counter = 1; + + } else { + if (ctx->gop_counter + b_counter + closed_gop_end == ctx->gop_size) { + av_log(avctx, AV_LOG_DEBUG, "Pick group-end P-picture to " + "encode next.\n"); + } else { + av_log(avctx, AV_LOG_DEBUG, "Pick normal P-picture to " + "encode next.\n"); + } + pic->type = FF_HW_PICTURE_TYPE_P; + av_assert0(start); + ctx->gop_counter += 1 + b_counter; + } + pic->is_reference = 1; + *pic_out = pic; + + hw_base_encode_add_ref(pic, pic, 0, 1, 0); + if (pic->type != FF_HW_PICTURE_TYPE_IDR) { + // TODO: apply both previous and forward multi reference for all vaapi encoders. + // And L0/L1 reference frame number can be set dynamically through query + // VAConfigAttribEncMaxRefFrames attribute. + if (avctx->codec_id == AV_CODEC_ID_AV1) { + for (i = 0; i < ctx->nb_next_prev; i++) + hw_base_encode_add_ref(pic, ctx->next_prev[i], + pic->type == FF_HW_PICTURE_TYPE_P, + b_counter > 0, 0); + } else + hw_base_encode_add_ref(pic, start, + pic->type == FF_HW_PICTURE_TYPE_P, + b_counter > 0, 0); + + hw_base_encode_add_ref(pic, ctx->next_prev[ctx->nb_next_prev - 1], 0, 0, 1); + } + + if (b_counter > 0) { + hw_base_encode_set_b_pictures(ctx, start, pic, pic, 1, + &prev); + } else { + prev = pic; + } + hw_base_encode_add_next_prev(ctx, prev); + + return 0; +} + +static int hw_base_encode_clear_old(AVCodecContext *avctx, FFHWBaseEncodeContext *ctx) +{ + FFHWBaseEncodePicture *pic, *prev, *next; + + av_assert0(ctx->pic_start); + + // Remove direct references once each picture is complete. + for (pic = ctx->pic_start; pic; pic = pic->next) { + if (pic->encode_complete && pic->next) + hw_base_encode_remove_refs(pic, 0); + } + + // Remove indirect references once a picture has no direct references. + for (pic = ctx->pic_start; pic; pic = pic->next) { + if (pic->encode_complete && pic->ref_count[0] == 0) + hw_base_encode_remove_refs(pic, 1); + } + + // Clear out all complete pictures with no remaining references. + prev = NULL; + for (pic = ctx->pic_start; pic; pic = next) { + next = pic->next; + if (pic->encode_complete && pic->ref_count[1] == 0) { + av_assert0(pic->ref_removed[0] && pic->ref_removed[1]); + if (prev) + prev->next = next; + else + ctx->pic_start = next; + ctx->op->free(avctx, pic); + base_encode_pic_free(pic); + } else { + prev = pic; + } + } + + return 0; +} + +static int hw_base_encode_check_frame(FFHWBaseEncodeContext *ctx, + const AVFrame *frame) +{ + if ((frame->crop_top || frame->crop_bottom || + frame->crop_left || frame->crop_right) && !ctx->crop_warned) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "Cropping information on input " + "frames ignored due to lack of API support.\n"); + ctx->crop_warned = 1; + } + + if (!ctx->roi_allowed) { + AVFrameSideData *sd = + av_frame_get_side_data(frame, AV_FRAME_DATA_REGIONS_OF_INTEREST); + + if (sd && !ctx->roi_warned) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "ROI side data on input " + "frames ignored due to lack of driver support.\n"); + ctx->roi_warned = 1; + } + } + + return 0; +} + +static int hw_base_encode_send_frame(AVCodecContext *avctx, FFHWBaseEncodeContext *ctx, + AVFrame *frame) +{ + FFHWBaseEncodePicture *pic; + int err; + + if (frame) { + av_log(avctx, AV_LOG_DEBUG, "Input frame: %ux%u (%"PRId64").\n", + frame->width, frame->height, frame->pts); + + err = hw_base_encode_check_frame(ctx, frame); + if (err < 0) + return err; + + pic = av_mallocz(sizeof(*pic)); + if (!pic) + return AVERROR(ENOMEM); + + pic->input_image = av_frame_alloc(); + if (!pic->input_image) { + err = AVERROR(ENOMEM); + goto fail; + } + + if (ctx->recon_frames_ref) { + pic->recon_image = av_frame_alloc(); + if (!pic->recon_image) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_hwframe_get_buffer(ctx->recon_frames_ref, pic->recon_image, 0); + if (err < 0) { + err = AVERROR(ENOMEM); + goto fail; + } + } + + pic->priv = av_mallocz(ctx->op->priv_size); + if (!pic->priv) { + err = AVERROR(ENOMEM); + goto fail; + } + + if (ctx->input_order == 0 || frame->pict_type == AV_PICTURE_TYPE_I) + pic->force_idr = 1; + + pic->pts = frame->pts; + pic->duration = frame->duration; + + if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { + err = av_buffer_replace(&pic->opaque_ref, frame->opaque_ref); + if (err < 0) + goto fail; + + pic->opaque = frame->opaque; + } + + av_frame_move_ref(pic->input_image, frame); + + if (ctx->input_order == 0) + ctx->first_pts = pic->pts; + if (ctx->input_order == ctx->decode_delay) + ctx->dts_pts_diff = pic->pts - ctx->first_pts; + if (ctx->output_delay > 0) + ctx->ts_ring[ctx->input_order % + (3 * ctx->output_delay + ctx->async_depth)] = pic->pts; + + pic->display_order = ctx->input_order; + ++ctx->input_order; + + if (ctx->pic_start) { + ctx->pic_end->next = pic; + ctx->pic_end = pic; + } else { + ctx->pic_start = pic; + ctx->pic_end = pic; + } + + err = ctx->op->init(avctx, pic); + if (err < 0) + goto fail; + } else { + ctx->end_of_stream = 1; + + // Fix timestamps if we hit end-of-stream before the initial decode + // delay has elapsed. + if (ctx->input_order <= ctx->decode_delay) + ctx->dts_pts_diff = ctx->pic_end->pts - ctx->first_pts; + } + + return 0; + +fail: + ctx->op->free(avctx, pic); + base_encode_pic_free(pic); + return err; +} + +int ff_hw_base_encode_set_output_property(FFHWBaseEncodeContext *ctx, + AVCodecContext *avctx, + FFHWBaseEncodePicture *pic, + AVPacket *pkt, int flag_no_delay) +{ + if (pic->type == FF_HW_PICTURE_TYPE_IDR) + pkt->flags |= AV_PKT_FLAG_KEY; + + pkt->pts = pic->pts; + pkt->duration = pic->duration; + + // for no-delay encoders this is handled in generic codec + if (avctx->codec->capabilities & AV_CODEC_CAP_DELAY && + avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { + pkt->opaque = pic->opaque; + pkt->opaque_ref = pic->opaque_ref; + pic->opaque_ref = NULL; + } + + if (flag_no_delay) { + pkt->dts = pkt->pts; + return 0; + } + + if (ctx->output_delay == 0) { + pkt->dts = pkt->pts; + } else if (pic->encode_order < ctx->decode_delay) { + if (ctx->ts_ring[pic->encode_order] < INT64_MIN + ctx->dts_pts_diff) + pkt->dts = INT64_MIN; + else + pkt->dts = ctx->ts_ring[pic->encode_order] - ctx->dts_pts_diff; + } else { + pkt->dts = ctx->ts_ring[(pic->encode_order - ctx->decode_delay) % + (3 * ctx->output_delay + ctx->async_depth)]; + } + + return 0; +} + +int ff_hw_base_encode_receive_packet(FFHWBaseEncodeContext *ctx, + AVCodecContext *avctx, AVPacket *pkt) +{ + FFHWBaseEncodePicture *pic = NULL; + AVFrame *frame = ctx->frame; + int err; + + av_assert0(ctx->op && ctx->op->init && ctx->op->issue && + ctx->op->output && ctx->op->free); + +start: + /** if no B frame before repeat P frame, sent repeat P frame out. */ + if (ctx->tail_pkt->size) { + for (FFHWBaseEncodePicture *tmp = ctx->pic_start; tmp; tmp = tmp->next) { + if (tmp->type == FF_HW_PICTURE_TYPE_B && tmp->pts < ctx->tail_pkt->pts) + break; + else if (!tmp->next) { + av_packet_move_ref(pkt, ctx->tail_pkt); + goto end; + } + } + } + + err = ff_encode_get_frame(avctx, frame); + if (err == AVERROR_EOF) { + frame = NULL; + } else if (err < 0) + return err; + + err = hw_base_encode_send_frame(avctx, ctx, frame); + if (err < 0) + return err; + + if (!ctx->pic_start) { + if (ctx->end_of_stream) + return AVERROR_EOF; + else + return AVERROR(EAGAIN); + } + + if (ctx->async_encode) { + if (av_fifo_can_write(ctx->encode_fifo)) { + err = hw_base_encode_pick_next(avctx, ctx, &pic); + if (!err) { + av_assert0(pic); + pic->encode_order = ctx->encode_order + + 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); + return err; + } + pic->encode_issued = 1; + av_fifo_write(ctx->encode_fifo, &pic, 1); + } + } + + if (!av_fifo_can_read(ctx->encode_fifo)) + return err; + + // More frames can be buffered + if (av_fifo_can_write(ctx->encode_fifo) && !ctx->end_of_stream) + return AVERROR(EAGAIN); + + av_fifo_read(ctx->encode_fifo, &pic, 1); + ctx->encode_order = pic->encode_order + 1; + } else { + err = hw_base_encode_pick_next(avctx, ctx, &pic); + if (err < 0) + return err; + av_assert0(pic); + + pic->encode_order = ctx->encode_order++; + + err = ctx->op->issue(avctx, pic); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); + return err; + } + + pic->encode_issued = 1; + } + + err = ctx->op->output(avctx, pic, pkt); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Output failed: %d.\n", err); + return err; + } + + ctx->output_order = pic->encode_order; + hw_base_encode_clear_old(avctx, ctx); + + /** loop to get an available pkt in encoder flushing. */ + if (ctx->end_of_stream && !pkt->size) + goto start; + +end: + if (pkt->size) + av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64", dts %"PRId64", " + "size %d bytes.\n", pkt->pts, pkt->dts, pkt->size); + + return 0; +} + +int ff_hw_base_init_gop_structure(FFHWBaseEncodeContext *ctx, AVCodecContext *avctx, + uint32_t ref_l0, uint32_t ref_l1, + int flags, int prediction_pre_only) +{ + 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; + } else if (ref_l0 < 1) { + av_log(avctx, AV_LOG_ERROR, "Driver does not support any " + "reference frames.\n"); + return AVERROR(EINVAL); + } else if (!(flags & FF_HW_FLAG_B_PICTURES) || ref_l1 < 1 || + avctx->max_b_frames < 1 || prediction_pre_only) { + if (ctx->p_to_gpb) + av_log(avctx, AV_LOG_VERBOSE, "Using intra and B-frames " + "(supported references: %d / %d).\n", + ref_l0, ref_l1); + else + av_log(avctx, AV_LOG_VERBOSE, "Using intra and P-frames " + "(supported references: %d / %d).\n", ref_l0, ref_l1); + ctx->gop_size = avctx->gop_size; + ctx->p_per_i = INT_MAX; + ctx->b_per_p = 0; + } else { + if (ctx->p_to_gpb) + av_log(avctx, AV_LOG_VERBOSE, "Using intra and B-frames " + "(supported references: %d / %d).\n", + ref_l0, ref_l1); + else + av_log(avctx, AV_LOG_VERBOSE, "Using intra, P- and B-frames " + "(supported references: %d / %d).\n", ref_l0, ref_l1); + ctx->gop_size = avctx->gop_size; + ctx->p_per_i = INT_MAX; + ctx->b_per_p = avctx->max_b_frames; + if (flags & FF_HW_FLAG_B_PICTURE_REFERENCES) { + ctx->max_b_depth = FFMIN(ctx->desired_b_depth, + av_log2(ctx->b_per_p) + 1); + } else { + ctx->max_b_depth = 1; + } + } + + if (flags & FF_HW_FLAG_NON_IDR_KEY_PICTURES) { + ctx->closed_gop = !!(avctx->flags & AV_CODEC_FLAG_CLOSED_GOP); + ctx->gop_per_idr = ctx->idr_interval + 1; + } else { + ctx->closed_gop = 1; + ctx->gop_per_idr = 1; + } + + return 0; +} + +int ff_hw_base_get_recon_format(FFHWBaseEncodeContext *ctx, const void *hwconfig, + enum AVPixelFormat *fmt) +{ + AVHWFramesConstraints *constraints = NULL; + enum AVPixelFormat recon_format; + int err, i; + + constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref, + hwconfig); + if (!constraints) { + err = AVERROR(ENOMEM); + goto fail; + } + + // Probably we can use the input surface format as the surface format + // of the reconstructed frames. If not, we just pick the first (only?) + // format in the valid list and hope that it all works. + recon_format = AV_PIX_FMT_NONE; + if (constraints->valid_sw_formats) { + for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { + if (ctx->input_frames->sw_format == + constraints->valid_sw_formats[i]) { + recon_format = ctx->input_frames->sw_format; + break; + } + } + if (recon_format == AV_PIX_FMT_NONE) { + // No match. Just use the first in the supported list and + // hope for the best. + recon_format = constraints->valid_sw_formats[0]; + } + } else { + // No idea what to use; copy input format. + recon_format = ctx->input_frames->sw_format; + } + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Using %s as format of " + "reconstructed frames.\n", av_get_pix_fmt_name(recon_format)); + + if (ctx->surface_width < constraints->min_width || + ctx->surface_height < constraints->min_height || + ctx->surface_width > constraints->max_width || + ctx->surface_height > constraints->max_height) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Hardware does not support encoding at " + "size %dx%d (constraints: width %d-%d height %d-%d).\n", + ctx->surface_width, ctx->surface_height, + constraints->min_width, constraints->max_width, + constraints->min_height, constraints->max_height); + err = AVERROR(EINVAL); + goto fail; + } + + *fmt = recon_format; + err = 0; +fail: + av_hwframe_constraints_free(&constraints); + return err; +} + +int ff_hw_base_encode_init(AVCodecContext *avctx, FFHWBaseEncodeContext *ctx) +{ + ctx->log_ctx = (void *)avctx; + + ctx->frame = av_frame_alloc(); + if (!ctx->frame) + return AVERROR(ENOMEM); + + if (!avctx->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " + "required to associate the encoding device.\n"); + return AVERROR(EINVAL); + } + + ctx->input_frames_ref = av_buffer_ref(avctx->hw_frames_ctx); + if (!ctx->input_frames_ref) + return AVERROR(ENOMEM); + + ctx->input_frames = (AVHWFramesContext *)ctx->input_frames_ref->data; + + ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref); + if (!ctx->device_ref) + return AVERROR(ENOMEM); + + ctx->device = (AVHWDeviceContext *)ctx->device_ref->data; + + ctx->tail_pkt = av_packet_alloc(); + if (!ctx->tail_pkt) + return AVERROR(ENOMEM); + + return 0; +} + +int ff_hw_base_encode_close(FFHWBaseEncodeContext *ctx) +{ + av_fifo_freep2(&ctx->encode_fifo); + + av_frame_free(&ctx->frame); + av_packet_free(&ctx->tail_pkt); + + av_buffer_unref(&ctx->device_ref); + av_buffer_unref(&ctx->input_frames_ref); + av_buffer_unref(&ctx->recon_frames_ref); + + return 0; +} diff --git a/libavcodec/hw_base_encode.h b/libavcodec/hw_base_encode.h new file mode 100644 index 000000000..e30b1e60a --- /dev/null +++ b/libavcodec/hw_base_encode.h @@ -0,0 +1,253 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_HW_BASE_ENCODE_H +#define AVCODEC_HW_BASE_ENCODE_H + +#include "avcodec.h" +#include "libavutil/hwcontext.h" +#include "libavutil/fifo.h" + +#define MAX_DPB_SIZE 16 +#define MAX_PICTURE_REFERENCES 2 +#define MAX_REORDER_DELAY 16 +#define MAX_ASYNC_DEPTH 64 +#define MAX_REFERENCE_LIST_NUM 2 + +static inline const char *ff_hw_base_encode_get_pictype_name(const int type) +{ + const char * const picture_type_name[] = { "IDR", "I", "P", "B" }; + return picture_type_name[type]; +} + +enum { + FF_HW_PICTURE_TYPE_IDR = 0, + FF_HW_PICTURE_TYPE_I = 1, + FF_HW_PICTURE_TYPE_P = 2, + FF_HW_PICTURE_TYPE_B = 3, +}; + +enum { + // Codec supports controlling the subdivision of pictures into slices. + FF_HW_FLAG_SLICE_CONTROL = 1 << 0, + // Codec only supports constant quality (no rate control). + FF_HW_FLAG_CONSTANT_QUALITY_ONLY = 1 << 1, + // Codec is intra-only. + FF_HW_FLAG_INTRA_ONLY = 1 << 2, + // Codec supports B-pictures. + FF_HW_FLAG_B_PICTURES = 1 << 3, + // Codec supports referencing B-pictures. + FF_HW_FLAG_B_PICTURE_REFERENCES = 1 << 4, + // Codec supports non-IDR key pictures (that is, key pictures do + // not necessarily empty the DPB). + FF_HW_FLAG_NON_IDR_KEY_PICTURES = 1 << 5, +}; + +typedef struct FFHWBaseEncodePicture { + // API-specific private data + void *priv; + // Codec-specific private data + void *codec_priv; + + struct FFHWBaseEncodePicture *next; + + int64_t display_order; + int64_t encode_order; + int64_t pts; + int64_t duration; + int force_idr; + + void *opaque; + AVBufferRef *opaque_ref; + + int type; + int b_depth; + int encode_issued; + int encode_complete; + + AVFrame *input_image; + AVFrame *recon_image; + + // Whether this picture is a reference picture. + int is_reference; + + // The contents of the DPB after this picture has been decoded. + // This will contain the picture itself if it is a reference picture, + // but not if it isn't. + int nb_dpb_pics; + struct FFHWBaseEncodePicture *dpb[MAX_DPB_SIZE]; + // The reference pictures used in decoding this picture. If they are + // used by later pictures they will also appear in the DPB. ref[0][] for + // previous reference frames. ref[1][] for future reference frames. + int nb_refs[MAX_REFERENCE_LIST_NUM]; + struct FFHWBaseEncodePicture *refs[MAX_REFERENCE_LIST_NUM][MAX_PICTURE_REFERENCES]; + // The previous reference picture in encode order. Must be in at least + // one of the reference list and DPB list. + struct FFHWBaseEncodePicture *prev; + // Reference count for other pictures referring to this one through + // the above pointers, directly from incomplete pictures and indirectly + // through completed pictures. + int ref_count[2]; + int ref_removed[2]; +} FFHWBaseEncodePicture; + +typedef struct FFHWEncodePictureOperation { + // Size of API-specific internal picture data + size_t priv_size; + // Initialize API-specific internals + int (*init)(AVCodecContext *avctx, FFHWBaseEncodePicture *pic); + // Issue the picture structure, which will send the frame surface to HW Encode API. + int (*issue)(AVCodecContext *avctx, FFHWBaseEncodePicture *pic); + // Get the output AVPacket. + int (*output)(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, AVPacket *pkt); + // Free the picture structure. + int (*free)(AVCodecContext *avctx, FFHWBaseEncodePicture *pic); +} FFHWEncodePictureOperation; + +typedef struct FFHWBaseEncodeContext { + const AVClass *class; + void *log_ctx; + + // Hardware-specific hooks. + const struct FFHWEncodePictureOperation *op; + + // Global options. + + // Number of I frames between IDR frames. + int idr_interval; + + // Desired B frame reference depth. + int desired_b_depth; + + // The required size of surfaces. This is probably the input + // size (AVCodecContext.width|height) aligned up to whatever + // block size is required by the codec. + int surface_width; + int surface_height; + + // The block size for slice calculations. + int slice_block_width; + int slice_block_height; + + // The hardware device context. + AVBufferRef *device_ref; + AVHWDeviceContext *device; + + // The hardware frame context containing the input frames. + AVBufferRef *input_frames_ref; + AVHWFramesContext *input_frames; + + // The hardware frame context containing the reconstructed frames. + AVBufferRef *recon_frames_ref; + AVHWFramesContext *recon_frames; + + // Current encoding window, in display (input) order. + FFHWBaseEncodePicture *pic_start, *pic_end; + // The next picture to use as the previous reference picture in + // encoding order. Order from small to large in encoding order. + FFHWBaseEncodePicture *next_prev[MAX_PICTURE_REFERENCES]; + int nb_next_prev; + + // Next input order index (display order). + int64_t input_order; + // Number of frames that output is behind input. + int64_t output_delay; + // Next encode order index. + int64_t encode_order; + // Number of frames decode output will need to be delayed. + int64_t decode_delay; + // Next output order index (in encode order). + int64_t output_order; + + // Timestamp handling. + int64_t first_pts; + int64_t dts_pts_diff; + int64_t ts_ring[MAX_REORDER_DELAY * 3 + + MAX_ASYNC_DEPTH]; + + // Frame type decision. + int gop_size; + int closed_gop; + int gop_per_idr; + int p_per_i; + int max_b_depth; + int b_per_p; + int force_idr; + int idr_counter; + int gop_counter; + int end_of_stream; + int p_to_gpb; + + // Whether the driver supports ROI at all. + int roi_allowed; + + // The encoder does not support cropping information, so warn about + // it the first time we encounter any nonzero crop fields. + int crop_warned; + // If the driver does not support ROI then warn the first time we + // encounter a frame with ROI side data. + int roi_warned; + + // The frame to be filled with data. + AVFrame *frame; + + // Whether the HW supports sync buffer function. + // If supported, encode_fifo/async_depth will be used together. + // Used for output buffer synchronization. + int async_encode; + + // Store buffered pic. + AVFifo *encode_fifo; + // Max number of frame buffered in encoder. + int async_depth; + + /** Tail data of a pic, now only used for av1 repeat frame header. */ + AVPacket *tail_pkt; +} FFHWBaseEncodeContext; + +int ff_hw_base_encode_set_output_property(FFHWBaseEncodeContext *ctx, AVCodecContext *avctx, + FFHWBaseEncodePicture *pic, AVPacket *pkt, int flag_no_delay); + +int ff_hw_base_encode_receive_packet(FFHWBaseEncodeContext *ctx, AVCodecContext *avctx, AVPacket *pkt); + +int ff_hw_base_init_gop_structure(FFHWBaseEncodeContext *ctx, AVCodecContext *avctx, + uint32_t ref_l0, uint32_t ref_l1, + int flags, int prediction_pre_only); + +int ff_hw_base_get_recon_format(FFHWBaseEncodeContext *ctx, const void *hwconfig, + enum AVPixelFormat *fmt); + +int ff_hw_base_encode_init(AVCodecContext *avctx, FFHWBaseEncodeContext *ctx); + +int ff_hw_base_encode_close(FFHWBaseEncodeContext *ctx); + +#define HW_BASE_ENCODE_COMMON_OPTIONS \ + { "idr_interval", \ + "Distance (in I-frames) between key frames", \ + OFFSET(common.base.idr_interval), AV_OPT_TYPE_INT, \ + { .i64 = 0 }, 0, INT_MAX, FLAGS }, \ + { "b_depth", \ + "Maximum B-frame reference depth", \ + OFFSET(common.base.desired_b_depth), AV_OPT_TYPE_INT, \ + { .i64 = 1 }, 1, INT_MAX, FLAGS }, \ + { "async_depth", "Maximum processing parallelism. " \ + "Increase this to improve single channel performance.", \ + OFFSET(common.base.async_depth), AV_OPT_TYPE_INT, \ + { .i64 = 2 }, 1, MAX_ASYNC_DEPTH, FLAGS } + +#endif /* AVCODEC_HW_BASE_ENCODE_H */ diff --git a/libavcodec/hw_base_encode_h264.c b/libavcodec/hw_base_encode_h264.c new file mode 100644 index 000000000..03c79ab6c --- /dev/null +++ b/libavcodec/hw_base_encode_h264.c @@ -0,0 +1,265 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 "hw_base_encode_h264.h" + +#include "h2645data.h" +#include "h264_levels.h" + +#include "libavutil/pixdesc.h" + +int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext *base_ctx, + AVCodecContext *avctx, + FFHWBaseEncodeH264 *common, + FFHWBaseEncodeH264Opts *opts) +{ + H264RawSPS *sps = &common->raw_sps; + H264RawPPS *pps = &common->raw_pps; + const AVPixFmtDescriptor *desc; + int bit_depth; + + memset(sps, 0, sizeof(*sps)); + memset(pps, 0, sizeof(*pps)); + + desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); + av_assert0(desc); + if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc->log2_chroma_h != 1) { + 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; + + sps->nal_unit_header.nal_ref_idc = 3; + sps->nal_unit_header.nal_unit_type = H264_NAL_SPS; + + sps->profile_idc = avctx->profile & 0xff; + + if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE || + avctx->profile == AV_PROFILE_H264_MAIN) + sps->constraint_set1_flag = 1; + + if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10) + sps->constraint_set3_flag = base_ctx->gop_size == 1; + + if (avctx->profile == AV_PROFILE_H264_MAIN || + avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10) { + sps->constraint_set4_flag = 1; + sps->constraint_set5_flag = base_ctx->b_per_p == 0; + } + + if (base_ctx->gop_size == 1) + common->dpb_frames = 0; + else + common->dpb_frames = 1 + base_ctx->max_b_depth; + + if (avctx->level != AV_LEVEL_UNKNOWN) { + sps->level_idc = avctx->level; + } else { + const H264LevelDescriptor *level; + int framerate; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + framerate = avctx->framerate.num / avctx->framerate.den; + else + framerate = 0; + + level = ff_h264_guess_level(sps->profile_idc, + opts->bit_rate, + framerate, + opts->mb_width * 16, + opts->mb_height * 16, + common->dpb_frames); + if (level) { + av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); + if (level->constraint_set3_flag) + sps->constraint_set3_flag = 1; + sps->level_idc = level->level_idc; + } else { + av_log(avctx, AV_LOG_WARNING, "Stream will not conform " + "to any level: using level 6.2.\n"); + sps->level_idc = 62; + } + } + + sps->seq_parameter_set_id = 0; + sps->chroma_format_idc = 1; + sps->bit_depth_luma_minus8 = bit_depth - 8; + sps->bit_depth_chroma_minus8 = bit_depth - 8; + + sps->log2_max_frame_num_minus4 = 4; + sps->pic_order_cnt_type = base_ctx->max_b_depth ? 0 : 2; + if (sps->pic_order_cnt_type == 0) { + sps->log2_max_pic_order_cnt_lsb_minus4 = 4; + } + + sps->max_num_ref_frames = common->dpb_frames; + + sps->pic_width_in_mbs_minus1 = opts->mb_width - 1; + sps->pic_height_in_map_units_minus1 = opts->mb_height - 1; + + sps->frame_mbs_only_flag = 1; + sps->direct_8x8_inference_flag = 1; + + if (avctx->width != 16 * opts->mb_width || + avctx->height != 16 * opts->mb_height) { + sps->frame_cropping_flag = 1; + + sps->frame_crop_left_offset = 0; + sps->frame_crop_right_offset = + (16 * opts->mb_width - avctx->width) / 2; + sps->frame_crop_top_offset = 0; + sps->frame_crop_bottom_offset = + (16 * opts->mb_height - avctx->height) / 2; + } else { + sps->frame_cropping_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) { + sps->vui.aspect_ratio_idc = i; + break; + } + } + if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) { + sps->vui.aspect_ratio_idc = 255; + sps->vui.sar_width = num; + sps->vui.sar_height = den; + } + sps->vui.aspect_ratio_info_present_flag = 1; + } + + // Unspecified video format, from table E-2. + sps->vui.video_format = 5; + sps->vui.video_full_range_flag = + avctx->color_range == AVCOL_RANGE_JPEG; + sps->vui.colour_primaries = avctx->color_primaries; + sps->vui.transfer_characteristics = avctx->color_trc; + sps->vui.matrix_coefficients = avctx->colorspace; + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) + sps->vui.colour_description_present_flag = 1; + if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED || + sps->vui.colour_description_present_flag) + sps->vui.video_signal_type_present_flag = 1; + + if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) { + sps->vui.chroma_loc_info_present_flag = 1; + sps->vui.chroma_sample_loc_type_top_field = + sps->vui.chroma_sample_loc_type_bottom_field = + avctx->chroma_sample_location - 1; + } + + sps->vui.timing_info_present_flag = 1; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + sps->vui.num_units_in_tick = avctx->framerate.den; + sps->vui.time_scale = 2 * avctx->framerate.num; + sps->vui.fixed_frame_rate_flag = 1; + } else { + sps->vui.num_units_in_tick = avctx->time_base.num; + sps->vui.time_scale = 2 * avctx->time_base.den; + sps->vui.fixed_frame_rate_flag = 0; + } + + if (opts->flags & FF_HW_H264_SEI_TIMING) { + H264RawHRD *hrd = &sps->vui.nal_hrd_parameters; + H264RawSEIBufferingPeriod *bp = &common->sei_buffering_period; + + sps->vui.nal_hrd_parameters_present_flag = 1; + + hrd->cpb_cnt_minus1 = 0; + + // Try to scale these to a sensible range so that the + // golomb encode of the value is not overlong. + hrd->bit_rate_scale = + av_clip_uintp2(av_log2(opts->bit_rate) - 15 - 6, 4); + hrd->bit_rate_value_minus1[0] = + (opts->bit_rate >> hrd->bit_rate_scale + 6) - 1; + + hrd->cpb_size_scale = + av_clip_uintp2(av_log2(opts->hrd_buffer_size) - 15 - 4, 4); + hrd->cpb_size_value_minus1[0] = + (opts->hrd_buffer_size >> hrd->cpb_size_scale + 4) - 1; + + // CBR mode as defined for the HRD cannot be achieved without filler + // data, so this flag cannot be set even with VAAPI CBR modes. + hrd->cbr_flag[0] = 0; + + hrd->initial_cpb_removal_delay_length_minus1 = 23; + hrd->cpb_removal_delay_length_minus1 = 23; + hrd->dpb_output_delay_length_minus1 = 7; + hrd->time_offset_length = 0; + + bp->seq_parameter_set_id = sps->seq_parameter_set_id; + + // This calculation can easily overflow 32 bits. + bp->nal.initial_cpb_removal_delay[0] = 90000 * + (uint64_t)opts->initial_buffer_fullness / + opts->hrd_buffer_size; + bp->nal.initial_cpb_removal_delay_offset[0] = 0; + } else { + sps->vui.nal_hrd_parameters_present_flag = 0; + sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag; + } + + sps->vui.bitstream_restriction_flag = 1; + sps->vui.motion_vectors_over_pic_boundaries_flag = 1; + sps->vui.log2_max_mv_length_horizontal = 15; + sps->vui.log2_max_mv_length_vertical = 15; + sps->vui.max_num_reorder_frames = base_ctx->max_b_depth; + sps->vui.max_dec_frame_buffering = base_ctx->max_b_depth + 1; + + pps->nal_unit_header.nal_ref_idc = 3; + pps->nal_unit_header.nal_unit_type = H264_NAL_PPS; + + pps->pic_parameter_set_id = 0; + pps->seq_parameter_set_id = 0; + + pps->entropy_coding_mode_flag = + !(sps->profile_idc == AV_PROFILE_H264_BASELINE || + sps->profile_idc == AV_PROFILE_H264_EXTENDED || + sps->profile_idc == AV_PROFILE_H264_CAVLC_444); + if (!opts->cabac && pps->entropy_coding_mode_flag) + pps->entropy_coding_mode_flag = 0; + + pps->num_ref_idx_l0_default_active_minus1 = 0; + pps->num_ref_idx_l1_default_active_minus1 = 0; + + pps->pic_init_qp_minus26 = opts->fixed_qp_idr - 26; + + if (sps->profile_idc == AV_PROFILE_H264_BASELINE || + sps->profile_idc == AV_PROFILE_H264_EXTENDED || + sps->profile_idc == AV_PROFILE_H264_MAIN) { + pps->more_rbsp_data = 0; + } else { + pps->more_rbsp_data = 1; + + pps->transform_8x8_mode_flag = 1; + } + + return 0; +} diff --git a/libavcodec/hw_base_encode_h264.h b/libavcodec/hw_base_encode_h264.h new file mode 100644 index 000000000..9bc6ad69a --- /dev/null +++ b/libavcodec/hw_base_encode_h264.h @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HW_BASE_ENCODE_H264_H +#define AVCODEC_HW_BASE_ENCODE_H264_H + +#include "hw_base_encode.h" +#include "cbs_h264.h" + +typedef struct FFHWBaseEncodeH264 { + H264RawSPS raw_sps; + H264RawPPS raw_pps; + + H264RawSEIBufferingPeriod sei_buffering_period; + + int dpb_frames; +} FFHWBaseEncodeH264; + +typedef struct FFHWBaseEncodeH264Opts { + int flags; +#define FF_HW_H264_SEI_TIMING (1 << 0) + + int mb_width; + int mb_height; + int64_t bit_rate; + int cabac; + int fixed_qp_idr; + uint64_t hrd_buffer_size; + uint64_t initial_buffer_fullness; +} FFHWBaseEncodeH264Opts; + +int ff_hw_base_encode_init_params_h264(FFHWBaseEncodeContext *base_ctx, + AVCodecContext *avctx, + FFHWBaseEncodeH264 *common, + FFHWBaseEncodeH264Opts *opts); + +#endif /* AVCODEC_HW_BASE_ENCODE_H264_H */ diff --git a/libavcodec/hw_base_encode_h265.c b/libavcodec/hw_base_encode_h265.c new file mode 100644 index 000000000..dceec8aba --- /dev/null +++ b/libavcodec/hw_base_encode_h265.c @@ -0,0 +1,351 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 "hw_base_encode_h265.h" + +#include "h2645data.h" +#include "h265_profile_level.h" + +#include "libavutil/pixdesc.h" + +int ff_hw_base_encode_init_params_h265(FFHWBaseEncodeContext *base_ctx, + AVCodecContext *avctx, + FFHWBaseEncodeH265 *common, + FFHWBaseEncodeH265Opts *opts) +{ + H265RawVPS *vps = &common->raw_vps; + H265RawSPS *sps = &common->raw_sps; + H265RawPPS *pps = &common->raw_pps; + H265RawProfileTierLevel *ptl = &vps->profile_tier_level; + H265RawVUI *vui = &sps->vui; + + const AVPixFmtDescriptor *desc; + int chroma_format, bit_depth; + int i; + + memset(vps, 0, sizeof(*vps)); + memset(sps, 0, sizeof(*sps)); + memset(pps, 0, sizeof(*pps)); + + 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; + + + // VPS + + vps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_VPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + + 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 = opts->tier; + + ptl->general_profile_compatibility_flag[ptl->general_profile_idc] = 1; + + if (ptl->general_profile_compatibility_flag[1]) + ptl->general_profile_compatibility_flag[2] = 1; + if (ptl->general_profile_compatibility_flag[3]) { + ptl->general_profile_compatibility_flag[1] = 1; + ptl->general_profile_compatibility_flag[2] = 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 != AV_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, + opts->nb_slices, opts->tile_rows, opts->tile_cols, + (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; + } + } + + 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; + + sps->pic_width_in_luma_samples = base_ctx->surface_width; + sps->pic_height_in_luma_samples = base_ctx->surface_height; + + if (avctx->width != base_ctx->surface_width || + avctx->height != base_ctx->surface_height) { + sps->conformance_window_flag = 1; + sps->conf_win_left_offset = 0; + sps->conf_win_right_offset = + (base_ctx->surface_width - avctx->width) >> desc->log2_chroma_w; + sps->conf_win_top_offset = 0; + sps->conf_win_bottom_offset = + (base_ctx->surface_height - avctx->height) >> desc->log2_chroma_h; + } else { + 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 = 8; + + 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]; + } + + // These values come from the capabilities of the first encoder + // implementation in the i965 driver on Intel Skylake. They may + // fail badly with other platforms or drivers. + // CTB size from 8x8 to 32x32. + sps->log2_min_luma_coding_block_size_minus3 = 0; + sps->log2_diff_max_min_luma_coding_block_size = 2; + // Transform size from 4x4 to 32x32. + sps->log2_min_luma_transform_block_size_minus2 = 0; + sps->log2_diff_max_min_luma_transform_block_size = 3; + // Full transform hierarchy allowed (2-5). + sps->max_transform_hierarchy_depth_inter = 3; + sps->max_transform_hierarchy_depth_intra = 3; + // AMP works. + sps->amp_enabled_flag = 1; + // SAO and temporal MVP do not work. + sps->sample_adaptive_offset_enabled_flag = 0; + sps->sps_temporal_mvp_enabled_flag = 0; + + sps->pcm_enabled_flag = 0; + + // STRPSs should ideally be here rather than defined individually in + // each slice, but the structure isn't completely fixed so for now + // don't bother. + sps->num_short_term_ref_pic_sets = 0; + sps->long_term_ref_pics_present_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->num_ref_idx_l0_default_active_minus1 = 0; + pps->num_ref_idx_l1_default_active_minus1 = 0; + + pps->init_qp_minus26 = opts->fixed_qp_idr - 26; + + pps->cu_qp_delta_enabled_flag = opts->cu_qp_delta_enabled_flag; + pps->diff_cu_qp_delta_depth = 0; + + if (opts->tile_rows && opts->tile_cols) { + int uniform_spacing; + + pps->tiles_enabled_flag = 1; + pps->num_tile_columns_minus1 = opts->tile_cols - 1; + pps->num_tile_rows_minus1 = opts->tile_rows - 1; + + // Test whether the spacing provided matches the H.265 uniform + // spacing, and set the flag if it does. + uniform_spacing = 1; + for (i = 0; i <= pps->num_tile_columns_minus1 && + uniform_spacing; i++) { + if (opts->col_width[i] != + (i + 1) * opts->slice_block_cols / opts->tile_cols - + i * opts->slice_block_cols / opts->tile_cols) + uniform_spacing = 0; + } + for (i = 0; i <= pps->num_tile_rows_minus1 && + uniform_spacing; i++) { + if (opts->row_height[i] != + (i + 1) * opts->slice_block_rows / opts->tile_rows - + i * opts->slice_block_rows / opts->tile_rows) + uniform_spacing = 0; + } + pps->uniform_spacing_flag = uniform_spacing; + + for (i = 0; i <= pps->num_tile_columns_minus1; i++) + pps->column_width_minus1[i] = opts->col_width[i] - 1; + for (i = 0; i <= pps->num_tile_rows_minus1; i++) + pps->row_height_minus1[i] = opts->row_height[i] - 1; + + pps->loop_filter_across_tiles_enabled_flag = 1; + } + + pps->pps_loop_filter_across_slices_enabled_flag = 1; + + return 0; +} diff --git a/libavcodec/hw_base_encode_h265.h b/libavcodec/hw_base_encode_h265.h new file mode 100644 index 000000000..468f91c9b --- /dev/null +++ b/libavcodec/hw_base_encode_h265.h @@ -0,0 +1,56 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_HW_BASE_ENCODE_H265_H +#define AVCODEC_HW_BASE_ENCODE_H265_H + +#include "hw_base_encode.h" +#include "cbs_h265.h" + +typedef struct FFHWBaseEncodeH265 { + H265RawVPS raw_vps; + H265RawSPS raw_sps; + H265RawPPS raw_pps; + + int dpb_frames; +} FFHWBaseEncodeH265; + +typedef struct FFHWBaseEncodeH265Opts { + int tier; + int fixed_qp_idr; + int cu_qp_delta_enabled_flag; + + int tile_rows; + int tile_cols; + + int nb_slices; + int slice_block_rows; + int slice_block_cols; + + // Tile width of the i-th column. + int col_width[22]; + // Tile height of i-th row. + int row_height[22]; +} FFHWBaseEncodeH265Opts; + +int ff_hw_base_encode_init_params_h265(FFHWBaseEncodeContext *base_ctx, + AVCodecContext *avctx, + FFHWBaseEncodeH265 *common, + FFHWBaseEncodeH265Opts *opts); + +#endif /* AVCODEC_HW_BASE_ENCODE_H265_H */ diff --git a/libavcodec/idctdsp.c b/libavcodec/idctdsp.c index de879f730..4259a117d 100644 --- a/libavcodec/idctdsp.c +++ b/libavcodec/idctdsp.c @@ -294,8 +294,6 @@ av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx) #if ARCH_AARCH64 ff_idctdsp_init_aarch64(c, avctx, high_bit_depth); -#elif ARCH_ALPHA - ff_idctdsp_init_alpha(c, avctx, high_bit_depth); #elif ARCH_ARM ff_idctdsp_init_arm(c, avctx, high_bit_depth); #elif ARCH_PPC diff --git a/libavcodec/iff.c b/libavcodec/iff.c index 32d771b88..13010b451 100644 --- a/libavcodec/iff.c +++ b/libavcodec/iff.c @@ -29,6 +29,7 @@ #include #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "bytestream.h" #include "avcodec.h" @@ -1661,7 +1662,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, gb); + decode_byterun(s->planebuf, s->planesize, gb); if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { memcpy(video, s->planebuf, s->planesize); video += s->planesize; @@ -1674,7 +1675,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->mask_buf, 0, avctx->width * sizeof(uint32_t)); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, gb); + decode_byterun(s->planebuf, s->planesize, gb); decodeplane32(s->mask_buf, s->planebuf, s->planesize, plane); } lookup_pal_indicies((uint32_t *)row, s->mask_buf, s->mask_palbuf, avctx->width); @@ -1685,7 +1686,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(s->ham_buf, 0, s->planesize * 8); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, gb); + decode_byterun(s->planebuf, s->planesize, gb); if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { memcpy(video, s->planebuf, s->planesize); video += s->planesize; @@ -1699,7 +1700,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, uint8_t *row = &frame->data[0][y * frame->linesize[0]]; memset(row, 0, avctx->width << 2); for (plane = 0; plane < s->bpp; plane++) { - buf += decode_byterun(s->planebuf, s->planesize, gb); + decode_byterun(s->planebuf, s->planesize, gb); decodeplane32((uint32_t *)row, s->planebuf, s->planesize, plane); } } @@ -1708,12 +1709,12 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { for (y = 0; y < avctx->height; y++) { uint8_t *row = &frame->data[0][y * frame->linesize[0]]; - buf += decode_byterun(row, avctx->width, gb); + decode_byterun(row, avctx->width, gb); } } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32 for (y = 0; y < avctx->height; y++) { uint8_t *row = &frame->data[0][y * frame->linesize[0]]; - buf += decode_byterun(s->ham_buf, avctx->width, gb); + decode_byterun(s->ham_buf, avctx->width, gb); decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize); } } else diff --git a/libavcodec/iirfilter.c b/libavcodec/iirfilter.c index 727a37044..cefe35ab6 100644 --- a/libavcodec/iirfilter.c +++ b/libavcodec/iirfilter.c @@ -277,20 +277,6 @@ av_cold struct FFIIRFilterState *ff_iir_filter_init_state(int order) } \ } -void ff_iir_filter(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) - } -} - /** * Perform IIR filtering on floating-point input samples. * diff --git a/libavcodec/iirfilter.h b/libavcodec/iirfilter.h index d6b8fe278..8ab8ae68c 100644 --- a/libavcodec/iirfilter.h +++ b/libavcodec/iirfilter.h @@ -28,7 +28,6 @@ #define AVCODEC_IIRFILTER_H #include -#include struct FFIIRFilterCoeffs; struct FFIIRFilterState; @@ -114,18 +113,4 @@ void ff_iir_filter_free_coeffsp(struct FFIIRFilterCoeffs **coeffs); */ void ff_iir_filter_free_statep(struct FFIIRFilterState **state); -/** - * Perform IIR filtering on signed 16-bit 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 ff_iir_filter(const struct FFIIRFilterCoeffs *coeffs, struct FFIIRFilterState *state, - int size, const int16_t *src, ptrdiff_t sstep, int16_t *dst, ptrdiff_t dstep); - #endif /* AVCODEC_IIRFILTER_H */ diff --git a/libavcodec/ilbcdec.c b/libavcodec/ilbcdec.c index ba1da168b..7fea39b43 100644 --- a/libavcodec/ilbcdec.c +++ b/libavcodec/ilbcdec.c @@ -658,7 +658,7 @@ static void get_codebook(int16_t * cbvec, /* (o) Constructed codebook vector * int16_t k, base_size; int16_t lag; /* Stack based */ - int16_t tempbuff2[SUBL + 5]; + int16_t tempbuff2[SUBL + 5] = {0}; /* Determine size of codebook sections */ base_size = lMem - cbveclen + 1; diff --git a/libavcodec/imc.c b/libavcodec/imc.c index 99eb08923..5891e3621 100644 --- a/libavcodec/imc.c +++ b/libavcodec/imc.c @@ -38,6 +38,7 @@ #include "libavutil/ffmath.h" #include "libavutil/float_dsp.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" #include "libavutil/tx.h" diff --git a/libavcodec/imm4.c b/libavcodec/imm4.c index ef7e692b8..573b61483 100644 --- a/libavcodec/imm4.c +++ b/libavcodec/imm4.c @@ -23,6 +23,7 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" @@ -452,6 +453,10 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if (ret < 0) return ret; + if (((avctx->width + 15) / 16) * ((avctx->height + 15) / 16) > get_bits_left(gb)) + return AVERROR_INVALIDDATA; + + if ((ret = ff_get_buffer(avctx, frame, (frame->flags & AV_FRAME_FLAG_KEY) ? AV_GET_BUFFER_FLAG_REF : 0)) < 0) return ret; diff --git a/libavcodec/indeo3.c b/libavcodec/indeo3.c index 7bb0235bd..fbabd4b6a 100644 --- a/libavcodec/indeo3.c +++ b/libavcodec/indeo3.c @@ -31,6 +31,7 @@ #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/intelh263dec.c b/libavcodec/intelh263dec.c index f8eeb6b44..4efae7938 100644 --- a/libavcodec/intelh263dec.c +++ b/libavcodec/intelh263dec.c @@ -19,12 +19,10 @@ */ #include "codec_internal.h" -#include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "h263data.h" #include "h263dec.h" -#include "mpegvideodata.h" /* don't understand why they choose a different header ! */ int ff_intel_h263_decode_picture_header(MpegEncContext *s) @@ -134,8 +132,9 @@ const FFCodec ff_h263i_decoder = { .p.id = AV_CODEC_ID_H263I, .priv_data_size = sizeof(MpegEncContext), .init = ff_h263_decode_init, - .close = ff_h263_decode_end, FF_CODEC_DECODE_CB(ff_h263_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, }; diff --git a/libavcodec/internal.h b/libavcodec/internal.h index 64fe0122c..98ab2797c 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -53,6 +53,13 @@ typedef struct AVCodecInternal { */ int is_copy; + /** + * This field is set to 1 when frame threading is being used and the parent + * AVCodecContext of this AVCodecInternal is a worker-thread context (i.e. + * one of those actually doing the decoding), 0 otherwise. + */ + int is_frame_mt; + /** * Audio encoders can set this flag during init to indicate that they * want the small last frame to be padded to a multiple of pad_samples. @@ -61,6 +68,8 @@ typedef struct AVCodecInternal { struct FramePool *pool; + struct FFRefStructPool *progress_frame_pool; + void *thread_ctx; /** @@ -121,7 +130,11 @@ typedef struct AVCodecInternal { void *hwaccel_priv_data; /** - * checks API usage: after codec draining, flush is required to resume operation + * decoding: AVERROR_EOF has been returned from ff_decode_get_packet(); must + * not be used by decoders that use the decode() callback, as they + * do not call ff_decode_get_packet() directly. + * + * encoding: a flush frame has been submitted to avcodec_send_frame(). */ int draining; diff --git a/libavcodec/interplayacm.c b/libavcodec/interplayacm.c index 057ab16e8..2ae992a71 100644 --- a/libavcodec/interplayacm.c +++ b/libavcodec/interplayacm.c @@ -19,6 +19,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #define BITSTREAM_READER_LE diff --git a/libavcodec/intrax8.c b/libavcodec/intrax8.c index 948391599..f1dce86a5 100644 --- a/libavcodec/intrax8.c +++ b/libavcodec/intrax8.c @@ -22,6 +22,7 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "avcodec.h" #include "get_bits.h" @@ -729,7 +730,7 @@ av_cold void ff_intrax8_common_end(IntraX8Context *w) av_freep(&w->prediction_table); } -int ff_intrax8_decode_picture(IntraX8Context *w, Picture *pict, +int ff_intrax8_decode_picture(IntraX8Context *w, MPVPicture *pict, GetBitContext *gb, int *mb_x, int *mb_y, int dquant, int quant_offset, int loopfilter, int lowdelay) diff --git a/libavcodec/intrax8.h b/libavcodec/intrax8.h index 8e22361f1..b9f8c4250 100644 --- a/libavcodec/intrax8.h +++ b/libavcodec/intrax8.h @@ -106,7 +106,7 @@ void ff_intrax8_common_end(IntraX8Context *w); * @param quant_offset offset away from zero * @param loopfilter enable filter after decoding a block */ -int ff_intrax8_decode_picture(IntraX8Context *w, Picture *pict, +int ff_intrax8_decode_picture(IntraX8Context *w, MPVPicture *pict, GetBitContext *gb, int *mb_x, int *mb_y, int quant, int halfpq, int loopfilter, int lowdelay); diff --git a/libavcodec/ituh263dec.c b/libavcodec/ituh263dec.c index aeeda1cc4..e0f3034e5 100644 --- a/libavcodec/ituh263dec.c +++ b/libavcodec/ituh263dec.c @@ -59,19 +59,19 @@ #define H263_MBTYPE_B_VLC_BITS 6 #define CBPC_B_VLC_BITS 3 -static const int h263_mb_type_b_map[15]= { - MB_TYPE_DIRECT2 | MB_TYPE_L0L1, - MB_TYPE_DIRECT2 | MB_TYPE_L0L1 | MB_TYPE_CBP, - MB_TYPE_DIRECT2 | MB_TYPE_L0L1 | MB_TYPE_CBP | MB_TYPE_QUANT, - MB_TYPE_L0 | MB_TYPE_16x16, - MB_TYPE_L0 | MB_TYPE_CBP | MB_TYPE_16x16, - MB_TYPE_L0 | MB_TYPE_CBP | MB_TYPE_QUANT | MB_TYPE_16x16, - MB_TYPE_L1 | MB_TYPE_16x16, - MB_TYPE_L1 | MB_TYPE_CBP | MB_TYPE_16x16, - MB_TYPE_L1 | MB_TYPE_CBP | MB_TYPE_QUANT | MB_TYPE_16x16, - MB_TYPE_L0L1 | MB_TYPE_16x16, - MB_TYPE_L0L1 | MB_TYPE_CBP | MB_TYPE_16x16, - MB_TYPE_L0L1 | MB_TYPE_CBP | MB_TYPE_QUANT | MB_TYPE_16x16, +static const int16_t h263_mb_type_b_map[15]= { + MB_TYPE_DIRECT2 | MB_TYPE_BIDIR_MV, + MB_TYPE_DIRECT2 | MB_TYPE_BIDIR_MV | MB_TYPE_CBP, + MB_TYPE_DIRECT2 | MB_TYPE_BIDIR_MV | MB_TYPE_CBP | MB_TYPE_QUANT, + MB_TYPE_FORWARD_MV | MB_TYPE_16x16, + MB_TYPE_FORWARD_MV | MB_TYPE_CBP | MB_TYPE_16x16, + MB_TYPE_FORWARD_MV | MB_TYPE_CBP | MB_TYPE_QUANT | MB_TYPE_16x16, + MB_TYPE_BACKWARD_MV | MB_TYPE_16x16, + MB_TYPE_BACKWARD_MV | MB_TYPE_CBP | MB_TYPE_16x16, + MB_TYPE_BACKWARD_MV | MB_TYPE_CBP | MB_TYPE_QUANT | MB_TYPE_16x16, + MB_TYPE_BIDIR_MV | MB_TYPE_16x16, + MB_TYPE_BIDIR_MV | MB_TYPE_CBP | MB_TYPE_16x16, + MB_TYPE_BIDIR_MV | MB_TYPE_CBP | MB_TYPE_QUANT | MB_TYPE_16x16, 0, //stuffing MB_TYPE_INTRA4x4 | MB_TYPE_CBP, MB_TYPE_INTRA4x4 | MB_TYPE_CBP | MB_TYPE_QUANT, @@ -125,9 +125,10 @@ static av_cold void h263_decode_init_vlc(void) 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_TABLE(h263_mbtype_b_vlc, H263_MBTYPE_B_VLC_BITS, 15, - &ff_h263_mbtype_b_tab[0][1], 2, 1, - &ff_h263_mbtype_b_tab[0][0], 2, 1, 0); + VLC_INIT_STATIC_SPARSE_TABLE(h263_mbtype_b_vlc, H263_MBTYPE_B_VLC_BITS, 15, + &ff_h263_mbtype_b_tab[0][1], 2, 1, + &ff_h263_mbtype_b_tab[0][0], 2, 1, + h263_mb_type_b_map, 2, 2, 0); VLC_INIT_STATIC_TABLE(cbpc_b_vlc, CBPC_B_VLC_BITS, 4, &ff_cbpc_b_tab[0][1], 2, 1, &ff_cbpc_b_tab[0][0], 2, 1, 0); @@ -357,20 +358,20 @@ static void preview_obmc(MpegEncContext *s){ do{ if (get_bits1(&s->gb)) { /* skip mb */ - mot_val = s->current_picture.motion_val[0][s->block_index[0]]; + mot_val = s->cur_pic.motion_val[0][s->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->current_picture.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0; + s->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); }while(cbpc == 20); if(cbpc & 4){ - s->current_picture.mb_type[xy] = MB_TYPE_INTRA; + s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; }else{ get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpc & 8) { @@ -382,7 +383,7 @@ static void preview_obmc(MpegEncContext *s){ } if ((cbpc & 16) == 0) { - s->current_picture.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_L0; + s->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) @@ -400,7 +401,7 @@ static void preview_obmc(MpegEncContext *s){ mot_val[1 ]= mot_val[3 ]= mot_val[1+stride]= mot_val[3+stride]= my; } else { - s->current_picture.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_L0; + s->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) @@ -534,7 +535,7 @@ static int h263_decode_block(MpegEncContext * s, int16_t * block, int n, int coded) { int level, i, j, run; - RLTable *rl = &ff_h263_rl_inter; + const RLTable *rl = &ff_h263_rl_inter; const uint8_t *scan_table; GetBitContext gb= s->gb; @@ -719,7 +720,7 @@ static int h263_get_modb(GetBitContext *gb, int pb_frame, int *cbpb) #define tab_size ((signed)FF_ARRAY_ELEMS(s->direct_scale_mv[0])) #define tab_bias (tab_size / 2) -static inline void set_one_direct_mv(MpegEncContext *s, Picture *p, int i) +static inline void set_one_direct_mv(MpegEncContext *s, const MPVPicture *p, int i) { int xy = s->block_index[i]; uint16_t time_pp = s->pp_time; @@ -750,12 +751,12 @@ static inline void set_one_direct_mv(MpegEncContext *s, Picture *p, int i) static int set_direct_mv(MpegEncContext *s) { const int mb_index = s->mb_x + s->mb_y * s->mb_stride; - Picture *p = &s->next_picture; + const MPVPicture *p = s->next_pic.ptr; int colocated_mb_type = p->mb_type[mb_index]; int i; if (s->codec_tag == AV_RL32("U263") && p->f->pict_type == AV_PICTURE_TYPE_I) { - p = &s->last_picture; + p = s->last_pic.ptr; colocated_mb_type = p->mb_type[mb_index]; } @@ -763,7 +764,7 @@ static int set_direct_mv(MpegEncContext *s) s->mv_type = MV_TYPE_8X8; for (i = 0; i < 4; i++) set_one_direct_mv(s, p, i); - return MB_TYPE_DIRECT2 | MB_TYPE_8x8 | MB_TYPE_L0L1; + return MB_TYPE_DIRECT2 | MB_TYPE_8x8 | MB_TYPE_BIDIR_MV; } else { set_one_direct_mv(s, p, 0); s->mv[0][1][0] = @@ -780,7 +781,7 @@ static int set_direct_mv(MpegEncContext *s) s->mv[1][3][1] = s->mv[1][0][1]; s->mv_type = MV_TYPE_8X8; // Note see prev line - return MB_TYPE_DIRECT2 | MB_TYPE_16x16 | MB_TYPE_L0L1; + return MB_TYPE_DIRECT2 | MB_TYPE_16x16 | MB_TYPE_BIDIR_MV; } } @@ -803,7 +804,7 @@ int ff_h263_decode_mb(MpegEncContext *s, s->block_last_index[i] = -1; s->mv_dir = MV_DIR_FORWARD; s->mv_type = MV_TYPE_16X16; - s->current_picture.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0; + 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); @@ -841,7 +842,7 @@ int ff_h263_decode_mb(MpegEncContext *s, s->mv_dir = MV_DIR_FORWARD; if ((cbpc & 16) == 0) { - s->current_picture.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_L0; + s->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); @@ -866,7 +867,7 @@ int ff_h263_decode_mb(MpegEncContext *s, if (s->umvplus && (mx - pred_x) == 1 && (my - pred_y) == 1) skip_bits1(&s->gb); /* Bit stuffing to prevent PSC */ } else { - s->current_picture.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_L0; + s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; s->mv_type = MV_TYPE_8X8; for(i=0;i<4;i++) { mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); @@ -894,8 +895,8 @@ int ff_h263_decode_mb(MpegEncContext *s, } else if(s->pict_type==AV_PICTURE_TYPE_B) { int mb_type; const int stride= s->b8_stride; - int16_t *mot_val0 = s->current_picture.motion_val[0][2 * (s->mb_x + s->mb_y * stride)]; - int16_t *mot_val1 = s->current_picture.motion_val[1][2 * (s->mb_x + s->mb_y * 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; //FIXME ugly @@ -911,8 +912,6 @@ int ff_h263_decode_mb(MpegEncContext *s, av_log(s->avctx, AV_LOG_ERROR, "b mb_type damaged at %d %d\n", s->mb_x, s->mb_y); return SLICE_ERROR; } - - mb_type= h263_mb_type_b_map[ mb_type ]; }while(!mb_type); s->mb_intra = IS_INTRA(mb_type); @@ -952,7 +951,7 @@ int ff_h263_decode_mb(MpegEncContext *s, s->mv_type= MV_TYPE_16X16; //FIXME UMV - if(USES_LIST(mb_type, 0)){ + 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; @@ -979,7 +978,7 @@ int ff_h263_decode_mb(MpegEncContext *s, mot_val[1 ]= mot_val[3 ]= mot_val[1+2*stride]= mot_val[3+2*stride]= my; } - if(USES_LIST(mb_type, 1)){ + 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; @@ -1007,7 +1006,7 @@ int ff_h263_decode_mb(MpegEncContext *s, } } - s->current_picture.mb_type[xy] = mb_type; + s->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); @@ -1022,11 +1021,11 @@ int ff_h263_decode_mb(MpegEncContext *s, dquant = cbpc & 4; s->mb_intra = 1; intra: - s->current_picture.mb_type[xy] = MB_TYPE_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->current_picture.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; + s->cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; s->h263_aic_dir = get_bits1(&s->gb); } diff --git a/libavcodec/ituh263enc.c b/libavcodec/ituh263enc.c index 97abfb3f4..8c41e45ab 100644 --- a/libavcodec/ituh263enc.c +++ b/libavcodec/ituh263enc.c @@ -42,6 +42,7 @@ #include "h263.h" #include "h263enc.h" #include "h263data.h" +#include "h263dsp.h" #include "mathops.h" #include "mpegutils.h" #include "internal.h" @@ -271,9 +272,7 @@ void ff_h263_encode_gob_header(MpegEncContext * s, int mb_line) */ void ff_clean_h263_qscales(MpegEncContext *s){ int i; - int8_t * const qscale_table = s->current_picture.qscale_table; - - ff_init_qscale_tab(s); + int8_t * const qscale_table = s->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) @@ -305,7 +304,7 @@ static const int dquant_code[5]= {1,0,9,2,3}; static void h263_encode_block(MpegEncContext * s, int16_t * block, int n) { int level, run, last, i, j, last_index, last_non_zero, sign, slevel, code; - RLTable *rl; + const RLTable *rl; rl = &ff_h263_rl_inter; if (s->mb_intra && !s->h263_aic) { @@ -512,7 +511,6 @@ void ff_h263_encode_mb(MpegEncContext * s, s->misc_bits++; s->last_bits++; } - s->skip_count++; return; } @@ -566,8 +564,8 @@ void ff_h263_encode_mb(MpegEncContext * s, /* motion vectors: 8x8 mode*/ ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); - motion_x = s->current_picture.motion_val[0][s->block_index[i]][0]; - motion_y = s->current_picture.motion_val[0][s->block_index[i]][1]; + 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]; if (!s->umvplus) { ff_h263_encode_motion_vector(s, motion_x - pred_x, motion_y - pred_y, 1); @@ -689,14 +687,30 @@ void ff_h263_encode_mb(MpegEncContext * s, } } +void ff_h263_update_mb(MpegEncContext *s) +{ + const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; + + if (s->cur_pic.mbskip_table) + s->cur_pic.mbskip_table[mb_xy] = s->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; + else + s->cur_pic.mb_type[mb_xy] = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; + + ff_h263_update_motion_val(s); +} + void ff_h263_encode_motion(PutBitContext *pb, int val, int f_code) { int range, bit_size, sign, code, bits; if (val == 0) { - /* zero vector */ - code = 0; - put_bits(pb, ff_mvtab[code][1], ff_mvtab[code][0]); + /* zero vector -- corresponds to ff_mvtab[0] */ + put_bits(pb, 1, 1); } else { bit_size = f_code - 1; range = 1 << bit_size; @@ -726,7 +740,7 @@ static av_cold void init_mv_penalty_and_fcode(void) for(mv=-MAX_DMV; mv<=MAX_DMV; mv++){ int len; - if(mv==0) len= ff_mvtab[0][1]; + if (mv==0) len = 1; // ff_mvtab[0][1] else{ int val, bit_size, code; @@ -740,7 +754,7 @@ static av_cold void init_mv_penalty_and_fcode(void) if(code<33){ len= ff_mvtab[code][1] + 1 + bit_size; }else{ - len= ff_mvtab[32][1] + av_log2(code>>5) + 2 + bit_size; + len = 12 /* ff_mvtab[32][1] */ + av_log2(code>>5) + 2 + bit_size; } } @@ -865,10 +879,9 @@ av_cold void ff_h263_encode_init(MpegEncContext *s) s->c_dc_scale_table= ff_mpeg1_dc_scale_table; } - if (s->lmin > s->lmax) { - av_log(s->avctx, AV_LOG_WARNING, "Clipping lmin value to %d\n", s->lmax); - s->lmin = s->lmax; - } +#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); } @@ -907,6 +920,7 @@ const FFCodec ff_h263_encoder = { .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}, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &h263_class, .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, @@ -938,6 +952,7 @@ const FFCodec ff_h263p_encoder = { .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 }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &h263p_class, .p.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/itut35.h b/libavcodec/itut35.h index ffa702498..a75ef3792 100644 --- a/libavcodec/itut35.h +++ b/libavcodec/itut35.h @@ -20,11 +20,13 @@ #define AVCODEC_ITUT35_H #define ITU_T_T35_COUNTRY_CODE_CN 0x26 +#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 #endif /* AVCODEC_ITUT35_H */ diff --git a/libavcodec/ivi.c b/libavcodec/ivi.c index 60769664a..e7d8d10c3 100644 --- a/libavcodec/ivi.c +++ b/libavcodec/ivi.c @@ -30,6 +30,7 @@ #include "libavutil/attributes.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #define BITSTREAM_READER_LE diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index 6f827be05..60cc0f309 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -72,6 +72,7 @@ #include "jpeg2000.h" #include "version.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "libavutil/intreadwrite.h" @@ -1864,6 +1865,7 @@ const FFCodec ff_jpeg2000_encoder = { AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &j2k_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/jfdctint_template.c b/libavcodec/jfdctint_template.c index aa2680132..58827b677 100644 --- a/libavcodec/jfdctint_template.c +++ b/libavcodec/jfdctint_template.c @@ -183,7 +183,7 @@ static av_always_inline void FUNC(row_fdct)(int16_t *data) { int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; int tmp10, tmp11, tmp12, tmp13; - int z1, z2, z3, z4, z5; + unsigned z1, z2, z3, z4, z5; int16_t *dataptr; int ctr; diff --git a/libavcodec/jni.c b/libavcodec/jni.c index 1193c608c..fcb483741 100644 --- a/libavcodec/jni.c +++ b/libavcodec/jni.c @@ -84,11 +84,13 @@ void *av_jni_get_java_vm(void *log_ctx) int av_jni_set_android_app_ctx(void *app_ctx, void *log_ctx) { #if CONFIG_JNI + jobjectRefType type; + JNIEnv *env = ff_jni_get_env(log_ctx); if (!env) return AVERROR(EINVAL); - jobjectRefType type = (*env)->GetObjectRefType(env, app_ctx); + type = (*env)->GetObjectRefType(env, app_ctx); if (type != JNIGlobalRefType) { av_log(log_ctx, AV_LOG_ERROR, "Application context must be passed as a global reference"); return AVERROR(EINVAL); diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h index d004c08f1..93221d90c 100644 --- a/libavcodec/jpeg2000.h +++ b/libavcodec/jpeg2000.h @@ -37,12 +37,14 @@ enum Jpeg2000Markers { JPEG2000_SOC = 0xff4f, // start of codestream + JPEG2000_CAP = 0xff50, // extended capabilities JPEG2000_SIZ = 0xff51, // image and tile size JPEG2000_COD, // coding style default JPEG2000_COC, // coding style component JPEG2000_TLM = 0xff55, // tile-part length, main header JPEG2000_PLM = 0xff57, // packet length, main header JPEG2000_PLT, // packet length, tile-part header + JPEG2000_CPF, // corresponding profile JPEG2000_QCD = 0xff5c, // quantization default JPEG2000_QCC, // quantization component JPEG2000_RGN, // region of interest @@ -58,6 +60,12 @@ enum Jpeg2000Markers { JPEG2000_EOC = 0xffd9, // end of codestream }; +enum JPEG2000_Ccap15_b14_15_params { + HTJ2K_HTONLY = 0, // HTONLY, bit 14 and 15 are 0 + HTJ2K_HTDECLARED, // HTDECLARED, bit 14 = 1 and bit 15 = 0 + HTJ2K_MIXED = 3, // MIXED, bit 14 and 15 are 1 +}; + #define JPEG2000_SOP_FIXED_BYTES 0xFF910004 #define JPEG2000_SOP_BYTE_LENGTH 6 @@ -192,6 +200,8 @@ typedef struct Jpeg2000Cblk { /* specific to HT code-blocks */ int zbp; int pass_lengths[2]; + uint8_t modes; // copy of SPcod/SPcoc field to parse HT-MIXED mode + uint8_t ht_plhd; // are we looking for HT placeholder passes? } Jpeg2000Cblk; // code block typedef struct Jpeg2000Prec { diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 72aaefbdb..2e09b279d 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -32,6 +32,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avcodec.h" @@ -53,6 +54,15 @@ #define HAD_COC 0x01 #define HAD_QCC 0x02 +// Values of flag for placeholder passes +enum HT_PLHD_STATUS { + HT_PLHD_OFF, + HT_PLHD_ON +}; + +#define HT_MIXED 0x80 // bit 7 of SPcod/SPcoc + + /* get_bits functions for JPEG2000 packet bitstream * It is a get_bit function with a bit-stuffing routine. If the value of the * byte is 0xFF, the next byte includes an extra zero bit stuffed into the MSB. @@ -381,6 +391,9 @@ static int get_siz(Jpeg2000DecoderContext *s) } else if (ncomponents == 1 && s->precision == 8) { s->avctx->pix_fmt = AV_PIX_FMT_GRAY8; i = 0; + } else if (ncomponents == 1 && s->precision == 12) { + s->avctx->pix_fmt = AV_PIX_FMT_GRAY16LE; + i = 0; } } @@ -407,6 +420,73 @@ static int get_siz(Jpeg2000DecoderContext *s) s->avctx->bits_per_raw_sample = s->precision; return 0; } +/* get extended capabilities (CAP) marker segment */ +static int get_cap(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) +{ + uint32_t Pcap; + uint16_t Ccap_i[32] = { 0 }; + uint16_t Ccap_15; + uint8_t P; + + if (bytestream2_get_bytes_left(&s->g) < 6) { + av_log(s->avctx, AV_LOG_ERROR, "Underflow while parsing the CAP marker\n"); + return AVERROR_INVALIDDATA; + } + + Pcap = bytestream2_get_be32u(&s->g); + s->isHT = (Pcap >> (31 - (15 - 1))) & 1; + for (int i = 0; i < 32; i++) { + if ((Pcap >> (31 - i)) & 1) + Ccap_i[i] = bytestream2_get_be16u(&s->g); + } + Ccap_15 = Ccap_i[14]; + if (s->isHT == 1) { + av_log(s->avctx, AV_LOG_INFO, "This codestream uses the HT block coder.\n"); + // Bits 14-15 + switch ((Ccap_15 >> 14) & 0x3) { + case 0x3: + s->Ccap15_b14_15 = HTJ2K_MIXED; + break; + case 0x1: + s->Ccap15_b14_15 = HTJ2K_HTDECLARED; + break; + case 0x0: + s->Ccap15_b14_15 = HTJ2K_HTONLY; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "Unknown CCap value.\n"); + return AVERROR(EINVAL); + break; + } + // Bit 13 + if ((Ccap_15 >> 13) & 1) { + av_log(s->avctx, AV_LOG_ERROR, "MULTIHT set is not supported.\n"); + return AVERROR_PATCHWELCOME; + } + // Bit 12 + s->Ccap15_b12 = (Ccap_15 >> 12) & 1; + // Bit 11 + s->Ccap15_b11 = (Ccap_15 >> 11) & 1; + // Bit 5 + s->Ccap15_b05 = (Ccap_15 >> 5) & 1; + // Bit 0-4 + P = Ccap_15 & 0x1F; + if (!P) + s->HT_B = 8; + else if (P < 20) + s->HT_B = P + 8; + else if (P < 31) + s->HT_B = 4 * (P - 19) + 27; + else + s->HT_B = 74; + + if (s->HT_B > 31) { + av_log(s->avctx, AV_LOG_ERROR, "Codestream exceeds available precision (B > 31).\n"); + return AVERROR_PATCHWELCOME; + } + } + return 0; +} /* get common part for COD and COC segments */ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) @@ -801,6 +881,15 @@ static int read_crg(Jpeg2000DecoderContext *s, int n) bytestream2_skip(&s->g, n - 2); return 0; } + +static int read_cpf(Jpeg2000DecoderContext *s, int n) +{ + if (bytestream2_get_bytes_left(&s->g) < (n - 2)) + return AVERROR_INVALIDDATA; + bytestream2_skip(&s->g, n - 2); + return 0; +} + /* Tile-part lengths: see ISO 15444-1:2002, section A.7.1 * Used to know the number of tile parts and lengths. * There may be multiple TLMs in the header. @@ -964,6 +1053,14 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno) comp->roi_shift = s->roi_shift[compno]; if (!codsty->init) return AVERROR_INVALIDDATA; + if (s->isHT && (!s->Ccap15_b05) && (!codsty->transform)) { + av_log(s->avctx, AV_LOG_ERROR, "Transformation = 0 (lossy DWT) is found in HTREV HT set\n"); + return AVERROR_INVALIDDATA; + } + if (s->isHT && s->Ccap15_b14_15 != (codsty->cblk_style >> 6) && s->Ccap15_b14_15 != HTJ2K_HTONLY) { + av_log(s->avctx, AV_LOG_ERROR, "SPcod/SPcoc value does not match bit 14-15 values of Ccap15\n"); + return AVERROR_INVALIDDATA; + } if (ret = ff_jpeg2000_init_component(comp, codsty, qntsty, s->cbps[compno], s->cdx[compno], s->cdy[compno], s->avctx)) @@ -1004,6 +1101,7 @@ static inline void select_header(Jpeg2000DecoderContext *s, const Jpeg2000Tile * { s->g = tile->tile_part[*tp_index].header_tpg; if (bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8) { + av_log(s->avctx, AV_LOG_WARNING, "Packet header bytes in PPM marker segment is too short.\n"); if (*tp_index < FF_ARRAY_ELEMS(tile->tile_part) - 1) { s->g = tile->tile_part[++(*tp_index)].tpg; } @@ -1013,10 +1111,18 @@ static inline void select_header(Jpeg2000DecoderContext *s, const Jpeg2000Tile * static inline void select_stream(Jpeg2000DecoderContext *s, const Jpeg2000Tile *tile, int *tp_index, const Jpeg2000CodingStyle *codsty) { + int32_t is_endof_tp; + s->g = tile->tile_part[*tp_index].tpg; - if (bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8) { + is_endof_tp = bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8; + // Following while loop is necessary because a tilepart may include only SOD marker. + // Such a tilepart has neither packet header nor compressed data. + while (is_endof_tp) { if (*tp_index < FF_ARRAY_ELEMS(tile->tile_part) - 1) { s->g = tile->tile_part[++(*tp_index)].tpg; + is_endof_tp = bytestream2_get_bytes_left(&s->g) == 0 && s->bit_index == 8; + } else { + is_endof_tp = 0; } } if (codsty->csty & JPEG2000_CSTY_SOP) { @@ -1066,100 +1172,293 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, int incl, newpasses, llen; void *tmp; - if (cblk->npasses) - incl = get_bits(s, 1); - else + if (!cblk->incl) { + incl = 0; + cblk->modes = codsty->cblk_style; + if (cblk->modes >= JPEG2000_CTSY_HTJ2K_F) + cblk->ht_plhd = HT_PLHD_ON; + if (layno > 0) + incl = tag_tree_decode(s, prec->cblkincl + cblkno, 0 + 1) == 0; incl = tag_tree_decode(s, prec->cblkincl + cblkno, layno + 1) == layno; - if (!incl) - continue; - else if (incl < 0) - return incl; - if (!cblk->npasses) { - int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100); - int v = expn[bandno] + numgbits - 1 - zbp; - - if (v < 0 || v > 30) { - av_log(s->avctx, AV_LOG_ERROR, - "nonzerobits %d invalid or unsupported\n", v); - return AVERROR_INVALIDDATA; + if (incl) { + int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100); + int v = expn[bandno] + numgbits - 1 - (zbp - tile->comp->roi_shift); + if (v < 0 || v > 30) { + av_log(s->avctx, AV_LOG_ERROR, + "nonzerobits %d invalid or unsupported\n", v); + return AVERROR_INVALIDDATA; + } + cblk->incl = 1; + cblk->nonzerobits = v; + cblk->zbp = zbp; + cblk->lblock = 3; } - cblk->zbp = zbp; - cblk->nonzerobits = v; - } - if ((newpasses = getnpasses(s)) < 0) - return newpasses; - av_assert2(newpasses > 0); - if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) { - avpriv_request_sample(s->avctx, "Too many passes"); - return AVERROR_PATCHWELCOME; - } - if ((llen = getlblockinc(s)) < 0) - return llen; - if (cblk->lblock + llen + av_log2(newpasses) > 16) { - avpriv_request_sample(s->avctx, - "Block with length beyond 16 bits"); - return AVERROR_PATCHWELCOME; + } else { + incl = get_bits(s, 1); } - cblk->lblock += llen; + if (incl) { + uint8_t bypass_term_threshold = 0; + uint8_t bits_to_read = 0; + uint32_t segment_bytes = 0; + int32_t segment_passes = 0; + uint8_t next_segment_passes = 0; + int32_t href_passes, pass_bound; + uint32_t tmp_length = 0; + int32_t newpasses_copy, npasses_copy; - cblk->nb_lengthinc = 0; - cblk->nb_terminationsinc = 0; - av_free(cblk->lengthinc); - cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc)); - if (!cblk->lengthinc) - return AVERROR(ENOMEM); - tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, sizeof(*cblk->data_start)); - if (!tmp) - return AVERROR(ENOMEM); - cblk->data_start = tmp; - do { - int newpasses1 = 0; + if ((newpasses = getnpasses(s)) <= 0) + return newpasses; + if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) { + avpriv_request_sample(s->avctx, "Too many passes"); + return AVERROR_PATCHWELCOME; + } + if ((llen = getlblockinc(s)) < 0) + return llen; + if (cblk->lblock + llen + av_log2(newpasses) > 16) { + avpriv_request_sample(s->avctx, + "Block with length beyond 16 bits"); + return AVERROR_PATCHWELCOME; + } + cblk->nb_lengthinc = 0; + cblk->nb_terminationsinc = 0; + av_free(cblk->lengthinc); + cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc)); + if (!cblk->lengthinc) + return AVERROR(ENOMEM); + tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, + sizeof(*cblk->data_start)); + if (!tmp) + return AVERROR(ENOMEM); + cblk->data_start = tmp; + cblk->lblock += llen; - while (newpasses1 < newpasses) { - newpasses1 ++; - if (needs_termination(codsty->cblk_style, cblk->npasses + newpasses1 - 1)) { - cblk->nb_terminationsinc ++; - break; + // Count number of necessary terminations for non HT code block + newpasses_copy = newpasses; + npasses_copy = cblk->npasses; + if (!(cblk->modes & JPEG2000_CTSY_HTJ2K_F)) { + do { + int newpasses1 = 0; + + while (newpasses1 < newpasses_copy) { + newpasses1++; + if (needs_termination(codsty->cblk_style, npasses_copy + newpasses1 - 1)) { + cblk->nb_terminationsinc++; + break; + } + } + npasses_copy += newpasses1; + newpasses_copy -= newpasses1; + } while (newpasses_copy); + } + + if (cblk->ht_plhd) { + href_passes = (cblk->npasses + newpasses - 1) % 3; + segment_passes = newpasses - href_passes; + pass_bound = 2; + bits_to_read = cblk->lblock; + if (segment_passes < 1) { + // No possible HT Cleanup pass here; may have placeholder passes + // or an original J2K block bit-stream (in MIXED mode). + segment_passes = newpasses; + while (pass_bound <= segment_passes) { + bits_to_read++; + pass_bound += pass_bound; + } + segment_bytes = get_bits(s, bits_to_read); + if (segment_bytes) { + if (cblk->modes & HT_MIXED) { + cblk->ht_plhd = HT_PLHD_OFF; + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F)); + } + else { + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + } + } + } else { + while (pass_bound <= segment_passes) { + bits_to_read++; + pass_bound += pass_bound; + } + segment_bytes = get_bits(s, bits_to_read); + if (segment_bytes) { + // No more placeholder passes + if (!(cblk->modes & HT_MIXED)) { + // Must be the first HT Cleanup pass + if (segment_bytes < 2) + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + next_segment_passes = 2; + cblk->ht_plhd = HT_PLHD_OFF; + // Write length information for HT CleanUp segment + cblk->pass_lengths[0] = segment_bytes; + } else if (cblk->lblock > 3 && segment_bytes > 1 + && (segment_bytes >> (bits_to_read - 1)) == 0) { + // Must be the first HT Cleanup pass, since length MSB is 0 + next_segment_passes = 2; + cblk->ht_plhd = HT_PLHD_OFF; + // Write length information for HT CleanUp segment + cblk->pass_lengths[0] = segment_bytes; + } else { + // Must have an original (non-HT) block coding pass + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F)); + cblk->ht_plhd = HT_PLHD_OFF; + segment_passes = newpasses; + while (pass_bound <= segment_passes) { + bits_to_read++; + pass_bound += pass_bound; + segment_bytes <<= 1; + segment_bytes += get_bits(s, 1); + } + } + } else { + // Probably parsing placeholder passes, but we need to read an + // extra length bit to verify this, since prior to the first + // HT Cleanup pass, the number of length bits read for a + // contributing code-block is dependent on the number of passes + // being included, as if it were a non-HT code-block. + segment_passes = newpasses; + if (pass_bound <= segment_passes) { + while (1) { + bits_to_read++; + pass_bound += pass_bound; + segment_bytes <<= 1; + segment_bytes += get_bits(s, 1); + if (pass_bound > segment_passes) + break; + } + if (segment_bytes) { + if (cblk->modes & HT_MIXED) { + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F)); + cblk->ht_plhd = HT_PLHD_OFF; + } else { + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + } + } + } + } + } + } else if (cblk->modes & JPEG2000_CTSY_HTJ2K_F) { + // Quality layer commences with a non-initial HT coding pass + if(bits_to_read != 0) + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + segment_passes = cblk->npasses % 3; + if (segment_passes == 0) { + // newpasses is a HT Cleanup pass; next segment has refinement passes + segment_passes = 1; + next_segment_passes = 2; + if (segment_bytes == 1) + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + } else { + // newpasses = 1 means npasses is HT SigProp; 2 means newpasses is + // HT MagRef pass + segment_passes = newpasses > 1 ? 3 - segment_passes : 1; + next_segment_passes = 1; + bits_to_read = av_log2(segment_passes); + } + 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 + 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 + bits_to_read = (uint8_t) cblk->lblock + av_log2((uint8_t) newpasses); + segment_bytes = get_bits(s, bits_to_read); + segment_passes = newpasses; + } else if (cblk->modes & JPEG2000_CBLK_TERMALL) { + // RESTART MODE + bits_to_read = cblk->lblock; + segment_bytes = get_bits(s, bits_to_read); + segment_passes = 1; + next_segment_passes = 1; + } else { + // BYPASS MODE + bypass_term_threshold = 10; + if(bits_to_read != 0) + av_log(s->avctx, AV_LOG_WARNING, "Length information for a codeblock is invalid\n"); + if (cblk->npasses < bypass_term_threshold) { + // May have from 1 to 10 uninterrupted passes before 1st RAW SigProp + segment_passes = bypass_term_threshold - cblk->npasses; + if (segment_passes > newpasses) + segment_passes = newpasses; + while ((2 << bits_to_read) <= segment_passes) + bits_to_read++; + next_segment_passes = 2; + } else if ((cblk->npasses - bypass_term_threshold) % 3 < 2) { + // 0 means newpasses is a RAW SigProp; 1 means newpasses is a RAW MagRef pass + segment_passes = newpasses > 1 ? 2 - (cblk->npasses - bypass_term_threshold) % 3 : 1; + bits_to_read = av_log2(segment_passes); + next_segment_passes = 1; + } else { + // newpasses is an isolated Cleanup pass that precedes a RAW SigProp pass + segment_passes = 1; + next_segment_passes = 2; + } + bits_to_read = (uint8_t) (bits_to_read + cblk->lblock); + segment_bytes = get_bits(s, bits_to_read); + } + // Update cblk->npasses and write length information + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes); + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes; + + if ((cblk->modes & JPEG2000_CTSY_HTJ2K_F) && cblk->ht_plhd == HT_PLHD_OFF) { + newpasses -= (uint8_t) segment_passes; + while (newpasses > 0) { + segment_passes = newpasses > 1 ? next_segment_passes : 1; + next_segment_passes = (uint8_t) (3 - next_segment_passes); + bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes)); + segment_bytes = get_bits(s, bits_to_read); + newpasses -= (uint8_t) (segment_passes); + // This is a FAST Refinement pass + // Write length information for HT Refinement segment + cblk->pass_lengths[1] += segment_bytes; + // Update cblk->npasses and write length information + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes); + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes; + } + } else { + newpasses -= (uint8_t) (segment_passes); + while (newpasses > 0) { + if (bypass_term_threshold != 0) { + segment_passes = newpasses > 1 ? next_segment_passes : 1; + next_segment_passes = (uint8_t) (3 - next_segment_passes); + bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes)); + } else { + if ((cblk->modes & JPEG2000_CBLK_TERMALL) == 0) + av_log(s->avctx, AV_LOG_WARNING, "Corrupted packet header is found.\n"); + segment_passes = 1; + bits_to_read = cblk->lblock; + } + segment_bytes = get_bits(s, bits_to_read); + newpasses -= (uint8_t) (segment_passes); + + // Update cblk->npasses and write length information + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes); + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes; } } - if (newpasses > 1 && (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F)) { - // Retrieve pass lengths for each pass - int href_passes = (cblk->npasses + newpasses - 1) % 3; - int eb = av_log2(newpasses - href_passes); - int extra_bit = newpasses > 2 ? 1 : 0; - if ((ret = get_bits(s, llen + eb + 3)) < 0) - return ret; - cblk->pass_lengths[0] = ret; - if ((ret = get_bits(s, llen + 3 + extra_bit)) < 0) - return ret; - cblk->pass_lengths[1] = ret; - ret = cblk->pass_lengths[0] + cblk->pass_lengths[1]; - } else { - if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0) - return ret; - cblk->pass_lengths[0] = ret; - } - if (ret > cblk->data_allocated) { - size_t new_size = FFMAX(2*cblk->data_allocated, ret); + for (int i = 0; i < cblk->nb_lengthinc; ++i) + tmp_length = (tmp_length < cblk->lengthinc[i]) ? cblk->lengthinc[i] : tmp_length; + + if (tmp_length > cblk->data_allocated) { + size_t new_size = FFMAX(2 * cblk->data_allocated, tmp_length); void *new = av_realloc(cblk->data, new_size); if (new) { cblk->data = new; cblk->data_allocated = new_size; } } - if (ret > cblk->data_allocated) { + if (tmp_length > cblk->data_allocated) { avpriv_request_sample(s->avctx, "Block with lengthinc greater than %"SIZE_SPECIFIER"", cblk->data_allocated); return AVERROR_PATCHWELCOME; } - cblk->lengthinc[cblk->nb_lengthinc++] = ret; - cblk->npasses += newpasses1; - newpasses -= newpasses1; - } while(newpasses); + } else { + // This codeblock has no contribution to the current packet + continue; + } } } jpeg2000_flush(s); @@ -1694,7 +1993,7 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, int width, int height, int bandpos, uint8_t roi_shift) { - int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1 + roi_shift; + int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1; int pass_cnt = 0; int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC; int term_cnt = 0; @@ -1908,7 +2207,7 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile Jpeg2000Band *band = rlevel->band + bandno; int cblkno = 0, bandpos; /* See Rec. ITU-T T.800, Equation E-2 */ - int magp = quantsty->expn[subbandno] + quantsty->nguardbits - 1; + int M_b = quantsty->expn[subbandno] + quantsty->nguardbits - 1; bandpos = bandno + (reslevelno > 0); @@ -1916,8 +2215,8 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile band->coord[1][0] == band->coord[1][1]) continue; - if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && magp >= 31) { - avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and magp >= 31"); + if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && M_b >= 31) { + avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and M_b >= 31"); return AVERROR_PATCHWELCOME; } @@ -1934,11 +2233,11 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile Jpeg2000Cblk *cblk = prec->cblk + cblkno; - if (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) + if (cblk->modes & JPEG2000_CTSY_HTJ2K_F) ret = ff_jpeg2000_decode_htj2k(s, codsty, &t1, cblk, cblk->coord[0][1] - cblk->coord[0][0], cblk->coord[1][1] - cblk->coord[1][0], - magp, comp->roi_shift); + M_b, comp->roi_shift); else ret = decode_cblk(s, codsty, &t1, cblk, cblk->coord[0][1] - cblk->coord[0][0], @@ -2177,22 +2476,63 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) if (!s->tile) s->numXtiles = s->numYtiles = 0; break; + case JPEG2000_CAP: + if (!s->ncomponents) { + av_log(s->avctx, AV_LOG_ERROR, "CAP marker segment shall come after SIZ\n"); + return AVERROR_INVALIDDATA; + } + ret = get_cap(s, codsty); + break; case JPEG2000_COC: + if (s->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; + } ret = get_coc(s, codsty, properties); break; case JPEG2000_COD: + if (s->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; + } ret = get_cod(s, codsty, properties); break; case JPEG2000_RGN: + if (s->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; + } ret = get_rgn(s, len); + if ((!s->Ccap15_b12) && s->isHT) { + av_log(s->avctx, AV_LOG_ERROR, "RGN marker found but the codestream belongs to the RGNFREE set\n"); + return AVERROR_INVALIDDATA; + } break; case JPEG2000_QCC: + if (s->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; + } ret = get_qcc(s, len, qntsty, properties); break; case JPEG2000_QCD: + if (s->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; + } ret = get_qcd(s, len, qntsty, properties); break; case JPEG2000_POC: + if (s->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; + } ret = get_poc(s, len, poc); break; case JPEG2000_SOT: @@ -2242,9 +2582,16 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) "Cannot have both PPT and PPM marker.\n"); return AVERROR_INVALIDDATA; } - + if ((!s->Ccap15_b11) && s->isHT) { + av_log(s->avctx, AV_LOG_ERROR, "PPT marker found but the codestream belongs to the HOMOGENEOUS set\n"); + return AVERROR_INVALIDDATA; + } ret = get_ppt(s, len); break; + case JPEG2000_CPF: + // Corresponding profile marker + ret = read_cpf(s, len); + break; default: av_log(s->avctx, AV_LOG_ERROR, "unsupported marker 0x%.4"PRIX16" at pos 0x%X\n", @@ -2502,8 +2849,6 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture, /* get picture buffer */ if ((ret = ff_thread_get_buffer(avctx, picture, 0)) < 0) goto end; - picture->pict_type = AV_PICTURE_TYPE_I; - picture->flags |= AV_FRAME_FLAG_KEY; if (ret = jpeg2000_read_bitstream_packets(s)) goto end; diff --git a/libavcodec/jpeg2000dec.h b/libavcodec/jpeg2000dec.h index d0ca6e7a7..78eba27ed 100644 --- a/libavcodec/jpeg2000dec.h +++ b/libavcodec/jpeg2000dec.h @@ -112,6 +112,13 @@ typedef struct Jpeg2000DecoderContext { Jpeg2000Tile *tile; Jpeg2000DSPContext dsp; + uint8_t isHT; // HTJ2K? + uint8_t Ccap15_b14_15; // HTONLY(= 0) or HTDECLARED(= 1) or MIXED(= 3) ? + uint8_t Ccap15_b12; // RGNFREE(= 0) or RGN(= 1)? + uint8_t Ccap15_b11; // HOMOGENEOUS(= 0) or HETEROGENEOUS(= 1) ? + uint8_t Ccap15_b05; // HTREV(= 0) or HTIRV(= 1) ? + uint8_t HT_B; // The parameter B for MAGBp value (see Table 4 in the Rec. ITU-T T.814 | ISO/IEC 15444-15) + /*options parameters*/ int reduction_factor; } Jpeg2000DecoderContext; diff --git a/libavcodec/jpeg2000htdec.c b/libavcodec/jpeg2000htdec.c index 4f0b10b42..c47c8d61f 100644 --- a/libavcodec/jpeg2000htdec.c +++ b/libavcodec/jpeg2000htdec.c @@ -51,6 +51,7 @@ #include "libavutil/attributes.h" #include "libavutil/common.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "jpeg2000htdec.h" #include "jpeg2000.h" #include "jpeg2000dec.h" @@ -121,7 +122,7 @@ static void jpeg2000_init_mel(StateVars *s, uint32_t Pcup) static void jpeg2000_init_mag_ref(StateVars *s, uint32_t Lref) { - s->pos = Lref - 2; + s->pos = Lref - 1; s->bits = 0; s->last = 0xFF; s->tmp = 0; @@ -144,9 +145,10 @@ static void jpeg2000_init_mel_decoder(MelDecoderState *mel_state) static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *array) { uint64_t tmp = 0; - int32_t position = buffer->pos - 4; uint32_t new_bits = 32; + buffer->last = array[buffer->pos + 1]; + if (buffer->bits_left >= 32) return 0; // enough data, no need to pull in more bits @@ -156,9 +158,24 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar * the bottom most bits. */ - for(int i = FFMAX(0, position + 1); i <= buffer->pos + 1; i++) - tmp = 256*tmp + array[i]; - + if (buffer->pos >= 3) { // Common case; we have at least 4 bytes available + tmp = array[buffer->pos - 3]; + tmp = (tmp << 8) | array[buffer->pos - 2]; + tmp = (tmp << 8) | array[buffer->pos - 1]; + tmp = (tmp << 8) | array[buffer->pos]; + tmp = (tmp << 8) | buffer->last; // For stuffing bit detection + buffer->pos -= 4; + } else { + if (buffer->pos >= 2) + tmp = array[buffer->pos - 2]; + if (buffer->pos >= 1) + tmp = (tmp << 8) | array[buffer->pos - 1]; + if (buffer->pos >= 0) + tmp = (tmp << 8) | array[buffer->pos]; + buffer->pos = 0; + tmp = (tmp << 8) | buffer->last; // For stuffing bit detection + } + // Now remove any stuffing bits, shifting things down as we go if ((tmp & 0x7FFF000000) > 0x7F8F000000) { tmp &= 0x7FFFFFFFFF; new_bits--; @@ -175,13 +192,11 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar tmp = (tmp & 0x0000007FFF) + ((tmp & 0xFFFFFF0000) >> 1); new_bits--; } - - tmp >>= 8; // Remove temporary byte loaded + tmp >>= 8; // Shifts away the extra byte we imported /* Add bits to the MSB of the bit buffer */ buffer->bit_buf |= tmp << buffer->bits_left; buffer->bits_left += new_bits; - buffer->pos = FFMAX(0, position); return 0; } @@ -195,7 +210,7 @@ static void jpeg2000_bitbuf_refill_forward(StateVars *buffer, const uint8_t *arr while (buffer->bits_left < 32) { buffer->tmp = 0xFF; buffer->bits = (buffer->last == 0xFF) ? 7 : 8; - if (buffer->pos <= length) { + if (buffer->pos < length) { buffer->tmp = array[buffer->pos]; buffer->pos += 1; buffer->last = buffer->tmp; @@ -405,6 +420,7 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t E[n] = 32 - ff_clz(v[pos][i] | 1); mu_n[n] = (v[pos][i] >> 1) + 1; mu_n[n] <<= pLSB; + mu_n[n] |= (1 << (pLSB - 1)); // Add 0.5 (reconstruction parameter = 1/2) mu_n[n] |= ((uint32_t) (v[pos][i] & 1)) << 31; // sign bit. } } @@ -412,8 +428,8 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t length) { - int cond = stream->pos <= length; - int pos = FFMIN(stream->pos, length); + int cond = stream->pos < length; + int pos = FFMIN(stream->pos, length - 1); if (stream->bits == 0) { stream->bits = (stream->tmp == 0xFF) ? 7 : 8; stream->pos += cond; @@ -425,14 +441,22 @@ static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t static int jpeg2000_peek_bit(StateVars *stream, const uint8_t *array, uint32_t length) { + uint8_t bit; + if (stream->bits == 0) { - int cond = stream->pos <= length; - int pos = FFMIN(stream->pos, length); - stream->bits = (stream->tmp == 0xFF) ? 7 : 8; - stream->pos += cond; - stream->tmp = cond ? array[pos] : 0xFF; + stream->bits = (stream->last == 0xFF) ? 7 : 8; + if (stream->pos < length) { + stream->tmp = array[stream->pos]; + stream->pos++; + } else { + stream->tmp = 0; + } + stream->last = stream->tmp; } - return (stream->tmp >> stream->bits) & 1; + bit = stream->tmp & 1; + stream->tmp >>= 1; + stream->bits--; + return bit; } static int jpeg2000_decode_mel_sym(MelDecoderState *mel_state, @@ -507,17 +531,17 @@ static int jpeg2000_decode_sig_emb(const Jpeg2000DecoderContext *s, MelDecoderSt } av_always_inline -static int jpeg2000_get_state(int x1, int x2, int width, int shift_by, +static int jpeg2000_get_state(int x1, int x2, int stride, int shift_by, const uint8_t *block_states) { - return (block_states[(x1 + 1) * (width + 2) + (x2 + 1)] >> shift_by) & 1; + return (block_states[(x1 + 1) * stride + (x2 + 1)] >> shift_by) & 1; } av_always_inline -static void jpeg2000_modify_state(int x1, int x2, int width, - int value, uint8_t *block_states) +static void jpeg2000_modify_state(int x1, int x2, int stride, + int value, uint8_t *block_states) { - block_states[(x1 + 1) * (width + 2) + (x2 + 1)] |= value; + block_states[(x1 + 1) * stride + (x2 + 1)] |= value; } av_always_inline @@ -527,8 +551,8 @@ static int jpeg2000_decode_ht_cleanup_segment(const Jpeg2000DecoderContext *s, StateVars *mel_stream, StateVars *vlc_stream, StateVars *mag_sgn_stream, const uint8_t *Dcup, uint32_t Lcup, uint32_t Pcup, uint8_t pLSB, - int width, int height, int32_t *sample_buf, - uint8_t *block_states) + int width, int height, const int stride, + int32_t *sample_buf, uint8_t *block_states) { uint16_t q = 0; // Represents current quad position uint16_t q1, q2; @@ -957,26 +981,26 @@ static int jpeg2000_decode_ht_cleanup_segment(const Jpeg2000DecoderContext *s, j1 = 2 * y; j2 = 2 * x; - sample_buf[j2 + (j1 * width)] = (int32_t)*mu; - jpeg2000_modify_state(j1, j2, width, *sigma, block_states); + sample_buf[j2 + (j1 * stride)] = (int32_t)*mu; + jpeg2000_modify_state(j1, j2, stride, *sigma, block_states); sigma += 1; mu += 1; x1 = y != quad_height - 1 || is_border_y == 0; - sample_buf[j2 + ((j1 + 1) * width)] = ((int32_t)*mu) * x1; - jpeg2000_modify_state(j1 + 1, j2, width, (*sigma) * x1, block_states); + sample_buf[j2 + ((j1 + 1) * stride)] = ((int32_t)*mu) * x1; + jpeg2000_modify_state(j1 + 1, j2, stride, (*sigma) * x1, block_states); sigma += 1; mu += 1; x2 = x != quad_width - 1 || is_border_x == 0; - sample_buf[(j2 + 1) + (j1 * width)] = ((int32_t)*mu) * x2; - jpeg2000_modify_state(j1, j2 + 1, width, (*sigma) * x2, block_states); + sample_buf[(j2 + 1) + (j1 * stride)] = ((int32_t)*mu) * x2; + jpeg2000_modify_state(j1, j2 + 1, stride, (*sigma) * x2, block_states); sigma += 1; mu += 1; x3 = x1 | x2; - sample_buf[(j2 + 1) + (j1 + 1) * width] = ((int32_t)*mu) * x3; - jpeg2000_modify_state(j1 + 1, j2 + 1, width, (*sigma) * x3, block_states); + sample_buf[(j2 + 1) + (j1 + 1) * stride] = ((int32_t)*mu) * x3; + jpeg2000_modify_state(j1 + 1, j2 + 1, stride, (*sigma) * x3, block_states); sigma += 1; mu += 1; } @@ -991,66 +1015,63 @@ free: static void jpeg2000_calc_mbr(uint8_t *mbr, const uint16_t i, const uint16_t j, const uint32_t mbr_info, uint8_t causal_cond, - uint8_t *block_states, int width) + uint8_t *block_states, int stride) { - int local_mbr = 0; + uint8_t *state_p0 = block_states + i * stride + j; + uint8_t *state_p1 = block_states + (i + 1) * stride + j; + uint8_t *state_p2 = block_states + (i + 2) * stride + j; - local_mbr |= jpeg2000_get_state(i - 1, j - 1, width, HT_SHIFT_SIGMA, block_states); - local_mbr |= jpeg2000_get_state(i - 1, j + 0, width, HT_SHIFT_SIGMA, block_states); - local_mbr |= jpeg2000_get_state(i - 1, j + 1, width, HT_SHIFT_SIGMA, block_states); - - local_mbr |= jpeg2000_get_state(i + 0, j - 1, width, HT_SHIFT_SIGMA, block_states); - local_mbr |= jpeg2000_get_state(i + 0, j + 1, width, HT_SHIFT_SIGMA, block_states); - - local_mbr |= jpeg2000_get_state(i + 1, j - 1, width, HT_SHIFT_SIGMA, block_states) * causal_cond; - local_mbr |= jpeg2000_get_state(i + 1, j + 0, width, HT_SHIFT_SIGMA, block_states) * causal_cond; - local_mbr |= jpeg2000_get_state(i + 1, j + 1, width, HT_SHIFT_SIGMA, block_states) * causal_cond; - - local_mbr |= jpeg2000_get_state(i - 1, j - 1, width, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i - 1, j - 1, width, HT_SHIFT_SCAN, block_states); - local_mbr |= jpeg2000_get_state(i - 1, j + 0, width, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i - 1, j - 1, width, HT_SHIFT_SCAN, block_states); - local_mbr |= jpeg2000_get_state(i - 1, j + 1, width, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i - 1, j + 1, width, HT_SHIFT_SCAN, block_states); - - local_mbr |= jpeg2000_get_state(i + 0, j - 1, width, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 0, j - 1, width, HT_SHIFT_SCAN, block_states); - local_mbr |= jpeg2000_get_state(i + 0, j + 1, width, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 0, j + 1, width, HT_SHIFT_SCAN, block_states); - - local_mbr |= jpeg2000_get_state(i + 1, j - 1, width, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 1, j - 1, width, HT_SHIFT_SCAN, block_states) * causal_cond; - local_mbr |= jpeg2000_get_state(i + 1, j + 0, width, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 1, j + 0, width, HT_SHIFT_SCAN, block_states) * causal_cond; - local_mbr |= jpeg2000_get_state(i + 1, j + 1, width, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 1, j + 1, width, HT_SHIFT_SCAN, block_states) * causal_cond; - - *mbr |= local_mbr; + uint8_t mbr0 = state_p0[0] | state_p0[1] | state_p0[2]; + uint8_t mbr1 = state_p1[0] | state_p1[2]; + uint8_t mbr2 = state_p2[0] | state_p2[1] | state_p2[2]; + *mbr = mbr0 | mbr1 | (mbr2 & causal_cond); + *mbr |= (mbr0 >> HT_SHIFT_REF) & (mbr0 >> HT_SHIFT_SCAN); + *mbr |= (mbr1 >> HT_SHIFT_REF) & (mbr1 >> HT_SHIFT_SCAN); + *mbr |= (mbr2 >> HT_SHIFT_REF) & (mbr2 >> HT_SHIFT_SCAN) & causal_cond; + *mbr &= 1; } static void jpeg2000_process_stripes_block(StateVars *sig_prop, int i_s, int j_s, int width, int height, int stride, int pLSB, int32_t *sample_buf, uint8_t *block_states, - uint8_t *magref_segment, uint32_t magref_length) + uint8_t *magref_segment, uint32_t magref_length, + uint8_t is_causal) { for (int j = j_s; j < j_s + width; j++) { uint32_t mbr_info = 0; for (int i = i_s; i < i_s + height; i++) { - int modify_state, cond; + int modify_state; uint8_t bit; - uint8_t causal_cond = i != (i_s + height - 1); - int32_t *sp = &sample_buf[j + (i * (stride - 2))]; + uint8_t causal_cond = (is_causal == 0) || (i != (i_s + height - 1)); + int32_t *sp = &sample_buf[j + (i * (stride))]; uint8_t mbr = 0; - if (jpeg2000_get_state(i, j, stride - 2, HT_SHIFT_SIGMA, block_states) == 0) - jpeg2000_calc_mbr(&mbr, i, j, mbr_info & 0x1EF, causal_cond, block_states, stride - 2); + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) == 0) + jpeg2000_calc_mbr(&mbr, i, j, mbr_info & 0x1EF, causal_cond, block_states, stride); mbr_info >>= 3; - cond = mbr != 0; - bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length); - *sp |= (bit * cond) << pLSB; - sig_prop->bits -= cond; - modify_state = (((1 << HT_SHIFT_REF_IND) | (1 << HT_SHIFT_REF)) * cond) | 1 << HT_SHIFT_SCAN; - jpeg2000_modify_state(i, j, stride - 2, modify_state, block_states); + + modify_state = block_states[(i + 1) * stride + (j + 1)]; + modify_state |= 1 << HT_SHIFT_SCAN; + if (mbr != 0) { + modify_state |= 1 << HT_SHIFT_REF_IND; + bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length); + modify_state |= bit << HT_SHIFT_REF; + *sp |= bit << pLSB; + *sp |= bit << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) + } + jpeg2000_modify_state(i, j, stride, modify_state, block_states); + } + } + // decode sign + for (int j = j_s; j < j_s + width; j++) { + for (int i = i_s; i < i_s + height; i++) { + uint8_t bit; + int32_t *sp = &sample_buf[j + (i * (stride))]; + 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; + } } } } @@ -1059,8 +1080,8 @@ static void jpeg2000_process_stripes_block(StateVars *sig_prop, int i_s, int j_s * See procedure decodeSigPropMag at Rec. ITU-T T.814, 7.4. */ av_noinline -static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width, - uint16_t height, uint8_t *magref_segment, +static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width, uint16_t height, + const int stride, uint8_t *magref_segment, uint32_t magref_length, uint8_t pLSB, int32_t *sample_buf, uint8_t *block_states) { @@ -1070,10 +1091,10 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width, const uint16_t num_h_stripe = width / 4; int b_width = 4; int b_height = 4; - int stride = width + 2; int last_width; uint16_t i = 0, j = 0; + uint8_t is_causal = cblk->modes & JPEG2000_CBLK_VSC; jpeg2000_init_zero(&sp_dec); @@ -1082,14 +1103,14 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width, for (int n2 = 0; n2 < num_h_stripe; n2++) { jpeg2000_process_stripes_block(&sp_dec, i, j, b_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, - magref_length); + magref_length, is_causal); j += 4; } last_width = width % 4; if (last_width) jpeg2000_process_stripes_block(&sp_dec, i, j, last_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, - magref_length); + magref_length, is_causal); i += 4; } @@ -1099,21 +1120,21 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width, for (int n2 = 0; n2 < num_h_stripe; n2++) { jpeg2000_process_stripes_block(&sp_dec, i, j, b_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, - magref_length); + magref_length, is_causal); j += 4; } last_width = width % 4; if (last_width) jpeg2000_process_stripes_block(&sp_dec, i, j, last_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, - magref_length); + magref_length, is_causal); } /** * See procedure decodeSigPropMag at Rec. ITU-T T.814, 7.5. */ -static int -jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, +static void +jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int stride, uint8_t *magref_segment,uint32_t magref_length, uint8_t pLSB, int32_t *sample_buf, uint8_t *block_states) { @@ -1123,7 +1144,8 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, uint16_t height = 4; uint16_t i_start = 0; int32_t *sp; - + int32_t bit; + int32_t tmp; jpeg2000_init_mag_ref(&mag_ref, magref_length); for (int n1 = 0; n1 < num_v_stripe; n1++) { @@ -1133,10 +1155,14 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, * We move column wise, going from one quad to another. See * Rec. ITU-T T.814, Figure 7. */ - sp = &sample_buf[j + i * width]; - if (jpeg2000_get_state(i, j, width, HT_SHIFT_SIGMA, block_states) != 0) { - jpeg2000_modify_state(i, j, width, 1 << HT_SHIFT_REF_IND, block_states); - *sp |= jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length) << pLSB; + sp = &sample_buf[j + i * stride]; + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) { + 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; + sp[0] &= tmp; + sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) } } } @@ -1145,22 +1171,25 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, height = block_height % 4; for (int j = 0; j < width; j++) { for (int i = i_start; i < i_start + height; i++) { - sp = &sample_buf[j + i * width]; - if (jpeg2000_get_state(i, j, width, HT_SHIFT_SIGMA, block_states) != 0) { - jpeg2000_modify_state(i, j, width, 1 << HT_SHIFT_REF_IND, block_states); - *sp |= jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length) << pLSB; + sp = &sample_buf[j + i * stride]; + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) { + 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; + sp[0] &= tmp; + sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) } } } - return 1; } int ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, - int width, int height, int magp, uint8_t roi_shift) + int width, int height, int M_b, uint8_t roi_shift) { - uint8_t p0 = 0; // Number of placeholder passes + uint8_t p0 = 0; // 3 * p0 = Number of placeholder passes uint32_t Lcup; // Length of HT cleanup segment uint32_t Lref; // Length of Refinement segment uint32_t Scup; // HT cleanup segment suffix length @@ -1174,7 +1203,7 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c int z_blk; // Number of ht coding pass - uint8_t empty_passes; + uint8_t num_plhd_passes; // Number of placeholder passes StateVars mag_sgn; // Magnitude and Sign StateVars mel; // Adaptive run-length coding @@ -1190,30 +1219,29 @@ 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 - int32_t M_b = magp; + uint8_t num_rempass; + + const int quad_buf_width = width + 4; + const int quad_buf_height = height + 4; /* codeblock size as constrained by Rec. ITU-T T.800, Table A.18 */ av_assert0(width <= 1024U && height <= 1024U); av_assert0(width * height <= 4096); av_assert0(width * height > 0); - if (roi_shift) - avpriv_report_missing_feature(s->avctx, "ROI shift"); - memset(t1->data, 0, t1->stride * height * sizeof(*t1->data)); memset(t1->flags, 0, t1->stride * (height + 2) * sizeof(*t1->flags)); if (cblk->npasses == 0) return 0; - if (cblk->npasses > 3) - p0 = 0; - else if (cblk->length == 0) - p0 = 1; - - empty_passes = p0 * 3; - z_blk = cblk->npasses - empty_passes; + num_rempass = cblk->npasses % 3; // Number of remainder passes + num_plhd_passes = num_rempass ? cblk->npasses - num_rempass : cblk->npasses - 3; + av_assert0(num_plhd_passes % 3 == 0); + p0 = num_plhd_passes / 3; + z_blk = cblk->npasses - num_plhd_passes; if (z_blk <= 0) return 0; // No passes within this set, continue @@ -1228,7 +1256,11 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c } Dcup = cblk->data; Dref = cblk->data + Lcup; // Dref comes after the refinement segment + + cblk->data[cblk->length] = 0xFF; // an extra byte for refinement segment (buffer->last) + S_blk = p0 + cblk->zbp; + cblk->zbp = S_blk - 1; pLSB = 30 - S_blk; Scup = (Dcup[Lcup - 1] << 4) + (Dcup[Lcup - 2] & 0x0F); @@ -1260,45 +1292,46 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c jpeg2000_init_mel_decoder(&mel_state); - sample_buf = av_calloc((width + 4) * (height + 4), sizeof(int32_t)); - block_states = av_calloc((width + 4) * (height + 4), sizeof(uint8_t)); + sample_buf = av_calloc(quad_buf_width * quad_buf_height, sizeof(int32_t)); + block_states = av_calloc(quad_buf_width * quad_buf_height, sizeof(uint8_t)); if (!sample_buf || !block_states) { ret = AVERROR(ENOMEM); goto free; } if ((ret = jpeg2000_decode_ht_cleanup_segment(s, cblk, t1, &mel_state, &mel, &vlc, - &mag_sgn, Dcup, Lcup, Pcup, pLSB, width, - height, sample_buf, block_states)) < 0) { + &mag_sgn, Dcup, Lcup, Pcup, pLSB, width, + height, quad_buf_width, sample_buf, block_states)) < 0) { av_log(s->avctx, AV_LOG_ERROR, "Bad HT cleanup segment\n"); goto free; } - if (cblk->npasses > 1) - jpeg2000_decode_sigprop_segment(cblk, width, height, Dref, Lref, - pLSB - 1, sample_buf, block_states); + if (z_blk > 1) + jpeg2000_decode_sigprop_segment(cblk, width, height, quad_buf_width, Dref, Lref, + pLSB - 1, sample_buf, block_states); - if (cblk->npasses > 2) { - - if (Lref < 2){ - av_log(s->avctx,AV_LOG_ERROR,"Invalid magnitude refinement length\n"); - ret = AVERROR_INVALIDDATA; - goto free; - } - if ((ret = jpeg2000_decode_magref_segment(width, height, Dref, Lref, - pLSB - 1, sample_buf, block_states)) < 0) - goto free; - } + if (z_blk > 2) + 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++) { + int32_t sign; + n = x + (y * t1->stride); - val = sample_buf[x + (y * width)]; + val = sample_buf[x + (y * quad_buf_width)]; + sign = val & INT32_MIN; + val &= INT32_MAX; + /* ROI shift, if necessary */ + if (roi_shift && (((uint32_t)val & ~mask) == 0)) + val <<= roi_shift; /* Convert sign-magnitude to two's complement. */ - val = val >> 31 ? 0x80000000 - val : val; + 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; } diff --git a/libavcodec/jpeg2000htdec.h b/libavcodec/jpeg2000htdec.h index 572d095c9..8d6919a0d 100644 --- a/libavcodec/jpeg2000htdec.h +++ b/libavcodec/jpeg2000htdec.h @@ -29,6 +29,6 @@ int ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, int width, - int height, int magp, uint8_t roi_shift); + int height, int M_b, uint8_t roi_shift); #endif /* AVCODEC_JPEG2000HTDEC_H */ diff --git a/libavcodec/jpeglsdec.c b/libavcodec/jpeglsdec.c index c245cf027..5f463c966 100644 --- a/libavcodec/jpeglsdec.c +++ b/libavcodec/jpeglsdec.c @@ -25,6 +25,7 @@ * JPEG-LS decoder. */ +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "get_bits.h" diff --git a/libavcodec/jpeglsenc.c b/libavcodec/jpeglsenc.c index 3481c61ee..d2f4a52f2 100644 --- a/libavcodec/jpeglsenc.c +++ b/libavcodec/jpeglsenc.c @@ -26,6 +26,7 @@ */ #define UNCHECKED_BITSTREAM_READER 1 +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/jpegxl_parser.c b/libavcodec/jpegxl_parser.c index 8c45e1a1b..76122af54 100644 --- a/libavcodec/jpegxl_parser.c +++ b/libavcodec/jpegxl_parser.c @@ -352,6 +352,8 @@ static int decode_hybrid_varlen_uint(GetBitContext *gb, JXLEntropyDecoder *dec, if (bundle->lz77_enabled && token >= bundle->lz77_min_symbol) { const JXLSymbolDistribution *lz77dist = &bundle->dists[bundle->cluster_map[bundle->num_dist - 1]]; + if (!dec->num_decoded) + return AVERROR_INVALIDDATA; ret = read_hybrid_uint(gb, &bundle->lz_len_conf, token - bundle->lz77_min_symbol, &dec->num_to_copy); if (ret < 0) return ret; @@ -531,6 +533,7 @@ static int read_dist_clustering(GetBitContext *gb, JXLEntropyDecoder *dec, JXLDi dec->state = -1; /* it's not going to necessarily be zero after reading */ dec->num_to_copy = 0; + dec->num_decoded = 0; dist_bundle_close(&nested); if (use_mtf) { uint8_t mtf[256]; @@ -1311,7 +1314,7 @@ static int parse_frame_header(void *avctx, JXLParseContext *ctx, GetBitContext * // permuted toc if (get_bits1(gb)) { JXLEntropyDecoder dec; - uint32_t end, lehmer = 0; + int64_t end, lehmer = 0; ret = entropy_decoder_init(avctx, gb, &dec, 8); if (ret < 0) return ret; @@ -1320,13 +1323,13 @@ static int parse_frame_header(void *avctx, JXLParseContext *ctx, GetBitContext * return AVERROR_BUFFER_TOO_SMALL; } end = entropy_decoder_read_symbol(gb, &dec, toc_context(toc_count)); - if (end > toc_count) { + if (end < 0 || end > toc_count) { entropy_decoder_close(&dec); return AVERROR_INVALIDDATA; } for (uint32_t i = 0; i < end; i++) { lehmer = entropy_decoder_read_symbol(gb, &dec, toc_context(lehmer)); - if (get_bits_left(gb) < 0) { + if (lehmer < 0 || get_bits_left(gb) < 0) { entropy_decoder_close(&dec); return AVERROR_BUFFER_TOO_SMALL; } diff --git a/libavcodec/jvdec.c b/libavcodec/jvdec.c index 13ede9068..2b7c9f0d2 100644 --- a/libavcodec/jvdec.c +++ b/libavcodec/jvdec.c @@ -215,8 +215,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, } if (video_size) { - s->frame->flags |= AV_FRAME_FLAG_KEY; - s->frame->pict_type = AV_PICTURE_TYPE_I; #if FF_API_PALETTE_HAS_CHANGED FF_DISABLE_DEPRECATION_WARNINGS s->frame->palette_has_changed = s->palette_has_changed; diff --git a/libavcodec/kgv1dec.c b/libavcodec/kgv1dec.c index 139ec9b05..bdc5a1625 100644 --- a/libavcodec/kgv1dec.c +++ b/libavcodec/kgv1dec.c @@ -27,6 +27,7 @@ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/lagarith.c b/libavcodec/lagarith.c index 75b557e51..0969448ed 100644 --- a/libavcodec/lagarith.c +++ b/libavcodec/lagarith.c @@ -570,9 +570,6 @@ static int lag_decode_frame(AVCodecContext *avctx, AVFrame *p, int i, j, planes = 3; int ret = 0; - p->flags |= AV_FRAME_FLAG_KEY; - p->pict_type = AV_PICTURE_TYPE_I; - frametype = buf[0]; offset_gu = AV_RL32(buf + 1); diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c new file mode 100644 index 000000000..ceeece3aa --- /dev/null +++ b/libavcodec/lcevcdec.c @@ -0,0 +1,319 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 "libavutil/avassert.h" +#include "libavutil/frame.h" +#include "libavutil/imgutils.h" +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "decode.h" +#include "lcevcdec.h" + +#if CONFIG_LIBLCEVC_DEC +static LCEVC_ColorFormat map_format(int format) +{ + switch (format) { + case AV_PIX_FMT_YUV420P: + return LCEVC_I420_8; + case AV_PIX_FMT_YUV420P10: + return LCEVC_I420_10_LE; + case AV_PIX_FMT_NV12: + return LCEVC_NV12_8; + case AV_PIX_FMT_NV21: + return LCEVC_NV21_8; + case AV_PIX_FMT_GRAY8: + return LCEVC_GRAY_8; + } + + return LCEVC_ColorFormat_Unknown; +} + +static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder, + const AVFrame *frame, LCEVC_PictureHandle *picture) +{ + LCEVC_PictureDesc desc; + LCEVC_ColorFormat fmt = map_format(frame->format); + LCEVC_PictureLockHandle lock; + uint8_t *data[4] = { NULL }; + int linesizes[4] = { 0 }; + uint32_t planes; + LCEVC_ReturnCode res; + + res = LCEVC_DefaultPictureDesc(&desc, fmt, frame->width, frame->height); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + desc.cropTop = frame->crop_top; + desc.cropBottom = frame->crop_bottom; + desc.cropLeft = frame->crop_left; + desc.cropRight = frame->crop_right; + desc.sampleAspectRatioNum = frame->sample_aspect_ratio.num; + desc.sampleAspectRatioDen = frame->sample_aspect_ratio.den; + + /* Allocate LCEVC Picture */ + res = LCEVC_AllocPicture(decoder, &desc, picture); + if (res != LCEVC_Success) { + return AVERROR_EXTERNAL; + } + res = LCEVC_LockPicture(decoder, *picture, LCEVC_Access_Write, &lock); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + res = LCEVC_GetPicturePlaneCount(decoder, *picture, &planes); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + for (unsigned i = 0; i < planes; i++) { + LCEVC_PicturePlaneDesc plane; + + res = LCEVC_GetPictureLockPlaneDesc(decoder, lock, i, &plane); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + data[i] = plane.firstSample; + linesizes[i] = plane.rowByteStride; + } + + av_image_copy2(data, linesizes, frame->data, frame->linesize, + frame->format, frame->width, frame->height); + + res = LCEVC_UnlockPicture(decoder, lock); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + return 0; +} + +static int alloc_enhanced_frame(void *logctx, LCEVC_DecoderHandle decoder, + const AVFrame *frame, LCEVC_PictureHandle *picture) +{ + LCEVC_PictureDesc desc ; + LCEVC_ColorFormat fmt = map_format(frame->format); + LCEVC_PicturePlaneDesc planes[4] = { 0 }; + int width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1); + int height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1); + LCEVC_ReturnCode res; + + res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + /* Set plane description */ + for (int i = 0; i < 4; i++) { + planes[i].firstSample = frame->data[i]; + planes[i].rowByteStride = frame->linesize[i]; + } + + /* Allocate LCEVC Picture */ + res = LCEVC_AllocPictureExternal(decoder, &desc, NULL, planes, picture); + if (res != LCEVC_Success) { + return AVERROR_EXTERNAL; + } + return 0; +} + +static int lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in) +{ + const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC); + LCEVC_PictureHandle picture; + LCEVC_ReturnCode res; + int ret = 0; + + if (!sd) + return 1; + + res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + ret = alloc_base_frame(logctx, lcevc->decoder, in, &picture); + if (ret < 0) + return ret; + + res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + memset(&picture, 0, sizeof(picture)); + ret = alloc_enhanced_frame(logctx, lcevc->decoder, in, &picture); + if (ret < 0) + return ret; + + res = LCEVC_SendDecoderPicture(lcevc->decoder, picture); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + return 0; +} + +static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out) +{ + LCEVC_PictureDesc desc; + LCEVC_DecodeInformation info; + LCEVC_PictureHandle picture; + LCEVC_ReturnCode res; + + res = LCEVC_ReceiveDecoderPicture(lcevc->decoder, &picture, &info); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + out->crop_top = desc.cropTop; + out->crop_bottom = desc.cropBottom; + out->crop_left = desc.cropLeft; + out->crop_right = desc.cropRight; + out->sample_aspect_ratio.num = desc.sampleAspectRatioNum; + out->sample_aspect_ratio.den = desc.sampleAspectRatioDen; + out->width = desc.width + out->crop_left + out->crop_right; + out->height = desc.height + out->crop_top + out->crop_bottom; + + res = LCEVC_FreePicture(lcevc->decoder, picture); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + return 0; +} + +static int lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out) +{ + LCEVC_PictureHandle picture; + LCEVC_ReturnCode res; + int ret; + + ret = generate_output(logctx, lcevc, out); + if (ret < 0) + return ret; + + while (1) { + res = LCEVC_ReceiveDecoderBase (lcevc->decoder, &picture); + if (res != LCEVC_Success && res != LCEVC_Again) + return AVERROR_EXTERNAL; + + if (res == LCEVC_Again) + break; + + res = LCEVC_FreePicture(lcevc->decoder, picture); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + } + + return 0; +} + +static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event, + LCEVC_PictureHandle pic, const LCEVC_DecodeInformation *info, + const uint8_t *data, uint32_t size, void *logctx) +{ + switch (event) { + case LCEVC_Log: + av_log(logctx, AV_LOG_INFO, "%s\n", data); + break; + default: + break; + } +} + +static void lcevc_free(FFRefStructOpaque unused, void *obj) +{ + FFLCEVCContext *lcevc = obj; + if (lcevc->initialized) + LCEVC_DestroyDecoder(lcevc->decoder); + memset(lcevc, 0, sizeof(*lcevc)); +} +#endif + +static int lcevc_init(FFLCEVCContext *lcevc, void *logctx) +{ +#if CONFIG_LIBLCEVC_DEC + LCEVC_AccelContextHandle dummy = { 0 }; + const int32_t event = LCEVC_Log; +#endif + + if (lcevc->initialized) + return 0; + +#if CONFIG_LIBLCEVC_DEC + if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) { + av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n"); + return AVERROR_EXTERNAL; + } + + LCEVC_ConfigureDecoderInt(lcevc->decoder, "log_level", 4); + LCEVC_ConfigureDecoderIntArray(lcevc->decoder, "events", 1, &event); + LCEVC_SetDecoderEventCallback(lcevc->decoder, event_callback, logctx); + + if (LCEVC_InitializeDecoder(lcevc->decoder) != LCEVC_Success) { + av_log(logctx, AV_LOG_ERROR, "Failed to initialize LCEVC decoder\n"); + LCEVC_DestroyDecoder(lcevc->decoder); + return AVERROR_EXTERNAL; + } + +#endif + lcevc->initialized = 1; + + return 0; +} + +int ff_lcevc_process(void *logctx, AVFrame *frame) +{ + FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + FFLCEVCContext *lcevc = fdd->post_process_opaque; + int ret; + + if (!lcevc->initialized) { + ret = lcevc_init(lcevc, logctx); + if (ret < 0) + return ret; + } + +#if CONFIG_LIBLCEVC_DEC + ret = lcevc_send_frame(logctx, lcevc, frame); + if (ret) + return ret < 0 ? ret : 0; + + lcevc_receive_frame(logctx, lcevc, frame); + if (ret < 0) + return ret; + + av_frame_remove_side_data(frame, AV_FRAME_DATA_LCEVC); +#endif + + return 0; +} + +int ff_lcevc_alloc(FFLCEVCContext **plcevc) +{ + FFLCEVCContext *lcevc = NULL; +#if CONFIG_LIBLCEVC_DEC + lcevc = ff_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free); + if (!lcevc) + return AVERROR(ENOMEM); +#endif + *plcevc = lcevc; + return 0; +} + +void ff_lcevc_unref(void *opaque) +{ + ff_refstruct_unref(&opaque); +} diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h new file mode 100644 index 000000000..7334d3a64 --- /dev/null +++ b/libavcodec/lcevcdec.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_LCEVCDEC_H +#define AVCODEC_LCEVCDEC_H + +#include "config_components.h" + +#include +#if CONFIG_LIBLCEVC_DEC +#include +#else +typedef uintptr_t LCEVC_DecoderHandle; +#endif +#include "refstruct.h" + +typedef struct FFLCEVCContext { + LCEVC_DecoderHandle decoder; + int initialized; +} FFLCEVCContext; + +struct AVFrame; + +int ff_lcevc_alloc(FFLCEVCContext **plcevc); +int ff_lcevc_process(void *logctx, struct AVFrame *frame); +void ff_lcevc_unref(void *opaque); +#endif /* AVCODEC_LCEVCDEC_H */ diff --git a/libavcodec/lcldec.c b/libavcodec/lcldec.c index b4304618e..b439dbe25 100644 --- a/libavcodec/lcldec.c +++ b/libavcodec/lcldec.c @@ -481,9 +481,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, return AVERROR_INVALIDDATA; } - frame->flags |= AV_FRAME_FLAG_KEY; - frame->pict_type = AV_PICTURE_TYPE_I; - *got_frame = 1; /* always report that the buffer was completely consumed */ diff --git a/libavcodec/leaddec.c b/libavcodec/leaddec.c index a6f6c3cc8..2f5152c22 100644 --- a/libavcodec/leaddec.c +++ b/libavcodec/leaddec.c @@ -30,6 +30,7 @@ #include "jpegquanttables.h" #include "jpegtables.h" #include "leaddata.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" @@ -181,9 +182,6 @@ static int lead_decode_frame(AVCodecContext *avctx, AVFrame * frame, if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; - frame->flags |= AV_FRAME_FLAG_KEY; - frame->pict_type = AV_PICTURE_TYPE_I; - av_fast_padded_malloc(&s->bitstream_buf, &s->bitstream_buf_size, avpkt->size - 8); if (!s->bitstream_buf) return AVERROR(ENOMEM); diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c index 8c1f84cc9..0f7571ee7 100644 --- a/libavcodec/libaomenc.c +++ b/libavcodec/libaomenc.c @@ -35,6 +35,7 @@ #include "libavutil/cpu.h" #include "libavutil/imgutils.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -42,6 +43,7 @@ #include "avcodec.h" #include "bsf.h" #include "codec_internal.h" +#include "dovi_rpu.h" #include "encode.h" #include "internal.h" #include "libaom.h" @@ -69,6 +71,7 @@ struct FrameListData { typedef struct AOMEncoderContext { AVClass *class; AVBSFContext *bsf; + DOVIContext dovi; struct aom_codec_ctx encoder; struct aom_image rawimg; struct aom_fixed_buf twopass_stats; @@ -154,27 +157,14 @@ static const char *const ctlidstr[] = { [AV1E_SET_TILE_COLUMNS] = "AV1E_SET_TILE_COLUMNS", [AV1E_SET_TILE_ROWS] = "AV1E_SET_TILE_ROWS", [AV1E_SET_ENABLE_RESTORATION] = "AV1E_SET_ENABLE_RESTORATION", -#ifdef AOM_CTRL_AV1E_SET_ROW_MT [AV1E_SET_ROW_MT] = "AV1E_SET_ROW_MT", -#endif -#ifdef AOM_CTRL_AV1E_SET_DENOISE_NOISE_LEVEL [AV1E_SET_DENOISE_NOISE_LEVEL] = "AV1E_SET_DENOISE_NOISE_LEVEL", -#endif -#ifdef AOM_CTRL_AV1E_SET_DENOISE_BLOCK_SIZE [AV1E_SET_DENOISE_BLOCK_SIZE] = "AV1E_SET_DENOISE_BLOCK_SIZE", -#endif -#ifdef AOM_CTRL_AV1E_SET_MAX_REFERENCE_FRAMES [AV1E_SET_MAX_REFERENCE_FRAMES] = "AV1E_SET_MAX_REFERENCE_FRAMES", -#endif -#ifdef AOM_CTRL_AV1E_SET_ENABLE_GLOBAL_MOTION [AV1E_SET_ENABLE_GLOBAL_MOTION] = "AV1E_SET_ENABLE_GLOBAL_MOTION", -#endif -#ifdef AOM_CTRL_AV1E_SET_ENABLE_INTRABC [AV1E_SET_ENABLE_INTRABC] = "AV1E_SET_ENABLE_INTRABC", -#endif [AV1E_SET_ENABLE_CDEF] = "AV1E_SET_ENABLE_CDEF", [AOME_SET_TUNING] = "AOME_SET_TUNING", -#if AOM_ENCODER_ABI_VERSION >= 22 [AV1E_SET_ENABLE_1TO4_PARTITIONS] = "AV1E_SET_ENABLE_1TO4_PARTITIONS", [AV1E_SET_ENABLE_AB_PARTITIONS] = "AV1E_SET_ENABLE_AB_PARTITIONS", [AV1E_SET_ENABLE_RECT_PARTITIONS] = "AV1E_SET_ENABLE_RECT_PARTITIONS", @@ -203,13 +193,10 @@ static const char *const ctlidstr[] = { [AV1E_SET_REDUCED_REFERENCE_SET] = "AV1E_SET_REDUCED_REFERENCE_SET", [AV1E_SET_ENABLE_SMOOTH_INTERINTRA] = "AV1E_SET_ENABLE_SMOOTH_INTERINTRA", [AV1E_SET_ENABLE_REF_FRAME_MVS] = "AV1E_SET_ENABLE_REF_FRAME_MVS", -#endif #ifdef AOM_CTRL_AV1E_GET_NUM_OPERATING_POINTS [AV1E_GET_NUM_OPERATING_POINTS] = "AV1E_GET_NUM_OPERATING_POINTS", #endif -#ifdef AOM_CTRL_AV1E_GET_SEQ_LEVEL_IDX [AV1E_GET_SEQ_LEVEL_IDX] = "AV1E_GET_SEQ_LEVEL_IDX", -#endif #ifdef AOM_CTRL_AV1E_GET_TARGET_SEQ_LEVEL_IDX [AV1E_GET_TARGET_SEQ_LEVEL_IDX] = "AV1E_GET_TARGET_SEQ_LEVEL_IDX", #endif @@ -432,10 +419,12 @@ static av_cold int aom_free(AVCodecContext *avctx) #endif aom_codec_destroy(&ctx->encoder); + aom_img_remove_metadata(&ctx->rawimg); av_freep(&ctx->twopass_stats.buf); av_freep(&avctx->stats_out); free_frame_list(ctx->coded_frame_list); av_bsf_free(&ctx->bsf); + ff_dovi_ctx_unref(&ctx->dovi); return 0; } @@ -690,12 +679,8 @@ static av_cold int aom_init(AVCodecContext *avctx, AOMContext *ctx = avctx->priv_data; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); struct aom_codec_enc_cfg enccfg = { 0 }; -#ifdef AOM_FRAME_IS_INTRAONLY aom_codec_flags_t flags = (avctx->flags & AV_CODEC_FLAG_PSNR) ? AOM_CODEC_USE_PSNR : 0; -#else - aom_codec_flags_t flags = 0; -#endif AVCPBProperties *cpb_props; int res; aom_img_fmt_t img_fmt; @@ -885,7 +870,6 @@ static av_cold int aom_init(AVCodecContext *avctx, 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 AOM_ENCODER_ABI_VERSION >= 22 if (ctx->enable_rect_partitions >= 0) codecctl_int(avctx, AV1E_SET_ENABLE_RECT_PARTITIONS, ctx->enable_rect_partitions); if (ctx->enable_1to4_partitions >= 0) @@ -942,7 +926,6 @@ static av_cold int aom_init(AVCodecContext *avctx, 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); -#endif codecctl_int(avctx, AOME_SET_STATIC_THRESHOLD, ctx->static_thresh); if (ctx->crf >= 0) @@ -971,37 +954,25 @@ static av_cold int aom_init(AVCodecContext *avctx, codecctl_int(avctx, AV1E_SET_TILE_ROWS, ctx->tile_rows_log2); } -#ifdef AOM_CTRL_AV1E_SET_DENOISE_NOISE_LEVEL if (ctx->denoise_noise_level >= 0) codecctl_int(avctx, AV1E_SET_DENOISE_NOISE_LEVEL, ctx->denoise_noise_level); -#endif -#ifdef AOM_CTRL_AV1E_SET_DENOISE_BLOCK_SIZE if (ctx->denoise_block_size >= 0) codecctl_int(avctx, AV1E_SET_DENOISE_BLOCK_SIZE, ctx->denoise_block_size); -#endif -#ifdef AOM_CTRL_AV1E_SET_ENABLE_GLOBAL_MOTION if (ctx->enable_global_motion >= 0) codecctl_int(avctx, AV1E_SET_ENABLE_GLOBAL_MOTION, ctx->enable_global_motion); -#endif -#ifdef AOM_CTRL_AV1E_SET_MAX_REFERENCE_FRAMES if (avctx->refs >= 3) { codecctl_int(avctx, AV1E_SET_MAX_REFERENCE_FRAMES, avctx->refs); } -#endif -#ifdef AOM_CTRL_AV1E_SET_ROW_MT if (ctx->row_mt >= 0) codecctl_int(avctx, AV1E_SET_ROW_MT, ctx->row_mt); -#endif -#ifdef AOM_CTRL_AV1E_SET_ENABLE_INTRABC if (ctx->enable_intrabc >= 0) codecctl_int(avctx, AV1E_SET_ENABLE_INTRABC, ctx->enable_intrabc); -#endif #if AOM_ENCODER_ABI_VERSION >= 23 { - AVDictionaryEntry *en = NULL; + const AVDictionaryEntry *en = NULL; - while ((en = av_dict_get(ctx->aom_params, "", en, AV_DICT_IGNORE_SUFFIX))) { + while ((en = av_dict_iterate(ctx->aom_params, en))) { int ret = aom_codec_set_option(&ctx->encoder, en->key, en->value); if (ret != AOM_CODEC_OK) { log_encoder_error(avctx, en->key); @@ -1022,6 +993,10 @@ static av_cold int aom_init(AVCodecContext *avctx, if (!cpb_props) return AVERROR(ENOMEM); + ctx->dovi.logctx = avctx; + if ((res = ff_dovi_configure(&ctx->dovi, avctx)) < 0) + return res; + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { const AVBitStreamFilter *filter = av_bsf_get_by_name("extract_extradata"); int ret; @@ -1064,7 +1039,6 @@ static inline void cx_pktcpy(AOMContext *ctx, dst->flags = src->data.frame.flags; dst->sz = src->data.frame.sz; dst->buf = src->data.frame.buf; -#ifdef AOM_FRAME_IS_INTRAONLY dst->frame_number = ++ctx->frame_number; dst->have_sse = ctx->have_sse; if (ctx->have_sse) { @@ -1073,7 +1047,6 @@ static inline void cx_pktcpy(AOMContext *ctx, memcpy(dst->sse, ctx->sse, sizeof(dst->sse)); ctx->have_sse = 0; } -#endif } /** @@ -1100,7 +1073,6 @@ static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, if (!!(cx_frame->flags & AOM_FRAME_IS_KEY)) { pkt->flags |= AV_PKT_FLAG_KEY; -#ifdef AOM_FRAME_IS_INTRAONLY pict_type = AV_PICTURE_TYPE_I; } else if (cx_frame->flags & AOM_FRAME_IS_INTRAONLY) { pict_type = AV_PICTURE_TYPE_I; @@ -1117,7 +1089,6 @@ static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, avctx->error[i] += cx_frame->sse[i + 1]; } cx_frame->have_sse = 0; -#endif } if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { @@ -1220,7 +1191,6 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out) stats->sz += pkt->data.twopass_stats.sz; break; } -#ifdef AOM_FRAME_IS_INTRAONLY case AOM_CODEC_PSNR_PKT: { av_assert0(!ctx->have_sse); @@ -1231,7 +1201,6 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out) ctx->have_sse = 1; break; } -#endif case AOM_CODEC_CUSTOM_PKT: // ignore unsupported/unrecognized packet types break; @@ -1281,6 +1250,7 @@ static int aom_encode(AVCodecContext *avctx, AVPacket *pkt, unsigned long duration = 0; int res, coded_size; aom_enc_frame_flags_t flags = 0; + AVFrameSideData *sd; if (frame) { rawimg = &ctx->rawimg; @@ -1318,6 +1288,26 @@ FF_ENABLE_DEPRECATION_WARNINGS break; } + aom_img_remove_metadata(rawimg); + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOVI_METADATA); + if (ctx->dovi.cfg.dv_profile && sd) { + const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->data; + uint8_t *t35; + int size; + if ((res = ff_dovi_rpu_generate(&ctx->dovi, metadata, FF_DOVI_WRAP_T35, + &t35, &size)) < 0) + return res; + res = aom_img_add_metadata(rawimg, OBU_METADATA_TYPE_ITUT_T35, + t35, size, AOM_MIF_ANY_FRAME); + av_free(t35); + if (res != AOM_CODEC_OK) + return AVERROR(ENOMEM); + } else if (ctx->dovi.cfg.dv_profile) { + av_log(avctx, AV_LOG_ERROR, "Dolby Vision enabled, but received frame " + "without AV_FRAME_DATA_DOVI_METADATA\n"); + return AVERROR_INVALIDDATA; + } + if (frame->pict_type == AV_PICTURE_TYPE_I) flags |= AOM_EFLAG_FORCE_KF; } @@ -1437,19 +1427,36 @@ static const enum AVPixelFormat av1_pix_fmts_highbd_with_gray[] = { AV_PIX_FMT_NONE }; -static av_cold void av1_init_static(FFCodec *codec) +static int av1_get_supported_config(const AVCodecContext *avctx, + const AVCodec *codec, + enum AVCodecConfig config, + unsigned flags, const void **out, + int *out_num) { - int supports_monochrome = aom_codec_version() >= 20001; - aom_codec_caps_t codec_caps = aom_codec_get_caps(aom_codec_av1_cx()); - if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) - codec->p.pix_fmts = supports_monochrome ? av1_pix_fmts_highbd_with_gray : - av1_pix_fmts_highbd; - else - codec->p.pix_fmts = supports_monochrome ? av1_pix_fmts_with_gray : - av1_pix_fmts; + if (config == AV_CODEC_CONFIG_PIX_FORMAT) { + int supports_monochrome = aom_codec_version() >= 20001; + aom_codec_caps_t codec_caps = aom_codec_get_caps(aom_codec_av1_cx()); + if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) { + if (supports_monochrome) { + *out = av1_pix_fmts_highbd_with_gray; + *out_num = FF_ARRAY_ELEMS(av1_pix_fmts_highbd_with_gray) - 1; + } else { + *out = av1_pix_fmts_highbd; + *out_num = FF_ARRAY_ELEMS(av1_pix_fmts_highbd) - 1; + } + } else { + if (supports_monochrome) { + *out = av1_pix_fmts_with_gray; + *out_num = FF_ARRAY_ELEMS(av1_pix_fmts_with_gray) - 1; + } else { + *out = av1_pix_fmts; + *out_num = FF_ARRAY_ELEMS(av1_pix_fmts) - 1; + } + } + return 0; + } - if (aom_codec_version_major() < 2) - codec->p.capabilities |= AV_CODEC_CAP_EXPERIMENTAL; + return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num); } static av_cold int av1_init(AVCodecContext *avctx) @@ -1501,6 +1508,8 @@ static const AVOption options[] = { { "ssim", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AOM_TUNE_SSIM}, 0, 0, VE, .unit = "tune"}, FF_AV1_PROFILE_OPTS { "still-picture", "Encode in single frame mode (typically used for still AVIF images).", OFFSET(still_picture), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, VE }, + { "dolbyvision", "Enable Dolby Vision RPU coding", OFFSET(dovi.enable), AV_OPT_TYPE_BOOL, {.i64 = FF_DOVI_AUTOMATIC }, -1, 1, VE, .unit = "dovi" }, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DOVI_AUTOMATIC}, .flags = VE, .unit = "dovi" }, { "enable-rect-partitions", "Enable rectangular partitions", OFFSET(enable_rect_partitions), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-1to4-partitions", "Enable 1:4/4:1 partitions", OFFSET(enable_1to4_partitions), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-ab-partitions", "Enable ab shape partitions", OFFSET(enable_ab_partitions), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, @@ -1559,6 +1568,7 @@ FFCodec ff_libaom_av1_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_ENCODER_RECON_FRAME | AV_CODEC_CAP_OTHER_THREADS, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles), .p.priv_class = &class_aom, .p.wrapper_name = "libaom", @@ -1570,5 +1580,5 @@ FFCodec ff_libaom_av1_encoder = { FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS, .defaults = defaults, - .init_static_data = av1_init_static, + .get_supported_config = av1_get_supported_config, }; diff --git a/libavcodec/libaribb24.c b/libavcodec/libaribb24.c index 507a11511..009c995de 100644 --- a/libavcodec/libaribb24.c +++ b/libavcodec/libaribb24.c @@ -23,6 +23,7 @@ #include "libavcodec/ass.h" #include "codec_internal.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include diff --git a/libavcodec/libaribcaption.c b/libavcodec/libaribcaption.c index fba682737..0b67d4177 100644 --- a/libavcodec/libaribcaption.c +++ b/libavcodec/libaribcaption.c @@ -25,6 +25,7 @@ #include "libavcodec/ass.h" #include "libavutil/avstring.h" #include "libavutil/avutil.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "libavutil/log.h" #include "libavutil/opt.h" diff --git a/libavcodec/libcodec2.c b/libavcodec/libcodec2.c index b8fa396fa..ebcd20c44 100644 --- a/libavcodec/libcodec2.c +++ b/libavcodec/libcodec2.c @@ -21,6 +21,7 @@ #include #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "libavutil/opt.h" #include "codec_internal.h" diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c index ddcd0708b..ff67f44bd 100644 --- a/libavcodec/libdav1d.c +++ b/libavcodec/libdav1d.c @@ -290,10 +290,10 @@ static av_cold int libdav1d_init(AVCodecContext *c) #endif dav1d->dovi.logctx = c; - dav1d->dovi.dv_profile = 10; // default for AV1 + dav1d->dovi.cfg.dv_profile = 10; // default for AV1 sd = ff_get_coded_side_data(c, AV_PKT_DATA_DOVI_CONF); - if (sd && sd->size > 0) - ff_dovi_update_cfg(&dav1d->dovi, (AVDOVIDecoderConfigurationRecord *) sd->data); + if (sd && sd->size >= sizeof(dav1d->dovi.cfg)) + dav1d->dovi.cfg = *(AVDOVIDecoderConfigurationRecord *) sd->data; return 0; } @@ -372,9 +372,10 @@ static int libdav1d_receive_frame_internal(AVCodecContext *c, Dav1dPicture *p) res = dav1d_get_picture(dav1d->c, p); if (res < 0) { - if (res == AVERROR(EINVAL)) + if (res == AVERROR(EINVAL)) { + dav1d_data_unref(data); res = AVERROR_INVALIDDATA; - else if (res == AVERROR(EAGAIN)) + } else if (res == AVERROR(EAGAIN)) res = c->internal->draining ? AVERROR_EOF : 1; } @@ -385,7 +386,7 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) { Libdav1dContext *dav1d = c->priv_data; Dav1dPicture pic = { 0 }, *p = &pic; - AVPacket *pkt; + const AVPacket *pkt; #if FF_DAV1D_VERSION_AT_LEAST(5,1) enum Dav1dEventFlags event_flags = 0; #endif @@ -439,7 +440,7 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) INT_MAX); ff_set_sar(c, frame->sample_aspect_ratio); - pkt = (AVPacket *)p->m.user_data.data; + pkt = (const AVPacket *)p->m.user_data.data; // match timestamps and packet size res = ff_decode_frame_props_from_pkt(c, frame, pkt); @@ -528,7 +529,7 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) if (!res) break; - res = ff_frame_new_side_data_from_buf(c, frame, AV_FRAME_DATA_A53_CC, &buf, NULL); + res = ff_frame_new_side_data_from_buf(c, frame, AV_FRAME_DATA_A53_CC, &buf); if (res < 0) goto fail; @@ -567,7 +568,8 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) provider_oriented_code != 0x800) break; - res = ff_dovi_rpu_parse(&dav1d->dovi, gb.buffer, gb.buffer_end - gb.buffer); + 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 diff --git a/libavcodec/libfdk-aacdec.c b/libavcodec/libfdk-aacdec.c index fa9d771c4..ac221645f 100644 --- a/libavcodec/libfdk-aacdec.c +++ b/libavcodec/libfdk-aacdec.c @@ -21,6 +21,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "codec_internal.h" @@ -110,7 +111,7 @@ static const AVClass fdk_aac_dec_class = { .version = LIBAVUTIL_VERSION_INT, }; -static int get_stream_info(AVCodecContext *avctx) +static int get_stream_info(AVCodecContext *avctx, AVFrame *frame) { FDKAACDecContext *s = avctx->priv_data; CStreamInfo *info = aacDecoder_GetStreamInfo(s->handle); @@ -129,6 +130,9 @@ static int get_stream_info(AVCodecContext *avctx) } avctx->sample_rate = info->sampleRate; avctx->frame_size = info->frameSize; + avctx->profile = info->aot - 1; + + frame->flags |= AV_FRAME_FLAG_KEY * !!(info->flags & AC_INDEP); #if FDKDEC_VER_AT_LEAST(2, 5) // 2.5.10 if (!s->output_delay_set && info->outputDelay) { // Set this only once. @@ -412,7 +416,7 @@ static int fdk_aac_decode_frame(AVCodecContext *avctx, AVFrame *frame, goto end; } - if ((ret = get_stream_info(avctx)) < 0) + if ((ret = get_stream_info(avctx, frame)) < 0) goto end; frame->nb_samples = avctx->frame_size; diff --git a/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c index fe3ba14ee..4dcfb25db 100644 --- a/libavcodec/libfdk-aacenc.c +++ b/libavcodec/libfdk-aacenc.c @@ -22,6 +22,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "audio_frame_queue.h" @@ -177,6 +178,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) AACContext *s = avctx->priv_data; int ret = AVERROR(EINVAL); AACENC_InfoStruct info = { 0 }; + AVCPBProperties *cpb_props; CHANNEL_MODE mode; AACENC_ERROR err; int aot = AV_PROFILE_AAC_LOW + 1; @@ -437,6 +439,14 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) memcpy(avctx->extradata, info.confBuf, info.confSize); } + + cpb_props = ff_encode_add_cpb_side_data(avctx); + if (!cpb_props) + return AVERROR(ENOMEM); + cpb_props->max_bitrate = + cpb_props->min_bitrate = + cpb_props->avg_bitrate = avctx->bit_rate; + return 0; error: aac_encode_close(avctx); @@ -539,6 +549,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } avpkt->size = out_args.numOutBytes; + avpkt->flags |= AV_PKT_FLAG_KEY; *got_packet_ptr = 1; return 0; } diff --git a/libavcodec/libjxldec.c b/libavcodec/libjxldec.c index d57a27418..9dfc261e3 100644 --- a/libavcodec/libjxldec.c +++ b/libavcodec/libjxldec.c @@ -483,7 +483,7 @@ static int libjxl_receive_frame(AVCodecContext *avctx, AVFrame *frame) /* 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, NULL); + ret = ff_frame_new_side_data_from_buf(avctx, ctx->frame, AV_FRAME_DATA_ICC_PROFILE, &ctx->iccp); if (ret < 0) return ret; } diff --git a/libavcodec/libjxlenc.c b/libavcodec/libjxlenc.c index 3f2c74097..8b0e60df6 100644 --- a/libavcodec/libjxlenc.c +++ b/libavcodec/libjxlenc.c @@ -31,6 +31,7 @@ #include "libavutil/error.h" #include "libavutil/frame.h" #include "libavutil/libm.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" diff --git a/libavcodec/libkvazaar.c b/libavcodec/libkvazaar.c index 0711d9ab3..e82be2a35 100644 --- a/libavcodec/libkvazaar.c +++ b/libavcodec/libkvazaar.c @@ -111,8 +111,8 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->kvz_params) { AVDictionary *dict = NULL; if (!av_dict_parse_string(&dict, ctx->kvz_params, "=", ",", 0)) { - AVDictionaryEntry *entry = NULL; - while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX))) { + const AVDictionaryEntry *entry = NULL; + while ((entry = av_dict_iterate(dict, entry))) { if (!api->config_parse(cfg, entry->key, entry->value)) { av_log(avctx, AV_LOG_WARNING, "Invalid option: %s=%s.\n", entry->key, entry->value); @@ -334,6 +334,7 @@ const FFCodec ff_libkvazaar_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, .p.pix_fmts = pix_fmts, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .priv_data_size = sizeof(LibkvazaarContext), diff --git a/libavcodec/liblc3dec.c b/libavcodec/liblc3dec.c new file mode 100644 index 000000000..d250ace38 --- /dev/null +++ b/libavcodec/liblc3dec.c @@ -0,0 +1,146 @@ +/* + * LC3 decoder wrapper + * Copyright (C) 2024 Antoine Soulier + * + * This file is part of FFmpeg. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" + +#include "avcodec.h" +#include "codec.h" +#include "codec_internal.h" +#include "decode.h" +#include "internal.h" + +#define DECODER_MAX_CHANNELS 2 + +typedef struct LibLC3DecContext { + int frame_us, srate_hz, hr_mode; + void *decoder_mem; + lc3_decoder_t decoder[DECODER_MAX_CHANNELS]; +} LibLC3DecContext; + +static av_cold int liblc3_decode_init(AVCodecContext *avctx) +{ + LibLC3DecContext *liblc3 = avctx->priv_data; + int channels = avctx->ch_layout.nb_channels; + int ep_mode; + unsigned decoder_size; + + if (avctx->extradata_size < 6) + return AVERROR_INVALIDDATA; + if (channels < 0 || channels > DECODER_MAX_CHANNELS) { + av_log(avctx, AV_LOG_ERROR, + "Invalid number of channels %d. Max %d channels are accepted\n", + channels, DECODER_MAX_CHANNELS); + return AVERROR(EINVAL); + } + + liblc3->frame_us = AV_RL16(avctx->extradata + 0) * 10; + liblc3->srate_hz = avctx->sample_rate; + ep_mode = AV_RL16(avctx->extradata + 2); + liblc3->hr_mode = AV_RL16(avctx->extradata + 4); + if (ep_mode != 0) { + av_log(avctx, AV_LOG_ERROR, + "Error protection mode is not supported.\n"); + return AVERROR(EINVAL); + } + + av_log(avctx, AV_LOG_INFO, + "Decoding %.1f ms frames.\n", liblc3->frame_us / 1000.f); + if (liblc3->hr_mode) + av_log(avctx, AV_LOG_INFO, "High-resolution mode enabled.\n"); + + decoder_size = lc3_hr_decoder_size( + liblc3->hr_mode, liblc3->frame_us, liblc3->srate_hz); + if (!decoder_size) + return AVERROR_INVALIDDATA; + + liblc3->decoder_mem = av_malloc_array(channels, decoder_size); + if (!liblc3->decoder_mem) + return AVERROR(ENOMEM); + + for (int ch = 0; ch < channels; ch++) { + liblc3->decoder[ch] = lc3_hr_setup_decoder( + liblc3->hr_mode, liblc3->frame_us, liblc3->srate_hz, 0, + (char *)liblc3->decoder_mem + ch * decoder_size); + } + + avctx->sample_fmt = 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; +} + +static av_cold int liblc3_decode_close(AVCodecContext *avctx) +{ + LibLC3DecContext *liblc3 = avctx->priv_data; + + av_freep(&liblc3->decoder_mem); + + return 0; +} + +static int liblc3_decode(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, AVPacket *avpkt) +{ + LibLC3DecContext *liblc3 = avctx->priv_data; + int channels = avctx->ch_layout.nb_channels; + uint8_t *in = avpkt->data; + int block_bytes, ret; + + frame->nb_samples = av_rescale( + liblc3->frame_us, liblc3->srate_hz, 1000*1000); + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + block_bytes = avpkt->size; + for (int ch = 0; ch < channels; ch++) { + int nbytes = block_bytes / channels + (ch < block_bytes % channels); + + ret = lc3_decode(liblc3->decoder[ch], in, nbytes, + LC3_PCM_FORMAT_FLOAT, frame->data[ch], 1); + if (ret < 0) + return AVERROR_INVALIDDATA; + + in += nbytes; + } + + frame->nb_samples = FFMIN(frame->nb_samples, avpkt->duration); + + *got_frame_ptr = 1; + + return avpkt->size; +} + +const FFCodec ff_liblc3_decoder = { + .p.name = "liblc3", + CODEC_LONG_NAME("LC3 (Low Complexity Communication Codec)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_LC3, + .p.capabilities = AV_CODEC_CAP_DR1, + .p.wrapper_name = "liblc3", + .priv_data_size = sizeof(LibLC3DecContext), + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .init = liblc3_decode_init, + .close = liblc3_decode_close, + FF_CODEC_DECODE_CB(liblc3_decode), +}; diff --git a/libavcodec/liblc3enc.c b/libavcodec/liblc3enc.c new file mode 100644 index 000000000..3c0bcc684 --- /dev/null +++ b/libavcodec/liblc3enc.c @@ -0,0 +1,214 @@ +/* + * LC3 encoder wrapper + * Copyright (C) 2024 Antoine Soulier + * + * This file is part of FFmpeg. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "libavutil/mem.h" + +#include "avcodec.h" +#include "codec.h" +#include "codec_internal.h" +#include "encode.h" + +#define ENCODER_MAX_CHANNELS 2 + +typedef struct LibLC3EncOpts { + float frame_duration; + int hr_mode; +} LibLC3EncOpts; + +typedef struct LibLC3EncContext { + const AVClass *av_class; + LibLC3EncOpts opts; + int block_bytes; + void *encoder_mem; + lc3_encoder_t encoder[ENCODER_MAX_CHANNELS]; + int delay_samples; + int remaining_samples; +} LibLC3EncContext; + +static av_cold int liblc3_encode_init(AVCodecContext *avctx) +{ + LibLC3EncContext *liblc3 = avctx->priv_data; + bool hr_mode = liblc3->opts.hr_mode; + int frame_us = liblc3->opts.frame_duration * 1000; + int srate_hz = avctx->sample_rate; + int channels = avctx->ch_layout.nb_channels; + int effective_bit_rate; + unsigned encoder_size; + + if (frame_us != 2500 && frame_us != 5000 && + frame_us != 7500 && frame_us != 10000 ) { + av_log(avctx, AV_LOG_ERROR, + "Unsupported frame duration %.1f ms.\n", frame_us / 1000.f); + return AVERROR(EINVAL); + } + if (channels < 0 || channels > ENCODER_MAX_CHANNELS) { + av_log(avctx, AV_LOG_ERROR, + "Invalid number of channels %d. Max %d channels are accepted\n", + channels, ENCODER_MAX_CHANNELS); + return AVERROR(EINVAL); + } + + hr_mode |= srate_hz > 48000; + hr_mode &= srate_hz >= 48000; + + if (frame_us == 7500 && hr_mode) { + av_log(avctx, AV_LOG_ERROR, + "High-resolution mode is not supported with 7.5 ms frames.\n"); + return AVERROR(EINVAL); + } + + av_log(avctx, AV_LOG_INFO, "Encoding %.1f ms frames.\n", frame_us / 1000.f); + if (hr_mode) + av_log(avctx, AV_LOG_INFO, "High-resolution mode is enabled.\n"); + + liblc3->block_bytes = lc3_hr_frame_block_bytes( + hr_mode, frame_us, srate_hz, channels, avctx->bit_rate); + + effective_bit_rate = lc3_hr_resolve_bitrate( + hr_mode, frame_us, srate_hz, liblc3->block_bytes); + + if (avctx->bit_rate != effective_bit_rate) + av_log(avctx, AV_LOG_WARNING, + "Bitrate changed to %d bps.\n", effective_bit_rate); + avctx->bit_rate = effective_bit_rate; + + encoder_size = lc3_hr_encoder_size(hr_mode, frame_us, srate_hz); + if (!encoder_size) + return AVERROR(EINVAL); + + liblc3->encoder_mem = av_malloc_array(channels, encoder_size); + if (!liblc3->encoder_mem) + return AVERROR(ENOMEM); + + for (int ch = 0; ch < channels; ch++) { + liblc3->encoder[ch] = lc3_hr_setup_encoder( + hr_mode, frame_us, srate_hz, 0, + (char *)liblc3->encoder_mem + ch * encoder_size); + } + + avctx->extradata = av_mallocz(6 + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) + return AVERROR(ENOMEM); + + AV_WL16(avctx->extradata + 0, frame_us / 10); + AV_WL16(avctx->extradata + 2, 0); + AV_WL16(avctx->extradata + 4, hr_mode); + avctx->extradata_size = 6; + + avctx->frame_size = av_rescale(frame_us, srate_hz, 1000*1000); + liblc3->delay_samples = lc3_hr_delay_samples(hr_mode, frame_us, srate_hz); + liblc3->remaining_samples = 0; + + return 0; +} + +static av_cold int liblc3_encode_close(AVCodecContext *avctx) +{ + LibLC3EncContext *liblc3 = avctx->priv_data; + + av_freep(&liblc3->encoder_mem); + + return 0; +} + +static int liblc3_encode(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet_ptr) +{ + 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; + + if ((ret = ff_get_encode_buffer(avctx, pkt, block_bytes, 0)) < 0) + return ret; + + if (frame) { + int padding = frame->nb_samples - frame->duration; + liblc3->remaining_samples = FFMAX(liblc3->delay_samples - padding, 0); + } else { + if (!liblc3->remaining_samples) + return 0; + + liblc3->remaining_samples = 0; + zero_frame = av_mallocz(avctx->frame_size * sizeof(float)); + if (!zero_frame) + return AVERROR(ENOMEM); + } + + 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); + + lc3_encode(liblc3->encoder[ch], + LC3_PCM_FORMAT_FLOAT, pcm, 1, nbytes, data_ptr); + + data_ptr += nbytes; + } + + if (zero_frame) + av_free(zero_frame); + + *got_packet_ptr = 1; + + return 0; +} + +#define OFFSET(x) offsetof(LibLC3EncContext, opts.x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "frame_duration", "Duration of a frame in milliseconds", + OFFSET(frame_duration), AV_OPT_TYPE_FLOAT, + { .dbl = 10.0 }, 2.5, 10.0, FLAGS }, + { "high_resolution", "Enable High-Resolution mode (48 KHz or 96 KHz)", + OFFSET(hr_mode), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, FLAGS }, + { NULL } +}; + +static const AVClass class = { + .class_name = "liblc3 encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_liblc3_encoder = { + .p.name = "liblc3", + CODEC_LONG_NAME("LC3 (Low Complexity Communication Codec)"), + .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", + .priv_data_size = sizeof(LibLC3EncContext), + .init = liblc3_encode_init, + .close = liblc3_encode_close, + FF_CODEC_ENCODE_CB(liblc3_encode), +}; diff --git a/libavcodec/libmp3lame.c b/libavcodec/libmp3lame.c index d3810eb2a..42558178e 100644 --- a/libavcodec/libmp3lame.c +++ b/libavcodec/libmp3lame.c @@ -31,6 +31,7 @@ #include "libavutil/float_dsp.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "audio_frame_queue.h" diff --git a/libavcodec/libopencore-amr.c b/libavcodec/libopencore-amr.c index 641a15612..b127b3310 100644 --- a/libavcodec/libopencore-amr.c +++ b/libavcodec/libopencore-amr.c @@ -26,6 +26,7 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "audio_frame_queue.h" diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index eef769eed..7107c1a67 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -24,6 +24,7 @@ #include "libavutil/attributes.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -32,7 +33,6 @@ #include "avcodec.h" #include "codec_internal.h" #include "encode.h" -#include "internal.h" #include "libopenh264.h" #if !OPENH264_VER_AT_LEAST(1, 6) @@ -445,6 +445,7 @@ const FFCodec ff_libopenh264_encoder = { .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .defaults = svc_enc_defaults, .p.priv_class = &class, .p.wrapper_name = "libopenh264", diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c index 6a4364b1f..01b67dffd 100644 --- a/libavcodec/libopenjpegenc.c +++ b/libavcodec/libopenjpegenc.c @@ -785,6 +785,7 @@ const FFCodec ff_libopenjpeg_encoder = { AV_PIX_FMT_XYZ12, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &openjpeg_class, .p.wrapper_name = "libopenjpeg", }; diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c index af25f27f7..6b8b2cda0 100644 --- a/libavcodec/libopusenc.c +++ b/libavcodec/libopusenc.c @@ -23,6 +23,7 @@ #include #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/librav1e.c b/libavcodec/librav1e.c index 2a6d8bfbe..546d00297 100644 --- a/libavcodec/librav1e.c +++ b/libavcodec/librav1e.c @@ -28,6 +28,7 @@ #include "libavutil/base64.h" #include "libavutil/common.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avcodec.h" @@ -667,6 +668,7 @@ const FFCodec ff_librav1e_encoder = { .p.priv_class = &class, .defaults = librav1e_defaults, .p.pix_fmts = 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 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c index 4c12cef25..7b19db5a2 100644 --- a/libavcodec/libspeexenc.c +++ b/libavcodec/libspeexenc.c @@ -87,6 +87,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c index 8fa42d590..79b28eb4d 100644 --- a/libavcodec/libsvtav1.c +++ b/libavcodec/libsvtav1.c @@ -23,18 +23,20 @@ #include #include #include +#include #include "libavutil/common.h" #include "libavutil/frame.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "libavutil/mastering_display_metadata.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/avassert.h" #include "codec_internal.h" -#include "internal.h" +#include "dovi_rpu.h" #include "encode.h" #include "packet_internal.h" #include "avcodec.h" @@ -62,6 +64,8 @@ typedef struct SvtContext { EOS_STATUS eos_flag; + DOVIContext dovi; + // User options. AVDictionary *svtav1_opts; int enc_mode; @@ -206,7 +210,7 @@ static int config_enc_params(EbSvtAv1EncConfiguration *param, { SvtContext *svt_enc = avctx->priv_data; const AVPixFmtDescriptor *desc; - AVDictionaryEntry *en = NULL; + const AVDictionaryEntry av_unused *en = NULL; // Update param from options if (svt_enc->enc_mode >= -1) @@ -322,7 +326,7 @@ FF_ENABLE_DEPRECATION_WARNINGS handle_side_data(avctx, param); #if SVT_AV1_CHECK_VERSION(0, 9, 1) - while ((en = av_dict_get(svt_enc->svtav1_opts, "", en, AV_DICT_IGNORE_SUFFIX))) { + while ((en = av_dict_iterate(svt_enc->svtav1_opts, en))) { EbErrorType ret = svt_av1_enc_parse_parameter(param, en->key, en->value); if (ret != EB_ErrorNone) { int level = (avctx->err_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING; @@ -332,7 +336,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } } #else - if ((en = av_dict_get(svt_enc->svtav1_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { + if (av_dict_count(svt_enc->svtav1_opts)) { int level = (avctx->err_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING; av_log(avctx, level, "svt-params needs libavcodec to be compiled with SVT-AV1 " "headers >= 0.9.1.\n"); @@ -418,6 +422,7 @@ static int read_in_data(EbSvtAv1EncConfiguration *param, const AVFrame *frame, in_data->cr_stride = AV_CEIL_RSHIFT(frame->linesize[2], bytes_shift); header_ptr->n_filled_len = frame_size; + svt_metadata_array_free(&header_ptr->metadata); return 0; } @@ -451,6 +456,11 @@ static av_cold int eb_enc_init(AVCodecContext *avctx) return svt_print_error(avctx, svt_ret, "Error initializing encoder"); } + svt_enc->dovi.logctx = avctx; + ret = ff_dovi_configure(&svt_enc->dovi, avctx); + if (ret < 0) + return ret; + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { EbBufferHeaderType *headerPtr = NULL; @@ -486,6 +496,8 @@ static int eb_send_frame(AVCodecContext *avctx, const AVFrame *frame) { SvtContext *svt_enc = avctx->priv_data; EbBufferHeaderType *headerPtr = svt_enc->in_buf; + AVFrameSideData *sd; + EbErrorType svt_ret; int ret; if (!frame) { @@ -524,7 +536,28 @@ static int eb_send_frame(AVCodecContext *avctx, const AVFrame *frame) if (avctx->gop_size == 1) headerPtr->pic_type = EB_AV1_KEY_PICTURE; - svt_av1_enc_send_picture(svt_enc->svt_handle, headerPtr); + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOVI_METADATA); + if (svt_enc->dovi.cfg.dv_profile && sd) { + const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->data; + uint8_t *t35; + int size; + if ((ret = ff_dovi_rpu_generate(&svt_enc->dovi, metadata, FF_DOVI_WRAP_T35, + &t35, &size)) < 0) + return ret; + ret = svt_add_metadata(headerPtr, EB_AV1_METADATA_TYPE_ITUT_T35, t35, size); + av_free(t35); + if (ret < 0) + return AVERROR(ENOMEM); + } else if (svt_enc->dovi.cfg.dv_profile) { + av_log(avctx, AV_LOG_ERROR, "Dolby Vision enabled, but received frame " + "without AV_FRAME_DATA_DOVI_METADATA\n"); + return AVERROR_INVALIDDATA; + } + + + svt_ret = svt_av1_enc_send_picture(svt_enc->svt_handle, headerPtr); + if (svt_ret != EB_ErrorNone) + return svt_print_error(avctx, svt_ret, "Error sending a frame to encoder"); return 0; } @@ -579,6 +612,8 @@ static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt) svt_ret = svt_av1_enc_get_packet(svt_enc->svt_handle, &headerPtr, svt_enc->eos_flag); if (svt_ret == EB_NoErrorEmptyQueue) return AVERROR(EAGAIN); + else if (svt_ret != EB_ErrorNone) + return svt_print_error(avctx, svt_ret, "Error getting an output packet from encoder"); #if SVT_AV1_CHECK_VERSION(2, 0, 0) if (headerPtr->flags & EB_BUFFERFLAG_EOS) { @@ -644,11 +679,13 @@ static av_cold int eb_enc_close(AVCodecContext *avctx) } if (svt_enc->in_buf) { av_free(svt_enc->in_buf->p_buffer); + svt_metadata_array_free(&svt_enc->in_buf->metadata); av_freep(&svt_enc->in_buf); } av_buffer_pool_uninit(&svt_enc->pool); av_frame_free(&svt_enc->frame); + ff_dovi_ctx_unref(&svt_enc->dovi); return 0; } @@ -695,6 +732,9 @@ static const AVOption options[] = { AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 63, VE }, { "svtav1-params", "Set the SVT-AV1 configuration using a :-separated list of key=value parameters", OFFSET(svtav1_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, + { "dolbyvision", "Enable Dolby Vision RPU coding", OFFSET(dovi.enable), AV_OPT_TYPE_BOOL, {.i64 = FF_DOVI_AUTOMATIC }, -1, 1, VE, .unit = "dovi" }, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DOVI_AUTOMATIC}, .flags = VE, .unit = "dovi" }, + {NULL}, }; @@ -729,6 +769,7 @@ const FFCodec ff_libsvtav1_encoder = { .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = eb_enc_defaults, .p.wrapper_name = "libsvtav1", diff --git a/libavcodec/libtheoraenc.c b/libavcodec/libtheoraenc.c index 06eeaae00..8844f4be6 100644 --- a/libavcodec/libtheoraenc.c +++ b/libavcodec/libtheoraenc.c @@ -33,6 +33,7 @@ /* FFmpeg includes */ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/log.h" #include "libavutil/base64.h" @@ -390,5 +391,6 @@ const FFCodec ff_libtheora_encoder = { .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.wrapper_name = "libtheora", }; diff --git a/libavcodec/libvorbisenc.c b/libavcodec/libvorbisenc.c index 6331cf0d7..e4f8cb67e 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/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "audio_frame_queue.h" diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index b1aa1c85a..228ede7c8 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -33,8 +33,8 @@ #include "avcodec.h" #include "codec_internal.h" #include "encode.h" -#include "internal.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libvpx.h" #include "packet_internal.h" #include "profiles.h" @@ -49,6 +49,9 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" +#define IS_VP9(avctx) (CONFIG_LIBVPX_VP9_ENCODER && avctx->codec_id == AV_CODEC_ID_VP9) +#define IS_VP8(avctx) (CONFIG_LIBVPX_VP8_ENCODER && avctx->codec_id == AV_CODEC_ID_VP8) + /** * Portion of struct vpx_codec_cx_pkt from vpx_encoder.h. * One encoded frame returned from the library. @@ -357,21 +360,20 @@ static int frame_data_submit(AVCodecContext *avctx, AVFifo *fifo, const struct vpx_codec_enc_cfg *enccfg = ctx->encoder.config.enc; FrameData fd = { .pts = frame->pts }; - - AVFrameSideData *av_uninit(sd); int ret; -#if CONFIG_LIBVPX_VP9_ENCODER - // Keep HDR10+ if it has bit depth higher than 8 and - // it has PQ trc (SMPTE2084). - sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DYNAMIC_HDR_PLUS); - if (avctx->codec_id == AV_CODEC_ID_VP9 && sd && + if (IS_VP9(avctx) && + // Keep HDR10+ if it has bit depth higher than 8 and + // it has PQ trc (SMPTE2084). enccfg->g_bit_depth > 8 && avctx->color_trc == AVCOL_TRC_SMPTE2084) { - fd.hdr10_plus = av_buffer_ref(sd->buf); - if (!fd.hdr10_plus) - return AVERROR(ENOMEM); + const AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DYNAMIC_HDR_PLUS); + + if (sd) { + fd.hdr10_plus = av_buffer_ref(sd->buf); + if (!fd.hdr10_plus) + return AVERROR(ENOMEM); + } } -#endif fd.duration = frame->duration; fd.frame_opaque = frame->opaque; @@ -682,7 +684,7 @@ static int vpx_ts_param_parse(VPxContext *ctx, struct vpx_codec_enc_cfg *enccfg, vp8_ts_parse_int_array(enccfg->ts_layer_id, value, value_len, VPX_TS_MAX_PERIODICITY); } else if (!strcmp(key, "ts_layering_mode")) { /* option for pre-defined temporal structures in function set_temporal_layer_pattern. */ - ts_layering_mode = strtoul(value, &value, 4); + ts_layering_mode = strtoul(value, &value, 10); } #if (VPX_ENCODER_ABI_VERSION >= 12) && CONFIG_LIBVPX_VP9_ENCODER @@ -784,7 +786,7 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, struct vpx_codec_enc_cfg *enccfg, vpx_codec_flags_t *flags, vpx_img_fmt_t *img_fmt) { - VPxContext av_unused *ctx = avctx->priv_data; + VPxContext *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) { @@ -2043,6 +2045,7 @@ const FFCodec ff_libvpx_vp8_encoder = { 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 }, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class_vp8, .defaults = defaults, .p.wrapper_name = "libvpx", @@ -2085,13 +2088,25 @@ static const enum AVPixelFormat vp9_pix_fmts_highbd[] = { AV_PIX_FMT_NONE }; -static av_cold void vp9_init_static(FFCodec *codec) +static int vp9_get_supported_config(const AVCodecContext *avctx, + const AVCodec *codec, + enum AVCodecConfig config, + unsigned flags, const void **out, + int *out_num) { - vpx_codec_caps_t codec_caps = vpx_codec_get_caps(vpx_codec_vp9_cx()); - if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) - codec->p.pix_fmts = vp9_pix_fmts_highbd; - else - codec->p.pix_fmts = vp9_pix_fmts_highcol; + if (config == AV_CODEC_CONFIG_PIX_FORMAT) { + vpx_codec_caps_t codec_caps = vpx_codec_get_caps(vpx_codec_vp9_cx()); + if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { + *out = vp9_pix_fmts_highbd; + *out_num = FF_ARRAY_ELEMS(vp9_pix_fmts_highbd) - 1; + } else { + *out = vp9_pix_fmts_highcol; + *out_num = FF_ARRAY_ELEMS(vp9_pix_fmts_highcol) - 1; + } + return 0; + } + + return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num); } static const AVClass class_vp9 = { @@ -2114,12 +2129,13 @@ FFCodec ff_libvpx_vp9_encoder = { .p.wrapper_name = "libvpx", .priv_data_size = sizeof(VPxContext), .init = vp9_init, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, FF_CODEC_ENCODE_CB(vpx_encode), .close = vpx_free, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS, .defaults = defaults, - .init_static_data = vp9_init_static, + .get_supported_config = vp9_get_supported_config, }; #endif /* CONFIG_LIBVPX_VP9_ENCODER */ diff --git a/libavcodec/libvvenc.c b/libavcodec/libvvenc.c new file mode 100644 index 000000000..ece9badb1 --- /dev/null +++ b/libavcodec/libvvenc.c @@ -0,0 +1,491 @@ +/* + * H.266 encoding using the VVenC library + * + * Copyright (C) 2022, Thomas Siedel + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/avstring.h" +#include "libavutil/avutil.h" +#include "libavutil/common.h" +#include "libavutil/frame.h" +#include "libavutil/imgutils.h" +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "encode.h" +#include "internal.h" +#include "packet_internal.h" +#include "profiles.h" + +#define VVENC_VERSION_INT AV_VERSION_INT(VVENC_VERSION_MAJOR, \ + VVENC_VERSION_MINOR, \ + VVENC_VERSION_PATCH) + +typedef struct VVenCContext { + AVClass *class; + vvencEncoder *encoder; + vvencAccessUnit *au; + bool encode_done; + int preset; + int qp; + int qpa; + int intra_refresh_sec; + char *level; + int tier; + char *stats; + AVDictionary *vvenc_opts; +} VVenCContext; + +static void vvenc_log_callback(void *ctx, int level, + const char *fmt, va_list args) +{ + vvenc_config params; + vvencEncoder *encoder = ctx; + if (encoder) { + vvenc_config_default(¶ms); + vvenc_get_config(encoder, ¶ms); + if ((int)params.m_verbosity >= level) + vfprintf(level == 1 ? stderr : stdout, fmt, args); + } +} + +static void vvenc_set_verbository(vvenc_config *params) +{ + int loglevel = av_log_get_level(); + params->m_verbosity = VVENC_SILENT; + if (loglevel >= AV_LOG_DEBUG) + params->m_verbosity = VVENC_DETAILS; + else if (loglevel >= AV_LOG_VERBOSE) + params->m_verbosity = VVENC_NOTICE; + else if (loglevel >= AV_LOG_INFO) + params->m_verbosity = VVENC_WARNING; +} + +static void vvenc_set_pic_format(AVCodecContext *avctx, vvenc_config *params) +{ + params->m_internChromaFormat = VVENC_CHROMA_420; + params->m_inputBitDepth[0] = 10; +} + +static void vvenc_set_color_format(AVCodecContext *avctx, vvenc_config *params) +{ + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) + params->m_colourPrimaries = (int) avctx->color_primaries; + if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED) + params->m_matrixCoefficients = (int) avctx->colorspace; + if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED) { + params->m_transferCharacteristics = (int) avctx->color_trc; + + if (avctx->color_trc == AVCOL_TRC_SMPTE2084) + params->m_HdrMode = (avctx->color_primaries == AVCOL_PRI_BT2020) ? + VVENC_HDR_PQ_BT2020 : VVENC_HDR_PQ; + else if (avctx->color_trc == AVCOL_TRC_BT2020_10 || avctx->color_trc == AVCOL_TRC_ARIB_STD_B67) + params->m_HdrMode = (avctx->color_trc == AVCOL_TRC_BT2020_10 || + avctx->color_primaries == AVCOL_PRI_BT2020 || + avctx->colorspace == AVCOL_SPC_BT2020_NCL || + avctx->colorspace == AVCOL_SPC_BT2020_CL) ? + VVENC_HDR_HLG_BT2020 : VVENC_HDR_HLG; + } + + if (params->m_HdrMode == VVENC_HDR_OFF && + (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || avctx->colorspace != AVCOL_SPC_UNSPECIFIED)) { + params->m_vuiParametersPresent = 1; + params->m_colourDescriptionPresent = true; + } +} + +static void vvenc_set_framerate(AVCodecContext *avctx, vvenc_config *params) +{ + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + params->m_FrameRate = avctx->framerate.num; + params->m_FrameScale = avctx->framerate.den; + } else { + params->m_FrameRate = avctx->time_base.den; + 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 +} + +static int vvenc_parse_vvenc_params(AVCodecContext *avctx, vvenc_config *params) +{ + VVenCContext *s = avctx->priv_data; + const AVDictionaryEntry *en = NULL; + int parse_ret; + int ret = 0; + + while ((en = av_dict_iterate(s->vvenc_opts, en))) { + av_log(avctx, AV_LOG_DEBUG, "vvenc_set_param: '%s:%s'\n", en->key, + en->value); + parse_ret = vvenc_set_param(params, en->key, en->value); + switch (parse_ret) { + case VVENC_PARAM_BAD_NAME: + av_log(avctx, AV_LOG_ERROR, "Unknown vvenc option: %s.\n", en->key); + ret = AVERROR(EINVAL); + break; + case VVENC_PARAM_BAD_VALUE: + av_log(avctx, AV_LOG_ERROR, "Invalid vvenc value for %s: %s.\n", en->key, en->value); + ret = AVERROR(EINVAL); + break; + default: + break; + } + + if (!av_strcasecmp(en->key, "rcstatsfile")) { + av_log(avctx, AV_LOG_ERROR, "vvenc-params 2pass option 'rcstatsfile' " + "not available. Use option 'passlogfile'\n"); + ret = AVERROR(EINVAL); + } + if (!av_strcasecmp(en->key, "passes") || !av_strcasecmp(en->key, "pass")) { + av_log(avctx, AV_LOG_ERROR, "vvenc-params 2pass option '%s' " + "not available. Use option 'pass'\n", en->key); + ret = AVERROR(EINVAL); + } + } + return ret; +} + +static int vvenc_set_rc_mode(AVCodecContext *avctx, vvenc_config *params) +{ + params->m_RCNumPasses = 1; + if ((avctx->flags & AV_CODEC_FLAG_PASS1 || avctx->flags & AV_CODEC_FLAG_PASS2)) { + if (!avctx->bit_rate) { + av_log(avctx, AV_LOG_ERROR, "A bitrate must be set to use two pass mode.\n"); + return AVERROR(EINVAL); + } + params->m_RCNumPasses = 2; + if (avctx->flags & AV_CODEC_FLAG_PASS1) + params->m_RCPass = 1; + else + params->m_RCPass = 2; + } + + if (avctx->rc_max_rate) { +#if VVENC_VERSION_INT >= AV_VERSION_INT(1,8,0) + params->m_RCMaxBitrate = avctx->rc_max_rate; +#endif + +#if VVENC_VERSION_INT < AV_VERSION_INT(1,11,0) + /* rc_max_rate without a bit_rate enables capped CQF mode. + (QP + subj. optimization + max. bitrate) */ + if (!avctx->bit_rate) { + av_log(avctx, AV_LOG_ERROR, "Capped Constant Quality Factor mode (capped CQF) " + "needs at least vvenc version >= 1.11.0 (current version %s)\n", vvenc_get_version()); + return AVERROR(EINVAL); + } +#endif + } + return 0; +} + +static int vvenc_init_extradata(AVCodecContext *avctx, VVenCContext *s) +{ + int ret; + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { + ret = vvenc_get_headers(s->encoder, s->au); + if (0 != ret) { + av_log(avctx, AV_LOG_ERROR, "cannot get (SPS,PPS) headers: %s\n", + vvenc_get_last_error(s->encoder)); + return AVERROR(EINVAL); + } + + if (s->au->payloadUsedSize <= 0) { + return AVERROR_INVALIDDATA; + } + + avctx->extradata_size = s->au->payloadUsedSize; + avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + return AVERROR(ENOMEM); + } + + memcpy(avctx->extradata, s->au->payload, avctx->extradata_size); + } + return 0; +} + +static av_cold int vvenc_init(AVCodecContext *avctx) +{ + int ret; + int framerate; + VVenCContext *s = avctx->priv_data; + vvenc_config params; + vvencPresetMode preset = (vvencPresetMode) s->preset; + + if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) { + av_log(avctx, AV_LOG_ERROR, "interlaced not supported\n"); + return AVERROR(EINVAL); + } + + vvenc_config_default(¶ms); + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + framerate = avctx->framerate.num / avctx->framerate.den; + else + framerate = avctx->time_base.den / avctx->time_base.num; + + vvenc_init_default(¶ms, avctx->width, avctx->height, framerate, + avctx->bit_rate, s->qp, preset); + + vvenc_set_verbository(¶ms); + + if (avctx->thread_count > 0) + params.m_numThreads = avctx->thread_count; + + /* GOP settings (IDR/CRA) */ + if (avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) + params.m_DecodingRefreshType = VVENC_DRT_IDR; + + if (avctx->gop_size == 1) { + params.m_GOPSize = 1; + params.m_IntraPeriod = 1; + } else + params.m_IntraPeriodSec = s->intra_refresh_sec; + + params.m_AccessUnitDelimiter = true; + params.m_usePerceptQPA = s->qpa; + params.m_levelTier = (vvencTier) s->tier; + + if (avctx->level > 0) + params.m_level = (vvencLevel)avctx->level; + + if (s->level) { + if (VVENC_PARAM_BAD_VALUE == vvenc_set_param(¶ms, "level", s->level)) { + av_log(avctx, AV_LOG_ERROR, "Invalid level_idc: %s.\n", s->level); + return AVERROR(EINVAL); + } + } + + vvenc_set_framerate(avctx, ¶ms); + + vvenc_set_pic_format(avctx, ¶ms); + + vvenc_set_color_format(avctx, ¶ms); + + ret = vvenc_parse_vvenc_params(avctx, ¶ms); + if (ret != 0) + return ret; + + ret = vvenc_set_rc_mode(avctx, ¶ms); + if (ret != 0) + return ret; + + s->encoder = vvenc_encoder_create(); + if (!s->encoder) { + av_log(avctx, AV_LOG_ERROR, "cannot create libvvenc encoder\n"); + return AVERROR(ENOMEM); + } + + vvenc_set_msg_callback(¶ms, s->encoder, vvenc_log_callback); + ret = vvenc_encoder_open(s->encoder, ¶ms); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "cannot open libvvenc encoder: %s\n", + vvenc_get_last_error(s->encoder)); + return AVERROR_EXTERNAL; + } + + vvenc_get_config(s->encoder, ¶ms); /* get the adapted config */ + + av_log(avctx, AV_LOG_INFO, "libvvenc version: %s\n", vvenc_get_version()); + if (av_log_get_level() >= AV_LOG_VERBOSE) + av_log(avctx, AV_LOG_INFO, "%s\n", vvenc_get_config_as_string(¶ms, params.m_verbosity)); + + if (params.m_RCNumPasses == 2) { + ret = vvenc_init_pass(s->encoder, params.m_RCPass - 1, s->stats); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "cannot init pass %d: %s\n", params.m_RCPass, + vvenc_get_last_error(s->encoder)); + return AVERROR_EXTERNAL; + } + } + + s->au = vvenc_accessUnit_alloc(); + if (!s->au) { + av_log(avctx, AV_LOG_FATAL, "cannot allocate memory for AU payload\n"); + return AVERROR(ENOMEM); + } + vvenc_accessUnit_alloc_payload(s->au, avctx->width * avctx->height); + if (!s->au->payload) { + av_log(avctx, AV_LOG_FATAL, "cannot allocate payload memory of size %d\n", + avctx->width * avctx->height); + return AVERROR(ENOMEM); + } + + ret = vvenc_init_extradata(avctx, s); + if (ret != 0) + return ret; + + s->encode_done = false; + return 0; +} + +static av_cold int vvenc_close(AVCodecContext *avctx) +{ + VVenCContext *s = avctx->priv_data; + + if (s->au) + vvenc_accessUnit_free(s->au, true); + + if (s->encoder) { + vvenc_print_summary(s->encoder); + + if (0 != vvenc_encoder_close(s->encoder)) + return AVERROR_EXTERNAL; + } + + return 0; +} + +static av_cold int vvenc_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, + int *got_packet) +{ + VVenCContext *s = avctx->priv_data; + vvencYUVBuffer *pyuvbuf; + vvencYUVBuffer yuvbuf; + int ret; + + pyuvbuf = NULL; + if (frame) { + vvenc_YUVBuffer_default(&yuvbuf); + yuvbuf.planes[0].ptr = (int16_t *) frame->data[0]; + yuvbuf.planes[1].ptr = (int16_t *) frame->data[1]; + yuvbuf.planes[2].ptr = (int16_t *) frame->data[2]; + + yuvbuf.planes[0].width = frame->width; + yuvbuf.planes[0].height = frame->height; + yuvbuf.planes[0].stride = frame->linesize[0] >> 1; /* stride is used in 16bit samples in vvenc */ + + yuvbuf.planes[1].width = frame->width >> 1; + yuvbuf.planes[1].height = frame->height >> 1; + yuvbuf.planes[1].stride = frame->linesize[1] >> 1; + + yuvbuf.planes[2].width = frame->width >> 1; + yuvbuf.planes[2].height = frame->height >> 1; + yuvbuf.planes[2].stride = frame->linesize[2] >> 1; + + yuvbuf.cts = frame->pts; + yuvbuf.ctsValid = true; + pyuvbuf = &yuvbuf; + } + + if (!s->encode_done) { + if (vvenc_encode(s->encoder, pyuvbuf, s->au, &s->encode_done) != 0) + return AVERROR_EXTERNAL; + } else + return 0; + + if (s->au->payloadUsedSize > 0) { + ret = ff_get_encode_buffer(avctx, pkt, s->au->payloadUsedSize, 0); + if (ret < 0) + return ret; + + memcpy(pkt->data, s->au->payload, s->au->payloadUsedSize); + + if (s->au->ctsValid) + pkt->pts = s->au->cts; + if (s->au->dtsValid) + pkt->dts = s->au->dts; + pkt->flags |= AV_PKT_FLAG_KEY * s->au->rap; + + *got_packet = 1; + return 0; + } + + return 0; +} + +static const enum AVPixelFormat pix_fmts_vvenc[] = { + AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_NONE +}; + +#define OFFSET(x) offsetof(VVenCContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "preset", "set encoding preset", OFFSET(preset), AV_OPT_TYPE_INT, {.i64 = 2}, 0, 4, VE, "preset"}, + { "faster", "0", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_FASTER}, INT_MIN, INT_MAX, VE, "preset" }, + { "fast", "1", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_FAST}, INT_MIN, INT_MAX, VE, "preset" }, + { "medium", "2", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_MEDIUM}, INT_MIN, INT_MAX, VE, "preset" }, + { "slow", "3", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_SLOW}, INT_MIN, INT_MAX, VE, "preset" }, + { "slower", "4", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_SLOWER}, INT_MIN, INT_MAX, VE, "preset" }, + { "qp", "set quantization", OFFSET(qp), AV_OPT_TYPE_INT, {.i64 = 32}, -1, 63, VE }, + { "qpa", "set subjective (perceptually motivated) optimization", OFFSET(qpa), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, VE}, + { "passlogfile", "Filename for 2 pass stats", OFFSET(stats), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, VE}, + { "stats", "Filename for 2 pass stats", OFFSET(stats), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, VE}, + { "period", "set (intra) refresh period in seconds", OFFSET(intra_refresh_sec), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, VE }, + { "vvenc-params", "set the vvenc configuration using a :-separated list of key=value parameters", OFFSET(vvenc_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, + { "level", "Specify level (as defined by Annex A)", OFFSET(level), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, VE}, + { "tier", "set vvc tier", OFFSET(tier), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, VE, "tier"}, + { "main", "main", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, VE, "tier"}, + { "high", "high", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, VE, "tier"}, + {NULL} +}; + +static const AVClass class = { + .class_name = "libvvenc", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const FFCodecDefault vvenc_defaults[] = { + { "b", "0" }, + { "g", "-1" }, + { NULL }, +}; + +const FFCodec ff_libvvenc_encoder = { + .p.name = "libvvenc", + CODEC_LONG_NAME("libvvenc H.266 / VVC"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_VVC, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | + AV_CODEC_CAP_OTHER_THREADS, + .p.profiles = NULL_IF_CONFIG_SMALL(ff_vvc_profiles), + .p.priv_class = &class, + .p.wrapper_name = "libvvenc", + .priv_data_size = sizeof(VVenCContext), + .p.pix_fmts = pix_fmts_vvenc, + .init = vvenc_init, + FF_CODEC_ENCODE_CB(vvenc_frame), + .close = vvenc_close, + .defaults = vvenc_defaults, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS +}; diff --git a/libavcodec/libwebpenc.c b/libavcodec/libwebpenc.c index d6edd8660..670412cc6 100644 --- a/libavcodec/libwebpenc.c +++ b/libavcodec/libwebpenc.c @@ -24,6 +24,7 @@ * WebP encoder using libwebp (WebPEncode API) */ +#include "libavutil/mem.h" #include "codec_internal.h" #include "encode.h" #include "libwebpenc_common.h" @@ -94,6 +95,7 @@ const FFCodec ff_libwebp_encoder = { .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, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_libwebpenc_class, .p.wrapper_name = "libwebp", .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, diff --git a/libavcodec/libwebpenc_animencoder.c b/libavcodec/libwebpenc_animencoder.c index 02f0b6f64..c5361d7f9 100644 --- a/libavcodec/libwebpenc_animencoder.c +++ b/libavcodec/libwebpenc_animencoder.c @@ -25,8 +25,8 @@ */ #include "libavutil/buffer.h" +#include "libavutil/mem.h" -#include "config.h" #include "codec_internal.h" #include "encode.h" #include "libwebpenc_common.h" @@ -168,6 +168,7 @@ const FFCodec ff_libwebp_anim_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .p.pix_fmts = ff_libwebpenc_pix_fmts, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_libwebpenc_class, .p.wrapper_name = "libwebp", .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, diff --git a/libavcodec/libwebpenc_common.c b/libavcodec/libwebpenc_common.c index 5645d1172..80040ea9e 100644 --- a/libavcodec/libwebpenc_common.c +++ b/libavcodec/libwebpenc_common.c @@ -24,6 +24,7 @@ * WebP encoder using libwebp: common structs and methods. */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libwebpenc_common.h" diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c index 813ccbbdb..409f45fc7 100644 --- a/libavcodec/libx264.c +++ b/libavcodec/libx264.c @@ -270,11 +270,9 @@ static void reconfig_encoder(AVCodecContext *ctx, const AVFrame *frame) case AV_STEREO3D_FRAMESEQUENCE: fpa_type = 5; break; -#if X264_BUILD >= 145 case AV_STEREO3D_2D: fpa_type = 6; break; -#endif default: fpa_type = -1; break; @@ -394,14 +392,14 @@ static int setup_mb_info(AVCodecContext *ctx, x264_picture_t *pic, return 0; } -static int setup_roi(AVCodecContext *ctx, x264_picture_t *pic, int bit_depth, +static int setup_roi(AVCodecContext *ctx, x264_picture_t *pic, const AVFrame *frame, const uint8_t *data, size_t size) { X264Context *x4 = ctx->priv_data; int mbx = (frame->width + MB_SIZE - 1) / MB_SIZE; int mby = (frame->height + MB_SIZE - 1) / MB_SIZE; - int qp_range = 51 + 6 * (bit_depth - 8); + int qp_range = 51 + 6 * (x4->params.i_bitdepth - 8); int nb_rois; const AVRegionOfInterest *roi; uint32_t roi_size; @@ -476,7 +474,7 @@ static int setup_frame(AVCodecContext *ctx, const AVFrame *frame, x264_sei_t *sei = &pic->extra_sei; unsigned int sei_data_size = 0; int64_t wallclock = 0; - int bit_depth, ret; + int ret; AVFrameSideData *sd; AVFrameSideData *mbinfo_sd; @@ -486,12 +484,7 @@ static int setup_frame(AVCodecContext *ctx, const AVFrame *frame, x264_picture_init(pic); pic->img.i_csp = x4->params.i_csp; -#if X264_BUILD >= 153 - bit_depth = x4->params.i_bitdepth; -#else - bit_depth = x264_bit_depth; -#endif - if (bit_depth > 8) + if (x4->params.i_bitdepth > 8) pic->img.i_csp |= X264_CSP_HIGH_DEPTH; pic->img.i_plane = av_pix_fmt_count_planes(ctx->pix_fmt); @@ -564,19 +557,19 @@ static int setup_frame(AVCodecContext *ctx, const AVFrame *frame, sd = av_frame_get_side_data(frame, AV_FRAME_DATA_REGIONS_OF_INTEREST); if (sd) { - ret = setup_roi(ctx, pic, bit_depth, frame, sd->data, sd->size); + ret = setup_roi(ctx, pic, frame, sd->data, sd->size); if (ret < 0) goto fail; } mbinfo_sd = av_frame_get_side_data(frame, AV_FRAME_DATA_VIDEO_HINT); if (mbinfo_sd) { - int ret = setup_mb_info(ctx, pic, frame, (const AVVideoHint *)mbinfo_sd->data); - if (ret < 0) { + int err = setup_mb_info(ctx, pic, frame, (const AVVideoHint *)mbinfo_sd->data); + if (err < 0) { /* No need to fail here, this is not fatal. We just proceed with no * mb_info and log a message */ - av_log(ctx, AV_LOG_WARNING, "setup_mb_info failed with error: %s\n", av_err2str(ret)); + av_log(ctx, AV_LOG_WARNING, "setup_mb_info failed with error: %s\n", av_err2str(err)); } } @@ -732,7 +725,7 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, /* SSE = MSE * width * height / scale -> because of possible chroma downsampling */ sse[i] = (int64_t)floor(mse * plane_size + .5); - }; + } errors = sse; } @@ -1111,9 +1104,7 @@ static av_cold int X264_init(AVCodecContext *avctx) x4->params.p_log_private = avctx; x4->params.i_log_level = X264_LOG_DEBUG; x4->params.i_csp = convert_pix_fmt(avctx->pix_fmt); -#if X264_BUILD >= 153 x4->params.i_bitdepth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth; -#endif PARSE_X264_OPT("weightp", wpredp); @@ -1182,11 +1173,10 @@ static av_cold int X264_init(AVCodecContext *avctx) else if (x4->params.i_level_idc > 0) { int i; int mbn = AV_CEIL_RSHIFT(avctx->width, 4) * AV_CEIL_RSHIFT(avctx->height, 4); - int scale = X264_BUILD < 129 ? 384 : 1; for (i = 0; iparams.i_level_idc) - x4->params.i_frame_reference = av_clip(x264_levels[i].dpb / mbn / scale, 1, x4->params.i_frame_reference); + x4->params.i_frame_reference = av_clip(x264_levels[i].dpb / mbn, 1, x4->params.i_frame_reference); } if (avctx->trellis >= 0) @@ -1230,12 +1220,7 @@ static av_cold int X264_init(AVCodecContext *avctx) x4->params.b_vfr_input = 0; } if (x4->avcintra_class >= 0) -#if X264_BUILD >= 142 x4->params.i_avcintra_class = x4->avcintra_class; -#else - av_log(avctx, AV_LOG_ERROR, - "x264 too old for AVC Intra, at least version 142 needed\n"); -#endif if (x4->avcintra_class > 200) { #if X264_BUILD < 164 @@ -1397,15 +1382,13 @@ FF_ENABLE_DEPRECATION_WARNINGS } } -#if X264_BUILD >= 142 /* Separate headers not supported in AVC-Intra mode */ if (x4->avcintra_class >= 0) x4->params.b_repeat_headers = 1; -#endif { - AVDictionaryEntry *en = NULL; - while (en = av_dict_get(x4->x264_params, "", en, AV_DICT_IGNORE_SUFFIX)) { + const AVDictionaryEntry *en = NULL; + while (en = av_dict_iterate(x4->x264_params, en)) { if ((ret = x264_param_parse(&x4->params, en->key, en->value)) < 0) { av_log(avctx, AV_LOG_WARNING, "Error parsing option '%s = %s'.\n", @@ -1515,18 +1498,6 @@ static const enum AVPixelFormat pix_fmts_8bit_rgb[] = { }; #endif -#if X264_BUILD < 153 -static av_cold void X264_init_static(FFCodec *codec) -{ - if (x264_bit_depth == 8) - codec->p.pix_fmts = pix_fmts_8bit; - else if (x264_bit_depth == 9) - codec->p.pix_fmts = pix_fmts_9bit; - else if (x264_bit_depth == 10) - codec->p.pix_fmts = pix_fmts_10bit; -} -#endif - #define OFFSET(x) offsetof(X264Context, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { @@ -1546,9 +1517,7 @@ static const AVOption options[] = { { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = X264_AQ_NONE}, INT_MIN, INT_MAX, VE, .unit = "aq_mode" }, { "variance", "Variance AQ (complexity mask)", 0, AV_OPT_TYPE_CONST, {.i64 = X264_AQ_VARIANCE}, INT_MIN, INT_MAX, VE, .unit = "aq_mode" }, { "autovariance", "Auto-variance AQ", 0, AV_OPT_TYPE_CONST, {.i64 = X264_AQ_AUTOVARIANCE}, INT_MIN, INT_MAX, VE, .unit = "aq_mode" }, -#if X264_BUILD >= 144 { "autovariance-biased", "Auto-variance AQ with bias to dark scenes", 0, AV_OPT_TYPE_CONST, {.i64 = X264_AQ_AUTOVARIANCE_BIASED}, INT_MIN, INT_MAX, VE, .unit = "aq_mode" }, -#endif { "aq-strength", "AQ strength. Reduces blocking and blurring in flat and textured areas.", OFFSET(aq_strength), AV_OPT_TYPE_FLOAT, {.dbl = -1}, -1, FLT_MAX, VE}, { "psy", "Use psychovisual optimizations.", OFFSET(psy), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, { "psy-rd", "Strength of psychovisual optimization, in : format.", OFFSET(psy_rd), AV_OPT_TYPE_STRING, {0 }, 0, 0, VE}, @@ -1646,10 +1615,7 @@ static const AVClass x264_class = { .version = LIBAVUTIL_VERSION_INT, }; -#if X264_BUILD >= 153 -const -#endif -FFCodec ff_libx264_encoder = { +const FFCodec ff_libx264_encoder = { .p.name = "libx264", CODEC_LONG_NAME("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"), .p.type = AVMEDIA_TYPE_VIDEO, @@ -1667,11 +1633,8 @@ FFCodec ff_libx264_encoder = { .flush = X264_flush, .close = X264_close, .defaults = x264_defaults, -#if X264_BUILD < 153 - .init_static_data = X264_init_static, -#else .p.pix_fmts = pix_fmts_all, -#endif + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS #if X264_BUILD < 158 | FF_CODEC_CAP_NOT_INIT_THREADSAFE @@ -1729,6 +1692,7 @@ const FFCodec ff_libx262_encoder = { AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .p.pix_fmts = pix_fmts_8bit, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &X262_class, .p.wrapper_name = "libx264", .priv_data_size = sizeof(X264Context), diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c index d3e74eaac..63cc497f8 100644 --- a/libavcodec/libx265.c +++ b/libavcodec/libx265.c @@ -31,10 +31,12 @@ #include "libavutil/buffer.h" #include "libavutil/internal.h" #include "libavutil/mastering_display_metadata.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avcodec.h" #include "codec_internal.h" +#include "dovi_rpu.h" #include "encode.h" #include "packet_internal.h" #include "atsc_a53.h" @@ -77,6 +79,8 @@ typedef struct libx265Context { * encounter a frame with ROI side data. */ int roi_warned; + + DOVIContext dovi; } libx265Context; static int is_keyframe(NalUnitType naltype) @@ -142,6 +146,8 @@ static av_cold int libx265_encode_close(AVCodecContext *avctx) if (ctx->encoder) ctx->api->encoder_close(ctx->encoder); + ff_dovi_ctx_unref(&ctx->dovi); + return 0; } @@ -315,12 +321,9 @@ FF_ENABLE_DEPRECATION_WARNINGS avctx->pix_fmt == AV_PIX_FMT_YUVJ422P || avctx->pix_fmt == AV_PIX_FMT_YUVJ444P; - if ((avctx->color_primaries <= AVCOL_PRI_SMPTE432 && - avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) || - (avctx->color_trc <= AVCOL_TRC_ARIB_STD_B67 && - avctx->color_trc != AVCOL_TRC_UNSPECIFIED) || - (avctx->colorspace <= AVCOL_SPC_ICTCP && - avctx->colorspace != AVCOL_SPC_UNSPECIFIED)) { + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { ctx->params->vui.bEnableColorDescriptionPresentFlag = 1; @@ -492,8 +495,8 @@ FF_ENABLE_DEPRECATION_WARNINGS } { - AVDictionaryEntry *en = NULL; - while ((en = av_dict_get(ctx->x265_opts, "", en, AV_DICT_IGNORE_SUFFIX))) { + 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); switch (parse_ret) { @@ -528,6 +531,14 @@ FF_ENABLE_DEPRECATION_WARNINGS } } +#if X265_BUILD >= 167 + ctx->dovi.logctx = avctx; + if ((ret = ff_dovi_configure(&ctx->dovi, avctx)) < 0) + return ret; + ctx->params->dolbyProfile = ctx->dovi.cfg.dv_profile * 10 + + ctx->dovi.cfg.dv_bl_signal_compatibility_id; +#endif + ctx->encoder = ctx->api->encoder_open(ctx->params); if (!ctx->encoder) { av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n"); @@ -631,6 +642,10 @@ static void free_picture(libx265Context *ctx, x265_picture *pic) for (int i = 0; i < sei->numPayloads; i++) av_free(sei->payloads[i].payload); +#if X265_BUILD >= 167 + av_free(pic->rpu.payload); +#endif + if (pic->userData) { int idx = (int)(intptr_t)pic->userData - 1; rd_release(ctx, idx); @@ -646,7 +661,13 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, { libx265Context *ctx = avctx->priv_data; x265_picture x265pic; - x265_picture x265pic_out = { 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 }; +#endif + x265_picture* x265pic_out; x265_nal *nal; x265_sei *sei; uint8_t *dst; @@ -662,6 +683,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, sei->numPayloads = 0; if (pic) { + AVFrameSideData *sd; ReorderedData *rd; int rd_idx; @@ -762,10 +784,37 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, sei->numPayloads++; } } + +#if X265_BUILD >= 167 + sd = av_frame_get_side_data(pic, AV_FRAME_DATA_DOVI_METADATA); + if (ctx->dovi.cfg.dv_profile && sd) { + const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->data; + ret = ff_dovi_rpu_generate(&ctx->dovi, metadata, FF_DOVI_WRAP_NAL, + &x265pic.rpu.payload, + &x265pic.rpu.payloadSize); + if (ret < 0) { + free_picture(ctx, &x265pic); + return ret; + } + } else if (ctx->dovi.cfg.dv_profile) { + av_log(avctx, AV_LOG_ERROR, "Dolby Vision enabled, but received frame " + "without AV_FRAME_DATA_DOVI_METADATA"); + free_picture(ctx, &x265pic); + return AVERROR_INVALIDDATA; + } +#endif } +#if (X265_BUILD >= 210) && (X265_BUILD < 213) + for (i = 0; i < MAX_SCALABLE_LAYERS; i++) + x265pic_lyrptr_out[i] = &x265pic_layers_out[i]; + ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal, - pic ? &x265pic : NULL, &x265pic_out); + pic ? &x265pic : NULL, x265pic_lyrptr_out); +#else + ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal, + pic ? &x265pic : NULL, &x265pic_solo_out); +#endif for (i = 0; i < sei->numPayloads; i++) av_free(sei->payloads[i].payload); @@ -795,10 +844,16 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, pkt->flags |= AV_PKT_FLAG_KEY; } - pkt->pts = x265pic_out.pts; - pkt->dts = x265pic_out.dts; +#if (X265_BUILD >= 210) && (X265_BUILD < 213) + x265pic_out = x265pic_lyrptr_out[0]; +#else + x265pic_out = &x265pic_solo_out; +#endif - switch (x265pic_out.sliceType) { + pkt->pts = x265pic_out->pts; + pkt->dts = x265pic_out->dts; + + switch (x265pic_out->sliceType) { case X265_TYPE_IDR: case X265_TYPE_I: pict_type = AV_PICTURE_TYPE_I; @@ -816,16 +871,16 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } #if X265_BUILD >= 130 - if (x265pic_out.sliceType == X265_TYPE_B) + if (x265pic_out->sliceType == X265_TYPE_B) #else - if (x265pic_out.frameData.sliceType == 'b') + if (x265pic_out->frameData.sliceType == 'b') #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_side_data_set_encoder_stats(pkt, x265pic_out->frameData.qp * FF_QP2LAMBDA, NULL, 0, pict_type); - if (x265pic_out.userData) { - int idx = (int)(intptr_t)x265pic_out.userData - 1; + if (x265pic_out->userData) { + int idx = (int)(intptr_t)x265pic_out->userData - 1; ReorderedData *rd = &ctx->rd[idx]; pkt->duration = rd->duration; @@ -894,14 +949,28 @@ static const enum AVPixelFormat x265_csp_twelve[] = { AV_PIX_FMT_NONE }; -static av_cold void libx265_encode_init_csp(FFCodec *codec) +static int libx265_get_supported_config(const AVCodecContext *avctx, + const AVCodec *codec, + enum AVCodecConfig config, + unsigned flags, const void **out, + int *out_num) { - if (x265_api_get(12)) - codec->p.pix_fmts = x265_csp_twelve; - else if (x265_api_get(10)) - codec->p.pix_fmts = x265_csp_ten; - else if (x265_api_get(8)) - codec->p.pix_fmts = x265_csp_eight; + if (config == AV_CODEC_CONFIG_PIX_FORMAT) { + if (x265_api_get(12)) { + *out = x265_csp_twelve; + *out_num = FF_ARRAY_ELEMS(x265_csp_twelve) - 1; + } else if (x265_api_get(10)) { + *out = x265_csp_ten; + *out_num = FF_ARRAY_ELEMS(x265_csp_ten) - 1; + } else if (x265_api_get(8)) { + *out = x265_csp_eight; + *out_num = FF_ARRAY_ELEMS(x265_csp_eight) - 1; + } else + return AVERROR_EXTERNAL; + return 0; + } + + return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num); } #define OFFSET(x) offsetof(libx265Context, x) @@ -914,8 +983,12 @@ static const AVOption options[] = { { "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 }, { "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 = 1 }, 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 }, +#if X265_BUILD >= 167 + { "dolbyvision", "Enable Dolby Vision RPU coding", OFFSET(dovi.enable), AV_OPT_TYPE_BOOL, {.i64 = FF_DOVI_AUTOMATIC }, -1, 1, VE, .unit = "dovi" }, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DOVI_AUTOMATIC}, .flags = VE, .unit = "dovi" }, +#endif { NULL } }; @@ -950,10 +1023,11 @@ FFCodec ff_libx265_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .p.wrapper_name = "libx265", .init = libx265_encode_init, - .init_static_data = libx265_encode_init_csp, + .get_supported_config = libx265_get_supported_config, FF_CODEC_ENCODE_CB(libx265_encode_frame), .close = libx265_encode_close, .priv_data_size = sizeof(libx265Context), diff --git a/libavcodec/libxavs.c b/libavcodec/libxavs.c index 4c7b1908c..d0f6e141c 100644 --- a/libavcodec/libxavs.c +++ b/libavcodec/libxavs.c @@ -435,6 +435,7 @@ const FFCodec ff_libxavs_encoder = { .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 }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &xavs_class, .defaults = xavs_defaults, .p.wrapper_name = "libxavs", diff --git a/libavcodec/libxavs2.c b/libavcodec/libxavs2.c index c493ddc32..1021d2ae2 100644 --- a/libavcodec/libxavs2.c +++ b/libavcodec/libxavs2.c @@ -301,6 +301,7 @@ const FFCodec ff_libxavs2_encoder = { FF_CODEC_CAP_AUTO_THREADS, .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &libxavs2, .defaults = xavs2_defaults, .p.wrapper_name = "libxavs2", diff --git a/libavcodec/libxevd.c b/libavcodec/libxevd.c index c6c7327e6..520fdab7d 100644 --- a/libavcodec/libxevd.c +++ b/libavcodec/libxevd.c @@ -170,14 +170,12 @@ static int export_stream_params(const XevdContext *xectx, AVCodecContext *avctx) } // the function returns sps->num_reorder_pics - ret = xevd_config(xectx->id, XEVD_CFG_GET_MAX_CODING_DELAY, &avctx->max_b_frames, &size); + ret = xevd_config(xectx->id, XEVD_CFG_GET_MAX_CODING_DELAY, &avctx->has_b_frames, &size); if (XEVD_FAILED(ret)) { av_log(avctx, AV_LOG_ERROR, "Failed to get max_coding_delay\n"); return AVERROR_EXTERNAL; } - avctx->has_b_frames = (avctx->max_b_frames) ? 1 : 0; - return 0; } @@ -415,6 +413,10 @@ static int libxevd_receive_frame(AVCodecContext *avctx, AVFrame *frame) return AVERROR(EAGAIN); } } else { + if (stat.stype == XEVD_ST_I) { + frame->pict_type = AV_PICTURE_TYPE_I; + frame->flags |= AV_FRAME_FLAG_KEY; + } return libxevd_return_frame(avctx, frame, imgb, &pkt_au); } } diff --git a/libavcodec/libxeve.c b/libavcodec/libxeve.c index c923ac1ca..61376f3e6 100644 --- a/libavcodec/libxeve.c +++ b/libavcodec/libxeve.c @@ -28,6 +28,7 @@ #include "libavutil/internal.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" @@ -196,7 +197,8 @@ static int get_conf(AVCodecContext *avctx, XEVE_CDSC *cdsc) if (avctx->framerate.num > 0) { // fps can be float number, but xeve API doesn't support it - cdsc->param.fps = lrintf(av_q2d(avctx->framerate)); + cdsc->param.fps.num = avctx->framerate.num; + cdsc->param.fps.den = avctx->framerate.den; } // GOP size (key-frame interval, I-picture period) @@ -480,8 +482,8 @@ static int libxeve_encode(AVCodecContext *avctx, AVPacket *avpkt, memcpy(avpkt->data, xectx->bitb.addr, xectx->stat.write); - avpkt->time_base.num = 1; - avpkt->time_base.den = xectx->cdsc.param.fps; + avpkt->time_base.num = xectx->cdsc.param.fps.den; + avpkt->time_base.den = xectx->cdsc.param.fps.num; avpkt->pts = xectx->bitb.ts[XEVE_TS_PTS]; avpkt->dts = xectx->bitb.ts[XEVE_TS_DTS]; @@ -612,5 +614,6 @@ const FFCodec ff_libxeve_encoder = { .p.profiles = NULL_IF_CONFIG_SMALL(ff_evc_profiles), .p.wrapper_name = "libxeve", .p.pix_fmts = 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 b9ac39429..fbd33b706 100644 --- a/libavcodec/libxvid.c +++ b/libavcodec/libxvid.c @@ -422,13 +422,13 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) /* Decide how we should decide blocks */ switch (avctx->mb_decision) { - case 2: + case FF_MB_DECISION_RD: x->vop_flags |= XVID_VOP_MODEDECISION_RD; x->me_flags |= XVID_ME_HALFPELREFINE8_RD | XVID_ME_QUARTERPELREFINE8_RD | XVID_ME_EXTSEARCH_RD | XVID_ME_CHECKPREDICTION_RD; - case 1: + case FF_MB_DECISION_BITS: if (!(x->vop_flags & XVID_VOP_MODEDECISION_RD)) x->vop_flags |= XVID_VOP_FAST_MODEDECISION_RD; x->me_flags |= XVID_ME_HALFPELREFINE16_RD | @@ -908,6 +908,7 @@ const FFCodec ff_libxvid_encoder = { 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 }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &xvid_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.wrapper_name = "libxvid", diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c index c2cbb0a42..68ffe1f76 100644 --- a/libavcodec/libzvbi-teletextdec.c +++ b/libavcodec/libzvbi-teletextdec.c @@ -22,10 +22,10 @@ #include "libavcodec/ass.h" #include "codec_internal.h" #include "libavcodec/dvbtxt.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/bprint.h" #include "libavutil/internal.h" -#include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/common.h" diff --git a/libavcodec/ljpegenc.c b/libavcodec/ljpegenc.c index 46546e216..927420c2d 100644 --- a/libavcodec/ljpegenc.c +++ b/libavcodec/ljpegenc.c @@ -328,4 +328,5 @@ const FFCodec ff_ljpeg_encoder = { 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}, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, }; diff --git a/libavcodec/loco.c b/libavcodec/loco.c index 8cc270acb..d73d8fa88 100644 --- a/libavcodec/loco.c +++ b/libavcodec/loco.c @@ -213,7 +213,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->flags |= AV_FRAME_FLAG_KEY; #define ADVANCE_BY_DECODED do { \ if (decoded < 0 || decoded >= buf_size) goto buf_too_small; \ diff --git a/libavcodec/loongarch/Makefile b/libavcodec/loongarch/Makefile index 07da2964e..92c8b3590 100644 --- a/libavcodec/loongarch/Makefile +++ b/libavcodec/loongarch/Makefile @@ -12,7 +12,7 @@ OBJS-$(CONFIG_HEVC_DECODER) += loongarch/hevcdsp_init_loongarch.o LASX-OBJS-$(CONFIG_H264QPEL) += loongarch/h264qpel_lasx.o LASX-OBJS-$(CONFIG_H264DSP) += loongarch/h264dsp_lasx.o \ loongarch/h264_deblock_lasx.o -LASX-OBJS-$(CONFIG_VC1_DECODER) += loongarch/vc1dsp_lasx.o +LASX-OBJS-$(CONFIG_VC1DSP) += loongarch/vc1dsp_lasx.o LASX-OBJS-$(CONFIG_HPELDSP) += loongarch/hpeldsp_lasx.o LASX-OBJS-$(CONFIG_IDCTDSP) += loongarch/simple_idct_lasx.o \ loongarch/idctdsp_lasx.o diff --git a/libavcodec/loongarch/hevcdsp_lasx.h b/libavcodec/loongarch/hevcdsp_lasx.h index 714cbf588..907ee9f4b 100644 --- a/libavcodec/loongarch/hevcdsp_lasx.h +++ b/libavcodec/loongarch/hevcdsp_lasx.h @@ -22,7 +22,7 @@ #ifndef AVCODEC_LOONGARCH_HEVCDSP_LASX_H #define AVCODEC_LOONGARCH_HEVCDSP_LASX_H -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #define PEL_UNI_W(PEL, DIR, WIDTH) \ void ff_hevc_put_hevc_##PEL##_uni_w_##DIR##WIDTH##_8_lasx(uint8_t *dst, \ diff --git a/libavcodec/loongarch/hevcdsp_lsx.h b/libavcodec/loongarch/hevcdsp_lsx.h index a5ef237b5..cf2a519e9 100644 --- a/libavcodec/loongarch/hevcdsp_lsx.h +++ b/libavcodec/loongarch/hevcdsp_lsx.h @@ -23,7 +23,7 @@ #ifndef AVCODEC_LOONGARCH_HEVCDSP_LSX_H #define AVCODEC_LOONGARCH_HEVCDSP_LSX_H -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #define MC(PEL, DIR, WIDTH) \ void ff_hevc_put_hevc_##PEL##_##DIR##WIDTH##_8_lsx(int16_t *dst, \ diff --git a/libavcodec/lpc.c b/libavcodec/lpc.c index 88ab37e76..e793e5403 100644 --- a/libavcodec/lpc.c +++ b/libavcodec/lpc.c @@ -21,6 +21,7 @@ #include "libavutil/common.h" #include "libavutil/lls.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #define LPC_USE_DOUBLE @@ -119,9 +120,8 @@ static void lpc_compute_autocorr_c(const double *data, ptrdiff_t len, int lag, if(j==lag){ double sum = 1.0; - for(i=j-1; ipict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; if ((avctx->extradata[3*4] & 3) != 3) { frame->flags |= AV_FRAME_FLAG_INTERLACED; if (avctx->extradata[3*4] & 1) diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c index 4f3049362..b85505c42 100644 --- a/libavcodec/magicyuv.c +++ b/libavcodec/magicyuv.c @@ -24,6 +24,7 @@ #define CACHED_BITSTREAM_READER !ARCH_X86_32 +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "avcodec.h" @@ -651,9 +652,6 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p, if (ret < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; - if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0) return ret; diff --git a/libavcodec/magicyuvenc.c b/libavcodec/magicyuvenc.c index 1c3ab5646..3364207f8 100644 --- a/libavcodec/magicyuvenc.c +++ b/libavcodec/magicyuvenc.c @@ -23,6 +23,7 @@ #include #include "libavutil/cpu.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/qsort.h" @@ -32,7 +33,6 @@ #include "codec_internal.h" #include "encode.h" #include "put_bits.h" -#include "thread.h" #include "lossless_videoencdsp.h" #define MAGICYUV_EXTRADATA_SIZE 32 @@ -211,10 +211,13 @@ static av_cold int magy_encode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); if (s->correlate) { - s->decorrelate_buf[0] = av_calloc(2U * (s->nb_slices * s->slice_height), FFALIGN(avctx->width, av_cpu_max_align())); + size_t max_align = av_cpu_max_align(); + size_t aligned_width = FFALIGN(avctx->width, max_align); + s->decorrelate_buf[0] = av_calloc(2U * (s->nb_slices * s->slice_height), + aligned_width); if (!s->decorrelate_buf[0]) return AVERROR(ENOMEM); - s->decorrelate_buf[1] = s->decorrelate_buf[0] + (s->nb_slices * s->slice_height) * FFALIGN(avctx->width, av_cpu_max_align()); + 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; @@ -375,11 +378,14 @@ static int count_plane_slice(AVCodecContext *avctx, int n, int plane) 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; memset(counts, 0, sizeof(sl->counts)); count_usage(dst, AV_CEIL_RSHIFT(avctx->width, s->hshift[plane]), - AV_CEIL_RSHIFT(s->slice_height, s->vshift[plane]), counts); + AV_CEIL_RSHIFT(height, s->vshift[plane]), counts); return 0; } @@ -493,7 +499,8 @@ static int encode_slice(AVCodecContext *avctx, void *tdata, static int predict_slice(AVCodecContext *avctx, void *tdata, int n, int threadnr) { - const int aligned_width = FFALIGN(avctx->width, av_cpu_max_align()); + size_t max_align = av_cpu_max_align(); + const int aligned_width = FFALIGN(avctx->width, max_align); MagicYUVContext *s = avctx->priv_data; const int slice_height = s->slice_height; const int last_height = FFMIN(slice_height, avctx->height - n * slice_height); @@ -689,5 +696,6 @@ const FFCodec ff_magicyuv_encoder = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }, + .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 a1dc32330..84a924f31 100644 --- a/libavcodec/mathops.h +++ b/libavcodec/mathops.h @@ -39,8 +39,6 @@ extern const uint8_t ff_zigzag_scan[16+1]; #if ARCH_ARM # include "arm/mathops.h" -#elif ARCH_AVR32 -# include "avr32/mathops.h" #elif ARCH_MIPS # include "mips/mathops.h" #elif ARCH_PPC diff --git a/libavcodec/mdec.c b/libavcodec/mdec.c index c4904216b..5ab40719a 100644 --- a/libavcodec/mdec.c +++ b/libavcodec/mdec.c @@ -27,6 +27,7 @@ * This is very similar to intra-only MPEG-1. */ +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" @@ -176,8 +177,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if ((ret = ff_thread_get_buffer(avctx, frame, 0)) < 0) return ret; - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; av_fast_padded_malloc(&a->bitstream_buffer, &a->bitstream_buffer_size, buf_size); if (!a->bitstream_buffer) diff --git a/libavcodec/me_cmp.c b/libavcodec/me_cmp.c index db3fb1260..f3e2f2482 100644 --- a/libavcodec/me_cmp.c +++ b/libavcodec/me_cmp.c @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/attributes.h" #include "libavutil/internal.h" #include "libavutil/mem_internal.h" @@ -473,74 +475,60 @@ static int zero_cmp(MpegEncContext *s, const uint8_t *a, const uint8_t *b, return 0; } -int ff_set_cmp(MECmpContext *c, me_cmp_func *cmp, int type) +av_cold int ff_set_cmp(const MECmpContext *c, me_cmp_func *cmp, int type, int mpvenc) { - int ret = 0; - int i; - - memset(cmp, 0, sizeof(void *) * 6); - - for (i = 0; i < 6; i++) { - switch (type & 0xFF) { - case FF_CMP_SAD: - cmp[i] = c->sad[i]; - break; - case FF_CMP_MEDIAN_SAD: - cmp[i] = c->median_sad[i]; - break; - case FF_CMP_SATD: - cmp[i] = c->hadamard8_diff[i]; - break; - case FF_CMP_SSE: - cmp[i] = c->sse[i]; - break; - case FF_CMP_DCT: - cmp[i] = c->dct_sad[i]; - break; - case FF_CMP_DCT264: - cmp[i] = c->dct264_sad[i]; - break; - case FF_CMP_DCTMAX: - cmp[i] = c->dct_max[i]; - break; - case FF_CMP_PSNR: - cmp[i] = c->quant_psnr[i]; - break; - case FF_CMP_BIT: - cmp[i] = c->bit[i]; - break; - case FF_CMP_RD: - cmp[i] = c->rd[i]; - break; - case FF_CMP_VSAD: - cmp[i] = c->vsad[i]; - break; - case FF_CMP_VSSE: - cmp[i] = c->vsse[i]; - break; - case FF_CMP_ZERO: - cmp[i] = zero_cmp; - break; - case FF_CMP_NSSE: - cmp[i] = c->nsse[i]; - break; -#if CONFIG_DWT - case FF_CMP_W53: - cmp[i]= c->w53[i]; - break; - case FF_CMP_W97: - cmp[i]= c->w97[i]; - break; -#endif - default: - av_log(NULL, AV_LOG_ERROR, - "invalid cmp function selection\n"); - ret = -1; - break; - } +#define ENTRY(CMP_FLAG, ARRAY, MPVENC_ONLY) \ + [FF_CMP_ ## CMP_FLAG] = { \ + .offset = offsetof(MECmpContext, ARRAY), \ + .mpv_only = MPVENC_ONLY, \ + .available = 1, \ } + static const struct { + char available; + char mpv_only; + uint16_t offset; + } cmp_func_list[] = { + ENTRY(SAD, sad, 0), + ENTRY(SSE, sse, 0), + ENTRY(SATD, hadamard8_diff, 0), + ENTRY(DCT, dct_sad, 1), + ENTRY(PSNR, quant_psnr, 1), + ENTRY(BIT, bit, 1), + ENTRY(RD, rd, 1), + ENTRY(VSAD, vsad, 0), + ENTRY(VSSE, vsse, 0), + ENTRY(NSSE, nsse, 0), +#if CONFIG_SNOW_DECODER || CONFIG_SNOW_ENCODER + ENTRY(W53, w53, 0), + ENTRY(W97, w97, 0), +#endif + ENTRY(DCTMAX, dct_max, 1), +#if CONFIG_GPL + ENTRY(DCT264, dct264_sad, 1), +#endif + ENTRY(MEDIAN_SAD, median_sad, 0), + }; + const me_cmp_func *me_cmp_func_array; - return ret; + type &= 0xFF; + + if (type == FF_CMP_ZERO) { + for (int i = 0; i < 6; i++) + cmp[i] = zero_cmp; + return 0; + } + if (type >= FF_ARRAY_ELEMS(cmp_func_list) || + !cmp_func_list[type].available || + !mpvenc && cmp_func_list[type].mpv_only) { + av_log(NULL, AV_LOG_ERROR, + "invalid cmp function selection\n"); + return AVERROR(EINVAL); + } + me_cmp_func_array = (const me_cmp_func*)(((const char*)c) + cmp_func_list[type].offset); + for (int i = 0; i < 6; i++) + cmp[i] = me_cmp_func_array[i]; + + return 0; } #define BUTTERFLY2(o1, o2, i1, i2) \ @@ -665,7 +653,7 @@ static int dct_sad8x8_c(MpegEncContext *s, const uint8_t *src1, s->pdsp.diff_pixels_unaligned(temp, src1, src2, stride); s->fdsp.fdct(temp); - return s->mecc.sum_abs_dctelem(temp); + return s->sum_abs_dctelem(temp); } #if CONFIG_GPL @@ -751,7 +739,7 @@ static int quant_psnr8x8_c(MpegEncContext *s, const uint8_t *src1, memcpy(bak, temp, 64 * sizeof(int16_t)); s->block_last_index[0 /* FIXME */] = - s->fast_dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + s->dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); s->dct_unquantize_inter(s, temp, 0, s->qscale); ff_simple_idct_int16_8bit(temp); // FIXME @@ -779,7 +767,7 @@ static int rd8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, s->block_last_index[0 /* FIXME */] = last = - s->fast_dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + s->dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); bits = 0; @@ -831,7 +819,7 @@ static int rd8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, s->idsp.idct_add(lsrc2, 8, temp); - distortion = s->mecc.sse[1](NULL, lsrc2, lsrc1, 8, 8); + distortion = s->sse_cmp[1](NULL, lsrc2, lsrc1, 8, 8); return distortion + ((bits * s->qscale * s->qscale * 109 + 64) >> 7); } @@ -849,7 +837,7 @@ static int bit8x8_c(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, s->block_last_index[0 /* FIXME */] = last = - s->fast_dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + s->dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); bits = 0; @@ -1007,6 +995,8 @@ WRAPPER8_16_SQ(bit8x8_c, bit16_c) av_cold void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx) { + memset(c, 0, sizeof(*c)); + c->sum_abs_dctelem = sum_abs_dctelem_c; /* TODO [0] 16 [1] 8 */ @@ -1058,8 +1048,6 @@ av_cold void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx) #if ARCH_AARCH64 ff_me_cmp_init_aarch64(c, avctx); -#elif ARCH_ALPHA - ff_me_cmp_init_alpha(c, avctx); #elif ARCH_ARM ff_me_cmp_init_arm(c, avctx); #elif ARCH_PPC diff --git a/libavcodec/me_cmp.h b/libavcodec/me_cmp.h index fee0ecb28..9053327c4 100644 --- a/libavcodec/me_cmp.h +++ b/libavcodec/me_cmp.h @@ -70,13 +70,6 @@ typedef struct MECmpContext { me_cmp_func dct_max[6]; me_cmp_func dct264_sad[6]; - me_cmp_func me_pre_cmp[6]; - me_cmp_func me_cmp[6]; - me_cmp_func me_sub_cmp[6]; - me_cmp_func mb_cmp[6]; - me_cmp_func ildct_cmp[6]; // only width 16 used - me_cmp_func frame_skip_cmp[6]; // only width 8 used - me_cmp_func pix_abs[2][4]; me_cmp_func median_sad[6]; } MECmpContext; @@ -90,7 +83,14 @@ void ff_me_cmp_init_riscv(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_x86(MECmpContext *c, AVCodecContext *avctx); void ff_me_cmp_init_mips(MECmpContext *c, AVCodecContext *avctx); -int ff_set_cmp(MECmpContext *c, me_cmp_func *cmp, int type); +/** + * 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. + */ +int ff_set_cmp(const MECmpContext *c, me_cmp_func *cmp, + int type, int mpvenc); void ff_dsputil_init_dwt(MECmpContext *c); diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c index 306359071..96c886666 100644 --- a/libavcodec/mediacodec_wrapper.c +++ b/libavcodec/mediacodec_wrapper.c @@ -365,6 +365,7 @@ int ff_AMediaCodecProfile_getProfileFromAVCodecContext(AVCodecContext *avctx) (void)VP9Profile3HDR; (void)VP9Profile2HDR10Plus; (void)VP9Profile3HDR10Plus; + (void)MPEG4ProfileSimpleFace; (void)AV1ProfileMain10; (void)AV1ProfileMain10HDR10; (void)AV1ProfileMain10HDR10Plus; @@ -1828,25 +1829,8 @@ typedef struct FFAMediaFormatNdk { void *libmedia; AMediaFormat *impl; - AMediaFormat *(*new)(void); - media_status_t (*delete)(AMediaFormat*); - - const char* (*toString)(AMediaFormat*); - - bool (*getInt32)(AMediaFormat*, const char *name, int32_t *out); - bool (*getInt64)(AMediaFormat*, const char *name, int64_t *out); - bool (*getFloat)(AMediaFormat*, const char *name, float *out); - bool (*getSize)(AMediaFormat*, const char *name, size_t *out); - bool (*getBuffer)(AMediaFormat*, const char *name, void** data, size_t *size); - bool (*getString)(AMediaFormat*, const char *name, const char **out); bool (*getRect)(AMediaFormat *, const char *name, int32_t *left, int32_t *top, int32_t *right, int32_t *bottom); - - void (*setInt32)(AMediaFormat*, const char* name, int32_t value); - void (*setInt64)(AMediaFormat*, const char* name, int64_t value); - void (*setFloat)(AMediaFormat*, const char* name, float value); - void (*setString)(AMediaFormat*, const char* name, const char* value); - void (*setBuffer)(AMediaFormat*, const char* name, const void* data, size_t size); void (*setRect)(AMediaFormat *, const char *name, int32_t left, int32_t top, int32_t right, int32_t bottom); } FFAMediaFormatNdk; @@ -1858,34 +1842,6 @@ typedef struct FFAMediaCodecNdk { AMediaCodec *impl; ANativeWindow *window; - AMediaCodec* (*createCodecByName)(const char *name); - AMediaCodec* (*createDecoderByType)(const char *mime_type); - AMediaCodec* (*createEncoderByType)(const char *mime_type); - media_status_t (*delete)(AMediaCodec*); - - media_status_t (*configure)(AMediaCodec *, - const AMediaFormat *format, - ANativeWindow *surface, - AMediaCrypto *crypto, - uint32_t flags); - media_status_t (*start)(AMediaCodec*); - media_status_t (*stop)(AMediaCodec*); - media_status_t (*flush)(AMediaCodec*); - - uint8_t* (*getInputBuffer)(AMediaCodec*, size_t idx, size_t *out_size); - uint8_t* (*getOutputBuffer)(AMediaCodec*, size_t idx, size_t *out_size); - - ssize_t (*dequeueInputBuffer)(AMediaCodec*, int64_t timeoutUs); - media_status_t (*queueInputBuffer)(AMediaCodec*, size_t idx, - long offset, size_t size, - uint64_t time, uint32_t flags); - - ssize_t (*dequeueOutputBuffer)(AMediaCodec*, AMediaCodecBufferInfo *info, int64_t timeoutUs); - AMediaFormat* (*getOutputFormat)(AMediaCodec*); - - media_status_t (*releaseOutputBuffer)(AMediaCodec*, size_t idx, bool render); - media_status_t (*releaseOutputBufferAtTime)(AMediaCodec *mData, size_t idx, int64_t timestampNs); - // Available since API level 28. media_status_t (*getName)(AMediaCodec*, char** out_name); void (*releaseName)(AMediaCodec*, char* name); @@ -1925,38 +1881,15 @@ static FFAMediaFormat *mediaformat_ndk_create(AMediaFormat *impl) #define GET_OPTIONAL_SYMBOL(sym) \ format->sym = dlsym(format->libmedia, "AMediaFormat_" #sym); -#define GET_SYMBOL(sym) \ - GET_OPTIONAL_SYMBOL(sym) \ - if (!format->sym) \ - goto error; - - GET_SYMBOL(new) - GET_SYMBOL(delete) - - GET_SYMBOL(toString) - - GET_SYMBOL(getInt32) - GET_SYMBOL(getInt64) - GET_SYMBOL(getFloat) - GET_SYMBOL(getSize) - GET_SYMBOL(getBuffer) - GET_SYMBOL(getString) GET_OPTIONAL_SYMBOL(getRect) - - GET_SYMBOL(setInt32) - GET_SYMBOL(setInt64) - GET_SYMBOL(setFloat) - GET_SYMBOL(setString) - GET_SYMBOL(setBuffer) GET_OPTIONAL_SYMBOL(setRect) -#undef GET_SYMBOL #undef GET_OPTIONAL_SYMBOL if (impl) { format->impl = impl; } else { - format->impl = format->new(); + format->impl = AMediaFormat_new(); if (!format->impl) goto error; } @@ -1984,7 +1917,7 @@ static int mediaformat_ndk_delete(FFAMediaFormat* ctx) av_assert0(format->api.class == &amediaformat_ndk_class); - if (format->impl && (format->delete(format->impl) != AMEDIA_OK)) + if (format->impl && (AMediaFormat_delete(format->impl) != AMEDIA_OK)) ret = AVERROR_EXTERNAL; if (format->libmedia) dlclose(format->libmedia); @@ -1996,39 +1929,39 @@ static int mediaformat_ndk_delete(FFAMediaFormat* ctx) static char* mediaformat_ndk_toString(FFAMediaFormat* ctx) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - const char *str = format->toString(format->impl); + const char *str = AMediaFormat_toString(format->impl); return av_strdup(str); } static int mediaformat_ndk_getInt32(FFAMediaFormat* ctx, const char *name, int32_t *out) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - return format->getInt32(format->impl, name, out); + return AMediaFormat_getInt32(format->impl, name, out); } static int mediaformat_ndk_getInt64(FFAMediaFormat* ctx, const char *name, int64_t *out) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - return format->getInt64(format->impl, name, out); + return AMediaFormat_getInt64(format->impl, name, out); } static int mediaformat_ndk_getFloat(FFAMediaFormat* ctx, const char *name, float *out) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - return format->getFloat(format->impl, name, out); + return AMediaFormat_getFloat(format->impl, name, out); } static int mediaformat_ndk_getBuffer(FFAMediaFormat* ctx, const char *name, void** data, size_t *size) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - return format->getBuffer(format->impl, name, data, size); + return AMediaFormat_getBuffer(format->impl, name, data, size); } static int mediaformat_ndk_getString(FFAMediaFormat* ctx, const char *name, const char **out) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; const char *tmp = NULL; - int ret = format->getString(format->impl, name, &tmp); + int ret = AMediaFormat_getString(format->impl, name, &tmp); if (tmp) *out = av_strdup(tmp); @@ -2047,31 +1980,31 @@ static int mediaformat_ndk_getRect(FFAMediaFormat *ctx, const char *name, static void mediaformat_ndk_setInt32(FFAMediaFormat* ctx, const char* name, int32_t value) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - format->setInt32(format->impl, name, value); + AMediaFormat_setInt32(format->impl, name, value); } static void mediaformat_ndk_setInt64(FFAMediaFormat* ctx, const char* name, int64_t value) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - format->setInt64(format->impl, name, value); + AMediaFormat_setInt64(format->impl, name, value); } static void mediaformat_ndk_setFloat(FFAMediaFormat* ctx, const char* name, float value) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - format->setFloat(format->impl, name, value); + AMediaFormat_setFloat(format->impl, name, value); } static void mediaformat_ndk_setString(FFAMediaFormat* ctx, const char* name, const char* value) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - format->setString(format->impl, name, value); + AMediaFormat_setString(format->impl, name, value); } static void mediaformat_ndk_setBuffer(FFAMediaFormat* ctx, const char* name, void* data, size_t size) { FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx; - format->setBuffer(format->impl, name, data, size); + AMediaFormat_setBuffer(format->impl, name, data, size); } static void mediaformat_ndk_setRect(FFAMediaFormat *ctx, const char *name, @@ -2117,54 +2050,28 @@ static inline FFAMediaCodec *ndk_codec_create(int method, const char *arg) { if (!codec->libmedia) goto error; -#define GET_SYMBOL(sym, required) \ +#define GET_SYMBOL(sym) \ codec->sym = dlsym(codec->libmedia, "AMediaCodec_" #sym); \ - if (!codec->sym) { \ - av_log(codec, required ? AV_LOG_ERROR : AV_LOG_INFO, \ - #sym "() unavailable from %s\n", lib_name); \ - if (required) \ - goto error; \ - } + if (!codec->sym) \ + av_log(codec, AV_LOG_INFO, #sym "() unavailable from %s\n", lib_name); - GET_SYMBOL(createCodecByName, 1) - GET_SYMBOL(createDecoderByType, 1) - GET_SYMBOL(createEncoderByType, 1) - GET_SYMBOL(delete, 1) + GET_SYMBOL(getName) + GET_SYMBOL(releaseName) - GET_SYMBOL(configure, 1) - GET_SYMBOL(start, 1) - GET_SYMBOL(stop, 1) - GET_SYMBOL(flush, 1) - - GET_SYMBOL(getInputBuffer, 1) - GET_SYMBOL(getOutputBuffer, 1) - - GET_SYMBOL(dequeueInputBuffer, 1) - GET_SYMBOL(queueInputBuffer, 1) - - GET_SYMBOL(dequeueOutputBuffer, 1) - GET_SYMBOL(getOutputFormat, 1) - - GET_SYMBOL(releaseOutputBuffer, 1) - GET_SYMBOL(releaseOutputBufferAtTime, 1) - - GET_SYMBOL(getName, 0) - GET_SYMBOL(releaseName, 0) - - GET_SYMBOL(setInputSurface, 0) - GET_SYMBOL(signalEndOfInputStream, 0) + GET_SYMBOL(setInputSurface) + GET_SYMBOL(signalEndOfInputStream) #undef GET_SYMBOL switch (method) { case CREATE_CODEC_BY_NAME: - codec->impl = codec->createCodecByName(arg); + codec->impl = AMediaCodec_createCodecByName(arg); break; case CREATE_DECODER_BY_TYPE: - codec->impl = codec->createDecoderByType(arg); + codec->impl = AMediaCodec_createDecoderByType(arg); break; case CREATE_ENCODER_BY_TYPE: - codec->impl = codec->createEncoderByType(arg); + codec->impl = AMediaCodec_createEncoderByType(arg); break; default: av_assert0(0); @@ -2201,7 +2108,7 @@ static int mediacodec_ndk_delete(FFAMediaCodec* ctx) av_assert0(codec->api.class == &amediacodec_ndk_class); - if (codec->impl && (codec->delete(codec->impl) != AMEDIA_OK)) + if (codec->impl && (AMediaCodec_delete(codec->impl) != AMEDIA_OK)) ret = AVERROR_EXTERNAL; if (codec->window) ANativeWindow_release(codec->window); @@ -2246,7 +2153,7 @@ static int mediacodec_ndk_configure(FFAMediaCodec* ctx, return AVERROR_EXTERNAL; } - status = codec->configure(codec->impl, format->impl, NULL, NULL, flags); + status = AMediaCodec_configure(codec->impl, format->impl, NULL, NULL, flags); if (status != AMEDIA_OK) { av_log(codec, AV_LOG_ERROR, "Encoder configure failed, %d\n", status); return AVERROR_EXTERNAL; @@ -2261,7 +2168,7 @@ static int mediacodec_ndk_configure(FFAMediaCodec* ctx, return AVERROR_EXTERNAL; } } else { - status = codec->configure(codec->impl, format->impl, native_window, NULL, flags); + status = AMediaCodec_configure(codec->impl, format->impl, native_window, NULL, flags); if (status != AMEDIA_OK) { av_log(codec, AV_LOG_ERROR, "Decoder configure failed, %d\n", status); return AVERROR_EXTERNAL; @@ -2275,7 +2182,7 @@ static int mediacodec_ndk_configure(FFAMediaCodec* ctx, static int mediacodec_ndk_ ## method(FFAMediaCodec* ctx) \ { \ FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; \ - media_status_t status = codec->method(codec->impl); \ + media_status_t status = AMediaCodec_ ## method (codec->impl); \ \ if (status != AMEDIA_OK) { \ av_log(codec, AV_LOG_ERROR, #method " failed, %d\n", status); \ @@ -2292,19 +2199,19 @@ MEDIACODEC_NDK_WRAPPER(flush) static uint8_t* mediacodec_ndk_getInputBuffer(FFAMediaCodec* ctx, size_t idx, size_t *out_size) { FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; - return codec->getInputBuffer(codec->impl, idx, out_size); + return AMediaCodec_getInputBuffer(codec->impl, idx, out_size); } static uint8_t* mediacodec_ndk_getOutputBuffer(FFAMediaCodec* ctx, size_t idx, size_t *out_size) { FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; - return codec->getOutputBuffer(codec->impl, idx, out_size); + return AMediaCodec_getOutputBuffer(codec->impl, idx, out_size); } static ssize_t mediacodec_ndk_dequeueInputBuffer(FFAMediaCodec* ctx, int64_t timeoutUs) { FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; - return codec->dequeueInputBuffer(codec->impl, timeoutUs); + return AMediaCodec_dequeueInputBuffer(codec->impl, timeoutUs); } static int mediacodec_ndk_queueInputBuffer(FFAMediaCodec *ctx, size_t idx, @@ -2312,7 +2219,7 @@ static int mediacodec_ndk_queueInputBuffer(FFAMediaCodec *ctx, size_t idx, uint64_t time, uint32_t flags) { FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; - return codec->queueInputBuffer(codec->impl, idx, offset, size, time, flags); + return AMediaCodec_queueInputBuffer(codec->impl, idx, offset, size, time, flags); } static ssize_t mediacodec_ndk_dequeueOutputBuffer(FFAMediaCodec* ctx, FFAMediaCodecBufferInfo *info, int64_t timeoutUs) @@ -2321,7 +2228,7 @@ static ssize_t mediacodec_ndk_dequeueOutputBuffer(FFAMediaCodec* ctx, FFAMediaCo AMediaCodecBufferInfo buf_info = {0}; ssize_t ret; - ret = codec->dequeueOutputBuffer(codec->impl, &buf_info, timeoutUs); + ret = AMediaCodec_dequeueOutputBuffer(codec->impl, &buf_info, timeoutUs); info->offset = buf_info.offset; info->size = buf_info.size; info->presentationTimeUs = buf_info.presentationTimeUs; @@ -2333,7 +2240,7 @@ static ssize_t mediacodec_ndk_dequeueOutputBuffer(FFAMediaCodec* ctx, FFAMediaCo static FFAMediaFormat* mediacodec_ndk_getOutputFormat(FFAMediaCodec* ctx) { FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; - AMediaFormat *format = codec->getOutputFormat(codec->impl); + AMediaFormat *format = AMediaCodec_getOutputFormat(codec->impl); if (!format) return NULL; @@ -2345,7 +2252,7 @@ static int mediacodec_ndk_releaseOutputBuffer(FFAMediaCodec* ctx, size_t idx, in FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; media_status_t status; - status = codec->releaseOutputBuffer(codec->impl, idx, render); + status = AMediaCodec_releaseOutputBuffer(codec->impl, idx, render); if (status != AMEDIA_OK) { av_log(codec, AV_LOG_ERROR, "release output buffer failed, %d\n", status); return AVERROR_EXTERNAL; @@ -2359,7 +2266,7 @@ static int mediacodec_ndk_releaseOutputBufferAtTime(FFAMediaCodec *ctx, size_t i FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx; media_status_t status; - status = codec->releaseOutputBufferAtTime(codec->impl, idx, timestampNs); + status = AMediaCodec_releaseOutputBufferAtTime(codec->impl, idx, timestampNs); if (status != AMEDIA_OK) { av_log(codec, AV_LOG_ERROR, "releaseOutputBufferAtTime failed, %d\n", status); return AVERROR_EXTERNAL; diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c index b8587289a..cc55b306b 100644 --- a/libavcodec/mediacodecdec.c +++ b/libavcodec/mediacodecdec.c @@ -27,6 +27,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/intreadwrite.h" #include "libavutil/pixfmt.h" @@ -37,7 +38,7 @@ #include "decode.h" #include "h264_parse.h" #include "h264_ps.h" -#include "hevc_parse.h" +#include "hevc/parse.h" #include "hwconfig.h" #include "internal.h" #include "jni.h" @@ -290,7 +291,11 @@ done: CONFIG_MPEG4_MEDIACODEC_DECODER || \ CONFIG_VP8_MEDIACODEC_DECODER || \ CONFIG_VP9_MEDIACODEC_DECODER || \ - CONFIG_AV1_MEDIACODEC_DECODER + CONFIG_AV1_MEDIACODEC_DECODER || \ + CONFIG_AAC_MEDIACODEC_DECODER || \ + CONFIG_AMRNB_MEDIACODEC_DECODER || \ + CONFIG_AMRWB_MEDIACODEC_DECODER || \ + CONFIG_MP3_MEDIACODEC_DECODER static int common_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) { int ret = 0; @@ -387,13 +392,55 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) goto done; break; #endif +#if CONFIG_AAC_MEDIACODEC_DECODER + case AV_CODEC_ID_AAC: + codec_mime = "audio/mp4a-latm"; + + ret = common_set_extradata(avctx, format); + if (ret < 0) + goto done; + break; +#endif +#if CONFIG_AMRNB_MEDIACODEC_DECODER + case AV_CODEC_ID_AMR_NB: + codec_mime = "audio/3gpp"; + + ret = common_set_extradata(avctx, format); + if (ret < 0) + goto done; + break; +#endif +#if CONFIG_AMRWB_MEDIACODEC_DECODER + case AV_CODEC_ID_AMR_WB: + codec_mime = "audio/amr-wb"; + + ret = common_set_extradata(avctx, format); + if (ret < 0) + goto done; + break; +#endif +#if CONFIG_MP3_MEDIACODEC_DECODER + case AV_CODEC_ID_MP3: + codec_mime = "audio/mpeg"; + + ret = common_set_extradata(avctx, format); + if (ret < 0) + goto done; + break; +#endif default: av_assert0(0); } ff_AMediaFormat_setString(format, "mime", codec_mime); - ff_AMediaFormat_setInt32(format, "width", avctx->width); - ff_AMediaFormat_setInt32(format, "height", avctx->height); + + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + ff_AMediaFormat_setInt32(format, "width", avctx->width); + ff_AMediaFormat_setInt32(format, "height", avctx->height); + } else { + ff_AMediaFormat_setInt32(format, "channel-count", avctx->ch_layout.nb_channels); + ff_AMediaFormat_setInt32(format, "sample-rate", avctx->sample_rate); + } s->ctx = av_mallocz(sizeof(*s->ctx)); if (!s->ctx) { @@ -461,7 +508,7 @@ static int mediacodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) /* feed decoder */ while (1) { - if (s->ctx->current_input_buffer < 0) { + if (s->ctx->current_input_buffer < 0 && !s->ctx->draining) { /* poll for input space */ index = ff_AMediaCodec_dequeueInputBuffer(s->ctx->codec, 0); if (index < 0) { @@ -610,3 +657,53 @@ DECLARE_MEDIACODEC_VDEC(vp9, "VP9", AV_CODEC_ID_VP9, NULL) #if CONFIG_AV1_MEDIACODEC_DECODER DECLARE_MEDIACODEC_VDEC(av1, "AV1", AV_CODEC_ID_AV1, NULL) #endif + +#define AD AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM +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 }, + { NULL } +}; + +#define DECLARE_MEDIACODEC_ACLASS(short_name) \ +static const AVClass ff_##short_name##_mediacodec_dec_class = { \ + .class_name = #short_name "_mediacodec", \ + .item_name = av_default_item_name, \ + .option = ff_mediacodec_adec_options, \ + .version = LIBAVUTIL_VERSION_INT, \ +}; + +#define DECLARE_MEDIACODEC_ADEC(short_name, full_name, codec_id, bsf) \ +DECLARE_MEDIACODEC_VCLASS(short_name) \ +const FFCodec ff_ ## short_name ## _mediacodec_decoder = { \ + .p.name = #short_name "_mediacodec", \ + CODEC_LONG_NAME(full_name " Android MediaCodec decoder"), \ + .p.type = AVMEDIA_TYPE_AUDIO, \ + .p.id = codec_id, \ + .p.priv_class = &ff_##short_name##_mediacodec_dec_class, \ + .priv_data_size = sizeof(MediaCodecH264DecContext), \ + .init = mediacodec_decode_init, \ + FF_CODEC_RECEIVE_FRAME_CB(mediacodec_receive_frame), \ + .flush = mediacodec_decode_flush, \ + .close = mediacodec_decode_close, \ + .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, \ + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, \ + .bsfs = bsf, \ + .p.wrapper_name = "mediacodec", \ +}; \ + +#if CONFIG_AAC_MEDIACODEC_DECODER +DECLARE_MEDIACODEC_ADEC(aac, "AAC", AV_CODEC_ID_AAC, "aac_adtstoasc") +#endif + +#if CONFIG_AMRNB_MEDIACODEC_DECODER +DECLARE_MEDIACODEC_ADEC(amrnb, "AMR-NB", AV_CODEC_ID_AMR_NB, NULL) +#endif + +#if CONFIG_AMRWB_MEDIACODEC_DECODER +DECLARE_MEDIACODEC_ADEC(amrwb, "AMR-WB", AV_CODEC_ID_AMR_WB, NULL) +#endif + +#if CONFIG_MP3_MEDIACODEC_DECODER +DECLARE_MEDIACODEC_ADEC(mp3, "MP3", AV_CODEC_ID_MP3, NULL) +#endif diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c index d6f91e6e8..3770b4f3a 100644 --- a/libavcodec/mediacodecdec_common.c +++ b/libavcodec/mediacodecdec_common.c @@ -23,6 +23,7 @@ #include #include +#include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/hwcontext_mediacodec.h" #include "libavutil/mem.h" @@ -30,6 +31,7 @@ #include "libavutil/pixfmt.h" #include "libavutil/time.h" #include "libavutil/timestamp.h" +#include "libavutil/channel_layout.h" #include "avcodec.h" #include "decode.h" @@ -85,6 +87,107 @@ #define OUTPUT_DEQUEUE_TIMEOUT_US 8000 #define OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US 1000000 +enum { + ENCODING_PCM_16BIT = 0x00000002, + ENCODING_PCM_8BIT = 0x00000003, + ENCODING_PCM_FLOAT = 0x00000004, + ENCODING_PCM_24BIT_PACKED = 0x00000015, + ENCODING_PCM_32BIT = 0x00000016, +}; + +static const struct { + + int pcm_format; + enum AVSampleFormat sample_format; + +} sample_formats[] = { + + { ENCODING_PCM_16BIT, AV_SAMPLE_FMT_S16 }, + { ENCODING_PCM_8BIT, AV_SAMPLE_FMT_U8 }, + { ENCODING_PCM_FLOAT, AV_SAMPLE_FMT_FLT }, + { ENCODING_PCM_32BIT, AV_SAMPLE_FMT_S32 }, + { 0 } +}; + +static enum AVSampleFormat mcdec_map_pcm_format(AVCodecContext *avctx, + MediaCodecDecContext *s, + int pcm_format) +{ + enum AVSampleFormat ret = AV_SAMPLE_FMT_NONE; + + for (int i = 0; i < FF_ARRAY_ELEMS(sample_formats); i++) { + if (sample_formats[i].pcm_format == pcm_format) { + return sample_formats[i].sample_format; + } + } + + av_log(avctx, AV_LOG_ERROR, "Output sample format 0x%x (value=%d) is not supported\n", + pcm_format, pcm_format); + + return ret; +} + +enum +{ + CHANNEL_OUT_FRONT_LEFT = 0x4, + CHANNEL_OUT_FRONT_RIGHT = 0x8, + CHANNEL_OUT_FRONT_CENTER = 0x10, + CHANNEL_OUT_LOW_FREQUENCY = 0x20, + CHANNEL_OUT_BACK_LEFT = 0x40, + CHANNEL_OUT_BACK_RIGHT = 0x80, + CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100, + CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200, + CHANNEL_OUT_BACK_CENTER = 0x400, + CHANNEL_OUT_SIDE_LEFT = 0x800, + CHANNEL_OUT_SIDE_RIGHT = 0x1000, + CHANNEL_OUT_TOP_CENTER = 0x2000, + CHANNEL_OUT_TOP_FRONT_LEFT = 0x4000, + CHANNEL_OUT_TOP_FRONT_CENTER = 0x8000, + CHANNEL_OUT_TOP_FRONT_RIGHT = 0x10000, + CHANNEL_OUT_TOP_BACK_LEFT = 0x20000, + CHANNEL_OUT_TOP_BACK_CENTER = 0x40000, + CHANNEL_OUT_TOP_BACK_RIGHT = 0x80000, +}; + +static const struct { + + int mask; + uint64_t layout; + +} channel_masks[] = { + { CHANNEL_OUT_FRONT_LEFT, AV_CH_FRONT_LEFT }, + { CHANNEL_OUT_FRONT_RIGHT, AV_CH_FRONT_RIGHT }, + { CHANNEL_OUT_FRONT_CENTER, AV_CH_FRONT_CENTER }, + { CHANNEL_OUT_LOW_FREQUENCY, AV_CH_LOW_FREQUENCY }, + { CHANNEL_OUT_BACK_LEFT, AV_CH_BACK_LEFT }, + { CHANNEL_OUT_BACK_RIGHT, AV_CH_BACK_RIGHT }, + { CHANNEL_OUT_FRONT_LEFT_OF_CENTER, AV_CH_FRONT_LEFT_OF_CENTER }, + { CHANNEL_OUT_FRONT_RIGHT_OF_CENTER, AV_CH_FRONT_RIGHT_OF_CENTER }, + { CHANNEL_OUT_BACK_CENTER, AV_CH_BACK_CENTER }, + { CHANNEL_OUT_SIDE_LEFT, AV_CH_SIDE_LEFT }, + { CHANNEL_OUT_SIDE_RIGHT, AV_CH_SIDE_RIGHT }, + { CHANNEL_OUT_TOP_CENTER, AV_CH_TOP_CENTER }, + { CHANNEL_OUT_TOP_FRONT_LEFT, AV_CH_TOP_FRONT_LEFT }, + { CHANNEL_OUT_TOP_FRONT_CENTER, AV_CH_TOP_FRONT_CENTER }, + { CHANNEL_OUT_TOP_FRONT_RIGHT, AV_CH_TOP_FRONT_RIGHT }, + { CHANNEL_OUT_TOP_BACK_LEFT, AV_CH_TOP_BACK_LEFT }, + { CHANNEL_OUT_TOP_BACK_CENTER, AV_CH_TOP_BACK_CENTER }, + { CHANNEL_OUT_TOP_BACK_RIGHT, AV_CH_TOP_BACK_RIGHT }, +}; + +static uint64_t mcdec_map_channel_mask(AVCodecContext *avctx, + int channel_mask) +{ + uint64_t channel_layout = 0; + + for (int i = 0; i < FF_ARRAY_ELEMS(channel_masks); i++) { + if (channel_mask & channel_masks[i].mask) + channel_layout |= channel_masks[i].layout; + } + + return channel_layout; +} + enum { COLOR_FormatYUV420Planar = 0x13, COLOR_FormatYUV420SemiPlanar = 0x15, @@ -265,13 +368,80 @@ fail: return ret; } -static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx, - MediaCodecDecContext *s, - uint8_t *data, - size_t size, - ssize_t index, - FFAMediaCodecBufferInfo *info, - AVFrame *frame) +static int mediacodec_wrap_sw_audio_buffer(AVCodecContext *avctx, + MediaCodecDecContext *s, + uint8_t *data, + size_t size, + ssize_t index, + FFAMediaCodecBufferInfo *info, + AVFrame *frame) +{ + int ret = 0; + int status = 0; + const int sample_size = av_get_bytes_per_sample(avctx->sample_fmt); + if (!sample_size) { + av_log(avctx, AV_LOG_ERROR, "Could not get bytes per sample\n"); + ret = AVERROR(ENOSYS); + goto done; + } + + frame->format = avctx->sample_fmt; + frame->sample_rate = avctx->sample_rate; + frame->nb_samples = info->size / (sample_size * avctx->ch_layout.nb_channels); + + ret = av_channel_layout_copy(&frame->ch_layout, &avctx->ch_layout); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not copy channel layout\n"); + goto done; + } + + /* MediaCodec buffers needs to be copied to our own refcounted buffers + * because the flush command invalidates all input and output buffers. + */ + ret = ff_get_buffer(avctx, frame, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer\n"); + goto done; + } + + /* Override frame->pts as ff_get_buffer will override its value based + * on the last avpacket received which is not in sync with the frame: + * * N avpackets can be pushed before 1 frame is actually returned + * * 0-sized avpackets are pushed to flush remaining frames at EOS */ + if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) { + frame->pts = av_rescale_q(info->presentationTimeUs, + AV_TIME_BASE_Q, + avctx->pkt_timebase); + } else { + frame->pts = info->presentationTimeUs; + } + frame->pkt_dts = AV_NOPTS_VALUE; + frame->flags |= AV_FRAME_FLAG_KEY; + + av_log(avctx, AV_LOG_TRACE, + "Frame: format=%d channels=%d sample_rate=%d nb_samples=%d", + avctx->sample_fmt, avctx->ch_layout.nb_channels, avctx->sample_rate, frame->nb_samples); + + memcpy(frame->data[0], data, info->size); + + ret = 0; +done: + status = ff_AMediaCodec_releaseOutputBuffer(s->codec, index, 0); + if (status < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to release output buffer\n"); + ret = AVERROR_EXTERNAL; + } + + return ret; +} + +static int mediacodec_wrap_sw_video_buffer(AVCodecContext *avctx, + MediaCodecDecContext *s, + uint8_t *data, + size_t size, + ssize_t index, + FFAMediaCodecBufferInfo *info, + AVFrame *frame) { int ret = 0; int status = 0; @@ -343,6 +513,22 @@ done: return ret; } +static int mediacodec_wrap_sw_buffer(AVCodecContext *avctx, + MediaCodecDecContext *s, + uint8_t *data, + size_t size, + ssize_t index, + FFAMediaCodecBufferInfo *info, + AVFrame *frame) +{ + if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) + return mediacodec_wrap_sw_audio_buffer(avctx, s, data, size, index, info, frame); + else if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) + return mediacodec_wrap_sw_video_buffer(avctx, s, data, size, index, info, frame); + else + av_assert0(0); +} + #define AMEDIAFORMAT_GET_INT32(name, key, mandatory) do { \ int32_t value = 0; \ if (ff_AMediaFormat_getInt32(s->format, key, &value)) { \ @@ -354,7 +540,7 @@ done: } \ } while (0) \ -static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecContext *s) +static int mediacodec_dec_parse_video_format(AVCodecContext *avctx, MediaCodecDecContext *s) { int ret = 0; int width = 0; @@ -463,6 +649,63 @@ fail: return ret; } +static int mediacodec_dec_parse_audio_format(AVCodecContext *avctx, MediaCodecDecContext *s) +{ + int ret = 0; + int sample_rate = 0; + int channel_count = 0; + int channel_mask = 0; + int pcm_encoding = 0; + char *format = NULL; + + if (!s->format) { + av_log(avctx, AV_LOG_ERROR, "Output MediaFormat is not set\n"); + return AVERROR(EINVAL); + } + + format = ff_AMediaFormat_toString(s->format); + if (!format) { + return AVERROR_EXTERNAL; + } + av_log(avctx, AV_LOG_DEBUG, "Parsing MediaFormat %s\n", format); + + /* Mandatory fields */ + AMEDIAFORMAT_GET_INT32(channel_count, "channel-count", 1); + AMEDIAFORMAT_GET_INT32(sample_rate, "sample-rate", 1); + + AMEDIAFORMAT_GET_INT32(pcm_encoding, "pcm-encoding", 0); + if (pcm_encoding) + avctx->sample_fmt = mcdec_map_pcm_format(avctx, s, pcm_encoding); + else + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + + avctx->sample_rate = sample_rate; + + AMEDIAFORMAT_GET_INT32(channel_mask, "channel-mask", 0); + if (channel_mask) + av_channel_layout_from_mask(&avctx->ch_layout, mcdec_map_channel_mask(avctx, channel_mask)); + else + av_channel_layout_default(&avctx->ch_layout, channel_count); + + av_log(avctx, AV_LOG_INFO, + "Output parameters channel-count=%d channel-layout=%x sample-rate=%d\n", + channel_count, channel_mask, sample_rate); + +fail: + av_freep(&format); + return ret; +} + +static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecContext *s) +{ + if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) + return mediacodec_dec_parse_audio_format(avctx, s); + else if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) + return mediacodec_dec_parse_video_format(avctx, s); + else + av_assert0(0); +} + static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContext *s) { FFAMediaCodec *codec = s->codec; @@ -486,11 +729,9 @@ static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContex return 0; } -int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, - const char *mime, FFAMediaFormat *format) +static int mediacodec_dec_get_video_codec(AVCodecContext *avctx, MediaCodecDecContext *s, + const char *mime, FFAMediaFormat *format) { - int ret = 0; - int status; int profile; enum AVPixelFormat pix_fmt; @@ -499,12 +740,6 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, AV_PIX_FMT_NONE, }; - s->avctx = avctx; - atomic_init(&s->refcount, 1); - atomic_init(&s->hw_buffer_count, 0); - atomic_init(&s->serial, 1); - s->current_input_buffer = -1; - pix_fmt = ff_get_format(avctx, pix_fmts); if (pix_fmt == AV_PIX_FMT_MEDIACODEC) { AVMediaCodecContext *user_ctx = avctx->hwaccel_context; @@ -536,8 +771,7 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, // getCodecNameByType() can fail due to missing JVM, while NDK // mediacodec can be used without JVM. if (!s->use_ndk_codec) { - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } av_log(avctx, AV_LOG_INFO, "Failed to getCodecNameByType\n"); } else { @@ -556,10 +790,52 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, } if (!s->codec) { av_log(avctx, AV_LOG_ERROR, "Failed to create media decoder for type %s and name %s\n", mime, s->codec_name); - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } + return 0; +} + +static int mediacodec_dec_get_audio_codec(AVCodecContext *avctx, MediaCodecDecContext *s, + const char *mime, FFAMediaFormat *format) +{ + s->codec = ff_AMediaCodec_createDecoderByType(mime, s->use_ndk_codec); + if (!s->codec) { + av_log(avctx, AV_LOG_ERROR, "Failed to create media decoder for mime %s\n", mime); + return AVERROR_EXTERNAL; + } + + s->codec_name = ff_AMediaCodec_getName(s->codec); + if (!s->codec_name) { + s->codec_name = av_strdup(mime); + if (!s->codec_name) + return AVERROR(ENOMEM); + } + + return 0; +} + +int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, + const char *mime, FFAMediaFormat *format) +{ + int ret; + int status; + + s->avctx = avctx; + atomic_init(&s->refcount, 1); + atomic_init(&s->hw_buffer_count, 0); + atomic_init(&s->serial, 1); + s->current_input_buffer = -1; + + if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) + ret = mediacodec_dec_get_audio_codec(avctx, s, mime, format); + else if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) + ret = mediacodec_dec_get_video_codec(avctx, s, mime, format); + else + av_assert0(0); + if (ret < 0) + goto fail; + status = ff_AMediaCodec_configure(s->codec, format, s->surface, NULL, 0); if (status < 0) { char *desc = ff_AMediaFormat_toString(format); @@ -583,12 +859,14 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, goto fail; } - s->format = ff_AMediaCodec_getOutputFormat(s->codec); - if (s->format) { - if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) { - av_log(avctx, AV_LOG_ERROR, - "Failed to configure context\n"); - goto fail; + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + s->format = ff_AMediaCodec_getOutputFormat(s->codec); + if (s->format) { + if ((ret = mediacodec_dec_parse_format(avctx, s)) < 0) { + av_log(avctx, AV_LOG_ERROR, + "Failed to configure context\n"); + goto fail; + } } } @@ -841,6 +1119,18 @@ int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s) int ff_mediacodec_dec_close(AVCodecContext *avctx, MediaCodecDecContext *s) { + if (!s) + return 0; + + if (s->codec) { + if (atomic_load(&s->hw_buffer_count) == 0) { + ff_AMediaCodec_stop(s->codec); + av_log(avctx, AV_LOG_DEBUG, "MediaCodec %p stopped\n", s->codec); + } else { + av_log(avctx, AV_LOG_DEBUG, "Not stopping MediaCodec (there are buffers pending)\n"); + } + } + ff_mediacodec_dec_unref(s); return 0; diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c index d3bf27cb7..e76ea8123 100644 --- a/libavcodec/mediacodecenc.c +++ b/libavcodec/mediacodecenc.c @@ -23,8 +23,10 @@ #include "config_components.h" #include "libavutil/avassert.h" +#include "libavutil/avstring.h" #include "libavutil/hwcontext_mediacodec.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" @@ -73,6 +75,7 @@ typedef struct MediaCodecEncContext { int bitrate_mode; int level; int pts_as_dts; + int extract_extradata; } MediaCodecEncContext; enum { @@ -111,28 +114,61 @@ static void mediacodec_output_format(AVCodecContext *avctx) ff_AMediaFormat_delete(out_format); } +static int extract_extradata_support(AVCodecContext *avctx) +{ + const AVBitStreamFilter *bsf = av_bsf_get_by_name("extract_extradata"); + + if (!bsf) { + av_log(avctx, AV_LOG_WARNING, "extract_extradata bsf not found\n"); + return 0; + } + + for (int i = 0; bsf->codec_ids[i] != AV_CODEC_ID_NONE; i++) { + if (bsf->codec_ids[i] == avctx->codec_id) + return 1; + } + + return 0; +} + static int mediacodec_init_bsf(AVCodecContext *avctx) { MediaCodecEncContext *s = avctx->priv_data; - char str[128]; + char str[128] = {0}; int ret; int crop_right = s->width - avctx->width; int crop_bottom = s->height - avctx->height; - if (!crop_right && !crop_bottom) + /* Nothing can be done for this format now */ + if (avctx->pix_fmt == AV_PIX_FMT_MEDIACODEC) return 0; - if (avctx->codec_id == AV_CODEC_ID_H264) - ret = snprintf(str, sizeof(str), "h264_metadata=crop_right=%d:crop_bottom=%d", - crop_right, crop_bottom); - else if (avctx->codec_id == AV_CODEC_ID_HEVC) - ret = snprintf(str, sizeof(str), "hevc_metadata=crop_right=%d:crop_bottom=%d", - crop_right, crop_bottom); - else + s->extract_extradata = (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) && + extract_extradata_support(avctx); + if (!crop_right && !crop_bottom && !s->extract_extradata) return 0; - if (ret >= sizeof(str)) - return AVERROR_BUFFER_TOO_SMALL; + ret = 0; + if (crop_right || crop_bottom) { + if (avctx->codec_id == AV_CODEC_ID_H264) + ret = snprintf(str, sizeof(str), "h264_metadata=crop_right=%d:crop_bottom=%d", + crop_right, crop_bottom); + else if (avctx->codec_id == AV_CODEC_ID_HEVC) + /* Encoder can use CTU size larger than 16x16, so the real crop + * margin can be larger than crop_right/crop_bottom. Let bsf figure + * out the real crop margin. + */ + ret = snprintf(str, sizeof(str), "hevc_metadata=width=%d:height=%d", + avctx->width, avctx->height); + if (ret >= sizeof(str)) + return AVERROR_BUFFER_TOO_SMALL; + } + + if (s->extract_extradata) { + ret = av_strlcatf(str, sizeof(str), "%sextract_extradata", ret ? "," : ""); + if (ret >= sizeof(str)) + return AVERROR_BUFFER_TOO_SMALL; + } ret = av_bsf_list_parse_str(str, &s->bsf); if (ret < 0) @@ -147,6 +183,8 @@ static int mediacodec_init_bsf(AVCodecContext *avctx) return ret; } +static int mediacodec_generate_extradata(AVCodecContext *avctx); + static av_cold int mediacodec_init(AVCodecContext *avctx) { const char *codec_mime = NULL; @@ -205,14 +243,6 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) avctx->codec_id == AV_CODEC_ID_HEVC)) { s->width = FFALIGN(avctx->width, 16); s->height = FFALIGN(avctx->height, 16); - // If avctx video size is aligned to 16 already, we don't need to do - // anything. If align is needed for HEVC, we should use the maximum CTU - // size. - if (avctx->codec_id == AV_CODEC_ID_HEVC && - (s->width != avctx->width || s->height != avctx->height)) { - s->width = FFALIGN(avctx->width, 64); - s->height = FFALIGN(avctx->height, 64); - } } else { s->width = avctx->width; s->height = avctx->height; @@ -346,14 +376,14 @@ static av_cold int mediacodec_init(AVCodecContext *avctx) goto bailout; mediacodec_output_format(avctx); - if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) - av_log(avctx, AV_LOG_WARNING, - "Mediacodec encoder doesn't support AV_CODEC_FLAG_GLOBAL_HEADER. " - "Use extract_extradata bsf when necessary.\n"); s->frame = av_frame_alloc(); - if (!s->frame) + if (!s->frame) { ret = AVERROR(ENOMEM); + goto bailout; + } + + ret = mediacodec_generate_extradata(avctx); bailout: if (format) @@ -361,9 +391,7 @@ bailout: return ret; } -static int mediacodec_receive(AVCodecContext *avctx, - AVPacket *pkt, - int *got_packet) +static int mediacodec_receive(AVCodecContext *avctx, AVPacket *pkt) { MediaCodecEncContext *s = avctx->priv_data; FFAMediaCodec *codec = s->codec; @@ -409,7 +437,7 @@ static int mediacodec_receive(AVCodecContext *avctx, memcpy(s->extradata, out_buf + out_info.offset, out_info.size); ff_AMediaCodec_releaseOutputBuffer(codec, index, false); // try immediately - return mediacodec_receive(avctx, pkt, got_packet); + return mediacodec_receive(avctx, pkt); } ret = ff_get_encode_buffer(avctx, pkt, out_info.size + s->extradata_size, 0); @@ -428,7 +456,6 @@ static int mediacodec_receive(AVCodecContext *avctx, if (out_info.flags & ff_AMediaCodec_getBufferFlagKeyFrame(codec)) pkt->flags |= AV_PKT_FLAG_KEY; ret = 0; - *got_packet = 1; av_log(avctx, AV_LOG_TRACE, "receive packet pts %" PRId64 " dts %" PRId64 " flags %d extradata %d\n", @@ -519,7 +546,6 @@ static int mediacodec_encode(AVCodecContext *avctx, AVPacket *pkt) { MediaCodecEncContext *s = avctx->priv_data; int ret; - int got_packet = 0; // Return on three case: // 1. Serious error @@ -534,7 +560,7 @@ static int mediacodec_encode(AVCodecContext *avctx, AVPacket *pkt) return ret; } - ret = mediacodec_receive(avctx, pkt, &got_packet); + ret = mediacodec_receive(avctx, pkt); if (s->bsf) { if (!ret || ret == AVERROR_EOF) ret = av_bsf_send_packet(s->bsf, pkt); @@ -562,6 +588,110 @@ static int mediacodec_encode(AVCodecContext *avctx, AVPacket *pkt) return 0; } +static int mediacodec_send_dummy_frame(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + int ret; + + s->frame->width = avctx->width; + s->frame->height = avctx->height; + s->frame->format = avctx->pix_fmt; + s->frame->pts = 0; + + ret = av_frame_get_buffer(s->frame, 0); + if (ret < 0) + return ret; + + do { + ret = mediacodec_send(avctx, s->frame); + } while (ret == AVERROR(EAGAIN)); + av_frame_unref(s->frame); + + if (ret < 0) + return ret; + + ret = mediacodec_send(avctx, NULL); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Flush failed: %s\n", av_err2str(ret)); + return ret; + } + + return 0; +} + +static int mediacodec_receive_dummy_pkt(AVCodecContext *avctx, AVPacket *pkt) +{ + MediaCodecEncContext *s = avctx->priv_data; + int ret; + + do { + ret = mediacodec_receive(avctx, pkt); + } while (ret == AVERROR(EAGAIN)); + + if (ret < 0) + return ret; + + do { + ret = av_bsf_send_packet(s->bsf, pkt); + if (ret < 0) + return ret; + ret = av_bsf_receive_packet(s->bsf, pkt); + } while (ret == AVERROR(EAGAIN)); + + return ret; +} + +static int mediacodec_generate_extradata(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + AVPacket *pkt = NULL; + int ret; + size_t side_size; + uint8_t *side; + + if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) + return 0; + + if (!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"); + return 0; + } + + pkt = av_packet_alloc(); + if (!pkt) + return AVERROR(ENOMEM); + + ret = mediacodec_send_dummy_frame(avctx); + if (ret < 0) + goto bailout; + ret = mediacodec_receive_dummy_pkt(avctx, pkt); + if (ret < 0) + goto bailout; + + side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size); + if (side && side_size > 0) { + avctx->extradata = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + ret = AVERROR(ENOMEM); + goto bailout; + } + + memcpy(avctx->extradata, side, side_size); + avctx->extradata_size = side_size; + } + +bailout: + if (s->eof_sent) { + s->eof_sent = 0; + ff_AMediaCodec_flush(s->codec); + } + av_bsf_flush(s->bsf); + av_packet_free(&pkt); + return ret; +} + static av_cold int mediacodec_close(AVCodecContext *avctx) { MediaCodecEncContext *s = avctx->priv_data; @@ -582,6 +712,15 @@ static av_cold int mediacodec_close(AVCodecContext *avctx) return 0; } +static av_cold void mediacodec_flush(AVCodecContext *avctx) +{ + MediaCodecEncContext *s = avctx->priv_data; + if (s->bsf) + av_bsf_flush(s->bsf); + av_frame_unref(s->frame); + ff_AMediaCodec_flush(s->codec); +} + static const AVCodecHWConfigInternal *const mediacodec_hw_configs[] = { &(const AVCodecHWConfigInternal) { .public = { @@ -632,13 +771,16 @@ const FFCodec ff_ ## short_name ## _mediacodec_encoder = { \ CODEC_LONG_NAME(long_name " Android MediaCodec encoder"), \ .p.type = AVMEDIA_TYPE_VIDEO, \ .p.id = codec_id, \ - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY \ - | AV_CODEC_CAP_HARDWARE, \ + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | \ + AV_CODEC_CAP_HARDWARE | \ + AV_CODEC_CAP_ENCODER_FLUSH, \ .priv_data_size = sizeof(MediaCodecEncContext), \ .p.pix_fmts = avc_pix_fmts, \ + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, \ .init = mediacodec_init, \ FF_CODEC_RECEIVE_PACKET_CB(mediacodec_encode), \ .close = mediacodec_close, \ + .flush = mediacodec_flush, \ .p.priv_class = &short_name ## _mediacodec_class, \ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \ .p.wrapper_name = "mediacodec", \ diff --git a/libavcodec/mf_utils.h b/libavcodec/mf_utils.h index aebfb9ad2..387c005f3 100644 --- a/libavcodec/mf_utils.h +++ b/libavcodec/mf_utils.h @@ -97,6 +97,11 @@ DEFINE_GUID(ff_CODECAPI_AVEncH264CABACEnable, 0xee6cad62, 0xd305, 0x4248, 0xa DEFINE_GUID(ff_CODECAPI_AVEncVideoForceKeyFrame, 0x398c1b98, 0x8353, 0x475a, 0x9e, 0xf2, 0x8f, 0x26, 0x5d, 0x26, 0x3, 0x45); DEFINE_GUID(ff_CODECAPI_AVEncMPVDefaultBPictureCount, 0x8d390aac, 0xdc5c, 0x4200, 0xb5, 0x7f, 0x81, 0x4d, 0x04, 0xba, 0xba, 0xb2); DEFINE_GUID(ff_CODECAPI_AVScenarioInfo, 0xb28a6e64,0x3ff9,0x446a,0x8a,0x4b,0x0d,0x7a,0x53,0x41,0x32,0x36); +DEFINE_GUID(ff_CODECAPI_AVEncCommonBufferSize, 0x0db96574, 0xb6a4, 0x4c8b, 0x81, 0x06, 0x37, 0x73, 0xde, 0x03, 0x10, 0xcd); +DEFINE_GUID(ff_CODECAPI_AVEncCommonMaxBitRate, 0x9651eae4, 0x39b9, 0x4ebf, 0x85, 0xef, 0xd7, 0xf4, 0x44, 0xec, 0x74, 0x65); +DEFINE_GUID(ff_CODECAPI_AVEncCommonQualityVsSpeed, 0x98332df8, 0x03cd, 0x476b, 0x89, 0xfa, 0x3f, 0x9e, 0x44, 0x2d, 0xec, 0x9f); +DEFINE_GUID(ff_CODECAPI_AVEncMPVGOPSize, 0x95f31b26, 0x95a4, 0x41aa, 0x93, 0x03, 0x24, 0x6a, 0x7f, 0xc6, 0xee, 0xf1); +DEFINE_GUID(ff_CODECAPI_AVEncVideoEncodeQP, 0x2cb5696b, 0x23fb, 0x4ce1, 0xa0, 0xf9, 0xef, 0x5b, 0x90, 0xfd, 0x55, 0xca); DEFINE_GUID(ff_MF_SA_D3D11_BINDFLAGS, 0xeacf97ad, 0x065c, 0x4408, 0xbe, 0xe3, 0xfd, 0xcb, 0xfd, 0x12, 0x8b, 0xe2); DEFINE_GUID(ff_MF_SA_D3D11_USAGE, 0xe85fe442, 0x2ca3, 0x486e, 0xa9, 0xc7, 0x10, 0x9d, 0xda, 0x60, 0x98, 0x80); diff --git a/libavcodec/mfenc.c b/libavcodec/mfenc.c index a674a35aa..b8f8a25f4 100644 --- a/libavcodec/mfenc.c +++ b/libavcodec/mfenc.c @@ -25,6 +25,7 @@ #include "encode.h" #include "mf_utils.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time.h" #include "codec_internal.h" @@ -695,6 +696,21 @@ FF_ENABLE_DEPRECATION_WARNINGS if (c->opt_enc_quality >= 0) ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncCommonQuality, FF_VAL_VT_UI4(c->opt_enc_quality)); + if (avctx->rc_max_rate > 0) + ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncCommonMaxBitRate, FF_VAL_VT_UI4(avctx->rc_max_rate)); + + if (avctx->gop_size > 0) + ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncMPVGOPSize, FF_VAL_VT_UI4(avctx->gop_size)); + + if(avctx->rc_buffer_size > 0) + ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncCommonBufferSize, FF_VAL_VT_UI4(avctx->rc_buffer_size)); + + if(avctx->compression_level >= 0) + ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncCommonQualityVsSpeed, FF_VAL_VT_UI4(avctx->compression_level)); + + if(avctx->global_quality > 0) + ICodecAPI_SetValue(c->codec_api, &ff_CODECAPI_AVEncVideoEncodeQP, FF_VAL_VT_UI4(avctx->global_quality )); + // Always set the number of b-frames. Qualcomm's HEVC encoder on SD835 // defaults this to 1, and that setting is buggy with many of the // rate control modes. (0 or 2 b-frames works fine with most rate @@ -1223,7 +1239,7 @@ static int mf_init(AVCodecContext *avctx) #define OFFSET(x) offsetof(MFContext, x) -#define MF_ENCODER(MEDIATYPE, NAME, ID, OPTS, FMTS, CAPS) \ +#define MF_ENCODER(MEDIATYPE, NAME, ID, OPTS, FMTS, CAPS, DEFAULTS) \ static const AVClass ff_ ## NAME ## _mf_encoder_class = { \ .class_name = #NAME "_mf", \ .item_name = av_default_item_name, \ @@ -1243,6 +1259,7 @@ static int mf_init(AVCodecContext *avctx) FMTS \ CAPS \ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \ + .defaults = DEFAULTS, \ }; #define AFMTS \ @@ -1252,9 +1269,9 @@ static int mf_init(AVCodecContext *avctx) .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID | \ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE, -MF_ENCODER(AUDIO, aac, AAC, NULL, AFMTS, ACAPS); -MF_ENCODER(AUDIO, ac3, AC3, NULL, AFMTS, ACAPS); -MF_ENCODER(AUDIO, mp3, MP3, NULL, AFMTS, ACAPS); +MF_ENCODER(AUDIO, aac, AAC, NULL, AFMTS, ACAPS, NULL); +MF_ENCODER(AUDIO, ac3, AC3, NULL, AFMTS, ACAPS, NULL); +MF_ENCODER(AUDIO, mp3, MP3, NULL, AFMTS, ACAPS, NULL); #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption venc_opts[] = { @@ -1283,6 +1300,11 @@ static const AVOption venc_opts[] = { {NULL} }; +static const FFCodecDefault defaults[] = { + { "g", "0" }, + { NULL }, +}; + #define VFMTS \ .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, \ AV_PIX_FMT_YUV420P, \ @@ -1291,5 +1313,5 @@ static const AVOption venc_opts[] = { .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID | \ AV_CODEC_CAP_DR1, -MF_ENCODER(VIDEO, h264, H264, venc_opts, VFMTS, VCAPS); -MF_ENCODER(VIDEO, hevc, HEVC, venc_opts, VFMTS, VCAPS); +MF_ENCODER(VIDEO, h264, H264, venc_opts, VFMTS, VCAPS, defaults); +MF_ENCODER(VIDEO, hevc, HEVC, venc_opts, VFMTS, VCAPS, defaults); diff --git a/libavcodec/mimic.c b/libavcodec/mimic.c index cd5d0d7e3..2925aa50f 100644 --- a/libavcodec/mimic.c +++ b/libavcodec/mimic.c @@ -21,6 +21,7 @@ #include +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" @@ -33,8 +34,8 @@ #include "bswapdsp.h" #include "hpeldsp.h" #include "idctdsp.h" +#include "progressframe.h" #include "thread.h" -#include "threadframe.h" #define MIMIC_HEADER_SIZE 20 #define MIMIC_VLC_BITS 11 @@ -51,7 +52,7 @@ typedef struct MimicContext { int cur_index; int prev_index; - ThreadFrame frames [16]; + ProgressFrame frames[16]; DECLARE_ALIGNED(32, int16_t, dct_block)[64]; @@ -104,16 +105,12 @@ static const uint8_t col_zag[64] = { static av_cold int mimic_decode_end(AVCodecContext *avctx) { MimicContext *ctx = avctx->priv_data; - int i; av_freep(&ctx->swap_buf); ctx->swap_buf_size = 0; - for (i = 0; i < FF_ARRAY_ELEMS(ctx->frames); i++) { - if (ctx->frames[i].f) - ff_thread_release_ext_buffer(&ctx->frames[i]); - av_frame_free(&ctx->frames[i].f); - } + for (int i = 0; i < FF_ARRAY_ELEMS(ctx->frames); i++) + ff_progress_frame_unref(&ctx->frames[i]); return 0; } @@ -129,7 +126,6 @@ static av_cold int mimic_decode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; MimicContext *ctx = avctx->priv_data; - int i; ctx->prev_index = 0; ctx->cur_index = 15; @@ -140,12 +136,6 @@ static av_cold int mimic_decode_init(AVCodecContext *avctx) ff_idctdsp_init(&ctx->idsp, avctx); ff_permute_scantable(ctx->permutated_scantable, col_zag, ctx->idsp.idct_permutation); - for (i = 0; i < FF_ARRAY_ELEMS(ctx->frames); i++) { - ctx->frames[i].f = av_frame_alloc(); - if (!ctx->frames[i].f) - return AVERROR(ENOMEM); - } - ff_thread_once(&init_static_once, mimic_init_static); return 0; @@ -155,7 +145,6 @@ static av_cold int mimic_decode_init(AVCodecContext *avctx) static int mimic_decode_update_thread_context(AVCodecContext *avctx, const AVCodecContext *avctx_from) { MimicContext *dst = avctx->priv_data, *src = avctx_from->priv_data; - int i, ret; if (avctx == avctx_from) return 0; @@ -163,13 +152,10 @@ static int mimic_decode_update_thread_context(AVCodecContext *avctx, const AVCod dst->cur_index = src->next_cur_index; dst->prev_index = src->next_prev_index; - for (i = 0; i < FF_ARRAY_ELEMS(dst->frames); i++) { - ff_thread_release_ext_buffer(&dst->frames[i]); - if (i != src->next_cur_index && src->frames[i].f->data[0]) { - ret = ff_thread_ref_frame(&dst->frames[i], &src->frames[i]); - if (ret < 0) - return ret; - } + for (int i = 0; i < FF_ARRAY_ELEMS(dst->frames); i++) { + ff_progress_frame_unref(&dst->frames[i]); + if (i != src->next_cur_index && src->frames[i].f) + ff_progress_frame_ref(&dst->frames[i], &src->frames[i]); } return 0; @@ -292,11 +278,10 @@ static int decode(MimicContext *ctx, int quality, int num_coeffs, } else { unsigned int backref = get_bits(&ctx->gb, 4); int index = (ctx->cur_index + backref) & 15; - uint8_t *p = ctx->frames[index].f->data[0]; - if (index != ctx->cur_index && p) { - ff_thread_await_progress(&ctx->frames[index], - cur_row, 0); + if (index != ctx->cur_index && ctx->frames[index].f) { + const uint8_t *p = ctx->frames[index].f->data[0]; + ff_progress_frame_await(&ctx->frames[index], cur_row); p += src - ctx->frames[ctx->prev_index].f->data[plane]; ctx->hdsp.put_pixels_tab[1][0](dst, p, stride, 8); @@ -306,8 +291,7 @@ static int decode(MimicContext *ctx, int quality, int num_coeffs, } } } else { - ff_thread_await_progress(&ctx->frames[ctx->prev_index], - cur_row, 0); + ff_progress_frame_await(&ctx->frames[ctx->prev_index], cur_row); ctx->hdsp.put_pixels_tab[1][0](dst, src, stride, 8); } src += 8; @@ -316,8 +300,7 @@ static int decode(MimicContext *ctx, int quality, int num_coeffs, src += (stride - ctx->num_hblocks[plane]) << 3; dst += (stride - ctx->num_hblocks[plane]) << 3; - ff_thread_report_progress(&ctx->frames[ctx->cur_index], - cur_row++, 0); + ff_progress_frame_report(&ctx->frames[ctx->cur_index], cur_row++); } } @@ -391,17 +374,18 @@ static int mimic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, return AVERROR_PATCHWELCOME; } - if (is_pframe && !ctx->frames[ctx->prev_index].f->data[0]) { + if (is_pframe && !ctx->frames[ctx->prev_index].f) { av_log(avctx, AV_LOG_ERROR, "decoding must start with keyframe\n"); return AVERROR_INVALIDDATA; } - ff_thread_release_ext_buffer(&ctx->frames[ctx->cur_index]); + ff_progress_frame_unref(&ctx->frames[ctx->cur_index]); + res = ff_progress_frame_get_buffer(avctx, &ctx->frames[ctx->cur_index], + AV_GET_BUFFER_FLAG_REF); + if (res < 0) + return res; ctx->frames[ctx->cur_index].f->pict_type = is_pframe ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I; - if ((res = ff_thread_get_ext_buffer(avctx, &ctx->frames[ctx->cur_index], - AV_GET_BUFFER_FLAG_REF)) < 0) - return res; ctx->next_prev_index = ctx->cur_index; ctx->next_cur_index = (ctx->cur_index - 1) & 15; @@ -418,10 +402,10 @@ static int mimic_decode_frame(AVCodecContext *avctx, AVFrame *rframe, init_get_bits(&ctx->gb, ctx->swap_buf, swap_buf_size << 3); res = decode(ctx, quality, num_coeffs, !is_pframe); - ff_thread_report_progress(&ctx->frames[ctx->cur_index], INT_MAX, 0); + ff_progress_frame_report(&ctx->frames[ctx->cur_index], INT_MAX); if (res < 0) { if (!(avctx->active_thread_type & FF_THREAD_FRAME)) - ff_thread_release_ext_buffer(&ctx->frames[ctx->cur_index]); + ff_progress_frame_unref(&ctx->frames[ctx->cur_index]); return res; } @@ -448,6 +432,6 @@ const FFCodec ff_mimic_decoder = { FF_CODEC_DECODE_CB(mimic_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, UPDATE_THREAD_CONTEXT(mimic_decode_update_thread_context), - .caps_internal = FF_CODEC_CAP_ALLOCATE_PROGRESS | + .caps_internal = FF_CODEC_CAP_USES_PROGRESSFRAMES | FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/mips/Makefile b/libavcodec/mips/Makefile index 50fe38a50..fc1bc6b03 100644 --- a/libavcodec/mips/Makefile +++ b/libavcodec/mips/Makefile @@ -1,5 +1,4 @@ -ARCH_HEADERS = aacsbr_mips.h aacpsy_mips.h \ - cabac.h compute_antialias_fixed.h \ +ARCH_HEADERS = cabac.h compute_antialias_fixed.h \ compute_antialias_float.h \ MIPSFPU-OBJS-$(CONFIG_AMRNB_DECODER) += mips/acelp_filters_mips.o \ @@ -15,10 +14,6 @@ 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 -OBJS-$(CONFIG_AAC_DECODER) += mips/aacdec_mips.o \ - mips/aacsbr_mips.o \ - mips/sbrdsp_mips.o \ - mips/aacpsdsp_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 @@ -36,7 +31,8 @@ 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/mpegvideoencdsp_init_mips.o +OBJS-$(CONFIG_MPEGVIDEOENC) += mips/mpegvideoenc_init_mips.o \ + 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 @@ -81,6 +77,7 @@ 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_IDCTDSP) += mips/idctdsp_mmi.o \ mips/simple_idct_mmi.o MMI-OBJS-$(CONFIG_MPEG4_DECODER) += mips/xvid_idct_mmi.o diff --git a/libavcodec/mips/aacdec_mips.c b/libavcodec/mips/aacdec_mips.c deleted file mode 100644 index 456e27091..000000000 --- a/libavcodec/mips/aacdec_mips.c +++ /dev/null @@ -1,443 +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. - * - * Authors: Darko Laus (darko@mips.com) - * Djordje Pesut (djordje@mips.com) - * Mirjana Vulin (mvulin@mips.com) - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * Reference: libavcodec/aacdec.c - */ - -#include "libavutil/attributes.h" -#include "libavcodec/aacdec.h" -#include "aacdec_mips.h" -#include "libavcodec/aactab.h" -#include "libavcodec/sinewin.h" -#include "libavutil/mips/asmdefs.h" - -#if HAVE_INLINE_ASM -#if HAVE_MIPSFPU -static av_always_inline void float_copy(float *dst, const float *src, int count) -{ - // Copy 'count' floats from src to dst - const float *loop_end = src + count; - int temp[8]; - - // count must be a multiple of 8 - av_assert2(count % 8 == 0); - - // loop unrolled 8 times - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "1: \n\t" - "lw %[temp0], 0(%[src]) \n\t" - "lw %[temp1], 4(%[src]) \n\t" - "lw %[temp2], 8(%[src]) \n\t" - "lw %[temp3], 12(%[src]) \n\t" - "lw %[temp4], 16(%[src]) \n\t" - "lw %[temp5], 20(%[src]) \n\t" - "lw %[temp6], 24(%[src]) \n\t" - "lw %[temp7], 28(%[src]) \n\t" - PTR_ADDIU "%[src], %[src], 32 \n\t" - "sw %[temp0], 0(%[dst]) \n\t" - "sw %[temp1], 4(%[dst]) \n\t" - "sw %[temp2], 8(%[dst]) \n\t" - "sw %[temp3], 12(%[dst]) \n\t" - "sw %[temp4], 16(%[dst]) \n\t" - "sw %[temp5], 20(%[dst]) \n\t" - "sw %[temp6], 24(%[dst]) \n\t" - "sw %[temp7], 28(%[dst]) \n\t" - "bne %[src], %[loop_end], 1b \n\t" - PTR_ADDIU "%[dst], %[dst], 32 \n\t" - ".set pop \n\t" - - : [temp0]"=&r"(temp[0]), [temp1]"=&r"(temp[1]), - [temp2]"=&r"(temp[2]), [temp3]"=&r"(temp[3]), - [temp4]"=&r"(temp[4]), [temp5]"=&r"(temp[5]), - [temp6]"=&r"(temp[6]), [temp7]"=&r"(temp[7]), - [src]"+r"(src), [dst]"+r"(dst) - : [loop_end]"r"(loop_end) - : "memory" - ); -} - -static av_always_inline int lcg_random(unsigned previous_val) -{ - union { unsigned u; int s; } v = { previous_val * 1664525u + 1013904223 }; - return v.s; -} - -static void imdct_and_windowing_mips(AACDecContext *ac, SingleChannelElement *sce) -{ - IndividualChannelStream *ics = &sce->ics; - float *in = sce->coeffs; - float *out = sce->ret; - float *saved = sce->saved; - const float *swindow = ics->use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128; - const float *lwindow_prev = ics->use_kb_window[1] ? ff_aac_kbd_long_1024 : ff_sine_1024; - const float *swindow_prev = ics->use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128; - float *buf = ac->buf_mdct; - int i; - - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - for (i = 0; i < 1024; i += 128) - ac->mdct128_fn(ac->mdct128, buf + i, in + i, sizeof(float)); - } else - ac->mdct1024_fn(ac->mdct1024, buf, in, sizeof(float)); - - /* window overlapping - * NOTE: To simplify the overlapping code, all 'meaningless' short to long - * and long to short transitions are considered to be short to short - * transitions. This leaves just two cases (long to long and short to short) - * with a little special sauce for EIGHT_SHORT_SEQUENCE. - */ - if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) && - (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) { - ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 512); - } else { - float_copy(out, saved, 448); - - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - { - float wi; - float wj; - int i; - float temp0, temp1, temp2, temp3; - float *dst0 = out + 448 + 0*128; - float *dst1 = dst0 + 64 + 63; - float *dst2 = saved + 63; - float *win0 = (float*)swindow; - float *win1 = win0 + 64 + 63; - float *win0_prev = (float*)swindow_prev; - float *win1_prev = win0_prev + 64 + 63; - float *src0_prev = saved + 448; - float *src1_prev = buf + 0*128 + 63; - float *src0 = buf + 0*128 + 64; - float *src1 = buf + 1*128 + 63; - - for(i = 0; i < 64; i++) - { - temp0 = src0_prev[0]; - temp1 = src1_prev[0]; - wi = *win0_prev; - wj = *win1_prev; - temp2 = src0[0]; - temp3 = src1[0]; - dst0[0] = temp0 * wj - temp1 * wi; - dst1[0] = temp0 * wi + temp1 * wj; - - wi = *win0; - wj = *win1; - - temp0 = src0[128]; - temp1 = src1[128]; - dst0[128] = temp2 * wj - temp3 * wi; - dst1[128] = temp2 * wi + temp3 * wj; - - temp2 = src0[256]; - temp3 = src1[256]; - dst0[256] = temp0 * wj - temp1 * wi; - dst1[256] = temp0 * wi + temp1 * wj; - dst0[384] = temp2 * wj - temp3 * wi; - dst1[384] = temp2 * wi + temp3 * wj; - - temp0 = src0[384]; - temp1 = src1[384]; - dst0[512] = temp0 * wj - temp1 * wi; - dst2[0] = temp0 * wi + temp1 * wj; - - src0++; - src1--; - src0_prev++; - src1_prev--; - win0++; - win1--; - win0_prev++; - win1_prev--; - dst0++; - dst1--; - dst2--; - } - } - } else { - ac->fdsp->vector_fmul_window(out + 448, saved + 448, buf, swindow_prev, 64); - float_copy(out + 576, buf + 64, 448); - } - } - - // buffer update - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - ac->fdsp->vector_fmul_window(saved + 64, buf + 4*128 + 64, buf + 5*128, swindow, 64); - ac->fdsp->vector_fmul_window(saved + 192, buf + 5*128 + 64, buf + 6*128, swindow, 64); - ac->fdsp->vector_fmul_window(saved + 320, buf + 6*128 + 64, buf + 7*128, swindow, 64); - float_copy(saved + 448, buf + 7*128 + 64, 64); - } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { - float_copy(saved, buf + 512, 448); - float_copy(saved + 448, buf + 7*128 + 64, 64); - } else { // LONG_STOP or ONLY_LONG - float_copy(saved, buf + 512, 512); - } -} - -static void apply_ltp_mips(AACDecContext *ac, SingleChannelElement *sce) -{ - const LongTermPrediction *ltp = &sce->ics.ltp; - const uint16_t *offsets = sce->ics.swb_offset; - int i, sfb; - int j, k; - - if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { - float *predTime = sce->ret; - float *predFreq = ac->buf_mdct; - float *p_predTime; - int16_t num_samples = 2048; - - if (ltp->lag < 1024) - num_samples = ltp->lag + 1024; - j = (2048 - num_samples) >> 2; - k = (2048 - num_samples) & 3; - p_predTime = &predTime[num_samples]; - - for (i = 0; i < num_samples; i++) - predTime[i] = sce->ltp_state[i + 2048 - ltp->lag] * ltp->coef; - for (i = 0; i < j; i++) { - - /* loop unrolled 4 times */ - __asm__ volatile ( - "sw $0, 0(%[p_predTime]) \n\t" - "sw $0, 4(%[p_predTime]) \n\t" - "sw $0, 8(%[p_predTime]) \n\t" - "sw $0, 12(%[p_predTime]) \n\t" - PTR_ADDIU "%[p_predTime], %[p_predTime], 16 \n\t" - - : [p_predTime]"+r"(p_predTime) - : - : "memory" - ); - } - for (i = 0; i < k; i++) { - - __asm__ volatile ( - "sw $0, 0(%[p_predTime]) \n\t" - PTR_ADDIU "%[p_predTime], %[p_predTime], 4 \n\t" - - : [p_predTime]"+r"(p_predTime) - : - : "memory" - ); - } - - ac->windowing_and_mdct_ltp(ac, predFreq, predTime, &sce->ics); - - if (sce->tns.present) - ac->apply_tns(predFreq, &sce->tns, &sce->ics, 0); - - for (sfb = 0; sfb < FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) - if (ltp->used[sfb]) - for (i = offsets[sfb]; i < offsets[sfb + 1]; i++) - sce->coeffs[i] += predFreq[i]; - } -} - -static av_always_inline void fmul_and_reverse(float *dst, const float *src0, const float *src1, int count) -{ - /* Multiply 'count' floats in src0 by src1 and store the results in dst in reverse */ - /* This should be equivalent to a normal fmul, followed by reversing dst */ - - // count must be a multiple of 4 - av_assert2(count % 4 == 0); - - // move src0 and src1 to the last element of their arrays - src0 += count - 1; - src1 += count - 1; - - for (; count > 0; count -= 4){ - float temp[12]; - - /* loop unrolled 4 times */ - __asm__ volatile ( - "lwc1 %[temp0], 0(%[ptr2]) \n\t" - "lwc1 %[temp1], -4(%[ptr2]) \n\t" - "lwc1 %[temp2], -8(%[ptr2]) \n\t" - "lwc1 %[temp3], -12(%[ptr2]) \n\t" - "lwc1 %[temp4], 0(%[ptr3]) \n\t" - "lwc1 %[temp5], -4(%[ptr3]) \n\t" - "lwc1 %[temp6], -8(%[ptr3]) \n\t" - "lwc1 %[temp7], -12(%[ptr3]) \n\t" - "mul.s %[temp8], %[temp0], %[temp4] \n\t" - "mul.s %[temp9], %[temp1], %[temp5] \n\t" - "mul.s %[temp10], %[temp2], %[temp6] \n\t" - "mul.s %[temp11], %[temp3], %[temp7] \n\t" - "swc1 %[temp8], 0(%[ptr1]) \n\t" - "swc1 %[temp9], 4(%[ptr1]) \n\t" - "swc1 %[temp10], 8(%[ptr1]) \n\t" - "swc1 %[temp11], 12(%[ptr1]) \n\t" - PTR_ADDIU "%[ptr1], %[ptr1], 16 \n\t" - PTR_ADDIU "%[ptr2], %[ptr2], -16 \n\t" - PTR_ADDIU "%[ptr3], %[ptr3], -16 \n\t" - - : [temp0]"=&f"(temp[0]), [temp1]"=&f"(temp[1]), - [temp2]"=&f"(temp[2]), [temp3]"=&f"(temp[3]), - [temp4]"=&f"(temp[4]), [temp5]"=&f"(temp[5]), - [temp6]"=&f"(temp[6]), [temp7]"=&f"(temp[7]), - [temp8]"=&f"(temp[8]), [temp9]"=&f"(temp[9]), - [temp10]"=&f"(temp[10]), [temp11]"=&f"(temp[11]), - [ptr1]"+r"(dst), [ptr2]"+r"(src0), [ptr3]"+r"(src1) - : - : "memory" - ); - } -} - -static void update_ltp_mips(AACDecContext *ac, SingleChannelElement *sce) -{ - IndividualChannelStream *ics = &sce->ics; - float *saved = sce->saved; - float *saved_ltp = sce->coeffs; - const float *lwindow = ics->use_kb_window[0] ? ff_aac_kbd_long_1024 : ff_sine_1024; - const float *swindow = ics->use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128; - uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - - if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { - float *p_saved_ltp = saved_ltp + 576; - float *loop_end1 = p_saved_ltp + 448; - - float_copy(saved_ltp, saved, 512); - - /* loop unrolled 8 times */ - __asm__ volatile ( - "1: \n\t" - "sw $0, 0(%[p_saved_ltp]) \n\t" - "sw $0, 4(%[p_saved_ltp]) \n\t" - "sw $0, 8(%[p_saved_ltp]) \n\t" - "sw $0, 12(%[p_saved_ltp]) \n\t" - "sw $0, 16(%[p_saved_ltp]) \n\t" - "sw $0, 20(%[p_saved_ltp]) \n\t" - "sw $0, 24(%[p_saved_ltp]) \n\t" - "sw $0, 28(%[p_saved_ltp]) \n\t" - PTR_ADDIU "%[p_saved_ltp],%[p_saved_ltp], 32 \n\t" - "bne %[p_saved_ltp], %[loop_end1], 1b \n\t" - - : [p_saved_ltp]"+r"(p_saved_ltp) - : [loop_end1]"r"(loop_end1) - : "memory" - ); - - ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64); - fmul_and_reverse(saved_ltp + 512, ac->buf_mdct + 960, swindow, 64); - } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { - float *buff0 = saved; - float *buff1 = saved_ltp; - float *loop_end = saved + 448; - - /* loop unrolled 8 times */ - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "1: \n\t" - "lw %[temp0], 0(%[src]) \n\t" - "lw %[temp1], 4(%[src]) \n\t" - "lw %[temp2], 8(%[src]) \n\t" - "lw %[temp3], 12(%[src]) \n\t" - "lw %[temp4], 16(%[src]) \n\t" - "lw %[temp5], 20(%[src]) \n\t" - "lw %[temp6], 24(%[src]) \n\t" - "lw %[temp7], 28(%[src]) \n\t" - PTR_ADDIU "%[src], %[src], 32 \n\t" - "sw %[temp0], 0(%[dst]) \n\t" - "sw %[temp1], 4(%[dst]) \n\t" - "sw %[temp2], 8(%[dst]) \n\t" - "sw %[temp3], 12(%[dst]) \n\t" - "sw %[temp4], 16(%[dst]) \n\t" - "sw %[temp5], 20(%[dst]) \n\t" - "sw %[temp6], 24(%[dst]) \n\t" - "sw %[temp7], 28(%[dst]) \n\t" - "sw $0, 2304(%[dst]) \n\t" - "sw $0, 2308(%[dst]) \n\t" - "sw $0, 2312(%[dst]) \n\t" - "sw $0, 2316(%[dst]) \n\t" - "sw $0, 2320(%[dst]) \n\t" - "sw $0, 2324(%[dst]) \n\t" - "sw $0, 2328(%[dst]) \n\t" - "sw $0, 2332(%[dst]) \n\t" - "bne %[src], %[loop_end], 1b \n\t" - PTR_ADDIU "%[dst], %[dst], 32 \n\t" - ".set pop \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), - [src]"+r"(buff0), [dst]"+r"(buff1) - : [loop_end]"r"(loop_end) - : "memory" - ); - ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64); - fmul_and_reverse(saved_ltp + 512, ac->buf_mdct + 960, swindow, 64); - } else { // LONG_STOP or ONLY_LONG - ac->fdsp->vector_fmul_reverse(saved_ltp, ac->buf_mdct + 512, &lwindow[512], 512); - fmul_and_reverse(saved_ltp + 512, ac->buf_mdct + 512, lwindow, 512); - } - - float_copy(sce->ltp_state, sce->ltp_state + 1024, 1024); - float_copy(sce->ltp_state + 1024, sce->ret, 1024); - float_copy(sce->ltp_state + 2048, saved_ltp, 1024); -} -#endif /* HAVE_MIPSFPU */ -#endif /* HAVE_INLINE_ASM */ - -void ff_aacdec_init_mips(AACDecContext *c) -{ -#if HAVE_INLINE_ASM -#if HAVE_MIPSFPU - c->imdct_and_windowing = imdct_and_windowing_mips; - c->apply_ltp = apply_ltp_mips; - c->update_ltp = update_ltp_mips; -#endif /* HAVE_MIPSFPU */ -#endif /* HAVE_INLINE_ASM */ -} diff --git a/libavcodec/mips/aacdec_mips.h b/libavcodec/mips/aacdec_mips.h deleted file mode 100644 index 71581986d..000000000 --- a/libavcodec/mips/aacdec_mips.h +++ /dev/null @@ -1,253 +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. - * - * Authors: Darko Laus (darko@mips.com) - * Djordje Pesut (djordje@mips.com) - * Mirjana Vulin (mvulin@mips.com) - * - * AAC Spectral Band Replication decoding functions optimized for MIPS - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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/aacdec.c - */ - -#ifndef AVCODEC_MIPS_AACDEC_MIPS_H -#define AVCODEC_MIPS_AACDEC_MIPS_H - -#include "libavcodec/aacdec.h" -#include "libavutil/mips/asmdefs.h" - -#if HAVE_INLINE_ASM && HAVE_MIPSFPU -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 -static inline float *VMUL2_mips(float *dst, const float *v, unsigned idx, - const float *scale) -{ - float temp0, temp1, temp2; - int temp3, temp4; - float *ret; - - __asm__ volatile( - "andi %[temp3], %[idx], 0x0F \n\t" - "andi %[temp4], %[idx], 0xF0 \n\t" - "sll %[temp3], %[temp3], 2 \n\t" - "srl %[temp4], %[temp4], 2 \n\t" - "lwc1 %[temp2], 0(%[scale]) \n\t" - "lwxc1 %[temp0], %[temp3](%[v]) \n\t" - "lwxc1 %[temp1], %[temp4](%[v]) \n\t" - "mul.s %[temp0], %[temp0], %[temp2] \n\t" - "mul.s %[temp1], %[temp1], %[temp2] \n\t" - PTR_ADDIU "%[ret], %[dst], 8 \n\t" - "swc1 %[temp0], 0(%[dst]) \n\t" - "swc1 %[temp1], 4(%[dst]) \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), - [temp2]"=&f"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [ret]"=&r"(ret) - : [idx]"r"(idx), [scale]"r"(scale), [v]"r"(v), - [dst]"r"(dst) - : "memory" - ); - return ret; -} - -static inline float *VMUL4_mips(float *dst, const float *v, unsigned idx, - const float *scale) -{ - int temp0, temp1, temp2, temp3; - float temp4, temp5, temp6, temp7, temp8; - float *ret; - - __asm__ volatile( - "andi %[temp0], %[idx], 0x03 \n\t" - "andi %[temp1], %[idx], 0x0C \n\t" - "andi %[temp2], %[idx], 0x30 \n\t" - "andi %[temp3], %[idx], 0xC0 \n\t" - "sll %[temp0], %[temp0], 2 \n\t" - "srl %[temp2], %[temp2], 2 \n\t" - "srl %[temp3], %[temp3], 4 \n\t" - "lwc1 %[temp4], 0(%[scale]) \n\t" - "lwxc1 %[temp5], %[temp0](%[v]) \n\t" - "lwxc1 %[temp6], %[temp1](%[v]) \n\t" - "lwxc1 %[temp7], %[temp2](%[v]) \n\t" - "lwxc1 %[temp8], %[temp3](%[v]) \n\t" - "mul.s %[temp5], %[temp5], %[temp4] \n\t" - "mul.s %[temp6], %[temp6], %[temp4] \n\t" - "mul.s %[temp7], %[temp7], %[temp4] \n\t" - "mul.s %[temp8], %[temp8], %[temp4] \n\t" - PTR_ADDIU "%[ret], %[dst], 16 \n\t" - "swc1 %[temp5], 0(%[dst]) \n\t" - "swc1 %[temp6], 4(%[dst]) \n\t" - "swc1 %[temp7], 8(%[dst]) \n\t" - "swc1 %[temp8], 12(%[dst]) \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), - [temp8]"=&f"(temp8), [ret]"=&r"(ret) - : [idx]"r"(idx), [scale]"r"(scale), [v]"r"(v), - [dst]"r"(dst) - : "memory" - ); - return ret; -} - -static inline float *VMUL2S_mips(float *dst, const float *v, unsigned idx, - unsigned sign, const float *scale) -{ - int temp0, temp1, temp2, temp3, temp4, temp5; - float temp6, temp7, temp8, temp9; - float *ret; - - __asm__ volatile( - "andi %[temp0], %[idx], 0x0F \n\t" - "andi %[temp1], %[idx], 0xF0 \n\t" - "lw %[temp4], 0(%[scale]) \n\t" - "srl %[temp2], %[sign], 1 \n\t" - "sll %[temp3], %[sign], 31 \n\t" - "sll %[temp2], %[temp2], 31 \n\t" - "sll %[temp0], %[temp0], 2 \n\t" - "srl %[temp1], %[temp1], 2 \n\t" - "lwxc1 %[temp8], %[temp0](%[v]) \n\t" - "lwxc1 %[temp9], %[temp1](%[v]) \n\t" - "xor %[temp5], %[temp4], %[temp2] \n\t" - "xor %[temp4], %[temp4], %[temp3] \n\t" - "mtc1 %[temp5], %[temp6] \n\t" - "mtc1 %[temp4], %[temp7] \n\t" - "mul.s %[temp8], %[temp8], %[temp6] \n\t" - "mul.s %[temp9], %[temp9], %[temp7] \n\t" - PTR_ADDIU "%[ret], %[dst], 8 \n\t" - "swc1 %[temp8], 0(%[dst]) \n\t" - "swc1 %[temp9], 4(%[dst]) \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), - [temp8]"=&f"(temp8), [temp9]"=&f"(temp9), - [ret]"=&r"(ret) - : [idx]"r"(idx), [scale]"r"(scale), [v]"r"(v), - [dst]"r"(dst), [sign]"r"(sign) - : "memory" - ); - return ret; -} - -static inline float *VMUL4S_mips(float *dst, const float *v, unsigned idx, - unsigned sign, const float *scale) -{ - int temp0, temp1, temp2, temp3, temp4; - float temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17; - float *ret; - unsigned int mask = 1U << 31; - - __asm__ volatile( - "lw %[temp0], 0(%[scale]) \n\t" - "andi %[temp1], %[idx], 0x03 \n\t" - "andi %[temp2], %[idx], 0x0C \n\t" - "andi %[temp3], %[idx], 0x30 \n\t" - "andi %[temp4], %[idx], 0xC0 \n\t" - "sll %[temp1], %[temp1], 2 \n\t" - "srl %[temp3], %[temp3], 2 \n\t" - "srl %[temp4], %[temp4], 4 \n\t" - "lwxc1 %[temp10], %[temp1](%[v]) \n\t" - "lwxc1 %[temp11], %[temp2](%[v]) \n\t" - "lwxc1 %[temp12], %[temp3](%[v]) \n\t" - "lwxc1 %[temp13], %[temp4](%[v]) \n\t" - "and %[temp1], %[sign], %[mask] \n\t" - "srl %[temp2], %[idx], 12 \n\t" - "srl %[temp3], %[idx], 13 \n\t" - "srl %[temp4], %[idx], 14 \n\t" - "andi %[temp2], %[temp2], 1 \n\t" - "andi %[temp3], %[temp3], 1 \n\t" - "andi %[temp4], %[temp4], 1 \n\t" - "sllv %[sign], %[sign], %[temp2] \n\t" - "xor %[temp1], %[temp0], %[temp1] \n\t" - "and %[temp2], %[sign], %[mask] \n\t" - "mtc1 %[temp1], %[temp14] \n\t" - "xor %[temp2], %[temp0], %[temp2] \n\t" - "sllv %[sign], %[sign], %[temp3] \n\t" - "mtc1 %[temp2], %[temp15] \n\t" - "and %[temp3], %[sign], %[mask] \n\t" - "sllv %[sign], %[sign], %[temp4] \n\t" - "xor %[temp3], %[temp0], %[temp3] \n\t" - "and %[temp4], %[sign], %[mask] \n\t" - "mtc1 %[temp3], %[temp16] \n\t" - "xor %[temp4], %[temp0], %[temp4] \n\t" - "mtc1 %[temp4], %[temp17] \n\t" - "mul.s %[temp10], %[temp10], %[temp14] \n\t" - "mul.s %[temp11], %[temp11], %[temp15] \n\t" - "mul.s %[temp12], %[temp12], %[temp16] \n\t" - "mul.s %[temp13], %[temp13], %[temp17] \n\t" - PTR_ADDIU "%[ret], %[dst], 16 \n\t" - "swc1 %[temp10], 0(%[dst]) \n\t" - "swc1 %[temp11], 4(%[dst]) \n\t" - "swc1 %[temp12], 8(%[dst]) \n\t" - "swc1 %[temp13], 12(%[dst]) \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp10]"=&f"(temp10), - [temp11]"=&f"(temp11), [temp12]"=&f"(temp12), - [temp13]"=&f"(temp13), [temp14]"=&f"(temp14), - [temp15]"=&f"(temp15), [temp16]"=&f"(temp16), - [temp17]"=&f"(temp17), [ret]"=&r"(ret), - [sign]"+r"(sign) - : [idx]"r"(idx), [scale]"r"(scale), [v]"r"(v), - [dst]"r"(dst), [mask]"r"(mask) - : "memory" - ); - return ret; -} - -#define VMUL2 VMUL2_mips -#define VMUL4 VMUL4_mips -#define VMUL2S VMUL2S_mips -#define VMUL4S VMUL4S_mips -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_INLINE_ASM && HAVE_MIPSFPU */ - -#endif /* AVCODEC_MIPS_AACDEC_MIPS_H */ diff --git a/libavcodec/mips/aacpsdsp_mips.c b/libavcodec/mips/aacpsdsp_mips.c deleted file mode 100644 index f63541330..000000000 --- a/libavcodec/mips/aacpsdsp_mips.c +++ /dev/null @@ -1,465 +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. - * - * Authors: Darko Laus (darko@mips.com) - * Djordje Pesut (djordje@mips.com) - * Mirjana Vulin (mvulin@mips.com) - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * Reference: libavcodec/aacpsdsp.c - */ - -#include "config.h" -#include "libavcodec/aacpsdsp.h" -#include "libavutil/mips/asmdefs.h" - -#if HAVE_INLINE_ASM -#if HAVE_MIPSFPU -static void ps_hybrid_analysis_ileave_mips(float (*out)[32][2], float L[2][38][64], - int i, int len) -{ - int temp0, temp1, temp2, temp3; - int temp4, temp5, temp6, temp7; - float *out1=&out[i][0][0]; - float *L1=&L[0][0][i]; - float *j=out1+ len*2; - - for (; i < 64; i++) { - - /* loop unrolled 8 times */ - __asm__ volatile ( - "1: \n\t" - "lw %[temp0], 0(%[L1]) \n\t" - "lw %[temp1], 9728(%[L1]) \n\t" - "lw %[temp2], 256(%[L1]) \n\t" - "lw %[temp3], 9984(%[L1]) \n\t" - "lw %[temp4], 512(%[L1]) \n\t" - "lw %[temp5], 10240(%[L1]) \n\t" - "lw %[temp6], 768(%[L1]) \n\t" - "lw %[temp7], 10496(%[L1]) \n\t" - "sw %[temp0], 0(%[out1]) \n\t" - "sw %[temp1], 4(%[out1]) \n\t" - "sw %[temp2], 8(%[out1]) \n\t" - "sw %[temp3], 12(%[out1]) \n\t" - "sw %[temp4], 16(%[out1]) \n\t" - "sw %[temp5], 20(%[out1]) \n\t" - "sw %[temp6], 24(%[out1]) \n\t" - "sw %[temp7], 28(%[out1]) \n\t" - PTR_ADDIU "%[out1], %[out1], 32 \n\t" - PTR_ADDIU "%[L1], %[L1], 1024 \n\t" - "bne %[out1], %[j], 1b \n\t" - - : [out1]"+r"(out1), [L1]"+r"(L1), [j]"+r"(j), - [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7) - : [len]"r"(len) - : "memory" - ); - out1-=(len<<1)-64; - L1-=(len<<6)-1; - j+=len*2; - } -} - -static void ps_hybrid_synthesis_deint_mips(float out[2][38][64], - float (*in)[32][2], - int i, int len) -{ - int n; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - float *out1 = (float*)out + i; - float *out2 = (float*)out + 2432 + i; - float *in1 = (float*)in + 64 * i; - float *in2 = (float*)in + 64 * i + 1; - - for (; i < 64; i++) { - for (n = 0; n < 7; n++) { - - /* loop unrolled 8 times */ - __asm__ volatile ( - "lw %[temp0], 0(%[in1]) \n\t" - "lw %[temp1], 0(%[in2]) \n\t" - "lw %[temp2], 8(%[in1]) \n\t" - "lw %[temp3], 8(%[in2]) \n\t" - "lw %[temp4], 16(%[in1]) \n\t" - "lw %[temp5], 16(%[in2]) \n\t" - "lw %[temp6], 24(%[in1]) \n\t" - "lw %[temp7], 24(%[in2]) \n\t" - PTR_ADDIU "%[out1], %[out1], 1024 \n\t" - PTR_ADDIU "%[out2], %[out2], 1024 \n\t" - PTR_ADDIU "%[in1], %[in1], 32 \n\t" - PTR_ADDIU "%[in2], %[in2], 32 \n\t" - "sw %[temp0], -1024(%[out1]) \n\t" - "sw %[temp1], -1024(%[out2]) \n\t" - "sw %[temp2], -768(%[out1]) \n\t" - "sw %[temp3], -768(%[out2]) \n\t" - "sw %[temp4], -512(%[out1]) \n\t" - "sw %[temp5], -512(%[out2]) \n\t" - "sw %[temp6], -256(%[out1]) \n\t" - "sw %[temp7], -256(%[out2]) \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), - [out1]"+r"(out1), [out2]"+r"(out2), - [in1]"+r"(in1), [in2]"+r"(in2) - : - : "memory" - ); - } - /* loop unrolled 8 times */ - __asm__ volatile ( - "lw %[temp0], 0(%[in1]) \n\t" - "lw %[temp1], 0(%[in2]) \n\t" - "lw %[temp2], 8(%[in1]) \n\t" - "lw %[temp3], 8(%[in2]) \n\t" - "lw %[temp4], 16(%[in1]) \n\t" - "lw %[temp5], 16(%[in2]) \n\t" - "lw %[temp6], 24(%[in1]) \n\t" - "lw %[temp7], 24(%[in2]) \n\t" - PTR_ADDIU "%[out1], %[out1], -7164 \n\t" - PTR_ADDIU "%[out2], %[out2], -7164 \n\t" - PTR_ADDIU "%[in1], %[in1], 32 \n\t" - PTR_ADDIU "%[in2], %[in2], 32 \n\t" - "sw %[temp0], 7164(%[out1]) \n\t" - "sw %[temp1], 7164(%[out2]) \n\t" - "sw %[temp2], 7420(%[out1]) \n\t" - "sw %[temp3], 7420(%[out2]) \n\t" - "sw %[temp4], 7676(%[out1]) \n\t" - "sw %[temp5], 7676(%[out2]) \n\t" - "sw %[temp6], 7932(%[out1]) \n\t" - "sw %[temp7], 7932(%[out2]) \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), - [out1]"+r"(out1), [out2]"+r"(out2), - [in1]"+r"(in1), [in2]"+r"(in2) - : - : "memory" - ); - } -} - -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 -static void ps_add_squares_mips(float *dst, const float (*src)[2], int n) -{ - int i; - float temp0, temp1, temp2, temp3, temp4, temp5; - float temp6, temp7, temp8, temp9, temp10, temp11; - float *src0 = (float*)&src[0][0]; - float *dst0 = &dst[0]; - - for (i = 0; i < 8; i++) { - /* loop unrolled 4 times */ - __asm__ volatile ( - "lwc1 %[temp0], 0(%[src0]) \n\t" - "lwc1 %[temp1], 4(%[src0]) \n\t" - "lwc1 %[temp2], 8(%[src0]) \n\t" - "lwc1 %[temp3], 12(%[src0]) \n\t" - "lwc1 %[temp4], 16(%[src0]) \n\t" - "lwc1 %[temp5], 20(%[src0]) \n\t" - "lwc1 %[temp6], 24(%[src0]) \n\t" - "lwc1 %[temp7], 28(%[src0]) \n\t" - "lwc1 %[temp8], 0(%[dst0]) \n\t" - "lwc1 %[temp9], 4(%[dst0]) \n\t" - "lwc1 %[temp10], 8(%[dst0]) \n\t" - "lwc1 %[temp11], 12(%[dst0]) \n\t" - "mul.s %[temp1], %[temp1], %[temp1] \n\t" - "mul.s %[temp3], %[temp3], %[temp3] \n\t" - "mul.s %[temp5], %[temp5], %[temp5] \n\t" - "mul.s %[temp7], %[temp7], %[temp7] \n\t" - "madd.s %[temp0], %[temp1], %[temp0], %[temp0] \n\t" - "madd.s %[temp2], %[temp3], %[temp2], %[temp2] \n\t" - "madd.s %[temp4], %[temp5], %[temp4], %[temp4] \n\t" - "madd.s %[temp6], %[temp7], %[temp6], %[temp6] \n\t" - "add.s %[temp0], %[temp8], %[temp0] \n\t" - "add.s %[temp2], %[temp9], %[temp2] \n\t" - "add.s %[temp4], %[temp10], %[temp4] \n\t" - "add.s %[temp6], %[temp11], %[temp6] \n\t" - "swc1 %[temp0], 0(%[dst0]) \n\t" - "swc1 %[temp2], 4(%[dst0]) \n\t" - "swc1 %[temp4], 8(%[dst0]) \n\t" - "swc1 %[temp6], 12(%[dst0]) \n\t" - PTR_ADDIU "%[dst0], %[dst0], 16 \n\t" - PTR_ADDIU "%[src0], %[src0], 32 \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8), - [temp9]"=&f"(temp9), [dst0]"+r"(dst0), [src0]"+r"(src0), - [temp10]"=&f"(temp10), [temp11]"=&f"(temp11) - : - : "memory" - ); - } -} - -static void ps_mul_pair_single_mips(float (*dst)[2], float (*src0)[2], float *src1, - int n) -{ - float temp0, temp1, temp2; - float *p_d, *p_s0, *p_s1, *end; - p_d = &dst[0][0]; - p_s0 = &src0[0][0]; - p_s1 = &src1[0]; - end = p_s1 + n; - - __asm__ volatile( - ".set push \n\t" - ".set noreorder \n\t" - "1: \n\t" - "lwc1 %[temp2], 0(%[p_s1]) \n\t" - "lwc1 %[temp0], 0(%[p_s0]) \n\t" - "lwc1 %[temp1], 4(%[p_s0]) \n\t" - PTR_ADDIU "%[p_d], %[p_d], 8 \n\t" - "mul.s %[temp0], %[temp0], %[temp2] \n\t" - "mul.s %[temp1], %[temp1], %[temp2] \n\t" - PTR_ADDIU "%[p_s0], %[p_s0], 8 \n\t" - "swc1 %[temp0], -8(%[p_d]) \n\t" - "swc1 %[temp1], -4(%[p_d]) \n\t" - "bne %[p_s1], %[end], 1b \n\t" - PTR_ADDIU "%[p_s1], %[p_s1], 4 \n\t" - ".set pop \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), - [temp2]"=&f"(temp2), [p_d]"+r"(p_d), - [p_s0]"+r"(p_s0), [p_s1]"+r"(p_s1) - : [end]"r"(end) - : "memory" - ); -} - -static void ps_decorrelate_mips(float (*out)[2], float (*delay)[2], - float (*ap_delay)[PS_QMF_TIME_SLOTS + PS_MAX_AP_DELAY][2], - const float phi_fract[2], const float (*Q_fract)[2], - const float *transient_gain, - float g_decay_slope, - int len) -{ - float *p_delay = &delay[0][0]; - float *p_out = &out[0][0]; - float *p_ap_delay = &ap_delay[0][0][0]; - const float *p_t_gain = transient_gain; - const float *p_Q_fract = &Q_fract[0][0]; - float ag0, ag1, ag2; - float phi_fract0 = phi_fract[0]; - float phi_fract1 = phi_fract[1]; - float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9; - float f1, f2, f3; - - float *p_delay_end = (p_delay + (len << 1)); - - /* merged 2 loops */ - f1 = 0.65143905753106; - f2 = 0.56471812200776; - f3 = 0.48954165955695; - __asm__ volatile( - ".set push \n\t" - ".set noreorder \n\t" - "mul.s %[ag0], %[ag0], %[g_decay_slope] \n\t" - "mul.s %[ag1], %[ag1], %[g_decay_slope] \n\t" - "mul.s %[ag2], %[ag2], %[g_decay_slope] \n\t" - "1: \n\t" - "lwc1 %[temp0], 0(%[p_delay]) \n\t" - "lwc1 %[temp1], 4(%[p_delay]) \n\t" - "lwc1 %[temp4], 16(%[p_ap_delay]) \n\t" - "lwc1 %[temp5], 20(%[p_ap_delay]) \n\t" - "mul.s %[temp3], %[temp0], %[phi_fract1] \n\t" - "lwc1 %[temp6], 0(%[p_Q_fract]) \n\t" - "mul.s %[temp2], %[temp1], %[phi_fract1] \n\t" - "lwc1 %[temp7], 4(%[p_Q_fract]) \n\t" - "madd.s %[temp3], %[temp3], %[temp1], %[phi_fract0] \n\t" - "msub.s %[temp2], %[temp2], %[temp0], %[phi_fract0] \n\t" - "mul.s %[temp8], %[temp5], %[temp7] \n\t" - "mul.s %[temp9], %[temp4], %[temp7] \n\t" - "lwc1 %[temp7], 12(%[p_Q_fract]) \n\t" - "mul.s %[temp0], %[ag0], %[temp2] \n\t" - "mul.s %[temp1], %[ag0], %[temp3] \n\t" - "msub.s %[temp8], %[temp8], %[temp4], %[temp6] \n\t" - "lwc1 %[temp4], 304(%[p_ap_delay]) \n\t" - "madd.s %[temp9], %[temp9], %[temp5], %[temp6] \n\t" - "lwc1 %[temp5], 308(%[p_ap_delay]) \n\t" - "sub.s %[temp0], %[temp8], %[temp0] \n\t" - "sub.s %[temp1], %[temp9], %[temp1] \n\t" - "madd.s %[temp2], %[temp2], %[ag0], %[temp0] \n\t" - "lwc1 %[temp6], 8(%[p_Q_fract]) \n\t" - "madd.s %[temp3], %[temp3], %[ag0], %[temp1] \n\t" - "mul.s %[temp8], %[temp5], %[temp7] \n\t" - "mul.s %[temp9], %[temp4], %[temp7] \n\t" - "lwc1 %[temp7], 20(%[p_Q_fract]) \n\t" - "msub.s %[temp8], %[temp8], %[temp4], %[temp6] \n\t" - "swc1 %[temp2], 40(%[p_ap_delay]) \n\t" - "mul.s %[temp2], %[ag1], %[temp0] \n\t" - "swc1 %[temp3], 44(%[p_ap_delay]) \n\t" - "mul.s %[temp3], %[ag1], %[temp1] \n\t" - "lwc1 %[temp4], 592(%[p_ap_delay]) \n\t" - "madd.s %[temp9], %[temp9], %[temp5], %[temp6] \n\t" - "lwc1 %[temp5], 596(%[p_ap_delay]) \n\t" - "sub.s %[temp2], %[temp8], %[temp2] \n\t" - "sub.s %[temp3], %[temp9], %[temp3] \n\t" - "lwc1 %[temp6], 16(%[p_Q_fract]) \n\t" - "madd.s %[temp0], %[temp0], %[ag1], %[temp2] \n\t" - "madd.s %[temp1], %[temp1], %[ag1], %[temp3] \n\t" - "mul.s %[temp8], %[temp5], %[temp7] \n\t" - "mul.s %[temp9], %[temp4], %[temp7] \n\t" - "msub.s %[temp8], %[temp8], %[temp4], %[temp6] \n\t" - "madd.s %[temp9], %[temp9], %[temp5], %[temp6] \n\t" - "swc1 %[temp0], 336(%[p_ap_delay]) \n\t" - "mul.s %[temp0], %[ag2], %[temp2] \n\t" - "swc1 %[temp1], 340(%[p_ap_delay]) \n\t" - "mul.s %[temp1], %[ag2], %[temp3] \n\t" - "lwc1 %[temp4], 0(%[p_t_gain]) \n\t" - "sub.s %[temp0], %[temp8], %[temp0] \n\t" - PTR_ADDIU "%[p_ap_delay], %[p_ap_delay], 8 \n\t" - "sub.s %[temp1], %[temp9], %[temp1] \n\t" - PTR_ADDIU "%[p_t_gain], %[p_t_gain], 4 \n\t" - "madd.s %[temp2], %[temp2], %[ag2], %[temp0] \n\t" - PTR_ADDIU "%[p_delay], %[p_delay], 8 \n\t" - "madd.s %[temp3], %[temp3], %[ag2], %[temp1] \n\t" - PTR_ADDIU "%[p_out], %[p_out], 8 \n\t" - "mul.s %[temp5], %[temp4], %[temp0] \n\t" - "mul.s %[temp6], %[temp4], %[temp1] \n\t" - "swc1 %[temp2], 624(%[p_ap_delay]) \n\t" - "swc1 %[temp3], 628(%[p_ap_delay]) \n\t" - "swc1 %[temp5], -8(%[p_out]) \n\t" - "swc1 %[temp6], -4(%[p_out]) \n\t" - "bne %[p_delay], %[p_delay_end],1b \n\t" - " swc1 %[temp6], -4(%[p_out]) \n\t" - ".set pop \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8), - [temp9]"=&f"(temp9), [p_delay]"+r"(p_delay), [p_ap_delay]"+r"(p_ap_delay), - [p_Q_fract]"+r"(p_Q_fract), [p_t_gain]"+r"(p_t_gain), [p_out]"+r"(p_out) - : [phi_fract0]"f"(phi_fract0), [phi_fract1]"f"(phi_fract1), - [p_delay_end]"r"(p_delay_end), [g_decay_slope]"f"(g_decay_slope), - [ag0]"f"(f1), [ag1]"f"(f2), [ag2]"f"(f3) - : "memory" - ); -} - -static void ps_stereo_interpolate_mips(float (*l)[2], float (*r)[2], - float h[2][4], float h_step[2][4], - int len) -{ - float h0 = h[0][0]; - float h1 = h[0][1]; - float h2 = h[0][2]; - float h3 = h[0][3]; - float hs0 = h_step[0][0]; - float hs1 = h_step[0][1]; - float hs2 = h_step[0][2]; - float hs3 = h_step[0][3]; - float temp0, temp1, temp2, temp3; - float l_re, l_im, r_re, r_im; - - float *l_end = ((float *)l + (len << 1)); - - __asm__ volatile( - ".set push \n\t" - ".set noreorder \n\t" - "1: \n\t" - "add.s %[h0], %[h0], %[hs0] \n\t" - "lwc1 %[l_re], 0(%[l]) \n\t" - "add.s %[h1], %[h1], %[hs1] \n\t" - "lwc1 %[r_re], 0(%[r]) \n\t" - "add.s %[h2], %[h2], %[hs2] \n\t" - "lwc1 %[l_im], 4(%[l]) \n\t" - "add.s %[h3], %[h3], %[hs3] \n\t" - "lwc1 %[r_im], 4(%[r]) \n\t" - "mul.s %[temp0], %[h0], %[l_re] \n\t" - PTR_ADDIU "%[l], %[l], 8 \n\t" - "mul.s %[temp2], %[h1], %[l_re] \n\t" - PTR_ADDIU "%[r], %[r], 8 \n\t" - "madd.s %[temp0], %[temp0], %[h2], %[r_re] \n\t" - "madd.s %[temp2], %[temp2], %[h3], %[r_re] \n\t" - "mul.s %[temp1], %[h0], %[l_im] \n\t" - "mul.s %[temp3], %[h1], %[l_im] \n\t" - "madd.s %[temp1], %[temp1], %[h2], %[r_im] \n\t" - "madd.s %[temp3], %[temp3], %[h3], %[r_im] \n\t" - "swc1 %[temp0], -8(%[l]) \n\t" - "swc1 %[temp2], -8(%[r]) \n\t" - "swc1 %[temp1], -4(%[l]) \n\t" - "bne %[l], %[l_end], 1b \n\t" - " swc1 %[temp3], -4(%[r]) \n\t" - ".set pop \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), - [temp2]"=&f"(temp2), [temp3]"=&f"(temp3), - [h0]"+f"(h0), [h1]"+f"(h1), [h2]"+f"(h2), - [h3]"+f"(h3), [l]"+r"(l), [r]"+r"(r), - [l_re]"=&f"(l_re), [l_im]"=&f"(l_im), - [r_re]"=&f"(r_re), [r_im]"=&f"(r_im) - : [hs0]"f"(hs0), [hs1]"f"(hs1), [hs2]"f"(hs2), - [hs3]"f"(hs3), [l_end]"r"(l_end) - : "memory" - ); -} -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_MIPSFPU */ -#endif /* HAVE_INLINE_ASM */ - -void ff_psdsp_init_mips(PSDSPContext *s) -{ -#if HAVE_INLINE_ASM -#if HAVE_MIPSFPU - s->hybrid_analysis_ileave = ps_hybrid_analysis_ileave_mips; - s->hybrid_synthesis_deint = ps_hybrid_synthesis_deint_mips; -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 - s->add_squares = ps_add_squares_mips; - s->mul_pair_single = ps_mul_pair_single_mips; - s->decorrelate = ps_decorrelate_mips; - s->stereo_interpolate[0] = ps_stereo_interpolate_mips; -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_MIPSFPU */ -#endif /* HAVE_INLINE_ASM */ -} diff --git a/libavcodec/mips/aacpsy_mips.h b/libavcodec/mips/aacpsy_mips.h deleted file mode 100644 index 7d27d32f1..000000000 --- a/libavcodec/mips/aacpsy_mips.h +++ /dev/null @@ -1,238 +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) - * - * AAC encoder psychoacoustic model routines 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/aacpsy.c - */ - -#ifndef AVCODEC_MIPS_AACPSY_MIPS_H -#define AVCODEC_MIPS_AACPSY_MIPS_H - -#include "libavutil/mips/asmdefs.h" - -#if HAVE_INLINE_ASM && HAVE_MIPSFPU && ( PSY_LAME_FIR_LEN == 21 ) -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 -static void calc_thr_3gpp_mips(const FFPsyWindowInfo *wi, const int num_bands, - AacPsyChannel *pch, const uint8_t *band_sizes, - const float *coefs, const int cutoff) -{ - int i, w, g; - int start = 0, wstart = 0; - for (w = 0; w < wi->num_windows*16; w += 16) { - wstart = 0; - for (g = 0; g < num_bands; g++) { - AacPsyBand *band = &pch->band[w+g]; - - float form_factor = 0.0f; - float Temp; - band->energy = 0.0f; - if (wstart < cutoff) { - for (i = 0; i < band_sizes[g]; i+=4) { - float a, b, c, d; - float ax, bx, cx, dx; - float *cf = (float *)&coefs[start+i]; - - __asm__ volatile ( - "lwc1 %[a], 0(%[cf]) \n\t" - "lwc1 %[b], 4(%[cf]) \n\t" - "lwc1 %[c], 8(%[cf]) \n\t" - "lwc1 %[d], 12(%[cf]) \n\t" - "abs.s %[a], %[a] \n\t" - "abs.s %[b], %[b] \n\t" - "abs.s %[c], %[c] \n\t" - "abs.s %[d], %[d] \n\t" - "sqrt.s %[ax], %[a] \n\t" - "sqrt.s %[bx], %[b] \n\t" - "sqrt.s %[cx], %[c] \n\t" - "sqrt.s %[dx], %[d] \n\t" - "madd.s %[e], %[e], %[a], %[a] \n\t" - "madd.s %[e], %[e], %[b], %[b] \n\t" - "madd.s %[e], %[e], %[c], %[c] \n\t" - "madd.s %[e], %[e], %[d], %[d] \n\t" - "add.s %[f], %[f], %[ax] \n\t" - "add.s %[f], %[f], %[bx] \n\t" - "add.s %[f], %[f], %[cx] \n\t" - "add.s %[f], %[f], %[dx] \n\t" - - : [a]"=&f"(a), [b]"=&f"(b), - [c]"=&f"(c), [d]"=&f"(d), - [e]"+f"(band->energy), [f]"+f"(form_factor), - [ax]"=&f"(ax), [bx]"=&f"(bx), - [cx]"=&f"(cx), [dx]"=&f"(dx) - : [cf]"r"(cf) - : "memory" - ); - } - } - - Temp = sqrtf((float)band_sizes[g] / band->energy); - band->thr = band->energy * 0.001258925f; - band->nz_lines = form_factor * sqrtf(Temp); - start += band_sizes[g]; - wstart += band_sizes[g]; - } - } -} - -static void psy_hp_filter_mips(const float *firbuf, float *hpfsmpl, const float * psy_fir_coeffs) -{ - float sum1, sum2, sum3, sum4; - float *fb = (float*)firbuf; - float *fb_end = fb + AAC_BLOCK_SIZE_LONG; - float *hp = hpfsmpl; - - float coeff0 = psy_fir_coeffs[1]; - float coeff1 = psy_fir_coeffs[3]; - float coeff2 = psy_fir_coeffs[5]; - float coeff3 = psy_fir_coeffs[7]; - float coeff4 = psy_fir_coeffs[9]; - - float f1 = 32768.0; - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - - "1: \n\t" - "lwc1 $f0, 40(%[fb]) \n\t" - "lwc1 $f1, 4(%[fb]) \n\t" - "lwc1 $f2, 80(%[fb]) \n\t" - "lwc1 $f3, 44(%[fb]) \n\t" - "lwc1 $f4, 8(%[fb]) \n\t" - "madd.s %[sum1], $f0, $f1, %[coeff0] \n\t" - "lwc1 $f5, 84(%[fb]) \n\t" - "lwc1 $f6, 48(%[fb]) \n\t" - "madd.s %[sum2], $f3, $f4, %[coeff0] \n\t" - "lwc1 $f7, 12(%[fb]) \n\t" - "madd.s %[sum1], %[sum1], $f2, %[coeff0] \n\t" - "lwc1 $f8, 88(%[fb]) \n\t" - "lwc1 $f9, 52(%[fb]) \n\t" - "madd.s %[sum2], %[sum2], $f5, %[coeff0] \n\t" - "madd.s %[sum3], $f6, $f7, %[coeff0] \n\t" - "lwc1 $f10, 16(%[fb]) \n\t" - "lwc1 $f11, 92(%[fb]) \n\t" - "madd.s %[sum1], %[sum1], $f7, %[coeff1] \n\t" - "lwc1 $f1, 72(%[fb]) \n\t" - "madd.s %[sum3], %[sum3], $f8, %[coeff0] \n\t" - "madd.s %[sum4], $f9, $f10, %[coeff0] \n\t" - "madd.s %[sum2], %[sum2], $f10, %[coeff1] \n\t" - "madd.s %[sum1], %[sum1], $f1, %[coeff1] \n\t" - "lwc1 $f4, 76(%[fb]) \n\t" - "lwc1 $f8, 20(%[fb]) \n\t" - "madd.s %[sum4], %[sum4], $f11, %[coeff0] \n\t" - "lwc1 $f11, 24(%[fb]) \n\t" - "madd.s %[sum2], %[sum2], $f4, %[coeff1] \n\t" - "madd.s %[sum1], %[sum1], $f8, %[coeff2] \n\t" - "madd.s %[sum3], %[sum3], $f8, %[coeff1] \n\t" - "madd.s %[sum4], %[sum4], $f11, %[coeff1] \n\t" - "lwc1 $f7, 64(%[fb]) \n\t" - "madd.s %[sum2], %[sum2], $f11, %[coeff2] \n\t" - "lwc1 $f10, 68(%[fb]) \n\t" - "madd.s %[sum3], %[sum3], $f2, %[coeff1] \n\t" - "madd.s %[sum4], %[sum4], $f5, %[coeff1] \n\t" - "madd.s %[sum1], %[sum1], $f7, %[coeff2] \n\t" - "madd.s %[sum2], %[sum2], $f10, %[coeff2] \n\t" - "lwc1 $f2, 28(%[fb]) \n\t" - "lwc1 $f5, 32(%[fb]) \n\t" - "lwc1 $f8, 56(%[fb]) \n\t" - "lwc1 $f11, 60(%[fb]) \n\t" - "madd.s %[sum3], %[sum3], $f2, %[coeff2] \n\t" - "madd.s %[sum4], %[sum4], $f5, %[coeff2] \n\t" - "madd.s %[sum1], %[sum1], $f2, %[coeff3] \n\t" - "madd.s %[sum2], %[sum2], $f5, %[coeff3] \n\t" - "madd.s %[sum3], %[sum3], $f1, %[coeff2] \n\t" - "madd.s %[sum4], %[sum4], $f4, %[coeff2] \n\t" - "madd.s %[sum1], %[sum1], $f8, %[coeff3] \n\t" - "madd.s %[sum2], %[sum2], $f11, %[coeff3] \n\t" - "lwc1 $f1, 36(%[fb]) \n\t" - PTR_ADDIU "%[fb], %[fb], 16 \n\t" - "madd.s %[sum4], %[sum4], $f0, %[coeff3] \n\t" - "madd.s %[sum3], %[sum3], $f1, %[coeff3] \n\t" - "madd.s %[sum1], %[sum1], $f1, %[coeff4] \n\t" - "madd.s %[sum2], %[sum2], $f0, %[coeff4] \n\t" - "madd.s %[sum4], %[sum4], $f10, %[coeff3] \n\t" - "madd.s %[sum3], %[sum3], $f7, %[coeff3] \n\t" - "madd.s %[sum1], %[sum1], $f6, %[coeff4] \n\t" - "madd.s %[sum2], %[sum2], $f9, %[coeff4] \n\t" - "madd.s %[sum4], %[sum4], $f6, %[coeff4] \n\t" - "madd.s %[sum3], %[sum3], $f3, %[coeff4] \n\t" - "mul.s %[sum1], %[sum1], %[f1] \n\t" - "mul.s %[sum2], %[sum2], %[f1] \n\t" - "madd.s %[sum4], %[sum4], $f11, %[coeff4] \n\t" - "madd.s %[sum3], %[sum3], $f8, %[coeff4] \n\t" - "swc1 %[sum1], 0(%[hp]) \n\t" - "swc1 %[sum2], 4(%[hp]) \n\t" - "mul.s %[sum4], %[sum4], %[f1] \n\t" - "mul.s %[sum3], %[sum3], %[f1] \n\t" - "swc1 %[sum4], 12(%[hp]) \n\t" - "swc1 %[sum3], 8(%[hp]) \n\t" - "bne %[fb], %[fb_end], 1b \n\t" - PTR_ADDIU "%[hp], %[hp], 16 \n\t" - - ".set pop \n\t" - - : [sum1]"=&f"(sum1), [sum2]"=&f"(sum2), - [sum3]"=&f"(sum3), [sum4]"=&f"(sum4), - [fb]"+r"(fb), [hp]"+r"(hp) - : [coeff0]"f"(coeff0), [coeff1]"f"(coeff1), - [coeff2]"f"(coeff2), [coeff3]"f"(coeff3), - [coeff4]"f"(coeff4), [fb_end]"r"(fb_end), [f1]"f"(f1) - : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", - "$f7", "$f8", "$f9", "$f10", "$f11", - "memory" - ); -} - -#define calc_thr_3gpp calc_thr_3gpp_mips -#define psy_hp_filter psy_hp_filter_mips - -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_INLINE_ASM && HAVE_MIPSFPU */ -#endif /* AVCODEC_MIPS_AACPSY_MIPS_H */ diff --git a/libavcodec/mips/aacsbr_mips.c b/libavcodec/mips/aacsbr_mips.c deleted file mode 100644 index e0715491e..000000000 --- a/libavcodec/mips/aacsbr_mips.c +++ /dev/null @@ -1,624 +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. - * - * Authors: Djordje Pesut (djordje@mips.com) - * Mirjana Vulin (mvulin@mips.com) - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * Reference: libavcodec/aacsbr.c - */ - -#include "libavcodec/aacdec.h" -#include "libavcodec/aacsbr.h" -#include "libavutil/mem_internal.h" -#include "libavutil/mips/asmdefs.h" - -#define ENVELOPE_ADJUSTMENT_OFFSET 2 - -#if HAVE_INLINE_ASM -#if HAVE_MIPSFPU -static int sbr_lf_gen_mips(SpectralBandReplication *sbr, - float X_low[32][40][2], const float W[2][32][32][2], - int buf_idx) -{ - int i, k; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - float *p_x_low = &X_low[0][8][0]; - float *p_w = (float*)&W[buf_idx][0][0][0]; - float *p_x1_low = &X_low[0][0][0]; - float *p_w1 = (float*)&W[1-buf_idx][24][0][0]; - - float *loop_end=p_x1_low + 2560; - - /* loop unrolled 8 times */ - __asm__ volatile ( - "1: \n\t" - "sw $0, 0(%[p_x1_low]) \n\t" - "sw $0, 4(%[p_x1_low]) \n\t" - "sw $0, 8(%[p_x1_low]) \n\t" - "sw $0, 12(%[p_x1_low]) \n\t" - "sw $0, 16(%[p_x1_low]) \n\t" - "sw $0, 20(%[p_x1_low]) \n\t" - "sw $0, 24(%[p_x1_low]) \n\t" - "sw $0, 28(%[p_x1_low]) \n\t" - PTR_ADDIU "%[p_x1_low],%[p_x1_low], 32 \n\t" - "bne %[p_x1_low], %[loop_end], 1b \n\t" - PTR_ADDIU "%[p_x1_low],%[p_x1_low], -10240 \n\t" - - : [p_x1_low]"+r"(p_x1_low) - : [loop_end]"r"(loop_end) - : "memory" - ); - - for (k = 0; k < sbr->kx[1]; k++) { - for (i = 0; i < 32; i+=4) { - /* loop unrolled 4 times */ - __asm__ volatile ( - "lw %[temp0], 0(%[p_w]) \n\t" - "lw %[temp1], 4(%[p_w]) \n\t" - "lw %[temp2], 256(%[p_w]) \n\t" - "lw %[temp3], 260(%[p_w]) \n\t" - "lw %[temp4], 512(%[p_w]) \n\t" - "lw %[temp5], 516(%[p_w]) \n\t" - "lw %[temp6], 768(%[p_w]) \n\t" - "lw %[temp7], 772(%[p_w]) \n\t" - "sw %[temp0], 0(%[p_x_low]) \n\t" - "sw %[temp1], 4(%[p_x_low]) \n\t" - "sw %[temp2], 8(%[p_x_low]) \n\t" - "sw %[temp3], 12(%[p_x_low]) \n\t" - "sw %[temp4], 16(%[p_x_low]) \n\t" - "sw %[temp5], 20(%[p_x_low]) \n\t" - "sw %[temp6], 24(%[p_x_low]) \n\t" - "sw %[temp7], 28(%[p_x_low]) \n\t" - PTR_ADDIU "%[p_x_low], %[p_x_low], 32 \n\t" - PTR_ADDIU "%[p_w], %[p_w], 1024 \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), - [p_w]"+r"(p_w), [p_x_low]"+r"(p_x_low) - : - : "memory" - ); - } - p_x_low += 16; - p_w -= 2046; - } - - for (k = 0; k < sbr->kx[0]; k++) { - for (i = 0; i < 2; i++) { - - /* loop unrolled 4 times */ - __asm__ volatile ( - "lw %[temp0], 0(%[p_w1]) \n\t" - "lw %[temp1], 4(%[p_w1]) \n\t" - "lw %[temp2], 256(%[p_w1]) \n\t" - "lw %[temp3], 260(%[p_w1]) \n\t" - "lw %[temp4], 512(%[p_w1]) \n\t" - "lw %[temp5], 516(%[p_w1]) \n\t" - "lw %[temp6], 768(%[p_w1]) \n\t" - "lw %[temp7], 772(%[p_w1]) \n\t" - "sw %[temp0], 0(%[p_x1_low]) \n\t" - "sw %[temp1], 4(%[p_x1_low]) \n\t" - "sw %[temp2], 8(%[p_x1_low]) \n\t" - "sw %[temp3], 12(%[p_x1_low]) \n\t" - "sw %[temp4], 16(%[p_x1_low]) \n\t" - "sw %[temp5], 20(%[p_x1_low]) \n\t" - "sw %[temp6], 24(%[p_x1_low]) \n\t" - "sw %[temp7], 28(%[p_x1_low]) \n\t" - PTR_ADDIU "%[p_x1_low], %[p_x1_low], 32 \n\t" - PTR_ADDIU "%[p_w1], %[p_w1], 1024 \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), - [p_w1]"+r"(p_w1), [p_x1_low]"+r"(p_x1_low) - : - : "memory" - ); - } - p_x1_low += 64; - p_w1 -= 510; - } - return 0; -} - -static int sbr_x_gen_mips(SpectralBandReplication *sbr, float X[2][38][64], - const float Y0[38][64][2], const float Y1[38][64][2], - const float X_low[32][40][2], int ch) -{ - int k, i; - const int i_f = 32; - int temp0, temp1, temp2, temp3; - const float *X_low1, *Y01, *Y11; - float *x1=&X[0][0][0]; - float *j=x1+4864; - const int i_Temp = FFMAX(2*sbr->data[ch].t_env_num_env_old - i_f, 0); - - /* loop unrolled 8 times */ - __asm__ volatile ( - "1: \n\t" - "sw $0, 0(%[x1]) \n\t" - "sw $0, 4(%[x1]) \n\t" - "sw $0, 8(%[x1]) \n\t" - "sw $0, 12(%[x1]) \n\t" - "sw $0, 16(%[x1]) \n\t" - "sw $0, 20(%[x1]) \n\t" - "sw $0, 24(%[x1]) \n\t" - "sw $0, 28(%[x1]) \n\t" - PTR_ADDIU "%[x1],%[x1], 32 \n\t" - "bne %[x1], %[j], 1b \n\t" - PTR_ADDIU "%[x1],%[x1], -19456 \n\t" - - : [x1]"+r"(x1) - : [j]"r"(j) - : "memory" - ); - - if (i_Temp != 0) { - - X_low1=&X_low[0][2][0]; - - for (k = 0; k < sbr->kx[0]; k++) { - - __asm__ volatile ( - "move %[i], $zero \n\t" - "2: \n\t" - "lw %[temp0], 0(%[X_low1]) \n\t" - "lw %[temp1], 4(%[X_low1]) \n\t" - "sw %[temp0], 0(%[x1]) \n\t" - "sw %[temp1], 9728(%[x1]) \n\t" - PTR_ADDIU "%[x1], %[x1], 256 \n\t" - PTR_ADDIU "%[X_low1], %[X_low1], 8 \n\t" - "addiu %[i], %[i], 1 \n\t" - "bne %[i], %[i_Temp], 2b \n\t" - - : [x1]"+r"(x1), [X_low1]"+r"(X_low1), [i]"=&r"(i), - [temp0]"=&r"(temp0), [temp1]"=&r"(temp1) - : [i_Temp]"r"(i_Temp) - : "memory" - ); - x1-=(i_Temp<<6)-1; - X_low1-=(i_Temp<<1)-80; - } - - x1=&X[0][0][k]; - Y01=(float*)&Y0[32][k][0]; - - for (; k < sbr->kx[0] + sbr->m[0]; k++) { - __asm__ volatile ( - "move %[i], $zero \n\t" - "3: \n\t" - "lw %[temp0], 0(%[Y01]) \n\t" - "lw %[temp1], 4(%[Y01]) \n\t" - "sw %[temp0], 0(%[x1]) \n\t" - "sw %[temp1], 9728(%[x1]) \n\t" - PTR_ADDIU "%[x1], %[x1], 256 \n\t" - PTR_ADDIU "%[Y01], %[Y01], 512 \n\t" - "addiu %[i], %[i], 1 \n\t" - "bne %[i], %[i_Temp], 3b \n\t" - - : [x1]"+r"(x1), [Y01]"+r"(Y01), [i]"=&r"(i), - [temp0]"=&r"(temp0), [temp1]"=&r"(temp1) - : [i_Temp]"r"(i_Temp) - : "memory" - ); - x1 -=(i_Temp<<6)-1; - Y01 -=(i_Temp<<7)-2; - } - } - - x1=&X[0][i_Temp][0]; - X_low1=&X_low[0][i_Temp+2][0]; - temp3=38; - - for (k = 0; k < sbr->kx[1]; k++) { - - __asm__ volatile ( - "move %[i], %[i_Temp] \n\t" - "4: \n\t" - "lw %[temp0], 0(%[X_low1]) \n\t" - "lw %[temp1], 4(%[X_low1]) \n\t" - "sw %[temp0], 0(%[x1]) \n\t" - "sw %[temp1], 9728(%[x1]) \n\t" - PTR_ADDIU "%[x1], %[x1], 256 \n\t" - PTR_ADDIU "%[X_low1],%[X_low1], 8 \n\t" - "addiu %[i], %[i], 1 \n\t" - "bne %[i], %[temp3], 4b \n\t" - - : [x1]"+r"(x1), [X_low1]"+r"(X_low1), [i]"=&r"(i), - [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2) - : [i_Temp]"r"(i_Temp), [temp3]"r"(temp3) - : "memory" - ); - x1 -= ((38-i_Temp)<<6)-1; - X_low1 -= ((38-i_Temp)<<1)- 80; - } - - x1=&X[0][i_Temp][k]; - Y11=&Y1[i_Temp][k][0]; - temp2=32; - - for (; k < sbr->kx[1] + sbr->m[1]; k++) { - - __asm__ volatile ( - "move %[i], %[i_Temp] \n\t" - "5: \n\t" - "lw %[temp0], 0(%[Y11]) \n\t" - "lw %[temp1], 4(%[Y11]) \n\t" - "sw %[temp0], 0(%[x1]) \n\t" - "sw %[temp1], 9728(%[x1]) \n\t" - PTR_ADDIU "%[x1], %[x1], 256 \n\t" - PTR_ADDIU "%[Y11], %[Y11], 512 \n\t" - "addiu %[i], %[i], 1 \n\t" - "bne %[i], %[temp2], 5b \n\t" - - : [x1]"+r"(x1), [Y11]"+r"(Y11), [i]"=&r"(i), - [temp0]"=&r"(temp0), [temp1]"=&r"(temp1) - : [i_Temp]"r"(i_Temp), [temp3]"r"(temp3), - [temp2]"r"(temp2) - : "memory" - ); - - x1 -= ((32-i_Temp)<<6)-1; - Y11 -= ((32-i_Temp)<<7)-2; - } - return 0; -} - -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 -static void sbr_hf_assemble_mips(float Y1[38][64][2], - const float X_high[64][40][2], - SpectralBandReplication *sbr, SBRData *ch_data, - const int e_a[2]) -{ - int e, i, j, m; - const int h_SL = 4 * !sbr->bs_smoothing_mode; - const int kx = sbr->kx[1]; - const int m_max = sbr->m[1]; - static const float h_smooth[5] = { - 0.33333333333333, - 0.30150283239582, - 0.21816949906249, - 0.11516383427084, - 0.03183050093751, - }; - - float (*g_temp)[48] = ch_data->g_temp, (*q_temp)[48] = ch_data->q_temp; - int indexnoise = ch_data->f_indexnoise; - int indexsine = ch_data->f_indexsine; - float *g_temp1, *q_temp1, *pok, *pok1; - uint32_t temp1, temp2, temp3, temp4; - int size = m_max; - - if (sbr->reset) { - for (i = 0; i < h_SL; i++) { - memcpy(g_temp[i + 2*ch_data->t_env[0]], sbr->gain[0], m_max * sizeof(sbr->gain[0][0])); - memcpy(q_temp[i + 2*ch_data->t_env[0]], sbr->q_m[0], m_max * sizeof(sbr->q_m[0][0])); - } - } else if (h_SL) { - memcpy(g_temp[2*ch_data->t_env[0]], g_temp[2*ch_data->t_env_num_env_old], 4*sizeof(g_temp[0])); - memcpy(q_temp[2*ch_data->t_env[0]], q_temp[2*ch_data->t_env_num_env_old], 4*sizeof(q_temp[0])); - } - - for (e = 0; e < ch_data->bs_num_env; e++) { - for (i = 2 * ch_data->t_env[e]; i < 2 * ch_data->t_env[e + 1]; i++) { - g_temp1 = g_temp[h_SL + i]; - pok = sbr->gain[e]; - q_temp1 = q_temp[h_SL + i]; - pok1 = sbr->q_m[e]; - - /* loop unrolled 4 times */ - for (j=0; j<(size>>2); j++) { - __asm__ volatile ( - "lw %[temp1], 0(%[pok]) \n\t" - "lw %[temp2], 4(%[pok]) \n\t" - "lw %[temp3], 8(%[pok]) \n\t" - "lw %[temp4], 12(%[pok]) \n\t" - "sw %[temp1], 0(%[g_temp1]) \n\t" - "sw %[temp2], 4(%[g_temp1]) \n\t" - "sw %[temp3], 8(%[g_temp1]) \n\t" - "sw %[temp4], 12(%[g_temp1]) \n\t" - "lw %[temp1], 0(%[pok1]) \n\t" - "lw %[temp2], 4(%[pok1]) \n\t" - "lw %[temp3], 8(%[pok1]) \n\t" - "lw %[temp4], 12(%[pok1]) \n\t" - "sw %[temp1], 0(%[q_temp1]) \n\t" - "sw %[temp2], 4(%[q_temp1]) \n\t" - "sw %[temp3], 8(%[q_temp1]) \n\t" - "sw %[temp4], 12(%[q_temp1]) \n\t" - PTR_ADDIU "%[pok], %[pok], 16 \n\t" - PTR_ADDIU "%[g_temp1], %[g_temp1], 16 \n\t" - PTR_ADDIU "%[pok1], %[pok1], 16 \n\t" - PTR_ADDIU "%[q_temp1], %[q_temp1], 16 \n\t" - - : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), - [pok]"+r"(pok), [g_temp1]"+r"(g_temp1), - [pok1]"+r"(pok1), [q_temp1]"+r"(q_temp1) - : - : "memory" - ); - } - - for (j=0; j<(size&3); j++) { - __asm__ volatile ( - "lw %[temp1], 0(%[pok]) \n\t" - "lw %[temp2], 0(%[pok1]) \n\t" - "sw %[temp1], 0(%[g_temp1]) \n\t" - "sw %[temp2], 0(%[q_temp1]) \n\t" - PTR_ADDIU "%[pok], %[pok], 4 \n\t" - PTR_ADDIU "%[g_temp1], %[g_temp1], 4 \n\t" - PTR_ADDIU "%[pok1], %[pok1], 4 \n\t" - PTR_ADDIU "%[q_temp1], %[q_temp1], 4 \n\t" - - : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), - [pok]"+r"(pok), [g_temp1]"+r"(g_temp1), - [pok1]"+r"(pok1), [q_temp1]"+r"(q_temp1) - : - : "memory" - ); - } - } - } - - for (e = 0; e < ch_data->bs_num_env; e++) { - for (i = 2 * ch_data->t_env[e]; i < 2 * ch_data->t_env[e + 1]; i++) { - LOCAL_ALIGNED_16(float, g_filt_tab, [48]); - LOCAL_ALIGNED_16(float, q_filt_tab, [48]); - float *g_filt, *q_filt; - - if (h_SL && e != e_a[0] && e != e_a[1]) { - g_filt = g_filt_tab; - q_filt = q_filt_tab; - - for (m = 0; m < m_max; m++) { - const int idx1 = i + h_SL; - g_filt[m] = 0.0f; - q_filt[m] = 0.0f; - - for (j = 0; j <= h_SL; j++) { - g_filt[m] += g_temp[idx1 - j][m] * h_smooth[j]; - q_filt[m] += q_temp[idx1 - j][m] * h_smooth[j]; - } - } - } else { - g_filt = g_temp[i + h_SL]; - q_filt = q_temp[i]; - } - - sbr->dsp.hf_g_filt(Y1[i] + kx, X_high + kx, g_filt, m_max, - i + ENVELOPE_ADJUSTMENT_OFFSET); - - if (e != e_a[0] && e != e_a[1]) { - sbr->dsp.hf_apply_noise[indexsine](Y1[i] + kx, sbr->s_m[e], - q_filt, indexnoise, - kx, m_max); - } else { - int idx = indexsine&1; - int A = (1-((indexsine+(kx & 1))&2)); - int B = (A^(-idx)) + idx; - float *out = &Y1[i][kx][idx]; - float *in = sbr->s_m[e]; - float temp0, temp1, temp2, temp3, temp4, temp5; - float A_f = (float)A; - float B_f = (float)B; - - for (m = 0; m+1 < m_max; m+=2) { - - temp2 = out[0]; - temp3 = out[2]; - - __asm__ volatile( - "lwc1 %[temp0], 0(%[in]) \n\t" - "lwc1 %[temp1], 4(%[in]) \n\t" - "madd.s %[temp4], %[temp2], %[temp0], %[A_f] \n\t" - "madd.s %[temp5], %[temp3], %[temp1], %[B_f] \n\t" - "swc1 %[temp4], 0(%[out]) \n\t" - "swc1 %[temp5], 8(%[out]) \n\t" - PTR_ADDIU "%[in], %[in], 8 \n\t" - PTR_ADDIU "%[out], %[out], 16 \n\t" - - : [temp0]"=&f" (temp0), [temp1]"=&f"(temp1), - [temp4]"=&f" (temp4), [temp5]"=&f"(temp5), - [in]"+r"(in), [out]"+r"(out) - : [A_f]"f"(A_f), [B_f]"f"(B_f), [temp2]"f"(temp2), - [temp3]"f"(temp3) - : "memory" - ); - } - if(m_max&1) - out[2*m ] += in[m ] * A; - } - indexnoise = (indexnoise + m_max) & 0x1ff; - indexsine = (indexsine + 1) & 3; - } - } - ch_data->f_indexnoise = indexnoise; - ch_data->f_indexsine = indexsine; -} - -static void sbr_hf_inverse_filter_mips(SBRDSPContext *dsp, - float (*alpha0)[2], float (*alpha1)[2], - const float X_low[32][40][2], int k0) -{ - int k; - float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, c; - float *phi1, *alpha_1, *alpha_0, res1, res2, temp_real, temp_im; - - c = 1.000001f; - - for (k = 0; k < k0; k++) { - LOCAL_ALIGNED_16(float, phi, [3], [2][2]); - float dk; - phi1 = &phi[0][0][0]; - alpha_1 = &alpha1[k][0]; - alpha_0 = &alpha0[k][0]; - dsp->autocorrelate(X_low[k], phi); - - __asm__ volatile ( - "lwc1 %[temp0], 40(%[phi1]) \n\t" - "lwc1 %[temp1], 16(%[phi1]) \n\t" - "lwc1 %[temp2], 24(%[phi1]) \n\t" - "lwc1 %[temp3], 28(%[phi1]) \n\t" - "mul.s %[dk], %[temp0], %[temp1] \n\t" - "lwc1 %[temp4], 0(%[phi1]) \n\t" - "mul.s %[res2], %[temp2], %[temp2] \n\t" - "lwc1 %[temp5], 4(%[phi1]) \n\t" - "madd.s %[res2], %[res2], %[temp3], %[temp3] \n\t" - "lwc1 %[temp6], 8(%[phi1]) \n\t" - "div.s %[res2], %[res2], %[c] \n\t" - "lwc1 %[temp0], 12(%[phi1]) \n\t" - "sub.s %[dk], %[dk], %[res2] \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [temp6]"=&f"(temp6), [res2]"=&f"(res2), [dk]"=&f"(dk) - : [phi1]"r"(phi1), [c]"f"(c) - : "memory" - ); - - if (!dk) { - alpha_1[0] = 0; - alpha_1[1] = 0; - } else { - __asm__ volatile ( - "mul.s %[temp_real], %[temp4], %[temp2] \n\t" - "nmsub.s %[temp_real], %[temp_real], %[temp5], %[temp3] \n\t" - "nmsub.s %[temp_real], %[temp_real], %[temp6], %[temp1] \n\t" - "mul.s %[temp_im], %[temp4], %[temp3] \n\t" - "madd.s %[temp_im], %[temp_im], %[temp5], %[temp2] \n\t" - "nmsub.s %[temp_im], %[temp_im], %[temp0], %[temp1] \n\t" - "div.s %[temp_real], %[temp_real], %[dk] \n\t" - "div.s %[temp_im], %[temp_im], %[dk] \n\t" - "swc1 %[temp_real], 0(%[alpha_1]) \n\t" - "swc1 %[temp_im], 4(%[alpha_1]) \n\t" - - : [temp_real]"=&f" (temp_real), [temp_im]"=&f"(temp_im) - : [phi1]"r"(phi1), [temp0]"f"(temp0), [temp1]"f"(temp1), - [temp2]"f"(temp2), [temp3]"f"(temp3), [temp4]"f"(temp4), - [temp5]"f"(temp5), [temp6]"f"(temp6), - [alpha_1]"r"(alpha_1), [dk]"f"(dk) - : "memory" - ); - } - - if (!phi1[4]) { - alpha_0[0] = 0; - alpha_0[1] = 0; - } else { - __asm__ volatile ( - "lwc1 %[temp6], 0(%[alpha_1]) \n\t" - "lwc1 %[temp7], 4(%[alpha_1]) \n\t" - "mul.s %[temp_real], %[temp6], %[temp2] \n\t" - "add.s %[temp_real], %[temp_real], %[temp4] \n\t" - "madd.s %[temp_real], %[temp_real], %[temp7], %[temp3] \n\t" - "mul.s %[temp_im], %[temp7], %[temp2] \n\t" - "add.s %[temp_im], %[temp_im], %[temp5] \n\t" - "nmsub.s %[temp_im], %[temp_im], %[temp6], %[temp3] \n\t" - "div.s %[temp_real], %[temp_real], %[temp1] \n\t" - "div.s %[temp_im], %[temp_im], %[temp1] \n\t" - "neg.s %[temp_real], %[temp_real] \n\t" - "neg.s %[temp_im], %[temp_im] \n\t" - "swc1 %[temp_real], 0(%[alpha_0]) \n\t" - "swc1 %[temp_im], 4(%[alpha_0]) \n\t" - - : [temp_real]"=&f"(temp_real), [temp_im]"=&f"(temp_im), - [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), - [res1]"=&f"(res1), [res2]"=&f"(res2) - : [alpha_1]"r"(alpha_1), [alpha_0]"r"(alpha_0), - [temp0]"f"(temp0), [temp1]"f"(temp1), [temp2]"f"(temp2), - [temp3]"f"(temp3), [temp4]"f"(temp4), [temp5]"f"(temp5) - : "memory" - ); - } - - __asm__ volatile ( - "lwc1 %[temp1], 0(%[alpha_1]) \n\t" - "lwc1 %[temp2], 4(%[alpha_1]) \n\t" - "lwc1 %[temp_real], 0(%[alpha_0]) \n\t" - "lwc1 %[temp_im], 4(%[alpha_0]) \n\t" - "mul.s %[res1], %[temp1], %[temp1] \n\t" - "madd.s %[res1], %[res1], %[temp2], %[temp2] \n\t" - "mul.s %[res2], %[temp_real], %[temp_real] \n\t" - "madd.s %[res2], %[res2], %[temp_im], %[temp_im] \n\t" - - : [temp_real]"=&f"(temp_real), [temp_im]"=&f"(temp_im), - [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [res1]"=&f"(res1), [res2]"=&f"(res2) - : [alpha_1]"r"(alpha_1), [alpha_0]"r"(alpha_0) - : "memory" - ); - - if (res1 >= 16.0f || res2 >= 16.0f) { - alpha_1[0] = 0; - alpha_1[1] = 0; - alpha_0[0] = 0; - alpha_0[1] = 0; - } - } -} -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_MIPSFPU */ -#endif /* HAVE_INLINE_ASM */ - -void ff_aacsbr_func_ptr_init_mips(AACSBRContext *c) -{ -#if HAVE_INLINE_ASM -#if HAVE_MIPSFPU - c->sbr_lf_gen = sbr_lf_gen_mips; - c->sbr_x_gen = sbr_x_gen_mips; -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 - c->sbr_hf_inverse_filter = sbr_hf_inverse_filter_mips; - c->sbr_hf_assemble = sbr_hf_assemble_mips; -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_MIPSFPU */ -#endif /* HAVE_INLINE_ASM */ -} diff --git a/libavcodec/mips/aacsbr_mips.h b/libavcodec/mips/aacsbr_mips.h deleted file mode 100644 index 447393164..000000000 --- a/libavcodec/mips/aacsbr_mips.h +++ /dev/null @@ -1,496 +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. - * - * Authors: Djordje Pesut (djordje@mips.com) - * Mirjana Vulin (mvulin@mips.com) - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * Reference: libavcodec/aacsbr.c - */ - -#ifndef AVCODEC_MIPS_AACSBR_MIPS_H -#define AVCODEC_MIPS_AACSBR_MIPS_H - -#include "libavcodec/aacdec.h" -#include "libavcodec/sbr.h" -#include "libavutil/mips/asmdefs.h" - -#if HAVE_INLINE_ASM -static void sbr_qmf_analysis_mips(AVFloatDSPContext *fdsp, AVTXContext *mdct, av_tx_fn mdct_fn, - SBRDSPContext *sbrdsp, const float *in, float *x, - float z[320], float W[2][32][32][2], int buf_idx) -{ - int i; - float *w0; - float *w1; - int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - - w0 = x; - w1 = x + 1024; - for(i = 0; i < 36; i++) - { - /* loop unrolled 8 times */ - __asm__ volatile( - "lw %[temp0], 0(%[w1]) \n\t" - "lw %[temp1], 4(%[w1]) \n\t" - "lw %[temp2], 8(%[w1]) \n\t" - "lw %[temp3], 12(%[w1]) \n\t" - "lw %[temp4], 16(%[w1]) \n\t" - "lw %[temp5], 20(%[w1]) \n\t" - "lw %[temp6], 24(%[w1]) \n\t" - "lw %[temp7], 28(%[w1]) \n\t" - "sw %[temp0], 0(%[w0]) \n\t" - "sw %[temp1], 4(%[w0]) \n\t" - "sw %[temp2], 8(%[w0]) \n\t" - "sw %[temp3], 12(%[w0]) \n\t" - "sw %[temp4], 16(%[w0]) \n\t" - "sw %[temp5], 20(%[w0]) \n\t" - "sw %[temp6], 24(%[w0]) \n\t" - "sw %[temp7], 28(%[w0]) \n\t" - PTR_ADDIU " %[w0], %[w0], 32 \n\t" - PTR_ADDIU " %[w1], %[w1], 32 \n\t" - - : [w0]"+r"(w0), [w1]"+r"(w1), - [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7) - : - : "memory" - ); - } - - w0 = x + 288; - w1 = (float*)in; - for(i = 0; i < 128; i++) - { - /* loop unrolled 8 times */ - __asm__ volatile( - "lw %[temp0], 0(%[w1]) \n\t" - "lw %[temp1], 4(%[w1]) \n\t" - "lw %[temp2], 8(%[w1]) \n\t" - "lw %[temp3], 12(%[w1]) \n\t" - "lw %[temp4], 16(%[w1]) \n\t" - "lw %[temp5], 20(%[w1]) \n\t" - "lw %[temp6], 24(%[w1]) \n\t" - "lw %[temp7], 28(%[w1]) \n\t" - "sw %[temp0], 0(%[w0]) \n\t" - "sw %[temp1], 4(%[w0]) \n\t" - "sw %[temp2], 8(%[w0]) \n\t" - "sw %[temp3], 12(%[w0]) \n\t" - "sw %[temp4], 16(%[w0]) \n\t" - "sw %[temp5], 20(%[w0]) \n\t" - "sw %[temp6], 24(%[w0]) \n\t" - "sw %[temp7], 28(%[w0]) \n\t" - PTR_ADDIU " %[w0], %[w0], 32 \n\t" - PTR_ADDIU " %[w1], %[w1], 32 \n\t" - - : [w0]"+r"(w0), [w1]"+r"(w1), - [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), - [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), - [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), - [temp6]"=&r"(temp6), [temp7]"=&r"(temp7) - : - : "memory" - ); - } - - for (i = 0; i < 32; i++) { // numTimeSlots*RATE = 16*2 as 960 sample frames - // are not supported - fdsp->vector_fmul_reverse(z, sbr_qmf_window_ds, x, 320); - sbrdsp->sum64x5(z); - sbrdsp->qmf_pre_shuffle(z); - mdct_fn(mdct, z, z+64, sizeof(float)); - sbrdsp->qmf_post_shuffle(W[buf_idx][i], z); - x += 32; - } -} - -#if HAVE_MIPSFPU -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 -static void sbr_qmf_synthesis_mips(AVTXContext *mdct, av_tx_fn mdct_fn, - SBRDSPContext *sbrdsp, AVFloatDSPContext *fdsp, - float *out, float X[2][38][64], - float mdct_buf[2][64], - float *v0, int *v_off, const unsigned int div) -{ - int i, n; - const float *sbr_qmf_window = div ? sbr_qmf_window_ds : sbr_qmf_window_us; - const int step = 128 >> div; - float *v; - float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10, temp11, temp12, temp13; - float temp14, temp15, temp16, temp17, temp18, temp19; - float *vv0, *s0, *dst; - dst = out; - - for (i = 0; i < 32; i++) { - if (*v_off < step) { - int saved_samples = (1280 - 128) >> div; - memcpy(&v0[SBR_SYNTHESIS_BUF_SIZE - saved_samples], v0, saved_samples * sizeof(float)); - *v_off = SBR_SYNTHESIS_BUF_SIZE - saved_samples - step; - } else { - *v_off -= step; - } - v = v0 + *v_off; - if (div) { - for (n = 0; n < 32; n++) { - X[0][i][ n] = -X[0][i][n]; - X[0][i][32+n] = X[1][i][31-n]; - } - mdct_fn(mdct, mdct_buf[0], X[0][i], sizeof(float)); - sbrdsp->qmf_deint_neg(v, mdct_buf[0]); - } else { - sbrdsp->neg_odd_64(X[1][i]); - mdct_fn(mdct, mdct_buf[0], X[0][i], sizeof(float)); - mdct_fn(mdct, mdct_buf[1], X[1][i], sizeof(float)); - sbrdsp->qmf_deint_bfly(v, mdct_buf[1], mdct_buf[0]); - } - - if(div == 0) - { - float *v0_end; - vv0 = v; - v0_end = v + 60; - s0 = (float*)sbr_qmf_window; - - /* 10 calls of function vector_fmul_add merged into one loop - and loop unrolled 4 times */ - __asm__ volatile( - ".set push \n\t" - ".set noreorder \n\t" - "lwc1 %[temp4], 0(%[v0]) \n\t" - "lwc1 %[temp5], 0(%[s0]) \n\t" - "lwc1 %[temp6], 4(%[v0]) \n\t" - "lwc1 %[temp7], 4(%[s0]) \n\t" - "lwc1 %[temp8], 8(%[v0]) \n\t" - "lwc1 %[temp9], 8(%[s0]) \n\t" - "lwc1 %[temp10], 12(%[v0]) \n\t" - "lwc1 %[temp11], 12(%[s0]) \n\t" - "lwc1 %[temp12], 768(%[v0]) \n\t" - "lwc1 %[temp13], 256(%[s0]) \n\t" - "lwc1 %[temp14], 772(%[v0]) \n\t" - "lwc1 %[temp15], 260(%[s0]) \n\t" - "lwc1 %[temp16], 776(%[v0]) \n\t" - "lwc1 %[temp17], 264(%[s0]) \n\t" - "lwc1 %[temp18], 780(%[v0]) \n\t" - "lwc1 %[temp19], 268(%[s0]) \n\t" - "1: \n\t" - "mul.s %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp4], 1024(%[v0]) \n\t" - "mul.s %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp5], 512(%[s0]) \n\t" - "mul.s %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp6], 1028(%[v0]) \n\t" - "mul.s %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp7], 516(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - "lwc1 %[temp8], 1032(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "lwc1 %[temp9], 520(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "lwc1 %[temp10], 1036(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "lwc1 %[temp11], 524(%[s0]) \n\t" - "lwc1 %[temp12], 1792(%[v0]) \n\t" - "lwc1 %[temp13], 768(%[s0]) \n\t" - "lwc1 %[temp14], 1796(%[v0]) \n\t" - "lwc1 %[temp15], 772(%[s0]) \n\t" - "lwc1 %[temp16], 1800(%[v0]) \n\t" - "lwc1 %[temp17], 776(%[s0]) \n\t" - "lwc1 %[temp18], 1804(%[v0]) \n\t" - "lwc1 %[temp19], 780(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp4], 2048(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp5], 1024(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp6], 2052(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp7], 1028(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - "lwc1 %[temp8], 2056(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "lwc1 %[temp9], 1032(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "lwc1 %[temp10], 2060(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "lwc1 %[temp11], 1036(%[s0]) \n\t" - "lwc1 %[temp12], 2816(%[v0]) \n\t" - "lwc1 %[temp13], 1280(%[s0]) \n\t" - "lwc1 %[temp14], 2820(%[v0]) \n\t" - "lwc1 %[temp15], 1284(%[s0]) \n\t" - "lwc1 %[temp16], 2824(%[v0]) \n\t" - "lwc1 %[temp17], 1288(%[s0]) \n\t" - "lwc1 %[temp18], 2828(%[v0]) \n\t" - "lwc1 %[temp19], 1292(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp4], 3072(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp5], 1536(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp6], 3076(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp7], 1540(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - "lwc1 %[temp8], 3080(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "lwc1 %[temp9], 1544(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "lwc1 %[temp10], 3084(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "lwc1 %[temp11], 1548(%[s0]) \n\t" - "lwc1 %[temp12], 3840(%[v0]) \n\t" - "lwc1 %[temp13], 1792(%[s0]) \n\t" - "lwc1 %[temp14], 3844(%[v0]) \n\t" - "lwc1 %[temp15], 1796(%[s0]) \n\t" - "lwc1 %[temp16], 3848(%[v0]) \n\t" - "lwc1 %[temp17], 1800(%[s0]) \n\t" - "lwc1 %[temp18], 3852(%[v0]) \n\t" - "lwc1 %[temp19], 1804(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp4], 4096(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp5], 2048(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp6], 4100(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp7], 2052(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - "lwc1 %[temp8], 4104(%[v0]) \n\t" - PTR_ADDIU "%[dst], %[dst], 16 \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "lwc1 %[temp9], 2056(%[s0]) \n\t" - PTR_ADDIU " %[s0], %[s0], 16 \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "lwc1 %[temp10], 4108(%[v0]) \n\t" - PTR_ADDIU " %[v0], %[v0], 16 \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "lwc1 %[temp11], 2044(%[s0]) \n\t" - "lwc1 %[temp12], 4848(%[v0]) \n\t" - "lwc1 %[temp13], 2288(%[s0]) \n\t" - "lwc1 %[temp14], 4852(%[v0]) \n\t" - "lwc1 %[temp15], 2292(%[s0]) \n\t" - "lwc1 %[temp16], 4856(%[v0]) \n\t" - "lwc1 %[temp17], 2296(%[s0]) \n\t" - "lwc1 %[temp18], 4860(%[v0]) \n\t" - "lwc1 %[temp19], 2300(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp4], 0(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp5], 0(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp6], 4(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp7], 4(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - "lwc1 %[temp8], 8(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "lwc1 %[temp9], 8(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "lwc1 %[temp10], 12(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "lwc1 %[temp11], 12(%[s0]) \n\t" - "lwc1 %[temp12], 768(%[v0]) \n\t" - "lwc1 %[temp13], 256(%[s0]) \n\t" - "lwc1 %[temp14], 772(%[v0]) \n\t" - "lwc1 %[temp15], 260(%[s0]) \n\t" - "lwc1 %[temp16], 776(%[v0]) \n\t" - "lwc1 %[temp17], 264(%[s0]) \n\t" - "lwc1 %[temp18], 780(%[v0]) \n\t" - "lwc1 %[temp19], 268(%[s0]) \n\t" - "swc1 %[temp0], -16(%[dst]) \n\t" - "swc1 %[temp1], -12(%[dst]) \n\t" - "swc1 %[temp2], -8(%[dst]) \n\t" - "bne %[v0], %[v0_end], 1b \n\t" - " swc1 %[temp3], -4(%[dst]) \n\t" - "mul.s %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp4], 1024(%[v0]) \n\t" - "mul.s %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp5], 512(%[s0]) \n\t" - "mul.s %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp6], 1028(%[v0]) \n\t" - "mul.s %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp7], 516(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - "lwc1 %[temp8], 1032(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "lwc1 %[temp9], 520(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "lwc1 %[temp10], 1036(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "lwc1 %[temp11], 524(%[s0]) \n\t" - "lwc1 %[temp12], 1792(%[v0]) \n\t" - "lwc1 %[temp13], 768(%[s0]) \n\t" - "lwc1 %[temp14], 1796(%[v0]) \n\t" - "lwc1 %[temp15], 772(%[s0]) \n\t" - "lwc1 %[temp16], 1800(%[v0]) \n\t" - "lwc1 %[temp17], 776(%[s0]) \n\t" - "lwc1 %[temp18], 1804(%[v0]) \n\t" - "lwc1 %[temp19], 780(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp4], 2048(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp5], 1024(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp6], 2052(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp7], 1028(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - "lwc1 %[temp8], 2056(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "lwc1 %[temp9], 1032(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "lwc1 %[temp10], 2060(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "lwc1 %[temp11], 1036(%[s0]) \n\t" - "lwc1 %[temp12], 2816(%[v0]) \n\t" - "lwc1 %[temp13], 1280(%[s0]) \n\t" - "lwc1 %[temp14], 2820(%[v0]) \n\t" - "lwc1 %[temp15], 1284(%[s0]) \n\t" - "lwc1 %[temp16], 2824(%[v0]) \n\t" - "lwc1 %[temp17], 1288(%[s0]) \n\t" - "lwc1 %[temp18], 2828(%[v0]) \n\t" - "lwc1 %[temp19], 1292(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp4], 3072(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp5], 1536(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp6], 3076(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp7], 1540(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - "lwc1 %[temp8], 3080(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "lwc1 %[temp9], 1544(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "lwc1 %[temp10], 3084(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "lwc1 %[temp11], 1548(%[s0]) \n\t" - "lwc1 %[temp12], 3840(%[v0]) \n\t" - "lwc1 %[temp13], 1792(%[s0]) \n\t" - "lwc1 %[temp14], 3844(%[v0]) \n\t" - "lwc1 %[temp15], 1796(%[s0]) \n\t" - "lwc1 %[temp16], 3848(%[v0]) \n\t" - "lwc1 %[temp17], 1800(%[s0]) \n\t" - "lwc1 %[temp18], 3852(%[v0]) \n\t" - "lwc1 %[temp19], 1804(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp4], 4096(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp5], 2048(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp6], 4100(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp7], 2052(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - "lwc1 %[temp8], 4104(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "lwc1 %[temp9], 2056(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "lwc1 %[temp10], 4108(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "lwc1 %[temp11], 2060(%[s0]) \n\t" - "lwc1 %[temp12], 4864(%[v0]) \n\t" - "lwc1 %[temp13], 2304(%[s0]) \n\t" - "lwc1 %[temp14], 4868(%[v0]) \n\t" - "lwc1 %[temp15], 2308(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp4], %[temp5] \n\t" - "lwc1 %[temp16], 4872(%[v0]) \n\t" - "madd.s %[temp1], %[temp1], %[temp6], %[temp7] \n\t" - "lwc1 %[temp17], 2312(%[s0]) \n\t" - "madd.s %[temp2], %[temp2], %[temp8], %[temp9] \n\t" - "lwc1 %[temp18], 4876(%[v0]) \n\t" - "madd.s %[temp3], %[temp3], %[temp10], %[temp11] \n\t" - "lwc1 %[temp19], 2316(%[s0]) \n\t" - "madd.s %[temp0], %[temp0], %[temp12], %[temp13] \n\t" - PTR_ADDIU "%[dst], %[dst], 16 \n\t" - "madd.s %[temp1], %[temp1], %[temp14], %[temp15] \n\t" - "madd.s %[temp2], %[temp2], %[temp16], %[temp17] \n\t" - "madd.s %[temp3], %[temp3], %[temp18], %[temp19] \n\t" - "swc1 %[temp0], -16(%[dst]) \n\t" - "swc1 %[temp1], -12(%[dst]) \n\t" - "swc1 %[temp2], -8(%[dst]) \n\t" - "swc1 %[temp3], -4(%[dst]) \n\t" - ".set pop \n\t" - - : [dst]"+r"(dst), [v0]"+r"(vv0), [s0]"+r"(s0), - [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8), - [temp9]"=&f"(temp9), [temp10]"=&f"(temp10), [temp11]"=&f"(temp11), - [temp12]"=&f"(temp12), [temp13]"=&f"(temp13), [temp14]"=&f"(temp14), - [temp15]"=&f"(temp15), [temp16]"=&f"(temp16), [temp17]"=&f"(temp17), - [temp18]"=&f"(temp18), [temp19]"=&f"(temp19) - : [v0_end]"r"(v0_end) - : "memory" - ); - } - else - { - fdsp->vector_fmul (out, v , sbr_qmf_window , 64 >> div); - fdsp->vector_fmul_add(out, v + ( 192 >> div), sbr_qmf_window + ( 64 >> div), out , 64 >> div); - fdsp->vector_fmul_add(out, v + ( 256 >> div), sbr_qmf_window + (128 >> div), out , 64 >> div); - fdsp->vector_fmul_add(out, v + ( 448 >> div), sbr_qmf_window + (192 >> div), out , 64 >> div); - fdsp->vector_fmul_add(out, v + ( 512 >> div), sbr_qmf_window + (256 >> div), out , 64 >> div); - fdsp->vector_fmul_add(out, v + ( 704 >> div), sbr_qmf_window + (320 >> div), out , 64 >> div); - fdsp->vector_fmul_add(out, v + ( 768 >> div), sbr_qmf_window + (384 >> div), out , 64 >> div); - fdsp->vector_fmul_add(out, v + ( 960 >> div), sbr_qmf_window + (448 >> div), out , 64 >> div); - fdsp->vector_fmul_add(out, v + (1024 >> div), sbr_qmf_window + (512 >> div), out , 64 >> div); - fdsp->vector_fmul_add(out, v + (1216 >> div), sbr_qmf_window + (576 >> div), out , 64 >> div); - out += 64 >> div; - } - } -} - -#define sbr_qmf_analysis sbr_qmf_analysis_mips -#define sbr_qmf_synthesis sbr_qmf_synthesis_mips - -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_MIPSFPU */ -#endif /* HAVE_INLINE_ASM */ - -#endif /* AVCODEC_MIPS_AACSBR_MIPS_H */ diff --git a/libavcodec/mips/ac3dsp_mips.c b/libavcodec/mips/ac3dsp_mips.c index e97a41292..cc49ba388 100644 --- a/libavcodec/mips/ac3dsp_mips.c +++ b/libavcodec/mips/ac3dsp_mips.c @@ -54,11 +54,13 @@ */ #include +#include #include "config.h" #include "libavcodec/ac3dsp.h" #include "libavcodec/ac3.h" #include "libavcodec/ac3tab.h" +#include "libavutil/macros.h" #include "libavutil/mips/asmdefs.h" #if HAVE_INLINE_ASM diff --git a/libavcodec/mips/h263dsp_mips.h b/libavcodec/mips/h263dsp_mips.h index f225ee563..d4de2233a 100644 --- a/libavcodec/mips/h263dsp_mips.h +++ b/libavcodec/mips/h263dsp_mips.h @@ -31,6 +31,6 @@ void ff_dct_unquantize_h263_inter_msa(MpegEncContext *s, int16_t *block, int32_t index, int32_t q_scale); void ff_dct_unquantize_h263_intra_msa(MpegEncContext *s, int16_t *block, int32_t index, int32_t q_scale); -int ff_pix_sum_msa(const uint8_t *pix, int line_size); +int ff_pix_sum_msa(const uint8_t *pix, ptrdiff_t line_size); #endif // #ifndef AVCODEC_MIPS_H263DSP_MIPS_H diff --git a/libavcodec/mips/h264dsp_init_mips.c b/libavcodec/mips/h264dsp_init_mips.c index e33df32c7..72f42895e 100644 --- a/libavcodec/mips/h264dsp_init_mips.c +++ b/libavcodec/mips/h264dsp_init_mips.c @@ -46,13 +46,6 @@ av_cold void ff_h264dsp_init_mips(H264DSPContext *c, const int bit_depth, c->h264_luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_8_mmi; - if (chroma_format_idc <= 1) - c->h264_chroma_dc_dequant_idct = - ff_h264_chroma_dc_dequant_idct_8_mmi; - else - c->h264_chroma_dc_dequant_idct = - ff_h264_chroma422_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; diff --git a/libavcodec/mips/h264dsp_mips.h b/libavcodec/mips/h264dsp_mips.h index 93a201c66..4a2a2c255 100644 --- a/libavcodec/mips/h264dsp_mips.h +++ b/libavcodec/mips/h264dsp_mips.h @@ -340,8 +340,6 @@ void ff_h264_idct_add8_422_8_mmi(uint8_t **dest, const int *block_offset, int16_t *block, int stride, const uint8_t nnzc[15*8]); void ff_h264_luma_dc_dequant_idct_8_mmi(int16_t *output, int16_t *input, int qmul); -void ff_h264_chroma_dc_dequant_idct_8_mmi(int16_t *block, int qmul); -void ff_h264_chroma422_dc_dequant_idct_8_mmi(int16_t *block, int qmul); void ff_h264_weight_pixels16_8_mmi(uint8_t *block, ptrdiff_t stride, int height, int log2_denom, int weight, int offset); diff --git a/libavcodec/mips/h264dsp_mmi.c b/libavcodec/mips/h264dsp_mmi.c index dff3d331b..bae1052dc 100644 --- a/libavcodec/mips/h264dsp_mmi.c +++ b/libavcodec/mips/h264dsp_mmi.c @@ -1084,53 +1084,6 @@ void ff_h264_luma_dc_dequant_idct_8_mmi(int16_t *output, int16_t *input, ); } -void ff_h264_chroma422_dc_dequant_idct_8_mmi(int16_t *block, int qmul) -{ - int temp[8]; - int t[8]; - - temp[0] = block[0] + block[16]; - temp[1] = block[0] - block[16]; - temp[2] = block[32] + block[48]; - temp[3] = block[32] - block[48]; - temp[4] = block[64] + block[80]; - temp[5] = block[64] - block[80]; - temp[6] = block[96] + block[112]; - temp[7] = block[96] - block[112]; - - t[0] = temp[0] + temp[4] + temp[2] + temp[6]; - t[1] = temp[0] - temp[4] + temp[2] - temp[6]; - t[2] = temp[0] - temp[4] - temp[2] + temp[6]; - t[3] = temp[0] + temp[4] - temp[2] - temp[6]; - t[4] = temp[1] + temp[5] + temp[3] + temp[7]; - t[5] = temp[1] - temp[5] + temp[3] - temp[7]; - t[6] = temp[1] - temp[5] - temp[3] + temp[7]; - t[7] = temp[1] + temp[5] - temp[3] - temp[7]; - - block[ 0]= (t[0]*qmul + 128) >> 8; - block[ 32]= (t[1]*qmul + 128) >> 8; - block[ 64]= (t[2]*qmul + 128) >> 8; - block[ 96]= (t[3]*qmul + 128) >> 8; - block[ 16]= (t[4]*qmul + 128) >> 8; - block[ 48]= (t[5]*qmul + 128) >> 8; - block[ 80]= (t[6]*qmul + 128) >> 8; - block[112]= (t[7]*qmul + 128) >> 8; -} - -void ff_h264_chroma_dc_dequant_idct_8_mmi(int16_t *block, int qmul) -{ - int a,b,c,d; - - d = block[0] - block[16]; - a = block[0] + block[16]; - b = block[32] - block[48]; - c = block[32] + block[48]; - block[0] = ((a+c)*qmul) >> 7; - block[16]= ((d+b)*qmul) >> 7; - block[32]= ((a-c)*qmul) >> 7; - block[48]= ((d-b)*qmul) >> 7; -} - void ff_h264_weight_pixels16_8_mmi(uint8_t *block, ptrdiff_t stride, int height, int log2_denom, int weight, int offset) { diff --git a/libavcodec/mips/hevcdsp_mips.h b/libavcodec/mips/hevcdsp_mips.h index a8f78ff73..049893802 100644 --- a/libavcodec/mips/hevcdsp_mips.h +++ b/libavcodec/mips/hevcdsp_mips.h @@ -21,7 +21,7 @@ #ifndef AVCODEC_MIPS_HEVCDSP_MIPS_H #define AVCODEC_MIPS_HEVCDSP_MIPS_H -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #define MC(PEL, DIR, WIDTH) \ void ff_hevc_put_hevc_##PEL##_##DIR##WIDTH##_8_msa(int16_t *dst, \ diff --git a/libavcodec/mips/hevcdsp_mmi.c b/libavcodec/mips/hevcdsp_mmi.c index 7ece7b9be..6ff52187e 100644 --- a/libavcodec/mips/hevcdsp_mmi.c +++ b/libavcodec/mips/hevcdsp_mmi.c @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavcodec/hevcdec.h" +#include "libavcodec/hevc/hevcdec.h" #include "libavcodec/bit_depth_template.c" #include "libavcodec/mips/hevcdsp_mips.h" #include "libavutil/mips/mmiutils.h" diff --git a/libavcodec/mips/hevcpred_mips.h b/libavcodec/mips/hevcpred_mips.h index 684870001..692a16215 100644 --- a/libavcodec/mips/hevcpred_mips.h +++ b/libavcodec/mips/hevcpred_mips.h @@ -21,7 +21,7 @@ #ifndef AVCODEC_MIPS_HEVCPRED_MIPS_H #define AVCODEC_MIPS_HEVCPRED_MIPS_H -#include "libavcodec/hevcpred.h" +#include "libavcodec/hevc/pred.h" void ff_hevc_intra_pred_planar_0_msa(uint8_t *dst, const uint8_t *src_top, @@ -67,7 +67,7 @@ void ff_pred_intra_pred_angular_3_msa(uint8_t *dst, const uint8_t *src_left, ptrdiff_t stride, int c_idx, int mode); -void ff_intra_pred_8_16x16_msa(struct HEVCLocalContext *s, int x0, int y0, int c_idx); -void ff_intra_pred_8_32x32_msa(struct HEVCLocalContext *s, int x0, int y0, int c_idx); +void ff_intra_pred_8_16x16_msa(struct HEVCLocalContext *s, const struct HEVCPPS *pps, int x0, int y0, int c_idx); +void ff_intra_pred_8_32x32_msa(struct HEVCLocalContext *s, const struct HEVCPPS *pps, int x0, int y0, int c_idx); #endif // #ifndef AVCODEC_MIPS_HEVCPRED_MIPS_H diff --git a/libavcodec/mips/hevcpred_msa.c b/libavcodec/mips/hevcpred_msa.c index b056ee986..a6824712a 100644 --- a/libavcodec/mips/hevcpred_msa.c +++ b/libavcodec/mips/hevcpred_msa.c @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavcodec/hevcdec.h" +#include "libavcodec/hevc/dec.h" #include "libavutil/mips/generic_macros_msa.h" #include "hevcpred_mips.h" @@ -1903,29 +1903,31 @@ void ff_pred_intra_pred_angular_3_msa(uint8_t *dst, } } -void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) +void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, const HEVCPPS *pps, + int x0, int y0, int c_idx) { v16u8 vec0; + const HEVCSPS *const sps = pps->sps; const HEVCContext *const s = lc->parent; int i; - int hshift = s->ps.sps->hshift[c_idx]; - int vshift = s->ps.sps->vshift[c_idx]; + int hshift = sps->hshift[c_idx]; + int vshift = sps->vshift[c_idx]; int size_in_luma_h = 16 << hshift; - int size_in_tbs_h = size_in_luma_h >> s->ps.sps->log2_min_tb_size; + int size_in_tbs_h = size_in_luma_h >> sps->log2_min_tb_size; int size_in_luma_v = 16 << vshift; - int size_in_tbs_v = size_in_luma_v >> s->ps.sps->log2_min_tb_size; + int size_in_tbs_v = size_in_luma_v >> sps->log2_min_tb_size; int x = x0 >> hshift; int y = y0 >> vshift; - int x_tb = (x0 >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask; - int y_tb = (y0 >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask; + int x_tb = (x0 >> sps->log2_min_tb_size) & sps->tb_mask; + int y_tb = (y0 >> sps->log2_min_tb_size) & sps->tb_mask; int cur_tb_addr = - s->ps.pps->min_tb_addr_zs[(y_tb) * (s->ps.sps->tb_mask + 2) + (x_tb)]; + pps->min_tb_addr_zs[(y_tb) * (sps->tb_mask + 2) + (x_tb)]; ptrdiff_t stride = s->frame->linesize[c_idx] / sizeof(uint8_t); uint8_t *src = (uint8_t *) s->frame->data[c_idx] + x + y * stride; - int min_pu_width = s->ps.sps->min_pu_width; + int min_pu_width = sps->min_pu_width; enum IntraPredMode mode = c_idx ? lc->tu.intra_pred_mode_c : lc->tu.intra_pred_mode; @@ -1941,102 +1943,102 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) uint8_t *filtered_top = filtered_top_array + 1; int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > - s->ps.pps->min_tb_addr_zs[((y_tb + size_in_tbs_v) & s->ps.sps->tb_mask) * - (s->ps.sps->tb_mask + 2) + (x_tb - 1)]; + pps->min_tb_addr_zs[((y_tb + size_in_tbs_v) & sps->tb_mask) * + (sps->tb_mask + 2) + (x_tb - 1)]; int cand_left = lc->na.cand_left; int cand_up_left = lc->na.cand_up_left; int cand_up = lc->na.cand_up; int cand_up_right = lc->na.cand_up_right && cur_tb_addr > - s->ps.pps->min_tb_addr_zs[(y_tb - 1) * (s->ps.sps->tb_mask + 2) + - ((x_tb + size_in_tbs_h) & s->ps.sps->tb_mask)]; + pps->min_tb_addr_zs[(y_tb - 1) * (sps->tb_mask + 2) + + ((x_tb + size_in_tbs_h) & sps->tb_mask)]; int bottom_left_size = (((y0 + 2 * size_in_luma_v) > - (s->ps.sps->height) ? (s->ps.sps->height) : (y0 + + (sps->height) ? (sps->height) : (y0 + 2 * size_in_luma_v)) - (y0 + size_in_luma_v)) >> vshift; int top_right_size = (((x0 + 2 * size_in_luma_h) > - (s->ps.sps->width) ? (s->ps.sps->width) : (x0 + 2 * size_in_luma_h)) - + (sps->width) ? (sps->width) : (x0 + 2 * size_in_luma_h)) - (x0 + size_in_luma_h)) >> hshift; - if (s->ps.pps->constrained_intra_pred_flag == 1) { - int size_in_luma_pu_v = ((size_in_luma_v) >> s->ps.sps->log2_min_pu_size); - int size_in_luma_pu_h = ((size_in_luma_h) >> s->ps.sps->log2_min_pu_size); - int on_pu_edge_x = !(x0 & ((1 << s->ps.sps->log2_min_pu_size) - 1)); - int on_pu_edge_y = !(y0 & ((1 << s->ps.sps->log2_min_pu_size) - 1)); + if (pps->constrained_intra_pred_flag == 1) { + int size_in_luma_pu_v = ((size_in_luma_v) >> sps->log2_min_pu_size); + int size_in_luma_pu_h = ((size_in_luma_h) >> sps->log2_min_pu_size); + int on_pu_edge_x = !(x0 & ((1 << sps->log2_min_pu_size) - 1)); + int on_pu_edge_y = !(y0 & ((1 << sps->log2_min_pu_size) - 1)); if (!size_in_luma_pu_h) size_in_luma_pu_h++; if (cand_bottom_left == 1 && on_pu_edge_x) { - int x_left_pu = ((x0 - 1) >> s->ps.sps->log2_min_pu_size); + int x_left_pu = ((x0 - 1) >> sps->log2_min_pu_size); int y_bottom_pu = - ((y0 + size_in_luma_v) >> s->ps.sps->log2_min_pu_size); + ((y0 + size_in_luma_v) >> sps->log2_min_pu_size); int max = ((size_in_luma_pu_v) > - (s->ps.sps->min_pu_height - - y_bottom_pu) ? (s->ps.sps->min_pu_height - + (sps->min_pu_height - + y_bottom_pu) ? (sps->min_pu_height - y_bottom_pu) : (size_in_luma_pu_v)); cand_bottom_left = 0; for (i = 0; i < max; i += 2) cand_bottom_left |= - ((s->ref->tab_mvf[(x_left_pu) + + ((s->cur_frame->tab_mvf[(x_left_pu) + (y_bottom_pu + i) * min_pu_width]).pred_flag == PF_INTRA); } if (cand_left == 1 && on_pu_edge_x) { - int x_left_pu = ((x0 - 1) >> s->ps.sps->log2_min_pu_size); - int y_left_pu = ((y0) >> s->ps.sps->log2_min_pu_size); + int x_left_pu = ((x0 - 1) >> sps->log2_min_pu_size); + int y_left_pu = ((y0) >> sps->log2_min_pu_size); int max = ((size_in_luma_pu_v) > - (s->ps.sps->min_pu_height - - y_left_pu) ? (s->ps.sps->min_pu_height - + (sps->min_pu_height - + y_left_pu) ? (sps->min_pu_height - y_left_pu) : (size_in_luma_pu_v)); cand_left = 0; for (i = 0; i < max; i += 2) cand_left |= - ((s->ref->tab_mvf[(x_left_pu) + + ((s->cur_frame->tab_mvf[(x_left_pu) + (y_left_pu + i) * min_pu_width]).pred_flag == PF_INTRA); } if (cand_up_left == 1) { - int x_left_pu = ((x0 - 1) >> s->ps.sps->log2_min_pu_size); - int y_top_pu = ((y0 - 1) >> s->ps.sps->log2_min_pu_size); + int x_left_pu = ((x0 - 1) >> sps->log2_min_pu_size); + int y_top_pu = ((y0 - 1) >> sps->log2_min_pu_size); cand_up_left = - (s->ref->tab_mvf[(x_left_pu) + + (s->cur_frame->tab_mvf[(x_left_pu) + (y_top_pu) * min_pu_width]).pred_flag == PF_INTRA; } if (cand_up == 1 && on_pu_edge_y) { - int x_top_pu = ((x0) >> s->ps.sps->log2_min_pu_size); - int y_top_pu = ((y0 - 1) >> s->ps.sps->log2_min_pu_size); + int x_top_pu = ((x0) >> sps->log2_min_pu_size); + int y_top_pu = ((y0 - 1) >> sps->log2_min_pu_size); int max = ((size_in_luma_pu_h) > - (s->ps.sps->min_pu_width - - x_top_pu) ? (s->ps.sps->min_pu_width - + (sps->min_pu_width - + x_top_pu) ? (sps->min_pu_width - x_top_pu) : (size_in_luma_pu_h)); cand_up = 0; for (i = 0; i < max; i += 2) cand_up |= - ((s->ref->tab_mvf[(x_top_pu + i) + + ((s->cur_frame->tab_mvf[(x_top_pu + i) + (y_top_pu) * min_pu_width]).pred_flag == PF_INTRA); } if (cand_up_right == 1 && on_pu_edge_y) { - int y_top_pu = ((y0 - 1) >> s->ps.sps->log2_min_pu_size); + int y_top_pu = ((y0 - 1) >> sps->log2_min_pu_size); int x_right_pu = - ((x0 + size_in_luma_h) >> s->ps.sps->log2_min_pu_size); + ((x0 + size_in_luma_h) >> sps->log2_min_pu_size); int max = ((size_in_luma_pu_h) > - (s->ps.sps->min_pu_width - - x_right_pu) ? (s->ps.sps->min_pu_width - + (sps->min_pu_width - + x_right_pu) ? (sps->min_pu_width - x_right_pu) : (size_in_luma_pu_h)); cand_up_right = 0; for (i = 0; i < max; i += 2) cand_up_right |= - ((s->ref->tab_mvf[(x_right_pu + i) + + ((s->cur_frame->tab_mvf[(x_right_pu + i) + (y_top_pu) * min_pu_width]).pred_flag == PF_INTRA); } @@ -2086,70 +2088,68 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) } while (0); } - if (s->ps.pps->constrained_intra_pred_flag == 1) { + if (pps->constrained_intra_pred_flag == 1) { if (cand_bottom_left || cand_left || cand_up_left || cand_up || cand_up_right) { int size_max_x = x0 + ((2 * 16) << hshift) < - s->ps.sps->width ? 2 * 16 : (s->ps.sps->width - x0) >> hshift; + sps->width ? 2 * 16 : (sps->width - x0) >> hshift; int size_max_y = y0 + ((2 * 16) << vshift) < - s->ps.sps->height ? 2 * 16 : (s->ps.sps->height - y0) >> vshift; + sps->height ? 2 * 16 : (sps->height - y0) >> vshift; int j = 16 + (cand_bottom_left ? bottom_left_size : 0) - 1; if (!cand_up_right) { - size_max_x = x0 + ((16) << hshift) < s->ps.sps->width ? - 16 : (s->ps.sps->width - x0) >> hshift; + size_max_x = x0 + ((16) << hshift) < sps->width ? + 16 : (sps->width - x0) >> hshift; } if (!cand_bottom_left) { - size_max_y = y0 + ((16) << vshift) < s->ps.sps->height ? - 16 : (s->ps.sps->height - y0) >> vshift; + size_max_y = y0 + ((16) << vshift) < sps->height ? + 16 : (sps->height - y0) >> vshift; } if (cand_bottom_left || cand_left || cand_up_left) { while (j > -1 && - !((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + !((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((j) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) j--; if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((j) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) { j = 0; while (j < size_max_x && - !((s->ref->tab_mvf[(((x0 + - ((j) << hshift)) >> s->ps.sps-> + !((s->cur_frame->tab_mvf[(((x0 + + ((j) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s-> - ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) j++; for (i = j; i > (j) - (j + 1); i--) if (! - ((s->ref->tab_mvf[(((x0 + + ((s->cur_frame->tab_mvf[(((x0 + ((i - - 1) << hshift)) >> s->ps.sps-> + 1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s-> - ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2160,12 +2160,12 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) j = 0; while (j < size_max_x && - !((s->ref->tab_mvf[(((x0 + - ((j) << hshift)) >> s->ps.sps-> + !((s->cur_frame->tab_mvf[(((x0 + + ((j) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2174,14 +2174,14 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) if (x0 > 0) { for (i = j; i > (j) - (j + 1); i--) if (! - ((s->ref->tab_mvf[(((x0 + + ((s->cur_frame->tab_mvf[(((x0 + ((i - 1) << hshift)) >> - s->ps.sps->log2_min_pu_size)) + sps->log2_min_pu_size)) + (((y0 + ((-1) << vshift)) >> - s->ps.sps->log2_min_pu_size)) + sps->log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2189,14 +2189,14 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) } else { for (i = j; i > (j) - (j); i--) if (! - ((s->ref->tab_mvf[(((x0 + + ((s->cur_frame->tab_mvf[(((x0 + ((i - 1) << hshift)) >> - s->ps.sps->log2_min_pu_size)) + sps->log2_min_pu_size)) + (((y0 + ((-1) << vshift)) >> - s->ps.sps->log2_min_pu_size)) + sps->log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2210,12 +2210,12 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) a = ((left[-1]) * 0x01010101U); for (i = 0; i < (0) + (size_max_y); i += 4) if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((i) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2239,13 +2239,13 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) for (i = (size_max_y - 1); i > (size_max_y - 1) - (size_max_y); i -= 4) if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((i - 3) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2253,12 +2253,12 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) else a = ((left[i - 3]) * 0x01010101U); if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) left[-1] = left[0]; @@ -2273,13 +2273,13 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) for (i = (size_max_y - 1); i > (size_max_y - 1) - (size_max_y); i -= 4) if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((i - 3) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2292,12 +2292,12 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) a = ((left[-1]) * 0x01010101U); for (i = 0; i < (0) + (size_max_x); i += 4) if (! - ((s->ref->tab_mvf[(((x0 + - ((i) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((i) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2369,8 +2369,8 @@ void ff_intra_pred_8_16x16_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) top[-1] = left[-1]; - if (!s->ps.sps->intra_smoothing_disabled_flag - && (c_idx == 0 || s->ps.sps->chroma_format_idc == 3)) { + if (!sps->intra_smoothing_disabled + && (c_idx == 0 || sps->chroma_format_idc == 3)) { if (mode != INTRA_DC && 16 != 4) { int intra_hor_ver_dist_thresh[] = { 7, 1, 0 }; int min_dist_vert_hor = @@ -2423,26 +2423,27 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) v8i16 res0, res1, res2, res3; v8i16 mul_val0 = { 63, 62, 61, 60, 59, 58, 57, 56 }; v8i16 mul_val1 = { 1, 2, 3, 4, 5, 6, 7, 8 }; + const HEVCSPS *const sps = pps->sps; const HEVCContext *const s = lc->parent; int i; - int hshift = s->ps.sps->hshift[c_idx]; - int vshift = s->ps.sps->vshift[c_idx]; + int hshift = sps->hshift[c_idx]; + int vshift = sps->vshift[c_idx]; int size_in_luma_h = 32 << hshift; - int size_in_tbs_h = size_in_luma_h >> s->ps.sps->log2_min_tb_size; + int size_in_tbs_h = size_in_luma_h >> sps->log2_min_tb_size; int size_in_luma_v = 32 << vshift; - int size_in_tbs_v = size_in_luma_v >> s->ps.sps->log2_min_tb_size; + int size_in_tbs_v = size_in_luma_v >> sps->log2_min_tb_size; int x = x0 >> hshift; int y = y0 >> vshift; - int x_tb = (x0 >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask; - int y_tb = (y0 >> s->ps.sps->log2_min_tb_size) & s->ps.sps->tb_mask; + int x_tb = (x0 >> sps->log2_min_tb_size) & sps->tb_mask; + int y_tb = (y0 >> sps->log2_min_tb_size) & sps->tb_mask; int cur_tb_addr = - s->ps.pps->min_tb_addr_zs[(y_tb) * (s->ps.sps->tb_mask + 2) + (x_tb)]; + pps->min_tb_addr_zs[(y_tb) * (sps->tb_mask + 2) + (x_tb)]; ptrdiff_t stride = s->frame->linesize[c_idx] / sizeof(uint8_t); uint8_t *src = (uint8_t *) s->frame->data[c_idx] + x + y * stride; - int min_pu_width = s->ps.sps->min_pu_width; + int min_pu_width = sps->min_pu_width; enum IntraPredMode mode = c_idx ? lc->tu.intra_pred_mode_c : lc->tu.intra_pred_mode; @@ -2458,102 +2459,102 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) uint8_t *filtered_top = filtered_top_array + 1; int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > - s->ps.pps->min_tb_addr_zs[((y_tb + size_in_tbs_v) & s->ps.sps->tb_mask) * - (s->ps.sps->tb_mask + 2) + (x_tb - 1)]; + pps->min_tb_addr_zs[((y_tb + size_in_tbs_v) & sps->tb_mask) * + (sps->tb_mask + 2) + (x_tb - 1)]; int cand_left = lc->na.cand_left; int cand_up_left = lc->na.cand_up_left; int cand_up = lc->na.cand_up; int cand_up_right = lc->na.cand_up_right && cur_tb_addr > - s->ps.pps->min_tb_addr_zs[(y_tb - 1) * (s->ps.sps->tb_mask + 2) + - ((x_tb + size_in_tbs_h) & s->ps.sps->tb_mask)]; + pps->min_tb_addr_zs[(y_tb - 1) * (sps->tb_mask + 2) + + ((x_tb + size_in_tbs_h) & sps->tb_mask)]; int bottom_left_size = (((y0 + 2 * size_in_luma_v) > - (s->ps.sps->height) ? (s->ps.sps->height) : (y0 + + (sps->height) ? (sps->height) : (y0 + 2 * size_in_luma_v)) - (y0 + size_in_luma_v)) >> vshift; int top_right_size = (((x0 + 2 * size_in_luma_h) > - (s->ps.sps->width) ? (s->ps.sps->width) : (x0 + 2 * size_in_luma_h)) - + (sps->width) ? (sps->width) : (x0 + 2 * size_in_luma_h)) - (x0 + size_in_luma_h)) >> hshift; - if (s->ps.pps->constrained_intra_pred_flag == 1) { - int size_in_luma_pu_v = ((size_in_luma_v) >> s->ps.sps->log2_min_pu_size); - int size_in_luma_pu_h = ((size_in_luma_h) >> s->ps.sps->log2_min_pu_size); - int on_pu_edge_x = !(x0 & ((1 << s->ps.sps->log2_min_pu_size) - 1)); - int on_pu_edge_y = !(y0 & ((1 << s->ps.sps->log2_min_pu_size) - 1)); + if (pps->constrained_intra_pred_flag == 1) { + int size_in_luma_pu_v = ((size_in_luma_v) >> sps->log2_min_pu_size); + int size_in_luma_pu_h = ((size_in_luma_h) >> sps->log2_min_pu_size); + int on_pu_edge_x = !(x0 & ((1 << sps->log2_min_pu_size) - 1)); + int on_pu_edge_y = !(y0 & ((1 << sps->log2_min_pu_size) - 1)); if (!size_in_luma_pu_h) size_in_luma_pu_h++; if (cand_bottom_left == 1 && on_pu_edge_x) { - int x_left_pu = ((x0 - 1) >> s->ps.sps->log2_min_pu_size); + int x_left_pu = ((x0 - 1) >> sps->log2_min_pu_size); int y_bottom_pu = - ((y0 + size_in_luma_v) >> s->ps.sps->log2_min_pu_size); + ((y0 + size_in_luma_v) >> sps->log2_min_pu_size); int max = ((size_in_luma_pu_v) > - (s->ps.sps->min_pu_height - - y_bottom_pu) ? (s->ps.sps->min_pu_height - + (sps->min_pu_height - + y_bottom_pu) ? (sps->min_pu_height - y_bottom_pu) : (size_in_luma_pu_v)); cand_bottom_left = 0; for (i = 0; i < max; i += 2) cand_bottom_left |= - ((s->ref->tab_mvf[(x_left_pu) + + ((s->cur_frame->tab_mvf[(x_left_pu) + (y_bottom_pu + i) * min_pu_width]).pred_flag == PF_INTRA); } if (cand_left == 1 && on_pu_edge_x) { - int x_left_pu = ((x0 - 1) >> s->ps.sps->log2_min_pu_size); - int y_left_pu = ((y0) >> s->ps.sps->log2_min_pu_size); + int x_left_pu = ((x0 - 1) >> sps->log2_min_pu_size); + int y_left_pu = ((y0) >> sps->log2_min_pu_size); int max = ((size_in_luma_pu_v) > - (s->ps.sps->min_pu_height - - y_left_pu) ? (s->ps.sps->min_pu_height - + (sps->min_pu_height - + y_left_pu) ? (sps->min_pu_height - y_left_pu) : (size_in_luma_pu_v)); cand_left = 0; for (i = 0; i < max; i += 2) cand_left |= - ((s->ref->tab_mvf[(x_left_pu) + + ((s->cur_frame->tab_mvf[(x_left_pu) + (y_left_pu + i) * min_pu_width]).pred_flag == PF_INTRA); } if (cand_up_left == 1) { - int x_left_pu = ((x0 - 1) >> s->ps.sps->log2_min_pu_size); - int y_top_pu = ((y0 - 1) >> s->ps.sps->log2_min_pu_size); + int x_left_pu = ((x0 - 1) >> sps->log2_min_pu_size); + int y_top_pu = ((y0 - 1) >> sps->log2_min_pu_size); cand_up_left = - (s->ref->tab_mvf[(x_left_pu) + + (s->cur_frame->tab_mvf[(x_left_pu) + (y_top_pu) * min_pu_width]).pred_flag == PF_INTRA; } if (cand_up == 1 && on_pu_edge_y) { - int x_top_pu = ((x0) >> s->ps.sps->log2_min_pu_size); - int y_top_pu = ((y0 - 1) >> s->ps.sps->log2_min_pu_size); + int x_top_pu = ((x0) >> sps->log2_min_pu_size); + int y_top_pu = ((y0 - 1) >> sps->log2_min_pu_size); int max = ((size_in_luma_pu_h) > - (s->ps.sps->min_pu_width - - x_top_pu) ? (s->ps.sps->min_pu_width - + (sps->min_pu_width - + x_top_pu) ? (sps->min_pu_width - x_top_pu) : (size_in_luma_pu_h)); cand_up = 0; for (i = 0; i < max; i += 2) cand_up |= - ((s->ref->tab_mvf[(x_top_pu + i) + + ((s->cur_frame->tab_mvf[(x_top_pu + i) + (y_top_pu) * min_pu_width]).pred_flag == PF_INTRA); } if (cand_up_right == 1 && on_pu_edge_y) { - int y_top_pu = ((y0 - 1) >> s->ps.sps->log2_min_pu_size); + int y_top_pu = ((y0 - 1) >> sps->log2_min_pu_size); int x_right_pu = - ((x0 + size_in_luma_h) >> s->ps.sps->log2_min_pu_size); + ((x0 + size_in_luma_h) >> sps->log2_min_pu_size); int max = ((size_in_luma_pu_h) > - (s->ps.sps->min_pu_width - - x_right_pu) ? (s->ps.sps->min_pu_width - + (sps->min_pu_width - + x_right_pu) ? (sps->min_pu_width - x_right_pu) : (size_in_luma_pu_h)); cand_up_right = 0; for (i = 0; i < max; i += 2) cand_up_right |= - ((s->ref->tab_mvf[(x_right_pu + i) + + ((s->cur_frame->tab_mvf[(x_right_pu + i) + (y_top_pu) * min_pu_width]).pred_flag == PF_INTRA); } @@ -2601,70 +2602,68 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) } while (0); } - if (s->ps.pps->constrained_intra_pred_flag == 1) { + if (pps->constrained_intra_pred_flag == 1) { if (cand_bottom_left || cand_left || cand_up_left || cand_up || cand_up_right) { int size_max_x = x0 + ((2 * 32) << hshift) < - s->ps.sps->width ? 2 * 32 : (s->ps.sps->width - x0) >> hshift; + sps->width ? 2 * 32 : (sps->width - x0) >> hshift; int size_max_y = y0 + ((2 * 32) << vshift) < - s->ps.sps->height ? 2 * 32 : (s->ps.sps->height - y0) >> vshift; + sps->height ? 2 * 32 : (sps->height - y0) >> vshift; int j = 32 + (cand_bottom_left ? bottom_left_size : 0) - 1; if (!cand_up_right) { - size_max_x = x0 + ((32) << hshift) < s->ps.sps->width ? - 32 : (s->ps.sps->width - x0) >> hshift; + size_max_x = x0 + ((32) << hshift) < sps->width ? + 32 : (sps->width - x0) >> hshift; } if (!cand_bottom_left) { - size_max_y = y0 + ((32) << vshift) < s->ps.sps->height ? - 32 : (s->ps.sps->height - y0) >> vshift; + size_max_y = y0 + ((32) << vshift) < sps->height ? + 32 : (sps->height - y0) >> vshift; } if (cand_bottom_left || cand_left || cand_up_left) { while (j > -1 && - !((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + !((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((j) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) j--; if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((j) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) { j = 0; while (j < size_max_x && - !((s->ref->tab_mvf[(((x0 + - ((j) << hshift)) >> s->ps.sps-> + !((s->cur_frame->tab_mvf[(((x0 + + ((j) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s-> - ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) j++; for (i = j; i > (j) - (j + 1); i--) if (! - ((s->ref->tab_mvf[(((x0 + + ((s->cur_frame->tab_mvf[(((x0 + ((i - - 1) << hshift)) >> s->ps.sps-> + 1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s-> - ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2675,12 +2674,12 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) j = 0; while (j < size_max_x && - !((s->ref->tab_mvf[(((x0 + - ((j) << hshift)) >> s->ps.sps-> + !((s->cur_frame->tab_mvf[(((x0 + + ((j) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2689,14 +2688,14 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) if (x0 > 0) { for (i = j; i > (j) - (j + 1); i--) if (! - ((s->ref->tab_mvf[(((x0 + + ((s->cur_frame->tab_mvf[(((x0 + ((i - 1) << hshift)) >> - s->ps.sps->log2_min_pu_size)) + sps->log2_min_pu_size)) + (((y0 + ((-1) << vshift)) >> - s->ps.sps->log2_min_pu_size)) + sps->log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2704,14 +2703,14 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) } else { for (i = j; i > (j) - (j); i--) if (! - ((s->ref->tab_mvf[(((x0 + + ((s->cur_frame->tab_mvf[(((x0 + ((i - 1) << hshift)) >> - s->ps.sps->log2_min_pu_size)) + sps->log2_min_pu_size)) + (((y0 + ((-1) << vshift)) >> - s->ps.sps->log2_min_pu_size)) + sps->log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2725,12 +2724,12 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) a = ((left[-1]) * 0x01010101U); for (i = 0; i < (0) + (size_max_y); i += 4) if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((i) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2753,13 +2752,13 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) for (i = (size_max_y - 1); i > (size_max_y - 1) - (size_max_y); i -= 4) if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((i - 3) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2767,12 +2766,12 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) else a = ((left[i - 3]) * 0x01010101U); if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) left[-1] = left[0]; @@ -2787,13 +2786,13 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) for (i = (size_max_y - 1); i > (size_max_y - 1) - (size_max_y); i -= 4) if (! - ((s->ref->tab_mvf[(((x0 + - ((-1) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((-1) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((i - 3) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2806,12 +2805,12 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) a = ((left[-1]) * 0x01010101U); for (i = 0; i < (0) + (size_max_x); i += 4) if (! - ((s->ref->tab_mvf[(((x0 + - ((i) << hshift)) >> s->ps.sps-> + ((s->cur_frame->tab_mvf[(((x0 + + ((i) << hshift)) >> sps-> log2_min_pu_size)) + (((y0 + ((-1) << vshift)) - >> s->ps.sps-> + >> sps-> log2_min_pu_size)) * min_pu_width]).pred_flag == PF_INTRA)) @@ -2886,8 +2885,8 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) top[-1] = left[-1]; - if (!s->ps.sps->intra_smoothing_disabled_flag - && (c_idx == 0 || s->ps.sps->chroma_format_idc == 3)) { + if (!sps->intra_smoothing_disabled + && (c_idx == 0 || sps->chroma_format_idc == 3)) { if (mode != INTRA_DC && 32 != 4) { int intra_hor_ver_dist_thresh[] = { 7, 1, 0 }; int min_dist_vert_hor = @@ -2901,7 +2900,7 @@ void ff_intra_pred_8_32x32_msa(HEVCLocalContext *lc, int x0, int y0, int c_idx) 0 ? ((int) (mode - 26U)) : (-((int) (mode - 26U)))))); if (min_dist_vert_hor > intra_hor_ver_dist_thresh[5 - 3]) { int threshold = 1 << (8 - 5); - if (s->ps.sps->sps_strong_intra_smoothing_enable_flag + if (sps->strong_intra_smoothing_enabled && c_idx == 0 && ((top[-1] + top[63] - 2 * top[31]) >= 0 ? (top[-1] + top[63] - diff --git a/libavcodec/mips/mpegvideo_init_mips.c b/libavcodec/mips/mpegvideo_init_mips.c index f687ad18f..1d02b0c93 100644 --- a/libavcodec/mips/mpegvideo_init_mips.c +++ b/libavcodec/mips/mpegvideo_init_mips.c @@ -36,8 +36,6 @@ av_cold void ff_mpv_common_init_mips(MpegEncContext *s) if (!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT)) if (!s->q_scale_type) s->dct_unquantize_mpeg2_intra = ff_dct_unquantize_mpeg2_intra_mmi; - - s->denoise_dct= ff_denoise_dct_mmi; } if (have_msa(cpu_flags)) { diff --git a/libavcodec/mips/mpegvideo_mmi.c b/libavcodec/mips/mpegvideo_mmi.c index 3d5b5e20a..7af421db6 100644 --- a/libavcodec/mips/mpegvideo_mmi.c +++ b/libavcodec/mips/mpegvideo_mmi.c @@ -434,75 +434,3 @@ void ff_dct_unquantize_mpeg2_intra_mmi(MpegEncContext *s, int16_t *block, block[0]= block0; } - -void ff_denoise_dct_mmi(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]; - 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" - MMI_LDC1(%[ftmp1], %[block], 0x00) - "pxor %[ftmp2], %[ftmp2], %[ftmp2] \n\t" - MMI_LDC1(%[ftmp3], %[block], 0x08) - "pxor %[ftmp4], %[ftmp4], %[ftmp4] \n\t" - "pcmpgth %[ftmp2], %[ftmp2], %[ftmp1] \n\t" - "pcmpgth %[ftmp4], %[ftmp4], %[ftmp3] \n\t" - "pxor %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "pxor %[ftmp3], %[ftmp3], %[ftmp4] \n\t" - "psubh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "psubh %[ftmp3], %[ftmp3], %[ftmp4] \n\t" - MMI_LDC1(%[ftmp6], %[offset], 0x00) - "mov.d %[ftmp5], %[ftmp1] \n\t" - "psubush %[ftmp1], %[ftmp1], %[ftmp6] \n\t" - MMI_LDC1(%[ftmp6], %[offset], 0x08) - "mov.d %[ftmp7], %[ftmp3] \n\t" - "psubush %[ftmp3], %[ftmp3], %[ftmp6] \n\t" - "pxor %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "pxor %[ftmp3], %[ftmp3], %[ftmp4] \n\t" - "psubh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "psubh %[ftmp3], %[ftmp3], %[ftmp4] \n\t" - MMI_SDC1(%[ftmp1], %[block], 0x00) - MMI_SDC1(%[ftmp3], %[block], 0x08) - "mov.d %[ftmp1], %[ftmp5] \n\t" - "mov.d %[ftmp3], %[ftmp7] \n\t" - "punpcklhw %[ftmp5], %[ftmp5], %[ftmp0] \n\t" - "punpckhhw %[ftmp1], %[ftmp1], %[ftmp0] \n\t" - "punpcklhw %[ftmp7], %[ftmp7], %[ftmp0] \n\t" - "punpckhhw %[ftmp3], %[ftmp3], %[ftmp0] \n\t" - MMI_LDC1(%[ftmp2], %[sum], 0x00) - "paddw %[ftmp5], %[ftmp5], %[ftmp2] \n\t" - MMI_LDC1(%[ftmp2], %[sum], 0x08) - "paddw %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - MMI_LDC1(%[ftmp2], %[sum], 0x10) - "paddw %[ftmp7], %[ftmp7], %[ftmp2] \n\t" - MMI_LDC1(%[ftmp2], %[sum], 0x18) - "paddw %[ftmp3], %[ftmp3], %[ftmp2] \n\t" - MMI_SDC1(%[ftmp5], %[sum], 0x00) - MMI_SDC1(%[ftmp1], %[sum], 0x08) - MMI_SDC1(%[ftmp7], %[sum], 0x10) - MMI_SDC1(%[ftmp3], %[sum], 0x18) - PTR_ADDIU "%[block], %[block], 0x10 \n\t" - PTR_ADDIU "%[sum], %[sum], 0x20 \n\t" - PTR_SUBU "%[addr0], %[block1], %[block] \n\t" - PTR_ADDIU "%[offset], %[offset], 0x10 \n\t" - "bgtz %[addr0], 1b \n\t" - : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), - [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), - [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), - [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), - RESTRICT_ASM_ALL64 - [addr0]"=&r"(addr[0]), - [block]"+&r"(block), [sum]"+&r"(sum), - [offset]"+&r"(offset) - : [block1]"r"(block+64) - : "memory" - ); -} diff --git a/libavutil/avr32/bswap.h b/libavcodec/mips/mpegvideoenc_init_mips.c similarity index 62% rename from libavutil/avr32/bswap.h rename to libavcodec/mips/mpegvideoenc_init_mips.c index e79d53f36..5ef066493 100644 --- a/libavutil/avr32/bswap.h +++ b/libavcodec/mips/mpegvideoenc_init_mips.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2015 Manojkumar Bhosale (Manojkumar.Bhosale@imgtec.com) + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -16,29 +18,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVUTIL_AVR32_BSWAP_H -#define AVUTIL_AVR32_BSWAP_H - -#include -#include "config.h" #include "libavutil/attributes.h" +#include "libavutil/mips/cpu.h" +#include "libavcodec/mpegvideoenc.h" +#include "mpegvideo_mips.h" -#if HAVE_INLINE_ASM - -#define av_bswap16 av_bswap16 -static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +av_cold void ff_mpvenc_dct_init_mips(MpegEncContext *s) { - __asm__ ("swap.bh %0" : "+r"(x)); - return x; + int cpu_flags = av_get_cpu_flags(); + + if (have_mmi(cpu_flags)) { + s->denoise_dct = ff_denoise_dct_mmi; + } } - -#define av_bswap32 av_bswap32 -static av_always_inline av_const uint32_t av_bswap32(uint32_t x) -{ - __asm__ ("swap.b %0" : "+r"(x)); - return x; -} - -#endif /* HAVE_INLINE_ASM */ - -#endif /* AVUTIL_AVR32_BSWAP_H */ diff --git a/libavcodec/mips/mpegvideoenc_mmi.c b/libavcodec/mips/mpegvideoenc_mmi.c new file mode 100644 index 000000000..65da155e9 --- /dev/null +++ b/libavcodec/mips/mpegvideoenc_mmi.c @@ -0,0 +1,98 @@ +/* + * Loongson SIMD optimized mpegvideo + * + * Copyright (c) 2015 Loongson Technology Corporation Limited + * Copyright (c) 2015 Zhou Xiaoyong + * Zhang Shuangshuang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 "mpegvideo_mips.h" +#include "libavutil/mips/mmiutils.h" + +void ff_denoise_dct_mmi(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]; + 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" + MMI_LDC1(%[ftmp1], %[block], 0x00) + "pxor %[ftmp2], %[ftmp2], %[ftmp2] \n\t" + MMI_LDC1(%[ftmp3], %[block], 0x08) + "pxor %[ftmp4], %[ftmp4], %[ftmp4] \n\t" + "pcmpgth %[ftmp2], %[ftmp2], %[ftmp1] \n\t" + "pcmpgth %[ftmp4], %[ftmp4], %[ftmp3] \n\t" + "pxor %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "pxor %[ftmp3], %[ftmp3], %[ftmp4] \n\t" + "psubh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "psubh %[ftmp3], %[ftmp3], %[ftmp4] \n\t" + MMI_LDC1(%[ftmp6], %[offset], 0x00) + "mov.d %[ftmp5], %[ftmp1] \n\t" + "psubush %[ftmp1], %[ftmp1], %[ftmp6] \n\t" + MMI_LDC1(%[ftmp6], %[offset], 0x08) + "mov.d %[ftmp7], %[ftmp3] \n\t" + "psubush %[ftmp3], %[ftmp3], %[ftmp6] \n\t" + "pxor %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "pxor %[ftmp3], %[ftmp3], %[ftmp4] \n\t" + "psubh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "psubh %[ftmp3], %[ftmp3], %[ftmp4] \n\t" + MMI_SDC1(%[ftmp1], %[block], 0x00) + MMI_SDC1(%[ftmp3], %[block], 0x08) + "mov.d %[ftmp1], %[ftmp5] \n\t" + "mov.d %[ftmp3], %[ftmp7] \n\t" + "punpcklhw %[ftmp5], %[ftmp5], %[ftmp0] \n\t" + "punpckhhw %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "punpcklhw %[ftmp7], %[ftmp7], %[ftmp0] \n\t" + "punpckhhw %[ftmp3], %[ftmp3], %[ftmp0] \n\t" + MMI_LDC1(%[ftmp2], %[sum], 0x00) + "paddw %[ftmp5], %[ftmp5], %[ftmp2] \n\t" + MMI_LDC1(%[ftmp2], %[sum], 0x08) + "paddw %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + MMI_LDC1(%[ftmp2], %[sum], 0x10) + "paddw %[ftmp7], %[ftmp7], %[ftmp2] \n\t" + MMI_LDC1(%[ftmp2], %[sum], 0x18) + "paddw %[ftmp3], %[ftmp3], %[ftmp2] \n\t" + MMI_SDC1(%[ftmp5], %[sum], 0x00) + MMI_SDC1(%[ftmp1], %[sum], 0x08) + MMI_SDC1(%[ftmp7], %[sum], 0x10) + MMI_SDC1(%[ftmp3], %[sum], 0x18) + PTR_ADDIU "%[block], %[block], 0x10 \n\t" + PTR_ADDIU "%[sum], %[sum], 0x20 \n\t" + PTR_SUBU "%[addr0], %[block1], %[block] \n\t" + PTR_ADDIU "%[offset], %[offset], 0x10 \n\t" + "bgtz %[addr0], 1b \n\t" + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), + RESTRICT_ASM_ALL64 + [addr0]"=&r"(addr[0]), + [block]"+&r"(block), [sum]"+&r"(sum), + [offset]"+&r"(offset) + : [block1]"r"(block+64) + : "memory" + ); +} diff --git a/libavcodec/mips/mpegvideoencdsp_msa.c b/libavcodec/mips/mpegvideoencdsp_msa.c index 9043730cd..91e0f0068 100644 --- a/libavcodec/mips/mpegvideoencdsp_msa.c +++ b/libavcodec/mips/mpegvideoencdsp_msa.c @@ -56,7 +56,7 @@ static int32_t sum_u8src_16width_msa(const uint8_t *src, int32_t stride) return sum; } -int ff_pix_sum_msa(const uint8_t *pix, int line_size) +int ff_pix_sum_msa(const uint8_t *pix, ptrdiff_t line_size) { return sum_u8src_16width_msa(pix, line_size); } diff --git a/libavcodec/mips/sbrdsp_mips.c b/libavcodec/mips/sbrdsp_mips.c deleted file mode 100644 index 1c87c9925..000000000 --- a/libavcodec/mips/sbrdsp_mips.c +++ /dev/null @@ -1,912 +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. - * - * Authors: Darko Laus (darko@mips.com) - * Djordje Pesut (djordje@mips.com) - * Mirjana Vulin (mvulin@mips.com) - * - * AAC Spectral Band Replication decoding functions optimized for MIPS - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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/sbrdsp.c - */ - -#include "config.h" -#include "libavcodec/sbrdsp.h" -#include "libavutil/mips/asmdefs.h" - -#if HAVE_INLINE_ASM -#if HAVE_MIPSFPU -static void sbr_qmf_pre_shuffle_mips(float *z) -{ - int Temp1, Temp2, Temp3, Temp4, Temp5, Temp6; - float *z1 = &z[66]; - float *z2 = &z[59]; - float *z3 = &z[2]; - float *z4 = z1 + 60; - - /* loop unrolled 5 times */ - __asm__ volatile ( - "lui %[Temp6], 0x8000 \n\t" - "1: \n\t" - "lw %[Temp1], 0(%[z2]) \n\t" - "lw %[Temp2], 4(%[z2]) \n\t" - "lw %[Temp3], 8(%[z2]) \n\t" - "lw %[Temp4], 12(%[z2]) \n\t" - "lw %[Temp5], 16(%[z2]) \n\t" - "xor %[Temp1], %[Temp1], %[Temp6] \n\t" - "xor %[Temp2], %[Temp2], %[Temp6] \n\t" - "xor %[Temp3], %[Temp3], %[Temp6] \n\t" - "xor %[Temp4], %[Temp4], %[Temp6] \n\t" - "xor %[Temp5], %[Temp5], %[Temp6] \n\t" - PTR_ADDIU "%[z2], %[z2], -20 \n\t" - "sw %[Temp1], 32(%[z1]) \n\t" - "sw %[Temp2], 24(%[z1]) \n\t" - "sw %[Temp3], 16(%[z1]) \n\t" - "sw %[Temp4], 8(%[z1]) \n\t" - "sw %[Temp5], 0(%[z1]) \n\t" - "lw %[Temp1], 0(%[z3]) \n\t" - "lw %[Temp2], 4(%[z3]) \n\t" - "lw %[Temp3], 8(%[z3]) \n\t" - "lw %[Temp4], 12(%[z3]) \n\t" - "lw %[Temp5], 16(%[z3]) \n\t" - "sw %[Temp1], 4(%[z1]) \n\t" - "sw %[Temp2], 12(%[z1]) \n\t" - "sw %[Temp3], 20(%[z1]) \n\t" - "sw %[Temp4], 28(%[z1]) \n\t" - "sw %[Temp5], 36(%[z1]) \n\t" - PTR_ADDIU "%[z3], %[z3], 20 \n\t" - PTR_ADDIU "%[z1], %[z1], 40 \n\t" - "bne %[z1], %[z4], 1b \n\t" - "lw %[Temp1], 132(%[z]) \n\t" - "lw %[Temp2], 128(%[z]) \n\t" - "lw %[Temp3], 0(%[z]) \n\t" - "lw %[Temp4], 4(%[z]) \n\t" - "xor %[Temp1], %[Temp1], %[Temp6] \n\t" - "sw %[Temp1], 504(%[z]) \n\t" - "sw %[Temp2], 508(%[z]) \n\t" - "sw %[Temp3], 256(%[z]) \n\t" - "sw %[Temp4], 260(%[z]) \n\t" - - : [Temp1]"=&r"(Temp1), [Temp2]"=&r"(Temp2), - [Temp3]"=&r"(Temp3), [Temp4]"=&r"(Temp4), - [Temp5]"=&r"(Temp5), [Temp6]"=&r"(Temp6), - [z1]"+r"(z1), [z2]"+r"(z2), [z3]"+r"(z3) - : [z4]"r"(z4), [z]"r"(z) - : "memory" - ); -} - -static void sbr_qmf_post_shuffle_mips(float W[32][2], const float *z) -{ - int Temp1, Temp2, Temp3, Temp4, Temp5; - float *W_ptr = (float *)W; - float *z1 = (float *)z; - float *z2 = (float *)&z[60]; - float *z_end = z1 + 32; - - /* loop unrolled 4 times */ - __asm__ volatile ( - "lui %[Temp5], 0x8000 \n\t" - "1: \n\t" - "lw %[Temp1], 0(%[z2]) \n\t" - "lw %[Temp2], 4(%[z2]) \n\t" - "lw %[Temp3], 8(%[z2]) \n\t" - "lw %[Temp4], 12(%[z2]) \n\t" - "xor %[Temp1], %[Temp1], %[Temp5] \n\t" - "xor %[Temp2], %[Temp2], %[Temp5] \n\t" - "xor %[Temp3], %[Temp3], %[Temp5] \n\t" - "xor %[Temp4], %[Temp4], %[Temp5] \n\t" - PTR_ADDIU "%[z2], %[z2], -16 \n\t" - "sw %[Temp1], 24(%[W_ptr]) \n\t" - "sw %[Temp2], 16(%[W_ptr]) \n\t" - "sw %[Temp3], 8(%[W_ptr]) \n\t" - "sw %[Temp4], 0(%[W_ptr]) \n\t" - "lw %[Temp1], 0(%[z1]) \n\t" - "lw %[Temp2], 4(%[z1]) \n\t" - "lw %[Temp3], 8(%[z1]) \n\t" - "lw %[Temp4], 12(%[z1]) \n\t" - "sw %[Temp1], 4(%[W_ptr]) \n\t" - "sw %[Temp2], 12(%[W_ptr]) \n\t" - "sw %[Temp3], 20(%[W_ptr]) \n\t" - "sw %[Temp4], 28(%[W_ptr]) \n\t" - PTR_ADDIU "%[z1], %[z1], 16 \n\t" - PTR_ADDIU "%[W_ptr],%[W_ptr], 32 \n\t" - "bne %[z1], %[z_end], 1b \n\t" - - : [Temp1]"=&r"(Temp1), [Temp2]"=&r"(Temp2), - [Temp3]"=&r"(Temp3), [Temp4]"=&r"(Temp4), - [Temp5]"=&r"(Temp5), [z1]"+r"(z1), - [z2]"+r"(z2), [W_ptr]"+r"(W_ptr) - : [z_end]"r"(z_end) - : "memory" - ); -} - -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 -static void sbr_sum64x5_mips(float *z) -{ - int k; - float *z1; - float f1, f2, f3, f4, f5, f6, f7, f8; - for (k = 0; k < 64; k += 8) { - - z1 = &z[k]; - - /* loop unrolled 8 times */ - __asm__ volatile ( - "lwc1 $f0, 0(%[z1]) \n\t" - "lwc1 $f1, 256(%[z1]) \n\t" - "lwc1 $f2, 4(%[z1]) \n\t" - "lwc1 $f3, 260(%[z1]) \n\t" - "lwc1 $f4, 8(%[z1]) \n\t" - "add.s %[f1], $f0, $f1 \n\t" - "lwc1 $f5, 264(%[z1]) \n\t" - "add.s %[f2], $f2, $f3 \n\t" - "lwc1 $f6, 12(%[z1]) \n\t" - "lwc1 $f7, 268(%[z1]) \n\t" - "add.s %[f3], $f4, $f5 \n\t" - "lwc1 $f8, 16(%[z1]) \n\t" - "lwc1 $f9, 272(%[z1]) \n\t" - "add.s %[f4], $f6, $f7 \n\t" - "lwc1 $f10, 20(%[z1]) \n\t" - "lwc1 $f11, 276(%[z1]) \n\t" - "add.s %[f5], $f8, $f9 \n\t" - "lwc1 $f12, 24(%[z1]) \n\t" - "lwc1 $f13, 280(%[z1]) \n\t" - "add.s %[f6], $f10, $f11 \n\t" - "lwc1 $f14, 28(%[z1]) \n\t" - "lwc1 $f15, 284(%[z1]) \n\t" - "add.s %[f7], $f12, $f13 \n\t" - "lwc1 $f0, 512(%[z1]) \n\t" - "lwc1 $f1, 516(%[z1]) \n\t" - "add.s %[f8], $f14, $f15 \n\t" - "lwc1 $f2, 520(%[z1]) \n\t" - "add.s %[f1], %[f1], $f0 \n\t" - "add.s %[f2], %[f2], $f1 \n\t" - "lwc1 $f3, 524(%[z1]) \n\t" - "add.s %[f3], %[f3], $f2 \n\t" - "lwc1 $f4, 528(%[z1]) \n\t" - "lwc1 $f5, 532(%[z1]) \n\t" - "add.s %[f4], %[f4], $f3 \n\t" - "lwc1 $f6, 536(%[z1]) \n\t" - "add.s %[f5], %[f5], $f4 \n\t" - "add.s %[f6], %[f6], $f5 \n\t" - "lwc1 $f7, 540(%[z1]) \n\t" - "add.s %[f7], %[f7], $f6 \n\t" - "lwc1 $f0, 768(%[z1]) \n\t" - "lwc1 $f1, 772(%[z1]) \n\t" - "add.s %[f8], %[f8], $f7 \n\t" - "lwc1 $f2, 776(%[z1]) \n\t" - "add.s %[f1], %[f1], $f0 \n\t" - "add.s %[f2], %[f2], $f1 \n\t" - "lwc1 $f3, 780(%[z1]) \n\t" - "add.s %[f3], %[f3], $f2 \n\t" - "lwc1 $f4, 784(%[z1]) \n\t" - "lwc1 $f5, 788(%[z1]) \n\t" - "add.s %[f4], %[f4], $f3 \n\t" - "lwc1 $f6, 792(%[z1]) \n\t" - "add.s %[f5], %[f5], $f4 \n\t" - "add.s %[f6], %[f6], $f5 \n\t" - "lwc1 $f7, 796(%[z1]) \n\t" - "add.s %[f7], %[f7], $f6 \n\t" - "lwc1 $f0, 1024(%[z1]) \n\t" - "lwc1 $f1, 1028(%[z1]) \n\t" - "add.s %[f8], %[f8], $f7 \n\t" - "lwc1 $f2, 1032(%[z1]) \n\t" - "add.s %[f1], %[f1], $f0 \n\t" - "add.s %[f2], %[f2], $f1 \n\t" - "lwc1 $f3, 1036(%[z1]) \n\t" - "add.s %[f3], %[f3], $f2 \n\t" - "lwc1 $f4, 1040(%[z1]) \n\t" - "lwc1 $f5, 1044(%[z1]) \n\t" - "add.s %[f4], %[f4], $f3 \n\t" - "lwc1 $f6, 1048(%[z1]) \n\t" - "add.s %[f5], %[f5], $f4 \n\t" - "add.s %[f6], %[f6], $f5 \n\t" - "lwc1 $f7, 1052(%[z1]) \n\t" - "add.s %[f7], %[f7], $f6 \n\t" - "swc1 %[f1], 0(%[z1]) \n\t" - "swc1 %[f2], 4(%[z1]) \n\t" - "add.s %[f8], %[f8], $f7 \n\t" - "swc1 %[f3], 8(%[z1]) \n\t" - "swc1 %[f4], 12(%[z1]) \n\t" - "swc1 %[f5], 16(%[z1]) \n\t" - "swc1 %[f6], 20(%[z1]) \n\t" - "swc1 %[f7], 24(%[z1]) \n\t" - "swc1 %[f8], 28(%[z1]) \n\t" - - : [f1]"=&f"(f1), [f2]"=&f"(f2), [f3]"=&f"(f3), - [f4]"=&f"(f4), [f5]"=&f"(f5), [f6]"=&f"(f6), - [f7]"=&f"(f7), [f8]"=&f"(f8) - : [z1]"r"(z1) - : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", - "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", - "$f12", "$f13", "$f14", "$f15", - "memory" - ); - } -} - -static float sbr_sum_square_mips(float (*x)[2], int n) -{ - float sum0 = 0.0f, sum1 = 0.0f; - float *p_x; - float temp0, temp1, temp2, temp3; - float *loop_end; - p_x = &x[0][0]; - loop_end = p_x + (n >> 1)*4 - 4; - - __asm__ volatile ( - ".set push \n\t" - ".set noreorder \n\t" - "lwc1 %[temp0], 0(%[p_x]) \n\t" - "lwc1 %[temp1], 4(%[p_x]) \n\t" - "lwc1 %[temp2], 8(%[p_x]) \n\t" - "lwc1 %[temp3], 12(%[p_x]) \n\t" - "1: \n\t" - PTR_ADDIU "%[p_x], %[p_x], 16 \n\t" - "madd.s %[sum0], %[sum0], %[temp0], %[temp0] \n\t" - "lwc1 %[temp0], 0(%[p_x]) \n\t" - "madd.s %[sum1], %[sum1], %[temp1], %[temp1] \n\t" - "lwc1 %[temp1], 4(%[p_x]) \n\t" - "madd.s %[sum0], %[sum0], %[temp2], %[temp2] \n\t" - "lwc1 %[temp2], 8(%[p_x]) \n\t" - "madd.s %[sum1], %[sum1], %[temp3], %[temp3] \n\t" - "bne %[p_x], %[loop_end], 1b \n\t" - " lwc1 %[temp3], 12(%[p_x]) \n\t" - "madd.s %[sum0], %[sum0], %[temp0], %[temp0] \n\t" - "madd.s %[sum1], %[sum1], %[temp1], %[temp1] \n\t" - "madd.s %[sum0], %[sum0], %[temp2], %[temp2] \n\t" - "madd.s %[sum1], %[sum1], %[temp3], %[temp3] \n\t" - ".set pop \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [sum0]"+f"(sum0), [sum1]"+f"(sum1), - [p_x]"+r"(p_x) - : [loop_end]"r"(loop_end) - : "memory" - ); - return sum0 + sum1; -} - -static void sbr_qmf_deint_bfly_mips(float *v, const float *src0, const float *src1) -{ - int i; - float temp0, temp1, temp2, temp3, temp4, temp5; - float temp6, temp7, temp8, temp9, temp10, temp11; - float *v0 = v; - float *v1 = &v[127]; - float *psrc0 = (float*)src0; - float *psrc1 = (float*)&src1[63]; - - for (i = 0; i < 4; i++) { - - /* loop unrolled 16 times */ - __asm__ volatile( - "lwc1 %[temp0], 0(%[src0]) \n\t" - "lwc1 %[temp1], 0(%[src1]) \n\t" - "lwc1 %[temp3], 4(%[src0]) \n\t" - "lwc1 %[temp4], -4(%[src1]) \n\t" - "lwc1 %[temp6], 8(%[src0]) \n\t" - "lwc1 %[temp7], -8(%[src1]) \n\t" - "lwc1 %[temp9], 12(%[src0]) \n\t" - "lwc1 %[temp10], -12(%[src1]) \n\t" - "add.s %[temp2], %[temp0], %[temp1] \n\t" - "add.s %[temp5], %[temp3], %[temp4] \n\t" - "add.s %[temp8], %[temp6], %[temp7] \n\t" - "add.s %[temp11], %[temp9], %[temp10] \n\t" - "sub.s %[temp0], %[temp0], %[temp1] \n\t" - "sub.s %[temp3], %[temp3], %[temp4] \n\t" - "sub.s %[temp6], %[temp6], %[temp7] \n\t" - "sub.s %[temp9], %[temp9], %[temp10] \n\t" - "swc1 %[temp2], 0(%[v1]) \n\t" - "swc1 %[temp0], 0(%[v0]) \n\t" - "swc1 %[temp5], -4(%[v1]) \n\t" - "swc1 %[temp3], 4(%[v0]) \n\t" - "swc1 %[temp8], -8(%[v1]) \n\t" - "swc1 %[temp6], 8(%[v0]) \n\t" - "swc1 %[temp11], -12(%[v1]) \n\t" - "swc1 %[temp9], 12(%[v0]) \n\t" - "lwc1 %[temp0], 16(%[src0]) \n\t" - "lwc1 %[temp1], -16(%[src1]) \n\t" - "lwc1 %[temp3], 20(%[src0]) \n\t" - "lwc1 %[temp4], -20(%[src1]) \n\t" - "lwc1 %[temp6], 24(%[src0]) \n\t" - "lwc1 %[temp7], -24(%[src1]) \n\t" - "lwc1 %[temp9], 28(%[src0]) \n\t" - "lwc1 %[temp10], -28(%[src1]) \n\t" - "add.s %[temp2], %[temp0], %[temp1] \n\t" - "add.s %[temp5], %[temp3], %[temp4] \n\t" - "add.s %[temp8], %[temp6], %[temp7] \n\t" - "add.s %[temp11], %[temp9], %[temp10] \n\t" - "sub.s %[temp0], %[temp0], %[temp1] \n\t" - "sub.s %[temp3], %[temp3], %[temp4] \n\t" - "sub.s %[temp6], %[temp6], %[temp7] \n\t" - "sub.s %[temp9], %[temp9], %[temp10] \n\t" - "swc1 %[temp2], -16(%[v1]) \n\t" - "swc1 %[temp0], 16(%[v0]) \n\t" - "swc1 %[temp5], -20(%[v1]) \n\t" - "swc1 %[temp3], 20(%[v0]) \n\t" - "swc1 %[temp8], -24(%[v1]) \n\t" - "swc1 %[temp6], 24(%[v0]) \n\t" - "swc1 %[temp11], -28(%[v1]) \n\t" - "swc1 %[temp9], 28(%[v0]) \n\t" - "lwc1 %[temp0], 32(%[src0]) \n\t" - "lwc1 %[temp1], -32(%[src1]) \n\t" - "lwc1 %[temp3], 36(%[src0]) \n\t" - "lwc1 %[temp4], -36(%[src1]) \n\t" - "lwc1 %[temp6], 40(%[src0]) \n\t" - "lwc1 %[temp7], -40(%[src1]) \n\t" - "lwc1 %[temp9], 44(%[src0]) \n\t" - "lwc1 %[temp10], -44(%[src1]) \n\t" - "add.s %[temp2], %[temp0], %[temp1] \n\t" - "add.s %[temp5], %[temp3], %[temp4] \n\t" - "add.s %[temp8], %[temp6], %[temp7] \n\t" - "add.s %[temp11], %[temp9], %[temp10] \n\t" - "sub.s %[temp0], %[temp0], %[temp1] \n\t" - "sub.s %[temp3], %[temp3], %[temp4] \n\t" - "sub.s %[temp6], %[temp6], %[temp7] \n\t" - "sub.s %[temp9], %[temp9], %[temp10] \n\t" - "swc1 %[temp2], -32(%[v1]) \n\t" - "swc1 %[temp0], 32(%[v0]) \n\t" - "swc1 %[temp5], -36(%[v1]) \n\t" - "swc1 %[temp3], 36(%[v0]) \n\t" - "swc1 %[temp8], -40(%[v1]) \n\t" - "swc1 %[temp6], 40(%[v0]) \n\t" - "swc1 %[temp11], -44(%[v1]) \n\t" - "swc1 %[temp9], 44(%[v0]) \n\t" - "lwc1 %[temp0], 48(%[src0]) \n\t" - "lwc1 %[temp1], -48(%[src1]) \n\t" - "lwc1 %[temp3], 52(%[src0]) \n\t" - "lwc1 %[temp4], -52(%[src1]) \n\t" - "lwc1 %[temp6], 56(%[src0]) \n\t" - "lwc1 %[temp7], -56(%[src1]) \n\t" - "lwc1 %[temp9], 60(%[src0]) \n\t" - "lwc1 %[temp10], -60(%[src1]) \n\t" - "add.s %[temp2], %[temp0], %[temp1] \n\t" - "add.s %[temp5], %[temp3], %[temp4] \n\t" - "add.s %[temp8], %[temp6], %[temp7] \n\t" - "add.s %[temp11], %[temp9], %[temp10] \n\t" - "sub.s %[temp0], %[temp0], %[temp1] \n\t" - "sub.s %[temp3], %[temp3], %[temp4] \n\t" - "sub.s %[temp6], %[temp6], %[temp7] \n\t" - "sub.s %[temp9], %[temp9], %[temp10] \n\t" - "swc1 %[temp2], -48(%[v1]) \n\t" - "swc1 %[temp0], 48(%[v0]) \n\t" - "swc1 %[temp5], -52(%[v1]) \n\t" - "swc1 %[temp3], 52(%[v0]) \n\t" - "swc1 %[temp8], -56(%[v1]) \n\t" - "swc1 %[temp6], 56(%[v0]) \n\t" - "swc1 %[temp11], -60(%[v1]) \n\t" - "swc1 %[temp9], 60(%[v0]) \n\t" - PTR_ADDIU " %[src0], %[src0], 64 \n\t" - PTR_ADDIU " %[src1], %[src1], -64 \n\t" - PTR_ADDIU " %[v0], %[v0], 64 \n\t" - PTR_ADDIU " %[v1], %[v1], -64 \n\t" - - : [v0]"+r"(v0), [v1]"+r"(v1), [src0]"+r"(psrc0), [src1]"+r"(psrc1), - [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8), - [temp9]"=&f"(temp9), [temp10]"=&f"(temp10), [temp11]"=&f"(temp11) - : - :"memory" - ); - } -} - -static void sbr_autocorrelate_mips(const float x[40][2], float phi[3][2][2]) -{ - int i; - float real_sum_0 = 0.0f; - float real_sum_1 = 0.0f; - float real_sum_2 = 0.0f; - float imag_sum_1 = 0.0f; - float imag_sum_2 = 0.0f; - float *p_x, *p_phi; - float temp0, temp1, temp2, temp3, temp4, temp5, temp6; - float temp7, temp_r, temp_r1, temp_r2, temp_r3, temp_r4; - p_x = (float*)&x[0][0]; - p_phi = &phi[0][0][0]; - - __asm__ volatile ( - "lwc1 %[temp0], 8(%[p_x]) \n\t" - "lwc1 %[temp1], 12(%[p_x]) \n\t" - "lwc1 %[temp2], 16(%[p_x]) \n\t" - "lwc1 %[temp3], 20(%[p_x]) \n\t" - "lwc1 %[temp4], 24(%[p_x]) \n\t" - "lwc1 %[temp5], 28(%[p_x]) \n\t" - "mul.s %[temp_r], %[temp1], %[temp1] \n\t" - "mul.s %[temp_r1], %[temp1], %[temp3] \n\t" - "mul.s %[temp_r2], %[temp1], %[temp2] \n\t" - "mul.s %[temp_r3], %[temp1], %[temp5] \n\t" - "mul.s %[temp_r4], %[temp1], %[temp4] \n\t" - "madd.s %[temp_r], %[temp_r], %[temp0], %[temp0] \n\t" - "madd.s %[temp_r1], %[temp_r1], %[temp0], %[temp2] \n\t" - "msub.s %[temp_r2], %[temp_r2], %[temp0], %[temp3] \n\t" - "madd.s %[temp_r3], %[temp_r3], %[temp0], %[temp4] \n\t" - "msub.s %[temp_r4], %[temp_r4], %[temp0], %[temp5] \n\t" - "add.s %[real_sum_0], %[real_sum_0], %[temp_r] \n\t" - "add.s %[real_sum_1], %[real_sum_1], %[temp_r1] \n\t" - "add.s %[imag_sum_1], %[imag_sum_1], %[temp_r2] \n\t" - "add.s %[real_sum_2], %[real_sum_2], %[temp_r3] \n\t" - "add.s %[imag_sum_2], %[imag_sum_2], %[temp_r4] \n\t" - PTR_ADDIU "%[p_x], %[p_x], 8 \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [real_sum_0]"+f"(real_sum_0), [real_sum_1]"+f"(real_sum_1), - [imag_sum_1]"+f"(imag_sum_1), [real_sum_2]"+f"(real_sum_2), - [temp_r]"=&f"(temp_r), [temp_r1]"=&f"(temp_r1), [temp_r2]"=&f"(temp_r2), - [temp_r3]"=&f"(temp_r3), [temp_r4]"=&f"(temp_r4), - [p_x]"+r"(p_x), [imag_sum_2]"+f"(imag_sum_2) - : - : "memory" - ); - - for (i = 0; i < 12; i++) { - __asm__ volatile ( - "lwc1 %[temp0], 8(%[p_x]) \n\t" - "lwc1 %[temp1], 12(%[p_x]) \n\t" - "lwc1 %[temp2], 16(%[p_x]) \n\t" - "lwc1 %[temp3], 20(%[p_x]) \n\t" - "lwc1 %[temp4], 24(%[p_x]) \n\t" - "lwc1 %[temp5], 28(%[p_x]) \n\t" - "mul.s %[temp_r], %[temp1], %[temp1] \n\t" - "mul.s %[temp_r1], %[temp1], %[temp3] \n\t" - "mul.s %[temp_r2], %[temp1], %[temp2] \n\t" - "mul.s %[temp_r3], %[temp1], %[temp5] \n\t" - "mul.s %[temp_r4], %[temp1], %[temp4] \n\t" - "madd.s %[temp_r], %[temp_r], %[temp0], %[temp0] \n\t" - "madd.s %[temp_r1], %[temp_r1], %[temp0], %[temp2] \n\t" - "msub.s %[temp_r2], %[temp_r2], %[temp0], %[temp3] \n\t" - "madd.s %[temp_r3], %[temp_r3], %[temp0], %[temp4] \n\t" - "msub.s %[temp_r4], %[temp_r4], %[temp0], %[temp5] \n\t" - "add.s %[real_sum_0], %[real_sum_0], %[temp_r] \n\t" - "add.s %[real_sum_1], %[real_sum_1], %[temp_r1] \n\t" - "add.s %[imag_sum_1], %[imag_sum_1], %[temp_r2] \n\t" - "add.s %[real_sum_2], %[real_sum_2], %[temp_r3] \n\t" - "add.s %[imag_sum_2], %[imag_sum_2], %[temp_r4] \n\t" - "lwc1 %[temp0], 32(%[p_x]) \n\t" - "lwc1 %[temp1], 36(%[p_x]) \n\t" - "mul.s %[temp_r], %[temp3], %[temp3] \n\t" - "mul.s %[temp_r1], %[temp3], %[temp5] \n\t" - "mul.s %[temp_r2], %[temp3], %[temp4] \n\t" - "mul.s %[temp_r3], %[temp3], %[temp1] \n\t" - "mul.s %[temp_r4], %[temp3], %[temp0] \n\t" - "madd.s %[temp_r], %[temp_r], %[temp2], %[temp2] \n\t" - "madd.s %[temp_r1], %[temp_r1], %[temp2], %[temp4] \n\t" - "msub.s %[temp_r2], %[temp_r2], %[temp2], %[temp5] \n\t" - "madd.s %[temp_r3], %[temp_r3], %[temp2], %[temp0] \n\t" - "msub.s %[temp_r4], %[temp_r4], %[temp2], %[temp1] \n\t" - "add.s %[real_sum_0], %[real_sum_0], %[temp_r] \n\t" - "add.s %[real_sum_1], %[real_sum_1], %[temp_r1] \n\t" - "add.s %[imag_sum_1], %[imag_sum_1], %[temp_r2] \n\t" - "add.s %[real_sum_2], %[real_sum_2], %[temp_r3] \n\t" - "add.s %[imag_sum_2], %[imag_sum_2], %[temp_r4] \n\t" - "lwc1 %[temp2], 40(%[p_x]) \n\t" - "lwc1 %[temp3], 44(%[p_x]) \n\t" - "mul.s %[temp_r], %[temp5], %[temp5] \n\t" - "mul.s %[temp_r1], %[temp5], %[temp1] \n\t" - "mul.s %[temp_r2], %[temp5], %[temp0] \n\t" - "mul.s %[temp_r3], %[temp5], %[temp3] \n\t" - "mul.s %[temp_r4], %[temp5], %[temp2] \n\t" - "madd.s %[temp_r], %[temp_r], %[temp4], %[temp4] \n\t" - "madd.s %[temp_r1], %[temp_r1], %[temp4], %[temp0] \n\t" - "msub.s %[temp_r2], %[temp_r2], %[temp4], %[temp1] \n\t" - "madd.s %[temp_r3], %[temp_r3], %[temp4], %[temp2] \n\t" - "msub.s %[temp_r4], %[temp_r4], %[temp4], %[temp3] \n\t" - "add.s %[real_sum_0], %[real_sum_0], %[temp_r] \n\t" - "add.s %[real_sum_1], %[real_sum_1], %[temp_r1] \n\t" - "add.s %[imag_sum_1], %[imag_sum_1], %[temp_r2] \n\t" - "add.s %[real_sum_2], %[real_sum_2], %[temp_r3] \n\t" - "add.s %[imag_sum_2], %[imag_sum_2], %[temp_r4] \n\t" - PTR_ADDIU "%[p_x], %[p_x], 24 \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [real_sum_0]"+f"(real_sum_0), [real_sum_1]"+f"(real_sum_1), - [imag_sum_1]"+f"(imag_sum_1), [real_sum_2]"+f"(real_sum_2), - [temp_r]"=&f"(temp_r), [temp_r1]"=&f"(temp_r1), - [temp_r2]"=&f"(temp_r2), [temp_r3]"=&f"(temp_r3), - [temp_r4]"=&f"(temp_r4), [p_x]"+r"(p_x), - [imag_sum_2]"+f"(imag_sum_2) - : - : "memory" - ); - } - __asm__ volatile ( - "lwc1 %[temp0], -296(%[p_x]) \n\t" - "lwc1 %[temp1], -292(%[p_x]) \n\t" - "lwc1 %[temp2], 8(%[p_x]) \n\t" - "lwc1 %[temp3], 12(%[p_x]) \n\t" - "lwc1 %[temp4], -288(%[p_x]) \n\t" - "lwc1 %[temp5], -284(%[p_x]) \n\t" - "lwc1 %[temp6], -280(%[p_x]) \n\t" - "lwc1 %[temp7], -276(%[p_x]) \n\t" - "madd.s %[temp_r], %[real_sum_0], %[temp0], %[temp0] \n\t" - "madd.s %[temp_r1], %[real_sum_0], %[temp2], %[temp2] \n\t" - "madd.s %[temp_r2], %[real_sum_1], %[temp0], %[temp4] \n\t" - "madd.s %[temp_r3], %[imag_sum_1], %[temp0], %[temp5] \n\t" - "madd.s %[temp_r], %[temp_r], %[temp1], %[temp1] \n\t" - "madd.s %[temp_r1], %[temp_r1], %[temp3], %[temp3] \n\t" - "madd.s %[temp_r2], %[temp_r2], %[temp1], %[temp5] \n\t" - "nmsub.s %[temp_r3], %[temp_r3], %[temp1], %[temp4] \n\t" - "lwc1 %[temp4], 16(%[p_x]) \n\t" - "lwc1 %[temp5], 20(%[p_x]) \n\t" - "swc1 %[temp_r], 40(%[p_phi]) \n\t" - "swc1 %[temp_r1], 16(%[p_phi]) \n\t" - "swc1 %[temp_r2], 24(%[p_phi]) \n\t" - "swc1 %[temp_r3], 28(%[p_phi]) \n\t" - "madd.s %[temp_r], %[real_sum_1], %[temp2], %[temp4] \n\t" - "madd.s %[temp_r1], %[imag_sum_1], %[temp2], %[temp5] \n\t" - "madd.s %[temp_r2], %[real_sum_2], %[temp0], %[temp6] \n\t" - "madd.s %[temp_r3], %[imag_sum_2], %[temp0], %[temp7] \n\t" - "madd.s %[temp_r], %[temp_r], %[temp3], %[temp5] \n\t" - "nmsub.s %[temp_r1], %[temp_r1], %[temp3], %[temp4] \n\t" - "madd.s %[temp_r2], %[temp_r2], %[temp1], %[temp7] \n\t" - "nmsub.s %[temp_r3], %[temp_r3], %[temp1], %[temp6] \n\t" - "swc1 %[temp_r], 0(%[p_phi]) \n\t" - "swc1 %[temp_r1], 4(%[p_phi]) \n\t" - "swc1 %[temp_r2], 8(%[p_phi]) \n\t" - "swc1 %[temp_r3], 12(%[p_phi]) \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp_r]"=&f"(temp_r), - [real_sum_0]"+f"(real_sum_0), [real_sum_1]"+f"(real_sum_1), - [real_sum_2]"+f"(real_sum_2), [imag_sum_1]"+f"(imag_sum_1), - [temp_r2]"=&f"(temp_r2), [temp_r3]"=&f"(temp_r3), - [temp_r1]"=&f"(temp_r1), [p_phi]"+r"(p_phi), - [imag_sum_2]"+f"(imag_sum_2) - : [p_x]"r"(p_x) - : "memory" - ); -} - -static void sbr_hf_gen_mips(float (*X_high)[2], const float (*X_low)[2], - const float alpha0[2], const float alpha1[2], - float bw, int start, int end) -{ - float alpha[4]; - int i; - float *p_x_low = (float*)&X_low[0][0] + 2*start; - float *p_x_high = &X_high[0][0] + 2*start; - float temp0, temp1, temp2, temp3, temp4, temp5, temp6; - float temp7, temp8, temp9, temp10, temp11, temp12; - - alpha[0] = alpha1[0] * bw * bw; - alpha[1] = alpha1[1] * bw * bw; - alpha[2] = alpha0[0] * bw; - alpha[3] = alpha0[1] * bw; - - for (i = start; i < end; i++) { - __asm__ volatile ( - "lwc1 %[temp0], -16(%[p_x_low]) \n\t" - "lwc1 %[temp1], -12(%[p_x_low]) \n\t" - "lwc1 %[temp2], -8(%[p_x_low]) \n\t" - "lwc1 %[temp3], -4(%[p_x_low]) \n\t" - "lwc1 %[temp5], 0(%[p_x_low]) \n\t" - "lwc1 %[temp6], 4(%[p_x_low]) \n\t" - "lwc1 %[temp7], 0(%[alpha]) \n\t" - "lwc1 %[temp8], 4(%[alpha]) \n\t" - "lwc1 %[temp9], 8(%[alpha]) \n\t" - "lwc1 %[temp10], 12(%[alpha]) \n\t" - PTR_ADDIU "%[p_x_high], %[p_x_high], 8 \n\t" - PTR_ADDIU "%[p_x_low], %[p_x_low], 8 \n\t" - "mul.s %[temp11], %[temp1], %[temp8] \n\t" - "msub.s %[temp11], %[temp11], %[temp0], %[temp7] \n\t" - "madd.s %[temp11], %[temp11], %[temp2], %[temp9] \n\t" - "nmsub.s %[temp11], %[temp11], %[temp3], %[temp10] \n\t" - "add.s %[temp11], %[temp11], %[temp5] \n\t" - "swc1 %[temp11], -8(%[p_x_high]) \n\t" - "mul.s %[temp12], %[temp1], %[temp7] \n\t" - "madd.s %[temp12], %[temp12], %[temp0], %[temp8] \n\t" - "madd.s %[temp12], %[temp12], %[temp3], %[temp9] \n\t" - "madd.s %[temp12], %[temp12], %[temp2], %[temp10] \n\t" - "add.s %[temp12], %[temp12], %[temp6] \n\t" - "swc1 %[temp12], -4(%[p_x_high]) \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5), - [temp6]"=&f"(temp6), [temp7]"=&f"(temp7), [temp8]"=&f"(temp8), - [temp9]"=&f"(temp9), [temp10]"=&f"(temp10), [temp11]"=&f"(temp11), - [temp12]"=&f"(temp12), [p_x_high]"+r"(p_x_high), - [p_x_low]"+r"(p_x_low) - : [alpha]"r"(alpha) - : "memory" - ); - } -} - -static void sbr_hf_g_filt_mips(float (*Y)[2], const float (*X_high)[40][2], - const float *g_filt, int m_max, intptr_t ixh) -{ - const float *p_x, *p_g, *loop_end; - float *p_y; - float temp0, temp1, temp2; - - p_g = &g_filt[0]; - p_y = &Y[0][0]; - p_x = &X_high[0][ixh][0]; - loop_end = p_g + m_max; - - __asm__ volatile( - ".set push \n\t" - ".set noreorder \n\t" - "1: \n\t" - "lwc1 %[temp0], 0(%[p_g]) \n\t" - "lwc1 %[temp1], 0(%[p_x]) \n\t" - "lwc1 %[temp2], 4(%[p_x]) \n\t" - "mul.s %[temp1], %[temp1], %[temp0] \n\t" - "mul.s %[temp2], %[temp2], %[temp0] \n\t" - PTR_ADDIU "%[p_g], %[p_g], 4 \n\t" - PTR_ADDIU "%[p_x], %[p_x], 320 \n\t" - "swc1 %[temp1], 0(%[p_y]) \n\t" - "swc1 %[temp2], 4(%[p_y]) \n\t" - "bne %[p_g], %[loop_end], 1b \n\t" - PTR_ADDIU "%[p_y], %[p_y], 8 \n\t" - ".set pop \n\t" - - : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1), - [temp2]"=&f"(temp2), [p_x]"+r"(p_x), - [p_y]"+r"(p_y), [p_g]"+r"(p_g) - : [loop_end]"r"(loop_end) - : "memory" - ); -} - -static void sbr_hf_apply_noise_0_mips(float (*Y)[2], const float *s_m, - const float *q_filt, int noise, - int kx, int m_max) -{ - int m; - - for (m = 0; m < m_max; m++){ - - float *Y1=&Y[m][0]; - float *ff_table; - float y0,y1, temp1, temp2, temp4, temp5; - int temp0, temp3; - const float *s_m1=&s_m[m]; - const float *q_filt1= &q_filt[m]; - - __asm__ volatile( - "lwc1 %[y0], 0(%[Y1]) \n\t" - "lwc1 %[temp1], 0(%[s_m1]) \n\t" - "addiu %[noise], %[noise], 1 \n\t" - "andi %[noise], %[noise], 0x1ff \n\t" - "sll %[temp0], %[noise], 3 \n\t" - PTR_ADDU "%[ff_table],%[ff_sbr_noise_table], %[temp0] \n\t" - "add.s %[y0], %[y0], %[temp1] \n\t" - "mfc1 %[temp3], %[temp1] \n\t" - "bne %[temp3], $0, 1f \n\t" - "lwc1 %[y1], 4(%[Y1]) \n\t" - "lwc1 %[temp2], 0(%[q_filt1]) \n\t" - "lwc1 %[temp4], 0(%[ff_table]) \n\t" - "lwc1 %[temp5], 4(%[ff_table]) \n\t" - "madd.s %[y0], %[y0], %[temp2], %[temp4] \n\t" - "madd.s %[y1], %[y1], %[temp2], %[temp5] \n\t" - "swc1 %[y1], 4(%[Y1]) \n\t" - "1: \n\t" - "swc1 %[y0], 0(%[Y1]) \n\t" - - : [ff_table]"=&r"(ff_table), [y0]"=&f"(y0), [y1]"=&f"(y1), - [temp0]"=&r"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5) - : [ff_sbr_noise_table]"r"(ff_sbr_noise_table), [noise]"r"(noise), - [Y1]"r"(Y1), [s_m1]"r"(s_m1), [q_filt1]"r"(q_filt1) - : "memory" - ); - } -} - -static void sbr_hf_apply_noise_1_mips(float (*Y)[2], const float *s_m, - const float *q_filt, int noise, - int kx, int m_max) -{ - float y0,y1,temp1, temp2, temp4, temp5; - int temp0, temp3, m; - float phi_sign = 1 - 2 * (kx & 1); - - for (m = 0; m < m_max; m++) { - - float *ff_table; - float *Y1=&Y[m][0]; - const float *s_m1=&s_m[m]; - const float *q_filt1= &q_filt[m]; - - __asm__ volatile( - "lwc1 %[y1], 4(%[Y1]) \n\t" - "lwc1 %[temp1], 0(%[s_m1]) \n\t" - "lw %[temp3], 0(%[s_m1]) \n\t" - "addiu %[noise], %[noise], 1 \n\t" - "andi %[noise], %[noise], 0x1ff \n\t" - "sll %[temp0], %[noise], 3 \n\t" - PTR_ADDU "%[ff_table],%[ff_sbr_noise_table],%[temp0] \n\t" - "madd.s %[y1], %[y1], %[temp1], %[phi_sign] \n\t" - "bne %[temp3], $0, 1f \n\t" - "lwc1 %[y0], 0(%[Y1]) \n\t" - "lwc1 %[temp2], 0(%[q_filt1]) \n\t" - "lwc1 %[temp4], 0(%[ff_table]) \n\t" - "lwc1 %[temp5], 4(%[ff_table]) \n\t" - "madd.s %[y0], %[y0], %[temp2], %[temp4] \n\t" - "madd.s %[y1], %[y1], %[temp2], %[temp5] \n\t" - "swc1 %[y0], 0(%[Y1]) \n\t" - "1: \n\t" - "swc1 %[y1], 4(%[Y1]) \n\t" - - : [ff_table] "=&r" (ff_table), [y0] "=&f" (y0), [y1] "=&f" (y1), - [temp0] "=&r" (temp0), [temp1] "=&f" (temp1), [temp2] "=&f" (temp2), - [temp3] "=&r" (temp3), [temp4] "=&f" (temp4), [temp5] "=&f" (temp5) - : [ff_sbr_noise_table] "r" (ff_sbr_noise_table), [noise] "r" (noise), - [Y1] "r" (Y1), [s_m1] "r" (s_m1), [q_filt1] "r" (q_filt1), - [phi_sign] "f" (phi_sign) - : "memory" - ); - phi_sign = -phi_sign; - } -} - -static void sbr_hf_apply_noise_2_mips(float (*Y)[2], const float *s_m, - const float *q_filt, int noise, - int kx, int m_max) -{ - int m, temp0, temp1; - float *ff_table; - float y0, y1, temp2, temp3, temp4, temp5; - - for (m = 0; m < m_max; m++) { - - float *Y1=&Y[m][0]; - const float *s_m1=&s_m[m]; - const float *q_filt1= &q_filt[m]; - - __asm__ volatile( - "lwc1 %[y0], 0(%[Y1]) \n\t" - "lwc1 %[temp3], 0(%[s_m1]) \n\t" - "addiu %[noise], %[noise], 1 \n\t" - "andi %[noise], %[noise], 0x1ff \n\t" - "sll %[temp0], %[noise], 3 \n\t" - PTR_ADDU "%[ff_table],%[ff_sbr_noise_table],%[temp0] \n\t" - "sub.s %[y0], %[y0], %[temp3] \n\t" - "mfc1 %[temp1], %[temp3] \n\t" - "bne %[temp1], $0, 1f \n\t" - "lwc1 %[y1], 4(%[Y1]) \n\t" - "lwc1 %[temp2], 0(%[q_filt1]) \n\t" - "lwc1 %[temp4], 0(%[ff_table]) \n\t" - "lwc1 %[temp5], 4(%[ff_table]) \n\t" - "madd.s %[y0], %[y0], %[temp2], %[temp4] \n\t" - "madd.s %[y1], %[y1], %[temp2], %[temp5] \n\t" - "swc1 %[y1], 4(%[Y1]) \n\t" - "1: \n\t" - "swc1 %[y0], 0(%[Y1]) \n\t" - - : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [y0]"=&f"(y0), - [y1]"=&f"(y1), [ff_table]"=&r"(ff_table), - [temp2]"=&f"(temp2), [temp3]"=&f"(temp3), - [temp4]"=&f"(temp4), [temp5]"=&f"(temp5) - : [ff_sbr_noise_table]"r"(ff_sbr_noise_table), [noise]"r"(noise), - [Y1]"r"(Y1), [s_m1]"r"(s_m1), [q_filt1]"r"(q_filt1) - : "memory" - ); - } -} - -static void sbr_hf_apply_noise_3_mips(float (*Y)[2], const float *s_m, - const float *q_filt, int noise, - int kx, int m_max) -{ - float phi_sign = 1 - 2 * (kx & 1); - int m; - - for (m = 0; m < m_max; m++) { - - float *Y1=&Y[m][0]; - float *ff_table; - float y0,y1, temp1, temp2, temp4, temp5; - int temp0, temp3; - const float *s_m1=&s_m[m]; - const float *q_filt1= &q_filt[m]; - - __asm__ volatile( - "lwc1 %[y1], 4(%[Y1]) \n\t" - "lwc1 %[temp1], 0(%[s_m1]) \n\t" - "addiu %[noise], %[noise], 1 \n\t" - "andi %[noise], %[noise], 0x1ff \n\t" - "sll %[temp0], %[noise], 3 \n\t" - PTR_ADDU "%[ff_table],%[ff_sbr_noise_table], %[temp0] \n\t" - "nmsub.s %[y1], %[y1], %[temp1], %[phi_sign] \n\t" - "mfc1 %[temp3], %[temp1] \n\t" - "bne %[temp3], $0, 1f \n\t" - "lwc1 %[y0], 0(%[Y1]) \n\t" - "lwc1 %[temp2], 0(%[q_filt1]) \n\t" - "lwc1 %[temp4], 0(%[ff_table]) \n\t" - "lwc1 %[temp5], 4(%[ff_table]) \n\t" - "madd.s %[y0], %[y0], %[temp2], %[temp4] \n\t" - "madd.s %[y1], %[y1], %[temp2], %[temp5] \n\t" - "swc1 %[y0], 0(%[Y1]) \n\t" - "1: \n\t" - "swc1 %[y1], 4(%[Y1]) \n\t" - - : [ff_table]"=&r"(ff_table), [y0]"=&f"(y0), [y1]"=&f"(y1), - [temp0]"=&r"(temp0), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2), - [temp3]"=&r"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5) - : [ff_sbr_noise_table]"r"(ff_sbr_noise_table), [noise]"r"(noise), - [Y1]"r"(Y1), [s_m1]"r"(s_m1), [q_filt1]"r"(q_filt1), - [phi_sign]"f"(phi_sign) - : "memory" - ); - phi_sign = -phi_sign; - } -} -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_MIPSFPU */ -#endif /* HAVE_INLINE_ASM */ - -void ff_sbrdsp_init_mips(SBRDSPContext *s) -{ -#if HAVE_INLINE_ASM -#if HAVE_MIPSFPU - s->qmf_pre_shuffle = sbr_qmf_pre_shuffle_mips; - s->qmf_post_shuffle = sbr_qmf_post_shuffle_mips; -#if !HAVE_MIPS32R6 && !HAVE_MIPS64R6 - s->sum64x5 = sbr_sum64x5_mips; - s->sum_square = sbr_sum_square_mips; - s->qmf_deint_bfly = sbr_qmf_deint_bfly_mips; - s->autocorrelate = sbr_autocorrelate_mips; - s->hf_gen = sbr_hf_gen_mips; - s->hf_g_filt = sbr_hf_g_filt_mips; - - s->hf_apply_noise[0] = sbr_hf_apply_noise_0_mips; - s->hf_apply_noise[1] = sbr_hf_apply_noise_1_mips; - s->hf_apply_noise[2] = sbr_hf_apply_noise_2_mips; - s->hf_apply_noise[3] = sbr_hf_apply_noise_3_mips; -#endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */ -#endif /* HAVE_MIPSFPU */ -#endif /* HAVE_INLINE_ASM */ -} diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index c9409eac6..ef4fc075b 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -36,6 +36,7 @@ #include "libavutil/emms.h" #include "libavutil/imgutils.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "blockdsp.h" @@ -467,6 +468,10 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) if (s->avctx->height <= 0) return AVERROR_INVALIDDATA; } + if (s->bayer && s->progressive) { + avpriv_request_sample(s->avctx, "progressively coded bayer picture"); + return AVERROR_INVALIDDATA; + } if (s->got_picture && s->interlaced && (s->bottom_field == !s->interlace_polarity)) { if (s->progressive) { @@ -842,9 +847,8 @@ static int decode_block(MJpegDecodeContext *s, int16_t *block, int component, return AVERROR_INVALIDDATA; } val = val * (unsigned)quant_matrix[0] + s->last_dc[component]; - val = av_clip_int16(val); s->last_dc[component] = val; - block[0] = val; + block[0] = av_clip_int16(val); /* AC coefs */ i = 0; {OPEN_READER(re, &s->gb); @@ -2377,7 +2381,7 @@ int ff_mjpeg_decode_frame_from_buf(AVCodecContext *avctx, AVFrame *frame, int hshift, vshift; int unescaped_buf_size; int start_code; - int i, index; + int index; int ret = 0; int is16bit; AVDictionaryEntry *e = NULL; @@ -2657,7 +2661,7 @@ the_end: if (s->upscale_v[p] == 1) h = (h+1)>>1; av_assert0(w > 0); - for (i = 0; i < h; i++) { + for (int i = 0; i < h; i++) { if (s->upscale_h[p] == 1) { if (is16bit) ((uint16_t*)line)[w - 1] = ((uint16_t*)line)[(w - 1) / 2]; else line[w - 1] = line[(w - 1) / 2]; @@ -2735,7 +2739,7 @@ the_end: h = AV_CEIL_RSHIFT(h, vshift); } dst = &((uint8_t *)s->picture_ptr->data[p])[(h - 1) * s->linesize[p]]; - for (i = h - 1; i; i--) { + for (int i = h - 1; i; i--) { uint8_t *src1 = &((uint8_t *)s->picture_ptr->data[p])[i * s->upscale_v[p] / (s->upscale_v[p] + 1) * s->linesize[p]]; uint8_t *src2 = &((uint8_t *)s->picture_ptr->data[p])[(i + 1) * s->upscale_v[p] / (s->upscale_v[p] + 1) * s->linesize[p]]; if (s->upscale_v[p] != 2 && (src1 == src2 || i == h - 1)) { @@ -2777,7 +2781,7 @@ the_end: int w = s->picture_ptr->width; int h = s->picture_ptr->height; av_assert0(s->nb_components == 4); - for (i=0; ipicture_ptr->width; int h = s->picture_ptr->height; av_assert0(s->nb_components == 4); - for (i=0; iiccnum; i++) + for (int i = 0; i < s->iccnum; i++) total_size += s->iccentries[i].length; ret = ff_frame_new_side_data(avctx, frame, AV_FRAME_DATA_ICC_PROFILE, total_size, &sd); @@ -2847,7 +2850,7 @@ the_end: if (sd) { /* Reassemble the parts, which are now in-order. */ - for (i = 0; i < s->iccnum; i++) { + for (int i = 0; i < s->iccnum; i++) { memcpy(sd->data + offset, s->iccentries[i].data, s->iccentries[i].length); offset += s->iccentries[i].length; } diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c index 521c9e8af..40da602a6 100644 --- a/libavcodec/mjpegenc.c +++ b/libavcodec/mjpegenc.c @@ -32,7 +32,7 @@ #include "config_components.h" -#include "libavutil/pixdesc.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" @@ -80,7 +80,7 @@ static av_cold void init_uni_ac_vlc(const uint8_t huff_size_ac[256], static void mjpeg_encode_picture_header(MpegEncContext *s) { - ff_mjpeg_encode_picture_header(s->avctx, &s->pb, s->picture->f, s->mjpeg_ctx, + 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); @@ -595,9 +595,7 @@ static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, MpegEncContext *s = avctx->priv_data; AVFrame *pic; int i, ret; - int chroma_h_shift, chroma_v_shift; - - av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &chroma_h_shift, &chroma_v_shift); + int chroma_v_shift = 1; /* AMV is 420-only */ if ((avctx->height & 15) && avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { av_log(avctx, AV_LOG_ERROR, @@ -642,7 +640,27 @@ static const AVClass mjpeg_class = { .version = LIBAVUTIL_VERSION_INT, }; -const FFCodec ff_mjpeg_encoder = { +static int mjpeg_get_supported_config(const AVCodecContext *avctx, + const AVCodec *codec, + enum AVCodecConfig config, + unsigned flags, const void **out, + int *out_num) +{ + if (config == AV_CODEC_CONFIG_COLOR_RANGE) { + static const enum AVColorRange mjpeg_ranges[] = { + AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG, AVCOL_RANGE_UNSPECIFIED, + }; + int strict = avctx ? avctx->strict_std_compliance : 0; + int index = strict > FF_COMPLIANCE_UNOFFICIAL ? 1 : 0; + *out = &mjpeg_ranges[index]; + *out_num = FF_ARRAY_ELEMS(mjpeg_ranges) - index - 1; + return 0; + } + + return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num); +} + +FFCodec ff_mjpeg_encoder = { .p.name = "mjpeg", CODEC_LONG_NAME("MJPEG (Motion JPEG)"), .p.type = AVMEDIA_TYPE_VIDEO, @@ -661,6 +679,7 @@ const FFCodec ff_mjpeg_encoder = { }, .p.priv_class = &mjpeg_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_mjpeg_profiles), + .get_supported_config = mjpeg_get_supported_config, }; #endif @@ -685,6 +704,7 @@ const FFCodec ff_amv_encoder = { .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_JPEG, .p.priv_class = &amv_class, .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, }; diff --git a/libavcodec/mjpegenc_common.c b/libavcodec/mjpegenc_common.c index 049ae3d92..751e43fd3 100644 --- a/libavcodec/mjpegenc_common.c +++ b/libavcodec/mjpegenc_common.c @@ -39,18 +39,17 @@ static int put_huffman_table(PutBitContext *p, int table_class, int table_id, const uint8_t *bits_table, const uint8_t *value_table) { - int n, i; + int n = 0; put_bits(p, 4, table_class); put_bits(p, 4, table_id); - n = 0; - for(i=1;i<=16;i++) { + for (int i = 1; i <= 16; i++) { n += bits_table[i]; put_bits(p, 8, bits_table[i]); } - for(i=0;i 1) { put_bits(p, 4, 0); /* 8 bit precision */ put_bits(p, 4, 1); /* table 1 */ - for(i=0;i<64;i++) { - j = intra_matrix_permutation[i]; + for (int i = 0; i < 64; i++) { + uint8_t j = intra_matrix_permutation[i]; put_bits(p, 8, chroma_intra_matrix[j]); } } diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c index 305c5d2b3..e85dac36a 100644 --- a/libavcodec/mlpdec.c +++ b/libavcodec/mlpdec.c @@ -1212,6 +1212,7 @@ static int read_access_unit(AVCodecContext *avctx, AVFrame *frame, goto error; m->is_major_sync_unit = 1; header_size += m->major_sync_header_size; + frame->flags |= AV_FRAME_FLAG_KEY; } if (!m->params_valid) { diff --git a/libavcodec/mlz.c b/libavcodec/mlz.c index 9087ffd8f..517636643 100644 --- a/libavcodec/mlz.c +++ b/libavcodec/mlz.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "mlz.h" av_cold int ff_mlz_init_dict(void *context, MLZ *mlz) diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c index a8cda2757..e42591110 100644 --- a/libavcodec/mmaldec.c +++ b/libavcodec/mmaldec.c @@ -42,6 +42,7 @@ #include "libavutil/buffer.h" #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/log.h" diff --git a/libavcodec/mobiclip.c b/libavcodec/mobiclip.c index 433de0abb..133a835ad 100644 --- a/libavcodec/mobiclip.c +++ b/libavcodec/mobiclip.c @@ -24,6 +24,7 @@ #include #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "avcodec.h" diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index 2091acbbe..e4f17fb2d 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -305,45 +305,44 @@ static int zero_cmp(MpegEncContext *s, const uint8_t *a, const uint8_t *b, static void zero_hpel(uint8_t *a, const uint8_t *b, ptrdiff_t stride, int h){ } -int ff_init_me(MpegEncContext *s){ - MotionEstContext * const c= &s->me; - int cache_size= FFMIN(ME_MAP_SIZE>>ME_MAP_SHIFT, 1<avctx->dia_size)&255, FFABS(s->avctx->pre_dia_size)&255); +av_cold int ff_me_init(MotionEstContext *c, AVCodecContext *avctx, + const MECmpContext *mecc, int mpvenc) +{ + int cache_size = FFMIN(ME_MAP_SIZE>>ME_MAP_SHIFT, 1<dia_size) & 255, FFABS(avctx->pre_dia_size) & 255); int ret; - if(FFMIN(s->avctx->dia_size, s->avctx->pre_dia_size) < -FFMIN(ME_MAP_SIZE, MAX_SAB_SIZE)){ - av_log(s->avctx, AV_LOG_ERROR, "ME_MAP size is too small for SAB diamond\n"); - return -1; + if (FFMIN(avctx->dia_size, avctx->pre_dia_size) < -FFMIN(ME_MAP_SIZE, MAX_SAB_SIZE)) { + av_log(avctx, AV_LOG_ERROR, "ME_MAP size is too small for SAB diamond\n"); + return AVERROR(EINVAL); } - c->avctx= s->avctx; + c->avctx = avctx; - if(s->codec_id == AV_CODEC_ID_H261) - c->avctx->me_sub_cmp = c->avctx->me_cmp; + if (avctx->codec_id == AV_CODEC_ID_H261) + avctx->me_sub_cmp = avctx->me_cmp; - if(cache_size < 2*dia_size && !c->stride){ - av_log(s->avctx, AV_LOG_INFO, "ME_MAP size may be a little small for the selected diamond size\n"); - } + if (cache_size < 2 * dia_size) + av_log(avctx, AV_LOG_INFO, "ME_MAP size may be a little small for the selected diamond size\n"); - ret = ff_set_cmp(&s->mecc, s->mecc.me_pre_cmp, c->avctx->me_pre_cmp); - ret |= ff_set_cmp(&s->mecc, s->mecc.me_cmp, c->avctx->me_cmp); - ret |= ff_set_cmp(&s->mecc, s->mecc.me_sub_cmp, c->avctx->me_sub_cmp); - ret |= ff_set_cmp(&s->mecc, s->mecc.mb_cmp, c->avctx->mb_cmp); + ret = ff_set_cmp(mecc, c->me_pre_cmp, avctx->me_pre_cmp, mpvenc); + ret |= ff_set_cmp(mecc, c->me_cmp, avctx->me_cmp, mpvenc); + ret |= ff_set_cmp(mecc, c->me_sub_cmp, avctx->me_sub_cmp, mpvenc); + ret |= ff_set_cmp(mecc, c->mb_cmp, avctx->mb_cmp, mpvenc); if (ret < 0) return ret; - c->flags = get_flags(c, 0, c->avctx->me_cmp &FF_CMP_CHROMA); - c->sub_flags= get_flags(c, 0, c->avctx->me_sub_cmp&FF_CMP_CHROMA); - c->mb_flags = get_flags(c, 0, c->avctx->mb_cmp &FF_CMP_CHROMA); + c->sse = mecc->sse[0]; + memcpy(c->pix_abs, mecc->pix_abs, sizeof(c->pix_abs)); -/*FIXME s->no_rounding b_type*/ - if (s->avctx->flags & AV_CODEC_FLAG_QPEL) { + c->flags = get_flags(c, 0, avctx->me_cmp & FF_CMP_CHROMA); + c->sub_flags = get_flags(c, 0, avctx->me_sub_cmp & FF_CMP_CHROMA); + c->mb_flags = get_flags(c, 0, avctx->mb_cmp & FF_CMP_CHROMA); + + if (avctx->codec_id == AV_CODEC_ID_H261) { + c->sub_motion_search = no_sub_motion_search; + } else if (avctx->flags & AV_CODEC_FLAG_QPEL) { c->sub_motion_search= qpel_motion_search; - c->qpel_avg = s->qdsp.avg_qpel_pixels_tab; - if (s->no_rounding) - c->qpel_put = s->qdsp.put_no_rnd_qpel_pixels_tab; - else - c->qpel_put = s->qdsp.put_qpel_pixels_tab; }else{ if(c->avctx->me_sub_cmp&FF_CMP_CHROMA) c->sub_motion_search= hpel_motion_search; @@ -354,6 +353,32 @@ int ff_init_me(MpegEncContext *s){ else c->sub_motion_search= hpel_motion_search; } + + /* 8x8 fullpel search would need a 4x4 chroma compare, which we do + * not have yet, and even if we had, the motion estimation code + * does not expect it. */ + if (avctx->codec_id != AV_CODEC_ID_SNOW) { + if ((avctx->me_cmp & FF_CMP_CHROMA) /* && !c->me_cmp[2] */) + c->me_cmp[2] = zero_cmp; + if ((avctx->me_sub_cmp & FF_CMP_CHROMA) && !c->me_sub_cmp[2]) + c->me_sub_cmp[2] = zero_cmp; + } + + return 0; +} + +void ff_me_init_pic(MpegEncContext *s) +{ + 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; + else + c->qpel_put = s->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; @@ -367,29 +392,15 @@ int ff_init_me(MpegEncContext *s){ c->stride = 16*s->mb_width + 32; c->uvstride= 8*s->mb_width + 16; } - - /* 8x8 fullpel search would need a 4x4 chroma compare, which we do - * not have yet, and even if we had, the motion estimation code - * does not expect it. */ if (s->codec_id != AV_CODEC_ID_SNOW) { - if ((c->avctx->me_cmp & FF_CMP_CHROMA) /* && !s->mecc.me_cmp[2] */) - s->mecc.me_cmp[2] = zero_cmp; - if ((c->avctx->me_sub_cmp & FF_CMP_CHROMA) && !s->mecc.me_sub_cmp[2]) - s->mecc.me_sub_cmp[2] = zero_cmp; c->hpel_put[2][0]= c->hpel_put[2][1]= c->hpel_put[2][2]= c->hpel_put[2][3]= zero_hpel; } - - if(s->codec_id == AV_CODEC_ID_H261){ - c->sub_motion_search= no_sub_motion_search; - } - - return 0; } #define CHECK_SAD_HALF_MV(suffix, x, y) \ {\ - d = s->mecc.pix_abs[size][(x ? 1 : 0) + (y ? 2 : 0)](NULL, pix, ptr + ((x) >> 1), stride, h); \ + d = c->pix_abs[size][(x ? 1 : 0) + (y ? 2 : 0)](NULL, pix, ptr + ((x) >> 1), stride, h); \ d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*penalty_factor;\ COPY3_IF_LT(dminh, d, dx, x, dy, y)\ } @@ -510,23 +521,23 @@ static inline void set_p_mv_tables(MpegEncContext * s, int mx, int my, int mv4) if(mv4){ int mot_xy= s->block_index[0]; - s->current_picture.motion_val[0][mot_xy ][0] = mx; - s->current_picture.motion_val[0][mot_xy ][1] = my; - s->current_picture.motion_val[0][mot_xy + 1][0] = mx; - s->current_picture.motion_val[0][mot_xy + 1][1] = my; + 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->b8_stride; - s->current_picture.motion_val[0][mot_xy ][0] = mx; - s->current_picture.motion_val[0][mot_xy ][1] = my; - s->current_picture.motion_val[0][mot_xy + 1][0] = mx; - s->current_picture.motion_val[0][mot_xy + 1][1] = my; + 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; } } /** * get fullpel ME search limits. */ -static inline void get_limits(MpegEncContext *s, int x, int y) +static inline void get_limits(MpegEncContext *s, int x, int y, int bframe) { MotionEstContext * const c= &s->me; int range= c->avctx->me_range >> (1 + !!(c->flags&FLAG_QPEL)); @@ -540,7 +551,7 @@ static inline void get_limits(MpegEncContext *s, int x, int y) c->ymin = - y - 16; c->xmax = - x + s->width; c->ymax = - y + s->height; - } else if (s->out_format == FMT_H261){ + } else if (!(av_builtin_constant_p(bframe) && bframe) && s->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; @@ -601,8 +612,8 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) c->ymax = - 16*s->mb_y + s->height - 8*(block>>1); } - P_LEFT[0] = s->current_picture.motion_val[0][mot_xy - 1][0]; - P_LEFT[1] = s->current_picture.motion_val[0][mot_xy - 1][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]; if (P_LEFT[0] > c->xmax * (1 << shift)) P_LEFT[0] = c->xmax * (1 << shift); @@ -611,10 +622,10 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) c->pred_x= pred_x4= P_LEFT[0]; c->pred_y= pred_y4= P_LEFT[1]; } else { - P_TOP[0] = s->current_picture.motion_val[0][mot_xy - mot_stride ][0]; - P_TOP[1] = s->current_picture.motion_val[0][mot_xy - mot_stride ][1]; - P_TOPRIGHT[0] = s->current_picture.motion_val[0][mot_xy - mot_stride + off[block]][0]; - P_TOPRIGHT[1] = s->current_picture.motion_val[0][mot_xy - mot_stride + off[block]][1]; + 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]; 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); @@ -642,7 +653,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) dmin4= c->sub_motion_search(s, &mx4, &my4, dmin4, block, block, size, h); - if (s->mecc.me_sub_cmp[0] != s->mecc.mb_cmp[0]) { + if (c->me_sub_cmp[0] != c->mb_cmp[0]) { int dxy; const int offset= ((block&1) + (block>>1)*stride)*8; uint8_t *dest_y = c->scratchpad + offset; @@ -675,8 +686,8 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) my4_sum+= my4; } - s->current_picture.motion_val[0][s->block_index[block]][0] = mx4; - s->current_picture.motion_val[0][s->block_index[block]][1] = 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; if(mx4 != mx || my4 != my) same=0; } @@ -684,11 +695,11 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) if(same) return INT_MAX; - if (s->mecc.me_sub_cmp[0] != s->mecc.mb_cmp[0]) { - dmin_sum += s->mecc.mb_cmp[0](s, - s->new_picture->data[0] + - s->mb_x * 16 + s->mb_y * 16 * stride, - c->scratchpad, stride, 16); + 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, + c->scratchpad, stride, 16); } if(c->avctx->mb_cmp&FF_CMP_CHROMA){ @@ -703,15 +714,15 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) offset= (s->mb_x*8 + (mx>>1)) + (s->mb_y*8 + (my>>1))*s->uvlinesize; if(s->no_rounding){ - s->hdsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad , s->last_picture.f->data[1] + offset, s->uvlinesize, 8); - s->hdsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad + 8, s->last_picture.f->data[2] + offset, s->uvlinesize, 8); + 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_picture.f->data[1] + offset, s->uvlinesize, 8); - s->hdsp.put_pixels_tab [1][dxy](c->scratchpad + 8, s->last_picture.f->data[2] + offset, s->uvlinesize, 8); + 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); } - dmin_sum += s->mecc.mb_cmp[1](s, s->new_picture->data[1] + s->mb_x * 8 + s->mb_y * 8 * s->uvlinesize, c->scratchpad, s->uvlinesize, 8); - dmin_sum += s->mecc.mb_cmp[1](s, s->new_picture->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->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); } c->pred_x= mx; @@ -807,7 +818,7 @@ static int interlaced_search(MpegEncContext *s, int ref_index, mv_table[xy][0]= mx_i; mv_table[xy][1]= my_i; - if (s->mecc.me_sub_cmp[0] != s->mecc.mb_cmp[0]) { + if (c->me_sub_cmp[0] != c->mb_cmp[0]) { int dxy; //FIXME chroma ME @@ -819,7 +830,7 @@ static int interlaced_search(MpegEncContext *s, int ref_index, }else{ s->hdsp.put_pixels_tab [size][dxy](c->scratchpad, ref , stride, h); } - dmin = s->mecc.mb_cmp[size](s, c->src[block][0], c->scratchpad, 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 dmin+= c->mb_penalty_factor; //field_select bits @@ -899,7 +910,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, const int shift= 1+s->quarter_sample; int mb_type=0; - init_ref(c, s->new_picture->data, s->last_picture.f->data, NULL, 16*mb_x, 16*mb_y, 0); + init_ref(c, s->new_pic->data, s->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); @@ -910,7 +921,7 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, 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); + get_limits(s, 16*mb_x, 16*mb_y, 0); c->skip=0; /* intra / predictive decision */ @@ -927,17 +938,17 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, const int mot_stride = s->b8_stride; const int mot_xy = s->block_index[0]; - P_LEFT[0] = s->current_picture.motion_val[0][mot_xy - 1][0]; - P_LEFT[1] = s->current_picture.motion_val[0][mot_xy - 1][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]; if (P_LEFT[0] > (c->xmax << shift)) P_LEFT[0] = c->xmax << shift; if (!s->first_slice_line) { - P_TOP[0] = s->current_picture.motion_val[0][mot_xy - mot_stride ][0]; - P_TOP[1] = s->current_picture.motion_val[0][mot_xy - mot_stride ][1]; - P_TOPRIGHT[0] = s->current_picture.motion_val[0][mot_xy - mot_stride + 2][0]; - P_TOPRIGHT[1] = s->current_picture.motion_val[0][mot_xy - mot_stride + 2][1]; + 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 (P_TOP[1] > (c->ymax << shift)) P_TOP[1] = c->ymax << shift; if (P_TOPRIGHT[0] < (c->xmin * (1 << shift))) @@ -965,7 +976,7 @@ 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; - vard = s->mecc.sse[0](NULL, pix, ppix, s->linesize, 16); + vard = c->sse(NULL, pix, ppix, s->linesize, 16); s->mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8; c->mc_mb_var_sum_temp += (vard+128)>>8; @@ -1042,15 +1053,15 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, *(uint32_t*)(&c->scratchpad[i*s->linesize+12]) = mean; } - intra_score= s->mecc.mb_cmp[0](s, c->scratchpad, pix, s->linesize, 16); + intra_score= c->mb_cmp[0](s, c->scratchpad, pix, s->linesize, 16); } intra_score += c->mb_penalty_factor*16 + s->intra_penalty; if(intra_score < dmin){ mb_type= CANDIDATE_MB_TYPE_INTRA; - s->current_picture.mb_type[mb_y*s->mb_stride + mb_x] = CANDIDATE_MB_TYPE_INTRA; //FIXME cleanup + s->cur_pic.mb_type[mb_y*s->mb_stride + mb_x] = CANDIDATE_MB_TYPE_INTRA; //FIXME cleanup }else - s->current_picture.mb_type[mb_y*s->mb_stride + mb_x] = 0; + s->cur_pic.mb_type[mb_y*s->mb_stride + mb_x] = 0; { int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); @@ -1070,14 +1081,14 @@ int ff_pre_estimate_p_frame_motion(MpegEncContext * s, 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_picture->data, s->last_picture.f->data, NULL, 16*mb_x, 16*mb_y, 0); + init_ref(c, s->new_pic->data, s->last_pic.data, NULL, 16*mb_x, 16*mb_y, 0); av_assert0(s->quarter_sample==0 || s->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; - get_limits(s, 16*mb_x, 16*mb_y); + get_limits(s, 16*mb_x, 16*mb_y, 0); c->skip=0; P_LEFT[0] = s->p_mv_table[xy + 1][0]; @@ -1127,12 +1138,9 @@ static int estimate_motion_b(MpegEncContext *s, int mb_x, int mb_y, const uint8_t * const mv_penalty = c->mv_penalty[f_code] + MAX_DMV; int mv_scale; - 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= mv_penalty; - get_limits(s, 16*mb_x, 16*mb_y); + get_limits(s, 16*mb_x, 16*mb_y, 1); if (s->motion_est != FF_ME_ZERO) { P_LEFT[0] = mv_table[mot_xy - 1][0]; @@ -1232,7 +1240,7 @@ static inline int check_bidir_mv(MpegEncContext * s, fbmin = (mv_penalty_f[motion_fx-pred_fx] + mv_penalty_f[motion_fy-pred_fy])*c->mb_penalty_factor +(mv_penalty_b[motion_bx-pred_bx] + mv_penalty_b[motion_by-pred_by])*c->mb_penalty_factor - + s->mecc.mb_cmp[size](s, src_data[0], dest_y, stride, h); // FIXME new_pic + + c->mb_cmp[size](s, src_data[0], dest_y, stride, h); // FIXME new_pic if(c->avctx->mb_cmp&FF_CMP_CHROMA){ } @@ -1406,7 +1414,7 @@ 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_picture.mb_type[mot_xy])) { + if (IS_8X8(s->next_pic.mb_type[mot_xy])) { s->mv_type= MV_TYPE_8X8; }else{ s->mv_type= MV_TYPE_16X16; @@ -1416,8 +1424,8 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) int index= s->block_index[i]; int min, max; - c->co_located_mv[i][0] = s->next_picture.motion_val[0][index][0]; - c->co_located_mv[i][1] = s->next_picture.motion_val[0][index][1]; + 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->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); @@ -1481,7 +1489,7 @@ static inline int direct_search(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, 0, 0, 16, 1); - get_limits(s, 16*mb_x, 16*mb_y); //restore c->?min/max, maybe not needed + get_limits(s, 16*mb_x, 16*mb_y, 1); //restore c->?min/max, maybe not needed mv_table[mot_xy][0]= mx; mv_table[mot_xy][1]= my; @@ -1495,18 +1503,17 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, int mb_x, int mb_y) { MotionEstContext * const c= &s->me; - const int penalty_factor= c->mb_penalty_factor; 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_picture->data, s->last_picture.f->data, - s->next_picture.f->data, 16 * mb_x, 16 * mb_y, 2); + init_ref(c, s->new_pic->data, s->last_pic.data, + s->next_pic.data, 16 * mb_x, 16 * mb_y, 2); - get_limits(s, 16*mb_x, 16*mb_y); + get_limits(s, 16*mb_x, 16*mb_y, 1); c->skip=0; - if (s->codec_id == AV_CODEC_ID_MPEG4 && s->next_picture.mbskip_table[xy]) { + if (s->codec_id == AV_CODEC_ID_MPEG4 && s->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; @@ -1517,22 +1524,27 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, return; } + 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); + if (s->codec_id == AV_CODEC_ID_MPEG4) dmin= direct_search(s, mb_x, mb_y); else dmin= INT_MAX; + // FIXME penalty stuff for non-MPEG-4 c->skip=0; fmin = estimate_motion_b(s, mb_x, mb_y, s->b_forw_mv_table, 0, s->f_code) + - 3 * penalty_factor; + 3 * c->mb_penalty_factor; c->skip=0; bmin = estimate_motion_b(s, mb_x, mb_y, s->b_back_mv_table, 2, s->b_code) + - 2 * penalty_factor; + 2 * c->mb_penalty_factor; ff_dlog(s, " %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) + penalty_factor; + fbmin= bidir_refine(s, mb_x, mb_y) + c->mb_penalty_factor; ff_dlog(s, "%d %d %d %d\n", dmin, fmin, bmin, fbmin); if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { @@ -1608,7 +1620,7 @@ int ff_get_best_fcode(MpegEncContext * s, const int16_t (*mv_table)[2], int type int best_fcode=-1; int best_score=-10000000; - if(s->msmpeg4_version) + if (s->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) range= FFMIN(range, 256); @@ -1659,9 +1671,9 @@ void ff_fix_long_p_mvs(MpegEncContext * s, int type) int y, range; av_assert0(s->pict_type==AV_PICTURE_TYPE_P); - range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version) ? 8 : 16) << f_code); + range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); - av_assert0(range <= 16 || !s->msmpeg4_version); + 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)); if(c->avctx->me_range && range > c->avctx->me_range) range= c->avctx->me_range; @@ -1680,14 +1692,14 @@ void ff_fix_long_p_mvs(MpegEncContext * s, int type) int block; for(block=0; block<4; block++){ int off= (block& 1) + (block>>1)*wrap; - int mx = s->current_picture.motion_val[0][ xy + off ][0]; - int my = s->current_picture.motion_val[0][ xy + off ][1]; + int mx = s->cur_pic.motion_val[0][ xy + off ][0]; + int my = s->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->current_picture.mb_type[i] = type; + s->cur_pic.mb_type[i] = type; } } } @@ -1708,7 +1720,7 @@ void ff_fix_long_mvs(MpegEncContext * s, uint8_t *field_select_table, int field_ 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) ? 8 : 16) << f_code); + int range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version != MSMP4_UNUSED) ? 8 : 16) << f_code); if(c->avctx->me_range && range > c->avctx->me_range) range= c->avctx->me_range; diff --git a/libavcodec/motion_est.h b/libavcodec/motion_est.h index f6a563b08..12f7cd43a 100644 --- a/libavcodec/motion_est.h +++ b/libavcodec/motion_est.h @@ -25,6 +25,7 @@ #include "avcodec.h" #include "hpeldsp.h" +#include "me_cmp.h" #include "qpeldsp.h" struct MpegEncContext; @@ -83,6 +84,14 @@ typedef struct MotionEstContext { int64_t mb_var_sum_temp; int scene_change_score; + me_cmp_func me_pre_cmp[6]; + me_cmp_func me_cmp[6]; + me_cmp_func me_sub_cmp[6]; + me_cmp_func mb_cmp[6]; + + me_cmp_func pix_abs[2][4]; + me_cmp_func sse; + op_pixels_func(*hpel_put)[4]; op_pixels_func(*hpel_avg)[4]; qpel_mc_func(*qpel_put)[16]; @@ -105,7 +114,13 @@ static inline int ff_h263_round_chroma(int x) return h263_chroma_roundtab[x & 0xf] + (x >> 3); } -int ff_init_me(struct MpegEncContext *s); +/** + * Performs one-time initialization of the MotionEstContext. + */ +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_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); diff --git a/libavcodec/motion_est_template.c b/libavcodec/motion_est_template.c index 1888697db..b2701aa32 100644 --- a/libavcodec/motion_est_template.c +++ b/libavcodec/motion_est_template.c @@ -64,8 +64,8 @@ static int hpel_motion_search(MpegEncContext * s, //FIXME factorize - cmp_sub = s->mecc.me_sub_cmp[size]; - chroma_cmp_sub = s->mecc.me_sub_cmp[size + 1]; + cmp_sub = c->me_sub_cmp[size]; + chroma_cmp_sub = c->me_sub_cmp[size + 1]; if(c->skip){ //FIXME move out of hpel? *mx_ptr = 0; @@ -178,8 +178,8 @@ static inline int get_mb_score(MpegEncContext *s, int mx, int my, //FIXME factorize - cmp_sub = s->mecc.mb_cmp[size]; - chroma_cmp_sub = s->mecc.mb_cmp[size + 1]; + cmp_sub = c->mb_cmp[size]; + chroma_cmp_sub = c->mb_cmp[size + 1]; d= cmp(s, mx>>(qpel+1), my>>(qpel+1), mx&mask, my&mask, size, h, ref_index, src_index, cmp_sub, chroma_cmp_sub, flags); //FIXME check cbp before adding penalty for (0,0) vector @@ -222,12 +222,12 @@ static int qpel_motion_search(MpegEncContext * s, LOAD_COMMON int flags= c->sub_flags; - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; // FIXME: factorize + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; // FIXME: factorize //FIXME factorize - cmp_sub = s->mecc.me_sub_cmp[size]; - chroma_cmp_sub = s->mecc.me_sub_cmp[size + 1]; + cmp_sub = c->me_sub_cmp[size]; + chroma_cmp_sub = c->me_sub_cmp[size + 1]; if(c->skip){ //FIXME somehow move up (benchmark) *mx_ptr = 0; @@ -424,8 +424,8 @@ static av_always_inline int small_diamond_search(MpegEncContext * s, int *best, LOAD_COMMON2 unsigned map_generation = c->map_generation; - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; { /* ensure that the best point is in the MAP as h/qpel refinement needs it */ const unsigned key = ((unsigned)best[1]<map_generation; - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; for(dia_size=1; dia_size<=4; dia_size++){ int dir; @@ -508,8 +508,8 @@ static int hex_search(MpegEncContext * s, int *best, int dmin, int x,y,d; const int dec= dia_size & (dia_size-1); - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; for(;dia_size; dia_size= dec ? dia_size-1 : dia_size>>1){ do{ @@ -545,8 +545,8 @@ static int l2s_dia_search(MpegEncContext * s, int *best, int dmin, static const int hex[8][2]={{-2, 0}, {-1,-1}, { 0,-2}, { 1,-1}, { 2, 0}, { 1, 1}, { 0, 2}, {-1, 1}}; - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; for(; dia_size; dia_size= dec ? dia_size-1 : dia_size>>1){ do{ @@ -584,8 +584,8 @@ static int umh_search(MpegEncContext * s, int *best, int dmin, {-2, 3}, { 0, 4}, { 2, 3}, {-2,-3}, { 0,-4}, { 2,-3},}; - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; x= best[0]; y= best[1]; @@ -627,8 +627,8 @@ static int full_search(MpegEncContext * s, int *best, int dmin, int x,y, d; const int dia_size= c->dia_size&0xFF; - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; for(y=FFMAX(-dia_size, ymin); y<=FFMIN(dia_size,ymax); y++){ for(x=FFMAX(-dia_size, xmin); x<=FFMIN(dia_size,xmax); x++){ @@ -693,8 +693,8 @@ static int sab_diamond_search(MpegEncContext * s, int *best, int dmin, av_assert1(minima_count <= MAX_SAB_SIZE); - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; /*Note jmap_generation; - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; for(dia_size=1; dia_size<=c->dia_size; dia_size++){ int dir, start, end; @@ -880,12 +880,12 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int if(c->pre_pass){ penalty_factor= c->pre_penalty_factor; - cmpf = s->mecc.me_pre_cmp[size]; - chroma_cmpf = s->mecc.me_pre_cmp[size + 1]; + cmpf = c->me_pre_cmp[size]; + chroma_cmpf = c->me_pre_cmp[size + 1]; }else{ penalty_factor= c->penalty_factor; - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; } map_generation= update_map_generation(c); @@ -1008,8 +1008,8 @@ static int epzs_motion_search2(MpegEncContext * s, int flags= c->flags; LOAD_COMMON2 - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; + cmpf = c->me_cmp[size]; + chroma_cmpf = c->me_cmp[size + 1]; map_generation= update_map_generation(c); diff --git a/libavcodec/motionpixels.c b/libavcodec/motionpixels.c index 9df0b2067..287f35f30 100644 --- a/libavcodec/motionpixels.c +++ b/libavcodec/motionpixels.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "config.h" diff --git a/libavcodec/mpc7.c b/libavcodec/mpc7.c index b23b4094d..f1ce4075c 100644 --- a/libavcodec/mpc7.c +++ b/libavcodec/mpc7.c @@ -28,6 +28,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/internal.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 8d88820c4..444ea83f3 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -31,14 +31,12 @@ #include "libavutil/avassert.h" #include "libavutil/thread.h" -#include "avcodec.h" #include "mpegvideo.h" -#include "mpeg12.h" #include "mpeg12codecs.h" #include "mpeg12data.h" #include "mpeg12dec.h" +#include "mpegutils.h" #include "rl.h" -#include "startcode.h" static const uint8_t table_mb_ptype[7][2] = { { 3, 5 }, // 0x01 MB_INTRA @@ -64,6 +62,30 @@ static const uint8_t table_mb_btype[11][2] = { { 2, 5 }, // 0x1E MB_QUANT|MB_FOR|MB_BACK|MB_PAT }; +static const int16_t ptype2mb_type[7] = { + MB_TYPE_INTRA, + MB_TYPE_FORWARD_MV | MB_TYPE_CBP | MB_TYPE_ZERO_MV | MB_TYPE_16x16, + MB_TYPE_FORWARD_MV, + MB_TYPE_FORWARD_MV | MB_TYPE_CBP, + MB_TYPE_QUANT | MB_TYPE_INTRA, + MB_TYPE_QUANT | MB_TYPE_FORWARD_MV | MB_TYPE_CBP | MB_TYPE_ZERO_MV | MB_TYPE_16x16, + MB_TYPE_QUANT | MB_TYPE_FORWARD_MV | MB_TYPE_CBP, +}; + +static const int16_t btype2mb_type[11] = { + MB_TYPE_INTRA, + MB_TYPE_BACKWARD_MV, + MB_TYPE_BACKWARD_MV | MB_TYPE_CBP, + MB_TYPE_FORWARD_MV, + MB_TYPE_FORWARD_MV | MB_TYPE_CBP, + MB_TYPE_BIDIR_MV, + MB_TYPE_BIDIR_MV | MB_TYPE_CBP, + MB_TYPE_QUANT | MB_TYPE_INTRA, + MB_TYPE_QUANT | MB_TYPE_BACKWARD_MV | MB_TYPE_CBP, + MB_TYPE_QUANT | MB_TYPE_FORWARD_MV | MB_TYPE_CBP, + MB_TYPE_QUANT | MB_TYPE_BIDIR_MV | MB_TYPE_CBP, +}; + 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) @@ -146,12 +168,14 @@ static av_cold void mpeg12_init_vlcs(void) &ff_mpeg12_mbPatTable[0][1], 2, 1, &ff_mpeg12_mbPatTable[0][0], 2, 1, 0); - VLC_INIT_STATIC_TABLE(ff_mb_ptype_vlc, MB_PTYPE_VLC_BITS, 7, - &table_mb_ptype[0][1], 2, 1, - &table_mb_ptype[0][0], 2, 1, 0); - VLC_INIT_STATIC_TABLE(ff_mb_btype_vlc, MB_BTYPE_VLC_BITS, 11, - &table_mb_btype[0][1], 2, 1, - &table_mb_btype[0][0], 2, 1, 0); + VLC_INIT_STATIC_SPARSE_TABLE(ff_mb_ptype_vlc, MB_PTYPE_VLC_BITS, 7, + &table_mb_ptype[0][1], 2, 1, + &table_mb_ptype[0][0], 2, 1, + ptype2mb_type, 2, 2, 0); + VLC_INIT_STATIC_SPARSE_TABLE(ff_mb_btype_vlc, MB_BTYPE_VLC_BITS, 11, + &table_mb_btype[0][1], 2, 1, + &table_mb_btype[0][0], 2, 1, + btype2mb_type, 2, 2, 0); ff_init_2d_vlc_rl(ff_mpeg1_vlc_table, ff_mpeg1_rl_vlc, ff_mpeg12_run, ff_mpeg12_level, MPEG12_RL_NB_ELEMS, @@ -180,8 +204,6 @@ int ff_mpeg1_decode_block_intra(GetBitContext *gb, component = index <= 3 ? 0 : index - 4 + 1; diff = decode_dc(gb, component); - if (diff >= 0xffff) - return AVERROR_INVALIDDATA; dc = last_dc[component]; dc += diff; diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c index d05d6355e..4f784611d 100644 --- a/libavcodec/mpeg12dec.c +++ b/libavcodec/mpeg12dec.c @@ -71,10 +71,9 @@ enum Mpeg2ClosedCaptionsFormat { typedef struct Mpeg1Context { MpegEncContext mpeg_enc_ctx; - int mpeg_enc_ctx_allocated; /* true if decoding context allocated */ int repeat_field; /* true if we must repeat the field */ AVPanScan pan_scan; /* some temporary storage for the panscan */ - AVStereo3D stereo3d; + enum AVStereo3DType stereo3d_type; int has_stereo3d; AVBufferRef *a53_buf_ref; enum Mpeg2ClosedCaptionsFormat cc_format; @@ -94,32 +93,6 @@ typedef struct Mpeg1Context { int64_t timecode_frame_start; /*< GOP timecode frame start number, in non drop frame format */ } Mpeg1Context; -#define MB_TYPE_ZERO_MV 0x20000000 - -static const uint32_t ptype2mb_type[7] = { - MB_TYPE_INTRA, - MB_TYPE_L0 | MB_TYPE_CBP | MB_TYPE_ZERO_MV | MB_TYPE_16x16, - MB_TYPE_L0, - MB_TYPE_L0 | MB_TYPE_CBP, - MB_TYPE_QUANT | MB_TYPE_INTRA, - MB_TYPE_QUANT | MB_TYPE_L0 | MB_TYPE_CBP | MB_TYPE_ZERO_MV | MB_TYPE_16x16, - MB_TYPE_QUANT | MB_TYPE_L0 | MB_TYPE_CBP, -}; - -static const uint32_t btype2mb_type[11] = { - MB_TYPE_INTRA, - MB_TYPE_L1, - MB_TYPE_L1 | MB_TYPE_CBP, - MB_TYPE_L0, - MB_TYPE_L0 | MB_TYPE_CBP, - MB_TYPE_L0L1, - MB_TYPE_L0L1 | MB_TYPE_CBP, - MB_TYPE_QUANT | MB_TYPE_INTRA, - MB_TYPE_QUANT | MB_TYPE_L1 | MB_TYPE_CBP, - MB_TYPE_QUANT | MB_TYPE_L0 | MB_TYPE_CBP, - MB_TYPE_QUANT | MB_TYPE_L0L1 | MB_TYPE_CBP, -}; - /* as H.263, but only 17 codes */ static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred) { @@ -161,7 +134,7 @@ static inline int mpeg1_decode_block_inter(MpegEncContext *s, int16_t *block, int n) { int level, i, j, run; - uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = s->intra_scantable.permutated; const uint16_t *quant_matrix = s->inter_matrix; const int qscale = s->qscale; @@ -245,7 +218,7 @@ static inline int mpeg2_decode_block_non_intra(MpegEncContext *s, int16_t *block, int n) { int level, i, j, run; - uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = s->intra_scantable.permutated; const uint16_t *quant_matrix; const int qscale = s->qscale; int mismatch; @@ -332,7 +305,7 @@ static inline int mpeg2_decode_block_intra(MpegEncContext *s, int level, dc, diff, i, j, run; int component; const RL_VLC_ELEM *rl_vlc; - uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = s->intra_scantable.permutated; const uint16_t *quant_matrix; const int qscale = s->qscale; int mismatch; @@ -438,21 +411,21 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) if (s->mb_skip_run-- != 0) { if (s->pict_type == AV_PICTURE_TYPE_P) { s->mb_skipped = 1; - s->current_picture.mb_type[s->mb_x + s->mb_y * s->mb_stride] = - MB_TYPE_SKIP | MB_TYPE_L0 | MB_TYPE_16x16; + s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride] = + MB_TYPE_SKIP | MB_TYPE_FORWARD_MV | MB_TYPE_16x16; } else { int mb_type; if (s->mb_x) - mb_type = s->current_picture.mb_type[s->mb_x + s->mb_y * s->mb_stride - 1]; + mb_type = s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride - 1]; else // FIXME not sure if this is allowed in MPEG at all - mb_type = s->current_picture.mb_type[s->mb_width + (s->mb_y - 1) * s->mb_stride - 1]; + mb_type = s->cur_pic.mb_type[s->mb_width + (s->mb_y - 1) * s->mb_stride - 1]; if (IS_INTRA(mb_type)) { av_log(s->avctx, AV_LOG_ERROR, "skip with previntra\n"); return AVERROR_INVALIDDATA; } - s->current_picture.mb_type[s->mb_x + s->mb_y * s->mb_stride] = + s->cur_pic.mb_type[s->mb_x + s->mb_y * s->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) @@ -484,7 +457,6 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) "Invalid mb type in P-frame at %d %d\n", s->mb_x, s->mb_y); return AVERROR_INVALIDDATA; } - mb_type = ptype2mb_type[mb_type]; break; case AV_PICTURE_TYPE_B: mb_type = get_vlc2(&s->gb, ff_mb_btype_vlc, MB_BTYPE_VLC_BITS, 1); @@ -493,7 +465,6 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) "Invalid mb type in B-frame at %d %d\n", s->mb_x, s->mb_y); return AVERROR_INVALIDDATA; } - mb_type = btype2mb_type[mb_type]; break; } ff_tlog(s->avctx, "mb_type=%x\n", mb_type); @@ -536,14 +507,14 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { for (i = 0; i < mb_block_count; i++) - if ((ret = mpeg2_decode_block_intra(s, *s->pblocks[i], i)) < 0) + 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->last_dc, *s->pblocks[i], + s->last_dc, s->block[i], i, s->qscale); if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", @@ -580,7 +551,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) s->mv[0][0][0] = 0; s->mv[0][0][1] = 0; } else { - av_assert2(mb_type & MB_TYPE_L0L1); + 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) { @@ -595,7 +566,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) s->qscale = mpeg_get_qscale(s); /* motion vectors */ - s->mv_dir = (mb_type >> 13) & 3; + s->mv_dir = MB_TYPE_MV_2_MV_DIR(mb_type); ff_tlog(s->avctx, "motion_type=%d\n", motion_type); switch (motion_type) { case MT_FRAME: /* or MT_16X8 */ @@ -603,7 +574,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) mb_type |= MB_TYPE_16x16; s->mv_type = MV_TYPE_16X16; for (i = 0; i < 2; i++) { - if (USES_LIST(mb_type, i)) { + if (HAS_MV(mb_type, i)) { /* MT_FRAME */ s->mv[i][0][0] = s->last_mv[i][0][0] = @@ -626,7 +597,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) mb_type |= MB_TYPE_16x8 | MB_TYPE_INTERLACED; s->mv_type = MV_TYPE_16X8; for (i = 0; i < 2; i++) { - if (USES_LIST(mb_type, i)) { + if (HAS_MV(mb_type, i)) { /* MT_16X8 */ for (j = 0; j < 2; j++) { s->field_select[i][j] = get_bits1(&s->gb); @@ -646,7 +617,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) if (s->picture_structure == PICT_FRAME) { mb_type |= MB_TYPE_16x8 | MB_TYPE_INTERLACED; for (i = 0; i < 2; i++) { - if (USES_LIST(mb_type, 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], @@ -666,7 +637,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) av_assert0(!s->progressive_sequence); mb_type |= MB_TYPE_16x16 | MB_TYPE_INTERLACED; for (i = 0; i < 2; i++) { - if (USES_LIST(mb_type, i)) { + if (HAS_MV(mb_type, i)) { s->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], @@ -686,7 +657,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) } s->mv_type = MV_TYPE_DMV; for (i = 0; i < 2; i++) { - if (USES_LIST(mb_type, i)) { + if (HAS_MV(mb_type, i)) { int dmx, dmy, mx, my, m; const int my_shift = s->picture_structure == PICT_FRAME; @@ -761,7 +732,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) for (i = 0; i < mb_block_count; i++) { if (cbp & (1 << 11)) { - if ((ret = mpeg2_decode_block_non_intra(s, *s->pblocks[i], i)) < 0) + if ((ret = mpeg2_decode_block_non_intra(s, s->block[i], i)) < 0) return ret; } else { s->block_last_index[i] = -1; @@ -771,7 +742,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) } else { for (i = 0; i < 6; i++) { if (cbp & 32) { - if ((ret = mpeg1_decode_block_inter(s, *s->pblocks[i], i)) < 0) + if ((ret = mpeg1_decode_block_inter(s, s->block[i], i)) < 0) return ret; } else { s->block_last_index[i] = -1; @@ -785,7 +756,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) } } - s->current_picture.mb_type[s->mb_x + s->mb_y * s->mb_stride] = mb_type; + s->cur_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride] = mb_type; return 0; } @@ -794,16 +765,20 @@ static av_cold int mpeg_decode_init(AVCodecContext *avctx) { Mpeg1Context *s = avctx->priv_data; MpegEncContext *s2 = &s->mpeg_enc_ctx; + int ret; + + s2->out_format = FMT_MPEG1; if ( avctx->codec_tag != AV_RL32("VCR2") && avctx->codec_tag != AV_RL32("BW10")) avctx->coded_width = avctx->coded_height = 0; // do not trust dimensions from input - ff_mpv_decode_init(s2, avctx); + ret = ff_mpv_decode_init(s2, avctx); + if (ret < 0) + return ret; ff_mpeg12_init_vlcs(); s2->chroma_format = 1; - s->mpeg_enc_ctx_allocated = 0; s->repeat_field = 0; avctx->color_range = AVCOL_RANGE_MPEG; return 0; @@ -817,16 +792,14 @@ static int mpeg_decode_update_thread_context(AVCodecContext *avctx, MpegEncContext *s = &ctx->mpeg_enc_ctx, *s1 = &ctx_from->mpeg_enc_ctx; int err; - if (avctx == avctx_from || - !ctx_from->mpeg_enc_ctx_allocated || - !s1->context_initialized) + if (avctx == avctx_from || !s1->context_initialized) return 0; err = ff_mpeg_update_thread_context(avctx, avctx_from); if (err) return err; - if (!ctx->mpeg_enc_ctx_allocated) + if (!s->context_initialized) memcpy(s + 1, s1 + 1, sizeof(Mpeg1Context) - sizeof(MpegEncContext)); return 0; @@ -961,7 +934,7 @@ static int mpeg_decode_postinit(AVCodecContext *avctx) avctx->sample_aspect_ratio = (AVRational){ 0, 1 }; } - if ((s1->mpeg_enc_ctx_allocated == 0) || + if (!s->context_initialized || avctx->coded_width != s->width || avctx->coded_height != s->height || s1->save_width != s->width || @@ -969,10 +942,8 @@ static int mpeg_decode_postinit(AVCodecContext *avctx) av_cmp_q(s1->save_aspect, s->avctx->sample_aspect_ratio) || (s1->save_progressive_seq != s->progressive_sequence && FFALIGN(s->height, 16) != FFALIGN(s->height, 32)) || 0) { - if (s1->mpeg_enc_ctx_allocated) { + if (s->context_initialized) ff_mpv_common_end(s); - s1->mpeg_enc_ctx_allocated = 0; - } ret = ff_set_dimensions(avctx, s->width, s->height); if (ret < 0) @@ -1029,8 +1000,8 @@ FF_ENABLE_DEPRECATION_WARNINGS if ((ret = ff_mpv_common_init(s)) < 0) return ret; - - s1->mpeg_enc_ctx_allocated = 1; + if (!s->avctx->lowres) + ff_mpv_framesize_disable(&s->sc); } return 0; } @@ -1233,7 +1204,7 @@ static int mpeg_decode_picture_coding_extension(Mpeg1Context *s1) s->mpeg_f_code[0][1] += !s->mpeg_f_code[0][1]; s->mpeg_f_code[1][0] += !s->mpeg_f_code[1][0]; s->mpeg_f_code[1][1] += !s->mpeg_f_code[1][1]; - if (!s->pict_type && s1->mpeg_enc_ctx_allocated) { + if (!s->pict_type && s->context_initialized) { av_log(s->avctx, AV_LOG_ERROR, "Missing picture start code\n"); if (s->avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_INVALIDDATA; @@ -1259,13 +1230,10 @@ static int mpeg_decode_picture_coding_extension(Mpeg1Context *s1) s->chroma_420_type = get_bits1(&s->gb); s->progressive_frame = get_bits1(&s->gb); - if (s->alternate_scan) { - ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, ff_alternate_vertical_scan); - ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_alternate_vertical_scan); - } else { - 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); - } + // 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); /* composite display not parsed */ ff_dlog(s->avctx, "intra_dc_precision=%d\n", s->intra_dc_precision); @@ -1281,10 +1249,11 @@ static int mpeg_decode_picture_coding_extension(Mpeg1Context *s1) return 0; } -static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size) +static int mpeg_field_start(Mpeg1Context *s1, const uint8_t *buf, int buf_size) { + MpegEncContext *s = &s1->mpeg_enc_ctx; AVCodecContext *avctx = s->avctx; - Mpeg1Context *s1 = (Mpeg1Context *) s; + int second_field = 0; int ret; if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS)) { @@ -1299,22 +1268,35 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size) if ((ret = ff_mpv_frame_start(s, avctx)) < 0) return ret; - ff_mpeg_er_frame_start(s); + if (s->picture_structure != PICT_FRAME) { + s->cur_pic.ptr->f->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * + (s->picture_structure == PICT_TOP_FIELD); - /* first check if we must repeat the frame */ - s->current_picture_ptr->f->repeat_pict = 0; - if (s->repeat_first_field) { - if (s->progressive_sequence) { - if (s->top_field_first) - s->current_picture_ptr->f->repeat_pict = 4; - else - s->current_picture_ptr->f->repeat_pict = 2; - } else if (s->progressive_frame) { - s->current_picture_ptr->f->repeat_pict = 1; + for (int i = 0; i < 3; i++) { + if (s->picture_structure == PICT_BOTTOM_FIELD) { + s->cur_pic.data[i] = FF_PTR_ADD(s->cur_pic.data[i], + s->cur_pic.linesize[i]); + } + s->cur_pic.linesize[i] *= 2; } } - ret = ff_frame_new_side_data(s->avctx, s->current_picture_ptr->f, + ff_mpeg_er_frame_start(s); + + /* first check if we must repeat the frame */ + s->cur_pic.ptr->f->repeat_pict = 0; + if (s->repeat_first_field) { + if (s->progressive_sequence) { + if (s->top_field_first) + s->cur_pic.ptr->f->repeat_pict = 4; + else + s->cur_pic.ptr->f->repeat_pict = 2; + } else if (s->progressive_frame) { + s->cur_pic.ptr->f->repeat_pict = 1; + } + } + + ret = ff_frame_new_side_data(s->avctx, s->cur_pic.ptr->f, AV_FRAME_DATA_PANSCAN, sizeof(s1->pan_scan), &pan_scan); if (ret < 0) @@ -1324,24 +1306,24 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size) if (s1->a53_buf_ref) { ret = ff_frame_new_side_data_from_buf( - s->avctx, s->current_picture_ptr->f, AV_FRAME_DATA_A53_CC, - &s1->a53_buf_ref, NULL); + s->avctx, s->cur_pic.ptr->f, AV_FRAME_DATA_A53_CC, + &s1->a53_buf_ref); if (ret < 0) return ret; } if (s1->has_stereo3d) { - AVStereo3D *stereo = av_stereo3d_create_side_data(s->current_picture_ptr->f); + AVStereo3D *stereo = av_stereo3d_create_side_data(s->cur_pic.ptr->f); if (!stereo) return AVERROR(ENOMEM); - *stereo = s1->stereo3d; + stereo->type = s1->stereo3d_type; s1->has_stereo3d = 0; } if (s1->has_afd) { AVFrameSideData *sd; - ret = ff_frame_new_side_data(s->avctx, s->current_picture_ptr->f, + ret = ff_frame_new_side_data(s->avctx, s->cur_pic.ptr->f, AV_FRAME_DATA_AFD, 1, &sd); if (ret < 0) return ret; @@ -1353,9 +1335,8 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size) if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_FRAME)) ff_thread_finish_setup(avctx); } else { // second field - int i; - - if (!s->current_picture_ptr) { + second_field = 1; + if (!s->cur_pic.ptr) { av_log(s->avctx, AV_LOG_ERROR, "first field missing\n"); return AVERROR_INVALIDDATA; } @@ -1367,18 +1348,31 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size) return ret; } } + ret = ff_mpv_alloc_dummy_frames(s); + if (ret < 0) + return ret; - for (i = 0; i < 4; i++) { - s->current_picture.f->data[i] = s->current_picture_ptr->f->data[i]; + for (int i = 0; i < 3; i++) { + s->cur_pic.data[i] = s->cur_pic.ptr->f->data[i]; if (s->picture_structure == PICT_BOTTOM_FIELD) - s->current_picture.f->data[i] += - s->current_picture_ptr->f->linesize[i]; + s->cur_pic.data[i] += + s->cur_pic.ptr->f->linesize[i]; } } if (avctx->hwaccel) { if ((ret = FF_HW_CALL(avctx, start_frame, buf, buf_size)) < 0) return ret; + } else if (s->codec_tag == MKTAG('V', 'C', 'R', '2')) { + // Exchange UV + FFSWAP(uint8_t*, s->cur_pic.data[1], s->cur_pic.data[2]); + FFSWAP(ptrdiff_t, s->cur_pic.linesize[1], s->cur_pic.linesize[2]); + if (!second_field) { + FFSWAP(uint8_t*, s->next_pic.data[1], s->next_pic.data[2]); + FFSWAP(ptrdiff_t, s->next_pic.linesize[1], s->next_pic.linesize[2]); + FFSWAP(uint8_t*, s->last_pic.data[1], s->last_pic.data[2]); + FFSWAP(ptrdiff_t, s->last_pic.linesize[1], s->last_pic.linesize[2]); + } } return 0; @@ -1499,7 +1493,7 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, return ret; // Note motion_val is normally NULL unless we want to extract the MVs. - if (s->current_picture.motion_val[0]) { + 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); @@ -1519,12 +1513,12 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, motion_y = s->mv[dir][i][1]; } - s->current_picture.motion_val[dir][xy][0] = motion_x; - s->current_picture.motion_val[dir][xy][1] = motion_y; - s->current_picture.motion_val[dir][xy + 1][0] = motion_x; - s->current_picture.motion_val[dir][xy + 1][1] = motion_y; - s->current_picture.ref_index [dir][b8_xy] = - s->current_picture.ref_index [dir][b8_xy + 1] = s->field_select[dir][i]; + 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); } @@ -1722,12 +1716,12 @@ static int slice_decode_thread(AVCodecContext *c, void *arg) * Handle slice ends. * @return 1 if it seems to be the last slice */ -static int slice_end(AVCodecContext *avctx, AVFrame *pict) +static int slice_end(AVCodecContext *avctx, AVFrame *pict, int *got_output) { Mpeg1Context *s1 = avctx->priv_data; MpegEncContext *s = &s1->mpeg_enc_ctx; - if (!s1->mpeg_enc_ctx_allocated || !s->current_picture_ptr) + if (!s->context_initialized || !s->cur_pic.ptr) return 0; if (s->avctx->hwaccel) { @@ -1748,19 +1742,21 @@ static int slice_end(AVCodecContext *avctx, AVFrame *pict) ff_mpv_frame_end(s); if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) { - int ret = av_frame_ref(pict, s->current_picture_ptr->f); + int ret = av_frame_ref(pict, s->cur_pic.ptr->f); if (ret < 0) return ret; - ff_print_debug_info(s, s->current_picture_ptr, pict); - ff_mpv_export_qp_table(s, pict, s->current_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG2); + 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_MPEG2); + *got_output = 1; } else { /* latency of 1 frame for I- and P-frames */ - if (s->last_picture_ptr) { - int ret = av_frame_ref(pict, s->last_picture_ptr->f); + if (s->last_pic.ptr && !s->last_pic.ptr->dummy) { + int ret = av_frame_ref(pict, s->last_pic.ptr->f); if (ret < 0) return ret; - ff_print_debug_info(s, s->last_picture_ptr, pict); - ff_mpv_export_qp_table(s, pict, s->last_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG2); + 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_MPEG2); + *got_output = 1; } } @@ -1849,7 +1845,6 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, s->chroma_format = 1; s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO; - s->out_format = FMT_MPEG1; if (s->avctx->flags & AV_CODEC_FLAG_LOW_DELAY) s->low_delay = 1; @@ -1867,11 +1862,9 @@ static int vcr2_init_sequence(AVCodecContext *avctx) int i, v, ret; /* start new MPEG-1 context decoding */ - s->out_format = FMT_MPEG1; - if (s1->mpeg_enc_ctx_allocated) { + if (s->context_initialized) ff_mpv_common_end(s); - s1->mpeg_enc_ctx_allocated = 0; - } + s->width = avctx->coded_width; s->height = avctx->coded_height; avctx->has_b_frames = 0; // true? @@ -1881,7 +1874,8 @@ static int vcr2_init_sequence(AVCodecContext *avctx) if ((ret = ff_mpv_common_init(s)) < 0) return ret; - s1->mpeg_enc_ctx_allocated = 1; + if (!s->avctx->lowres) + ff_mpv_framesize_disable(&s->sc); for (i = 0; i < 64; i++) { int j = s->idsp.idct_permutation[i]; @@ -2122,16 +2116,16 @@ static void mpeg_decode_user_data(AVCodecContext *avctx, switch (S3D_video_format_type) { case 0x03: - s1->stereo3d.type = AV_STEREO3D_SIDEBYSIDE; + s1->stereo3d_type = AV_STEREO3D_SIDEBYSIDE; break; case 0x04: - s1->stereo3d.type = AV_STEREO3D_TOPBOTTOM; + s1->stereo3d_type = AV_STEREO3D_TOPBOTTOM; break; case 0x08: - s1->stereo3d.type = AV_STEREO3D_2D; + s1->stereo3d_type = AV_STEREO3D_2D; break; case 0x23: - s1->stereo3d.type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX; + s1->stereo3d_type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX; break; } } @@ -2201,14 +2195,9 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, s2->er.error_count += s2->thread_context[i]->er.error_count; } - ret = slice_end(avctx, picture); + ret = slice_end(avctx, picture, got_output); if (ret < 0) return ret; - else if (ret) { - // FIXME: merge with the stuff in mpeg_decode_slice - if (s2->last_picture_ptr || s2->low_delay || s2->pict_type == AV_PICTURE_TYPE_B) - *got_output = 1; - } } s2->pict_type = 0; @@ -2402,7 +2391,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, return AVERROR_INVALIDDATA; } - if (!s2->last_picture_ptr) { + if (!s2->last_pic.ptr) { /* Skip B-frames if we do not have reference frames and * GOP is not closed. */ if (s2->pict_type == AV_PICTURE_TYPE_B) { @@ -2416,7 +2405,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, } if (s2->pict_type == AV_PICTURE_TYPE_I || (s2->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL)) s->sync = 1; - if (!s2->next_picture_ptr) { + if (!s2->next_pic.ptr) { /* Skip P-frames if we do not have a reference frame or * we have an invalid header. */ if (s2->pict_type == AV_PICTURE_TYPE_P && !s->sync) { @@ -2435,7 +2424,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, break; } - if (!s->mpeg_enc_ctx_allocated) + if (!s2->context_initialized) break; if (s2->codec_id == AV_CODEC_ID_MPEG2VIDEO) { @@ -2454,10 +2443,10 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, if (s->first_slice) { skip_frame = 0; s->first_slice = 0; - if ((ret = mpeg_field_start(s2, buf, buf_size)) < 0) + if ((ret = mpeg_field_start(s, buf, buf_size)) < 0) return ret; } - if (!s2->current_picture_ptr) { + if (!s2->cur_pic.ptr) { av_log(avctx, AV_LOG_ERROR, "current_picture not initialized\n"); return AVERROR_INVALIDDATA; @@ -2521,21 +2510,20 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture, if (buf_size == 0 || (buf_size == 4 && AV_RB32(buf) == SEQ_END_CODE)) { /* special case for last picture */ - if (s2->low_delay == 0 && s2->next_picture_ptr) { - int ret = av_frame_ref(picture, s2->next_picture_ptr->f); + if (s2->low_delay == 0 && s2->next_pic.ptr) { + int ret = av_frame_ref(picture, s2->next_pic.ptr->f); if (ret < 0) return ret; - s2->next_picture_ptr = NULL; + ff_mpv_unref_picture(&s2->next_pic); *got_output = 1; } return buf_size; } - if (s->mpeg_enc_ctx_allocated == 0 && ( s2->codec_tag == AV_RL32("VCR2") - || s2->codec_tag == AV_RL32("BW10") - )) + if (!s2->context_initialized && + (s2->codec_tag == AV_RL32("VCR2") || s2->codec_tag == AV_RL32("BW10"))) vcr2_init_sequence(avctx); s->slice_count = 0; @@ -2550,14 +2538,14 @@ static int mpeg_decode_frame(AVCodecContext *avctx, AVFrame *picture, } s->extradata_decoded = 1; if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) { - s2->current_picture_ptr = NULL; + ff_mpv_unref_picture(&s2->cur_pic); return ret; } } ret = decode_chunks(avctx, picture, got_output, buf, buf_size); if (ret<0 || *got_output) { - s2->current_picture_ptr = NULL; + ff_mpv_unref_picture(&s2->cur_pic); if (s->timecode_frame_start != -1 && *got_output) { char tcbuf[AV_TIMECODE_STR_SIZE]; @@ -2593,10 +2581,8 @@ static av_cold int mpeg_decode_end(AVCodecContext *avctx) { Mpeg1Context *s = avctx->priv_data; - if (s->mpeg_enc_ctx_allocated) - ff_mpv_common_end(&s->mpeg_enc_ctx); av_buffer_unref(&s->a53_buf_ref); - return 0; + return ff_mpv_decode_close(avctx); } const FFCodec ff_mpeg1video_decoder = { @@ -2750,13 +2736,8 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, m->intra_vlc_format = !!(s->flags & 0x20); m->alternate_scan = !!(s->flags & 0x10); - if (s->flags & 0x10) { - ff_init_scantable(m->idsp.idct_permutation, &m->inter_scantable, ff_alternate_vertical_scan); - ff_init_scantable(m->idsp.idct_permutation, &m->intra_scantable, ff_alternate_vertical_scan); - } else { - ff_init_scantable(m->idsp.idct_permutation, &m->inter_scantable, ff_zigzag_direct); - ff_init_scantable(m->idsp.idct_permutation, &m->intra_scantable, ff_zigzag_direct); - } + ff_init_scantable(m->idsp.idct_permutation, &m->intra_scantable, + s->flags & 0x10 ? ff_alternate_vertical_scan : ff_zigzag_direct); m->last_dc[0] = m->last_dc[1] = m->last_dc[2] = 1 << (7 + (s->flags & 3)); m->qscale = 1; @@ -2792,8 +2773,6 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, m->intra_scantable.permutated, m->last_dc, s->block[n], n, m->qscale); - if (ret >= 0) - m->block_last_index[n] = ret; } else { ret = mpeg2_decode_block_intra(m, s->block[n], n); } @@ -2821,8 +2800,6 @@ static int ipu_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (get_bits_left(gb) != 32) return AVERROR_INVALIDDATA; - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; @@ -2834,8 +2811,9 @@ static av_cold int ipu_decode_init(AVCodecContext *avctx) MpegEncContext *m = &s->m; avctx->pix_fmt = AV_PIX_FMT_YUV420P; + m->avctx = avctx; - ff_mpv_decode_init(m, avctx); + ff_idctdsp_init(&m->idsp, avctx); ff_mpeg12_init_vlcs(); for (int i = 0; i < 64; i++) { @@ -2845,22 +2823,6 @@ static av_cold int ipu_decode_init(AVCodecContext *avctx) m->chroma_intra_matrix[j] = v; } - for (int i = 0; i < 64; i++) { - int j = m->idsp.idct_permutation[i]; - int v = ff_mpeg1_default_non_intra_matrix[i]; - m->inter_matrix[j] = v; - m->chroma_inter_matrix[j] = v; - } - - return 0; -} - -static av_cold int ipu_decode_end(AVCodecContext *avctx) -{ - IPUContext *s = avctx->priv_data; - - ff_mpv_common_end(&s->m); - return 0; } @@ -2872,7 +2834,5 @@ const FFCodec ff_ipu_decoder = { .priv_data_size = sizeof(IPUContext), .init = ipu_decode_init, FF_CODEC_DECODE_CB(ipu_decode_frame), - .close = ipu_decode_end, .p.capabilities = AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/mpeg12dec.h b/libavcodec/mpeg12dec.h index 464117914..79809b7c3 100644 --- a/libavcodec/mpeg12dec.h +++ b/libavcodec/mpeg12dec.h @@ -25,6 +25,8 @@ #include "get_bits.h" #include "mpeg12vlc.h" +#define MB_TYPE_ZERO_MV MB_TYPE_CODEC_SPECIFIC + static inline int decode_dc(GetBitContext *gb, int component) { int code, diff; diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c index 76377aea1..e56571da0 100644 --- a/libavcodec/mpeg12enc.c +++ b/libavcodec/mpeg12enc.c @@ -137,16 +137,15 @@ 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(MPEG12EncContext *mpeg12) +static int find_frame_rate_index(AVCodecContext *avctx, MPEG12EncContext *mpeg12) { - MpegEncContext *const s = &mpeg12->mpeg; int i; AVRational bestq = (AVRational) {0, 0}; AVRational ext; - AVRational target = av_inv_q(s->avctx->time_base); + AVRational target = av_inv_q(avctx->time_base); for (i = 1; i < 14; i++) { - if (s->avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL && + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL && i >= 9) break; @@ -154,7 +153,7 @@ static int find_frame_rate_index(MPEG12EncContext *mpeg12) for (ext.den=1; ext.den <= 32; ext.den++) { AVRational q = av_mul_q(ext, ff_mpeg12_frame_rate_tab[i]); - if (s->codec_id != AV_CODEC_ID_MPEG2VIDEO && (ext.den!=1 || ext.num!=1)) + if (avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO && (ext.den!=1 || ext.num!=1)) continue; if (av_gcd(ext.den, ext.num) != 1) continue; @@ -180,7 +179,6 @@ static int find_frame_rate_index(MPEG12EncContext *mpeg12) static av_cold int encode_init(AVCodecContext *avctx) { MPEG12EncContext *const mpeg12 = avctx->priv_data; - MpegEncContext *const s = &mpeg12->mpeg; int ret; int max_size = avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 16383 : 4095; @@ -237,7 +235,7 @@ static av_cold int encode_init(AVCodecContext *avctx) if ((ret = ff_mpv_encode_init(avctx)) < 0) return ret; - if (find_frame_rate_index(mpeg12) < 0) { + 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); @@ -259,7 +257,7 @@ static av_cold int encode_init(AVCodecContext *avctx) 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, s); + 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); @@ -271,11 +269,10 @@ static av_cold int encode_init(AVCodecContext *avctx) return 0; } -static void put_header(MpegEncContext *s, int header) +static void put_header(MpegEncContext *s, uint32_t header) { align_put_bits(&s->pb); - put_bits(&s->pb, 16, header >> 16); - put_sbits(&s->pb, 16, header); + put_bits32(&s->pb, header); } /* put sequence header if needed */ @@ -290,7 +287,7 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) AVRational aspect_ratio = s->avctx->sample_aspect_ratio; int aspect_ratio_info; - if (!(s->current_picture.f->flags & AV_FRAME_FLAG_KEY)) + if (!(s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY)) return; if (aspect_ratio.num == 0 || aspect_ratio.den == 0) @@ -382,7 +379,7 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) 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->current_picture_ptr->f, AV_FRAME_DATA_PANSCAN); + side_data = av_frame_get_side_data(s->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) { @@ -419,10 +416,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->current_picture_ptr->coded_picture_number + + time_code = s->cur_pic.ptr->coded_picture_number + mpeg12->timecode_frame_start; - mpeg12->gop_picture_number = s->current_picture_ptr->coded_picture_number; + mpeg12->gop_picture_number = s->cur_pic.ptr->coded_picture_number; av_assert0(mpeg12->drop_frame_timecode == !!(mpeg12->tc.flags & AV_TIMECODE_FLAG_DROPFRAME)); if (mpeg12->drop_frame_timecode) @@ -470,7 +467,7 @@ void ff_mpeg1_encode_slice_header(MpegEncContext *s) void ff_mpeg1_encode_picture_header(MpegEncContext *s) { MPEG12EncContext *const mpeg12 = (MPEG12EncContext*)s; - AVFrameSideData *side_data; + const AVFrameSideData *side_data; mpeg1_encode_sequence_header(s); /* MPEG-1 picture header */ @@ -530,7 +527,7 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s) if (s->progressive_sequence) put_bits(&s->pb, 1, 0); /* no repeat */ else - put_bits(&s->pb, 1, !!(s->current_picture_ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); + put_bits(&s->pb, 1, !!(s->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; @@ -554,10 +551,10 @@ 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->current_picture_ptr->f, + side_data = av_frame_get_side_data(s->cur_pic.ptr->f, AV_FRAME_DATA_STEREO3D); if (side_data) { - AVStereo3D *stereo = (AVStereo3D *)side_data->data; + const AVStereo3D *stereo = (AVStereo3D *)side_data->data; uint8_t fpa_type; switch (stereo->type) { @@ -594,7 +591,7 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s) } if (CONFIG_MPEG2VIDEO_ENCODER && mpeg12->a53_cc) { - side_data = av_frame_get_side_data(s->current_picture_ptr->f, + side_data = av_frame_get_side_data(s->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) { @@ -693,12 +690,12 @@ static inline void encode_dc(MpegEncContext *s, int diff, int component) put_bits(&s->pb, ff_mpeg12_vlc_dc_lum_bits[index] + index, (ff_mpeg12_vlc_dc_lum_code[index] << index) + - av_mod_uintp2(diff, index)); + av_zero_extend(diff, index)); else put_bits(&s->pb, ff_mpeg12_vlc_dc_chroma_bits[index] + index, (ff_mpeg12_vlc_dc_chroma_code[index] << index) + - av_mod_uintp2(diff, index)); + av_zero_extend(diff, index)); } else { if (component == 0) put_bits(&s->pb, @@ -711,7 +708,7 @@ static inline void encode_dc(MpegEncContext *s, int diff, int component) } } -static void mpeg1_encode_block(MpegEncContext *s, int16_t *block, int n) +static void mpeg1_encode_block(MpegEncContext *s, const int16_t *block, int n) { int alevel, level, last_non_zero, dc, diff, i, j, run, last_index, sign; int code, component; @@ -793,7 +790,7 @@ next_coef: } static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, - int16_t block[8][64], + const int16_t block[8][64], int motion_x, int motion_y, int mb_block_count, int chroma_y_shift) @@ -824,7 +821,6 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s, (s->mv[1][0][1] - s->last_mv[1][0][1])) : 0)) == 0))) { s->mb_skip_run++; s->qscale -= s->dquant; - s->skip_count++; s->misc_bits++; s->last_bits++; if (s->pict_type == AV_PICTURE_TYPE_P) { @@ -1100,12 +1096,12 @@ static av_cold void mpeg12_encode_init_static(void) bits = ff_mpeg12_vlc_dc_lum_bits[index] + index; code = (ff_mpeg12_vlc_dc_lum_code[index] << index) + - av_mod_uintp2(diff, index); + av_zero_extend(diff, index); mpeg1_lum_dc_uni[i + 255] = bits + (code << 8); bits = ff_mpeg12_vlc_dc_chroma_bits[index] + index; code = (ff_mpeg12_vlc_dc_chroma_code[index] << index) + - av_mod_uintp2(diff, index); + av_zero_extend(diff, index); mpeg1_chr_dc_uni[i + 255] = bits + (code << 8); } @@ -1245,6 +1241,7 @@ const FFCodec ff_mpeg1video_encoder = { .p.supported_framerates = ff_mpeg12_frame_rate_tab + 1, .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, @@ -1264,6 +1261,7 @@ const FFCodec ff_mpeg2video_encoder = { .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/mpeg4audio.h b/libavcodec/mpeg4audio.h index 56615ef32..0819e48a4 100644 --- a/libavcodec/mpeg4audio.h +++ b/libavcodec/mpeg4audio.h @@ -68,50 +68,51 @@ int avpriv_mpeg4audio_get_config2(MPEG4AudioConfig *c, const uint8_t *buf, int size, int sync_extension, void *logctx); enum AudioObjectType { - AOT_NULL, + AOT_NULL = 0, // Support? Name - AOT_AAC_MAIN, ///< Y Main - AOT_AAC_LC, ///< Y Low Complexity - AOT_AAC_SSR, ///< N (code in SoC repo) Scalable Sample Rate - AOT_AAC_LTP, ///< Y Long Term Prediction - AOT_SBR, ///< Y Spectral Band Replication - AOT_AAC_SCALABLE, ///< N Scalable - AOT_TWINVQ, ///< N Twin Vector Quantizer - AOT_CELP, ///< N Code Excited Linear Prediction - AOT_HVXC, ///< N Harmonic Vector eXcitation Coding + AOT_AAC_MAIN = 1, ///< Y Main + AOT_AAC_LC = 2, ///< Y Low Complexity + AOT_AAC_SSR = 3, ///< N (code in SoC repo) Scalable Sample Rate + AOT_AAC_LTP = 4, ///< Y Long Term Prediction + AOT_SBR = 5, ///< Y Spectral Band Replication + AOT_AAC_SCALABLE = 6, ///< N Scalable + AOT_TWINVQ = 7, ///< N Twin Vector Quantizer + AOT_CELP = 8, ///< N Code Excited Linear Prediction + AOT_HVXC = 9, ///< N Harmonic Vector eXcitation Coding + AOT_TTSI = 12, ///< N Text-To-Speech Interface - AOT_MAINSYNTH, ///< N Main Synthesis - AOT_WAVESYNTH, ///< N Wavetable Synthesis - AOT_MIDI, ///< N General MIDI - AOT_SAFX, ///< N Algorithmic Synthesis and Audio Effects - AOT_ER_AAC_LC, ///< N Error Resilient Low Complexity + AOT_MAINSYNTH = 13, ///< N Main Synthesis + AOT_WAVESYNTH = 14, ///< N Wavetable Synthesis + AOT_MIDI = 15, ///< N General MIDI + AOT_SAFX = 16, ///< N Algorithmic Synthesis and Audio Effects + AOT_ER_AAC_LC = 17, ///< N Error Resilient Low Complexity + AOT_ER_AAC_LTP = 19, ///< N Error Resilient Long Term Prediction - AOT_ER_AAC_SCALABLE, ///< N Error Resilient Scalable - AOT_ER_TWINVQ, ///< N Error Resilient Twin Vector Quantizer - AOT_ER_BSAC, ///< N Error Resilient Bit-Sliced Arithmetic Coding - AOT_ER_AAC_LD, ///< N Error Resilient Low Delay - AOT_ER_CELP, ///< N Error Resilient Code Excited Linear Prediction - AOT_ER_HVXC, ///< N Error Resilient Harmonic Vector eXcitation Coding - AOT_ER_HILN, ///< N Error Resilient Harmonic and Individual Lines plus Noise - AOT_ER_PARAM, ///< N Error Resilient Parametric - AOT_SSC, ///< N SinuSoidal Coding - AOT_PS, ///< N Parametric Stereo - AOT_SURROUND, ///< N MPEG Surround - AOT_ESCAPE, ///< Y Escape Value - AOT_L1, ///< Y Layer 1 - AOT_L2, ///< Y Layer 2 - AOT_L3, ///< Y Layer 3 - AOT_DST, ///< N Direct Stream Transfer - AOT_ALS, ///< Y Audio LosslesS - AOT_SLS, ///< N Scalable LosslesS - AOT_SLS_NON_CORE, ///< N Scalable LosslesS (non core) - AOT_ER_AAC_ELD, ///< N Error Resilient Enhanced Low Delay - AOT_SMR_SIMPLE, ///< N Symbolic Music Representation Simple - AOT_SMR_MAIN, ///< N Symbolic Music Representation Main - AOT_USAC_NOSBR, ///< N Unified Speech and Audio Coding (no SBR) - AOT_SAOC, ///< N Spatial Audio Object Coding - AOT_LD_SURROUND, ///< N Low Delay MPEG Surround - AOT_USAC, ///< N Unified Speech and Audio Coding + AOT_ER_AAC_SCALABLE = 20, ///< N Error Resilient Scalable + AOT_ER_TWINVQ = 21, ///< N Error Resilient Twin Vector Quantizer + AOT_ER_BSAC = 22, ///< N Error Resilient Bit-Sliced Arithmetic Coding + AOT_ER_AAC_LD = 23, ///< N Error Resilient Low Delay + AOT_ER_CELP = 24, ///< N Error Resilient Code Excited Linear Prediction + AOT_ER_HVXC = 25, ///< N Error Resilient Harmonic Vector eXcitation Coding + AOT_ER_HILN = 26, ///< N Error Resilient Harmonic and Individual Lines plus Noise + AOT_ER_PARAM = 27, ///< N Error Resilient Parametric + AOT_SSC = 28, ///< N SinuSoidal Coding + AOT_PS = 29, ///< N Parametric Stereo + AOT_SURROUND = 30, ///< N MPEG Surround + AOT_ESCAPE = 31, ///< Y Escape Value + AOT_L1 = 32, ///< Y Layer 1 + AOT_L2 = 33, ///< Y Layer 2 + AOT_L3 = 34, ///< Y Layer 3 + AOT_DST = 35, ///< N Direct Stream Transfer + AOT_ALS = 36, ///< Y Audio LosslesS + AOT_SLS = 37, ///< N Scalable LosslesS + AOT_SLS_NON_CORE = 38, ///< N Scalable LosslesS (non core) + AOT_ER_AAC_ELD = 39, ///< N Error Resilient Enhanced Low Delay + AOT_SMR_SIMPLE = 40, ///< N Symbolic Music Representation Simple + AOT_SMR_MAIN = 41, ///< N Symbolic Music Representation Main + AOT_USAC = 42, ///< Y Unified Speech and Audio Coding + AOT_SAOC = 43, ///< N Spatial Audio Object Coding + AOT_LD_SURROUND = 44, ///< N Low Delay MPEG Surround }; #define MAX_PCE_SIZE 320 ///pb_time; int p_mx, p_my; - p_mx = s->next_picture.motion_val[0][xy][0]; + p_mx = s->next_pic.motion_val[0][xy][0]; if ((unsigned)(p_mx + tab_bias) < tab_size) { s->mv[0][i][0] = s->direct_scale_mv[0][p_mx + tab_bias] + mx; s->mv[1][i][0] = mx ? s->mv[0][i][0] - p_mx @@ -108,7 +108,7 @@ static inline void ff_mpeg4_set_one_direct_mv(MpegEncContext *s, int mx, s->mv[1][i][0] = mx ? s->mv[0][i][0] - p_mx : p_mx * (time_pb - time_pp) / time_pp; } - p_my = s->next_picture.motion_val[0][xy][1]; + p_my = s->next_pic.motion_val[0][xy][1]; if ((unsigned)(p_my + tab_bias) < tab_size) { s->mv[0][i][1] = s->direct_scale_mv[0][p_my + tab_bias] + my; s->mv[1][i][1] = my ? s->mv[0][i][1] - p_my @@ -129,7 +129,7 @@ static inline void ff_mpeg4_set_one_direct_mv(MpegEncContext *s, int mx, int ff_mpeg4_set_direct_mv(MpegEncContext *s, int mx, int my) { const int mb_index = s->mb_x + s->mb_y * s->mb_stride; - const int colocated_mb_type = s->next_picture.mb_type[mb_index]; + const int colocated_mb_type = s->next_pic.mb_type[mb_index]; uint16_t time_pp; uint16_t time_pb; int i; @@ -141,11 +141,11 @@ int ff_mpeg4_set_direct_mv(MpegEncContext *s, int mx, int my) s->mv_type = MV_TYPE_8X8; for (i = 0; i < 4; i++) ff_mpeg4_set_one_direct_mv(s, mx, my, i); - return MB_TYPE_DIRECT2 | MB_TYPE_8x8 | MB_TYPE_L0L1; + return MB_TYPE_DIRECT2 | MB_TYPE_8x8 | MB_TYPE_BIDIR_MV; } else if (IS_INTERLACED(colocated_mb_type)) { s->mv_type = MV_TYPE_FIELD; for (i = 0; i < 2; i++) { - int field_select = s->next_picture.ref_index[0][4 * mb_index + 2 * i]; + int field_select = s->next_pic.ref_index[0][4 * mb_index + 2 * i]; s->field_select[0][i] = field_select; s->field_select[1][i] = i; if (s->top_field_first) { @@ -169,7 +169,7 @@ int ff_mpeg4_set_direct_mv(MpegEncContext *s, int mx, int my) (time_pb - time_pp) / time_pp; } return MB_TYPE_DIRECT2 | MB_TYPE_16x8 | - MB_TYPE_L0L1 | MB_TYPE_INTERLACED; + MB_TYPE_BIDIR_MV | MB_TYPE_INTERLACED; } else { ff_mpeg4_set_one_direct_mv(s, mx, my, 0); s->mv[0][1][0] = @@ -190,6 +190,6 @@ int ff_mpeg4_set_direct_mv(MpegEncContext *s, int mx, int my) else s->mv_type = MV_TYPE_8X8; // Note see prev line - return MB_TYPE_DIRECT2 | MB_TYPE_16x16 | MB_TYPE_L0L1; + return MB_TYPE_DIRECT2 | MB_TYPE_16x16 | MB_TYPE_BIDIR_MV; } } diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c index 402594e01..b00b523bd 100644 --- a/libavcodec/mpeg4video_parser.c +++ b/libavcodec/mpeg4video_parser.c @@ -122,7 +122,7 @@ static av_cold int mpeg4video_parse_init(AVCodecParserContext *s) struct Mp4vParseContext *pc = s->priv_data; pc->first_picture = 1; - pc->dec_ctx.m.quant_precision = 5; + pc->dec_ctx.quant_precision = 5; pc->dec_ctx.m.slice_context_count = 1; pc->dec_ctx.showed_packed_warning = 1; return 0; diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c index 04a9ae504..debcafc4c 100644 --- a/libavcodec/mpeg4videodec.c +++ b/libavcodec/mpeg4videodec.c @@ -45,7 +45,7 @@ #include "internal.h" #include "profiles.h" #include "qpeldsp.h" -#include "threadframe.h" +#include "threadprogress.h" #include "xvididct.h" #include "unary.h" @@ -67,11 +67,11 @@ static VLCElem studio_chroma_dc[528]; static const uint8_t mpeg4_block_count[4] = { 0, 6, 8, 12 }; -static const int mb_type_b_map[4] = { - MB_TYPE_DIRECT2 | MB_TYPE_L0L1, - MB_TYPE_L0L1 | MB_TYPE_16x16, - MB_TYPE_L1 | MB_TYPE_16x16, - MB_TYPE_L0 | MB_TYPE_16x16, +static const int16_t mb_type_b_map[4] = { + MB_TYPE_DIRECT2 | MB_TYPE_BIDIR_MV, + MB_TYPE_BIDIR_MV | MB_TYPE_16x16, + MB_TYPE_BACKWARD_MV | MB_TYPE_16x16, + MB_TYPE_FORWARD_MV | MB_TYPE_16x16, }; static void gmc1_motion(MpegEncContext *s, const Mpeg4DecContext *ctx, @@ -316,7 +316,7 @@ void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n, int dir) { int i; int16_t *ac_val, *ac_val1; - int8_t *const qscale_table = s->current_picture.qscale_table; + int8_t *const qscale_table = s->cur_pic.qscale_table; /* find prediction */ ac_val = &s->ac_val[0][0][0] + s->block_index[n] * 16; @@ -728,7 +728,7 @@ int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx) s->mb_y = mb_num / s->mb_width; if (ctx->shape != BIN_ONLY_SHAPE) { - int qscale = get_bits(&s->gb, s->quant_precision); + int qscale = get_bits(&s->gb, ctx->quant_precision); if (qscale) s->chroma_qscale = s->qscale = qscale; } @@ -895,7 +895,7 @@ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) else code = get_vlc2(&s->gb, dc_chrom, DC_VLC_BITS, 1); - if (code < 0 || code > 9 /* && s->nbit < 9 */) { + if (code < 0) { av_log(s->avctx, AV_LOG_ERROR, "illegal dc vlc\n"); return AVERROR_INVALIDDATA; } @@ -949,8 +949,7 @@ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) int dir = 0; mb_num++; - ff_update_block_index(s, s->avctx->bits_per_raw_sample, - s->avctx->lowres, s->chroma_x_shift); + 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; @@ -970,13 +969,13 @@ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) } while (cbpc == 8); s->cbp_table[xy] = cbpc & 3; - s->current_picture.mb_type[xy] = MB_TYPE_INTRA; + s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; s->mb_intra = 1; if (cbpc & 4) ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); - s->current_picture.qscale_table[xy] = s->qscale; + s->cur_pic.qscale_table[xy] = s->qscale; s->mbintra_table[xy] = 1; for (i = 0; i < 6; i++) { @@ -994,7 +993,7 @@ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) s->pred_dir_table[xy] = dir; } else { /* P/S_TYPE */ int mx, my, pred_x, pred_y, bits; - int16_t *const mot_val = s->current_picture.motion_val[0][s->block_index[0]]; + int16_t *const mot_val = s->cur_pic.motion_val[0][s->block_index[0]]; const int stride = s->b8_stride * 2; try_again: @@ -1007,16 +1006,16 @@ try_again: /* skip mb */ if (s->pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - s->current_picture.mb_type[xy] = MB_TYPE_SKIP | + s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_GMC | - MB_TYPE_L0; + MB_TYPE_FORWARD_MV; mx = get_amv(ctx, 0); my = get_amv(ctx, 1); } else { - s->current_picture.mb_type[xy] = MB_TYPE_SKIP | + s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | - MB_TYPE_L0; + MB_TYPE_FORWARD_MV; mx = my = 0; } mot_val[0] = @@ -1047,7 +1046,7 @@ try_again: s->mb_intra = ((cbpc & 4) != 0); if (s->mb_intra) { - s->current_picture.mb_type[xy] = MB_TYPE_INTRA; + s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; s->mbintra_table[xy] = 1; mot_val[0] = mot_val[2] = @@ -1080,14 +1079,14 @@ try_again: my = ff_h263_decode_motion(s, pred_y, s->f_code); if (my >= 0xffff) return AVERROR_INVALIDDATA; - s->current_picture.mb_type[xy] = MB_TYPE_16x16 | - MB_TYPE_L0; + s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | + MB_TYPE_FORWARD_MV; } else { mx = get_amv(ctx, 0); my = get_amv(ctx, 1); - s->current_picture.mb_type[xy] = MB_TYPE_16x16 | + s->cur_pic.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_GMC | - MB_TYPE_L0; + MB_TYPE_FORWARD_MV; } mot_val[0] = @@ -1100,8 +1099,8 @@ try_again: mot_val[3 + stride] = my; } else { int i; - s->current_picture.mb_type[xy] = MB_TYPE_8x8 | - MB_TYPE_L0; + s->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); @@ -1141,8 +1140,7 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) const int xy = s->mb_x + s->mb_y * s->mb_stride; mb_num++; - ff_update_block_index(s, s->avctx->bits_per_raw_sample, - s->avctx->lowres, s->chroma_x_shift); + 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; @@ -1156,9 +1154,9 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) } s->cbp_table[xy] |= cbpy << 2; - s->current_picture.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; + s->cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; } else { /* P || S_TYPE */ - if (IS_INTRA(s->current_picture.mb_type[xy])) { + if (IS_INTRA(s->cur_pic.mb_type[xy])) { int i; int dir = 0; int ac_pred = get_bits1(&s->gb); @@ -1172,7 +1170,7 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) if (s->cbp_table[xy] & 8) ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); - s->current_picture.qscale_table[xy] = s->qscale; + s->cur_pic.qscale_table[xy] = s->qscale; for (i = 0; i < 6; i++) { int dc_pred_dir; @@ -1188,10 +1186,10 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) } s->cbp_table[xy] &= 3; // remove dquant s->cbp_table[xy] |= cbpy << 2; - s->current_picture.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; + s->cur_pic.mb_type[xy] |= ac_pred * MB_TYPE_ACPRED; s->pred_dir_table[xy] = dir; - } else if (IS_SKIP(s->current_picture.mb_type[xy])) { - s->current_picture.qscale_table[xy] = s->qscale; + } else if (IS_SKIP(s->cur_pic.mb_type[xy])) { + s->cur_pic.qscale_table[xy] = s->qscale; s->cbp_table[xy] = 0; } else { int cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); @@ -1204,7 +1202,7 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) if (s->cbp_table[xy] & 8) ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]); - s->current_picture.qscale_table[xy] = s->qscale; + s->cur_pic.qscale_table[xy] = s->qscale; s->cbp_table[xy] &= 3; // remove dquant s->cbp_table[xy] |= (cbpy ^ 0xf) << 2; @@ -1294,8 +1292,8 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, MpegEncContext *s = &ctx->m; int level, i, last, run, qmul, qadd; int av_uninit(dc_pred_dir); - RLTable *rl; - RL_VLC_ELEM *rl_vlc; + const RLTable *rl; + const RL_VLC_ELEM *rl_vlc; const uint8_t *scan_table; // Note intra & rvlc should be optimized away if this is inlined @@ -1567,20 +1565,20 @@ static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) av_assert2(s == (void*)ctx); - mb_type = s->current_picture.mb_type[xy]; + mb_type = s->cur_pic.mb_type[xy]; cbp = s->cbp_table[xy]; use_intra_dc_vlc = s->qscale < ctx->intra_dc_threshold; - if (s->current_picture.qscale_table[xy] != s->qscale) - ff_set_qscale(s, s->current_picture.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) { int i; for (i = 0; i < 4; i++) { - s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0]; - s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1]; + 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->mb_intra = IS_INTRA(mb_type); @@ -1594,12 +1592,14 @@ static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) && ctx->vol_sprite_usage == GMC_SPRITE) { s->mcsel = 1; s->mb_skipped = 0; + s->cur_pic.mbskip_table[xy] = 0; } else { s->mcsel = 0; s->mb_skipped = 1; + s->cur_pic.mbskip_table[xy] = 1; } } else if (s->mb_intra) { - s->ac_pred = IS_ACPRED(s->current_picture.mb_type[xy]); + 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? @@ -1612,7 +1612,7 @@ static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) } } else { /* I-Frame */ s->mb_intra = 1; - s->ac_pred = IS_ACPRED(s->current_picture.mb_type[xy]); + s->ac_pred = IS_ACPRED(s->cur_pic.mb_type[xy]); } if (!IS_SKIP(mb_type)) { @@ -1651,7 +1651,6 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) { Mpeg4DecContext *ctx = s->avctx->priv_data; int cbpc, cbpy, i, cbp, pred_x, pred_y, mx, my, dquant; - int16_t *mot_val; static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; const int xy = s->mb_x + s->mb_y * s->mb_stride; int next; @@ -1671,21 +1670,22 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv_type = MV_TYPE_16X16; if (s->pict_type == AV_PICTURE_TYPE_S && ctx->vol_sprite_usage == GMC_SPRITE) { - s->current_picture.mb_type[xy] = MB_TYPE_SKIP | + s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_GMC | MB_TYPE_16x16 | - MB_TYPE_L0; + 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; } else { - s->current_picture.mb_type[xy] = MB_TYPE_SKIP | - MB_TYPE_16x16 | - MB_TYPE_L0; + s->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; } goto end; @@ -1726,9 +1726,8 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv_dir = MV_DIR_FORWARD; if ((cbpc & 16) == 0) { if (s->mcsel) { - s->current_picture.mb_type[xy] = MB_TYPE_GMC | - MB_TYPE_16x16 | - MB_TYPE_L0; + s->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; mx = get_amv(ctx, 0); @@ -1736,8 +1735,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv[0][0][0] = mx; s->mv[0][0][1] = my; } else if ((!s->progressive_sequence) && get_bits1(&s->gb)) { - s->current_picture.mb_type[xy] = MB_TYPE_16x8 | - MB_TYPE_L0 | + s->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; @@ -1760,7 +1758,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv[0][i][1] = my; } } else { - s->current_picture.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_L0; + s->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); @@ -1777,10 +1775,10 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv[0][0][1] = my; } } else { - s->current_picture.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_L0; + s->cur_pic.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_FORWARD_MV; s->mv_type = MV_TYPE_8X8; for (i = 0; i < 4; i++) { - mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); + 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); if (mx >= 0xffff) return AVERROR_INVALIDDATA; @@ -1810,11 +1808,11 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->last_mv[i][1][1] = 0; } - ff_thread_await_progress(&s->next_picture_ptr->tf, s->mb_y, 0); + ff_thread_progress_await(&s->next_pic.ptr->progress, s->mb_y); } /* if we skipped it in the future P-frame than skip it now too */ - s->mb_skipped = s->next_picture.mbskip_table[s->mb_y * s->mb_stride + s->mb_x]; // Note, skiptab=0 if last was GMC + s->mb_skipped = s->next_pic.mbskip_table[s->mb_y * s->mb_stride + s->mb_x]; // Note, skiptab=0 if last was GMC if (s->mb_skipped) { /* skip mb */ @@ -1827,16 +1825,16 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv[0][0][1] = s->mv[1][0][0] = s->mv[1][0][1] = 0; - s->current_picture.mb_type[xy] = MB_TYPE_SKIP | + s->cur_pic.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | - MB_TYPE_L0; + MB_TYPE_FORWARD_MV; goto end; } modb1 = get_bits1(&s->gb); if (modb1) { // like MB_TYPE_B_DIRECT but no vectors coded - mb_type = MB_TYPE_DIRECT2 | MB_TYPE_SKIP | MB_TYPE_L0L1; + mb_type = MB_TYPE_DIRECT2 | MB_TYPE_SKIP | MB_TYPE_BIDIR_MV; cbp = 0; } else { modb2 = get_bits1(&s->gb); @@ -1845,7 +1843,6 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) av_log(s->avctx, AV_LOG_ERROR, "illegal MB_type\n"); return AVERROR_INVALIDDATA; } - mb_type = mb_type_b_map[mb_type]; if (modb2) { cbp = 0; } else { @@ -1866,11 +1863,11 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) mb_type |= MB_TYPE_16x8 | MB_TYPE_INTERLACED; mb_type &= ~MB_TYPE_16x16; - if (USES_LIST(mb_type, 0)) { + if (HAS_FORWARD_MV(mb_type)) { s->field_select[0][0] = get_bits1(&s->gb); s->field_select[0][1] = get_bits1(&s->gb); } - if (USES_LIST(mb_type, 1)) { + if (HAS_BACKWARD_MV(mb_type)) { s->field_select[1][0] = get_bits1(&s->gb); s->field_select[1][1] = get_bits1(&s->gb); } @@ -1881,7 +1878,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) if ((mb_type & (MB_TYPE_DIRECT2 | MB_TYPE_INTERLACED)) == 0) { s->mv_type = MV_TYPE_16X16; - if (USES_LIST(mb_type, 0)) { + if (HAS_FORWARD_MV(mb_type)) { s->mv_dir = MV_DIR_FORWARD; mx = ff_h263_decode_motion(s, s->last_mv[0][0][0], s->f_code); @@ -1894,7 +1891,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv[0][0][1] = my; } - if (USES_LIST(mb_type, 1)) { + if (HAS_BACKWARD_MV(mb_type)) { s->mv_dir |= MV_DIR_BACKWARD; mx = ff_h263_decode_motion(s, s->last_mv[1][0][0], s->b_code); @@ -1909,7 +1906,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) } else if (!IS_DIRECT(mb_type)) { s->mv_type = MV_TYPE_FIELD; - if (USES_LIST(mb_type, 0)) { + if (HAS_FORWARD_MV(mb_type)) { s->mv_dir = MV_DIR_FORWARD; for (i = 0; i < 2; i++) { @@ -1921,7 +1918,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) } } - if (USES_LIST(mb_type, 1)) { + if (HAS_BACKWARD_MV(mb_type)) { s->mv_dir |= MV_DIR_BACKWARD; for (i = 0; i < 2; i++) { @@ -1947,7 +1944,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT; mb_type |= ff_mpeg4_set_direct_mv(s, mx, my); } - s->current_picture.mb_type[xy] = mb_type; + s->cur_pic.mb_type[xy] = mb_type; } else { /* I-Frame */ int use_intra_dc_vlc; @@ -1966,9 +1963,9 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) intra: s->ac_pred = get_bits1(&s->gb); if (s->ac_pred) - s->current_picture.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; + s->cur_pic.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED; else - s->current_picture.mb_type[xy] = MB_TYPE_INTRA; + s->cur_pic.mb_type[xy] = MB_TYPE_INTRA; cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc, CBPY_VLC_BITS, 1); if (cbpy < 0) { @@ -2015,11 +2012,11 @@ end: if (s->pict_type == AV_PICTURE_TYPE_B) { const int delta = s->mb_x + 1 == s->mb_width ? 2 : 1; - ff_thread_await_progress(&s->next_picture_ptr->tf, + 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, 0); - if (s->next_picture.mbskip_table[xy + delta]) + : s->mb_y); + if (s->next_pic.mbskip_table[xy + delta]) return SLICE_OK; } @@ -2073,7 +2070,7 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n 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]; - uint8_t *const scantable = s->intra_scantable.permutated; + const uint8_t *const scantable = s->intra_scantable.permutated; const uint16_t *quant_matrix; uint32_t flc; const int min = -1 * (1 << (s->avctx->bits_per_raw_sample + 6)); @@ -2709,17 +2706,16 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) // FIXME sadct disable bit if verid!=1 && shape not rect if (get_bits1(gb) == 1) { /* not_8_bit */ - s->quant_precision = get_bits(gb, 4); /* quant_precision */ + 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"); - if (s->quant_precision != 5) + if (ctx->quant_precision != 5) av_log(s->avctx, AV_LOG_ERROR, - "quant precision %d\n", s->quant_precision); - if (s->quant_precision<3 || s->quant_precision>9) { - s->quant_precision = 5; - } + "quant precision %d\n", ctx->quant_precision); + if (ctx->quant_precision < 3 || ctx->quant_precision > 9) + ctx->quant_precision = 5; } else { - s->quant_precision = 5; + ctx->quant_precision = 5; } // FIXME a bunch of grayscale shape things @@ -2907,7 +2903,7 @@ no_cplx_est: 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, ctx->time_increment_bits, - s->quant_precision, + ctx->quant_precision, s->progressive_sequence, s->low_delay, ctx->scalability ? "scalability " :"" , s->quarter_sample ? "qpel " : "", @@ -3254,22 +3250,17 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, } else s->alternate_scan = 0; } - if (s->alternate_scan) { - ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, ff_alternate_vertical_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); - ff_permute_scantable(s->permutated_intra_v_scantable, ff_alternate_vertical_scan, - s->idsp.idct_permutation); } else { - 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); } + 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 @@ -3294,7 +3285,7 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb, } if (ctx->shape != BIN_ONLY_SHAPE) { - s->chroma_qscale = s->qscale = get_bits(gb, s->quant_precision); + s->chroma_qscale = s->qscale = get_bits(gb, ctx->quant_precision); if (s->qscale == 0) { av_log(s->avctx, AV_LOG_ERROR, "Error, header damaged or not MPEG-4 header (qscale=0)\n"); @@ -3433,21 +3424,8 @@ static int decode_studio_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb) s->q_scale_type = get_bits1(gb); } - if (s->alternate_scan) { - ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, ff_alternate_vertical_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); - ff_permute_scantable(s->permutated_intra_v_scantable, ff_alternate_vertical_scan, - s->idsp.idct_permutation); - } else { - 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); - } + ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, + s->alternate_scan ? ff_alternate_vertical_scan : ff_zigzag_direct); mpeg4_load_default_matrices(s); @@ -3794,9 +3772,10 @@ static av_cold void mpeg4_init_static(void) VLC_INIT_STATIC_TABLE_FROM_LENGTHS(sprite_trajectory, SPRITE_TRAJ_VLC_BITS, 15, ff_sprite_trajectory_lens, 1, NULL, 0, 0, 0, 0); - VLC_INIT_STATIC_TABLE(mb_type_b_vlc, MB_TYPE_B_VLC_BITS, 4, - &ff_mb_type_b_tab[0][1], 2, 1, - &ff_mb_type_b_tab[0][0], 2, 1, 0); + VLC_INIT_STATIC_SPARSE_TABLE(mb_type_b_vlc, MB_TYPE_B_VLC_BITS, 4, + &ff_mb_type_b_tab[0][1], 2, 1, + &ff_mb_type_b_tab[0][0], 2, 1, + mb_type_b_map, 2, 2, 0); } static av_cold int decode_init(AVCodecContext *avctx) @@ -3818,6 +3797,7 @@ static av_cold int decode_init(AVCodecContext *avctx) s->low_delay = 0; /* default, might be overridden in the vol header during header parsing */ s->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; @@ -3859,12 +3839,12 @@ const FFCodec ff_mpeg4_decoder = { .p.id = AV_CODEC_ID_MPEG4, .priv_data_size = sizeof(Mpeg4DecContext), .init = decode_init, - .close = ff_h263_decode_end, FF_CODEC_DECODE_CB(ff_h263_decode_frame), + .close = ff_mpv_decode_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_SKIP_FRAME_FILL_PARAM | - FF_CODEC_CAP_ALLOCATE_PROGRESS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .flush = ff_mpeg_flush, .p.max_lowres = 3, .p.profiles = NULL_IF_CONFIG_SMALL(ff_mpeg4_video_profiles), diff --git a/libavcodec/mpeg4videodec.h b/libavcodec/mpeg4videodec.h index 4a26d1898..734237b16 100644 --- a/libavcodec/mpeg4videodec.h +++ b/libavcodec/mpeg4videodec.h @@ -60,6 +60,8 @@ typedef struct Mpeg4DecContext { int enhancement_type; int scalability; + int quant_precision; + /// QP above which the ac VLC should be used for intra dc int intra_dc_threshold; diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c index d1e50612d..98254c2c6 100644 --- a/libavcodec/mpeg4videoenc.c +++ b/libavcodec/mpeg4videoenc.c @@ -22,10 +22,10 @@ #include "libavutil/attributes.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/thread.h" #include "codec_internal.h" -#include "mpegutils.h" #include "mpegvideo.h" #include "h263.h" #include "h263enc.h" @@ -71,7 +71,7 @@ static uint8_t uni_mpeg4_inter_rl_len[64 * 64 * 2 * 2]; * @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], - int block_last_index, uint8_t scantable[64]) + int block_last_index, const uint8_t scantable[64]) { int last = 0; int j; @@ -106,7 +106,7 @@ static inline int get_block_rate(MpegEncContext *s, int16_t block[64], * @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], - const int dir[6], uint8_t *st[6], + const int dir[6], const uint8_t *st[6], const int zigzag_last_index[6]) { int i, n; @@ -137,12 +137,12 @@ static inline void restore_ac_coeffs(MpegEncContext *s, int16_t block[6][64], * @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], - const int dir[6], uint8_t *st[6], + const int dir[6], const uint8_t *st[6], int zigzag_last_index[6]) { int score = 0; int i, n; - int8_t *const qscale_table = s->current_picture.qscale_table; + const int8_t *const qscale_table = s->cur_pic.qscale_table; memcpy(zigzag_last_index, s->block_last_index, sizeof(int) * 6); @@ -222,7 +222,7 @@ static inline int decide_ac_pred(MpegEncContext *s, int16_t block[6][64], void ff_clean_mpeg4_qscales(MpegEncContext *s) { int i; - int8_t *const qscale_table = s->current_picture.qscale_table; + int8_t *const qscale_table = s->cur_pic.qscale_table; ff_clean_h263_qscales(s); @@ -288,14 +288,14 @@ static inline int mpeg4_get_dc_length(int level, int n) * Encode an 8x8 block. * @param n block index (0-3 are luma, 4-5 are chroma) */ -static inline void mpeg4_encode_block(MpegEncContext *s, - int16_t *block, int n, int intra_dc, - uint8_t *scan_table, PutBitContext *dc_pb, +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) { int i, last_non_zero; - uint32_t *bits_tab; - uint8_t *len_tab; + 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 @@ -350,11 +350,11 @@ static inline void mpeg4_encode_block(MpegEncContext *s, } static int mpeg4_get_block_length(MpegEncContext *s, - int16_t *block, int n, - int intra_dc, uint8_t *scan_table) + const int16_t *block, int n, + int intra_dc, const uint8_t *scan_table) { int i, last_non_zero; - uint8_t *len_tab; + const uint8_t *len_tab; const int last_index = s->block_last_index[n]; int len = 0; @@ -403,8 +403,10 @@ static int mpeg4_get_block_length(MpegEncContext *s, return len; } -static inline void mpeg4_encode_blocks(MpegEncContext *s, int16_t block[6][64], - int intra_dc[6], uint8_t **scan_table, +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) { @@ -511,8 +513,7 @@ 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_picture.mbskip_table[s->mb_y * s->mb_stride + s->mb_x]) { // FIXME avoid DCT & ... - s->skip_count++; + 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] = @@ -536,7 +537,6 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], s->misc_bits++; s->last_bits++; } - s->skip_count++; return; } @@ -646,13 +646,13 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], y = s->mb_y * 16; offset = x + y * s->linesize; - p_pic = s->new_picture->data[0] + offset; + p_pic = s->new_pic->data[0] + offset; s->mb_skipped = 1; for (i = 0; i < s->max_b_frames; i++) { const uint8_t *b_pic; int diff; - Picture *pic = s->reordered_input_picture[i + 1]; + const MPVPicture *pic = s->reordered_input_picture[i + 1]; if (!pic || pic->f->pict_type != AV_PICTURE_TYPE_B) break; @@ -673,7 +673,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], } diff = diff * 256 / (xe * ye); } else { - diff = s->mecc.sad[0](NULL, p_pic, b_pic, s->linesize, 16); + diff = s->sad_cmp[0](NULL, p_pic, b_pic, s->linesize, 16); } if (diff > s->qscale * 70) { // FIXME check that 70 is optimal s->mb_skipped = 0; @@ -691,7 +691,6 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], s->misc_bits++; s->last_bits++; } - s->skip_count++; return; } @@ -780,8 +779,8 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); ff_h263_encode_motion_vector(s, - s->current_picture.motion_val[0][s->block_index[i]][0] - pred_x, - s->current_picture.motion_val[0][s->block_index[i]][1] - pred_y, + 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->f_code); } } @@ -799,7 +798,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], int dc_diff[6]; // dc values with the dc prediction subtracted int dir[6]; // prediction direction int zigzag_last_index[6]; - uint8_t *scan_table[6]; + const uint8_t *scan_table[6]; int i; for (i = 0; i < 6; i++) @@ -863,11 +862,9 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], */ void ff_mpeg4_stuffing(PutBitContext *pbc) { - int length; - put_bits(pbc, 1, 0); - length = (-put_bits_count(pbc)) & 7; - if (length) - put_bits(pbc, length, (1 << length) - 1); + int length = 8 - (put_bits_count(pbc) & 7); + + put_bits(pbc, length, (1 << (length - 1)) - 1); } /* must be called before writing the header */ @@ -886,10 +883,9 @@ static void mpeg4_encode_gop_header(MpegEncContext *s) int64_t hours, minutes, seconds; int64_t time; - put_bits(&s->pb, 16, 0); - put_bits(&s->pb, 16, GOP_STARTCODE); + put_bits32(&s->pb, GOP_STARTCODE); - time = s->current_picture_ptr->f->pts; + 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; @@ -936,13 +932,11 @@ static void mpeg4_encode_visual_object_header(MpegEncContext *s) // FIXME levels - put_bits(&s->pb, 16, 0); - put_bits(&s->pb, 16, VOS_STARTCODE); + put_bits32(&s->pb, VOS_STARTCODE); put_bits(&s->pb, 8, profile_and_level_indication); - put_bits(&s->pb, 16, 0); - put_bits(&s->pb, 16, VISUAL_OBJ_STARTCODE); + put_bits32(&s->pb, VISUAL_OBJ_STARTCODE); put_bits(&s->pb, 1, 1); put_bits(&s->pb, 4, vo_ver_id); @@ -969,10 +963,8 @@ static void mpeg4_encode_vol_header(MpegEncContext *s, vo_type = SIMPLE_VO_TYPE; } - put_bits(&s->pb, 16, 0); - put_bits(&s->pb, 16, 0x100 + vo_number); /* video obj */ - put_bits(&s->pb, 16, 0); - put_bits(&s->pb, 16, 0x120 + vol_number); /* video obj layer */ + put_bits32(&s->pb, 0x100 + vo_number); /* video obj */ + put_bits32(&s->pb, 0x120 + vol_number); /* video obj layer */ put_bits(&s->pb, 1, 0); /* random access vol */ put_bits(&s->pb, 8, vo_type); /* video obj type indication */ @@ -1049,8 +1041,7 @@ static void mpeg4_encode_vol_header(MpegEncContext *s, /* user data */ if (!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT)) { - put_bits(&s->pb, 16, 0); - put_bits(&s->pb, 16, 0x1B2); /* user_data */ + put_bits32(&s->pb, USER_DATA_STARTCODE); ff_put_string(&s->pb, LIBAVCODEC_IDENT, 0); } } @@ -1074,8 +1065,7 @@ int ff_mpeg4_encode_picture_header(MpegEncContext *s) s->partitioned_frame = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_B; - put_bits(&s->pb, 16, 0); /* vop header */ - put_bits(&s->pb, 16, VOP_STARTCODE); /* vop header */ + put_bits32(&s->pb, VOP_STARTCODE); /* vop header */ put_bits(&s->pb, 2, s->pict_type - 1); /* pict type: I = 0 , P = 1 */ time_div = FFUDIV(s->time, s->avctx->time_base.den); @@ -1101,7 +1091,7 @@ int ff_mpeg4_encode_picture_header(MpegEncContext *s) } put_bits(&s->pb, 3, 0); /* intra dc VLC threshold */ if (!s->progressive_sequence) { - put_bits(&s->pb, 1, !!(s->current_picture_ptr->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)); + 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); } // FIXME sprite stuff @@ -1368,7 +1358,7 @@ void ff_mpeg4_encode_video_packet_header(MpegEncContext *s) 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, s->quant_precision, s->qscale); + put_bits(&s->pb, 5 /* quant_precision */, s->qscale); put_bits(&s->pb, 1, 0); /* no HEC */ } @@ -1403,6 +1393,7 @@ const FFCodec ff_mpeg4_encoder = { 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 }, + .color_ranges = AVCOL_RANGE_MPEG, .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/mpeg_er.c b/libavcodec/mpeg_er.c index 803496325..3cbdeeebe 100644 --- a/libavcodec/mpeg_er.c +++ b/libavcodec/mpeg_er.c @@ -16,12 +16,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "error_resilience.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "mpeg_er.h" -static void set_erpic(ERPicture *dst, Picture *src) +static void set_erpic(ERPicture *dst, const MPVPicture *src) { int i; @@ -33,7 +35,7 @@ static void set_erpic(ERPicture *dst, Picture *src) } dst->f = src->f; - dst->tf = &src->tf; + dst->progress = &src->progress; for (i = 0; i < 2; i++) { dst->motion_val[i] = src->motion_val[i]; @@ -48,9 +50,9 @@ void ff_mpeg_er_frame_start(MpegEncContext *s) { ERContext *er = &s->er; - set_erpic(&er->cur_pic, s->current_picture_ptr); - set_erpic(&er->next_pic, s->next_picture_ptr); - set_erpic(&er->last_pic, s->last_picture_ptr); + set_erpic(&er->cur_pic, s->cur_pic.ptr); + 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; @@ -66,6 +68,8 @@ static void mpeg_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type, { MpegEncContext *s = opaque; + av_assert1(!mb_intra); + s->mv_dir = mv_dir; s->mv_type = mv_type; s->mb_intra = mb_intra; @@ -75,21 +79,17 @@ 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)); - ff_init_block_index(s); - ff_update_block_index(s, s->avctx->bits_per_raw_sample, - s->avctx->lowres, s->chroma_x_shift); + // The following disables the IDCT. + for (size_t i = 0; i < FF_ARRAY_ELEMS(s->block_last_index); i++) + s->block_last_index[i] = -1; - s->bdsp.clear_blocks(s->block[0]); - if (!s->chroma_y_shift) - s->bdsp.clear_blocks(s->block[6]); - - s->dest[0] = s->current_picture.f->data[0] + + s->dest[0] = s->cur_pic.data[0] + s->mb_y * 16 * s->linesize + s->mb_x * 16; - s->dest[1] = s->current_picture.f->data[1] + + s->dest[1] = s->cur_pic.data[1] + s->mb_y * (16 >> s->chroma_y_shift) * s->uvlinesize + s->mb_x * (16 >> s->chroma_x_shift); - s->dest[2] = s->current_picture.f->data[2] + + s->dest[2] = s->cur_pic.data[2] + s->mb_y * (16 >> s->chroma_y_shift) * s->uvlinesize + s->mb_x * (16 >> s->chroma_x_shift); diff --git a/libavcodec/mpegaudiodec_template.c b/libavcodec/mpegaudiodec_template.c index 2b84e6570..c73b1e005 100644 --- a/libavcodec/mpegaudiodec_template.c +++ b/libavcodec/mpegaudiodec_template.c @@ -32,6 +32,7 @@ #include "libavutil/crc.h" #include "libavutil/float_dsp.h" #include "libavutil/libm.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c index 270630bea..cde060aa1 100644 --- a/libavcodec/mpegpicture.c +++ b/libavcodec/mpegpicture.c @@ -18,82 +18,137 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include - #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" #include "avcodec.h" -#include "motion_est.h" #include "mpegpicture.h" -#include "mpegutils.h" #include "refstruct.h" -#include "threadframe.h" -static void av_noinline free_picture_tables(Picture *pic) +static void mpv_pic_reset(FFRefStructOpaque unused, void *obj) { - pic->alloc_mb_width = - pic->alloc_mb_height = 0; + MPVPicture *pic = obj; - av_buffer_unref(&pic->mbskip_table_buf); - av_buffer_unref(&pic->qscale_table_buf); - av_buffer_unref(&pic->mb_type_buf); + av_frame_unref(pic->f); + ff_thread_progress_reset(&pic->progress); + + ff_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); for (int i = 0; i < 2; i++) { - av_buffer_unref(&pic->motion_val_buf[i]); - av_buffer_unref(&pic->ref_index_buf[i]); + ff_refstruct_unref(&pic->motion_val_base[i]); + ff_refstruct_unref(&pic->ref_index[i]); + + pic->motion_val[i] = NULL; } + + pic->mb_type = NULL; + pic->qscale_table = NULL; + + pic->mb_stride = + pic->mb_width = + pic->mb_height = 0; + + pic->dummy = 0; + pic->field_picture = 0; + pic->b_frame_score = 0; + pic->reference = 0; + pic->shared = 0; + pic->display_picture_number = 0; + pic->coded_picture_number = 0; } -static int make_table_writable(AVBufferRef **ref) +static int av_cold mpv_pic_init(FFRefStructOpaque opaque, void *obj) { - AVBufferRef *old = *ref, *new; + MPVPicture *pic = obj; + int ret, init_progress = (uintptr_t)opaque.nc; - if (av_buffer_is_writable(old)) - return 0; - new = av_buffer_allocz(old->size); - if (!new) + ret = ff_thread_progress_init(&pic->progress, init_progress); + if (ret < 0) + return ret; + + pic->f = av_frame_alloc(); + if (!pic->f) return AVERROR(ENOMEM); - av_buffer_unref(ref); - *ref = new; return 0; } -static int make_tables_writable(Picture *pic) +static void av_cold mpv_pic_free(FFRefStructOpaque unused, void *obj) { -#define MAKE_WRITABLE(table) \ -do {\ - int ret = make_table_writable(&pic->table); \ - if (ret < 0) \ - return ret; \ -} while (0) + MPVPicture *pic = obj; - MAKE_WRITABLE(mbskip_table_buf); - MAKE_WRITABLE(qscale_table_buf); - MAKE_WRITABLE(mb_type_buf); - - if (pic->motion_val_buf[0]) { - for (int i = 0; i < 2; i++) { - MAKE_WRITABLE(motion_val_buf[i]); - MAKE_WRITABLE(ref_index_buf[i]); - } - } - - return 0; + ff_thread_progress_destroy(&pic->progress); + av_frame_free(&pic->f); } -int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, - ScratchpadContext *sc, int linesize) +av_cold FFRefStructPool *ff_mpv_alloc_pic_pool(int init_progress) +{ + return ff_refstruct_pool_alloc_ext(sizeof(MPVPicture), + FF_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); + memset(pic, 0, sizeof(*pic)); +} + +static void set_workpic_from_pic(MPVWorkPicture *wpic, const MPVPicture *pic) +{ + for (int i = 0; i < MPV_MAX_PLANES; i++) { + wpic->data[i] = pic->f->data[i]; + wpic->linesize[i] = pic->f->linesize[i]; + } + wpic->qscale_table = pic->qscale_table; + wpic->mb_type = pic->mb_type; + wpic->mbskip_table = pic->mbskip_table; + + for (int i = 0; i < 2; i++) { + wpic->motion_val[i] = pic->motion_val[i]; + wpic->ref_index[i] = pic->ref_index[i]; + } + wpic->reference = pic->reference; +} + +void ff_mpv_replace_picture(MPVWorkPicture *dst, const MPVWorkPicture *src) +{ + av_assert1(dst != src); + ff_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); + if (!pic) { + memset(wpic, 0, sizeof(*wpic)); + return; + } + set_workpic_from_pic(wpic, pic); +} + +int ff_mpv_framesize_alloc(AVCodecContext *avctx, + ScratchpadContext *sc, int linesize) { # define EMU_EDGE_HEIGHT (4 * 70) - int alloc_size = FFALIGN(FFABS(linesize) + 64, 32); + int linesizeabs = FFABS(linesize); + int alloc_size = FFALIGN(linesizeabs + 64, 32); + + if (linesizeabs <= sc->linesize) + return 0; if (avctx->hwaccel) return 0; - if (linesize < 24) { + if (linesizeabs < 24) { av_log(avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n"); return AVERROR_PATCHWELCOME; } @@ -101,6 +156,9 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, if (av_image_check_size2(alloc_size, EMU_EDGE_HEIGHT, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0) return AVERROR(ENOMEM); + av_freep(&sc->edge_emu_buffer); + av_freep(&sc->scratchpad_buf); + // edge emu needs blocksize + filter length - 1 // (= 17x17 for halfpel / 21x21 for H.264) // VC-1 computes luma and chroma simultaneously and needs 19X19 + 9x9 @@ -108,290 +166,93 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, // linesize * interlaced * MBsize // we also use this buffer for encoding in encode_mb_internal() needig an additional 32 lines if (!FF_ALLOCZ_TYPED_ARRAY(sc->edge_emu_buffer, alloc_size * EMU_EDGE_HEIGHT) || - !FF_ALLOCZ_TYPED_ARRAY(me->scratchpad, alloc_size * 4 * 16 * 2)) { + !FF_ALLOCZ_TYPED_ARRAY(sc->scratchpad_buf, alloc_size * 4 * 16 * 2)) { + sc->linesize = 0; av_freep(&sc->edge_emu_buffer); return AVERROR(ENOMEM); } + sc->linesize = linesizeabs; - me->temp = me->scratchpad; - sc->rd_scratchpad = me->scratchpad; - sc->b_scratchpad = me->scratchpad; - sc->obmc_scratchpad = me->scratchpad + 16; + sc->obmc_scratchpad = sc->scratchpad_buf + 16; return 0; } -/** - * Check the pic's linesize and allocate linesize dependent scratch buffers - */ -static int handle_pic_linesizes(AVCodecContext *avctx, Picture *pic, - MotionEstContext *me, ScratchpadContext *sc, - int linesize, int uvlinesize) +int ff_mpv_pic_check_linesize(void *logctx, const AVFrame *f, + ptrdiff_t *linesizep, ptrdiff_t *uvlinesizep) { - int ret; + ptrdiff_t linesize = *linesizep, uvlinesize = *uvlinesizep; - if ((linesize && linesize != pic->f->linesize[0]) || - (uvlinesize && uvlinesize != pic->f->linesize[1])) { - av_log(avctx, AV_LOG_ERROR, - "get_buffer() failed (stride changed: linesize=%d/%d uvlinesize=%d/%d)\n", - linesize, pic->f->linesize[0], - uvlinesize, pic->f->linesize[1]); - ff_mpeg_unref_picture(pic); - return -1; + 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, f->linesize[0], + uvlinesize, f->linesize[1]); + return AVERROR_PATCHWELCOME; } - if (av_pix_fmt_count_planes(pic->f->format) > 2 && - pic->f->linesize[1] != pic->f->linesize[2]) { - av_log(avctx, AV_LOG_ERROR, - "get_buffer() failed (uv stride mismatch)\n"); - ff_mpeg_unref_picture(pic); - return -1; - } - - if (!sc->edge_emu_buffer && - (ret = ff_mpeg_framesize_alloc(avctx, me, sc, - pic->f->linesize[0])) < 0) { - av_log(avctx, AV_LOG_ERROR, - "get_buffer() failed to allocate context scratch buffers.\n"); - ff_mpeg_unref_picture(pic); - return ret; + if (av_pix_fmt_count_planes(f->format) > 2 && + f->linesize[1] != f->linesize[2]) { + av_log(logctx, AV_LOG_ERROR, "uv stride mismatch unsupported\n"); + return AVERROR_PATCHWELCOME; } + *linesizep = f->linesize[0]; + *uvlinesizep = f->linesize[1]; return 0; } -static int alloc_picture_tables(AVCodecContext *avctx, Picture *pic, int encoding, int out_format, - int mb_stride, int mb_width, int mb_height, int b8_stride) +static int alloc_picture_tables(BufferPoolContext *pools, MPVPicture *pic, + int mb_height) { - const int big_mb_num = mb_stride * (mb_height + 1) + 1; - const int mb_array_size = mb_stride * mb_height; - const int b8_array_size = b8_stride * mb_height * 2; - int i; - - - pic->mbskip_table_buf = av_buffer_allocz(mb_array_size + 2); - pic->qscale_table_buf = av_buffer_allocz(big_mb_num + mb_stride); - pic->mb_type_buf = av_buffer_allocz((big_mb_num + mb_stride) * - sizeof(uint32_t)); - if (!pic->mbskip_table_buf || !pic->qscale_table_buf || !pic->mb_type_buf) - return AVERROR(ENOMEM); - - if (out_format == FMT_H263 || encoding || - (avctx->export_side_data & AV_CODEC_EXPORT_DATA_MVS)) { - int mv_size = 2 * (b8_array_size + 4) * sizeof(int16_t); - int ref_index_size = 4 * mb_array_size; - - for (i = 0; mv_size && i < 2; i++) { - pic->motion_val_buf[i] = av_buffer_allocz(mv_size); - pic->ref_index_buf[i] = av_buffer_allocz(ref_index_size); - if (!pic->motion_val_buf[i] || !pic->ref_index_buf[i]) - return AVERROR(ENOMEM); +#define GET_BUFFER(name, buf_suffix, idx_suffix) do { \ + pic->name ## buf_suffix idx_suffix = ff_refstruct_pool_get(pools->name ## _pool); \ + if (!pic->name ## buf_suffix idx_suffix) \ + return AVERROR(ENOMEM); \ +} while (0) + GET_BUFFER(qscale_table, _base,); + GET_BUFFER(mb_type, _base,); + if (pools->motion_val_pool) { + if (pools->mbskip_table_pool) + GET_BUFFER(mbskip_table,,); + for (int i = 0; i < 2; i++) { + GET_BUFFER(ref_index,, [i]); + GET_BUFFER(motion_val, _base, [i]); + pic->motion_val[i] = pic->motion_val_base[i] + 4; } } +#undef GET_BUFFER - pic->alloc_mb_width = mb_width; - pic->alloc_mb_height = mb_height; - pic->alloc_mb_stride = mb_stride; + pic->mb_width = pools->alloc_mb_width; + pic->mb_height = mb_height; + pic->mb_stride = pools->alloc_mb_stride; + + pic->qscale_table = pic->qscale_table_base + 2 * pic->mb_stride + 1; + pic->mb_type = pic->mb_type_base + 2 * pic->mb_stride + 1; return 0; } -/** - * Allocate a Picture. - * The pixels are allocated/set by calling get_buffer() if shared = 0 - */ -int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me, - ScratchpadContext *sc, int encoding, int out_format, - int mb_stride, int mb_width, int mb_height, int b8_stride, - ptrdiff_t *linesize, ptrdiff_t *uvlinesize) +int ff_mpv_alloc_pic_accessories(AVCodecContext *avctx, MPVWorkPicture *wpic, + ScratchpadContext *sc, + BufferPoolContext *pools, int mb_height) { - int i, ret; + MPVPicture *pic = wpic->ptr; + int ret; - if (pic->qscale_table_buf) - if ( pic->alloc_mb_width != mb_width - || pic->alloc_mb_height != mb_height) - free_picture_tables(pic); - - if (handle_pic_linesizes(avctx, pic, me, sc, - *linesize, *uvlinesize) < 0) - return -1; - - *linesize = pic->f->linesize[0]; - *uvlinesize = pic->f->linesize[1]; - - if (!pic->qscale_table_buf) - ret = alloc_picture_tables(avctx, pic, encoding, out_format, - mb_stride, mb_width, mb_height, b8_stride); - else - ret = make_tables_writable(pic); + ret = ff_mpv_framesize_alloc(avctx, sc, pic->f->linesize[0]); if (ret < 0) goto fail; - pic->mbskip_table = pic->mbskip_table_buf->data; - pic->qscale_table = pic->qscale_table_buf->data + 2 * mb_stride + 1; - pic->mb_type = (uint32_t*)pic->mb_type_buf->data + 2 * mb_stride + 1; + ret = alloc_picture_tables(pools, pic, mb_height); + if (ret < 0) + goto fail; - if (pic->motion_val_buf[0]) { - for (i = 0; i < 2; i++) { - pic->motion_val[i] = (int16_t (*)[2])pic->motion_val_buf[i]->data + 4; - pic->ref_index[i] = pic->ref_index_buf[i]->data; - } - } + set_workpic_from_pic(wpic, pic); return 0; fail: - av_log(avctx, AV_LOG_ERROR, "Error allocating a picture.\n"); - ff_mpeg_unref_picture(pic); - free_picture_tables(pic); - return AVERROR(ENOMEM); -} - -/** - * Deallocate a picture; frees the picture tables in case they - * need to be reallocated anyway. - */ -void ff_mpeg_unref_picture(Picture *pic) -{ - pic->tf.f = pic->f; - ff_thread_release_ext_buffer(&pic->tf); - - ff_refstruct_unref(&pic->hwaccel_picture_private); - - if (pic->needs_realloc) - free_picture_tables(pic); - - pic->field_picture = 0; - pic->b_frame_score = 0; - pic->needs_realloc = 0; - pic->reference = 0; - pic->shared = 0; - pic->display_picture_number = 0; - pic->coded_picture_number = 0; -} - -int ff_update_picture_tables(Picture *dst, const Picture *src) -{ - int i, ret; - - ret = av_buffer_replace(&dst->mbskip_table_buf, src->mbskip_table_buf); - ret |= av_buffer_replace(&dst->qscale_table_buf, src->qscale_table_buf); - ret |= av_buffer_replace(&dst->mb_type_buf, src->mb_type_buf); - for (i = 0; i < 2; i++) { - ret |= av_buffer_replace(&dst->motion_val_buf[i], src->motion_val_buf[i]); - ret |= av_buffer_replace(&dst->ref_index_buf[i], src->ref_index_buf[i]); - } - - if (ret < 0) { - free_picture_tables(dst); - return ret; - } - - dst->mbskip_table = src->mbskip_table; - dst->qscale_table = src->qscale_table; - dst->mb_type = src->mb_type; - for (i = 0; i < 2; i++) { - dst->motion_val[i] = src->motion_val[i]; - dst->ref_index[i] = src->ref_index[i]; - } - - dst->alloc_mb_width = src->alloc_mb_width; - dst->alloc_mb_height = src->alloc_mb_height; - dst->alloc_mb_stride = src->alloc_mb_stride; - - return 0; -} - -int ff_mpeg_ref_picture(Picture *dst, Picture *src) -{ - int ret; - - av_assert0(!dst->f->buf[0]); - av_assert0(src->f->buf[0]); - - src->tf.f = src->f; - dst->tf.f = dst->f; - ret = ff_thread_ref_frame(&dst->tf, &src->tf); - if (ret < 0) - goto fail; - - ret = ff_update_picture_tables(dst, src); - if (ret < 0) - goto fail; - - ff_refstruct_replace(&dst->hwaccel_picture_private, - src->hwaccel_picture_private); - - dst->field_picture = src->field_picture; - dst->b_frame_score = src->b_frame_score; - dst->needs_realloc = src->needs_realloc; - dst->reference = src->reference; - dst->shared = src->shared; - dst->display_picture_number = src->display_picture_number; - dst->coded_picture_number = src->coded_picture_number; - - return 0; -fail: - ff_mpeg_unref_picture(dst); + av_log(avctx, AV_LOG_ERROR, "Error allocating picture accessories.\n"); return ret; } - -static inline int pic_is_unused(Picture *pic) -{ - if (!pic->f->buf[0]) - return 1; - if (pic->needs_realloc) - return 1; - return 0; -} - -static int find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared) -{ - int i; - - if (shared) { - for (i = 0; i < MAX_PICTURE_COUNT; i++) { - if (!picture[i].f->buf[0]) - return i; - } - } else { - for (i = 0; i < MAX_PICTURE_COUNT; i++) { - if (pic_is_unused(&picture[i])) - return i; - } - } - - av_log(avctx, AV_LOG_FATAL, - "Internal error, picture buffer overflow\n"); - /* We could return -1, but the codec would crash trying to draw into a - * non-existing frame anyway. This is safer than waiting for a random crash. - * Also the return of this is never useful, an encoder must only allocate - * as much as allowed in the specification. This has no relationship to how - * much libavcodec could allocate (and MAX_PICTURE_COUNT is always large - * enough for such valid streams). - * Plus, a decoder has to check stream validity and remove frames if too - * many reference frames are around. Waiting for "OOM" is not correct at - * all. Similarly, missing reference frames have to be replaced by - * interpolated/MC frames, anything else is a bug in the codec ... - */ - abort(); - return -1; -} - -int ff_find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared) -{ - int ret = find_unused_picture(avctx, picture, shared); - - if (ret >= 0 && ret < MAX_PICTURE_COUNT) { - if (picture[ret].needs_realloc) { - ff_mpeg_unref_picture(&picture[ret]); - } - } - return ret; -} - -void av_cold ff_mpv_picture_free(Picture *pic) -{ - free_picture_tables(pic); - ff_mpeg_unref_picture(pic); - av_frame_free(&pic->f); -} diff --git a/libavcodec/mpegpicture.h b/libavcodec/mpegpicture.h index a457586be..196aa9b74 100644 --- a/libavcodec/mpegpicture.h +++ b/libavcodec/mpegpicture.h @@ -21,83 +21,132 @@ #ifndef AVCODEC_MPEGPICTURE_H #define AVCODEC_MPEGPICTURE_H +#include +#include #include -#include "libavutil/frame.h" - #include "avcodec.h" -#include "motion_est.h" -#include "threadframe.h" +#include "threadprogress.h" -#define MPEGVIDEO_MAX_PLANES 4 -#define MAX_PICTURE_COUNT 36 +#define MPV_MAX_PLANES 3 #define EDGE_WIDTH 16 typedef struct ScratchpadContext { uint8_t *edge_emu_buffer; ///< temporary buffer for if MVs point to out-of-frame data - uint8_t *rd_scratchpad; ///< scratchpad for rate distortion mb decision uint8_t *obmc_scratchpad; - uint8_t *b_scratchpad; ///< scratchpad used for writing into write only buffers + union { + uint8_t *scratchpad_buf; ///< the other *_scratchpad point into this buffer + uint8_t *rd_scratchpad; ///< scratchpad for rate distortion mb decision + }; + int linesize; ///< linesize that the buffers in this context have been allocated for } ScratchpadContext; -/** - * Picture. - */ -typedef struct Picture { - struct AVFrame *f; - ThreadFrame tf; +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; + 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 +} BufferPoolContext; - AVBufferRef *qscale_table_buf; +/** + * MPVPicture. + */ +typedef struct MPVPicture { + struct AVFrame *f; + + int8_t *qscale_table_base; int8_t *qscale_table; - AVBufferRef *motion_val_buf[2]; + int16_t (*motion_val_base[2])[2]; int16_t (*motion_val[2])[2]; - AVBufferRef *mb_type_buf; + uint32_t *mb_type_base; uint32_t *mb_type; ///< types and macros are defined in mpegutils.h - AVBufferRef *mbskip_table_buf; uint8_t *mbskip_table; - AVBufferRef *ref_index_buf[2]; int8_t *ref_index[2]; - 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 - /// RefStruct reference for hardware accelerator private data void *hwaccel_picture_private; + int mb_width; ///< mb_width of the tables + int mb_height; ///< mb_height of the tables + int mb_stride; ///< mb_stride of the tables + + int dummy; ///< Picture is a dummy and should not be output int field_picture; ///< whether or not the picture was encoded in separate fields int b_frame_score; - int needs_realloc; ///< Picture needs to be reallocated (eg due to a frame size change) int reference; int shared; int display_picture_number; int coded_picture_number; -} Picture; + + ThreadProgress progress; +} MPVPicture; + +typedef struct MPVWorkPicture { + uint8_t *data[MPV_MAX_PLANES]; + ptrdiff_t linesize[MPV_MAX_PLANES]; + + MPVPicture *ptr; ///< RefStruct reference + + int8_t *qscale_table; + + int16_t (*motion_val[2])[2]; + + uint32_t *mb_type; ///< types and macros are defined in mpegutils.h + + uint8_t *mbskip_table; + + int8_t *ref_index[2]; + + int reference; +} MPVWorkPicture; /** - * Allocate a Picture's accessories, but not the AVFrame's buffer itself. + * Allocate a pool of MPVPictures. */ -int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me, - ScratchpadContext *sc, int encoding, int out_format, - int mb_stride, int mb_width, int mb_height, int b8_stride, - ptrdiff_t *linesize, ptrdiff_t *uvlinesize); +struct FFRefStructPool *ff_mpv_alloc_pic_pool(int init_progress); -int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, - ScratchpadContext *sc, int linesize); +/** + * Allocate an MPVPicture's accessories (but not the AVFrame's buffer itself) + * and set the MPVWorkPicture's fields. + */ +int ff_mpv_alloc_pic_accessories(AVCodecContext *avctx, MPVWorkPicture *pic, + ScratchpadContext *sc, + BufferPoolContext *pools, int mb_height); -int ff_mpeg_ref_picture(Picture *dst, Picture *src); -void ff_mpeg_unref_picture(Picture *picture); +/** + * Check that the linesizes of an AVFrame are consistent with the requirements + * of mpegvideo. + * FIXME: There should be no need for this function. mpegvideo should be made + * to work with changing linesizes. + */ +int ff_mpv_pic_check_linesize(void *logctx, const struct AVFrame *f, + ptrdiff_t *linesizep, ptrdiff_t *uvlinesizep); -void ff_mpv_picture_free(Picture *pic); -int ff_update_picture_tables(Picture *dst, const Picture *src); +int ff_mpv_framesize_alloc(AVCodecContext *avctx, + ScratchpadContext *sc, int linesize); -int ff_find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared); +/** + * Disable allocating the ScratchpadContext's buffers in future calls + * to ff_mpv_framesize_alloc(). + */ +static inline void ff_mpv_framesize_disable(ScratchpadContext *sc) +{ + sc->linesize = INT_MAX; +} + +void ff_mpv_unref_picture(MPVWorkPicture *pic); +void ff_mpv_workpic_from_pic(MPVWorkPicture *wpic, MPVPicture *pic); +void ff_mpv_replace_picture(MPVWorkPicture *dst, const MPVWorkPicture *src); #endif /* AVCODEC_MPEGPICTURE_H */ diff --git a/libavcodec/mpegutils.c b/libavcodec/mpegutils.c index d94e8f422..73b6650b7 100644 --- a/libavcodec/mpegutils.c +++ b/libavcodec/mpegutils.c @@ -24,6 +24,7 @@ #include "libavutil/common.h" #include "libavutil/emms.h" #include "libavutil/frame.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/motion_vector.h" #include "libavutil/avassert.h" @@ -56,6 +57,7 @@ void ff_draw_horiz_band(AVCodecContext *avctx, int first_field, int low_delay) { const int field_pic = picture_structure != PICT_FRAME; + const AVPixFmtDescriptor *desc; const AVFrame *src; int offset[AV_NUM_DATA_POINTERS]; @@ -81,21 +83,13 @@ void ff_draw_horiz_band(AVCodecContext *avctx, else return; - if (cur->pict_type == AV_PICTURE_TYPE_B && - picture_structure == PICT_FRAME && - avctx->codec_id != AV_CODEC_ID_SVQ3) { - for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) - offset[i] = 0; - } else { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); - int vshift = desc->log2_chroma_h; + desc = av_pix_fmt_desc_get(avctx->pix_fmt); - offset[0] = y * src->linesize[0]; - offset[1] = - offset[2] = (y >> vshift) * src->linesize[1]; - for (int i = 3; i < AV_NUM_DATA_POINTERS; i++) - offset[i] = 0; - } + offset[0] = y * src->linesize[0]; + offset[1] = + offset[2] = (y >> desc->log2_chroma_h) * src->linesize[1]; + for (int i = 3; i < AV_NUM_DATA_POINTERS; i++) + offset[i] = 0; emms_c(); @@ -103,12 +97,14 @@ void ff_draw_horiz_band(AVCodecContext *avctx, y, picture_structure, h); } -static char get_type_mv_char(int mb_type) +#define HAS_MV_EXT(mb_type, flags, dir) ((mb_type) & flags[(dir)]) + +static char get_type_mv_char(int mb_type, const int mb_type_mv_flags[2]) { // Type & MV direction if (IS_PCM(mb_type)) return 'P'; - else if (IS_INTRA(mb_type) && IS_ACPRED(mb_type)) + else if (IS_ACPRED(mb_type)) return 'A'; else if (IS_INTRA4x4(mb_type)) return 'i'; @@ -124,12 +120,12 @@ static char get_type_mv_char(int mb_type) return 'G'; else if (IS_SKIP(mb_type)) return 'S'; - else if (!USES_LIST(mb_type, 1)) + else if (!HAS_MV_EXT(mb_type, 1, mb_type_mv_flags)) return '>'; - else if (!USES_LIST(mb_type, 0)) + else if (!HAS_MV_EXT(mb_type, 0, mb_type_mv_flags)) return '<'; else { - av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1)); + av_assert2(HAS_MV_EXT(mb_type, 0, mb_type_mv_flags) && HAS_MV_EXT(mb_type, 1, mb_type_mv_flags)); return 'X'; } } @@ -157,16 +153,19 @@ static char get_interlacement_char(int mb_type) } void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, - const uint8_t *mbskip_table, const uint32_t *mbtype_table, + const uint32_t *mbtype_table, const int8_t *qscale_table, int16_t (*const motion_val[2])[2], int mb_width, int mb_height, int mb_stride, int quarter_sample) { + const int is_h264 = avctx->codec_id == AV_CODEC_ID_H264; + const int mb_type_mv_flags[2] = { is_h264 ? MB_TYPE_L0 : MB_TYPE_FORWARD_MV, + is_h264 ? MB_TYPE_L1 : MB_TYPE_BACKWARD_MV }; + if ((avctx->export_side_data & AV_CODEC_EXPORT_DATA_MVS) && mbtype_table && motion_val[0]) { const int shift = 1 + quarter_sample; const int scale = 1 << shift; - const int mv_sample_log2 = avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_SVQ3 ? 2 : 1; - const int mv_stride = (mb_width << mv_sample_log2) + - (avctx->codec->id == AV_CODEC_ID_H264 ? 0 : 1); + const int mv_sample_log2 = is_h264 ? 2 : 1; + const int mv_stride = (mb_width << mv_sample_log2) + !is_h264; int mb_x, mb_y, mbcount = 0; /* size is width * height * 2 * 4 where 2 is for directions and 4 is @@ -179,7 +178,7 @@ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, for (mb_x = 0; mb_x < mb_width; mb_x++) { int i, direction, mb_type = mbtype_table[mb_x + mb_y * mb_stride]; for (direction = 0; direction < 2; direction++) { - if (!USES_LIST(mb_type, direction)) + if (!HAS_MV_EXT(mb_type, direction, mb_type_mv_flags)) continue; if (IS_8X8(mb_type)) { for (i = 0; i < 4; i++) { @@ -249,7 +248,7 @@ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, return; - if (avctx->debug & (FF_DEBUG_SKIP | FF_DEBUG_QP | FF_DEBUG_MB_TYPE)) { + if (avctx->debug & (FF_DEBUG_QP | FF_DEBUG_MB_TYPE)) { int x,y; AVBPrint buf; int n; @@ -268,8 +267,6 @@ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, av_bprint_chars(&buf, ' ', margin_left); n = 0; - if (avctx->debug & FF_DEBUG_SKIP) - n++; if (avctx->debug & FF_DEBUG_QP) n += 2; if (avctx->debug & FF_DEBUG_MB_TYPE) @@ -285,12 +282,6 @@ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, for (x = 0; x < mb_width; x++) { if (x == 0) av_bprintf(&buf, "%*d ", margin_left - 1, y << 4); - if (avctx->debug & FF_DEBUG_SKIP) { - int count = mbskip_table ? mbskip_table[x + y * mb_stride] : 0; - if (count > 9) - count = 9; - av_bprintf(&buf, "%1d", count); - } if (avctx->debug & FF_DEBUG_QP) { av_bprintf(&buf, "%2d", qscale_table[x + y * mb_stride]); } @@ -298,7 +289,7 @@ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, int mb_type = mbtype_table[x + y * mb_stride]; av_bprintf(&buf, "%c%c%c", - get_type_mv_char(mb_type), + get_type_mv_char(mb_type, mb_type_mv_flags), get_segmentation_char(mb_type), get_interlacement_char(mb_type)); } diff --git a/libavcodec/mpegutils.h b/libavcodec/mpegutils.h index 386110bb8..e4ce26d29 100644 --- a/libavcodec/mpegutils.h +++ b/libavcodec/mpegutils.h @@ -27,11 +27,6 @@ #include "avcodec.h" -/** - * Return value for header parsers if frame is not coded. - * */ -#define FRAME_SKIPPED 100 - /* picture type */ #define PICT_TOP_FIELD 1 #define PICT_BOTTOM_FIELD 2 @@ -50,9 +45,12 @@ #define MB_TYPE_8x8 (1 << 6) #define MB_TYPE_INTERLACED (1 << 7) #define MB_TYPE_DIRECT2 (1 << 8) // FIXME -#define MB_TYPE_ACPRED (1 << 9) -#define MB_TYPE_GMC (1 << 10) -#define MB_TYPE_SKIP (1 << 11) +#define MB_TYPE_CBP (1 << 10) +#define MB_TYPE_QUANT (1 << 11) +#define MB_TYPE_FORWARD_MV (1 << 12) +#define MB_TYPE_BACKWARD_MV (1 << 13) +#define MB_TYPE_BIDIR_MV (MB_TYPE_FORWARD_MV | MB_TYPE_BACKWARD_MV) +// MB_TYPE_P[01]L[01], MB_TYPE_L[01] and MB_TYPE_L0L1 are H.264 only. #define MB_TYPE_P0L0 (1 << 12) #define MB_TYPE_P1L0 (1 << 13) #define MB_TYPE_P0L1 (1 << 14) @@ -60,11 +58,15 @@ #define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0) #define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1) #define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) -#define MB_TYPE_QUANT (1 << 16) -#define MB_TYPE_CBP (1 << 17) +#define MB_TYPE_GMC (1 << 16) +#define MB_TYPE_SKIP (1 << 17) +#define MB_TYPE_ACPRED (1 << 18) #define MB_TYPE_INTRA MB_TYPE_INTRA4x4 // default mb_type if there is just one type +// The following MB-type can be used by each codec as it sees fit. +#define MB_TYPE_CODEC_SPECIFIC (1 << 9) + #define IS_INTRA4x4(a) ((a) & MB_TYPE_INTRA4x4) #define IS_INTRA16x16(a) ((a) & MB_TYPE_INTRA16x16) #define IS_PCM(a) ((a) & MB_TYPE_INTRA_PCM) @@ -80,47 +82,16 @@ #define IS_16X8(a) ((a) & MB_TYPE_16x8) #define IS_8X16(a) ((a) & MB_TYPE_8x16) #define IS_8X8(a) ((a) & MB_TYPE_8x8) -#define IS_SUB_8X8(a) ((a) & MB_TYPE_16x16) // note reused -#define IS_SUB_8X4(a) ((a) & MB_TYPE_16x8) // note reused -#define IS_SUB_4X8(a) ((a) & MB_TYPE_8x16) // note reused -#define IS_SUB_4X4(a) ((a) & MB_TYPE_8x8) // note reused #define IS_ACPRED(a) ((a) & MB_TYPE_ACPRED) #define IS_QUANT(a) ((a) & MB_TYPE_QUANT) -#define IS_DIR(a, part, list) ((a) & (MB_TYPE_P0L0 << ((part) + 2 * (list)))) - -// does this mb use listX, note does not work if subMBs -#define USES_LIST(a, list) ((a) & ((MB_TYPE_P0L0 | MB_TYPE_P1L0) << (2 * (list)))) #define HAS_CBP(a) ((a) & MB_TYPE_CBP) +#define HAS_FORWARD_MV(a) ((a) & MB_TYPE_FORWARD_MV) +#define HAS_BACKWARD_MV(a) ((a) & MB_TYPE_BACKWARD_MV) +// dir == 0 means forward, dir == 1 is backward +#define HAS_MV(a, dir) ((a) & (MB_TYPE_FORWARD_MV << (dir))) -/* MB types for encoding */ -#define CANDIDATE_MB_TYPE_INTRA (1 << 0) -#define CANDIDATE_MB_TYPE_INTER (1 << 1) -#define CANDIDATE_MB_TYPE_INTER4V (1 << 2) -#define CANDIDATE_MB_TYPE_SKIPPED (1 << 3) - -#define CANDIDATE_MB_TYPE_DIRECT (1 << 4) -#define CANDIDATE_MB_TYPE_FORWARD (1 << 5) -#define CANDIDATE_MB_TYPE_BACKWARD (1 << 6) -#define CANDIDATE_MB_TYPE_BIDIR (1 << 7) - -#define CANDIDATE_MB_TYPE_INTER_I (1 << 8) -#define CANDIDATE_MB_TYPE_FORWARD_I (1 << 9) -#define CANDIDATE_MB_TYPE_BACKWARD_I (1 << 10) -#define CANDIDATE_MB_TYPE_BIDIR_I (1 << 11) - -#define CANDIDATE_MB_TYPE_DIRECT0 (1 << 12) - -#define INPLACE_OFFSET 16 - -enum OutputFormat { - FMT_MPEG1, - FMT_H261, - FMT_H263, - FMT_MJPEG, - FMT_SPEEDHQ, -}; - +#define MB_TYPE_MV_2_MV_DIR(a) (((a) >> 12) & (MV_DIR_FORWARD | MV_DIR_BACKWARD)) /** * Draw a horizontal band if supported. @@ -135,7 +106,7 @@ void ff_draw_horiz_band(AVCodecContext *avctx, const AVFrame *cur, const AVFrame * Print debugging info for the given picture. */ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, - const uint8_t *mbskip_table, const uint32_t *mbtype_table, + const uint32_t *mbtype_table, const int8_t *qscale_table, int16_t (*const motion_val[2])[2], int mb_width, int mb_height, int mb_stride, int quarter_sample); diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 81796e42b..01e310e48 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/mem.h" #include "avcodec.h" #include "blockdsp.h" @@ -40,6 +41,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) @@ -108,8 +110,7 @@ static void dct_unquantize_mpeg2_intra_c(MpegEncContext *s, if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; else qscale <<= 1; - if(s->alternate_scan) nCoeffs= 63; - else nCoeffs= s->block_last_index[n]; + nCoeffs= s->block_last_index[n]; block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; quant_matrix = s->intra_matrix; @@ -139,8 +140,7 @@ static void dct_unquantize_mpeg2_intra_bitexact(MpegEncContext *s, if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; else qscale <<= 1; - if(s->alternate_scan) nCoeffs= 63; - else nCoeffs= s->block_last_index[n]; + nCoeffs= s->block_last_index[n]; block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; sum += block[0]; @@ -173,8 +173,7 @@ static void dct_unquantize_mpeg2_inter_c(MpegEncContext *s, if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; else qscale <<= 1; - if(s->alternate_scan) nCoeffs= 63; - else nCoeffs= s->block_last_index[n]; + nCoeffs= s->block_last_index[n]; quant_matrix = s->inter_matrix; for(i=0; i<=nCoeffs; i++) { @@ -271,7 +270,7 @@ static void gray8(uint8_t *dst, const uint8_t *src, ptrdiff_t linesize, int h) } /* init common dct for both encoder and decoder */ -static av_cold int dct_init(MpegEncContext *s) +static av_cold void dsp_init(MpegEncContext *s) { ff_blockdsp_init(&s->bdsp); ff_hpeldsp_init(&s->hdsp, s->avctx->flags); @@ -289,52 +288,18 @@ static av_cold int dct_init(MpegEncContext *s) s->hdsp.put_no_rnd_pixels_tab[1][i] = gray8; } } - - 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_ALPHA - ff_mpv_common_init_axp(s); -#elif 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 - - return 0; } av_cold void ff_init_scantable(const uint8_t *permutation, ScanTable *st, const uint8_t *src_scantable) { - int end; - st->scantable = src_scantable; - for (int i = 0; i < 64; i++) { + for (int i = 0, end = -1; i < 64; i++) { int j = src_scantable[i]; st->permutated[i] = permutation[j]; - } - - end = -1; - for (int i = 0; i < 64; i++) { - int j = st->permutated[i]; - if (j > end) - end = j; + if (permutation[j] > end) + end = permutation[j]; st->raster_end[i] = end; } } @@ -359,18 +324,33 @@ av_cold void ff_mpv_idct_init(MpegEncContext *s) 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) { - int y_size = s->b8_stride * (2 * s->mb_height + 1); - int c_size = s->mb_stride * (s->mb_height + 1); - int yc_size = y_size + 2 * c_size; - int i; - - if (s->mb_height & 1) - yc_size += 2*s->b8_stride + 2*s->mb_stride; - if (s->encoding) { s->me.map = av_mallocz(2 * ME_MAP_SIZE * sizeof(*s->me.map)); if (!s->me.map) @@ -386,16 +366,12 @@ static int init_duplicate_context(MpegEncContext *s) return AVERROR(ENOMEM); s->block = s->blocks[0]; - for (i = 0; i < 12; i++) { - s->pblocks[i] = &s->block[i]; - } - - if (s->avctx->codec_tag == AV_RL32("VCR2")) { - // exchange uv - FFSWAP(void *, s->pblocks[4], s->pblocks[5]); - } - 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); @@ -437,11 +413,10 @@ static void free_duplicate_context(MpegEncContext *s) return; av_freep(&s->sc.edge_emu_buffer); - av_freep(&s->me.scratchpad); - s->me.temp = - s->sc.rd_scratchpad = - s->sc.b_scratchpad = + 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); @@ -463,12 +438,7 @@ static void free_duplicate_contexts(MpegEncContext *s) static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) { #define COPY(a) bak->a = src->a - COPY(sc.edge_emu_buffer); - COPY(me.scratchpad); - COPY(me.temp); - COPY(sc.rd_scratchpad); - COPY(sc.b_scratchpad); - COPY(sc.obmc_scratchpad); + COPY(sc); COPY(me.map); COPY(me.score_map); COPY(blocks); @@ -476,7 +446,6 @@ static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) COPY(start_mb_y); COPY(end_mb_y); COPY(me.map_generation); - COPY(pb); COPY(dct_error_sum); COPY(dct_count[0]); COPY(dct_count[1]); @@ -490,21 +459,14 @@ static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) int ff_update_duplicate_context(MpegEncContext *dst, const MpegEncContext *src) { MpegEncContext bak; - int i, ret; + int ret; // FIXME copy only needed parts backup_duplicate_context(&bak, dst); memcpy(dst, src, sizeof(MpegEncContext)); backup_duplicate_context(dst, &bak); - for (i = 0; i < 12; i++) { - dst->pblocks[i] = &dst->block[i]; - } - if (dst->avctx->codec_tag == AV_RL32("VCR2")) { - // exchange uv - FFSWAP(void *, dst->pblocks[4], dst->pblocks[5]); - } - if (!dst->sc.edge_emu_buffer && - (ret = ff_mpeg_framesize_alloc(dst->avctx, &dst->me, - &dst->sc, dst->linesize)) < 0) { + + ret = ff_mpv_framesize_alloc(dst->avctx, &dst->sc, dst->linesize); + if (ret < 0) { av_log(dst->avctx, AV_LOG_ERROR, "failed to allocate context " "scratch buffers.\n"); return ret; @@ -527,7 +489,6 @@ void ff_mpv_common_defaults(MpegEncContext *s) s->progressive_sequence = 1; s->picture_structure = PICT_FRAME; - s->coded_picture_number = 0; s->picture_number = 0; s->f_code = 1; @@ -536,20 +497,38 @@ void ff_mpv_common_defaults(MpegEncContext *s) s->slice_context_count = 1; } +static 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); + pools->alloc_mb_height = pools->alloc_mb_width = pools->alloc_mb_stride = 0; +} + int ff_mpv_init_context_frame(MpegEncContext *s) { + BufferPoolContext *const pools = &s->buffer_pools; int y_size, c_size, yc_size, i, mb_array_size, mv_table_size, x, y; + int mb_height; 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; + /* 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. */ + mb_height = s->msmpeg4_version == MSMP4_VC1 ? + FFALIGN(s->mb_height, 2) : s->mb_height; + s->mb_width = (s->width + 15) / 16; s->mb_stride = s->mb_width + 1; s->b8_stride = s->mb_width * 2 + 1; - mb_array_size = s->mb_height * s->mb_stride; - mv_table_size = (s->mb_height + 2) * s->mb_stride + 1; + mb_array_size = mb_height * s->mb_stride; + mv_table_size = (mb_height + 2) * s->mb_stride + 1; /* set default edge pos, will be overridden * in decode_header if needed */ @@ -565,13 +544,10 @@ int ff_mpv_init_context_frame(MpegEncContext *s) s->block_wrap[4] = s->block_wrap[5] = s->mb_stride; - y_size = s->b8_stride * (2 * s->mb_height + 1); - c_size = s->mb_stride * (s->mb_height + 1); + y_size = s->b8_stride * (2 * mb_height + 1); + c_size = s->mb_stride * (mb_height + 1); yc_size = y_size + 2 * c_size; - if (s->mb_height & 1) - yc_size += 2*s->b8_stride + 2*s->mb_stride; - if (!FF_ALLOCZ_TYPED_ARRAY(s->mb_index2xy, s->mb_num + 1)) return AVERROR(ENOMEM); for (y = 0; y < s->mb_height; y++) @@ -580,6 +556,12 @@ 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)); \ + if (!pools->name ##_pool) \ + return AVERROR(ENOMEM); \ +} while (0) + if (s->codec_id == AV_CODEC_ID_MPEG4 || (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME)) { /* interlaced direct mode decoding tables */ @@ -594,13 +576,21 @@ int ff_mpv_init_context_frame(MpegEncContext *s) tmp += mv_table_size; } } + 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); + if (!s->encoding) { + /* cbp, pred_dir */ + if (!(s->cbp_table = av_mallocz(mb_array_size)) || + !(s->pred_dir_table = av_mallocz(mb_array_size))) + return AVERROR(ENOMEM); + } + } } - if (s->out_format == FMT_H263) { - /* cbp values, cbp, ac_pred, pred_dir */ - if (!(s->coded_block_base = av_mallocz(y_size + (s->mb_height&1)*2*s->b8_stride)) || - !(s->cbp_table = av_mallocz(mb_array_size)) || - !(s->pred_dir_table = av_mallocz(mb_array_size))) + if (s->msmpeg4_version >= MSMP4_V3) { + s->coded_block_base = av_mallocz(y_size); + if (!s->coded_block_base) return AVERROR(ENOMEM); s->coded_block = s->coded_block_base + s->b8_stride + 1; } @@ -624,14 +614,35 @@ int ff_mpv_init_context_frame(MpegEncContext *s) 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); + + if (s->out_format == FMT_H263 || s->encoding || + (s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_MVS)) { + const int b8_array_size = s->b8_stride * mb_height * 2; + int mv_size = 2 * (b8_array_size + 4) * sizeof(int16_t); + int ref_index_size = 4 * mb_array_size; + + /* 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(ref_index, ref_index_size, 0); + } +#undef ALLOC_POOL + pools->alloc_mb_width = s->mb_width; + pools->alloc_mb_height = mb_height; + pools->alloc_mb_stride = s->mb_stride; + return !CONFIG_MPEGVIDEODEC || s->encoding ? 0 : ff_mpeg_er_init(s); } static void clear_context(MpegEncContext *s) { - memset(&s->next_picture, 0, sizeof(s->next_picture)); - memset(&s->last_picture, 0, sizeof(s->last_picture)); - memset(&s->current_picture, 0, sizeof(s->current_picture)); + 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)); @@ -640,22 +651,17 @@ static void clear_context(MpegEncContext *s) s->dct_error_sum = NULL; s->block = NULL; s->blocks = NULL; - memset(s->pblocks, 0, sizeof(s->pblocks)); s->ac_val_base = NULL; s->ac_val[0] = s->ac_val[1] = s->ac_val[2] =NULL; - s->sc.edge_emu_buffer = NULL; s->me.scratchpad = NULL; - s->me.temp = - s->sc.rd_scratchpad = - s->sc.b_scratchpad = - s->sc.obmc_scratchpad = NULL; + s->me.temp = NULL; + memset(&s->sc, 0, sizeof(s->sc)); s->bitstream_buffer = NULL; s->allocated_bitstream_buffer_size = 0; - s->picture = NULL; s->p_field_mv_table_base = NULL; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) @@ -680,10 +686,10 @@ static void clear_context(MpegEncContext *s) */ av_cold int ff_mpv_common_init(MpegEncContext *s) { - int i, ret; int nb_slices = (HAVE_THREADS && s->avctx->active_thread_type & FF_THREAD_SLICE) ? s->avctx->thread_count : 1; + int ret; clear_context(s); @@ -700,7 +706,7 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) av_image_check_size(s->width, s->height, 0, s->avctx)) return AVERROR(EINVAL); - dct_init(s); + dsp_init(s); /* set chroma shifts */ ret = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, @@ -709,19 +715,6 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) if (ret) return ret; - if (!FF_ALLOCZ_TYPED_ARRAY(s->picture, MAX_PICTURE_COUNT)) - return AVERROR(ENOMEM); - for (i = 0; i < MAX_PICTURE_COUNT; i++) { - s->picture[i].f = av_frame_alloc(); - if (!s->picture[i].f) - goto fail_nomem; - } - - if (!(s->next_picture.f = av_frame_alloc()) || - !(s->last_picture.f = av_frame_alloc()) || - !(s->current_picture.f = av_frame_alloc())) - goto fail_nomem; - if ((ret = ff_mpv_init_context_frame(s))) goto fail; @@ -748,8 +741,6 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) // } return 0; - fail_nomem: - ret = AVERROR(ENOMEM); fail: ff_mpv_common_end(s); return ret; @@ -759,6 +750,7 @@ void ff_mpv_free_context_frame(MpegEncContext *s) { free_duplicate_contexts(s); + free_buffer_pools(&s->buffer_pools); av_freep(&s->p_field_mv_table_base); for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) @@ -788,29 +780,18 @@ void ff_mpv_common_end(MpegEncContext *s) av_freep(&s->bitstream_buffer); s->allocated_bitstream_buffer_size = 0; - if (!s->avctx) - return; - - if (s->picture) { - for (int i = 0; i < MAX_PICTURE_COUNT; i++) - ff_mpv_picture_free(&s->picture[i]); - } - av_freep(&s->picture); - ff_mpv_picture_free(&s->last_picture); - ff_mpv_picture_free(&s->current_picture); - ff_mpv_picture_free(&s->next_picture); + ff_mpv_unref_picture(&s->last_pic); + ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&s->next_pic); s->context_initialized = 0; s->context_reinit = 0; - s->last_picture_ptr = - s->next_picture_ptr = - s->current_picture_ptr = NULL; s->linesize = s->uvlinesize = 0; } /** - * Clean dc, ac, coded_block for the current non-intra MB. + * Clean dc, ac for the current non-intra MB. */ void ff_clean_intra_table_entries(MpegEncContext *s) { @@ -824,12 +805,6 @@ void ff_clean_intra_table_entries(MpegEncContext *s) /* 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)); - if (s->msmpeg4_version>=3) { - s->coded_block[xy ] = - s->coded_block[xy + 1 ] = - s->coded_block[xy + wrap] = - s->coded_block[xy + 1 + wrap] = 0; - } /* chroma */ wrap = s->mb_stride; xy = s->mb_x + s->mb_y * wrap; @@ -843,8 +818,8 @@ void ff_clean_intra_table_entries(MpegEncContext *s) } void ff_init_block_index(MpegEncContext *s){ //FIXME maybe rename - const int linesize = s->current_picture.f->linesize[0]; //not s->linesize as this would be wrong for field pics - const int uvlinesize = s->current_picture.f->linesize[1]; + 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 width_of_mb = (4 + (s->avctx->bits_per_raw_sample > 8)) - s->avctx->lowres; const int height_of_mb = 4 - s->avctx->lowres; @@ -856,9 +831,9 @@ void ff_init_block_index(MpegEncContext *s){ //FIXME maybe rename s->block_index[5]= s->mb_stride*(s->mb_y + s->mb_height + 2) + s->b8_stride*s->mb_height*2 + s->mb_x - 1; //block_index is not used by mpeg2, so it is not affected by chroma_format - s->dest[0] = s->current_picture.f->data[0] + (int)((s->mb_x - 1U) << width_of_mb); - s->dest[1] = s->current_picture.f->data[1] + (int)((s->mb_x - 1U) << (width_of_mb - s->chroma_x_shift)); - s->dest[2] = s->current_picture.f->data[2] + (int)((s->mb_x - 1U) << (width_of_mb - s->chroma_x_shift)); + s->dest[0] = s->cur_pic.data[0] + (int)((s->mb_x - 1U) << width_of_mb); + s->dest[1] = s->cur_pic.data[1] + (int)((s->mb_x - 1U) << (width_of_mb - s->chroma_x_shift)); + s->dest[2] = s->cur_pic.data[2] + (int)((s->mb_x - 1U) << (width_of_mb - s->chroma_x_shift)); if (s->picture_structure == PICT_FRAME) { s->dest[0] += s->mb_y * linesize << height_of_mb; diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index d7c2f5768..8083299b6 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -28,7 +28,6 @@ #ifndef AVCODEC_MPEGVIDEO_H #define AVCODEC_MPEGVIDEO_H -#include "avcodec.h" #include "blockdsp.h" #include "error_resilience.h" #include "fdctdsp.h" @@ -44,7 +43,6 @@ #include "pixblockdsp.h" #include "put_bits.h" #include "ratecontrol.h" -#include "mpegutils.h" #include "qpeldsp.h" #include "videodsp.h" @@ -61,6 +59,14 @@ typedef struct ScanTable { uint8_t raster_end[64]; } ScanTable; +enum OutputFormat { + FMT_MPEG1, + FMT_H261, + FMT_H263, + FMT_MJPEG, + FMT_SPEEDHQ, +}; + /** * MpegEncContext. */ @@ -122,9 +128,11 @@ 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 - Picture *picture; ///< main picture buffer - Picture **input_picture; ///< next pictures on display order for encoding - Picture **reordered_input_picture; ///< pointer to the next pictures in coded order for encoding + 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 + + BufferPoolContext buffer_pools; int64_t user_specified_pts; ///< last non-zero pts from AVFrame which was passed into avcodec_send_frame() /** @@ -148,29 +156,26 @@ typedef struct MpegEncContext { * copy of the previous picture structure. * note, linesize & data, might not match the previous picture (for field pictures) */ - Picture last_picture; + MPVWorkPicture last_pic; /** * copy of the next picture structure. * note, linesize & data, might not match the next picture (for field pictures) */ - Picture next_picture; + MPVWorkPicture next_pic; /** * Reference to the source picture for encoding. * note, linesize & data, might not match the source picture (for field pictures) */ - AVFrame *new_picture; + AVFrame *new_pic; /** * copy of the current picture structure. * note, linesize & data, might not match the current picture (for field pictures) */ - Picture current_picture; ///< buffer to store the decompressed current picture + MPVWorkPicture cur_pic; - Picture *last_picture_ptr; ///< pointer to the previous picture. - Picture *next_picture_ptr; ///< pointer to the next picture (for bidir pred) - Picture *current_picture_ptr; ///< pointer to the current picture int skipped_last_frame; int last_dc[3]; ///< last DC values for MPEG-1 int16_t *dc_val_base; @@ -215,7 +220,6 @@ typedef struct MpegEncContext { H264ChromaContext h264chroma; HpelDSPContext hdsp; IDCTDSPContext idsp; - MECmpContext mecc; MpegvideoEncDSPContext mpvencdsp; PixblockDSPContext pdsp; QpelDSPContext qdsp; @@ -248,7 +252,7 @@ typedef struct MpegEncContext { 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[MPEGVIDEO_MAX_PLANES]; + uint64_t encoding_error[MPV_MAX_PLANES]; int motion_est; ///< ME algorithm int me_penalty_compensation; @@ -283,7 +287,7 @@ typedef struct MpegEncContext { 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 mpegutils.h) + 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]; @@ -339,7 +343,6 @@ typedef struct MpegEncContext { int i_tex_bits; int p_tex_bits; int i_count; - int skip_count; int misc_bits; ///< cbp, mb_type int last_bits; ///< temp var used for calculating the above vars @@ -381,7 +384,6 @@ typedef struct MpegEncContext { uint16_t pp_field_time; uint16_t pb_field_time; ///< like above, just for interlaced int mcsel; - int quant_precision; 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 @@ -414,7 +416,15 @@ typedef struct MpegEncContext { int slice_height; ///< in macroblocks int first_slice_line; ///< used in MPEG-4 too to handle resync markers int flipflop_rounding; - int msmpeg4_version; ///< 0=not msmpeg4, 1=mp41, 2=mp42, 3=mp43/divx3 4=wmv1/7 5=wmv2/8 + enum { + MSMP4_UNUSED, + MSMP4_V1, + MSMP4_V2, + MSMP4_V3, + MSMP4_WMV1, + 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; @@ -462,7 +472,6 @@ typedef struct MpegEncContext { int rtp_payload_size; uint8_t *ptr_lastgob; - int16_t (*pblocks[12])[64]; 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 @@ -490,12 +499,17 @@ typedef struct MpegEncContext { void (*dct_unquantize_inter)(struct MpegEncContext *s, // unquantizer to use (MPEG-4 can use both) int16_t *block/*align 16*/, int n, int qscale); int (*dct_quantize)(struct MpegEncContext *s, int16_t *block/*align 16*/, int n, int qscale, int *overflow); - int (*fast_dct_quantize)(struct MpegEncContext *s, int16_t *block/*align 16*/, int n, int qscale, int *overflow); void (*denoise_dct)(struct MpegEncContext *s, int16_t *block); int mpv_flags; ///< flags set by private options int quantizer_noise_shaping; + 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); + /** * ratecontrol qmin qmax limiting method * 0-> clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax. @@ -532,6 +546,7 @@ typedef struct MpegEncContext { 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; @@ -588,8 +603,8 @@ void ff_mpv_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int dir, uint8_t *const *ref_picture, - op_pixels_func (*pix_op)[4], - qpel_mc_func (*qpix_op)[16]); + const op_pixels_func (*pix_op)[4], + const qpel_mc_func (*qpix_op)[16]); static inline void ff_update_block_index(MpegEncContext *s, int bits_per_raw_sample, int lowres, int chroma_x_shift) diff --git a/libavcodec/mpegvideo_dec.c b/libavcodec/mpegvideo_dec.c index 88facfc39..1cab10893 100644 --- a/libavcodec/mpegvideo_dec.c +++ b/libavcodec/mpegvideo_dec.c @@ -38,12 +38,15 @@ #include "mpegvideo.h" #include "mpegvideodec.h" #include "mpeg4videodec.h" +#include "refstruct.h" #include "thread.h" -#include "threadframe.h" +#include "threadprogress.h" #include "wmv2dec.h" -void ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) +int ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) { + enum ThreadingStatus thread_status; + ff_mpv_common_defaults(s); s->avctx = avctx; @@ -56,7 +59,19 @@ void ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) s->codec_tag = ff_toupper4(avctx->codec_tag); ff_mpv_idct_init(s); + ff_h264chroma_init(&s->h264chroma, 8); //for lowres + + if (s->picture_pool) // VC-1 can call this multiple times + return 0; + + thread_status = ff_thread_sync_ref(avctx, offsetof(MpegEncContext, picture_pool)); + if (thread_status != FF_THREAD_IS_COPY) { + s->picture_pool = ff_mpv_alloc_pic_pool(thread_status != FF_THREAD_NO_FRAME_THREADING); + if (!s->picture_pool) + return AVERROR(ENOMEM); + } + return 0; } int ff_mpeg_update_thread_context(AVCodecContext *dst, @@ -100,41 +115,14 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, s->quarter_sample = s1->quarter_sample; - s->coded_picture_number = s1->coded_picture_number; s->picture_number = s1->picture_number; - av_assert0(!s->picture || s->picture != s1->picture); - if (s->picture) - for (int i = 0; i < MAX_PICTURE_COUNT; i++) { - ff_mpeg_unref_picture(&s->picture[i]); - if (s1->picture && s1->picture[i].f->buf[0] && - (ret = ff_mpeg_ref_picture(&s->picture[i], &s1->picture[i])) < 0) - return ret; - } + 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); -#define UPDATE_PICTURE(pic)\ -do {\ - ff_mpeg_unref_picture(&s->pic);\ - if (s1->pic.f && s1->pic.f->buf[0])\ - ret = ff_mpeg_ref_picture(&s->pic, &s1->pic);\ - else\ - ret = ff_update_picture_tables(&s->pic, &s1->pic);\ - if (ret < 0)\ - return ret;\ -} while (0) - - UPDATE_PICTURE(current_picture); - UPDATE_PICTURE(last_picture); - UPDATE_PICTURE(next_picture); - -#define REBASE_PICTURE(pic, new_ctx, old_ctx) \ - ((pic && pic >= old_ctx->picture && \ - pic < old_ctx->picture + MAX_PICTURE_COUNT) ? \ - &new_ctx->picture[pic - old_ctx->picture] : NULL) - - s->last_picture_ptr = REBASE_PICTURE(s1->last_picture_ptr, s, s1); - s->current_picture_ptr = REBASE_PICTURE(s1->current_picture_ptr, s, s1); - s->next_picture_ptr = REBASE_PICTURE(s1->next_picture_ptr, s, s1); + s->linesize = s1->linesize; + s->uvlinesize = s1->uvlinesize; // Error/bug resilience s->workaround_bugs = s1->workaround_bugs; @@ -148,7 +136,6 @@ do {\ // B-frame info s->max_b_frames = s1->max_b_frames; s->low_delay = s1->low_delay; - s->droppable = s1->droppable; // DivX handling (doesn't work) s->divx_packed = s1->divx_packed; @@ -166,20 +153,6 @@ do {\ s1->bitstream_buffer_size); } - // linesize-dependent scratch buffer allocation - if (!s->sc.edge_emu_buffer) - if (s1->linesize) { - if (ff_mpeg_framesize_alloc(s->avctx, &s->me, - &s->sc, s1->linesize) < 0) { - av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate context " - "scratch buffers.\n"); - return AVERROR(ENOMEM); - } - } else { - av_log(s->avctx, AV_LOG_ERROR, "Context scratch buffers could not " - "be allocated due to unknown size.\n"); - } - // MPEG-2/interlacing info memcpy(&s->progressive_sequence, &s1->progressive_sequence, (char *) &s1->rtp_mode - (char *) &s1->progressive_sequence); @@ -187,6 +160,15 @@ do {\ return 0; } +int ff_mpv_decode_close(AVCodecContext *avctx) +{ + MpegEncContext *s = avctx->priv_data; + + ff_refstruct_pool_uninit(&s->picture_pool); + ff_mpv_common_end(s); + return 0; +} + int ff_mpv_common_frame_size_change(MpegEncContext *s) { int err = 0; @@ -196,13 +178,9 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s) ff_mpv_free_context_frame(s); - if (s->picture) - for (int i = 0; i < MAX_PICTURE_COUNT; i++) - s->picture[i].needs_realloc = 1; - - s->last_picture_ptr = - s->next_picture_ptr = - s->current_picture_ptr = NULL; + ff_mpv_unref_picture(&s->last_pic); + ff_mpv_unref_picture(&s->next_pic); + ff_mpv_unref_picture(&s->cur_pic); if ((s->width || s->height) && (err = av_image_check_size(s->width, s->height, 0, s->avctx)) < 0) @@ -235,20 +213,26 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s) return err; } -static int alloc_picture(MpegEncContext *s, Picture *pic) +static int alloc_picture(MpegEncContext *s, MPVWorkPicture *dst, int reference) { AVCodecContext *avctx = s->avctx; + MPVPicture *pic = ff_refstruct_pool_get(s->picture_pool); int ret; - pic->tf.f = pic->f; + if (!pic) + return AVERROR(ENOMEM); + + dst->ptr = pic; + + pic->reference = reference; /* WM Image / Screen codecs allocate internal buffers with different * dimensions / colorspaces; ignore user-defined callbacks for these. */ if (avctx->codec_id != AV_CODEC_ID_WMV3IMAGE && avctx->codec_id != AV_CODEC_ID_VC1IMAGE && avctx->codec_id != AV_CODEC_ID_MSS2) { - ret = ff_thread_get_ext_buffer(avctx, &pic->tf, - pic->reference ? AV_GET_BUFFER_FLAG_REF : 0); + ret = ff_thread_get_buffer(avctx, pic->f, + reference ? AV_GET_BUFFER_FLAG_REF : 0); } else { pic->f->width = avctx->width; pic->f->height = avctx->height; @@ -258,18 +242,44 @@ static int alloc_picture(MpegEncContext *s, Picture *pic) if (ret < 0) goto fail; + ret = ff_mpv_pic_check_linesize(avctx, pic->f, &s->linesize, &s->uvlinesize); + if (ret < 0) + goto fail; + ret = ff_hwaccel_frame_priv_alloc(avctx, &pic->hwaccel_picture_private); if (ret < 0) goto fail; - return ff_alloc_picture(s->avctx, pic, &s->me, &s->sc, 0, s->out_format, - s->mb_stride, s->mb_width, s->mb_height, s->b8_stride, - &s->linesize, &s->uvlinesize); + av_assert1(s->mb_width == s->buffer_pools.alloc_mb_width); + av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height || + FFALIGN(s->mb_height, 2) == 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, dst, &s->sc, + &s->buffer_pools, s->mb_height); + if (ret < 0) + goto fail; + + return 0; fail: - ff_mpeg_unref_picture(pic); + ff_mpv_unref_picture(dst); return ret; } +static int av_cold alloc_dummy_frame(MpegEncContext *s, MPVWorkPicture *dst) +{ + MPVPicture *pic; + int ret = alloc_picture(s, dst, 1); + if (ret < 0) + return ret; + + pic = dst->ptr; + pic->dummy = 1; + + ff_thread_progress_report(&pic->progress, INT_MAX); + + return 0; +} + static void color_frame(AVFrame *frame, int luma) { int h_chroma_shift, v_chroma_shift; @@ -288,200 +298,95 @@ static void color_frame(AVFrame *frame, int luma) } } +int ff_mpv_alloc_dummy_frames(MpegEncContext *s) +{ + AVCodecContext *avctx = s->avctx; + int ret; + + av_assert1(!s->last_pic.ptr || s->last_pic.ptr->f->buf[0]); + av_assert1(!s->next_pic.ptr || s->next_pic.ptr->f->buf[0]); + if (!s->last_pic.ptr && s->pict_type != AV_PICTURE_TYPE_I) { + if (s->pict_type == AV_PICTURE_TYPE_B && s->next_pic.ptr) + av_log(avctx, AV_LOG_DEBUG, + "allocating dummy last picture for B frame\n"); + else if (s->codec_id != AV_CODEC_ID_H261 /* H.261 has no keyframes */ && + (s->picture_structure == PICT_FRAME || s->first_field)) + av_log(avctx, AV_LOG_ERROR, + "warning: first frame is no keyframe\n"); + + /* Allocate a dummy frame */ + ret = alloc_dummy_frame(s, &s->last_pic); + if (ret < 0) + return ret; + + if (!avctx->hwaccel) { + int luma_val = s->codec_id == AV_CODEC_ID_FLV1 || s->codec_id == AV_CODEC_ID_H263 ? 16 : 0x80; + color_frame(s->last_pic.ptr->f, luma_val); + } + } + if (!s->next_pic.ptr && s->pict_type == AV_PICTURE_TYPE_B) { + /* Allocate a dummy frame */ + ret = alloc_dummy_frame(s, &s->next_pic); + if (ret < 0) + return ret; + } + + av_assert0(s->pict_type == AV_PICTURE_TYPE_I || (s->last_pic.ptr && + s->last_pic.ptr->f->buf[0])); + + return 0; +} + /** * generic function called after decoding * the header and before a frame is decoded. */ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx) { - Picture *pic; - int idx, ret; + int ret; s->mb_skipped = 0; if (!ff_thread_can_start_frame(avctx)) { av_log(avctx, AV_LOG_ERROR, "Attempt to start a frame outside SETUP state\n"); - return -1; + return AVERROR_BUG; } - /* mark & release old frames */ - if (s->pict_type != AV_PICTURE_TYPE_B && s->last_picture_ptr && - s->last_picture_ptr != s->next_picture_ptr && - s->last_picture_ptr->f->buf[0]) { - ff_mpeg_unref_picture(s->last_picture_ptr); - } - - /* release non reference/forgotten frames */ - for (int i = 0; i < MAX_PICTURE_COUNT; i++) { - if (!s->picture[i].reference || - (&s->picture[i] != s->last_picture_ptr && - &s->picture[i] != s->next_picture_ptr && - !s->picture[i].needs_realloc)) { - ff_mpeg_unref_picture(&s->picture[i]); - } - } - - ff_mpeg_unref_picture(&s->current_picture); - ff_mpeg_unref_picture(&s->last_picture); - ff_mpeg_unref_picture(&s->next_picture); - - if (s->current_picture_ptr && !s->current_picture_ptr->f->buf[0]) { - // we already have an unused image - // (maybe it was set before reading the header) - pic = s->current_picture_ptr; - } else { - idx = ff_find_unused_picture(s->avctx, s->picture, 0); - if (idx < 0) { - av_log(s->avctx, AV_LOG_ERROR, "no frame buffer available\n"); - return idx; - } - pic = &s->picture[idx]; - } - - pic->reference = 0; - if (!s->droppable) { - if (s->pict_type != AV_PICTURE_TYPE_B) - pic->reference = 3; - } - - if (alloc_picture(s, pic) < 0) - return -1; - - s->current_picture_ptr = pic; - // FIXME use only the vars from current_pic - s->current_picture_ptr->f->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * !!s->top_field_first; - if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO || - s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { - if (s->picture_structure != PICT_FRAME) - s->current_picture_ptr->f->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * - ((s->picture_structure == PICT_TOP_FIELD) == s->first_field); - } - s->current_picture_ptr->f->flags |= AV_FRAME_FLAG_INTERLACED * (!s->progressive_frame && - !s->progressive_sequence); - s->current_picture_ptr->field_picture = s->picture_structure != PICT_FRAME; - - s->current_picture_ptr->f->pict_type = s->pict_type; - if (s->pict_type == AV_PICTURE_TYPE_I) - s->current_picture_ptr->f->flags |= AV_FRAME_FLAG_KEY; - else - s->current_picture_ptr->f->flags &= ~AV_FRAME_FLAG_KEY; - - if ((ret = ff_mpeg_ref_picture(&s->current_picture, - s->current_picture_ptr)) < 0) + ff_mpv_unref_picture(&s->cur_pic); + ret = alloc_picture(s, &s->cur_pic, + s->pict_type != AV_PICTURE_TYPE_B && !s->droppable); + if (ret < 0) return ret; + s->cur_pic.ptr->f->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * !!s->top_field_first; + s->cur_pic.ptr->f->flags |= AV_FRAME_FLAG_INTERLACED * + (!s->progressive_frame && !s->progressive_sequence); + s->cur_pic.ptr->field_picture = s->picture_structure != PICT_FRAME; + + s->cur_pic.ptr->f->pict_type = s->pict_type; + if (s->pict_type == AV_PICTURE_TYPE_I) + s->cur_pic.ptr->f->flags |= AV_FRAME_FLAG_KEY; + else + s->cur_pic.ptr->f->flags &= ~AV_FRAME_FLAG_KEY; + if (s->pict_type != AV_PICTURE_TYPE_B) { - s->last_picture_ptr = s->next_picture_ptr; + ff_mpv_workpic_from_pic(&s->last_pic, s->next_pic.ptr); if (!s->droppable) - s->next_picture_ptr = s->current_picture_ptr; + ff_mpv_workpic_from_pic(&s->next_pic, s->cur_pic.ptr); } ff_dlog(s->avctx, "L%p N%p C%p L%p N%p C%p type:%d drop:%d\n", - s->last_picture_ptr, s->next_picture_ptr,s->current_picture_ptr, - s->last_picture_ptr ? s->last_picture_ptr->f->data[0] : NULL, - s->next_picture_ptr ? s->next_picture_ptr->f->data[0] : NULL, - s->current_picture_ptr ? s->current_picture_ptr->f->data[0] : NULL, + (void*)s->last_pic.ptr, (void*)s->next_pic.ptr, (void*)s->cur_pic.ptr, + s->last_pic.ptr ? s->last_pic.ptr->f->data[0] : NULL, + s->next_pic.ptr ? s->next_pic.ptr->f->data[0] : NULL, + s->cur_pic.ptr ? s->cur_pic.ptr->f->data[0] : NULL, s->pict_type, s->droppable); - if ((!s->last_picture_ptr || !s->last_picture_ptr->f->buf[0]) && - (s->pict_type != AV_PICTURE_TYPE_I)) { - if (s->pict_type == AV_PICTURE_TYPE_B && s->next_picture_ptr && s->next_picture_ptr->f->buf[0]) - av_log(avctx, AV_LOG_DEBUG, - "allocating dummy last picture for B frame\n"); - else if (s->pict_type != AV_PICTURE_TYPE_I) - av_log(avctx, AV_LOG_ERROR, - "warning: first frame is no keyframe\n"); - - /* Allocate a dummy frame */ - idx = ff_find_unused_picture(s->avctx, s->picture, 0); - if (idx < 0) { - av_log(s->avctx, AV_LOG_ERROR, "no frame buffer available\n"); - return idx; - } - s->last_picture_ptr = &s->picture[idx]; - - s->last_picture_ptr->reference = 3; - s->last_picture_ptr->f->flags &= ~AV_FRAME_FLAG_KEY; - s->last_picture_ptr->f->pict_type = AV_PICTURE_TYPE_P; - - if (alloc_picture(s, s->last_picture_ptr) < 0) { - s->last_picture_ptr = NULL; - return -1; - } - - if (!avctx->hwaccel) { - int luma_val = s->codec_id == AV_CODEC_ID_FLV1 || s->codec_id == AV_CODEC_ID_H263 ? 16 : 0x80; - color_frame(s->last_picture_ptr->f, luma_val); - } - - ff_thread_report_progress(&s->last_picture_ptr->tf, INT_MAX, 0); - ff_thread_report_progress(&s->last_picture_ptr->tf, INT_MAX, 1); - } - if ((!s->next_picture_ptr || !s->next_picture_ptr->f->buf[0]) && - s->pict_type == AV_PICTURE_TYPE_B) { - /* Allocate a dummy frame */ - idx = ff_find_unused_picture(s->avctx, s->picture, 0); - if (idx < 0) { - av_log(s->avctx, AV_LOG_ERROR, "no frame buffer available\n"); - return idx; - } - s->next_picture_ptr = &s->picture[idx]; - - s->next_picture_ptr->reference = 3; - s->next_picture_ptr->f->flags &= ~AV_FRAME_FLAG_KEY; - s->next_picture_ptr->f->pict_type = AV_PICTURE_TYPE_P; - - if (alloc_picture(s, s->next_picture_ptr) < 0) { - s->next_picture_ptr = NULL; - return -1; - } - ff_thread_report_progress(&s->next_picture_ptr->tf, INT_MAX, 0); - ff_thread_report_progress(&s->next_picture_ptr->tf, INT_MAX, 1); - } - - if (s->last_picture_ptr) { - if (s->last_picture_ptr->f->buf[0] && - (ret = ff_mpeg_ref_picture(&s->last_picture, - s->last_picture_ptr)) < 0) - return ret; - } - if (s->next_picture_ptr) { - if (s->next_picture_ptr->f->buf[0] && - (ret = ff_mpeg_ref_picture(&s->next_picture, - s->next_picture_ptr)) < 0) - return ret; - } - - av_assert0(s->pict_type == AV_PICTURE_TYPE_I || (s->last_picture_ptr && - s->last_picture_ptr->f->buf[0])); - - if (s->picture_structure != PICT_FRAME) { - for (int i = 0; i < 4; i++) { - if (s->picture_structure == PICT_BOTTOM_FIELD) { - s->current_picture.f->data[i] = FF_PTR_ADD(s->current_picture.f->data[i], - s->current_picture.f->linesize[i]); - } - s->current_picture.f->linesize[i] *= 2; - s->last_picture.f->linesize[i] *= 2; - s->next_picture.f->linesize[i] *= 2; - } - } - - /* set dequantizer, we can't do it during init as - * it might change for MPEG-4 and we can't do it in the header - * decode as init is not called for MPEG-4 there yet */ - 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; - } + ret = ff_mpv_alloc_dummy_frames(s); + if (ret < 0) + return ret; if (s->avctx->debug & FF_DEBUG_NOMC) - color_frame(s->current_picture_ptr->f, 0x80); + color_frame(s->cur_pic.ptr->f, 0x80); return 0; } @@ -491,22 +396,23 @@ void ff_mpv_frame_end(MpegEncContext *s) { emms_c(); - if (s->current_picture.reference) - ff_thread_report_progress(&s->current_picture_ptr->tf, INT_MAX, 0); + if (s->cur_pic.reference) + ff_thread_progress_report(&s->cur_pic.ptr->progress, INT_MAX); } -void ff_print_debug_info(const MpegEncContext *s, const Picture *p, AVFrame *pict) +void ff_print_debug_info(const MpegEncContext *s, const MPVPicture *p, AVFrame *pict) { - ff_print_debug_info2(s->avctx, pict, s->mbskip_table, p->mb_type, + 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); } -int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, const Picture *p, int qp_type) +int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, + const MPVPicture *p, int qp_type) { AVVideoEncParams *par; int mult = (qp_type == FF_MPV_QSCALE_TYPE_MPEG1) ? 2 : 1; - unsigned int nb_mb = p->alloc_mb_height * p->alloc_mb_width; + unsigned int nb_mb = p->mb_height * p->mb_width; if (!(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS)) return 0; @@ -515,10 +421,10 @@ int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, const Picture *p if (!par) return AVERROR(ENOMEM); - for (unsigned y = 0; y < p->alloc_mb_height; y++) - for (unsigned x = 0; x < p->alloc_mb_width; x++) { - const unsigned int block_idx = y * p->alloc_mb_width + x; - const unsigned int mb_xy = y * p->alloc_mb_stride + x; + for (unsigned y = 0; y < p->mb_height; y++) + for (unsigned x = 0; x < p->mb_width; x++) { + const unsigned int block_idx = y * p->mb_width + x; + const unsigned int mb_xy = y * p->mb_stride + x; AVVideoBlockParams *const b = av_video_enc_params_block(par, block_idx); b->src_x = x * 16; @@ -534,8 +440,8 @@ int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, const Picture *p void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h) { - ff_draw_horiz_band(s->avctx, s->current_picture_ptr->f, - s->last_picture_ptr ? s->last_picture_ptr->f : NULL, + ff_draw_horiz_band(s->avctx, s->cur_pic.ptr->f, + s->last_pic.ptr ? s->last_pic.ptr->f : NULL, y, h, s->picture_structure, s->first_field, s->low_delay); } @@ -544,16 +450,9 @@ void ff_mpeg_flush(AVCodecContext *avctx) { MpegEncContext *const s = avctx->priv_data; - if (!s->picture) - return; - - for (int i = 0; i < MAX_PICTURE_COUNT; i++) - ff_mpeg_unref_picture(&s->picture[i]); - s->current_picture_ptr = s->last_picture_ptr = s->next_picture_ptr = NULL; - - ff_mpeg_unref_picture(&s->current_picture); - ff_mpeg_unref_picture(&s->last_picture); - ff_mpeg_unref_picture(&s->next_picture); + ff_mpv_unref_picture(&s->cur_pic); + ff_mpv_unref_picture(&s->last_pic); + ff_mpv_unref_picture(&s->next_pic); s->mb_x = s->mb_y = 0; @@ -564,7 +463,7 @@ void ff_mpeg_flush(AVCodecContext *avctx) 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_report_progress(&s->current_picture_ptr->tf, s->mb_y, 0); + ff_thread_progress_report(&s->cur_pic.ptr->progress, s->mb_y); } @@ -578,11 +477,13 @@ static inline int hpel_motion_lowres(MpegEncContext *s, int motion_x, int motion_y) { const int lowres = s->avctx->lowres; - const int op_index = FFMIN(lowres, 3); + const int op_index = lowres; const int s_mask = (2 << lowres) - 1; int emu = 0; int sx, sy; + av_assert2(op_index <= 3); + if (s->quarter_sample) { motion_x /= 2; motion_y /= 2; @@ -631,14 +532,17 @@ static av_always_inline void mpeg_motion_lowres(MpegEncContext *s, int mx, my, src_x, src_y, uvsrc_x, uvsrc_y, sx, sy, uvsx, uvsy; ptrdiff_t uvlinesize, linesize; const int lowres = s->avctx->lowres; - const int op_index = FFMIN(lowres - 1 + s->chroma_x_shift, 3); + const int op_index = lowres - 1 + s->chroma_x_shift; const int block_s = 8 >> lowres; const int s_mask = (2 << lowres) - 1; const int h_edge_pos = s->h_edge_pos >> lowres; const int v_edge_pos = s->v_edge_pos >> lowres; int hc = s->chroma_y_shift ? (h+1-bottom_field)>>1 : h; - linesize = s->current_picture.f->linesize[0] << field_based; - uvlinesize = s->current_picture.f->linesize[1] << field_based; + + av_assert2(op_index <= 3); + + linesize = s->cur_pic.linesize[0] << field_based; + uvlinesize = s->cur_pic.linesize[1] << field_based; // FIXME obviously not perfect but qpel will not work in lowres anyway if (s->quarter_sample) { @@ -761,7 +665,7 @@ static inline void chroma_4mv_motion_lowres(MpegEncContext *s, int mx, int my) { const int lowres = s->avctx->lowres; - const int op_index = FFMIN(lowres, 3); + const int op_index = lowres; const int block_s = 8 >> lowres; const int s_mask = (2 << lowres) - 1; const int h_edge_pos = s->h_edge_pos >> lowres + 1; @@ -770,6 +674,8 @@ static inline void chroma_4mv_motion_lowres(MpegEncContext *s, ptrdiff_t offset; const uint8_t *ptr; + av_assert2(op_index <= 3); + if (s->quarter_sample) { mx /= 2; my /= 2; @@ -881,9 +787,9 @@ static inline void MPV_motion_lowres(MpegEncContext *s, s->mv[dir][1][0], s->mv[dir][1][1], block_s, mb_y); } else { - if ( s->picture_structure != s->field_select[dir][0] + 1 && s->pict_type != AV_PICTURE_TYPE_B && !s->first_field - || !ref_picture[0]) { - ref_picture = s->current_picture_ptr->f->data; + if (s->picture_structure != s->field_select[dir][0] + 1 && + s->pict_type != AV_PICTURE_TYPE_B && !s->first_field) { + ref_picture = s->cur_pic.ptr->f->data; } mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, 0, s->field_select[dir][0], @@ -896,12 +802,11 @@ static inline void MPV_motion_lowres(MpegEncContext *s, for (int i = 0; i < 2; i++) { uint8_t *const *ref2picture; - if ((s->picture_structure == s->field_select[dir][i] + 1 || - s->pict_type == AV_PICTURE_TYPE_B || s->first_field) && - ref_picture[0]) { + if (s->picture_structure == s->field_select[dir][i] + 1 || + s->pict_type == AV_PICTURE_TYPE_B || s->first_field) { ref2picture = ref_picture; } else { - ref2picture = s->current_picture_ptr->f->data; + ref2picture = s->cur_pic.ptr->f->data; } mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, @@ -929,9 +834,6 @@ static inline void MPV_motion_lowres(MpegEncContext *s, pix_op = s->h264chroma.avg_h264_chroma_pixels_tab; } } else { - if (!ref_picture[0]) { - ref_picture = s->current_picture_ptr->f->data; - } for (int i = 0; i < 2; i++) { mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, 0, s->picture_structure != i + 1, @@ -945,7 +847,7 @@ static inline void MPV_motion_lowres(MpegEncContext *s, // opposite parity is always in the same // frame if this is second field if (!s->first_field) { - ref_picture = s->current_picture_ptr->f->data; + ref_picture = s->cur_pic.ptr->f->data; } } } @@ -1019,15 +921,16 @@ void ff_mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]) } } + av_assert2((s->out_format <= FMT_H261) == (s->out_format == FMT_H261 || s->out_format == FMT_MPEG1)); if (!s->avctx->lowres) { #if !CONFIG_SMALL - if (s->out_format == FMT_MPEG1) - mpv_reconstruct_mb_internal(s, block, 0, DEFINITELY_MPEG12); + if (s->out_format <= FMT_H261) + mpv_reconstruct_mb_internal(s, block, 0, DEFINITELY_MPEG12_H261); else - mpv_reconstruct_mb_internal(s, block, 0, NOT_MPEG12); + mpv_reconstruct_mb_internal(s, block, 0, NOT_MPEG12_H261); #else - mpv_reconstruct_mb_internal(s, block, 0, MAY_BE_MPEG12); + mpv_reconstruct_mb_internal(s, block, 0, MAY_BE_MPEG12_H261); #endif } else - mpv_reconstruct_mb_internal(s, block, 1, MAY_BE_MPEG12); + mpv_reconstruct_mb_internal(s, block, 1, MAY_BE_MPEG12_H261); } diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 5fab30214..74b598d08 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -39,6 +39,7 @@ #include "libavutil/internal.h" #include "libavutil/intmath.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/thread.h" @@ -74,6 +75,7 @@ #include "wmv2enc.h" #include "rv10enc.h" #include "packet_internal.h" +#include "refstruct.h" #include #include "sp5x.h" @@ -82,10 +84,13 @@ #define QMAT_SHIFT_MMX 16 #define QMAT_SHIFT 21 -static int encode_picture(MpegEncContext *s); +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, + 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 uint8_t default_mv_penalty[MAX_FCODE + 1][MAX_DMV * 2 + 1]; @@ -230,11 +235,11 @@ void ff_write_quant_matrix(PutBitContext *pb, uint16_t *matrix) } /** - * init s->current_picture.qscale_table from s->lambda_table + * init s->cur_pic.qscale_table from s->lambda_table */ -void ff_init_qscale_tab(MpegEncContext *s) +static void init_qscale_tab(MpegEncContext *s) { - int8_t * const qscale_table = s->current_picture.qscale_table; + int8_t * const qscale_table = s->cur_pic.qscale_table; int i; for (i = 0; i < s->mb_num; i++) { @@ -250,7 +255,6 @@ static void update_duplicate_context_after_me(MpegEncContext *dst, { #define COPY(a) dst->a= src->a COPY(pict_type); - COPY(current_picture); COPY(f_code); COPY(b_code); COPY(qscale); @@ -287,21 +291,58 @@ static void mpv_encode_defaults(MpegEncContext *s) s->picture_in_gop_number = 0; } -av_cold int ff_dct_encode_init(MpegEncContext *s) +av_cold void ff_dct_encode_init(MpegEncContext *s) { -#if ARCH_X86 + s->dct_quantize = dct_quantize_c; + s->denoise_dct = denoise_dct_c; + +#if ARCH_MIPS + ff_mpvenc_dct_init_mips(s); +#elif ARCH_X86 ff_dct_encode_init_x86(s); #endif - if (CONFIG_H263_ENCODER) - ff_h263dsp_init(&s->h263dsp); - if (!s->dct_quantize) - s->dct_quantize = ff_dct_quantize_c; - if (!s->denoise_dct) - s->denoise_dct = denoise_dct_c; - s->fast_dct_quantize = s->dct_quantize; if (s->avctx->trellis) s->dct_quantize = dct_quantize_trellis_c; +} + +static av_cold int me_cmp_init(MpegEncContext *s, AVCodecContext *avctx) +{ + MECmpContext mecc; + me_cmp_func me_cmp[6]; + int ret; + + ff_me_cmp_init(&mecc, 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); + if (ret < 0) + return ret; + s->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) + return ret; + if (!me_cmp[0] || !me_cmp[4]) + return AVERROR(EINVAL); + s->ildct_cmp[0] = me_cmp[0]; + s->ildct_cmp[1] = me_cmp[4]; + } + + s->sum_abs_dctelem = mecc.sum_abs_dctelem; + + s->sse_cmp[0] = mecc.sse[0]; + s->sse_cmp[1] = mecc.sse[1]; + s->sad_cmp[0] = mecc.sad[0]; + s->sad_cmp[1] = mecc.sad[1]; + if (avctx->mb_cmp == FF_CMP_NSSE) { + s->n_sse_cmp[0] = mecc.nsse[0]; + s->n_sse_cmp[1] = mecc.nsse[1]; + } else { + s->n_sse_cmp[0] = mecc.sse[0]; + s->n_sse_cmp[1] = mecc.sse[1]; + } return 0; } @@ -526,6 +567,12 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) 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 && + (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) && @@ -562,7 +609,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) if ((s->mpv_flags & FF_MPV_FLAG_QP_RD) && avctx->mb_decision != FF_MB_DECISION_RD) { - av_log(avctx, AV_LOG_ERROR, "QP RD needs mbd=2\n"); + av_log(avctx, AV_LOG_ERROR, "QP RD needs mbd=rd\n"); return AVERROR(EINVAL); } @@ -713,6 +760,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) 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->flipflop_rounding = 1; /* /Fx */ /* These are just to be sure */ @@ -746,6 +794,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) s->out_format = FMT_H263; s->h263_pred = 1; s->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); break; @@ -753,7 +802,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) s->out_format = FMT_H263; s->h263_pred = 1; s->unrestricted_mv = 1; - s->msmpeg4_version = 2; + s->msmpeg4_version = MSMP4_V2; avctx->delay = 0; s->low_delay = 1; break; @@ -761,7 +810,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) s->out_format = FMT_H263; s->h263_pred = 1; s->unrestricted_mv = 1; - s->msmpeg4_version = 3; + s->msmpeg4_version = MSMP4_V3; s->flipflop_rounding = 1; avctx->delay = 0; s->low_delay = 1; @@ -770,7 +819,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) s->out_format = FMT_H263; s->h263_pred = 1; s->unrestricted_mv = 1; - s->msmpeg4_version = 4; + s->msmpeg4_version = MSMP4_WMV1; s->flipflop_rounding = 1; avctx->delay = 0; s->low_delay = 1; @@ -779,7 +828,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) s->out_format = FMT_H263; s->h263_pred = 1; s->unrestricted_mv = 1; - s->msmpeg4_version = 5; + s->msmpeg4_version = MSMP4_WMV2; s->flipflop_rounding = 1; avctx->delay = 0; s->low_delay = 1; @@ -808,9 +857,11 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) return ret; ff_fdctdsp_init(&s->fdsp, avctx); - ff_me_cmp_init(&s->mecc, avctx); ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx); ff_pixblockdsp_init(&s->pdsp, avctx); + ret = me_cmp_init(s, avctx); + if (ret < 0) + return ret; if (!(avctx->stats_out = av_mallocz(256)) || !FF_ALLOCZ_TYPED_ARRAY(s->q_intra_matrix, 32) || @@ -821,7 +872,8 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) !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_picture = av_frame_alloc())) + !(s->new_pic = av_frame_alloc()) || + !(s->picture_pool = ff_mpv_alloc_pic_pool(0))) return AVERROR(ENOMEM); /* Allocate MV tables; the MV and MB tables will be copied @@ -905,17 +957,12 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) s->h263_slice_structured = 1; } - s->quant_precision = 5; - - ret = ff_set_cmp(&s->mecc, s->mecc.ildct_cmp, avctx->ildct_cmp); - ret |= ff_set_cmp(&s->mecc, s->mecc.frame_skip_cmp, s->frame_skip_cmp); - if (ret < 0) - return AVERROR(EINVAL); - if (CONFIG_H263_ENCODER && s->out_format == FMT_H263) { ff_h263_encode_init(s); - if (CONFIG_MSMPEG4ENC && s->msmpeg4_version) +#if CONFIG_MSMPEG4ENC + if (s->msmpeg4_version != MSMP4_UNUSED) ff_msmpeg4_encode_init(s); +#endif } /* init q matrix */ @@ -989,14 +1036,21 @@ av_cold int ff_mpv_encode_end(AVCodecContext *avctx) MpegEncContext *s = avctx->priv_data; int i; - ff_rate_control_uninit(s); + ff_rate_control_uninit(&s->rc_context); ff_mpv_common_end(s); + ff_refstruct_pool_uninit(&s->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 (i = 0; i < FF_ARRAY_ELEMS(s->tmp_frames); i++) av_frame_free(&s->tmp_frames[i]); - av_frame_free(&s->new_picture); + av_frame_free(&s->new_pic); av_freep(&avctx->stats_out); @@ -1051,7 +1105,7 @@ static void mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]) } } - mpv_reconstruct_mb_internal(s, block, 0, MAY_BE_MPEG12); + mpv_reconstruct_mb_internal(s, block, 0, MAY_BE_MPEG12_H261); } static int get_sae(const uint8_t *src, int ref, int stride) @@ -1080,8 +1134,8 @@ static int get_intra_count(MpegEncContext *s, const uint8_t *src, for (y = 0; y < h; y += 16) { for (x = 0; x < w; x += 16) { int offset = x + y * stride; - int sad = s->mecc.sad[0](NULL, src + offset, ref + offset, - stride, 16); + int sad = s->sad_cmp[0](NULL, src + offset, ref + offset, + stride, 16); int mean = (s->mpvencdsp.pix_sum(src + offset, stride) + 128) >> 8; int sae = get_sae(src + offset, mean, stride); @@ -1091,42 +1145,54 @@ static int get_intra_count(MpegEncContext *s, const uint8_t *src, return acc; } -static int alloc_picture(MpegEncContext *s, Picture *pic) +/** + * 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) { AVCodecContext *avctx = s->avctx; int ret; - pic->f->width = avctx->width + 2 * EDGE_WIDTH; - pic->f->height = avctx->height + 2 * EDGE_WIDTH; + f->width = avctx->width + 2 * EDGE_WIDTH; + f->height = avctx->height + 2 * EDGE_WIDTH; - ret = ff_encode_alloc_frame(avctx, pic->f); + ret = ff_encode_alloc_frame(avctx, f); if (ret < 0) return ret; - for (int i = 0; pic->f->data[i]; i++) { - int offset = (EDGE_WIDTH >> (i ? s->chroma_y_shift : 0)) * - pic->f->linesize[i] + - (EDGE_WIDTH >> (i ? s->chroma_x_shift : 0)); - pic->f->data[i] += offset; - } - pic->f->width = avctx->width; - pic->f->height = avctx->height; + ret = ff_mpv_pic_check_linesize(avctx, f, &s->linesize, &s->uvlinesize); + if (ret < 0) + return ret; - return ff_alloc_picture(s->avctx, pic, &s->me, &s->sc, 1, s->out_format, - s->mb_stride, s->mb_width, s->mb_height, s->b8_stride, - &s->linesize, &s->uvlinesize); + for (int i = 0; f->data[i]; i++) { + int offset = (EDGE_WIDTH >> (i ? s->chroma_y_shift : 0)) * + f->linesize[i] + + (EDGE_WIDTH >> (i ? s->chroma_x_shift : 0)); + f->data[i] += offset; + } + f->width = avctx->width; + f->height = avctx->height; + + ret = av_frame_copy_props(f, props_frame); + if (ret < 0) + return ret; + + return 0; } static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) { - Picture *pic = NULL; + MPVPicture *pic = NULL; int64_t pts; - int i, display_picture_number = 0, ret; + int display_picture_number = 0, ret; int encoding_delay = s->max_b_frames ? s->max_b_frames : (s->low_delay ? 0 : 1); int flush_offset = 1; int direct = 1; + av_assert1(!s->input_picture[0]); + if (pic_arg) { pts = pic_arg->pts; display_picture_number = s->input_picture_number++; @@ -1172,26 +1238,18 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) ff_dlog(s->avctx, "%d %d %"PTRDIFF_SPECIFIER" %"PTRDIFF_SPECIFIER"\n", pic_arg->linesize[0], pic_arg->linesize[1], s->linesize, s->uvlinesize); - i = ff_find_unused_picture(s->avctx, s->picture, direct); - if (i < 0) - return i; - - pic = &s->picture[i]; - pic->reference = 3; + pic = ff_refstruct_pool_get(s->picture_pool); + if (!pic) + return AVERROR(ENOMEM); if (direct) { if ((ret = av_frame_ref(pic->f, pic_arg)) < 0) - return ret; + goto fail; pic->shared = 1; } else { - ret = alloc_picture(s, pic); + ret = prepare_picture(s, pic->f, pic_arg); if (ret < 0) - return ret; - ret = av_frame_copy_props(pic->f, pic_arg); - if (ret < 0) { - ff_mpeg_unref_picture(pic); - return ret; - } + goto fail; for (int i = 0; i < 3; i++) { ptrdiff_t src_stride = pic_arg->linesize[i]; @@ -1236,17 +1294,17 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) pic->display_picture_number = display_picture_number; pic->f->pts = pts; // we set this here to avoid modifying pic_arg - } else { - /* Flushing: When we have not received enough input frames, - * ensure s->input_picture[0] contains the first picture */ + } else if (!s->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. + * 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]) break; - if (flush_offset <= 1) - flush_offset = 1; - else - encoding_delay = encoding_delay - flush_offset + 1; + encoding_delay -= flush_offset - 1; } /* shift buffer entries */ @@ -1258,9 +1316,12 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg) s->input_picture[encoding_delay] = pic; return 0; +fail: + ff_refstruct_unref(&pic); + return ret; } -static int skip_check(MpegEncContext *s, const Picture *p, const Picture *ref) +static int skip_check(MpegEncContext *s, const MPVPicture *p, const MPVPicture *ref) { int x, y, plane; int score = 0; @@ -1274,7 +1335,7 @@ static int skip_check(MpegEncContext *s, const Picture *p, const Picture *ref) 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->mecc.frame_skip_cmp[1](s, dptr, rptr, stride, 8); + int v = s->frame_skip_cmp_fn(s, dptr, rptr, stride, 8); switch (FFABS(s->frame_skip_exp)) { case 0: score = FFMAX(score, v); break; @@ -1340,7 +1401,6 @@ static int estimate_best_b_count(MpegEncContext *s) return AVERROR(ENOMEM); //emms_c(); - //s->next_picture_ptr->quality; 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]; @@ -1350,8 +1410,8 @@ static int estimate_best_b_count(MpegEncContext *s) FF_LAMBDA_SHIFT; for (i = 0; i < s->max_b_frames + 2; i++) { - const Picture *pre_input_ptr = i ? s->input_picture[i - 1] : - s->next_picture_ptr; + const MPVPicture *pre_input_ptr = i ? s->input_picture[i - 1] : + s->next_pic.ptr; if (pre_input_ptr) { const uint8_t *data[4]; @@ -1467,210 +1527,224 @@ fail: return best_b_count; } +/** + * Determines whether an input picture is discarded or not + * and if not determines the length of the next chain of B frames + * and moves these pictures (including the P frame) into + * reordered_input_picture. + * 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) +{ + /* Either nothing to do or can't do anything */ + if (s->reordered_input_picture[0] || !s->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)) { + // FIXME check that the gop check above is +-1 correct + ff_refstruct_unref(&s->input_picture[0]); + + ff_vbv_update(s, 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++; + } 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 (pict_num >= s->rc_context.num_entries) + break; + if (!s->input_picture[i]) { + s->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; + } + } + + if (s->b_frame_strategy == 0) { + b_frames = s->max_b_frames; + while (b_frames && !s->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 = + get_intra_count(s, + s->input_picture[i ]->f->data[0], + s->input_picture[i - 1]->f->data[0], + s->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) + 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); + if (b_frames < 0) { + ff_refstruct_unref(&s->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; + 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, + "warning, too many B-frames in a row\n"); + } + + if (s->picture_in_gop_number + b_frames >= s->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; + } else { + if (s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) + b_frames = 0; + s->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) + 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++; + 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 = + AV_PICTURE_TYPE_B; + s->reordered_input_picture[i + 1]->coded_picture_number = + s->coded_picture_number++; + } + } + + return 0; +} + static int select_input_picture(MpegEncContext *s) { - int i, ret; + int ret; + + av_assert1(!s->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; - /* set next picture type & ordering */ - if (!s->reordered_input_picture[0] && s->input_picture[0]) { - if (s->frame_skip_threshold || s->frame_skip_factor) { - if (s->picture_in_gop_number < s->gop_size && - s->next_picture_ptr && - skip_check(s, s->input_picture[0], s->next_picture_ptr)) { - // FIXME check that the gop check above is +-1 correct - av_frame_unref(s->input_picture[0]->f); + ret = set_bframe_chain_length(s); + av_assert1(!s->input_picture[0]); + if (ret < 0) + return ret; - ff_vbv_update(s, 0); - - goto no_output_pic; - } - } - - if (/*s->picture_in_gop_number >= s->gop_size ||*/ - !s->next_picture_ptr || s->intra_only) { - s->reordered_input_picture[0] = s->input_picture[0]; - s->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_I; - s->reordered_input_picture[0]->coded_picture_number = - s->coded_picture_number++; - } else { - int b_frames = 0; - - if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { - for (i = 0; i < s->max_b_frames + 1; i++) { - int pict_num = s->input_picture[0]->display_picture_number + i; - - if (pict_num >= s->rc_context.num_entries) - break; - if (!s->input_picture[i]) { - s->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; - } - } - - if (s->b_frame_strategy == 0) { - b_frames = s->max_b_frames; - while (b_frames && !s->input_picture[b_frames]) - b_frames--; - } else if (s->b_frame_strategy == 1) { - 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 = - get_intra_count(s, - s->input_picture[i ]->f->data[0], - s->input_picture[i - 1]->f->data[0], - s->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) - 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); - if (b_frames < 0) { - ff_mpeg_unref_picture(s->input_picture[0]); - return b_frames; - } - } - - emms_c(); - - for (i = b_frames - 1; i >= 0; i--) { - int type = s->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, - "warning, too many B-frames in a row\n"); - } - - if (s->picture_in_gop_number + b_frames >= s->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; - } else { - if (s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) - b_frames = 0; - s->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) - b_frames--; - - s->reordered_input_picture[0] = s->input_picture[b_frames]; - 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++; - for (i = 0; i < b_frames; i++) { - s->reordered_input_picture[i + 1] = s->input_picture[i]; - s->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++; - } - } - } -no_output_pic: - av_frame_unref(s->new_picture); + 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 ? 3 : 0; - - if ((ret = av_frame_ref(s->new_picture, - s->reordered_input_picture[0]->f))) - goto fail; + s->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_B; if (s->reordered_input_picture[0]->shared || s->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); - Picture *pic; - int i = ff_find_unused_picture(s->avctx, s->picture, 0); - if (i < 0) - return i; - pic = &s->picture[i]; - - pic->reference = s->reordered_input_picture[0]->reference; - ret = alloc_picture(s, pic); + ret = prepare_picture(s, s->reordered_input_picture[0]->f, s->new_pic); if (ret < 0) goto fail; - - ret = av_frame_copy_props(pic->f, s->reordered_input_picture[0]->f); - if (ret < 0) { - ff_mpeg_unref_picture(pic); - goto fail; - } - pic->coded_picture_number = s->reordered_input_picture[0]->coded_picture_number; - pic->display_picture_number = s->reordered_input_picture[0]->display_picture_number; - - /* mark us unused / free shared pic */ - av_frame_unref(s->reordered_input_picture[0]->f); - s->reordered_input_picture[0]->shared = 0; - - s->current_picture_ptr = pic; } else { // input is not a shared pix -> reuse buffer for current_pix - s->current_picture_ptr = s->reordered_input_picture[0]; - for (i = 0; i < 4; i++) { - if (s->new_picture->data[i]) - s->new_picture->data[i] += INPLACE_OFFSET; + ret = av_frame_ref(s->new_pic, s->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; } } - s->picture_number = s->current_picture_ptr->display_picture_number; + 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); + if (ret < 0) { + ff_mpv_unref_picture(&s->cur_pic); + return ret; + } + s->picture_number = s->cur_pic.ptr->display_picture_number; } return 0; fail: - ff_mpeg_unref_picture(s->reordered_input_picture[0]); + ff_refstruct_unref(&s->reordered_input_picture[0]); return ret; } static void frame_end(MpegEncContext *s) { if (s->unrestricted_mv && - s->current_picture.reference && + s->cur_pic.reference && !s->intra_only) { int hshift = s->chroma_x_shift; int vshift = s->chroma_y_shift; - s->mpvencdsp.draw_edges(s->current_picture.f->data[0], - s->current_picture.f->linesize[0], + s->mpvencdsp.draw_edges(s->cur_pic.data[0], + s->cur_pic.linesize[0], s->h_edge_pos, s->v_edge_pos, EDGE_WIDTH, EDGE_WIDTH, EDGE_TOP | EDGE_BOTTOM); - s->mpvencdsp.draw_edges(s->current_picture.f->data[1], - s->current_picture.f->linesize[1], + s->mpvencdsp.draw_edges(s->cur_pic.data[1], + s->cur_pic.linesize[1], s->h_edge_pos >> hshift, s->v_edge_pos >> vshift, EDGE_WIDTH >> hshift, EDGE_WIDTH >> vshift, EDGE_TOP | EDGE_BOTTOM); - s->mpvencdsp.draw_edges(s->current_picture.f->data[2], - s->current_picture.f->linesize[2], + s->mpvencdsp.draw_edges(s->cur_pic.data[2], + s->cur_pic.linesize[2], s->h_edge_pos >> hshift, s->v_edge_pos >> vshift, EDGE_WIDTH >> hshift, @@ -1681,7 +1755,7 @@ static void frame_end(MpegEncContext *s) emms_c(); s->last_pict_type = s->pict_type; - s->last_lambda_for [s->pict_type] = s->current_picture_ptr->f->quality; + 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; } @@ -1707,59 +1781,30 @@ static void update_noise_reduction(MpegEncContext *s) } } -static int frame_start(MpegEncContext *s) +static void frame_start(MpegEncContext *s) { - int ret; - - /* mark & release old frames */ - if (s->pict_type != AV_PICTURE_TYPE_B && s->last_picture_ptr && - s->last_picture_ptr != s->next_picture_ptr && - s->last_picture_ptr->f->buf[0]) { - ff_mpeg_unref_picture(s->last_picture_ptr); - } - - s->current_picture_ptr->f->pict_type = s->pict_type; - - ff_mpeg_unref_picture(&s->current_picture); - if ((ret = ff_mpeg_ref_picture(&s->current_picture, - s->current_picture_ptr)) < 0) - return ret; + s->cur_pic.ptr->f->pict_type = s->pict_type; if (s->pict_type != AV_PICTURE_TYPE_B) { - s->last_picture_ptr = s->next_picture_ptr; - s->next_picture_ptr = s->current_picture_ptr; - } - - if (s->last_picture_ptr) { - ff_mpeg_unref_picture(&s->last_picture); - if (s->last_picture_ptr->f->buf[0] && - (ret = ff_mpeg_ref_picture(&s->last_picture, - s->last_picture_ptr)) < 0) - return ret; - } - if (s->next_picture_ptr) { - ff_mpeg_unref_picture(&s->next_picture); - if (s->next_picture_ptr->f->buf[0] && - (ret = ff_mpeg_ref_picture(&s->next_picture, - s->next_picture_ptr)) < 0) - return ret; + ff_mpv_replace_picture(&s->last_pic, &s->next_pic); + ff_mpv_replace_picture(&s->next_pic, &s->cur_pic); } if (s->dct_error_sum) { av_assert2(s->noise_reduction && s->encoding); update_noise_reduction(s); } - - return 0; } int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic_arg, int *got_packet) { MpegEncContext *s = avctx->priv_data; - int i, stuffing_count, ret; + int stuffing_count, ret; int context_count = s->slice_context_count; + ff_mpv_unref_picture(&s->cur_pic); + s->vbv_ignore_qmax = 0; s->picture_in_gop_number++; @@ -1772,12 +1817,12 @@ int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, } /* output? */ - if (s->new_picture->data[0]) { + 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 * (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_picture, &pkt_size); + ret = ff_mjpeg_add_icc_profile_size(avctx, s->new_pic, &pkt_size); if (ret < 0) return ret; } @@ -1788,26 +1833,16 @@ int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, s->mb_info_ptr = av_packet_new_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, s->mb_width*s->mb_height*12); + if (!s->mb_info_ptr) + return AVERROR(ENOMEM); s->prev_mb_info = s->last_mb_info = s->mb_info_size = 0; } - for (i = 0; i < context_count; i++) { - int start_y = s->thread_context[i]->start_mb_y; - int end_y = s->thread_context[i]-> end_mb_y; - int h = s->mb_height; - uint8_t *start = pkt->data + (size_t)(((int64_t) pkt->size) * start_y / h); - uint8_t *end = pkt->data + (size_t)(((int64_t) pkt->size) * end_y / h); - - init_put_bits(&s->thread_context[i]->pb, start, end - start); - } - - s->pict_type = s->new_picture->pict_type; + s->pict_type = s->new_pic->pict_type; //emms_c(); - ret = frame_start(s); - if (ret < 0) - return ret; + frame_start(s); vbv_retry: - ret = encode_picture(s); + ret = encode_picture(s, pkt); if (growing_buffer) { av_assert0(s->pb.buf == avctx->internal->byte_buffer); pkt->data = s->pb.buf; @@ -1842,19 +1877,12 @@ vbv_retry: s->mb_skipped = 0; // done in frame_start() // done in encode_picture() so we must undo it if (s->pict_type == AV_PICTURE_TYPE_P) { - if (s->flipflop_rounding || - s->codec_id == AV_CODEC_ID_H263P || - s->codec_id == AV_CODEC_ID_MPEG4) - s->no_rounding ^= 1; + s->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; } - for (i = 0; i < context_count; i++) { - PutBitContext *pb = &s->thread_context[i]->pb; - init_put_bits(pb, pb->buf, pb->buf_end - pb->buf); - } s->vbv_ignore_qmax = 1; av_log(avctx, AV_LOG_VERBOSE, "reencoding frame due to VBV\n"); goto vbv_retry; @@ -1866,12 +1894,11 @@ vbv_retry: if (avctx->flags & AV_CODEC_FLAG_PASS1) ff_write_pass1_stats(s); - for (i = 0; i < 4; i++) { + for (int i = 0; i < MPV_MAX_PLANES; i++) avctx->error[i] += s->encoding_error[i]; - } - ff_side_data_set_encoder_stats(pkt, s->current_picture.f->quality, + ff_side_data_set_encoder_stats(pkt, s->cur_pic.ptr->f->quality, s->encoding_error, - (avctx->flags&AV_CODEC_FLAG_PSNR) ? MPEGVIDEO_MAX_PLANES : 0, + (avctx->flags&AV_CODEC_FLAG_PSNR) ? MPV_MAX_PLANES : 0, s->pict_type); if (avctx->flags & AV_CODEC_FLAG_PASS1) @@ -1963,10 +1990,10 @@ vbv_retry: } s->total_bits += s->frame_bits; - pkt->pts = s->current_picture.f->pts; - pkt->duration = s->current_picture.f->duration; + 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->current_picture.coded_picture_number) + if (!s->cur_pic.ptr->coded_picture_number) pkt->dts = pkt->pts - s->dts_delta; else pkt->dts = s->reordered_pts; @@ -1976,12 +2003,12 @@ vbv_retry: // 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->current_picture.f); + ret = ff_encode_reordered_opaque(avctx, pkt, s->cur_pic.ptr->f); if (ret < 0) return ret; } - if (s->current_picture.f->flags & AV_FRAME_FLAG_KEY) + if (s->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); @@ -1989,11 +2016,7 @@ vbv_retry: s->frame_bits = 0; } - /* release non-reference frames */ - for (i = 0; i < MAX_PICTURE_COUNT; i++) { - if (!s->picture[i].reference) - ff_mpeg_unref_picture(&s->picture[i]); - } + ff_mpv_unref_picture(&s->cur_pic); av_assert1((s->frame_bits & 7) == 0); @@ -2148,11 +2171,11 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, const int mb_xy = mb_x + mb_y * s->mb_stride; s->lambda = s->lambda_table[mb_xy]; - update_qscale(s); + s->lambda2 = (s->lambda * s->lambda + FF_LAMBDA_SCALE / 2) >> + FF_LAMBDA_SHIFT; if (!(s->mpv_flags & FF_MPV_FLAG_QP_RD)) { - s->qscale = s->current_picture_ptr->qscale_table[mb_xy]; - s->dquant = s->qscale - last_qp; + s->dquant = s->cur_pic.qscale_table[mb_xy] - last_qp; if (s->out_format == FMT_H263) { s->dquant = av_clip(s->dquant, -2, 2); @@ -2175,11 +2198,11 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, wrap_y = s->linesize; wrap_c = s->uvlinesize; - ptr_y = s->new_picture->data[0] + + ptr_y = s->new_pic->data[0] + (mb_y * 16 * wrap_y) + mb_x * 16; - ptr_cb = s->new_picture->data[1] + + ptr_cb = s->new_pic->data[1] + (mb_y * mb_block_height * wrap_c) + mb_x * mb_block_width; - ptr_cr = s->new_picture->data[2] + + 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){ @@ -2210,15 +2233,15 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, int progressive_score, interlaced_score; s->interlaced_dct = 0; - progressive_score = s->mecc.ildct_cmp[4](s, ptr_y, NULL, wrap_y, 8) + - s->mecc.ildct_cmp[4](s, ptr_y + wrap_y * 8, - NULL, wrap_y, 8) - 400; + 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; if (progressive_score > 0) { - interlaced_score = s->mecc.ildct_cmp[4](s, ptr_y, - NULL, wrap_y * 2, 8) + - s->mecc.ildct_cmp[4](s, ptr_y + wrap_y, - NULL, wrap_y * 2, 8); + interlaced_score = s->ildct_cmp[1](s, ptr_y, + NULL, wrap_y * 2, 8) + + s->ildct_cmp[1](s, ptr_y + wrap_y, + NULL, wrap_y * 2, 8); if (progressive_score > interlaced_score) { s->interlaced_dct = 1; @@ -2274,14 +2297,14 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, if (s->mv_dir & MV_DIR_FORWARD) { ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 0, - s->last_picture.f->data, + 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_picture.f->data, + s->next_pic.data, op_pix, op_qpix); } @@ -2289,20 +2312,20 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, int progressive_score, interlaced_score; s->interlaced_dct = 0; - progressive_score = s->mecc.ildct_cmp[0](s, dest_y, ptr_y, wrap_y, 8) + - s->mecc.ildct_cmp[0](s, dest_y + wrap_y * 8, - ptr_y + wrap_y * 8, - wrap_y, 8) - 400; + 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) progressive_score -= 400; if (progressive_score > 0) { - interlaced_score = s->mecc.ildct_cmp[0](s, dest_y, ptr_y, - wrap_y * 2, 8) + - s->mecc.ildct_cmp[0](s, dest_y + wrap_y, - ptr_y + wrap_y, - wrap_y * 2, 8); + interlaced_score = s->ildct_cmp[0](s, dest_y, ptr_y, + wrap_y * 2, 8) + + s->ildct_cmp[0](s, dest_y + wrap_y, + ptr_y + wrap_y, + wrap_y * 2, 8); if (progressive_score > interlaced_score) { s->interlaced_dct = 1; @@ -2339,28 +2362,28 @@ 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) { // FIXME optimize - if (s->mecc.sad[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->qscale) skip_dct[0] = 1; - if (s->mecc.sad[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->qscale) skip_dct[1] = 1; - if (s->mecc.sad[1](NULL, ptr_y + dct_offset, dest_y + dct_offset, - wrap_y, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_y + dct_offset, dest_y + dct_offset, + wrap_y, 8) < 20 * s->qscale) skip_dct[2] = 1; - if (s->mecc.sad[1](NULL, ptr_y + dct_offset + 8, dest_y + dct_offset + 8, - wrap_y, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_y + dct_offset + 8, dest_y + dct_offset + 8, + wrap_y, 8) < 20 * s->qscale) skip_dct[3] = 1; - if (s->mecc.sad[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->qscale) skip_dct[4] = 1; - if (s->mecc.sad[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->qscale) skip_dct[5] = 1; if (!chroma_y_shift) { /* 422 */ - if (s->mecc.sad[1](NULL, ptr_cb + uv_dct_offset, - dest_cb + uv_dct_offset, - wrap_c, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_cb + uv_dct_offset, + dest_cb + uv_dct_offset, + wrap_c, 8) < 20 * s->qscale) skip_dct[6] = 1; - if (s->mecc.sad[1](NULL, ptr_cr + uv_dct_offset, - dest_cr + uv_dct_offset, - wrap_c, 8) < 20 * s->qscale) + if (s->sad_cmp[1](NULL, ptr_cr + uv_dct_offset, + dest_cr + uv_dct_offset, + wrap_c, 8) < 20 * s->qscale) skip_dct[7] = 1; } } @@ -2446,7 +2469,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, } // non c quantize code returns incorrect block_last_index FIXME - if (s->alternate_scan && s->dct_quantize != ff_dct_quantize_c) { + if (s->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) { @@ -2507,7 +2530,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, } } -static av_always_inline void encode_mb(MpegEncContext *s, int motion_x, int motion_y) +static void encode_mb(MpegEncContext *s, int motion_x, int motion_y) { if (s->chroma_format == CHROMA_420) encode_mb_internal(s, motion_x, motion_y, 8, 8, 6, 1, 1, CHROMA_420); @@ -2534,7 +2557,6 @@ static inline void copy_context_before_encode(MpegEncContext *d, d->i_tex_bits= s->i_tex_bits; d->p_tex_bits= s->p_tex_bits; d->i_count= s->i_count; - d->skip_count= s->skip_count; d->misc_bits= s->misc_bits; d->last_bits= 0; @@ -2563,7 +2585,6 @@ static inline void copy_context_after_encode(MpegEncContext *d, d->i_tex_bits= s->i_tex_bits; d->p_tex_bits= s->p_tex_bits; d->i_count= s->i_count; - d->skip_count= s->skip_count; d->misc_bits= s->misc_bits; d->mb_intra= s->mb_intra; @@ -2584,9 +2605,9 @@ static inline void copy_context_after_encode(MpegEncContext *d, d->esc3_level_length= s->esc3_level_length; } -static inline void encode_mb_hq(MpegEncContext *s, MpegEncContext *backup, MpegEncContext *best, - PutBitContext pb[2], PutBitContext pb2[2], PutBitContext tex_pb[2], - int *dmin, int *next_block, int motion_x, int motion_y) +static void encode_mb_hq(MpegEncContext *s, MpegEncContext *backup, MpegEncContext *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]; @@ -2641,9 +2662,9 @@ static int sse(MpegEncContext *s, const uint8_t *src1, const uint8_t *src2, int int x,y; if(w==16 && h==16) - return s->mecc.sse[0](NULL, src1, src2, stride, 16); + return s->sse_cmp[0](NULL, src1, src2, stride, 16); else if(w==8 && h==8) - return s->mecc.sse[1](NULL, src1, src2, stride, 8); + return s->sse_cmp[1](NULL, src1, src2, stride, 8); for(y=0; ymb_y*16 + 16 > s->height) h= s->height- s->mb_y*16; if(w==16 && h==16) - if(s->avctx->mb_cmp == FF_CMP_NSSE){ - return s->mecc.nsse[0](s, s->new_picture->data[0] + s->mb_x * 16 + s->mb_y * s->linesize * 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->mecc.nsse[1](s, s->new_picture->data[1] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, + 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->mecc.nsse[1](s, s->new_picture->data[2] + s->mb_x * chroma_mb_w + s->mb_y * 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); - }else{ - return s->mecc.sse[0](NULL, s->new_picture->data[0] + s->mb_x * 16 + s->mb_y * s->linesize * 16, - s->dest[0], s->linesize, 16) + - s->mecc.sse[1](NULL, s->new_picture->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->mecc.sse[1](NULL, s->new_picture->data[2] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, - s->dest[2], s->uvlinesize, chroma_mb_h); - } else - return sse(s, s->new_picture->data[0] + s->mb_x * 16 + s->mb_y * s->linesize * 16, + 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_picture->data[1] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, + 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_picture->data[2] + s->mb_x * chroma_mb_w + s->mb_y * s->uvlinesize * chroma_mb_h, + 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); } @@ -2742,7 +2754,7 @@ static int mb_var_thread(AVCodecContext *c, void *arg){ for(mb_x=0; mb_x < s->mb_width; mb_x++) { int xx = mb_x * 16; int yy = mb_y * 16; - const uint8_t *pix = s->new_picture->data[0] + (yy * s->linesize) + xx; + const uint8_t *pix = s->new_pic->data[0] + (yy * s->linesize) + xx; int varc; int sum = s->mpvencdsp.pix_sum(pix, s->linesize); @@ -2877,7 +2889,6 @@ static int encode_thread(AVCodecContext *c, void *arg){ s->i_tex_bits=0; s->p_tex_bits=0; s->i_count=0; - s->skip_count=0; for(i=0; i<3; i++){ /* init last dc values */ @@ -3106,8 +3117,8 @@ static int encode_thread(AVCodecContext *c, void *arg){ s->mv_type = MV_TYPE_8X8; s->mb_intra= 0; for(i=0; i<4; i++){ - s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0]; - s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1]; + 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]; } encode_mb_hq(s, &backup_s, &best_s, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); @@ -3294,7 +3305,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ } } - s->current_picture.qscale_table[xy] = best_s.qscale; + s->cur_pic.qscale_table[xy] = best_s.qscale; copy_context_after_encode(s, &best_s); @@ -3318,7 +3329,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ if (CONFIG_H263_ENCODER && s->out_format == FMT_H263 && s->pict_type!=AV_PICTURE_TYPE_B) - ff_h263_update_motion_val(s); + 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); @@ -3361,8 +3372,8 @@ static int encode_thread(AVCodecContext *c, void *arg){ s->mv_type = MV_TYPE_8X8; s->mb_intra= 0; for(i=0; i<4; i++){ - s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0]; - s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1]; + 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]; } break; case CANDIDATE_MB_TYPE_DIRECT: @@ -3444,7 +3455,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ if (CONFIG_H263_ENCODER && s->out_format == FMT_H263 && s->pict_type!=AV_PICTURE_TYPE_B) - ff_h263_update_motion_val(s); + ff_h263_update_mb(s); mpv_reconstruct_mb(s, s->block); } @@ -3463,13 +3474,13 @@ static int encode_thread(AVCodecContext *c, void *arg){ if(s->mb_y*16 + 16 > s->height) h= s->height- s->mb_y*16; s->encoding_error[0] += sse( - s, s->new_picture->data[0] + s->mb_x*16 + s->mb_y*s->linesize*16, + s, s->new_pic->data[0] + s->mb_x*16 + s->mb_y*s->linesize*16, s->dest[0], w, h, s->linesize); s->encoding_error[1] += sse( - s, s->new_picture->data[1] + s->mb_x*8 + s->mb_y*s->uvlinesize*chr_h, + 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->encoding_error[2] += sse( - s, s->new_picture->data[2] + s->mb_x*8 + s->mb_y*s->uvlinesize*chr_h, + 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); } if(s->loop_filter){ @@ -3481,9 +3492,12 @@ static int encode_thread(AVCodecContext *c, void *arg){ } } +#if CONFIG_MSMPEG4ENC //not beautiful here but we must write it before flushing so it has to be here - if (CONFIG_MSMPEG4ENC && s->msmpeg4_version && s->msmpeg4_version<4 && s->pict_type == AV_PICTURE_TYPE_I) + if (s->msmpeg4_version != MSMP4_UNUSED && s->msmpeg4_version < MSMP4_WMV1 && + s->pict_type == AV_PICTURE_TYPE_I) ff_msmpeg4_encode_ext_header(s); +#endif write_slice_end(s); @@ -3506,7 +3520,6 @@ static void merge_context_after_encode(MpegEncContext *dst, MpegEncContext *src) MERGE(i_tex_bits); MERGE(p_tex_bits); MERGE(i_count); - MERGE(skip_count); MERGE(misc_bits); MERGE(encoding_error[0]); MERGE(encoding_error[1]); @@ -3527,18 +3540,18 @@ static void merge_context_after_encode(MpegEncContext *dst, MpegEncContext *src) static int estimate_qp(MpegEncContext *s, int dry_run){ if (s->next_lambda){ - s->current_picture_ptr->f->quality = - s->current_picture.f->quality = 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->current_picture_ptr->f->quality = - s->current_picture.f->quality = quality; - if (s->current_picture.f->quality < 0) + s->cur_pic.ptr->f->quality = quality; + if (s->cur_pic.ptr->f->quality < 0) return -1; } if(s->adaptive_quant){ + init_qscale_tab(s); + switch(s->codec_id){ case AV_CODEC_ID_MPEG4: if (CONFIG_MPEG4_ENCODER) @@ -3550,22 +3563,20 @@ static int estimate_qp(MpegEncContext *s, int dry_run){ if (CONFIG_H263_ENCODER) ff_clean_h263_qscales(s); break; - default: - ff_init_qscale_tab(s); } s->lambda= s->lambda_table[0]; //FIXME broken }else - s->lambda = s->current_picture.f->quality; + s->lambda = s->cur_pic.ptr->f->quality; update_qscale(s); return 0; } /* must be called before writing the header */ static void set_frame_distances(MpegEncContext * s){ - av_assert1(s->current_picture_ptr->f->pts != AV_NOPTS_VALUE); - s->time = s->current_picture_ptr->f->pts * s->avctx->time_base.num; + av_assert1(s->cur_pic.ptr->f->pts != AV_NOPTS_VALUE); + s->time = s->cur_pic.ptr->f->pts * s->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); @@ -3577,7 +3588,7 @@ static void set_frame_distances(MpegEncContext * s){ } } -static int encode_picture(MpegEncContext *s) +static int encode_picture(MpegEncContext *s, const AVPacket *pkt) { int i, ret; int bits; @@ -3589,21 +3600,19 @@ static int encode_picture(MpegEncContext *s) /* 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)) + if (s->out_format == FMT_MPEG1 || (s->h263_pred && s->msmpeg4_version == MSMP4_UNUSED)) set_frame_distances(s); if(CONFIG_MPEG4_ENCODER && s->codec_id == AV_CODEC_ID_MPEG4) ff_set_mpeg4_time(s); s->me.scene_change_score=0; -// s->lambda= s->current_picture_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){ - if(s->msmpeg4_version >= 3) s->no_rounding=1; - else s->no_rounding=0; + s->no_rounding = s->msmpeg4_version >= MSMP4_V3; }else if(s->pict_type!=AV_PICTURE_TYPE_B){ - if(s->flipflop_rounding || s->codec_id == AV_CODEC_ID_H263P || s->codec_id == AV_CODEC_ID_MPEG4) - s->no_rounding ^= 1; + s->no_rounding ^= s->flipflop_rounding; } if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { @@ -3625,15 +3634,27 @@ static int encode_picture(MpegEncContext *s) s->q_chroma_intra_matrix16 = s->q_intra_matrix16; } - s->mb_intra=0; //for the rate distortion & bit compare functions - for(i=1; ithread_context[i], s); - if (ret < 0) - return ret; - } + ff_me_init_pic(s); - if(ff_init_me(s)<0) - return -1; + s->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; + + if (i) { + ret = ff_update_duplicate_context(slice, s); + if (ret < 0) + return ret; + } + 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); + } /* Estimate motion for every MB */ if(s->pict_type != AV_PICTURE_TYPE_I){ @@ -3669,7 +3690,7 @@ static int encode_picture(MpegEncContext *s) 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 >= 3) + 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); @@ -3784,18 +3805,14 @@ static int encode_picture(MpegEncContext *s) } } - //FIXME var duplication if (s->pict_type == AV_PICTURE_TYPE_I) { - s->current_picture_ptr->f->flags |= AV_FRAME_FLAG_KEY; //FIXME pic_ptr - s->current_picture.f->flags |= AV_FRAME_FLAG_KEY; + s->cur_pic.ptr->f->flags |= AV_FRAME_FLAG_KEY; } else { - s->current_picture_ptr->f->flags &= ~AV_FRAME_FLAG_KEY; //FIXME pic_ptr - s->current_picture.f->flags &= ~AV_FRAME_FLAG_KEY; + s->cur_pic.ptr->f->flags &= ~AV_FRAME_FLAG_KEY; } - s->current_picture_ptr->f->pict_type = - s->current_picture.f->pict_type = s->pict_type; + s->cur_pic.ptr->f->pict_type = s->pict_type; - if (s->current_picture.f->flags & AV_FRAME_FLAG_KEY) + if (s->cur_pic.ptr->f->flags & AV_FRAME_FLAG_KEY) s->picture_in_gop_number=0; s->mb_x = s->mb_y = 0; @@ -3817,8 +3834,10 @@ static int encode_picture(MpegEncContext *s) case FMT_H263: if (CONFIG_WMV2_ENCODER && s->codec_id == AV_CODEC_ID_WMV2) ff_wmv2_encode_picture_header(s); - else if (CONFIG_MSMPEG4ENC && s->msmpeg4_version) +#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) @@ -3905,8 +3924,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s, int coeff_count[64]; int qmul, qadd, start_i, last_non_zero, i, dc; const int esc_length= s->ac_esc_length; - uint8_t * length; - uint8_t * last_length; + const uint8_t *length, *last_length; const int lambda= s->lambda2 >> (FF_LAMBDA_SHIFT - 6); int mpeg2_qscale; @@ -4229,8 +4247,8 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? int prev_run=0; int prev_level=0; int qmul, qadd, start_i, last_non_zero, i, dc; - uint8_t * length; - uint8_t * last_length; + 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 @@ -4543,7 +4561,7 @@ static int dct_quantize_refine(MpegEncContext *s, //FIXME breaks denoise? * permutation up, the block is not (inverse) permutated * to scantable order! */ -void ff_block_permute(int16_t *block, uint8_t *permutation, +void ff_block_permute(int16_t *block, const uint8_t *permutation, const uint8_t *scantable, int last) { int i; @@ -4568,9 +4586,9 @@ void ff_block_permute(int16_t *block, uint8_t *permutation, } } -int ff_dct_quantize_c(MpegEncContext *s, - int16_t *block, int n, - int qscale, int *overflow) +static int dct_quantize_c(MpegEncContext *s, + int16_t *block, int n, + int qscale, int *overflow) { int i, j, level, last_non_zero, q, start_i; const int *qmat; diff --git a/libavcodec/mpegvideo_motion.c b/libavcodec/mpegvideo_motion.c index 8922f5b1a..6e9368dd9 100644 --- a/libavcodec/mpegvideo_motion.c +++ b/libavcodec/mpegvideo_motion.c @@ -38,7 +38,7 @@ static inline int hpel_motion(MpegEncContext *s, uint8_t *dest, uint8_t *src, int src_x, int src_y, - op_pixels_func *pix_op, + const op_pixels_func *pix_op, int motion_x, int motion_y) { int dxy = 0; @@ -79,7 +79,7 @@ void mpeg_motion_internal(MpegEncContext *s, int bottom_field, int field_select, uint8_t *const *ref_picture, - op_pixels_func (*pix_op)[4], + const op_pixels_func (*pix_op)[4], int motion_x, int motion_y, int h, @@ -93,8 +93,8 @@ void mpeg_motion_internal(MpegEncContext *s, ptrdiff_t uvlinesize, linesize; v_edge_pos = s->v_edge_pos >> field_based; - linesize = s->current_picture.f->linesize[0] << field_based; - uvlinesize = s->current_picture.f->linesize[1] << field_based; + linesize = s->cur_pic.linesize[0] << field_based; + uvlinesize = s->cur_pic.linesize[1] << field_based; block_y_half = (field_based | is_16x8); dxy = ((motion_y & 1) << 1) | (motion_x & 1); @@ -114,13 +114,16 @@ void mpeg_motion_internal(MpegEncContext *s, uvsrc_y = src_y >> 1; } // Even chroma mv's are full pel in H261 - } else if (!is_mpeg12 && s->out_format == FMT_H261) { + } else if (!CONFIG_SMALL && !is_mpeg12 || + CONFIG_SMALL && s->out_format == FMT_H261) { + av_assert2(s->out_format == FMT_H261); mx = motion_x / 4; my = motion_y / 4; uvdxy = 0; uvsrc_x = s->mb_x * 8 + mx; uvsrc_y = mb_y * 8 + my; } else { + av_assert2(s->out_format == FMT_MPEG1); if (s->chroma_y_shift) { mx = motion_x / 2; my = motion_y / 2; @@ -216,7 +219,7 @@ void mpeg_motion_internal(MpegEncContext *s, static void mpeg_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int field_select, uint8_t *const *ref_picture, - op_pixels_func (*pix_op)[4], + const op_pixels_func (*pix_op)[4], int motion_x, int motion_y, int h, int is_16x8, int mb_y) { #if !CONFIG_SMALL @@ -235,23 +238,23 @@ static void mpeg_motion_field(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int bottom_field, int field_select, uint8_t *const *ref_picture, - op_pixels_func (*pix_op)[4], - int motion_x, int motion_y, int h, int mb_y) + const op_pixels_func (*pix_op)[4], + int motion_x, int motion_y, int mb_y) { #if !CONFIG_SMALL if (s->out_format == FMT_MPEG1) mpeg_motion_internal(s, dest_y, dest_cb, dest_cr, 1, bottom_field, field_select, ref_picture, pix_op, - motion_x, motion_y, h, 1, 0, mb_y); + motion_x, motion_y, 8, 1, 0, mb_y); else #endif mpeg_motion_internal(s, dest_y, dest_cb, dest_cr, 1, bottom_field, field_select, ref_picture, pix_op, - motion_x, motion_y, h, 0, 0, mb_y); + motion_x, motion_y, 8, 0, 0, mb_y); } // FIXME: SIMDify, avg variant, 16x16 version -static inline void put_obmc(uint8_t *dst, uint8_t *src[5], int stride) +static inline void put_obmc(uint8_t *dst, uint8_t *const src[5], int stride) { int x; uint8_t *const top = src[1]; @@ -307,7 +310,7 @@ static inline void put_obmc(uint8_t *dst, uint8_t *src[5], int stride) static inline void obmc_motion(MpegEncContext *s, uint8_t *dest, uint8_t *src, int src_x, int src_y, - op_pixels_func *pix_op, + const op_pixels_func *pix_op, int16_t mv[5][2] /* mid top left right bottom */) #define MID 0 { @@ -336,8 +339,8 @@ static inline void qpel_motion(MpegEncContext *s, uint8_t *dest_cr, int field_based, int bottom_field, int field_select, uint8_t *const *ref_picture, - op_pixels_func (*pix_op)[4], - qpel_mc_func (*qpix_op)[16], + const op_pixels_func (*pix_op)[4], + const qpel_mc_func (*qpix_op)[16], int motion_x, int motion_y, int h) { const uint8_t *ptr_y, *ptr_cb, *ptr_cr; @@ -440,7 +443,7 @@ static inline void qpel_motion(MpegEncContext *s, static void chroma_4mv_motion(MpegEncContext *s, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t *const *ref_picture, - op_pixels_func *pix_op, + const op_pixels_func *pix_op, int mx, int my) { const uint8_t *ptr; @@ -508,10 +511,10 @@ static inline void apply_obmc(MpegEncContext *s, uint8_t *dest_cb, uint8_t *dest_cr, uint8_t *const *ref_picture, - op_pixels_func (*pix_op)[4]) + const op_pixels_func (*pix_op)[4]) { LOCAL_ALIGNED_8(int16_t, mv_cache, [4], [4][2]); - const Picture *cur_frame = &s->current_picture; + const MPVWorkPicture *cur_frame = &s->cur_pic; int mb_x = s->mb_x; int mb_y = s->mb_y; const int xy = mb_x + mb_y * s->mb_stride; @@ -596,8 +599,8 @@ static inline void apply_8x8(MpegEncContext *s, uint8_t *dest_cr, int dir, uint8_t *const *ref_picture, - qpel_mc_func (*qpix_op)[16], - op_pixels_func (*pix_op)[4]) + const qpel_mc_func (*qpix_op)[16], + const op_pixels_func (*pix_op)[4]) { int dxy, mx, my, src_x, src_y; int i; @@ -681,8 +684,8 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, uint8_t *dest_cr, int dir, uint8_t *const *ref_picture, - op_pixels_func (*pix_op)[4], - qpel_mc_func (*qpix_op)[16], + const op_pixels_func (*pix_op)[4], + const qpel_mc_func (*qpix_op)[16], int is_mpeg12) { int i; @@ -719,7 +722,11 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, dir, ref_picture, qpix_op, pix_op); break; case MV_TYPE_FIELD: - if (s->picture_structure == PICT_FRAME) { + // Only MPEG-1/2 can have a picture_structure != PICT_FRAME here. + if (!CONFIG_SMALL) + av_assert2(is_mpeg12 || s->picture_structure == PICT_FRAME); + if ((!CONFIG_SMALL && !is_mpeg12) || + s->picture_structure == PICT_FRAME) { if (!is_mpeg12 && s->quarter_sample) { for (i = 0; i < 2; i++) qpel_motion(s, dest_y, dest_cb, dest_cr, @@ -731,17 +738,18 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, mpeg_motion_field(s, dest_y, dest_cb, dest_cr, 0, s->field_select[dir][0], ref_picture, pix_op, - s->mv[dir][0][0], s->mv[dir][0][1], 8, mb_y); + s->mv[dir][0][0], s->mv[dir][0][1], mb_y); /* bottom field */ mpeg_motion_field(s, dest_y, dest_cb, dest_cr, 1, s->field_select[dir][1], ref_picture, pix_op, - s->mv[dir][1][0], s->mv[dir][1][1], 8, mb_y); + s->mv[dir][1][0], s->mv[dir][1][1], mb_y); } } else { - if ( s->picture_structure != s->field_select[dir][0] + 1 && s->pict_type != AV_PICTURE_TYPE_B && !s->first_field - || !ref_picture[0]) { - ref_picture = s->current_picture_ptr->f->data; + av_assert2(s->out_format == FMT_MPEG1); + if (s->picture_structure != s->field_select[dir][0] + 1 && + s->pict_type != AV_PICTURE_TYPE_B && !s->first_field) { + ref_picture = s->cur_pic.ptr->f->data; } mpeg_motion(s, dest_y, dest_cb, dest_cr, @@ -755,12 +763,11 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, for (i = 0; i < 2; i++) { uint8_t *const *ref2picture; - if ((s->picture_structure == s->field_select[dir][i] + 1 || - s->pict_type == AV_PICTURE_TYPE_B || s->first_field) && - ref_picture[0]) { + if (s->picture_structure == s->field_select[dir][i] + 1 || + s->pict_type == AV_PICTURE_TYPE_B || s->first_field) { ref2picture = ref_picture; } else { - ref2picture = s->current_picture_ptr->f->data; + ref2picture = s->cur_pic.ptr->f->data; } mpeg_motion(s, dest_y, dest_cb, dest_cr, @@ -783,13 +790,10 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, mpeg_motion_field(s, dest_y, dest_cb, dest_cr, j, j ^ i, ref_picture, pix_op, s->mv[dir][2 * i + j][0], - s->mv[dir][2 * i + j][1], 8, mb_y); + s->mv[dir][2 * i + j][1], mb_y); pix_op = s->hdsp.avg_pixels_tab; } } else { - if (!ref_picture[0]) { - ref_picture = s->current_picture_ptr->f->data; - } for (i = 0; i < 2; i++) { mpeg_motion(s, dest_y, dest_cb, dest_cr, s->picture_structure != i + 1, @@ -803,7 +807,7 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, /* opposite parity is always in the same frame if this is * second field */ if (!s->first_field) - ref_picture = s->current_picture_ptr->f->data; + ref_picture = s->cur_pic.ptr->f->data; } } break; @@ -816,9 +820,12 @@ void ff_mpv_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int dir, uint8_t *const *ref_picture, - op_pixels_func (*pix_op)[4], - qpel_mc_func (*qpix_op)[16]) + const op_pixels_func (*pix_op)[4], + const qpel_mc_func (*qpix_op)[16]) { + av_assert2(s->out_format == FMT_MPEG1 || + s->out_format == FMT_H263 || + s->out_format == FMT_H261); prefetch_motion(s, ref_picture, dir); #if !CONFIG_SMALL diff --git a/libavcodec/mpegvideodec.h b/libavcodec/mpegvideodec.h index 0b841bc1a..610036471 100644 --- a/libavcodec/mpegvideodec.h +++ b/libavcodec/mpegvideodec.h @@ -44,22 +44,30 @@ * Initialize the given MpegEncContext for decoding. * the changed fields will not depend upon * the prior state of the MpegEncContext. + * + * Also initialize the picture pool. */ -void ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx); +int ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx); int ff_mpv_common_frame_size_change(MpegEncContext *s); 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_frame_end(MpegEncContext *s); -int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, const Picture *p, int qp_type); +int ff_mpv_export_qp_table(const MpegEncContext *s, AVFrame *f, + const MPVPicture *p, int qp_type); 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); +int ff_mpv_decode_close(AVCodecContext *avctx); -void ff_print_debug_info(const MpegEncContext *s, const Picture *p, AVFrame *pict); +void ff_print_debug_info(const MpegEncContext *s, const MPVPicture *p, AVFrame *pict); static inline int mpeg_get_qscale(MpegEncContext *s) { diff --git a/libavcodec/mpegvideoenc.h b/libavcodec/mpegvideoenc.h index 1e2978266..f5044a030 100644 --- a/libavcodec/mpegvideoenc.h +++ b/libavcodec/mpegvideoenc.h @@ -34,6 +34,25 @@ #include "mpegvideo.h" #define UNI_AC_ENC_INDEX(run,level) ((run)*128 + (level)) +#define INPLACE_OFFSET 16 + +/* MB types for encoding */ +#define CANDIDATE_MB_TYPE_INTRA (1 << 0) +#define CANDIDATE_MB_TYPE_INTER (1 << 1) +#define CANDIDATE_MB_TYPE_INTER4V (1 << 2) +#define CANDIDATE_MB_TYPE_SKIPPED (1 << 3) + +#define CANDIDATE_MB_TYPE_DIRECT (1 << 4) +#define CANDIDATE_MB_TYPE_FORWARD (1 << 5) +#define CANDIDATE_MB_TYPE_BACKWARD (1 << 6) +#define CANDIDATE_MB_TYPE_BIDIR (1 << 7) + +#define CANDIDATE_MB_TYPE_INTER_I (1 << 8) +#define CANDIDATE_MB_TYPE_FORWARD_I (1 << 9) +#define CANDIDATE_MB_TYPE_BACKWARD_I (1 << 10) +#define CANDIDATE_MB_TYPE_BIDIR_I (1 << 11) + +#define CANDIDATE_MB_TYPE_DIRECT0 (1 << 12) /* mpegvideo_enc common options */ #define FF_MPV_FLAG_SKIP_RD 0x0001 @@ -126,14 +145,14 @@ int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t s void ff_write_quant_matrix(PutBitContext *pb, uint16_t *matrix); -int ff_dct_encode_init(MpegEncContext *s); +void ff_dct_encode_init(MpegEncContext *s); +void ff_mpvenc_dct_init_mips(MpegEncContext *s); void ff_dct_encode_init_x86(MpegEncContext *s); -int ff_dct_quantize_c(MpegEncContext *s, int16_t *block, int n, int qscale, int *overflow); void ff_convert_matrix(MpegEncContext *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, uint8_t *permutation, +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) diff --git a/libavcodec/mpegvideoencdsp.c b/libavcodec/mpegvideoencdsp.c index 997d04866..5e4c446d9 100644 --- a/libavcodec/mpegvideoencdsp.c +++ b/libavcodec/mpegvideoencdsp.c @@ -57,7 +57,7 @@ static void add_8x8basis_c(int16_t rem[64], const int16_t basis[64], int scale) (BASIS_SHIFT - RECON_SHIFT); } -static int pix_sum_c(const uint8_t *pix, int line_size) +static int pix_sum_c(const uint8_t *pix, ptrdiff_t line_size) { int s = 0, i, j; @@ -78,7 +78,7 @@ static int pix_sum_c(const uint8_t *pix, int line_size) return s; } -static int pix_norm1_c(const uint8_t *pix, int line_size) +static int pix_norm1_c(const uint8_t *pix, ptrdiff_t line_size) { int s = 0, i, j; const uint32_t *sq = ff_square_tab + 256; @@ -114,20 +114,32 @@ static int pix_norm1_c(const uint8_t *pix, int line_size) return s; } -/* draw the edges of width 'w' of an image of size width, height */ -// FIXME: Check that this is OK for MPEG-4 interlaced. -static void draw_edges_8_c(uint8_t *buf, int wrap, int width, int height, - int w, int h, int sides) +static av_always_inline void draw_edges_lr(uint8_t *ptr, ptrdiff_t wrap, int width, int height, int w) { - uint8_t *ptr = buf, *last_line; - int i; - - /* left and right */ - for (i = 0; i < height; i++) { + for (int i = 0; i < height; i++) { memset(ptr - w, ptr[0], w); memset(ptr + width, ptr[width - 1], w); ptr += wrap; } +} + +/* draw the edges of width 'w' of an image of size width, height */ +// FIXME: Check that this is OK for MPEG-4 interlaced. +static void draw_edges_8_c(uint8_t *buf, ptrdiff_t wrap, int width, int height, + int w, int h, int sides) +{ + uint8_t *last_line; + int i; + + /* left and right */ + if (w == 16) { + draw_edges_lr(buf, wrap, width, height, 16); + } else if (w == 8) { + draw_edges_lr(buf, wrap, width, height, 8); + } else { + av_assert1(w == 4); + draw_edges_lr(buf, wrap, width, height, 4); + } /* top and bottom + corners */ buf -= w; @@ -142,9 +154,18 @@ static void draw_edges_8_c(uint8_t *buf, int wrap, int width, int height, memcpy(last_line + (i + 1) * wrap, last_line, width + w + w); } +/* This wrapper function only serves to convert the stride parameters + * from ptrdiff_t to int for av_image_copy_plane(). */ +static void copy_plane_wrapper(uint8_t *dst, ptrdiff_t dst_wrap, + const uint8_t *src, ptrdiff_t src_wrap, + int width, int height) +{ + av_image_copy_plane(dst, dst_wrap, src, src_wrap, width, height); +} + /* 2x2 -> 1x1 */ -static void shrink22(uint8_t *dst, int dst_wrap, - const uint8_t *src, int src_wrap, +static void shrink22(uint8_t *dst, ptrdiff_t dst_wrap, + const uint8_t *src, ptrdiff_t src_wrap, int width, int height) { int w; @@ -176,8 +197,8 @@ static void shrink22(uint8_t *dst, int dst_wrap, } /* 4x4 -> 1x1 */ -static void shrink44(uint8_t *dst, int dst_wrap, - const uint8_t *src, int src_wrap, +static void shrink44(uint8_t *dst, ptrdiff_t dst_wrap, + const uint8_t *src, ptrdiff_t src_wrap, int width, int height) { int w; @@ -207,8 +228,8 @@ static void shrink44(uint8_t *dst, int dst_wrap, } /* 8x8 -> 1x1 */ -static void shrink88(uint8_t *dst, int dst_wrap, - const uint8_t *src, int src_wrap, +static void shrink88(uint8_t *dst, ptrdiff_t dst_wrap, + const uint8_t *src, ptrdiff_t src_wrap, int width, int height) { int w, i; @@ -235,7 +256,7 @@ av_cold void ff_mpegvideoencdsp_init(MpegvideoEncDSPContext *c, c->try_8x8basis = try_8x8basis_c; c->add_8x8basis = add_8x8basis_c; - c->shrink[0] = av_image_copy_plane; + c->shrink[0] = copy_plane_wrapper; c->shrink[1] = shrink22; c->shrink[2] = shrink44; c->shrink[3] = shrink88; @@ -245,10 +266,14 @@ av_cold void ff_mpegvideoencdsp_init(MpegvideoEncDSPContext *c, c->draw_edges = draw_edges_8_c; -#if ARCH_ARM +#if ARCH_AARCH64 + ff_mpegvideoencdsp_init_aarch64(c, avctx); +#elif ARCH_ARM ff_mpegvideoencdsp_init_arm(c, avctx); #elif ARCH_PPC ff_mpegvideoencdsp_init_ppc(c, avctx); +#elif ARCH_RISCV + ff_mpegvideoencdsp_init_riscv(c, avctx); #elif ARCH_X86 ff_mpegvideoencdsp_init_x86(c, avctx); #elif ARCH_MIPS diff --git a/libavcodec/mpegvideoencdsp.h b/libavcodec/mpegvideoencdsp.h index 95084679d..6ec665677 100644 --- a/libavcodec/mpegvideoencdsp.h +++ b/libavcodec/mpegvideoencdsp.h @@ -34,22 +34,26 @@ typedef struct MpegvideoEncDSPContext { const int16_t basis[64], int scale); void (*add_8x8basis)(int16_t rem[64], const int16_t basis[64], int scale); - int (*pix_sum)(const uint8_t *pix, int line_size); - int (*pix_norm1)(const uint8_t *pix, int line_size); + int (*pix_sum)(const uint8_t *pix, ptrdiff_t line_size); + int (*pix_norm1)(const uint8_t *pix, ptrdiff_t line_size); - void (*shrink[4])(uint8_t *dst, int dst_wrap, const uint8_t *src, - int src_wrap, int width, int height); + void (*shrink[4])(uint8_t *dst, ptrdiff_t dst_wrap, const uint8_t *src, + ptrdiff_t src_wrap, int width, int height); - void (*draw_edges)(uint8_t *buf, int wrap, int width, int height, + void (*draw_edges)(uint8_t *buf, ptrdiff_t wrap, int width, int height, int w, int h, int sides); } MpegvideoEncDSPContext; void ff_mpegvideoencdsp_init(MpegvideoEncDSPContext *c, AVCodecContext *avctx); +void ff_mpegvideoencdsp_init_aarch64(MpegvideoEncDSPContext *c, + AVCodecContext *avctx); void ff_mpegvideoencdsp_init_arm(MpegvideoEncDSPContext *c, AVCodecContext *avctx); void ff_mpegvideoencdsp_init_ppc(MpegvideoEncDSPContext *c, AVCodecContext *avctx); +void ff_mpegvideoencdsp_init_riscv(MpegvideoEncDSPContext *c, + AVCodecContext *avctx); void ff_mpegvideoencdsp_init_x86(MpegvideoEncDSPContext *c, AVCodecContext *avctx); void ff_mpegvideoencdsp_init_mips(MpegvideoEncDSPContext *c, diff --git a/libavcodec/mpv_reconstruct_mb_template.c b/libavcodec/mpv_reconstruct_mb_template.c index 6f7a5fb1b..dca982ae0 100644 --- a/libavcodec/mpv_reconstruct_mb_template.c +++ b/libavcodec/mpv_reconstruct_mb_template.c @@ -20,9 +20,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define NOT_MPEG12 0 -#define MAY_BE_MPEG12 1 -#define DEFINITELY_MPEG12 2 +#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, @@ -56,14 +56,14 @@ 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(s) (is_mpeg12 == MAY_BE_MPEG12 ? ((s)->out_format == FMT_MPEG1) : 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->current_picture.qscale_table[mb_xy] = s->qscale; + s->cur_pic.qscale_table[mb_xy] = s->qscale; /* update DC predictors for P macroblocks */ if (!s->mb_intra) { - if (is_mpeg12 != DEFINITELY_MPEG12 && (s->h263_pred || s->h263_aic)) { + 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 { @@ -71,7 +71,7 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], s->last_dc[1] = s->last_dc[2] = 128 << s->intra_dc_precision; } - } else if (is_mpeg12 != DEFINITELY_MPEG12 && (s->h263_pred || s->h263_aic)) + } else if (is_mpeg12 != DEFINITELY_MPEG12_H261 && (s->h263_pred || s->h263_aic)) s->mbintra_table[mb_xy] = 1; #if IS_ENCODER @@ -80,11 +80,10 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], s->avctx->mb_decision != FF_MB_DECISION_RD)) // FIXME precalc #endif /* IS_ENCODER */ { - uint8_t *dest_y, *dest_cb, *dest_cr; + 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->current_picture.f->linesize[0]; //not s->linesize as this would be wrong for field pics - const int uvlinesize = s->current_picture.f->linesize[1]; - const int readable = IS_ENCODER || lowres_flag || s->pict_type != AV_PICTURE_TYPE_B; + 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 */ @@ -96,7 +95,7 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], s->mb_skipped = 0; av_assert2(s->pict_type!=AV_PICTURE_TYPE_I); *mbskip_ptr = 1; - } else if(!s->current_picture.reference) { + } else if (!s->cur_pic.reference) { *mbskip_ptr = 1; } else{ *mbskip_ptr = 0; /* not skipped */ @@ -106,30 +105,20 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], dct_linesize = linesize << s->interlaced_dct; dct_offset = s->interlaced_dct ? linesize : linesize * block_size; - if (readable) { - dest_y = s->dest[0]; - dest_cb = s->dest[1]; - dest_cr = s->dest[2]; - } else { - dest_y = s->sc.b_scratchpad; - dest_cb = s->sc.b_scratchpad + 16 * linesize; - dest_cr = s->sc.b_scratchpad + 32 * linesize; - } - 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 && + 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_await_progress(&s->last_picture_ptr->tf, - lowest_referenced_row(s, 0), 0); + ff_thread_progress_await(&s->last_pic.ptr->progress, + lowest_referenced_row(s, 0)); } if (s->mv_dir & MV_DIR_BACKWARD) { - ff_thread_await_progress(&s->next_picture_ptr->tf, - lowest_referenced_row(s, 1), 0); + ff_thread_progress_await(&s->next_pic.ptr->progress, + lowest_referenced_row(s, 1)); } } @@ -137,17 +126,17 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], 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_picture.f->data, op_pix); + 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_picture.f->data, op_pix); + MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix); } } else { - op_pixels_func (*op_pix)[4]; - qpel_mc_func (*op_qpix)[16]; + const op_pixels_func (*op_pix)[4]; + const qpel_mc_func (*op_qpix)[16]; - if ((is_mpeg12 == DEFINITELY_MPEG12 || !s->no_rounding) || s->pict_type == AV_PICTURE_TYPE_B) { + 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 { @@ -155,12 +144,12 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], 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_picture.f->data, op_pix, op_qpix); + 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_picture.f->data, op_pix, op_qpix); + ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 1, s->next_pic.data, op_pix, op_qpix); } } @@ -169,11 +158,11 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], 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) - goto skip_idct; + return; } /* add dct residue */ - if (!(IS_MPEG12(s) || s->msmpeg4_version || + if (!(IS_MPEG12_H261(s) || s->msmpeg4_version != MSMP4_UNUSED || (s->codec_id == AV_CODEC_ID_MPEG4 && !s->mpeg_quant))) #endif /* !IS_ENCODER */ { @@ -183,7 +172,8 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], 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)) { - if (s->chroma_y_shift) { + 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 { @@ -197,7 +187,7 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], } } #if !IS_ENCODER - else if (is_mpeg12 == DEFINITELY_MPEG12 || (s->codec_id != AV_CODEC_ID_WMV2)) { + 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); @@ -232,12 +222,12 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], #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 && CONFIG_MPEG4_DECODER && + 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(s)) + } else if (!IS_MPEG12_H261(s)) #endif /* !IS_ENCODER */ { /* dct only in intra block */ @@ -288,14 +278,6 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], } } //gray } - } -skip_idct: - if (!readable) { - s->hdsp.put_pixels_tab[0][0](s->dest[0], dest_y, linesize, 16); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - s->hdsp.put_pixels_tab[s->chroma_x_shift][0](s->dest[1], dest_cb, uvlinesize, 16 >> s->chroma_y_shift); - s->hdsp.put_pixels_tab[s->chroma_x_shift][0](s->dest[2], dest_cr, uvlinesize, 16 >> s->chroma_y_shift); - } #endif /* !IS_ENCODER */ } } diff --git a/libavcodec/mscc.c b/libavcodec/mscc.c index e467b48ba..6d57f1b62 100644 --- a/libavcodec/mscc.c +++ b/libavcodec/mscc.c @@ -23,6 +23,7 @@ #include #include +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" @@ -148,28 +149,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if (avpkt->size < 3) return buf_size; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - return ret; - - if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { - size_t size; - 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); - } - memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); - } - ret = inflateReset(zstream); if (ret != Z_OK) { av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret); @@ -197,6 +176,27 @@ inflate_error: av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret); return AVERROR_UNKNOWN; } + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { + size_t size; + 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); + } + memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); + } bytestream2_init(&gb, s->decomp_buf, zstream->total_out); bytestream2_init_writer(&pb, s->uncomp_buf, s->uncomp_size); @@ -210,9 +210,6 @@ inflate_error: s->uncomp_buf + s->bpp * j * avctx->width, s->bpp * avctx->width); } - frame->flags |= AV_FRAME_FLAG_KEY; - frame->pict_type = AV_PICTURE_TYPE_I; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/msmpeg4.c b/libavcodec/msmpeg4.c index a2c4c5772..872dc8db6 100644 --- a/libavcodec/msmpeg4.c +++ b/libavcodec/msmpeg4.c @@ -27,17 +27,20 @@ * MSMPEG4 backend for encoder and decoder */ +#include "config.h" + #include "libavutil/thread.h" +#if ARCH_X86 +#include "libavutil/x86/asm.h" +#endif #include "avcodec.h" #include "idctdsp.h" #include "mpegvideo.h" #include "msmpeg4.h" -#include "libavutil/x86/asm.h" #include "mpeg4videodata.h" #include "msmpeg4data.h" #include "msmpeg4_vc1_data.h" -#include "mpegvideodata.h" /* * You can also call this codec: MPEG-4 with a twist! @@ -116,12 +119,11 @@ av_cold void ff_msmpeg4_common_init(MpegEncContext *s) static AVOnce init_static_once = AV_ONCE_INIT; switch(s->msmpeg4_version){ - case 1: - case 2: - s->y_dc_scale_table= - s->c_dc_scale_table= ff_mpeg1_dc_scale_table; + case MSMP4_V1: + case MSMP4_V2: + // Correct *_dc_scale_tables (ff_mpeg1_dc_scale_table) is the default break; - case 3: + case MSMP4_V3: if(s->workaround_bugs){ s->y_dc_scale_table= ff_old_ff_y_dc_scale_table; s->c_dc_scale_table= ff_wmv1_c_dc_scale_table; @@ -130,14 +132,14 @@ av_cold void ff_msmpeg4_common_init(MpegEncContext *s) s->c_dc_scale_table= ff_mpeg4_c_dc_scale_table; } break; - case 4: - case 5: + case MSMP4_WMV1: + case MSMP4_WMV2: 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>=4){ + 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], @@ -214,9 +216,8 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n, b = dc_val[ - 1 - wrap]; c = dc_val[ - wrap]; - if(s->first_slice_line && (n&2)==0 && s->msmpeg4_version<4){ + if (s->first_slice_line && !(n & 2) && s->msmpeg4_version < MSMP4_WMV1) b=c=1024; - } /* XXX: the following solution consumes divisions, but it does not necessitate to modify mpegvideo.c. The problem comes from the @@ -255,7 +256,7 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n, #endif /* XXX: WARNING: they did not choose the same test as MPEG-4. This is very important ! */ - if(s->msmpeg4_version>3){ + if (s->msmpeg4_version > MSMP4_V3) { if(s->inter_intra_pred){ uint8_t *dest; int wrap; @@ -278,10 +279,10 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n, int bs = 8 >> s->avctx->lowres; if(n<4){ wrap= s->linesize; - dest= s->current_picture.f->data[0] + (((n >> 1) + 2*s->mb_y) * bs* wrap ) + ((n & 1) + 2*s->mb_x) * bs; + dest = s->cur_pic.data[0] + (((n >> 1) + 2*s->mb_y) * bs* wrap ) + ((n & 1) + 2*s->mb_x) * bs; }else{ wrap= s->uvlinesize; - dest= s->current_picture.f->data[n - 3] + (s->mb_y * bs * wrap) + s->mb_x * bs; + dest = s->cur_pic.data[n - 3] + (s->mb_y * bs * wrap) + s->mb_x * bs; } if(s->mb_x==0) a= (1024 + (scale>>1))/scale; else a= get_dc(dest-bs, wrap, scale*8>>(2*s->avctx->lowres), bs); diff --git a/libavcodec/msmpeg4dec.c b/libavcodec/msmpeg4dec.c index bf1e4877b..12bef4f50 100644 --- a/libavcodec/msmpeg4dec.c +++ b/libavcodec/msmpeg4dec.c @@ -28,6 +28,7 @@ #include "codec_internal.h" #include "mpegutils.h" #include "mpegvideo.h" +#include "mpegvideodec.h" #include "msmpeg4.h" #include "msmpeg4dec.h" #include "libavutil/imgutils.h" @@ -105,7 +106,7 @@ static int msmpeg4v2_decode_motion(MpegEncContext * s, int pred, int f_code) static int msmpeg4v12_decode_mb(MpegEncContext *s, int16_t block[6][64]) { int cbp, code, i; - uint32_t * const mb_type_ptr = &s->current_picture.mb_type[s->mb_x + s->mb_y*s->mb_stride]; + uint32_t * const mb_type_ptr = &s->cur_pic.mb_type[s->mb_x + s->mb_y*s->mb_stride]; if (s->pict_type == AV_PICTURE_TYPE_P) { if (s->use_skip_mb_code) { @@ -119,12 +120,12 @@ static int msmpeg4v12_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv[0][0][0] = 0; s->mv[0][0][1] = 0; s->mb_skipped = 1; - *mb_type_ptr = MB_TYPE_SKIP | MB_TYPE_L0 | MB_TYPE_16x16; + *mb_type_ptr = MB_TYPE_SKIP | MB_TYPE_FORWARD_MV | MB_TYPE_16x16; return 0; } } - if(s->msmpeg4_version==2) + if (s->msmpeg4_version == MSMP4_V2) code = get_vlc2(&s->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); @@ -138,7 +139,7 @@ static int msmpeg4v12_decode_mb(MpegEncContext *s, int16_t block[6][64]) cbp = code & 0x3; } else { s->mb_intra = 1; - if(s->msmpeg4_version==2) + if (s->msmpeg4_version == MSMP4_V2) cbp = get_vlc2(&s->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); @@ -158,7 +159,8 @@ static int msmpeg4v12_decode_mb(MpegEncContext *s, int16_t block[6][64]) } cbp|= cbpy<<2; - if(s->msmpeg4_version==1 || (cbp&3) != 3) cbp^= 0x3C; + if (s->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); @@ -168,10 +170,10 @@ static int msmpeg4v12_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv_type = MV_TYPE_16X16; s->mv[0][0][0] = mx; s->mv[0][0][1] = my; - *mb_type_ptr = MB_TYPE_L0 | MB_TYPE_16x16; + *mb_type_ptr = MB_TYPE_FORWARD_MV | MB_TYPE_16x16; } else { int v; - if(s->msmpeg4_version==2){ + 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 (v < 0) { @@ -207,7 +209,7 @@ static int msmpeg4v34_decode_mb(MpegEncContext *s, int16_t block[6][64]) { int cbp, code, i; uint8_t *coded_val; - uint32_t * const mb_type_ptr = &s->current_picture.mb_type[s->mb_x + s->mb_y*s->mb_stride]; + uint32_t * const mb_type_ptr = &s->cur_pic.mb_type[s->mb_x + s->mb_y*s->mb_stride]; if (get_bits_left(&s->gb) <= 0) return AVERROR_INVALIDDATA; @@ -224,7 +226,7 @@ static int msmpeg4v34_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv[0][0][0] = 0; s->mv[0][0][1] = 0; s->mb_skipped = 1; - *mb_type_ptr = MB_TYPE_SKIP | MB_TYPE_L0 | MB_TYPE_16x16; + *mb_type_ptr = MB_TYPE_SKIP | MB_TYPE_FORWARD_MV | MB_TYPE_16x16; return 0; } @@ -263,7 +265,7 @@ static int msmpeg4v34_decode_mb(MpegEncContext *s, int16_t block[6][64]) s->mv_type = MV_TYPE_16X16; s->mv[0][0][0] = mx; s->mv[0][0][1] = my; - *mb_type_ptr = MB_TYPE_L0 | MB_TYPE_16x16; + *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, ((cbp & 3) ? 1 : 0) +((cbp & 0x3C)? 2 : 0), @@ -365,16 +367,16 @@ av_cold int ff_msmpeg4_decode_init(AVCodecContext *avctx) ff_msmpeg4_common_init(s); - switch(s->msmpeg4_version){ - case 1: - case 2: + switch (s->msmpeg4_version) { + case MSMP4_V1: + case MSMP4_V2: s->decode_mb= msmpeg4v12_decode_mb; break; - case 3: - case 4: + case MSMP4_V3: + case MSMP4_WMV1: s->decode_mb= msmpeg4v34_decode_mb; break; - case 5: + case MSMP4_WMV2: break; } @@ -397,7 +399,7 @@ int ff_msmpeg4_decode_picture_header(MpegEncContext * s) if (get_bits_left(&s->gb) * 8LL < (s->width+15)/16 * ((s->height+15)/16)) return AVERROR_INVALIDDATA; - if(s->msmpeg4_version==1){ + if (s->msmpeg4_version == MSMP4_V1) { int start_code = get_bits_long(&s->gb, 32); if(start_code!=0x00000100){ av_log(s->avctx, AV_LOG_ERROR, "invalid startcode\n"); @@ -421,7 +423,7 @@ int ff_msmpeg4_decode_picture_header(MpegEncContext * s) if (s->pict_type == AV_PICTURE_TYPE_I) { code = get_bits(&s->gb, 5); - if(s->msmpeg4_version==1){ + 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); return -1; @@ -439,20 +441,20 @@ int ff_msmpeg4_decode_picture_header(MpegEncContext * s) } switch(s->msmpeg4_version){ - case 1: - case 2: + case MSMP4_V1: + case MSMP4_V2: s->rl_chroma_table_index = 2; s->rl_table_index = 2; s->dc_table_index = 0; //not used break; - case 3: + case MSMP4_V3: s->rl_chroma_table_index = decode012(&s->gb); s->rl_table_index = decode012(&s->gb); s->dc_table_index = get_bits1(&s->gb); break; - case 4: + case MSMP4_WMV1: ff_msmpeg4_decode_ext_header(s, (2+5+5+17+7)/8); if(s->bit_rate > MBAC_BITRATE) s->per_mb_rl_table= get_bits1(&s->gb); @@ -478,9 +480,9 @@ int ff_msmpeg4_decode_picture_header(MpegEncContext * s) s->slice_height); } else { switch(s->msmpeg4_version){ - case 1: - case 2: - if(s->msmpeg4_version==1) + case MSMP4_V1: + case MSMP4_V2: + if (s->msmpeg4_version == MSMP4_V1) s->use_skip_mb_code = 1; else s->use_skip_mb_code = get_bits1(&s->gb); @@ -489,7 +491,7 @@ int ff_msmpeg4_decode_picture_header(MpegEncContext * s) s->dc_table_index = 0; //not used s->mv_table_index = 0; break; - case 3: + 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; @@ -498,7 +500,7 @@ int ff_msmpeg4_decode_picture_header(MpegEncContext * s) s->mv_table_index = get_bits1(&s->gb); break; - case 4: + 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); @@ -544,13 +546,13 @@ int ff_msmpeg4_decode_picture_header(MpegEncContext * s) int ff_msmpeg4_decode_ext_header(MpegEncContext * s, int buf_size) { int left= buf_size*8 - get_bits_count(&s->gb); - int length= s->msmpeg4_version>=3 ? 17 : 16; + int length = s->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>=3) + if (s->msmpeg4_version >= MSMP4_V3) s->flipflop_rounding= get_bits1(&s->gb); else s->flipflop_rounding= 0; @@ -558,7 +560,7 @@ int ff_msmpeg4_decode_ext_header(MpegEncContext * s, int buf_size) else if(leftflipflop_rounding= 0; - if(s->msmpeg4_version != 2) + if (s->msmpeg4_version != MSMP4_V2) av_log(s->avctx, AV_LOG_ERROR, "ext header missing, %d left\n", left); } else @@ -573,7 +575,7 @@ static int msmpeg4_decode_dc(MpegEncContext * s, int n, int *dir_ptr) { int level, pred; - if(s->msmpeg4_version<=2){ + if (s->msmpeg4_version <= MSMP4_V2) { if (n < 4) { level = get_vlc2(&s->gb, v2_dc_lum_vlc, MSMP4_DC_VLC_BITS, 3); } else { @@ -599,7 +601,7 @@ static int msmpeg4_decode_dc(MpegEncContext * s, int n, int *dir_ptr) } } - if(s->msmpeg4_version==1){ + if (s->msmpeg4_version == MSMP4_V1) { int32_t *dc_val; pred = msmpeg4v1_pred_dc(s, n, &dc_val); level += pred; @@ -626,9 +628,9 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, int n, int coded, const uint8_t *scan_table) { int level, i, last, run, run_diff; - int av_uninit(dc_pred_dir); - RLTable *rl; - RL_VLC_ELEM *rl_vlc; + 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) { @@ -657,7 +659,7 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, } block[0] = level; - run_diff = s->msmpeg4_version >= 4; + run_diff = s->msmpeg4_version >= MSMP4_WMV1; i = 0; if (!coded) { goto not_coded; @@ -677,7 +679,7 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, i = -1; rl = &ff_rl_table[3 + s->rl_table_index]; - if(s->msmpeg4_version==2) + if (s->msmpeg4_version == MSMP4_V2) run_diff = 0; else run_diff = 1; @@ -699,12 +701,13 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, int cache; cache= GET_CACHE(re, &s->gb); /* escape */ - if (s->msmpeg4_version==1 || (cache&0x80000000)==0) { - if (s->msmpeg4_version==1 || (cache&0x40000000)==0) { + if (s->msmpeg4_version == MSMP4_V1 || (cache&0x80000000)==0) { + if (s->msmpeg4_version == MSMP4_V1 || (cache&0x40000000)==0) { /* third escape */ - if(s->msmpeg4_version!=1) LAST_SKIP_BITS(re, &s->gb, 2); + if (s->msmpeg4_version != MSMP4_V1) + LAST_SKIP_BITS(re, &s->gb, 2); UPDATE_CACHE(re, &s->gb); - if(s->msmpeg4_version<=3){ + 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); @@ -803,7 +806,7 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, i = 63; /* XXX: not optimal */ } } - if(s->msmpeg4_version>=4 && i>0) i=63; //FIXME/XXX optimize + if (s->msmpeg4_version >= MSMP4_WMV1 && i > 0) i=63; //FIXME/XXX optimize s->block_last_index[n] = i; return 0; @@ -811,7 +814,7 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block, void ff_msmpeg4_decode_motion(MpegEncContext *s, int *mx_ptr, int *my_ptr) { - MVTable *mv; + const MVTable *mv; int code, mx, my; mv = &ff_mv_tables[s->mv_table_index]; @@ -848,10 +851,11 @@ const FFCodec ff_msmpeg4v1_decoder = { .p.id = AV_CODEC_ID_MSMPEG4V1, .priv_data_size = sizeof(MpegEncContext), .init = ff_msmpeg4_decode_init, - .close = ff_h263_decode_end, FF_CODEC_DECODE_CB(ff_h263_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .p.max_lowres = 3, }; @@ -862,10 +866,11 @@ const FFCodec ff_msmpeg4v2_decoder = { .p.id = AV_CODEC_ID_MSMPEG4V2, .priv_data_size = sizeof(MpegEncContext), .init = ff_msmpeg4_decode_init, - .close = ff_h263_decode_end, FF_CODEC_DECODE_CB(ff_h263_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .p.max_lowres = 3, }; @@ -876,10 +881,11 @@ const FFCodec ff_msmpeg4v3_decoder = { .p.id = AV_CODEC_ID_MSMPEG4V3, .priv_data_size = sizeof(MpegEncContext), .init = ff_msmpeg4_decode_init, - .close = ff_h263_decode_end, FF_CODEC_DECODE_CB(ff_h263_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .p.max_lowres = 3, }; @@ -890,9 +896,10 @@ const FFCodec ff_wmv1_decoder = { .p.id = AV_CODEC_ID_WMV1, .priv_data_size = sizeof(MpegEncContext), .init = ff_msmpeg4_decode_init, - .close = ff_h263_decode_end, FF_CODEC_DECODE_CB(ff_h263_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .p.max_lowres = 3, }; diff --git a/libavcodec/msmpeg4enc.c b/libavcodec/msmpeg4enc.c index 119ea8f15..5ce4e6e30 100644 --- a/libavcodec/msmpeg4enc.c +++ b/libavcodec/msmpeg4enc.c @@ -71,8 +71,7 @@ void ff_msmpeg4_code012(PutBitContext *pb, int n) if (n == 0) { put_bits(pb, 1, 0); } else { - put_bits(pb, 1, 1); - put_bits(pb, 1, (n >= 2)); + put_bits(pb, 2, 2 | (n >= 2)); } } @@ -141,7 +140,7 @@ 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 >= 4) { + if (s->msmpeg4_version >= MSMP4_WMV1) { s->min_qcoeff = -255; s->max_qcoeff = 255; } @@ -226,7 +225,7 @@ void ff_msmpeg4_encode_picture_header(MpegEncContext * s) put_bits(&s->pb, 2, s->pict_type - 1); put_bits(&s->pb, 5, s->qscale); - if(s->msmpeg4_version<=2){ + if (s->msmpeg4_version <= MSMP4_V2) { s->rl_table_index = 2; s->rl_chroma_table_index = 2; } @@ -235,7 +234,7 @@ void ff_msmpeg4_encode_picture_header(MpegEncContext * s) 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==4) + 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); @@ -244,13 +243,13 @@ void ff_msmpeg4_encode_picture_header(MpegEncContext * s) s->slice_height= s->mb_height/1; put_bits(&s->pb, 5, 0x16 + s->mb_height/s->slice_height); - if(s->msmpeg4_version==4){ + if (s->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(s->msmpeg4_version>2){ + 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); @@ -261,10 +260,10 @@ void ff_msmpeg4_encode_picture_header(MpegEncContext * s) } else { put_bits(&s->pb, 1, s->use_skip_mb_code); - if(s->msmpeg4_version==4 && s->bit_rate>MBAC_BITRATE) + if (s->msmpeg4_version == MSMP4_WMV1 && s->bit_rate > MBAC_BITRATE) put_bits(&s->pb, 1, s->per_mb_rl_table); - if(s->msmpeg4_version>2){ + if (s->msmpeg4_version > MSMP4_V2) { if(!s->per_mb_rl_table) ff_msmpeg4_code012(&s->pb, s->rl_table_index); @@ -298,7 +297,7 @@ FF_ENABLE_DEPRECATION_WARNINGS put_bits(&s->pb, 11, FFMIN(s->bit_rate / 1024, 2047)); - if (s->msmpeg4_version >= 3) + if (s->msmpeg4_version >= MSMP4_V3) put_bits(&s->pb, 1, s->flipflop_rounding); else av_assert0(!s->flipflop_rounding); @@ -340,7 +339,7 @@ void ff_msmpeg4_encode_motion(MpegEncContext * s, 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 < 4){ + if (s->msmpeg4_version < MSMP4_WMV1) { ff_mpeg4_clean_buffers(s); } s->first_slice_line = 1; @@ -389,7 +388,6 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, { int cbp, coded_cbp, i; int pred_x, pred_y; - uint8_t *coded_block; ff_msmpeg4_handle_slices(s); @@ -405,14 +403,13 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, put_bits(&s->pb, 1, 1); s->last_bits++; s->misc_bits++; - s->skip_count++; return; } if (s->use_skip_mb_code) put_bits(&s->pb, 1, 0); /* mb coded */ - if(s->msmpeg4_version<=2){ + if (s->msmpeg4_version <= MSMP4_V2) { put_bits(&s->pb, ff_v2_mb_type[cbp&3][1], ff_v2_mb_type[cbp&3][0]); @@ -450,21 +447,11 @@ void ff_msmpeg4_encode_mb(MpegEncContext * 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); + for (int i = 0; i < 6; i++) { + int 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->msmpeg4_version<=2){ + if (s->msmpeg4_version <= MSMP4_V2) { if (s->pict_type == AV_PICTURE_TYPE_I) { put_bits(&s->pb, ff_v2_intra_cbpc[cbp&3][1], ff_v2_intra_cbpc[cbp&3][0]); @@ -481,6 +468,18 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s, ff_h263_cbpy_tab[cbp>>2][0]); }else{ if (s->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); + *coded_block = val; + val ^= pred; + coded_cbp |= val << (5 - i); + } + put_bits(&s->pb, ff_msmp4_mb_i_table[coded_cbp][1], ff_msmp4_mb_i_table[coded_cbp][0]); } else { @@ -524,7 +523,7 @@ static void msmpeg4_encode_dc(MpegEncContext * s, int level, int n, int *dir_ptr /* do the prediction */ level -= pred; - if(s->msmpeg4_version<=2){ + if (s->msmpeg4_version <= MSMP4_V2) { if (n < 4) { put_bits(&s->pb, ff_v2_dc_lum_table[level + 256][1], @@ -575,20 +574,17 @@ void ff_msmpeg4_encode_block(MpegEncContext * s, int16_t * block, int n) } else { rl = &ff_rl_table[3 + s->rl_chroma_table_index]; } - run_diff = s->msmpeg4_version>=4; + run_diff = s->msmpeg4_version >= MSMP4_WMV1; scantable= s->intra_scantable.permutated; } else { i = 0; rl = &ff_rl_table[3 + s->rl_table_index]; - if(s->msmpeg4_version<=2) - run_diff = 0; - else - run_diff = 1; + run_diff = s->msmpeg4_version > MSMP4_V2; scantable= s->inter_scantable.permutated; } /* recalculate block_last_index for M$ wmv1 */ - if (s->msmpeg4_version >= 4 && s->block_last_index[n] > 0) { + if (s->msmpeg4_version >= MSMP4_WMV1 && s->block_last_index[n] > 0) { for(last_index=63; last_index>=0; last_index--){ if(block[scantable[last_index]]) break; } @@ -634,7 +630,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 == 4 && code == rl->n) + if (s->msmpeg4_version == MSMP4_WMV1 && code == rl->n) goto esc3; code = get_rl_index(rl, last, run1, level); if (code == rl->n) { @@ -642,7 +638,7 @@ 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>=4){ + if (s->msmpeg4_version >= MSMP4_WMV1) { if(s->esc3_level_length==0){ s->esc3_level_length=8; s->esc3_run_length= 6; @@ -685,6 +681,7 @@ const FFCodec ff_msmpeg4v2_encoder = { .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 }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_mpv_enc_class, .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, @@ -700,6 +697,7 @@ const FFCodec ff_msmpeg4v3_encoder = { .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 }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_mpv_enc_class, .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, @@ -715,6 +713,7 @@ const FFCodec ff_wmv1_encoder = { .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 }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ff_mpv_enc_class, .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/msp2dec.c b/libavcodec/msp2dec.c index 30a2825e4..e1daeeb14 100644 --- a/libavcodec/msp2dec.c +++ b/libavcodec/msp2dec.c @@ -46,9 +46,6 @@ static int msp2_decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; - bytestream2_init(&idx, buf, 2 * avctx->height); buf += 2 * avctx->height; buf_size -= 2 * avctx->height; diff --git a/libavcodec/mss12.c b/libavcodec/mss12.c index 5afdaacfe..8dd3b4fc8 100644 --- a/libavcodec/mss12.c +++ b/libavcodec/mss12.c @@ -27,6 +27,7 @@ #include "libavutil/intfloat.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "mss12.h" diff --git a/libavcodec/mss2.c b/libavcodec/mss2.c index d54a1220b..1888053eb 100644 --- a/libavcodec/mss2.c +++ b/libavcodec/mss2.c @@ -24,12 +24,12 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "codec_internal.h" #include "decode.h" #include "error_resilience.h" #include "mpeg_er.h" #include "mpegvideodec.h" -#include "qpeldsp.h" #include "vc1.h" #include "wmv2data.h" #include "mss12.h" @@ -382,7 +382,7 @@ static int decode_wmv9(AVCodecContext *avctx, const uint8_t *buf, int buf_size, MSS12Context *c = &ctx->c; VC1Context *v = avctx->priv_data; MpegEncContext *s = &v->s; - AVFrame *f; + MPVWorkPicture *f; int ret; ff_mpeg_flush(avctx); @@ -431,7 +431,7 @@ static int decode_wmv9(AVCodecContext *avctx, const uint8_t *buf, int buf_size, ff_mpv_frame_end(s); - f = s->current_picture.f; + f = &s->cur_pic; if (v->respic == 3) { ctx->dsp.upsample_plane(f->data[0], f->linesize[0], w, h); diff --git a/libavcodec/mss3.c b/libavcodec/mss3.c index 2701e9b91..257943f64 100644 --- a/libavcodec/mss3.c +++ b/libavcodec/mss3.c @@ -24,6 +24,7 @@ * Microsoft Screen 3 (aka Microsoft ATC Screen) decoder */ +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/mss4.c b/libavcodec/mss4.c index 8ae4f152c..c931aa4e4 100644 --- a/libavcodec/mss4.c +++ b/libavcodec/mss4.c @@ -25,6 +25,7 @@ * aka Microsoft Expression Encoder Screen) decoder */ +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "libavutil/imgutils.h" diff --git a/libavcodec/msvideo1enc.c b/libavcodec/msvideo1enc.c index 3bea3ed29..b8704367c 100644 --- a/libavcodec/msvideo1enc.c +++ b/libavcodec/msvideo1enc.c @@ -29,6 +29,7 @@ #include "encode.h" #include "bytestream.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "elbg.h" #include "libavutil/imgutils.h" /** diff --git a/libavcodec/mv30.c b/libavcodec/mv30.c index 8c45c8304..124a37e23 100644 --- a/libavcodec/mv30.c +++ b/libavcodec/mv30.c @@ -23,6 +23,7 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "avcodec.h" diff --git a/libavcodec/mvcdec.c b/libavcodec/mvcdec.c index 6c971f709..44cab1889 100644 --- a/libavcodec/mvcdec.c +++ b/libavcodec/mvcdec.c @@ -246,9 +246,6 @@ static int mvc_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (ret < 0) return ret; - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/mvha.c b/libavcodec/mvha.c index 356cebc64..4aad56640 100644 --- a/libavcodec/mvha.c +++ b/libavcodec/mvha.c @@ -183,6 +183,8 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret); return AVERROR_EXTERNAL; } + if (zstream->avail_out > 0) + memset(zstream->next_out, 0, zstream->avail_out); } } } else if (type == MKTAG('H','U','F','Y')) { @@ -271,8 +273,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } } - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/mwsc.c b/libavcodec/mwsc.c index a7e870258..0d4ee9791 100644 --- a/libavcodec/mwsc.c +++ b/libavcodec/mwsc.c @@ -22,6 +22,7 @@ #include +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/mxpegdec.c b/libavcodec/mxpegdec.c index 73df2ff9f..c5c14cbe7 100644 --- a/libavcodec/mxpegdec.c +++ b/libavcodec/mxpegdec.c @@ -25,6 +25,7 @@ * MxPEG decoder */ +#include "libavutil/mem.h" #include "codec_internal.h" #include "decode.h" #include "mjpeg.h" diff --git a/libavcodec/nellymoserdec.c b/libavcodec/nellymoserdec.c index 727cd4833..e9b124399 100644 --- a/libavcodec/nellymoserdec.c +++ b/libavcodec/nellymoserdec.c @@ -34,6 +34,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/tx.h" diff --git a/libavcodec/nellymoserenc.c b/libavcodec/nellymoserenc.c index a550ae46c..32ae5f782 100644 --- a/libavcodec/nellymoserenc.c +++ b/libavcodec/nellymoserenc.c @@ -38,6 +38,7 @@ #include "libavutil/common.h" #include "libavutil/float_dsp.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "libavutil/tx.h" diff --git a/libavcodec/notchlc.c b/libavcodec/notchlc.c index 6351a313f..246a3e017 100644 --- a/libavcodec/notchlc.c +++ b/libavcodec/notchlc.c @@ -23,6 +23,7 @@ #include #define BITSTREAM_READER_LE +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" @@ -92,6 +93,9 @@ static int lz4_decompress(AVCodecContext *avctx, } while (current == 255); } + if (bytestream2_get_bytes_left(gb) < num_literals) + return AVERROR_INVALIDDATA; + if (pos + num_literals < HISTORY_SIZE) { bytestream2_get_buffer(gb, history + pos, num_literals); pos += num_literals; @@ -516,9 +520,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, if (ret < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/nuv.c b/libavcodec/nuv.c index 1dda770c9..c2301be77 100644 --- a/libavcodec/nuv.c +++ b/libavcodec/nuv.c @@ -26,6 +26,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/lzo.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c index 1741ee7e4..932544564 100644 --- a/libavcodec/nvdec.c +++ b/libavcodec/nvdec.c @@ -28,6 +28,7 @@ #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" #include "libavutil/cuda_check.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" diff --git a/libavcodec/nvdec_av1.c b/libavcodec/nvdec_av1.c index 35f22ebf8..6b408edb8 100644 --- a/libavcodec/nvdec_av1.c +++ b/libavcodec/nvdec_av1.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "avcodec.h" #include "nvdec.h" #include "decode.h" @@ -105,9 +106,7 @@ static int nvdec_av1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u .show_frame = frame_header->show_frame, .disable_cdf_update = frame_header->disable_cdf_update, .allow_screen_content_tools = frame_header->allow_screen_content_tools, - .force_integer_mv = frame_header->force_integer_mv || - frame_header->frame_type == AV1_FRAME_INTRA_ONLY || - frame_header->frame_type == AV1_FRAME_KEY, + .force_integer_mv = s->cur_frame.force_integer_mv, .coded_denom = frame_header->coded_denom, .allow_intrabc = frame_header->allow_intrabc, .allow_high_precision_mv = frame_header->allow_high_precision_mv, @@ -250,8 +249,8 @@ static int nvdec_av1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u AVFrame *ref_frame = s->ref[ref_idx].f; ppc->ref_frame[i].index = ppc->ref_frame_map[ref_idx]; - ppc->ref_frame[i].width = ref_frame->width; - ppc->ref_frame[i].height = ref_frame->height; + ppc->ref_frame[i].width = ref_frame ? ref_frame->width : 0; + ppc->ref_frame[i].height = ref_frame ? ref_frame->height : 0; /* Global Motion */ ppc->global_motion[i].invalid = !frame_header->is_global[AV1_REF_FRAME_LAST + i]; diff --git a/libavcodec/nvdec_h264.c b/libavcodec/nvdec_h264.c index ea6c1081e..9adbc521e 100644 --- a/libavcodec/nvdec_h264.c +++ b/libavcodec/nvdec_h264.c @@ -23,6 +23,7 @@ #include #include +#include "libavutil/mem.h" #include "avcodec.h" #include "nvdec.h" #include "decode.h" diff --git a/libavcodec/nvdec_hevc.c b/libavcodec/nvdec_hevc.c index ff118af04..e01ce4c78 100644 --- a/libavcodec/nvdec_hevc.c +++ b/libavcodec/nvdec_hevc.c @@ -23,17 +23,18 @@ #include #include +#include "libavutil/mem.h" #include "avcodec.h" #include "nvdec.h" #include "decode.h" #include "internal.h" -#include "hevcdec.h" -#include "hevc_data.h" +#include "hevc/hevcdec.h" +#include "hevc/data.h" #include "hwaccel_internal.h" static void dpb_add(CUVIDHEVCPICPARAMS *pp, int idx, const HEVCFrame *src) { - FrameDecodeData *fdd = (FrameDecodeData*)src->frame->private_ref->data; + FrameDecodeData *fdd = (FrameDecodeData*)src->f->private_ref->data; const NVDECFrame *cf = fdd->hwaccel_priv; pp->RefPicIdx[idx] = cf ? cf->idx : -1; @@ -43,8 +44,8 @@ static void dpb_add(CUVIDHEVCPICPARAMS *pp, int idx, const HEVCFrame *src) static void fill_scaling_lists(CUVIDHEVCPICPARAMS *ppc, const HEVCContext *s) { - const ScalingList *sl = s->ps.pps->scaling_list_data_present_flag ? - &s->ps.pps->scaling_list : &s->ps.sps->scaling_list; + const ScalingList *sl = s->pps->scaling_list_data_present_flag ? + &s->pps->scaling_list : &s->pps->sps->scaling_list; int i, j, pos; for (i = 0; i < 6; i++) { @@ -72,8 +73,9 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { const HEVCContext *s = avctx->priv_data; - const HEVCPPS *pps = s->ps.pps; - const HEVCSPS *sps = s->ps.sps; + const HEVCLayerContext *l = &s->layers[s->cur_layer]; + const HEVCPPS *pps = s->pps; + const HEVCSPS *sps = pps->sps; NVDECContext *ctx = avctx->internal->hwaccel_priv_data; CUVIDPICPARAMS *pp = &ctx->pic_params; @@ -83,11 +85,11 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, int i, j, dpb_size, ret; - ret = ff_nvdec_start_frame(avctx, s->ref->frame); + ret = ff_nvdec_start_frame(avctx, s->cur_frame->f); if (ret < 0) return ret; - fdd = (FrameDecodeData*)s->ref->frame->private_ref->data; + fdd = (FrameDecodeData*)s->cur_frame->f->private_ref->data; cf = (NVDECFrame*)fdd->hwaccel_priv; *pp = (CUVIDPICPARAMS) { @@ -104,44 +106,44 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_coding_block_size, .log2_min_transform_block_size_minus2 = sps->log2_min_tb_size - 2, .log2_diff_max_min_transform_block_size = sps->log2_max_trafo_size - sps->log2_min_tb_size, - .pcm_enabled_flag = sps->pcm_enabled_flag, - .log2_min_pcm_luma_coding_block_size_minus3 = sps->pcm_enabled_flag ? sps->pcm.log2_min_pcm_cb_size - 3 : 0, + .pcm_enabled_flag = sps->pcm_enabled, + .log2_min_pcm_luma_coding_block_size_minus3 = sps->pcm_enabled ? sps->pcm.log2_min_pcm_cb_size - 3 : 0, .log2_diff_max_min_pcm_luma_coding_block_size = sps->pcm.log2_max_pcm_cb_size - sps->pcm.log2_min_pcm_cb_size, - .pcm_sample_bit_depth_luma_minus1 = sps->pcm_enabled_flag ? sps->pcm.bit_depth - 1 : 0, - .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_enabled_flag ? sps->pcm.bit_depth_chroma - 1 : 0, + .pcm_sample_bit_depth_luma_minus1 = sps->pcm_enabled ? sps->pcm.bit_depth - 1 : 0, + .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_enabled ? sps->pcm.bit_depth_chroma - 1 : 0, #if NVDECAPI_CHECK_VERSION(8, 1) .log2_max_transform_skip_block_size_minus2 = pps->log2_max_transform_skip_block_size - 2, .log2_sao_offset_scale_luma = pps->log2_sao_offset_scale_luma, .log2_sao_offset_scale_chroma = pps->log2_sao_offset_scale_chroma, - .high_precision_offsets_enabled_flag = sps->high_precision_offsets_enabled_flag, + .high_precision_offsets_enabled_flag = sps->high_precision_offsets_enabled, #endif - .pcm_loop_filter_disabled_flag = sps->pcm.loop_filter_disable_flag, - .strong_intra_smoothing_enabled_flag = sps->sps_strong_intra_smoothing_enable_flag, + .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled, + .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled, .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra, .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter, - .amp_enabled_flag = sps->amp_enabled_flag, - .separate_colour_plane_flag = sps->separate_colour_plane_flag, + .amp_enabled_flag = sps->amp_enabled, + .separate_colour_plane_flag = sps->separate_colour_plane, .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_poc_lsb - 4, .num_short_term_ref_pic_sets = sps->nb_st_rps, - .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag, + .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present, .num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps, - .sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag, + .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled, .sample_adaptive_offset_enabled_flag = sps->sao_enabled, - .scaling_list_enable_flag = sps->scaling_list_enable_flag, + .scaling_list_enable_flag = sps->scaling_list_enabled, .IrapPicFlag = IS_IRAP(s), .IdrPicFlag = IS_IDR(s), .bit_depth_luma_minus8 = sps->bit_depth - 8, .bit_depth_chroma_minus8 = sps->bit_depth - 8, #if NVDECAPI_CHECK_VERSION(9, 0) - .sps_range_extension_flag = sps->sps_range_extension_flag, - .transform_skip_rotation_enabled_flag = sps->transform_skip_rotation_enabled_flag, - .transform_skip_context_enabled_flag = sps->transform_skip_context_enabled_flag, - .implicit_rdpcm_enabled_flag = sps->implicit_rdpcm_enabled_flag, - .explicit_rdpcm_enabled_flag = sps->explicit_rdpcm_enabled_flag, - .extended_precision_processing_flag = sps->extended_precision_processing_flag, - .intra_smoothing_disabled_flag = sps->intra_smoothing_disabled_flag, - .persistent_rice_adaptation_enabled_flag = sps->persistent_rice_adaptation_enabled_flag, - .cabac_bypass_alignment_enabled_flag = sps->cabac_bypass_alignment_enabled_flag, + .sps_range_extension_flag = sps->range_extension, + .transform_skip_rotation_enabled_flag = sps->transform_skip_rotation_enabled, + .transform_skip_context_enabled_flag = sps->transform_skip_context_enabled, + .implicit_rdpcm_enabled_flag = sps->implicit_rdpcm_enabled, + .explicit_rdpcm_enabled_flag = sps->explicit_rdpcm_enabled, + .extended_precision_processing_flag = sps->extended_precision_processing, + .intra_smoothing_disabled_flag = sps->intra_smoothing_disabled, + .persistent_rice_adaptation_enabled_flag = sps->persistent_rice_adaptation_enabled, + .cabac_bypass_alignment_enabled_flag = sps->cabac_bypass_alignment_enabled, #endif .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag, @@ -186,11 +188,11 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, .NumBitsForShortTermRPSInSlice = s->sh.short_term_rps ? s->sh.short_term_ref_pic_set_size : 0, .NumDeltaPocsOfRefRpsIdx = s->sh.short_term_rps ? s->sh.short_term_rps->rps_idx_num_delta_pocs : 0, - .NumPocTotalCurr = ff_hevc_frame_nb_refs(s), + .NumPocTotalCurr = ff_hevc_frame_nb_refs(&s->sh, pps, s->cur_layer), .NumPocStCurrBefore = s->rps[ST_CURR_BEF].nb_refs, .NumPocStCurrAfter = s->rps[ST_CURR_AFT].nb_refs, .NumPocLtCurr = s->rps[LT_CURR].nb_refs, - .CurrPicOrderCntVal = s->ref->poc, + .CurrPicOrderCntVal = s->cur_frame->poc, }, }; @@ -224,8 +226,8 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, } dpb_size = 0; - for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { - const HEVCFrame *ref = &s->DPB[i]; + for (i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + const HEVCFrame *ref = &l->DPB[i]; if (!(ref->flags & (HEVC_FRAME_FLAG_SHORT_REF | HEVC_FRAME_FLAG_LONG_REF))) continue; if (dpb_size >= FF_ARRAY_ELEMS(ppc->RefPicIdx)) { @@ -299,7 +301,7 @@ static int nvdec_hevc_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { const HEVCContext *s = avctx->priv_data; - const HEVCSPS *sps = s->ps.sps; + const HEVCSPS *sps = s->pps->sps; return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering + 1, 1); } diff --git a/libavcodec/nvdec_mpeg12.c b/libavcodec/nvdec_mpeg12.c index a4603c7ea..99b2b14f1 100644 --- a/libavcodec/nvdec_mpeg12.c +++ b/libavcodec/nvdec_mpeg12.c @@ -25,6 +25,7 @@ #include "avcodec.h" #include "hwaccel_internal.h" #include "internal.h" +#include "mpegutils.h" #include "mpegvideo.h" #include "nvdec.h" #include "decode.h" @@ -38,7 +39,7 @@ static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer CUVIDMPEG2PICPARAMS *ppc = &pp->CodecSpecific.mpeg2; FrameDecodeData *fdd; NVDECFrame *cf; - AVFrame *cur_frame = s->current_picture.f; + AVFrame *cur_frame = s->cur_pic.ptr->f; int ret, i; @@ -63,8 +64,8 @@ static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer s->pict_type == AV_PICTURE_TYPE_P, .CodecSpecific.mpeg2 = { - .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_picture.f), - .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_picture.f), + .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_pic.ptr ? s->last_pic.ptr->f : NULL), + .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_pic.ptr ? s->next_pic.ptr->f : NULL), .picture_coding_type = s->pict_type, .full_pel_forward_vector = s->full_pel[0], diff --git a/libavcodec/nvdec_mpeg4.c b/libavcodec/nvdec_mpeg4.c index 20a049943..80da11b5b 100644 --- a/libavcodec/nvdec_mpeg4.c +++ b/libavcodec/nvdec_mpeg4.c @@ -38,7 +38,7 @@ static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, CUVIDMPEG4PICPARAMS *ppc = &pp->CodecSpecific.mpeg4; FrameDecodeData *fdd; NVDECFrame *cf; - AVFrame *cur_frame = s->current_picture.f; + AVFrame *cur_frame = s->cur_pic.ptr->f; int ret, i; @@ -60,8 +60,8 @@ static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, s->pict_type == AV_PICTURE_TYPE_S, .CodecSpecific.mpeg4 = { - .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_picture.f), - .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_picture.f), + .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_pic.ptr ? s->last_pic.ptr->f : NULL), + .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_pic.ptr ? s->next_pic.ptr->f : NULL), .video_object_layer_width = s->width, .video_object_layer_height = s->height, diff --git a/libavcodec/nvdec_vc1.c b/libavcodec/nvdec_vc1.c index 5096d784d..0668863cb 100644 --- a/libavcodec/nvdec_vc1.c +++ b/libavcodec/nvdec_vc1.c @@ -38,7 +38,7 @@ static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u CUVIDPICPARAMS *pp = &ctx->pic_params; FrameDecodeData *fdd; NVDECFrame *cf; - AVFrame *cur_frame = s->current_picture.f; + AVFrame *cur_frame = s->cur_pic.ptr->f; int ret; @@ -63,8 +63,8 @@ static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, u s->pict_type == AV_PICTURE_TYPE_P, .CodecSpecific.vc1 = { - .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_picture.f), - .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_picture.f), + .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_pic.ptr ? s->last_pic.ptr->f : NULL), + .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_pic.ptr ? s->next_pic.ptr->f : NULL), .FrameWidth = cur_frame->width, .FrameHeight = cur_frame->height, diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index a44beb349..2cce478be 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -23,7 +23,7 @@ #include "config_components.h" #include "nvenc.h" -#include "hevc_sei.h" +#include "hevc/sei.h" #if CONFIG_AV1_NVENC_ENCODER #include "av1.h" #endif @@ -242,8 +242,20 @@ static void nvenc_map_preset(NvencContext *ctx) static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) { -#if NVENCAPI_CHECK_VERSION(12, 1) +#if NVENCAPI_CHECK_VERSION(12, 3) const char *minver = "(unknown)"; +#elif NVENCAPI_CHECK_VERSION(12, 2) +# if defined(_WIN32) || defined(__CYGWIN__) + const char *minver = "551.76"; +# else + const char *minver = "550.54.14"; +# endif +#elif NVENCAPI_CHECK_VERSION(12, 1) +# if defined(_WIN32) || defined(__CYGWIN__) + const char *minver = "531.61"; +# else + const char *minver = "530.41.03"; +# endif #elif NVENCAPI_CHECK_VERSION(12, 0) # if defined(_WIN32) || defined(__CYGWIN__) const char *minver = "522.25"; @@ -502,7 +514,7 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) } ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE); - if (IS_10BIT(ctx->data_pix_fmt) && ret <= 0) { + if ((IS_10BIT(ctx->data_pix_fmt) || ctx->highbitdepth) && ret <= 0) { av_log(avctx, AV_LOG_WARNING, "10 bit encode not supported\n"); return AVERROR(ENOSYS); } @@ -594,6 +606,33 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) return AVERROR(ENOSYS); } +#ifdef NVENC_HAVE_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"); + return AVERROR(ENOSYS); + } +#endif + +#ifdef NVENC_HAVE_LOOKAHEAD_LEVEL + ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_LOOKAHEAD_LEVEL); + if(ctx->rc_lookahead > 0 && ctx->lookahead_level > 0 && + ctx->lookahead_level != NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT && + ctx->lookahead_level > ret) + { + av_log(avctx, AV_LOG_WARNING, "Lookahead level not supported. Maximum level: %d\n", ret); + return AVERROR(ENOSYS); + } +#endif + +#ifdef NVENC_HAVE_UNIDIR_B + ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_UNIDIRECTIONAL_B); + if(ctx->unidir_b && ret <= 0) { + av_log(avctx, AV_LOG_WARNING, "Unidirectional B-Frames not supported by the device\n"); + return AVERROR(ENOSYS); + } +#endif + ctx->support_dyn_bitrate = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE); return 0; @@ -987,7 +1026,7 @@ static av_cold int nvenc_recalc_surfaces(AVCodecContext *avctx) return 0; } -static av_cold void nvenc_setup_rate_control(AVCodecContext *avctx) +static av_cold int nvenc_setup_rate_control(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; @@ -1116,6 +1155,24 @@ static av_cold void nvenc_setup_rate_control(AVCodecContext *avctx) if (ctx->encode_config.rcParams.lookaheadDepth < ctx->rc_lookahead) av_log(avctx, AV_LOG_WARNING, "Clipping lookahead depth to %d (from %d) due to lack of surfaces/delay", ctx->encode_config.rcParams.lookaheadDepth, ctx->rc_lookahead); + +#ifdef NVENC_HAVE_LOOKAHEAD_LEVEL + if (ctx->lookahead_level >= 0) { + switch (ctx->lookahead_level) { + case NV_ENC_LOOKAHEAD_LEVEL_0: + case NV_ENC_LOOKAHEAD_LEVEL_1: + case NV_ENC_LOOKAHEAD_LEVEL_2: + case NV_ENC_LOOKAHEAD_LEVEL_3: + case NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT: + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid lookahead level.\n"); + return AVERROR(EINVAL); + } + + ctx->encode_config.rcParams.lookaheadLevel = ctx->lookahead_level; + } +#endif } } @@ -1143,6 +1200,8 @@ static av_cold void nvenc_setup_rate_control(AVCodecContext *avctx) ctx->encode_config.rcParams.vbvBufferSize = avctx->rc_buffer_size = 0; ctx->encode_config.rcParams.maxBitRate = avctx->rc_max_rate; } + + return 0; } static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) @@ -1361,8 +1420,8 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) break; } - // force setting profile as main10 if input is 10 bit - if (IS_10BIT(ctx->data_pix_fmt)) { + // force setting profile as main10 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_HEVC_PROFILE_MAIN10_GUID; avctx->profile = AV_PROFILE_HEVC_MAIN_10; } @@ -1376,8 +1435,8 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) hevc->chromaFormatIDC = IS_YUV444(ctx->data_pix_fmt) ? 3 : 1; #ifdef NVENC_HAVE_NEW_BIT_DEPTH_API - hevc->inputBitDepth = hevc->outputBitDepth = - IS_10BIT(ctx->data_pix_fmt) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; + hevc->inputBitDepth = IS_10BIT(ctx->data_pix_fmt) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; + hevc->outputBitDepth = (IS_10BIT(ctx->data_pix_fmt) || ctx->highbitdepth) ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8; #else hevc->pixelBitDepthMinus8 = IS_10BIT(ctx->data_pix_fmt) ? 2 : 0; #endif @@ -1396,6 +1455,25 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) hevc->numRefL1 = avctx->refs; #endif +#ifdef NVENC_HAVE_TEMPORAL_FILTER + if (ctx->tf_level >= 0) { + hevc->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; } @@ -1600,6 +1678,10 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS } +#ifdef NVENC_HAVE_UNIDIR_B + ctx->init_encode_params.enableUniDirectionalB = ctx->unidir_b; +#endif + ctx->init_encode_params.enableEncodeAsync = 0; ctx->init_encode_params.enablePTD = 1; @@ -1614,6 +1696,15 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ctx->weighted_pred == 1) ctx->init_encode_params.enableWeightedPrediction = 1; +#ifdef NVENC_HAVE_SPLIT_FRAME_ENCODING + ctx->init_encode_params.splitEncodeMode = ctx->split_encode_mode; + + if (ctx->split_encode_mode != NV_ENC_SPLIT_DISABLE_MODE) { + if (avctx->codec->id == AV_CODEC_ID_HEVC && ctx->weighted_pred == 1) + av_log(avctx, AV_LOG_WARNING, "Split encoding not supported with weighted prediction enabled.\n"); + } +#endif + if (ctx->bluray_compat) { ctx->aud = 1; ctx->dpb_size = FFMIN(FFMAX(avctx->refs, 0), 6); @@ -1648,7 +1739,9 @@ FF_ENABLE_DEPRECATION_WARNINGS nvenc_recalc_surfaces(avctx); - nvenc_setup_rate_control(avctx); + res = nvenc_setup_rate_control(avctx); + if (res < 0) + return res; if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) { ctx->encode_config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD; @@ -1800,7 +1893,8 @@ static av_cold int nvenc_setup_surfaces(AVCodecContext *avctx) if (!ctx->frame_data_array) return AVERROR(ENOMEM); - ctx->timestamp_list = av_fifo_alloc2(ctx->nb_surfaces, sizeof(int64_t), 0); + ctx->timestamp_list = av_fifo_alloc2(ctx->nb_surfaces + ctx->encode_config.frameIntervalP, + sizeof(int64_t), 0); if (!ctx->timestamp_list) return AVERROR(ENOMEM); @@ -2254,26 +2348,65 @@ static inline int64_t timestamp_queue_dequeue(AVFifo *queue) return timestamp; } +static inline int64_t timestamp_queue_peek(AVFifo *queue, size_t index) +{ + int64_t timestamp = AV_NOPTS_VALUE; + av_fifo_peek(queue, ×tamp, 1, index); + + return timestamp; +} + static int nvenc_set_timestamp(AVCodecContext *avctx, NV_ENC_LOCK_BITSTREAM *params, AVPacket *pkt) { NvencContext *ctx = avctx->priv_data; + unsigned int delay; + int64_t delay_time; pkt->pts = params->outputTimeStamp; - if (avctx->codec_descriptor->props & AV_CODEC_PROP_REORDER) { -FF_DISABLE_DEPRECATION_WARNINGS - pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list) - -#if FF_API_TICKS_PER_FRAME - FFMAX(avctx->ticks_per_frame, 1) * -#endif - FFMAX(ctx->encode_config.frameIntervalP - 1, 0); -FF_ENABLE_DEPRECATION_WARNINGS - } else { + if (!(avctx->codec_descriptor->props & AV_CODEC_PROP_REORDER)) { pkt->dts = pkt->pts; + return 0; } + // This can be more than necessary, but we don't know the real reorder delay. + delay = FFMAX(ctx->encode_config.frameIntervalP - 1, 0); + if (ctx->output_frame_num >= delay) { + pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list); + ctx->output_frame_num++; + return 0; + } + + delay_time = ctx->initial_delay_time; + if (!delay_time) { + int64_t t1, t2, t3; + t1 = timestamp_queue_peek(ctx->timestamp_list, delay); + t2 = timestamp_queue_peek(ctx->timestamp_list, 0); + t3 = (delay > 1) ? timestamp_queue_peek(ctx->timestamp_list, 1) : t1; + + if (t1 != AV_NOPTS_VALUE) { + delay_time = t1 - t2; + } else if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + delay_time = av_rescale_q(delay, (AVRational) {avctx->framerate.den, avctx->framerate.num}, + avctx->time_base); + } else if (t3 != AV_NOPTS_VALUE) { + delay_time = delay * (t3 - t2); + } else { + delay_time = delay; + } + ctx->initial_delay_time = delay_time; + } + + /* The following method is simple, but doesn't guarantee monotonic with VFR + * when delay_time isn't accurate (that is, t1 == AV_NOPTS_VALUE) + * + * dts = timestamp_queue_peek(ctx->timestamp_list, ctx->output_frame_num) - delay_time + */ + pkt->dts = timestamp_queue_peek(ctx->timestamp_list, 0) - delay_time * (delay - ctx->output_frame_num) / delay; + ctx->output_frame_num++; + return 0; } @@ -2700,6 +2833,7 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) pic_params.encodePicFlags = 0; } + pic_params.frameIdx = ctx->frame_idx_counter++; pic_params.inputTimeStamp = frame->pts; if (ctx->extra_sei) { @@ -2808,4 +2942,6 @@ av_cold void ff_nvenc_encode_flush(AVCodecContext *avctx) nvenc_send_frame(avctx, NULL); av_fifo_reset2(ctx->timestamp_list); + ctx->output_frame_num = 0; + ctx->initial_delay_time = 0; } diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index d99d8a0d7..0130b9936 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -81,11 +81,16 @@ typedef void ID3D11Device; // SDK 12.1 compile time feature checks #if NVENCAPI_CHECK_VERSION(12, 1) #define NVENC_NO_DEPRECATED_RC +#define NVENC_HAVE_SPLIT_FRAME_ENCODING #endif // SDK 12.2 compile time feature checks #if NVENCAPI_CHECK_VERSION(12, 2) #define NVENC_HAVE_NEW_BIT_DEPTH_API +#define NVENC_HAVE_TEMPORAL_FILTER +#define NVENC_HAVE_LOOKAHEAD_LEVEL +#define NVENC_HAVE_UHQ_TUNING +#define NVENC_HAVE_UNIDIR_B #endif typedef struct NvencSurface @@ -201,6 +206,9 @@ typedef struct NvencContext AVFifo *output_surface_queue; AVFifo *output_surface_ready_queue; AVFifo *timestamp_list; + // This is for DTS calculating, reset after flush + uint64_t output_frame_num; + int64_t initial_delay_time; NV_ENC_SEI_PAYLOAD *sei_data; int sei_data_size; @@ -222,6 +230,8 @@ typedef struct NvencContext void *nvencoder; + uint32_t frame_idx_counter; + int preset; int profile; int level; @@ -271,6 +281,10 @@ typedef struct NvencContext int highbitdepth; int max_slice_size; int rgb_mode; + int tf_level; + int lookahead_level; + int unidir_b; + int split_encode_mode; } NvencContext; int ff_nvenc_encode_init(AVCodecContext *avctx); diff --git a/libavcodec/nvenc_av1.c b/libavcodec/nvenc_av1.c index c46cee9fa..79253cff6 100644 --- a/libavcodec/nvenc_av1.c +++ b/libavcodec/nvenc_av1.c @@ -105,8 +105,8 @@ static const AVOption options[] = { OFFSET(async_depth), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 0, INT_MAX, VE }, { "rc-lookahead", "Number of frames to look ahead for rate-control", OFFSET(rc_lookahead), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, - { "cq", "Set target quality level (0 to 51, 0 means automatic) for constant quality mode in VBR rate control", - OFFSET(quality), AV_OPT_TYPE_FLOAT, { .dbl = 0.}, 0., 51., VE }, + { "cq", "Set target quality level (0 to 63, 0 means automatic) for constant quality mode in VBR rate control", + OFFSET(quality), AV_OPT_TYPE_FLOAT, { .dbl = 0.}, 0., 63., VE }, { "init_qpP", "Initial QP value for P frame", OFFSET(init_qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, VE }, { "init_qpB", "Initial QP value for B frame", OFFSET(init_qp_b), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, VE }, { "init_qpI", "Initial QP value for I frame", OFFSET(init_qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, VE }, @@ -149,6 +149,23 @@ 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 }, +#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" }, + { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT }, 0, 0, VE, .unit = "lookahead_level" }, + { "0", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_0 }, 0, 0, VE, .unit = "lookahead_level" }, + { "1", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_1 }, 0, 0, VE, .unit = "lookahead_level" }, + { "2", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_2 }, 0, 0, VE, .unit = "lookahead_level" }, + { "3", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_3 }, 0, 0, VE, .unit = "lookahead_level" }, +#endif +#ifdef NVENC_HAVE_SPLIT_FRAME_ENCODING + { "split_encode_mode", "Specifies the split encoding mode", OFFSET(split_encode_mode), AV_OPT_TYPE_INT, { .i64 = NV_ENC_SPLIT_AUTO_MODE }, 0, NV_ENC_SPLIT_DISABLE_MODE, VE, .unit = "split_encode_mode" }, + { "disabled", "Disabled for all configurations", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_DISABLE_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, + { "auto", "Enabled or disabled depending on the preset and tuning info", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_AUTO_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, + { "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" }, +#endif { NULL } }; @@ -185,6 +202,7 @@ const FFCodec ff_av1_nvenc_encoder = { .p.priv_class = &av1_nvenc_class, .defaults = defaults, .p.pix_fmts = 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 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c index a555252a5..8cbe4dca3 100644 --- a/libavcodec/nvenc_h264.c +++ b/libavcodec/nvenc_h264.c @@ -215,6 +215,15 @@ 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_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" }, + { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT }, 0, 0, VE, .unit = "lookahead_level" }, + { "0", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_0 }, 0, 0, VE, .unit = "lookahead_level" }, + { "1", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_1 }, 0, 0, VE, .unit = "lookahead_level" }, + { "2", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_2 }, 0, 0, VE, .unit = "lookahead_level" }, + { "3", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_3 }, 0, 0, VE, .unit = "lookahead_level" }, +#endif { NULL } }; @@ -256,6 +265,7 @@ const FFCodec ff_h264_nvenc_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .p.pix_fmts = 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 65fcb4efb..5696e14dd 100644 --- a/libavcodec/nvenc_hevc.c +++ b/libavcodec/nvenc_hevc.c @@ -51,8 +51,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_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" }, @@ -180,6 +183,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_NEW_BIT_DEPTH_API + { "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 }, @@ -196,6 +202,32 @@ 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_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" }, + { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_AUTOSELECT }, 0, 0, VE, .unit = "lookahead_level" }, + { "0", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_0 }, 0, 0, VE, .unit = "lookahead_level" }, + { "1", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_1 }, 0, 0, VE, .unit = "lookahead_level" }, + { "2", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_2 }, 0, 0, VE, .unit = "lookahead_level" }, + { "3", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_LOOKAHEAD_LEVEL_3 }, 0, 0, VE, .unit = "lookahead_level" }, +#endif +#ifdef NVENC_HAVE_UNIDIR_B + { "unidir_b", "Enable use of unidirectional B-Frames.", OFFSET(unidir_b), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, +#endif +#ifdef NVENC_HAVE_SPLIT_FRAME_ENCODING + { "split_encode_mode", "Specifies the split encoding mode", OFFSET(split_encode_mode), AV_OPT_TYPE_INT, { .i64 = NV_ENC_SPLIT_AUTO_MODE }, 0, NV_ENC_SPLIT_DISABLE_MODE, VE, .unit = "split_encode_mode" }, + { "disabled", "Disabled for all configurations", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_DISABLE_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, + { "auto", "Enabled or disabled depending on the preset and tuning info", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_SPLIT_AUTO_MODE }, 0, 0, VE, .unit = "split_encode_mode" }, + { "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" }, +#endif { NULL } }; @@ -232,6 +264,7 @@ const FFCodec ff_hevc_nvenc_encoder = { .p.priv_class = &hevc_nvenc_class, .defaults = defaults, .p.pix_fmts = 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 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, diff --git a/libavcodec/omx.c b/libavcodec/omx.c index 3fdde753b..2c3865506 100644 --- a/libavcodec/omx.c +++ b/libavcodec/omx.c @@ -38,6 +38,7 @@ #include "libavutil/common.h" #include "libavutil/imgutils.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" @@ -947,6 +948,7 @@ const FFCodec ff_mpeg4_omx_encoder = { FF_CODEC_ENCODE_CB(omx_encode_frame), .close = omx_encode_end, .p.pix_fmts = omx_encoder_pix_fmts, + .color_ranges = AVCOL_RANGE_MPEG, .p.capabilities = AV_CODEC_CAP_DELAY, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .p.priv_class = &omx_mpeg4enc_class, @@ -968,6 +970,7 @@ const FFCodec ff_h264_omx_encoder = { FF_CODEC_ENCODE_CB(omx_encode_frame), .close = omx_encode_end, .p.pix_fmts = 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, .p.priv_class = &omx_h264enc_class, diff --git a/libavcodec/on2avc.c b/libavcodec/on2avc.c index 8d0c88124..3badfae89 100644 --- a/libavcodec/on2avc.c +++ b/libavcodec/on2avc.c @@ -23,6 +23,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/ffmath.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/tx.h" diff --git a/libavcodec/options.c b/libavcodec/options.c index 5169f2e47..f60c41bdc 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -173,11 +173,10 @@ void avcodec_free_context(AVCodecContext **pavctx) av_freep(&avctx->extradata); av_freep(&avctx->subtitle_header); av_freep(&avctx->intra_matrix); + av_freep(&avctx->chroma_intra_matrix); av_freep(&avctx->inter_matrix); av_freep(&avctx->rc_override); av_channel_layout_uninit(&avctx->ch_layout); - av_frame_side_data_free( - &avctx->decoded_side_data, &avctx->nb_decoded_side_data); av_freep(pavctx); } diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index 7a2ef3474..47da41b0a 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -93,6 +93,7 @@ static const AVOption avcodec_options[] = { {"prft", "export Producer Reference Time through packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_PRFT}, INT_MIN, INT_MAX, A|V|S|E, .unit = "export_side_data"}, {"venc_params", "export video encoding parameters through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS}, INT_MIN, INT_MAX, V|D, .unit = "export_side_data"}, {"film_grain", "export film grain parameters through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_FILM_GRAIN}, INT_MIN, INT_MAX, V|D, .unit = "export_side_data"}, +{"enhancements", "export picture enhancement metadata through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_ENHANCEMENTS}, INT_MIN, INT_MAX, V|D, .unit = "export_side_data"}, {"time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, INT_MAX}, {"g", "set the group of picture (GOP) size", OFFSET(gop_size), AV_OPT_TYPE_INT, {.i64 = 12 }, INT_MIN, INT_MAX, V|E}, {"ar", "set audio sampling rate (in Hz)", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|D|E}, @@ -158,6 +159,7 @@ static const AVOption avcodec_options[] = { {"mmx", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_MMX }, INT_MIN, INT_MAX, V|E, .unit = "dct"}, {"altivec", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_ALTIVEC }, INT_MIN, INT_MAX, V|E, .unit = "dct"}, {"faan", "floating point AAN DCT", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_FAAN }, INT_MIN, INT_MAX, V|E, .unit = "dct"}, +{"neon", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_NEON }, INT_MIN, INT_MAX, V|E, .unit = "dct"}, {"lumi_mask", "compresses bright areas stronger than medium ones", OFFSET(lumi_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E}, {"tcplx_mask", "temporal complexity masking", OFFSET(temporal_cplx_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E}, {"scplx_mask", "spatial complexity masking", OFFSET(spatial_cplx_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E}, @@ -331,8 +333,11 @@ static const AVOption avcodec_options[] = { {"chroma-derived-nc", "Chroma-derived NCL", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_CHROMA_DERIVED_NCL }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, {"chroma-derived-c", "Chroma-derived CL", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_CHROMA_DERIVED_CL }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, {"ictcp", "ICtCp", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_ICTCP }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, +{"ipt-c2", "IPT-C2", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_IPT_C2 }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, {"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, {"ycocg", "YCGCO", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_YCGCO }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, +{"ycgco-re", "YCgCo-R, even add.", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_YCGCO_RE }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, +{"ycgco-ro", "YCgCo-R, odd add.", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_YCGCO_RO }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, {"bt2020_ncl", "BT.2020 NCL", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT2020_NCL }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, {"bt2020_cl", "BT.2020 CL", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT2020_CL }, INT_MIN, INT_MAX, V|E|D, .unit = "colorspace_type"}, {"color_range", "color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, INT_MAX, V|E|D, .unit = "color_range_type"}, diff --git a/libavcodec/opus/Makefile b/libavcodec/opus/Makefile new file mode 100644 index 000000000..53cb98e28 --- /dev/null +++ b/libavcodec/opus/Makefile @@ -0,0 +1,30 @@ +clean:: + $(RM) $(CLEANSUFFIXES:%=libavcodec/opus/%) + +OBJS-$(CONFIG_OPUS_DECODER) += \ + opus/dec.o \ + opus/dec_celt.o \ + opus/celt.o \ + opus/pvq.o \ + opus/silk.o \ + opus/tab.o \ + opus/dsp.o \ + opus/parse.o \ + opus/rc.o \ + + +OBJS-$(CONFIG_OPUS_PARSER) += \ + opus/parser.o \ + opus/parse.o \ + + +OBJS-$(CONFIG_OPUS_ENCODER) += \ + opus/enc.o \ + opus/enc_psy.o \ + opus/celt.o \ + opus/pvq.o \ + opus/rc.o \ + opus/tab.o \ + + +libavcodec/opus/%.o: CPPFLAGS += -I$(SRC_PATH)/libavcodec/ diff --git a/libavcodec/opus_celt.c b/libavcodec/opus/celt.c similarity index 99% rename from libavcodec/opus_celt.c rename to libavcodec/opus/celt.c index a24c38be5..3b9c63370 100644 --- a/libavcodec/opus_celt.c +++ b/libavcodec/opus/celt.c @@ -21,9 +21,9 @@ #include -#include "opus_celt.h" -#include "opus_pvq.h" -#include "opustab.h" +#include "celt.h" +#include "pvq.h" +#include "tab.h" void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc) { diff --git a/libavcodec/opus_celt.h b/libavcodec/opus/celt.h similarity index 98% rename from libavcodec/opus_celt.h rename to libavcodec/opus/celt.h index 2dbb79be6..e957f2c12 100644 --- a/libavcodec/opus_celt.h +++ b/libavcodec/opus/celt.h @@ -26,9 +26,10 @@ #include -#include "avcodec.h" -#include "opusdsp.h" -#include "opus_rc.h" +#include "libavcodec/avcodec.h" + +#include "dsp.h" +#include "rc.h" #include "libavutil/float_dsp.h" #include "libavutil/libm.h" diff --git a/libavcodec/opusdec.c b/libavcodec/opus/dec.c similarity index 99% rename from libavcodec/opusdec.c rename to libavcodec/opus/dec.c index c5f06e060..6c59dc1f4 100644 --- a/libavcodec/opusdec.c +++ b/libavcodec/opus/dec.c @@ -41,6 +41,7 @@ #include "libavutil/ffmath.h" #include "libavutil/float_dsp.h" #include "libavutil/frame.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" @@ -50,11 +51,11 @@ #include "codec_internal.h" #include "decode.h" #include "opus.h" -#include "opustab.h" -#include "opus_celt.h" -#include "opus_parse.h" -#include "opus_rc.h" -#include "opus_silk.h" +#include "tab.h" +#include "celt.h" +#include "parse.h" +#include "rc.h" +#include "silk.h" static const uint16_t silk_frame_duration_ms[16] = { 10, 20, 40, 60, diff --git a/libavcodec/opusdec_celt.c b/libavcodec/opus/dec_celt.c similarity index 98% rename from libavcodec/opusdec_celt.c rename to libavcodec/opus/dec_celt.c index c2904cc9e..3feb4a4e4 100644 --- a/libavcodec/opusdec_celt.c +++ b/libavcodec/opus/dec_celt.c @@ -27,9 +27,10 @@ #include -#include "opus_celt.h" -#include "opustab.h" -#include "opus_pvq.h" +#include "libavutil/mem.h" +#include "celt.h" +#include "tab.h" +#include "pvq.h" /* Use the 2D z-transform to apply prediction in both the time domain (alpha) * and the frequency domain (beta) */ @@ -459,7 +460,9 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, /* deemphasis */ block->emph_coeff = f->opusdsp.deemphasis(output[i], &block->buf[1024 - frame_size], - block->emph_coeff, frame_size); + block->emph_coeff, + ff_opus_deemph_weights, + frame_size); } if (channels == 1) @@ -515,7 +518,7 @@ void ff_celt_flush(CeltFrame *f) * a lesser discontinuity when seeking. * The deemphasis functions differ from libopus in that they require * an initial state divided by the coefficient. */ - block->emph_coeff = 0.0f / CELT_EMPH_COEFF; + block->emph_coeff = 0.0f / ff_opus_deemph_weights[0]; } f->seed = 0; diff --git a/libavcodec/opusdsp.c b/libavcodec/opus/dsp.c similarity index 88% rename from libavcodec/opusdsp.c rename to libavcodec/opus/dsp.c index 0764d712e..6cd76cece 100644 --- a/libavcodec/opusdsp.c +++ b/libavcodec/opus/dsp.c @@ -18,7 +18,8 @@ #include "config.h" #include "libavutil/attributes.h" -#include "opusdsp.h" +#include "libavutil/mem_internal.h" +#include "dsp.h" static void postfilter_c(float *data, int period, float *gains, int len) { @@ -43,10 +44,11 @@ static void postfilter_c(float *data, int period, float *gains, int len) } } -static float deemphasis_c(float *y, float *x, float coeff, int len) +static float deemphasis_c(float *y, float *x, float coeff, const float *weights, int len) { + const float c = weights[0]; for (int i = 0; i < len; i++) - coeff = y[i] = x[i] + coeff*CELT_EMPH_COEFF; + coeff = y[i] = x[i] + coeff*c; return coeff; } diff --git a/libavcodec/opusdsp.h b/libavcodec/opus/dsp.h similarity index 84% rename from libavcodec/opusdsp.h rename to libavcodec/opus/dsp.h index c2a301e83..2179ee695 100644 --- a/libavcodec/opusdsp.h +++ b/libavcodec/opus/dsp.h @@ -16,14 +16,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_OPUSDSP_H -#define AVCODEC_OPUSDSP_H - -#define CELT_EMPH_COEFF 0.8500061035f +#ifndef AVCODEC_OPUS_DSP_H +#define AVCODEC_OPUS_DSP_H typedef struct OpusDSP { void (*postfilter)(float *data, int period, float *gains, int len); - float (*deemphasis)(float *out, float *in, float coeff, int len); + float (*deemphasis)(float *out, float *in, float coeff, const float *weights, int len); } OpusDSP; void ff_opus_dsp_init(OpusDSP *ctx); @@ -32,4 +30,4 @@ void ff_opus_dsp_init_x86(OpusDSP *ctx); void ff_opus_dsp_init_aarch64(OpusDSP *ctx); void ff_opus_dsp_init_riscv(OpusDSP *ctx); -#endif /* AVCODEC_OPUSDSP_H */ +#endif /* AVCODEC_OPUS_DSP_H */ diff --git a/libavcodec/opusenc.c b/libavcodec/opus/enc.c similarity index 99% rename from libavcodec/opusenc.c rename to libavcodec/opus/enc.c index 379d0e0c5..539826311 100644 --- a/libavcodec/opusenc.c +++ b/libavcodec/opus/enc.c @@ -22,13 +22,14 @@ #include #include "encode.h" -#include "opusenc.h" -#include "opus_pvq.h" -#include "opusenc_psy.h" -#include "opustab.h" +#include "enc.h" +#include "pvq.h" +#include "enc_psy.h" +#include "tab.h" #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "bytestream.h" @@ -163,6 +164,7 @@ static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f) { const int subframesize = s->avctx->frame_size; const int subframes = OPUS_BLOCK_SIZE(s->packet.framesize) / subframesize; + const float c = ff_opus_deemph_weights[0]; /* Filter overlap */ for (int ch = 0; ch < f->channels; ch++) { @@ -171,7 +173,7 @@ static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f) for (int i = 0; i < CELT_OVERLAP; i++) { float sample = b->overlap[i]; b->overlap[i] = sample - m; - m = sample * CELT_EMPH_COEFF; + m = sample * c; } b->emph_coeff = m; } @@ -184,7 +186,7 @@ static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f) for (int i = 0; i < subframesize; i++) { float sample = b->samples[sf*subframesize + i]; b->samples[sf*subframesize + i] = sample - m; - m = sample * CELT_EMPH_COEFF; + m = sample * c; } if (sf != (subframes - 1)) b->emph_coeff = m; diff --git a/libavcodec/opusenc.h b/libavcodec/opus/enc.h similarity index 94% rename from libavcodec/opusenc.h rename to libavcodec/opus/enc.h index 4d691d6a7..d56f91e62 100644 --- a/libavcodec/opusenc.h +++ b/libavcodec/opus/enc.h @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_OPUSENC_H -#define AVCODEC_OPUSENC_H +#ifndef AVCODEC_OPUS_ENC_H +#define AVCODEC_OPUS_ENC_H #include "libavutil/intmath.h" #include "opus.h" @@ -52,4 +52,4 @@ typedef struct OpusPacketInfo { int frames; } OpusPacketInfo; -#endif /* AVCODEC_OPUSENC_H */ +#endif /* AVCODEC_OPUS_ENC_H */ diff --git a/libavcodec/opusenc_psy.c b/libavcodec/opus/enc_psy.c similarity index 99% rename from libavcodec/opusenc_psy.c rename to libavcodec/opus/enc_psy.c index 48ccd2ebd..250cfb567 100644 --- a/libavcodec/opusenc_psy.c +++ b/libavcodec/opus/enc_psy.c @@ -21,10 +21,11 @@ #include -#include "opusenc_psy.h" -#include "opus_celt.h" -#include "opus_pvq.h" -#include "opustab.h" +#include "libavutil/mem.h" +#include "enc_psy.h" +#include "celt.h" +#include "pvq.h" +#include "tab.h" #include "libavfilter/window_func.h" static float pvq_band_cost(CeltPVQ *pvq, CeltFrame *f, OpusRangeCoder *rc, int band, diff --git a/libavcodec/opusenc_psy.h b/libavcodec/opus/enc_psy.h similarity index 94% rename from libavcodec/opusenc_psy.h rename to libavcodec/opus/enc_psy.h index bc1a88c03..569a33c03 100644 --- a/libavcodec/opusenc_psy.h +++ b/libavcodec/opus/enc_psy.h @@ -19,15 +19,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_OPUSENC_PSY_H -#define AVCODEC_OPUSENC_PSY_H +#ifndef AVCODEC_OPUS_ENC_PSY_H +#define AVCODEC_OPUS_ENC_PSY_H #include "libavutil/tx.h" #include "libavutil/mem_internal.h" -#include "opusenc.h" -#include "opus_celt.h" -#include "opusenc_utils.h" +#include "enc.h" +#include "celt.h" +#include "enc_utils.h" /* Each step is 2.5ms */ typedef struct OpusPsyStep { @@ -94,4 +94,4 @@ int ff_opus_psy_init(OpusPsyContext *s, AVCodecContext *avctx, void ff_opus_psy_signal_eof(OpusPsyContext *s); int ff_opus_psy_end(OpusPsyContext *s); -#endif /* AVCODEC_OPUSENC_PSY_H */ +#endif /* AVCODEC_OPUS_ENC_PSY_H */ diff --git a/libavcodec/opusenc_utils.h b/libavcodec/opus/enc_utils.h similarity index 96% rename from libavcodec/opusenc_utils.h rename to libavcodec/opus/enc_utils.h index c76295979..3ebcdbbb6 100644 --- a/libavcodec/opusenc_utils.h +++ b/libavcodec/opus/enc_utils.h @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_OPUSENC_UTILS_H -#define AVCODEC_OPUSENC_UTILS_H +#ifndef AVCODEC_OPUS_ENC_UTILS_H +#define AVCODEC_OPUS_ENC_UTILS_H #include #include @@ -87,4 +87,4 @@ static inline float bessel_filter(FFBesselFilter *s, float x) return s->y[0]; } -#endif /* AVCODEC_OPUSENC_UTILS_H */ +#endif /* AVCODEC_OPUS_ENC_UTILS_H */ diff --git a/libavcodec/opus.h b/libavcodec/opus/opus.h similarity index 94% rename from libavcodec/opus.h rename to libavcodec/opus/opus.h index f87b63aac..9b1693329 100644 --- a/libavcodec/opus.h +++ b/libavcodec/opus/opus.h @@ -20,8 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_OPUS_H -#define AVCODEC_OPUS_H +#ifndef AVCODEC_OPUS_OPUS_H +#define AVCODEC_OPUS_OPUS_H #include @@ -56,4 +56,4 @@ enum OpusBandwidth { OPUS_BANDWITH_NB }; -#endif /* AVCODEC_OPUS_H */ +#endif /* AVCODEC_OPUS_OPUS_H */ diff --git a/libavcodec/opus_parse.c b/libavcodec/opus/parse.c similarity index 99% rename from libavcodec/opus_parse.c rename to libavcodec/opus/parse.c index e922d1f30..78a2a75fc 100644 --- a/libavcodec/opus_parse.c +++ b/libavcodec/opus/parse.c @@ -35,7 +35,7 @@ #include "internal.h" #include "mathops.h" #include "opus.h" -#include "opus_parse.h" +#include "parse.h" #include "vorbis_data.h" static const uint16_t opus_frame_duration[32] = { diff --git a/libavcodec/opus_parse.h b/libavcodec/opus/parse.h similarity index 98% rename from libavcodec/opus_parse.h rename to libavcodec/opus/parse.h index 83ed3c788..467957364 100644 --- a/libavcodec/opus_parse.h +++ b/libavcodec/opus/parse.h @@ -25,7 +25,7 @@ #include -#include "avcodec.h" +#include "libavcodec/avcodec.h" #include "opus.h" typedef struct OpusPacket { diff --git a/libavcodec/opus_parser.c b/libavcodec/opus/parser.c similarity index 99% rename from libavcodec/opus_parser.c rename to libavcodec/opus/parser.c index e6df34aba..41665e68f 100644 --- a/libavcodec/opus_parser.c +++ b/libavcodec/opus/parser.c @@ -25,10 +25,11 @@ * Determines the duration for each packet. */ +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "opus.h" -#include "opus_parse.h" +#include "parse.h" #include "parser.h" typedef struct OpusParserContext { diff --git a/libavcodec/opus_pvq.c b/libavcodec/opus/pvq.c similarity index 99% rename from libavcodec/opus_pvq.c rename to libavcodec/opus/pvq.c index 0a6dc4cdf..fe57ab02c 100644 --- a/libavcodec/opus_pvq.c +++ b/libavcodec/opus/pvq.c @@ -27,9 +27,10 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "mathops.h" -#include "opustab.h" -#include "opus_pvq.h" +#include "tab.h" +#include "pvq.h" #define ROUND_MUL16(a,b) ((MUL16(a, b) + 16384) >> 15) @@ -662,7 +663,7 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, if (itheta == 0) { imid = 32767; iside = 0; - fill = av_mod_uintp2(fill, blocks); + fill = av_zero_extend(fill, blocks); delta = -16384; } else if (itheta == 16384) { imid = 0; @@ -877,7 +878,7 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, for (i = 0; i < N0; i++) lowband_out[i] = n * X[i]; } - cm = av_mod_uintp2(cm, blocks); + cm = av_zero_extend(cm, blocks); } return cm; diff --git a/libavcodec/opus_pvq.h b/libavcodec/opus/pvq.h similarity index 98% rename from libavcodec/opus_pvq.h rename to libavcodec/opus/pvq.h index b71bc4903..07f568f6c 100644 --- a/libavcodec/opus_pvq.h +++ b/libavcodec/opus/pvq.h @@ -25,7 +25,7 @@ #include "libavutil/mem_internal.h" -#include "opus_celt.h" +#include "celt.h" #define QUANT_FN(name) uint32_t (name)(struct CeltPVQ *pvq, CeltFrame *f, \ OpusRangeCoder *rc, const int band, float *X, \ diff --git a/libavcodec/opus_rc.c b/libavcodec/opus/rc.c similarity index 98% rename from libavcodec/opus_rc.c rename to libavcodec/opus/rc.c index 031332c9c..8e58a52b8 100644 --- a/libavcodec/opus_rc.c +++ b/libavcodec/opus/rc.c @@ -20,7 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "opus_rc.h" +#include "rc.h" #define OPUS_RC_BITS 32 #define OPUS_RC_SYM 8 @@ -147,7 +147,7 @@ uint32_t ff_opus_rc_get_raw(OpusRangeCoder *rc, uint32_t count) rc->rb.bytes--; } - value = av_mod_uintp2(rc->rb.cacheval, count); + value = av_zero_extend(rc->rb.cacheval, count); rc->rb.cacheval >>= count; rc->rb.cachelen -= count; rc->total_bits += count; @@ -163,7 +163,7 @@ void ff_opus_rc_put_raw(OpusRangeCoder *rc, uint32_t val, uint32_t count) const int to_write = FFMIN(32 - rc->rb.cachelen, count); rc->total_bits += count; - rc->rb.cacheval |= av_mod_uintp2(val, to_write) << rc->rb.cachelen; + rc->rb.cacheval |= av_zero_extend(val, to_write) << rc->rb.cachelen; rc->rb.cachelen = (rc->rb.cachelen + to_write) % 32; if (!rc->rb.cachelen && count) { @@ -171,7 +171,7 @@ void ff_opus_rc_put_raw(OpusRangeCoder *rc, uint32_t val, uint32_t count) rc->rb.bytes += 4; rc->rb.position -= 4; rc->rb.cachelen = count - to_write; - rc->rb.cacheval = av_mod_uintp2(val >> to_write, rc->rb.cachelen); + rc->rb.cacheval = av_zero_extend(val >> to_write, rc->rb.cachelen); av_assert0(rc->rng_cur < rc->rb.position); } } diff --git a/libavcodec/opus_rc.h b/libavcodec/opus/rc.h similarity index 99% rename from libavcodec/opus_rc.h rename to libavcodec/opus/rc.h index 4cd2378bd..e9407f2ca 100644 --- a/libavcodec/opus_rc.h +++ b/libavcodec/opus/rc.h @@ -24,7 +24,9 @@ #define AVCODEC_OPUS_RC_H #include -#include "get_bits.h" + +#include "libavcodec/get_bits.h" + #include "opus.h" #define opus_ilog(i) (av_log2(i) + !!(i)) diff --git a/libavcodec/opus_silk.c b/libavcodec/opus/silk.c similarity index 99% rename from libavcodec/opus_silk.c rename to libavcodec/opus/silk.c index 27671516a..97bb95037 100644 --- a/libavcodec/opus_silk.c +++ b/libavcodec/opus/silk.c @@ -26,11 +26,12 @@ #include +#include "libavutil/mem.h" #include "mathops.h" #include "opus.h" -#include "opus_rc.h" -#include "opus_silk.h" -#include "opustab.h" +#include "rc.h" +#include "silk.h" +#include "tab.h" #define ROUND_MULL(a,b,s) (((MUL64(a, b) >> ((s) - 1)) + 1) >> 1) diff --git a/libavcodec/opus_silk.h b/libavcodec/opus/silk.h similarity index 98% rename from libavcodec/opus_silk.h rename to libavcodec/opus/silk.h index 4b595da2b..824b49271 100644 --- a/libavcodec/opus_silk.h +++ b/libavcodec/opus/silk.h @@ -24,7 +24,7 @@ #define AVCODEC_OPUS_SILK_H #include "opus.h" -#include "opus_rc.h" +#include "rc.h" #define SILK_HISTORY 322 #define SILK_MAX_LPC 16 diff --git a/libavcodec/opustab.c b/libavcodec/opus/tab.c similarity index 98% rename from libavcodec/opustab.c rename to libavcodec/opus/tab.c index 2a5751117..e7d20d168 100644 --- a/libavcodec/opustab.c +++ b/libavcodec/opus/tab.c @@ -22,7 +22,7 @@ #include "libavutil/mem_internal.h" -#include "opustab.h" +#include "tab.h" const uint8_t ff_opus_default_coupled_streams[] = { 0, 1, 1, 2, 2, 2, 2, 3 }; @@ -1159,3 +1159,31 @@ const uint32_t * const ff_celt_pvq_u_row[15] = { celt_pvq_u + 1207, celt_pvq_u + 1226, celt_pvq_u + 1240, celt_pvq_u + 1248, celt_pvq_u + 1254, celt_pvq_u + 1257 }; + +/* Deemphasis constant (alpha_p), as specified in RFC6716 as 0.8500061035. + * libopus uses a slighly 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 + +DECLARE_ALIGNED(16, const float, ff_opus_deemph_weights)[] = { + CELT_EMPH_COEFF, + CELT_EMPH_COEFF*CELT_EMPH_COEFF, + CELT_EMPH_COEFF*CELT_EMPH_COEFF*CELT_EMPH_COEFF, + CELT_EMPH_COEFF*CELT_EMPH_COEFF*CELT_EMPH_COEFF*CELT_EMPH_COEFF, + + 0, + CELT_EMPH_COEFF, + CELT_EMPH_COEFF*CELT_EMPH_COEFF, + CELT_EMPH_COEFF*CELT_EMPH_COEFF*CELT_EMPH_COEFF, + + 0, + 0, + CELT_EMPH_COEFF, + CELT_EMPH_COEFF*CELT_EMPH_COEFF, + + 0, + 0, + 0, + CELT_EMPH_COEFF, +}; diff --git a/libavcodec/opustab.h b/libavcodec/opus/tab.h similarity index 97% rename from libavcodec/opustab.h rename to libavcodec/opus/tab.h index 9c9f1b9d9..109a422b9 100644 --- a/libavcodec/opustab.h +++ b/libavcodec/opus/tab.h @@ -20,8 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_OPUSTAB_H -#define AVCODEC_OPUSTAB_H +#ifndef AVCODEC_OPUS_TAB_H +#define AVCODEC_OPUS_TAB_H #include @@ -161,7 +161,9 @@ 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]; +extern const float ff_opus_deemph_weights[]; + extern const uint32_t * const ff_celt_pvq_u_row[15]; FF_VISIBILITY_POP_HIDDEN -#endif /* AVCODEC_OPUSTAB_H */ +#endif /* AVCODEC_OPUS_TAB_H */ diff --git a/libavcodec/osq.c b/libavcodec/osq.c index 1663f0b15..83b4a9d61 100644 --- a/libavcodec/osq.c +++ b/libavcodec/osq.c @@ -21,6 +21,7 @@ #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" @@ -159,6 +160,8 @@ static int update_residue_parameter(OSQChannel *cb) int rice_k; sum = cb->sum; + if (!sum) + return 0; x = sum / cb->count; rice_k = ceil(log2(x)); if (rice_k >= 30) { @@ -297,7 +300,7 @@ static int do_decode(AVCodecContext *avctx, AVFrame *frame, int decorrelate, int dst[n] += (int)(P2 + P3) / 2 + (unsigned)p; break; case 8: - dst[n] += (int)(P2 + P3) / 2; + dst[n] += (int)(P2 + P3) / 2 + 0U; break; case 9: dst[n] += (int)(P2 * 2 + P3) / 3 + (unsigned)p; @@ -306,13 +309,13 @@ static int do_decode(AVCodecContext *avctx, AVFrame *frame, int decorrelate, int dst[n] += (int)(P2 + P3 * 2) / 3 + (unsigned)p; break; case 11: - dst[n] += (int)((unsigned)dst[A] + dst[B]) / 2; + dst[n] += (int)((unsigned)dst[A] + dst[B]) / 2 + 0U; break; case 12: dst[n] += (unsigned)dst[B]; break; case 13: - dst[n] += (int)(unsigned)(dst[D] + dst[B]) / 2; + dst[n] += (int)((unsigned)dst[D] + dst[B]) / 2 + 0U; break; case 14: dst[n] += (int)((unsigned)P2 + dst[A]) / 2 + (unsigned)p; @@ -339,7 +342,7 @@ static int do_decode(AVCodecContext *avctx, AVFrame *frame, int decorrelate, int if (nb_channels == 2 && ch == 1) { if (decorrelate) - dst[n] += s->decode_buffer[0][OFFSET+n]; + dst[n] += (unsigned)s->decode_buffer[0][OFFSET+n]; } if (downsample) diff --git a/libavcodec/avpacket.c b/libavcodec/packet.c similarity index 99% rename from libavcodec/avpacket.c rename to libavcodec/packet.c index e118bbaad..381001fd6 100644 --- a/libavcodec/avpacket.c +++ b/libavcodec/packet.c @@ -305,6 +305,8 @@ const char *av_packet_side_data_name(enum AVPacketSideDataType type) case AV_PKT_DATA_IAMF_MIX_GAIN_PARAM: return "IAMF Mix Gain Parameter Data"; case AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM: return "IAMF Demixing Info Parameter Data"; 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"; } return NULL; } diff --git a/libavcodec/packet.h b/libavcodec/packet.h index b0ba3baea..0a2801054 100644 --- a/libavcodec/packet.h +++ b/libavcodec/packet.h @@ -59,10 +59,6 @@ enum AVPacketSideDataType { * An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows: * @code * u32le param_flags - * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) - * s32le channel_count - * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) - * u64le channel_layout * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) * s32le sample_rate * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) @@ -330,6 +326,25 @@ enum AVPacketSideDataType { */ AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT, + /** + * The number of pixels to discard from the top/bottom/left/right border of the + * decoded frame to obtain the sub-rectangle intended for presentation. + * + * @code + * u32le crop_top + * u32le crop_bottom + * u32le crop_left + * u32le crop_right + * @endcode + */ + AV_PKT_DATA_FRAME_CROPPING, + + /** + * Raw LCEVC payload data, as a uint8_t array, with NAL emulation + * bytes intact. + */ + AV_PKT_DATA_LCEVC, + /** * The number of side data types. * This is not part of the public API/ABI in the sense that it may @@ -341,7 +356,9 @@ enum AVPacketSideDataType { AV_PKT_DATA_NB }; +#if FF_API_QUALITY_FACTOR #define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED +#endif /** * This structure stores auxiliary information for decoding, presenting, or diff --git a/libavcodec/pafvideo.c b/libavcodec/pafvideo.c index 14eb42435..c17ae9ae4 100644 --- a/libavcodec/pafvideo.c +++ b/libavcodec/pafvideo.c @@ -20,6 +20,7 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/parser.c b/libavcodec/parser.c index af17ee9c1..426cc314f 100644 --- a/libavcodec/parser.c +++ b/libavcodec/parser.c @@ -236,6 +236,7 @@ int ff_combine_frame(ParseContext *pc, int next, } pc->buffer = new_buffer; memcpy(&pc->buffer[pc->index], *buf, *buf_size); + memset(&pc->buffer[pc->index + *buf_size], 0, AV_INPUT_BUFFER_PADDING_SIZE); pc->index += *buf_size; return -1; } diff --git a/libavcodec/pcm.c b/libavcodec/pcm.c index 4abca7cc0..a51086a92 100644 --- a/libavcodec/pcm.c +++ b/libavcodec/pcm.c @@ -28,6 +28,7 @@ #include "config_components.h" #include "libavutil/attributes.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/reverse.h" #include "libavutil/thread.h" #include "avcodec.h" diff --git a/libavcodec/pcx.c b/libavcodec/pcx.c index 8e2aae7b5..15f2e3c2c 100644 --- a/libavcodec/pcx.c +++ b/libavcodec/pcx.c @@ -22,6 +22,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/pcxenc.c b/libavcodec/pcxenc.c index cf9b41b75..b763c7df4 100644 --- a/libavcodec/pcxenc.c +++ b/libavcodec/pcxenc.c @@ -26,9 +26,9 @@ * @see http://bespin.org/~qz/pc-gpe/pcx.txt */ +#include "libavutil/imgutils_internal.h" #include "avcodec.h" #include "bytestream.h" -#include "libavutil/imgutils.h" #include "codec_internal.h" #include "encode.h" diff --git a/libavcodec/pgssubdec.c b/libavcodec/pgssubdec.c index 5f76f1261..d93bcf1b6 100644 --- a/libavcodec/pgssubdec.c +++ b/libavcodec/pgssubdec.c @@ -31,6 +31,7 @@ #include "mathops.h" #include "libavutil/colorspace.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #define RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b)) diff --git a/libavcodec/pgxdec.c b/libavcodec/pgxdec.c index cc7cdb8c9..bffd57edd 100644 --- a/libavcodec/pgxdec.c +++ b/libavcodec/pgxdec.c @@ -139,8 +139,6 @@ static int pgx_decode_frame(AVCodecContext *avctx, AVFrame *p, return AVERROR_INVALIDDATA; if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; avctx->bits_per_raw_sample = depth; if (bpp == 8) write_frame_8(p, &g, width, height, sign, depth); diff --git a/libavcodec/photocd.c b/libavcodec/photocd.c index 07e8d460b..75948d1b4 100644 --- a/libavcodec/photocd.c +++ b/libavcodec/photocd.c @@ -331,9 +331,6 @@ static int photocd_decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; - bytestream2_init(gb, avpkt->data, avpkt->size); if (s->resolution < 3) { diff --git a/libavcodec/pictordec.c b/libavcodec/pictordec.c index 5aaa725bd..845a88245 100644 --- a/libavcodec/pictordec.c +++ b/libavcodec/pictordec.c @@ -25,6 +25,7 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "cga_data.h" diff --git a/libavcodec/pixblockdsp.c b/libavcodec/pixblockdsp.c index 8703e5aea..1fff24451 100644 --- a/libavcodec/pixblockdsp.c +++ b/libavcodec/pixblockdsp.c @@ -26,6 +26,13 @@ static void get_pixels_16_c(int16_t *restrict block, const uint8_t *pixels, ptrdiff_t stride) +{ + for (int i = 0; i < 8; i++) + AV_COPY128(block + i * 8, pixels + i * stride); +} + +static void get_pixels_unaligned_16_c(int16_t *restrict block, + const uint8_t *pixels, ptrdiff_t stride) { AV_COPY128U(block + 0 * 8, pixels + 0 * stride); AV_COPY128U(block + 1 * 8, pixels + 1 * stride); @@ -90,7 +97,7 @@ av_cold void ff_pixblockdsp_init(PixblockDSPContext *c, AVCodecContext *avctx) case 10: case 12: case 14: - c->get_pixels_unaligned = + c->get_pixels_unaligned = get_pixels_unaligned_16_c; c->get_pixels = get_pixels_16_c; break; default: @@ -103,8 +110,6 @@ av_cold void ff_pixblockdsp_init(PixblockDSPContext *c, AVCodecContext *avctx) #if ARCH_AARCH64 ff_pixblockdsp_init_aarch64(c, avctx, high_bit_depth); -#elif ARCH_ALPHA - ff_pixblockdsp_init_alpha(c, avctx, high_bit_depth); #elif ARCH_ARM ff_pixblockdsp_init_arm(c, avctx, high_bit_depth); #elif ARCH_PPC diff --git a/libavcodec/pixlet.c b/libavcodec/pixlet.c index 914f0636b..e9c561d70 100644 --- a/libavcodec/pixlet.c +++ b/libavcodec/pixlet.c @@ -22,6 +22,7 @@ #include #include "libavutil/intmath.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" @@ -161,7 +162,7 @@ static int read_low_coeffs(AVCodecContext *avctx, int16_t *dst, int size, continue; nbits = ((state + 8) >> 5) + (state ? ff_clz(state) : 32) - 24; - escape = av_mod_uintp2(16383, nbits); + escape = av_zero_extend(16383, nbits); cnt1 = get_unary(bc, 0, 8); if (cnt1 > 7) { rlen = get_bits(bc, 16); @@ -268,7 +269,7 @@ static int read_high_coeffs(AVCodecContext *avctx, const uint8_t *src, int16_t * continue; pfx = ((state + 8) >> 5) + (state ? ff_clz(state) : 32) - 24; - escape = av_mod_uintp2(16383, pfx); + escape = av_zero_extend(16383, pfx); cnt1 = get_unary(bc, 0, 8); if (cnt1 < 8) { if (pfx < 1 || pfx > 25) @@ -666,8 +667,6 @@ static int pixlet_decode_frame(AVCodecContext *avctx, AVFrame *p, bytestream2_skip(&ctx->gb, 8); - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; p->color_range = AVCOL_RANGE_JPEG; ret = ff_thread_get_buffer(avctx, p, 0); diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index ea586332b..c5b32c166 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -30,6 +30,7 @@ #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "libavutil/mastering_display_metadata.h" +#include "libavutil/mem.h" #include "libavutil/pixfmt.h" #include "libavutil/rational.h" #include "libavutil/stereo3d.h" @@ -41,8 +42,8 @@ #include "apng.h" #include "png.h" #include "pngdsp.h" +#include "progressframe.h" #include "thread.h" -#include "threadframe.h" #include "zlib_wrapper.h" #include @@ -62,8 +63,8 @@ typedef struct PNGDecContext { AVCodecContext *avctx; GetByteContext gb; - ThreadFrame last_picture; - ThreadFrame picture; + ProgressFrame last_picture; + ProgressFrame picture; AVDictionary *frame_metadata; @@ -874,7 +875,7 @@ static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s, s->bpp += byte_depth; } - ff_thread_release_ext_buffer(&s->picture); + ff_progress_frame_unref(&s->picture); if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) { /* We only need a buffer for the current picture. */ ret = ff_thread_get_buffer(avctx, p, 0); @@ -883,8 +884,8 @@ static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s, } else if (s->dispose_op == APNG_DISPOSE_OP_BACKGROUND) { /* We need a buffer for the current picture as well as * a buffer for the reference to retain. */ - ret = ff_thread_get_ext_buffer(avctx, &s->picture, - AV_GET_BUFFER_FLAG_REF); + ret = ff_progress_frame_get_buffer(avctx, &s->picture, + AV_GET_BUFFER_FLAG_REF); if (ret < 0) return ret; ret = ff_thread_get_buffer(avctx, p, 0); @@ -892,8 +893,9 @@ static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s, return ret; } else { /* The picture output this time and the reference to retain coincide. */ - if ((ret = ff_thread_get_ext_buffer(avctx, &s->picture, - AV_GET_BUFFER_FLAG_REF)) < 0) + ret = ff_progress_frame_get_buffer(avctx, &s->picture, + AV_GET_BUFFER_FLAG_REF); + if (ret < 0) return ret; ret = av_frame_ref(p, s->picture.f); if (ret < 0) @@ -1017,7 +1019,7 @@ static int decode_trns_chunk(AVCodecContext *avctx, PNGDecContext *s, for (i = 0; i < length / 2; i++) { /* only use the least significant bits */ - v = av_mod_uintp2(bytestream2_get_be16(gb), s->bit_depth); + v = av_zero_extend(bytestream2_get_be16(gb), s->bit_depth); if (s->bit_depth > 8) AV_WB16(&s->transparent_color_be[2 * i], v); @@ -1257,7 +1259,7 @@ static void handle_p_frame_png(PNGDecContext *s, AVFrame *p) ls = FFMIN(ls, s->width * s->bpp); - ff_thread_await_progress(&s->last_picture, INT_MAX, 0); + ff_progress_frame_await(&s->last_picture, INT_MAX); for (j = 0; j < s->height; j++) { for (i = 0; i < ls; i++) pd[i] += pd_last[i]; @@ -1289,7 +1291,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, return AVERROR_PATCHWELCOME; } - ff_thread_await_progress(&s->last_picture, INT_MAX, 0); + ff_progress_frame_await(&s->last_picture, INT_MAX); // copy unchanged rectangles from the last frame for (y = 0; y < s->y_offset; y++) @@ -1677,7 +1679,7 @@ exit_loop: } /* handle P-frames only if a predecessor frame is available */ - if (s->last_picture.f->data[0]) { + if (s->last_picture.f) { if ( !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG") && s->last_picture.f->width == p->width && s->last_picture.f->height== p->height @@ -1694,12 +1696,11 @@ exit_loop: if (CONFIG_APNG_DECODER && s->dispose_op == APNG_DISPOSE_OP_BACKGROUND) apng_reset_background(s, p); - ff_thread_report_progress(&s->picture, INT_MAX, 0); - - return 0; - + ret = 0; fail: - ff_thread_report_progress(&s->picture, INT_MAX, 0); + if (s->picture.f) + ff_progress_frame_report(&s->picture, INT_MAX); + return ret; } @@ -1786,8 +1787,8 @@ static int decode_frame_png(AVCodecContext *avctx, AVFrame *p, goto the_end; if (!(avctx->active_thread_type & FF_THREAD_FRAME)) { - ff_thread_release_ext_buffer(&s->last_picture); - FFSWAP(ThreadFrame, s->picture, s->last_picture); + ff_progress_frame_unref(&s->last_picture); + FFSWAP(ProgressFrame, s->picture, s->last_picture); } *got_frame = 1; @@ -1838,12 +1839,9 @@ static int decode_frame_apng(AVCodecContext *avctx, AVFrame *p, return ret; if (!(avctx->active_thread_type & FF_THREAD_FRAME)) { - if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) { - ff_thread_release_ext_buffer(&s->picture); - } else { - ff_thread_release_ext_buffer(&s->last_picture); - FFSWAP(ThreadFrame, s->picture, s->last_picture); - } + if (s->dispose_op != APNG_DISPOSE_OP_PREVIOUS) + FFSWAP(ProgressFrame, s->picture, s->last_picture); + ff_progress_frame_unref(&s->picture); } *got_frame = 1; @@ -1856,8 +1854,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { PNGDecContext *psrc = src->priv_data; PNGDecContext *pdst = dst->priv_data; - ThreadFrame *src_frame = NULL; - int ret; + const ProgressFrame *src_frame; if (dst == src) return 0; @@ -1882,12 +1879,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) src_frame = psrc->dispose_op == APNG_DISPOSE_OP_PREVIOUS ? &psrc->last_picture : &psrc->picture; - ff_thread_release_ext_buffer(&pdst->last_picture); - if (src_frame && src_frame->f->data[0]) { - ret = ff_thread_ref_frame(&pdst->last_picture, src_frame); - if (ret < 0) - return ret; - } + ff_progress_frame_replace(&pdst->last_picture, src_frame); return 0; } @@ -1898,10 +1890,6 @@ static av_cold int png_dec_init(AVCodecContext *avctx) PNGDecContext *s = avctx->priv_data; s->avctx = avctx; - s->last_picture.f = av_frame_alloc(); - s->picture.f = av_frame_alloc(); - if (!s->last_picture.f || !s->picture.f) - return AVERROR(ENOMEM); ff_pngdsp_init(&s->dsp); @@ -1912,10 +1900,8 @@ static av_cold int png_dec_end(AVCodecContext *avctx) { PNGDecContext *s = avctx->priv_data; - ff_thread_release_ext_buffer(&s->last_picture); - av_frame_free(&s->last_picture.f); - ff_thread_release_ext_buffer(&s->picture); - av_frame_free(&s->picture.f); + ff_progress_frame_unref(&s->last_picture); + ff_progress_frame_unref(&s->picture); av_freep(&s->buffer); s->buffer_size = 0; av_freep(&s->last_row); @@ -1943,7 +1929,7 @@ const FFCodec ff_apng_decoder = { 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_ALLOCATE_PROGRESS | + FF_CODEC_CAP_USES_PROGRESSFRAMES | FF_CODEC_CAP_ICC_PROFILES, }; #endif @@ -1961,7 +1947,8 @@ const FFCodec ff_png_decoder = { UPDATE_THREAD_CONTEXT(update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | - FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_USES_PROGRESSFRAMES | FF_CODEC_CAP_ICC_PROFILES, }; #endif diff --git a/libavcodec/pngdsp.c b/libavcodec/pngdsp.c index 65916b138..50ee96a68 100644 --- a/libavcodec/pngdsp.c +++ b/libavcodec/pngdsp.c @@ -21,20 +21,33 @@ #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 +#define BITS 64 +typedef uint64_t uint_native; +#else +#define BITS 32 +typedef uint32_t uint_native; +#endif +#define RN AV_JOIN(AV_RN, BITS) +#define RNA AV_JOIN(AV_JOIN(AV_RN, BITS), A) +#define WN AV_JOIN(AV_WN, BITS) + // 0x7f7f7f7f or 0x7f7f7f7f7f7f7f7f or whatever, depending on the cpu's native arithmetic size -#define pb_7f (~0UL / 255 * 0x7f) -#define pb_80 (~0UL / 255 * 0x80) +#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) { long i; - for (i = 0; i <= w - (int) sizeof(long); i += sizeof(long)) { - long a = *(long *)(src1 + i); - long b = *(long *)(src2 + i); - *(long *)(dst + i) = ((a & pb_7f) + (b & pb_7f)) ^ ((a ^ b) & pb_80); + for (i = 0; i <= w - (int) sizeof(uint_native); i += sizeof(uint_native)) { + uint_native a = RNA(src1 + i); + uint_native b = RN (src2 + i); + WN(dst + i, ((a & pb_7f) + (b & pb_7f)) ^ ((a ^ b) & pb_80)); } for (; i < w; i++) dst[i] = src1[i] + src2[i]; diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c index 819cd8365..cb79c04e1 100644 --- a/libavcodec/pngenc.c +++ b/libavcodec/pngenc.c @@ -33,6 +33,7 @@ #include "libavutil/csp.h" #include "libavutil/libm.h" #include "libavutil/mastering_display_metadata.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/rational.h" #include "libavutil/stereo3d.h" diff --git a/libavcodec/pnmdec.c b/libavcodec/pnmdec.c index 40cc2ae86..59013ada4 100644 --- a/libavcodec/pnmdec.c +++ b/libavcodec/pnmdec.c @@ -64,8 +64,6 @@ static int pnm_decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; avctx->bits_per_raw_sample = av_log2(s->maxval) + 1; switch (avctx->pix_fmt) { diff --git a/libavcodec/ppc/hevcdsp.c b/libavcodec/ppc/hevcdsp.c index c1d562a40..7b032ef26 100644 --- a/libavcodec/ppc/hevcdsp.c +++ b/libavcodec/ppc/hevcdsp.c @@ -26,7 +26,7 @@ #include "libavutil/ppc/cpu.h" #include "libavutil/ppc/util_altivec.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #if HAVE_ALTIVEC static const vec_s16 trans4[4] = { diff --git a/libavcodec/ppc/hpeldsp_altivec.c b/libavcodec/ppc/hpeldsp_altivec.c index a531b6b6e..4bf6b28ed 100644 --- a/libavcodec/ppc/hpeldsp_altivec.c +++ b/libavcodec/ppc/hpeldsp_altivec.c @@ -41,9 +41,9 @@ void ff_put_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t li register vector unsigned char pixelsv1D; int i; - register ptrdiff_t line_size_2 = line_size << 1; + register ptrdiff_t line_size_2 = line_size * (1 << 1); register ptrdiff_t line_size_3 = line_size + line_size_2; - register ptrdiff_t line_size_4 = line_size << 2; + 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 diff --git a/libavcodec/ppc/mpegvideoencdsp.c b/libavcodec/ppc/mpegvideoencdsp.c index 07d3e76ee..bd0c7fb15 100644 --- a/libavcodec/ppc/mpegvideoencdsp.c +++ b/libavcodec/ppc/mpegvideoencdsp.c @@ -30,7 +30,7 @@ #if HAVE_ALTIVEC #if HAVE_VSX -static int pix_norm1_altivec(const uint8_t *pix, int line_size) +static int pix_norm1_altivec(const uint8_t *pix, ptrdiff_t line_size) { int i, s = 0; const vector unsigned int zero = @@ -57,7 +57,7 @@ static int pix_norm1_altivec(const uint8_t *pix, int line_size) return s; } #else -static int pix_norm1_altivec(const uint8_t *pix, int line_size) +static int pix_norm1_altivec(const uint8_t *pix, ptrdiff_t line_size) { int i, s = 0; const vector unsigned int zero = @@ -87,7 +87,7 @@ static int pix_norm1_altivec(const uint8_t *pix, int line_size) #endif /* HAVE_VSX */ #if HAVE_VSX -static int pix_sum_altivec(const uint8_t *pix, int line_size) +static int pix_sum_altivec(const uint8_t *pix, ptrdiff_t line_size) { int i, s; const vector unsigned int zero = @@ -115,7 +115,7 @@ static int pix_sum_altivec(const uint8_t *pix, int line_size) return s; } #else -static int pix_sum_altivec(const uint8_t *pix, int line_size) +static int pix_sum_altivec(const uint8_t *pix, ptrdiff_t line_size) { int i, s; const vector unsigned int zero = diff --git a/libavcodec/profiles.c b/libavcodec/profiles.c index 5bb8f150e..3cef82be3 100644 --- a/libavcodec/profiles.c +++ b/libavcodec/profiles.c @@ -18,7 +18,8 @@ #include "config.h" -#include "avcodec.h" +#include "codec.h" +#include "defs.h" #include "profiles.h" #if !CONFIG_SMALL @@ -32,6 +33,7 @@ const AVProfile ff_aac_profiles[] = { { AV_PROFILE_AAC_MAIN, "Main" }, { AV_PROFILE_AAC_SSR, "SSR" }, { AV_PROFILE_AAC_LTP, "LTP" }, + { AV_PROFILE_AAC_USAC, "xHE-AAC" }, { AV_PROFILE_UNKNOWN }, }; @@ -97,6 +99,7 @@ const AVProfile ff_hevc_profiles[] = { { AV_PROFILE_HEVC_MAIN_10, "Main 10" }, { AV_PROFILE_HEVC_MAIN_STILL_PICTURE, "Main Still Picture" }, { AV_PROFILE_HEVC_REXT, "Rext" }, + { AV_PROFILE_HEVC_MULTIVIEW_MAIN, "Multiview Main" }, { AV_PROFILE_HEVC_SCC, "Scc" }, { AV_PROFILE_UNKNOWN }, }; diff --git a/libavcodec/profiles.h b/libavcodec/profiles.h index ffc8710ef..33b7ffc17 100644 --- a/libavcodec/profiles.h +++ b/libavcodec/profiles.h @@ -19,7 +19,8 @@ #ifndef AVCODEC_PROFILES_H #define AVCODEC_PROFILES_H -#include "avcodec.h" +#include "codec.h" +#include "defs.h" #include "libavutil/opt.h" #define FF_AVCTX_PROFILE_OPTION(name, description, type, value) \ @@ -34,6 +35,7 @@ FF_AVCTX_PROFILE_OPTION("aac_he_v2", NULL, AUDIO, AV_PROFILE_AAC_HE_V2)\ FF_AVCTX_PROFILE_OPTION("aac_ld", NULL, AUDIO, AV_PROFILE_AAC_LD)\ FF_AVCTX_PROFILE_OPTION("aac_eld", NULL, AUDIO, AV_PROFILE_AAC_ELD)\ + FF_AVCTX_PROFILE_OPTION("aac_xhe", NULL, AUDIO, AV_PROFILE_AAC_USAC)\ FF_AVCTX_PROFILE_OPTION("mpeg2_aac_low", NULL, AUDIO, AV_PROFILE_MPEG2_AAC_LOW)\ FF_AVCTX_PROFILE_OPTION("mpeg2_aac_he", NULL, AUDIO, AV_PROFILE_MPEG2_AAC_HE)\ diff --git a/libavcodec/progressframe.h b/libavcodec/progressframe.h new file mode 100644 index 000000000..32a345bee --- /dev/null +++ b/libavcodec/progressframe.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2022 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 + */ + +#ifndef AVCODEC_PROGRESSFRAME_H +#define AVCODEC_PROGRESSFRAME_H + +/** + * ProgressFrame is an API to easily share frames without an underlying + * av_frame_ref(). Its main usecase is in frame-threading scenarios, + * yet it could also be used for purely single-threaded decoders that + * want to keep multiple references to the same frame. + * + * The underlying principle behind the API is that all that is needed + * to share a frame is a reference count and a contract between all parties. + * The ProgressFrame provides the reference count and the frame is unreferenced + * via ff_thread_release_buffer() when the reference count reaches zero. + * + * In order to make this API also usable for frame-threaded decoders it also + * provides a way of exchanging simple information about the state of + * decoding the frame via ff_thread_progress_report() and + * ff_thread_progress_await(). + * + * The typical contract for frame-threaded decoders is as follows: + * Thread A initializes a ProgressFrame via ff_thread_progress_get_buffer() + * (which already allocates the AVFrame's data buffers), calls + * ff_thread_finish_setup() and starts decoding the frame. Later threads + * receive a reference to this frame, which means they get a pointer + * to the AVFrame and the internal reference count gets incremented. + * Later threads whose frames use A's frame as reference as well as + * the thread that will eventually output A's frame will wait for + * progress on said frame reported by A. As soon as A has reported + * that it has finished decoding its frame, it must no longer modify it + * (neither its data nor its properties). + * + * Because creating a reference with this API does not involve reads + * from the actual AVFrame, the decoding thread may modify the properties + * (i.e. non-data fields) until it has indicated to be done with this + * frame. This is important for e.g. propagating decode_error_flags; + * it also allows to add side-data late. + */ + +struct AVCodecContext; + +/** + * The ProgressFrame structure. + * Hint: It is guaranteed that the AVFrame pointer is at the start + * of ProgressFrame. This allows to use an unnamed + * union { + * struct { + * AVFrame *f; + * }; + * ProgressFrame pf; + * }; + * to simplify accessing the embedded AVFrame. + */ +typedef struct ProgressFrame { + struct AVFrame *f; + struct ProgressInternal *progress; +} ProgressFrame; + +/** + * Notify later decoding threads when part of their reference frame is ready. + * Call this when some part of the frame is finished decoding. + * Later calls with lower values of progress have no effect. + * + * @param f The frame being decoded. + * @param progress Value, in arbitrary units, of how much of the frame has decoded. + * + * @warning Calling this on a blank ProgressFrame causes undefined behaviour + */ +void ff_progress_frame_report(ProgressFrame *f, int progress); + +/** + * Wait for earlier decoding threads to finish reference frames. + * Call this before accessing some part of a frame, with a given + * value for progress, and it will return after the responsible decoding + * thread calls ff_thread_progress_report() with the same or + * higher value for progress. + * + * @param f The frame being referenced. + * @param progress Value, in arbitrary units, to wait for. + * + * @warning Calling this on a blank ProgressFrame causes undefined behaviour + */ +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(). + * + * @note: This must only be called by codecs with the + * FF_CODEC_CAP_USES_PROGRESSFRAMES internal cap. + */ +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. + * + * @note: This must only be called by codecs with the + * FF_CODEC_CAP_USES_PROGRESSFRAMES internal cap. + * @see ff_progress_frame_alloc + */ +int ff_progress_frame_get_buffer(struct AVCodecContext *avctx, + ProgressFrame *f, int flags); + +/** + * Give up a reference to the underlying frame contained in a ProgressFrame + * and reset the ProgressFrame, setting all pointers to NULL. + * + * @note: This implies that when using this API the check for whether + * a frame exists is by checking ProgressFrame.f and not + * ProgressFrame.f->data[0] or ProgressFrame.f->buf[0]. + */ +void ff_progress_frame_unref(ProgressFrame *f); + +/** + * Set dst->f to src->f and make dst a co-owner of src->f. + * dst can then be used to wait on progress of the underlying frame. + * + * @note: There is no underlying av_frame_ref() here. dst->f and src->f + * really point to the same AVFrame. Typically this means that + * the decoding thread is allowed to set all the properties of + * the AVFrame until it has indicated to have finished decoding. + * Afterwards later threads may read all of these fields. + * Access to the frame's data is governed by + * ff_thread_progress_report/await(). + */ +void ff_progress_frame_ref(ProgressFrame *dst, const ProgressFrame *src); + +/** + * Do nothing if dst and src already refer to the same AVFrame; + * otherwise unreference dst and if src is not blank, put a reference + * to src's AVFrame in its place (in case src is not blank). + */ +void ff_progress_frame_replace(ProgressFrame *dst, const ProgressFrame *src); + +#endif /* AVCODEC_PROGRESSFRAME_H */ diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec.c similarity index 99% rename from libavcodec/proresdec2.c rename to libavcodec/proresdec.c index faf6dfc97..6a256107b 100644 --- a/libavcodec/proresdec2.c +++ b/libavcodec/proresdec.c @@ -31,6 +31,7 @@ #include "config_components.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" @@ -786,8 +787,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } ctx->frame = frame; - ctx->frame->pict_type = AV_PICTURE_TYPE_I; - ctx->frame->flags |= AV_FRAME_FLAG_KEY; ctx->first_field = 1; buf += 8; diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c index b1a173e95..4493ed03b 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/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "avcodec.h" @@ -414,7 +415,7 @@ static void put_alpha_diff(PutBitContext *pb, int cur, int prev) const int dsize = 1 << dbits - 1; int diff = cur - prev; - diff = av_mod_uintp2(diff, abits); + diff = av_zero_extend(diff, abits); if (diff >= (1 << abits) - dsize) diff -= 1 << abits; if (diff < -dsize || diff > dsize || !diff) { @@ -955,6 +956,7 @@ const FFCodec ff_prores_aw_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .p.pix_fmts = pix_fmts, + .color_ranges = AVCOL_RANGE_MPEG, .priv_data_size = sizeof(ProresContext), .init = prores_encode_init, .close = prores_encode_close, @@ -972,6 +974,7 @@ const FFCodec ff_prores_encoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .p.pix_fmts = pix_fmts, + .color_ranges = AVCOL_RANGE_MPEG, .priv_data_size = sizeof(ProresContext), .init = prores_encode_init, .close = prores_encode_close, diff --git a/libavcodec/proresenc_kostya.c b/libavcodec/proresenc_kostya.c index 9d9f705ce..226f95f8c 100644 --- a/libavcodec/proresenc_kostya.c +++ b/libavcodec/proresenc_kostya.c @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -476,7 +477,7 @@ static void put_alpha_diff(PutBitContext *pb, int cur, int prev, int abits) const int dsize = 1 << dbits - 1; int diff = cur - prev; - diff = av_mod_uintp2(diff, abits); + diff = av_zero_extend(diff, abits); if (diff >= (1 << abits) - dsize) diff -= 1 << abits; if (diff < -dsize || diff > dsize || !diff) { @@ -720,7 +721,7 @@ static int est_alpha_diff(int cur, int prev, int abits) const int dsize = 1 << dbits - 1; int diff = cur - prev; - diff = av_mod_uintp2(diff, abits); + diff = av_zero_extend(diff, abits); if (diff >= (1 << abits) - dsize) diff -= 1 << abits; if (diff < -dsize || diff > dsize || !diff) @@ -1384,6 +1385,7 @@ const FFCodec ff_prores_ks_encoder = { AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE }, + .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, diff --git a/libavcodec/prosumer.c b/libavcodec/prosumer.c index a1ed6a9e5..1930e3e3e 100644 --- a/libavcodec/prosumer.c +++ b/libavcodec/prosumer.c @@ -194,8 +194,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, } } - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/psd.c b/libavcodec/psd.c index d3456e6b3..3e5bfcd36 100644 --- a/libavcodec/psd.c +++ b/libavcodec/psd.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "bytestream.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c index ca84b8139..d32e56de0 100644 --- a/libavcodec/pthread.c +++ b/libavcodec/pthread.c @@ -32,6 +32,7 @@ #include "libavutil/thread.h" #include "avcodec.h" +#include "avcodec_internal.h" #include "codec_internal.h" #include "pthread_internal.h" #include "thread.h" diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index fd356bd19..1b1b96623 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -22,18 +22,17 @@ * @see doc/multithreading.txt */ -#include "config.h" - #include -#include #include "avcodec.h" #include "avcodec_internal.h" +#include "codec_desc.h" #include "codec_internal.h" #include "decode.h" #include "hwaccel_internal.h" #include "hwconfig.h" #include "internal.h" +#include "packet_internal.h" #include "pthread_internal.h" #include "refstruct.h" #include "thread.h" @@ -66,6 +65,12 @@ enum { INITIALIZED, ///< Thread has been properly set up }; +typedef struct DecodedFrames { + AVFrame **f; + size_t nb_f; + size_t nb_f_allocated; +} DecodedFrames; + typedef struct ThreadFrameProgress { atomic_int progress[2]; } ThreadFrameProgress; @@ -90,8 +95,10 @@ typedef struct PerThreadContext { AVPacket *avpkt; ///< Input packet (for decoding) or output (for encoding). - AVFrame *frame; ///< Output frame (for decoding) or input (for encoding). - int got_frame; ///< The output of got_picture_ptr from the last avcodec_decode_video() call. + /** + * Decoded frames from a single decode iteration. + */ + DecodedFrames df; int result; ///< The result of the last codec decode/encode() call. atomic_int state; @@ -108,6 +115,10 @@ typedef struct PerThreadContext { int hwaccel_threadsafe; atomic_int debug_threads; ///< Set if the FF_DEBUG_THREADS option is set. + + /// The following two fields have the same semantics as the DecodeContext field + int intra_only_flag; + enum AVPictureType initial_pict_type; } PerThreadContext; /** @@ -128,14 +139,17 @@ typedef struct FrameThreadContext { pthread_cond_t async_cond; int async_lock; + DecodedFrames df; + int result; + + /** + * Packet to be submitted to the next thread for decoding. + */ + AVPacket *next_pkt; + int next_decoding; ///< The next context to submit a packet to. int next_finished; ///< The next context to return output from. - int delaying; /**< - * Set for the first N packets, where N is the number of threads. - * While it is set, ff_thread_en/decode_frame won't return any results. - */ - /* hwaccel state for thread-unsafe hwaccels is temporarily stored here in * order to transfer its ownership to the next decoding thread without the * need for extra synchronization */ @@ -178,6 +192,52 @@ static void thread_set_name(PerThreadContext *p) ff_thread_setname(name); } +// get a free frame to decode into +static AVFrame *decoded_frames_get_free(DecodedFrames *df) +{ + if (df->nb_f == df->nb_f_allocated) { + AVFrame **tmp = av_realloc_array(df->f, df->nb_f + 1, + sizeof(*df->f)); + if (!tmp) + return NULL; + df->f = tmp; + + df->f[df->nb_f] = av_frame_alloc(); + if (!df->f[df->nb_f]) + return NULL; + + df->nb_f_allocated++; + } + + av_assert0(!df->f[df->nb_f]->buf[0]); + + return df->f[df->nb_f]; +} + +static void decoded_frames_pop(DecodedFrames *df, AVFrame *dst) +{ + AVFrame *tmp_frame = df->f[0]; + av_frame_move_ref(dst, tmp_frame); + memmove(df->f, df->f + 1, (df->nb_f - 1) * sizeof(*df->f)); + df->f[--df->nb_f] = tmp_frame; +} + +static void decoded_frames_flush(DecodedFrames *df) +{ + for (size_t i = 0; i < df->nb_f; i++) + av_frame_unref(df->f[i]); + df->nb_f = 0; +} + +static void decoded_frames_free(DecodedFrames *df) +{ + for (size_t i = 0; i < df->nb_f_allocated; i++) + av_frame_free(&df->f[i]); + av_freep(&df->f); + df->nb_f = 0; + df->nb_f_allocated = 0; +} + /** * Codec worker thread. * @@ -195,6 +255,8 @@ static attribute_align_arg void *frame_worker_thread(void *arg) pthread_mutex_lock(&p->mutex); while (1) { + int ret; + while (atomic_load(&p->state) == STATE_INPUT_READY && !p->die) pthread_cond_wait(&p->input_cond, &p->mutex); @@ -218,16 +280,31 @@ static attribute_align_arg void *frame_worker_thread(void *arg) p->hwaccel_serializing = 1; } - av_frame_unref(p->frame); - p->got_frame = 0; - p->result = codec->cb.decode(avctx, p->frame, &p->got_frame, p->avpkt); + ret = 0; + while (ret >= 0) { + AVFrame *frame; - if ((p->result < 0 || !p->got_frame) && p->frame->buf[0]) - av_frame_unref(p->frame); + /* get the frame which will store the output */ + frame = decoded_frames_get_free(&p->df); + if (!frame) { + p->result = AVERROR(ENOMEM); + goto alloc_fail; + } + + /* do the actual decoding */ + ret = ff_decode_receive_frame_internal(avctx, frame); + if (ret == 0) + p->df.nb_f++; + else if (ret < 0 && frame->buf[0]) + av_frame_unref(frame); + + p->result = (ret == AVERROR(EAGAIN)) ? 0 : ret; + } if (atomic_load(&p->state) == STATE_SETTING_UP) ff_thread_finish_setup(avctx); +alloc_fail: if (p->hwaccel_serializing) { /* wipe hwaccel state for thread-unsafe hwaccels to avoid stale * pointers lying around; @@ -329,6 +406,7 @@ FF_ENABLE_DEPRECATION_WARNINGS dst->hwaccel_flags = src->hwaccel_flags; ff_refstruct_replace(&dst->internal->pool, src->internal->pool); + ff_decode_internal_sync(dst, src); } if (for_user) { @@ -422,18 +500,21 @@ static int update_context_from_user(AVCodecContext *dst, const AVCodecContext *s } static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx, - AVPacket *avpkt) + AVPacket *in_pkt) { FrameThreadContext *fctx = p->parent; PerThreadContext *prev_thread = fctx->prev_thread; const AVCodec *codec = p->avctx->codec; int ret; - if (!avpkt->size && !(codec->capabilities & AV_CODEC_CAP_DELAY)) - return 0; - pthread_mutex_lock(&p->mutex); + av_packet_unref(p->avpkt); + av_packet_move_ref(p->avpkt, in_pkt); + + if (AVPACKET_IS_EMPTY(p->avpkt)) + p->avctx->internal->draining = 1; + ret = update_context_from_user(p->avctx, user_avctx); if (ret) { pthread_mutex_unlock(&p->mutex); @@ -444,7 +525,6 @@ static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx, memory_order_relaxed); if (prev_thread) { - int err; if (atomic_load(&prev_thread->state) == STATE_SETTING_UP) { pthread_mutex_lock(&prev_thread->progress_mutex); while (atomic_load(&prev_thread->state) == STATE_SETTING_UP) @@ -452,10 +532,16 @@ static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx, pthread_mutex_unlock(&prev_thread->progress_mutex); } - err = update_context_from_thread(p->avctx, prev_thread->avctx, 0); - if (err) { - pthread_mutex_unlock(&p->mutex); - return err; + /* codecs without delay might not be prepared to be called repeatedly here during + * flushing (vp3/theora), and also don't need to be, since from this point on, they + * will always return EOF anyway */ + if (!p->avctx->internal->draining || + (codec->capabilities & AV_CODEC_CAP_DELAY)) { + ret = update_context_from_thread(p->avctx, prev_thread->avctx, 0); + if (ret) { + pthread_mutex_unlock(&p->mutex); + return ret; + } } } @@ -467,70 +553,47 @@ static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx, FFSWAP(void*, p->avctx->internal->hwaccel_priv_data, fctx->stash_hwaccel_priv); } - av_packet_unref(p->avpkt); - ret = av_packet_ref(p->avpkt, avpkt); - if (ret < 0) { - pthread_mutex_unlock(&p->mutex); - av_log(p->avctx, AV_LOG_ERROR, "av_packet_ref() failed in submit_packet()\n"); - return ret; - } - atomic_store(&p->state, STATE_SETTING_UP); pthread_cond_signal(&p->input_cond); pthread_mutex_unlock(&p->mutex); fctx->prev_thread = p; - fctx->next_decoding++; + fctx->next_decoding = (fctx->next_decoding + 1) % p->avctx->thread_count; return 0; } -int ff_thread_decode_frame(AVCodecContext *avctx, - AVFrame *picture, int *got_picture_ptr, - AVPacket *avpkt) +int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame *frame) { FrameThreadContext *fctx = avctx->internal->thread_ctx; - int finished = fctx->next_finished; - PerThreadContext *p; - int err; + int ret = 0; /* release the async lock, permitting blocked hwaccel threads to * go forward while we are in this function */ async_unlock(fctx); - /* - * Submit a packet to the next decoding thread. - */ + /* submit packets to threads while there are no buffered results to return */ + while (!fctx->df.nb_f && !fctx->result) { + PerThreadContext *p; - p = &fctx->threads[fctx->next_decoding]; - err = submit_packet(p, avctx, avpkt); - if (err) - goto finish; - - /* - * If we're still receiving the initial packets, don't return a frame. - */ - - if (fctx->next_decoding > (avctx->thread_count-1-(avctx->codec_id == AV_CODEC_ID_FFV1))) - fctx->delaying = 0; - - if (fctx->delaying) { - *got_picture_ptr=0; - if (avpkt->size) { - err = avpkt->size; + /* 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); + if (ret < 0 && ret != AVERROR_EOF) goto finish; - } - } - /* - * Return the next available frame from the oldest thread. - * If we're at the end of the stream, then we have to skip threads that - * didn't output a frame/error, because we don't want to accidentally signal - * EOF (avpkt->size == 0 && *got_picture_ptr == 0 && err >= 0). - */ + ret = submit_packet(&fctx->threads[fctx->next_decoding], avctx, + fctx->next_pkt); + if (ret < 0) + goto finish; - do { - p = &fctx->threads[finished++]; + /* do not return any frames until all threads have something to do */ + if (fctx->next_decoding != fctx->next_finished && + !avctx->internal->draining) + continue; + + p = &fctx->threads[fctx->next_finished]; + fctx->next_finished = (fctx->next_finished + 1) % avctx->thread_count; if (atomic_load(&p->state) != STATE_INPUT_READY) { pthread_mutex_lock(&p->progress_mutex); @@ -539,35 +602,26 @@ int ff_thread_decode_frame(AVCodecContext *avctx, pthread_mutex_unlock(&p->progress_mutex); } - av_frame_move_ref(picture, p->frame); - *got_picture_ptr = p->got_frame; - picture->pkt_dts = p->avpkt->dts; - err = p->result; + update_context_from_thread(avctx, p->avctx, 1); + fctx->result = p->result; + p->result = 0; + if (p->df.nb_f) + FFSWAP(DecodedFrames, fctx->df, p->df); + } - /* - * A later call with avkpt->size == 0 may loop over all threads, - * including this one, searching for a frame/error to return before being - * stopped by the "finished != fctx->next_finished" condition. - * Make sure we don't mistakenly return the same frame/error again. - */ - p->got_frame = 0; - p->result = 0; + /* a thread may return multiple frames AND an error + * we first return all the frames, then the error */ + if (fctx->df.nb_f) { + decoded_frames_pop(&fctx->df, frame); + ret = 0; + } else { + ret = fctx->result; + fctx->result = 0; + } - if (finished >= avctx->thread_count) finished = 0; - } while (!avpkt->size && !*got_picture_ptr && err >= 0 && finished != fctx->next_finished); - - update_context_from_thread(avctx, p->avctx, 1); - - if (fctx->next_decoding >= avctx->thread_count) fctx->next_decoding = 0; - - fctx->next_finished = finished; - - /* return the size of the consumed packet if no error occurred */ - if (err >= 0) - err = avpkt->size; finish: async_lock(fctx); - return err; + return ret; } void ff_thread_report_progress(ThreadFrame *f, int n, int field) @@ -675,7 +729,6 @@ static void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count pthread_cond_wait(&p->output_cond, &p->progress_mutex); pthread_mutex_unlock(&p->progress_mutex); } - p->got_frame = 0; } async_lock(fctx); @@ -728,12 +781,16 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) } ff_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); av_freep(&ctx->internal); av_buffer_unref(&ctx->hw_frames_ctx); + av_frame_side_data_free(&ctx->decoded_side_data, + &ctx->nb_decoded_side_data); } - av_frame_free(&p->frame); + decoded_frames_free(&p->df); ff_pthread_free(p, per_thread_offsets); av_packet_free(&p->avpkt); @@ -741,6 +798,9 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) av_freep(&p->avctx); } + decoded_frames_free(&fctx->df); + av_packet_free(&fctx->next_pkt); + av_freep(&fctx->threads); ff_pthread_free(fctx, thread_ctx_offsets); @@ -761,12 +821,21 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, AVCodecContext *copy; int err; + p->initial_pict_type = AV_PICTURE_TYPE_NONE; + if (avctx->codec_descriptor->props & AV_CODEC_PROP_INTRA_ONLY) { + p->intra_only_flag = AV_FRAME_FLAG_KEY; + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) + p->initial_pict_type = AV_PICTURE_TYPE_I; + } + atomic_init(&p->state, STATE_INPUT_READY); copy = av_memdup(avctx, sizeof(*avctx)); if (!copy) return AVERROR(ENOMEM); copy->priv_data = NULL; + copy->decoded_side_data = NULL; + copy->nb_decoded_side_data = 0; /* From now on, this PerThreadContext will be cleaned up by * ff_frame_thread_free in case of errors. */ @@ -778,7 +847,9 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, copy->internal = ff_decode_internal_alloc(); if (!copy->internal) return AVERROR(ENOMEM); + ff_decode_internal_sync(copy, avctx); copy->internal->thread_ctx = p; + copy->internal->progress_frame_pool = avctx->internal->progress_frame_pool; copy->delay = avctx->delay; @@ -799,13 +870,17 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, if (err < 0) return err; - if (!(p->frame = av_frame_alloc()) || - !(p->avpkt = av_packet_alloc())) + if (!(p->avpkt = av_packet_alloc())) return AVERROR(ENOMEM); + copy->internal->is_frame_mt = 1; if (!first) copy->internal->is_copy = 1; + copy->internal->in_pkt = av_packet_alloc(); + if (!copy->internal->in_pkt) + return AVERROR(ENOMEM); + copy->internal->last_pkt_props = av_packet_alloc(); if (!copy->internal->last_pkt_props) return AVERROR(ENOMEM); @@ -820,9 +895,19 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, } p->thread_init = NEEDS_CLOSE; - if (first) + if (first) { update_context_from_thread(avctx, copy, 1); + av_frame_side_data_free(&avctx->decoded_side_data, &avctx->nb_decoded_side_data); + for (int i = 0; i < copy->nb_decoded_side_data; i++) { + err = av_frame_side_data_clone(&avctx->decoded_side_data, + &avctx->nb_decoded_side_data, + copy->decoded_side_data[i], 0); + if (err < 0) + return err; + } + } + atomic_init(&p->debug_threads, (copy->debug & FF_DEBUG_THREADS) != 0); err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p)); @@ -865,8 +950,11 @@ int ff_frame_thread_init(AVCodecContext *avctx) return err; } + fctx->next_pkt = av_packet_alloc(); + if (!fctx->next_pkt) + return AVERROR(ENOMEM); + fctx->async_lock = 1; - fctx->delaying = 1; if (codec->p.type == AVMEDIA_TYPE_VIDEO) avctx->delay = avctx->thread_count - 1; @@ -907,17 +995,18 @@ void ff_thread_flush(AVCodecContext *avctx) } fctx->next_decoding = fctx->next_finished = 0; - fctx->delaying = 1; fctx->prev_thread = NULL; + + decoded_frames_flush(&fctx->df); + fctx->result = 0; + for (i = 0; i < avctx->thread_count; i++) { PerThreadContext *p = &fctx->threads[i]; - // Make sure decode flush calls with size=0 won't return old frames - p->got_frame = 0; - av_frame_unref(p->frame); + + decoded_frames_flush(&p->df); p->result = 0; - if (ffcodec(avctx->codec)->flush) - ffcodec(avctx->codec)->flush(p->avctx); + avcodec_flush_buffers(p->avctx); } } @@ -970,22 +1059,15 @@ int ff_thread_get_ext_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) int ret; f->owner[0] = f->owner[1] = avctx; - /* Hint: It is possible for this function to be called with codecs - * that don't support frame threading at all, namely in case - * a frame-threaded decoder shares code with codecs that are not. - * This currently affects non-MPEG-4 mpegvideo codecs and and VP7. - * The following check will always be true for them. */ if (!(avctx->active_thread_type & FF_THREAD_FRAME)) return ff_get_buffer(avctx, f->f, flags); - if (ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_ALLOCATE_PROGRESS) { - f->progress = ff_refstruct_allocz(sizeof(*f->progress)); - if (!f->progress) - return AVERROR(ENOMEM); + f->progress = ff_refstruct_allocz(sizeof(*f->progress)); + if (!f->progress) + return AVERROR(ENOMEM); - atomic_init(&f->progress->progress[0], -1); - atomic_init(&f->progress->progress[1], -1); - } + atomic_init(&f->progress->progress[0], -1); + atomic_init(&f->progress->progress[1], -1); ret = ff_thread_get_buffer(avctx, f->f, flags); if (ret) @@ -1000,3 +1082,35 @@ void ff_thread_release_ext_buffer(ThreadFrame *f) if (f->f) av_frame_unref(f->f); } + +enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset) +{ + PerThreadContext *p; + const void *ref; + + if (!avctx->internal->is_copy) + return avctx->active_thread_type & FF_THREAD_FRAME ? + FF_THREAD_IS_FIRST_THREAD : FF_THREAD_NO_FRAME_THREADING; + + p = avctx->internal->thread_ctx; + + av_assert1(memcpy(&ref, (char*)avctx->priv_data + offset, sizeof(ref)) && ref == NULL); + + 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); + + return FF_THREAD_IS_COPY; +} + +int ff_thread_get_packet(AVCodecContext *avctx, AVPacket *pkt) +{ + PerThreadContext *p = avctx->internal->thread_ctx; + + if (!AVPACKET_IS_EMPTY(p->avpkt)) { + av_packet_move_ref(pkt, p->avpkt); + return 0; + } + + return avctx->internal->draining ? AVERROR_EOF : AVERROR(EAGAIN); +} diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c index a4d31c6f4..ac455e48e 100644 --- a/libavcodec/pthread_slice.c +++ b/libavcodec/pthread_slice.c @@ -41,11 +41,6 @@ typedef int (action_func)(AVCodecContext *c, void *arg); typedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr); typedef int (main_func)(AVCodecContext *c); -typedef struct Progress { - pthread_cond_t cond; - pthread_mutex_t mutex; -} Progress; - typedef struct SliceThreadContext { AVSliceThread *thread; action_func *func; @@ -54,11 +49,6 @@ typedef struct SliceThreadContext { void *args; int *rets; int job_size; - - int *entries; - int entries_count; - int thread_count; - Progress *progress; } SliceThreadContext; static void main_function(void *priv) { @@ -82,18 +72,9 @@ static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb void ff_slice_thread_free(AVCodecContext *avctx) { SliceThreadContext *c = avctx->internal->thread_ctx; - int i; avpriv_slicethread_free(&c->thread); - for (i = 0; i < c->thread_count; i++) { - Progress *const progress = &c->progress[i]; - pthread_mutex_destroy(&progress->mutex); - pthread_cond_destroy(&progress->cond); - } - - av_freep(&c->entries); - av_freep(&c->progress); av_freep(&avctx->internal->thread_ctx); } @@ -175,86 +156,3 @@ int ff_slice_thread_init(AVCodecContext *avctx) avctx->execute2 = thread_execute2; return 0; } - -int av_cold ff_slice_thread_init_progress(AVCodecContext *avctx) -{ - SliceThreadContext *const p = avctx->internal->thread_ctx; - int err, i = 0, thread_count = avctx->thread_count; - - p->progress = av_calloc(thread_count, sizeof(*p->progress)); - if (!p->progress) { - err = AVERROR(ENOMEM); - goto fail; - } - - for (; i < thread_count; i++) { - Progress *const progress = &p->progress[i]; - err = pthread_mutex_init(&progress->mutex, NULL); - if (err) { - err = AVERROR(err); - goto fail; - } - err = pthread_cond_init (&progress->cond, NULL); - if (err) { - err = AVERROR(err); - pthread_mutex_destroy(&progress->mutex); - goto fail; - } - } - err = 0; -fail: - p->thread_count = i; - return err; -} - -void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n) -{ - SliceThreadContext *p = avctx->internal->thread_ctx; - Progress *const progress = &p->progress[thread]; - int *entries = p->entries; - - pthread_mutex_lock(&progress->mutex); - entries[field] +=n; - pthread_cond_signal(&progress->cond); - pthread_mutex_unlock(&progress->mutex); -} - -void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift) -{ - SliceThreadContext *p = avctx->internal->thread_ctx; - Progress *progress; - int *entries = p->entries; - - if (!entries || !field) return; - - thread = thread ? thread - 1 : p->thread_count - 1; - progress = &p->progress[thread]; - - pthread_mutex_lock(&progress->mutex); - while ((entries[field - 1] - entries[field]) < shift){ - pthread_cond_wait(&progress->cond, &progress->mutex); - } - pthread_mutex_unlock(&progress->mutex); -} - -int ff_slice_thread_allocz_entries(AVCodecContext *avctx, int count) -{ - if (avctx->active_thread_type & FF_THREAD_SLICE) { - SliceThreadContext *p = avctx->internal->thread_ctx; - - if (p->entries_count == count) { - memset(p->entries, 0, p->entries_count * sizeof(*p->entries)); - return 0; - } - av_freep(&p->entries); - - p->entries = av_calloc(count, sizeof(*p->entries)); - if (!p->entries) { - p->entries_count = 0; - return AVERROR(ENOMEM); - } - p->entries_count = count; - } - - return 0; -} diff --git a/libavcodec/put_bits.h b/libavcodec/put_bits.h index 4561dc131..0caaa6b33 100644 --- a/libavcodec/put_bits.h +++ b/libavcodec/put_bits.h @@ -282,7 +282,7 @@ static inline void put_sbits(PutBitContext *pb, int n, int32_t value) { av_assert2(n >= 0 && n <= 31); - put_bits(pb, n, av_mod_uintp2(value, n)); + put_bits(pb, n, av_zero_extend(value, n)); } /** diff --git a/libavcodec/put_golomb.h b/libavcodec/put_golomb.h index df47fd2c0..43c1233fd 100644 --- a/libavcodec/put_golomb.h +++ b/libavcodec/put_golomb.h @@ -103,7 +103,7 @@ static inline void set_ur_golomb(PutBitContext *pb, int i, int k, int limit, e = i >> k; if (e < limit) - put_bits(pb, e + k + 1, (1 << k) + av_mod_uintp2(i, k)); + put_bits(pb, e + k + 1, (1 << k) + av_zero_extend(i, k)); else put_bits(pb, limit + esc_len, i - limit + 1); } diff --git a/libavcodec/qdrw.c b/libavcodec/qdrw.c index 21a53b8e7..ca38f48bd 100644 --- a/libavcodec/qdrw.c +++ b/libavcodec/qdrw.c @@ -506,9 +506,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } if (*got_frame) { - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; - return avpkt->size; } else { av_log(avctx, AV_LOG_ERROR, "Frame contained no usable data\n"); diff --git a/libavcodec/qoidec.c b/libavcodec/qoidec.c index 37bc2084c..bb48fa23c 100644 --- a/libavcodec/qoidec.c +++ b/libavcodec/qoidec.c @@ -106,9 +106,6 @@ static int qoi_decode_frame(AVCodecContext *avctx, AVFrame *p, memcpy(&dst[off_x * channels], px, channels); } - p->flags |= AV_FRAME_FLAG_KEY; - p->pict_type = AV_PICTURE_TYPE_I; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index 452c0c685..8a3dc9570 100644 --- a/libavcodec/qsv.c +++ b/libavcodec/qsv.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -29,18 +30,17 @@ #include "libavutil/error.h" #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_qsv.h" -#include "libavutil/imgutils.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "qsv_internal.h" +#include "refstruct.h" #define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl)) #define QSV_HAVE_USER_PLUGIN !QSV_ONEVPL #define QSV_HAVE_AUDIO !QSV_ONEVPL -#include "mfxvp8.h" - #if QSV_HAVE_USER_PLUGIN #include #endif @@ -73,6 +73,10 @@ int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id) case AV_CODEC_ID_AV1: return MFX_CODEC_AV1; #endif +#if QSV_VERSION_ATLEAST(2, 11) + case AV_CODEC_ID_VVC: + return MFX_CODEC_VVC; +#endif default: break; @@ -464,8 +468,8 @@ static int ff_qsv_set_display_handle(AVCodecContext *avctx, QSVSession *qs) AVVAAPIDeviceContext *hwctx; int ret; - av_dict_set(&child_device_opts, "kernel_driver", "i915", 0); - av_dict_set(&child_device_opts, "driver", "iHD", 0); + av_dict_set(&child_device_opts, "vendor_id", "0x8086", 0); + av_dict_set(&child_device_opts, "driver", "iHD", 0); ret = av_hwdevice_ctx_create(&qs->va_device_ref, AV_HWDEVICE_TYPE_VAAPI, NULL, child_device_opts, 0); av_dict_free(&child_device_opts); @@ -741,20 +745,19 @@ int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs, return 0; } -static void mids_buf_free(void *opaque, uint8_t *data) +static void mids_buf_free(FFRefStructOpaque opaque, void *obj) { - AVBufferRef *hw_frames_ref = opaque; + AVBufferRef *hw_frames_ref = opaque.nc; av_buffer_unref(&hw_frames_ref); - av_freep(&data); } -static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref) +static QSVMid *qsv_create_mids(AVBufferRef *hw_frames_ref) { AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data; AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; int nb_surfaces = frames_hwctx->nb_surfaces; - AVBufferRef *mids_buf, *hw_frames_ref1; + AVBufferRef *hw_frames_ref1; QSVMid *mids; int i; @@ -762,35 +765,27 @@ static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref) if (!hw_frames_ref1) return NULL; - mids = av_calloc(nb_surfaces, sizeof(*mids)); + mids = ff_refstruct_alloc_ext(nb_surfaces * sizeof(*mids), 0, + hw_frames_ref1, mids_buf_free); if (!mids) { av_buffer_unref(&hw_frames_ref1); return NULL; } - mids_buf = av_buffer_create((uint8_t*)mids, nb_surfaces * sizeof(*mids), - mids_buf_free, hw_frames_ref1, 0); - if (!mids_buf) { - av_buffer_unref(&hw_frames_ref1); - av_freep(&mids); - return NULL; - } - for (i = 0; i < nb_surfaces; i++) { QSVMid *mid = &mids[i]; mid->handle_pair = (mfxHDLPair*)frames_hwctx->surfaces[i].Data.MemId; mid->hw_frames_ref = hw_frames_ref1; } - return mids_buf; + return mids; } static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_ref, - AVBufferRef *mids_buf) + QSVMid *mids) { AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data; AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; - QSVMid *mids = (QSVMid*)mids_buf->data; int nb_surfaces = frames_hwctx->nb_surfaces; int i; @@ -811,12 +806,7 @@ static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_re return AVERROR(ENOMEM); } - resp->mids[resp->NumFrameActual + 1] = av_buffer_ref(mids_buf); - if (!resp->mids[resp->NumFrameActual + 1]) { - av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]); - av_freep(&resp->mids); - return AVERROR(ENOMEM); - } + resp->mids[resp->NumFrameActual + 1] = ff_refstruct_ref(mids); return 0; } @@ -839,8 +829,16 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, AVHWFramesContext *frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; mfxFrameInfo *i = &req->Info; - mfxFrameInfo *i1 = &frames_hwctx->surfaces[0].Info; + mfxFrameInfo *i1; + if (!frames_hwctx->nb_surfaces) { + av_log(ctx->logctx, AV_LOG_DEBUG, + "Dynamic frame pools, no frame is pre-allocated\n"); + + return MFX_ERR_NONE; + } + + i1 = &frames_hwctx->surfaces[0].Info; if (i->Width > i1->Width || i->Height > i1->Height || i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) { av_log(ctx->logctx, AV_LOG_ERROR, "Mismatching surface properties in an " @@ -850,7 +848,7 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, return MFX_ERR_UNSUPPORTED; } - ret = qsv_setup_mids(resp, ctx->hw_frames_ctx, ctx->mids_buf); + ret = qsv_setup_mids(resp, ctx->hw_frames_ctx, ctx->mids); if (ret < 0) { av_log(ctx->logctx, AV_LOG_ERROR, "Error filling an external frame allocation request\n"); @@ -859,12 +857,17 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, } else if (req->Type & MFX_MEMTYPE_INTERNAL_FRAME) { /* internal frames -- allocate a new hw frames context */ AVHWFramesContext *ext_frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; + AVQSVFramesContext *ext_frames_hwctx = ext_frames_ctx->hwctx; mfxFrameInfo *i = &req->Info; - AVBufferRef *frames_ref, *mids_buf; + AVBufferRef *frames_ref; + QSVMid *mids; AVHWFramesContext *frames_ctx; AVQSVFramesContext *frames_hwctx; + if (!ext_frames_hwctx->nb_surfaces) + return MFX_ERR_UNSUPPORTED; + frames_ref = av_hwframe_ctx_alloc(ext_frames_ctx->device_ref); if (!frames_ref) return MFX_ERR_MEMORY_ALLOC; @@ -889,14 +892,14 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, return MFX_ERR_MEMORY_ALLOC; } - mids_buf = qsv_create_mids(frames_ref); - if (!mids_buf) { + mids = qsv_create_mids(frames_ref); + if (!mids) { av_buffer_unref(&frames_ref); return MFX_ERR_MEMORY_ALLOC; } - ret = qsv_setup_mids(resp, frames_ref, mids_buf); - av_buffer_unref(&mids_buf); + ret = qsv_setup_mids(resp, frames_ref, mids); + ff_refstruct_unref(&mids); av_buffer_unref(&frames_ref); if (ret < 0) { av_log(ctx->logctx, AV_LOG_ERROR, @@ -912,19 +915,31 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) { + if (!resp->mids) + return MFX_ERR_NONE; + av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]); - av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual + 1]); + ff_refstruct_unref(&resp->mids[resp->NumFrameActual + 1]); av_freep(&resp->mids); return MFX_ERR_NONE; } static mfxStatus qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) { - QSVMid *qsv_mid = mid; - AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)qsv_mid->hw_frames_ref->data; - AVQSVFramesContext *hw_frames_hwctx = hw_frames_ctx->hwctx; + QSVFramesContext *ctx = (QSVFramesContext *)pthis; + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; + AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; + QSVMid *qsv_mid; + AVHWFramesContext *hw_frames_ctx; + AVQSVFramesContext *hw_frames_hwctx; int ret; + if (!frames_hwctx->nb_surfaces) + return MFX_ERR_UNSUPPORTED; + + qsv_mid = mid; + hw_frames_ctx = (AVHWFramesContext*)qsv_mid->hw_frames_ref->data; + hw_frames_hwctx = hw_frames_ctx->hwctx; if (qsv_mid->locked_frame) return MFX_ERR_UNDEFINED_BEHAVIOR; @@ -977,8 +992,15 @@ fail: static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) { - QSVMid *qsv_mid = mid; + QSVFramesContext *ctx = (QSVFramesContext *)pthis; + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; + AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; + QSVMid *qsv_mid; + if (!frames_hwctx->nb_surfaces) + return MFX_ERR_UNSUPPORTED; + + qsv_mid = mid; av_frame_free(&qsv_mid->locked_frame); av_frame_free(&qsv_mid->hw_frame); @@ -987,9 +1009,18 @@ static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) { - QSVMid *qsv_mid = (QSVMid*)mid; + QSVFramesContext *ctx = (QSVFramesContext *)pthis; + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; + AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; mfxHDLPair *pair_dst = (mfxHDLPair*)hdl; - mfxHDLPair *pair_src = (mfxHDLPair*)qsv_mid->handle_pair; + mfxHDLPair *pair_src; + + if (frames_hwctx->nb_surfaces) { + QSVMid *qsv_mid = (QSVMid*)mid; + pair_src = (mfxHDLPair*)qsv_mid->handle_pair; + } else { + pair_src = (mfxHDLPair*)mid; + } pair_dst->first = pair_src->first; @@ -1103,14 +1134,17 @@ int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *psession, if (!opaque) { qsv_frames_ctx->logctx = avctx; + qsv_frames_ctx->mids = NULL; + qsv_frames_ctx->nb_mids = 0; /* allocate the memory ids for the external frames */ - av_buffer_unref(&qsv_frames_ctx->mids_buf); - qsv_frames_ctx->mids_buf = qsv_create_mids(qsv_frames_ctx->hw_frames_ctx); - if (!qsv_frames_ctx->mids_buf) - return AVERROR(ENOMEM); - qsv_frames_ctx->mids = (QSVMid*)qsv_frames_ctx->mids_buf->data; - qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces; + if (frames_hwctx->nb_surfaces) { + ff_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); + qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces; + } err = MFXVideoCORE_SetFrameAllocator(session, &frame_allocator); if (err != MFX_ERR_NONE) diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h index c2d301b4a..d970cd20f 100644 --- a/libavcodec/qsv_internal.h +++ b/libavcodec/qsv_internal.h @@ -115,11 +115,12 @@ typedef struct QSVFramesContext { AVBufferRef *hw_frames_ctx; void *logctx; - /* The memory ids for the external frames. - * Refcounted, since we need one reference owned by the QSVFramesContext - * (i.e. by the encoder/decoder) and another one given to the MFX session - * from the frame allocator. */ - AVBufferRef *mids_buf; + /** + * The memory ids for the external frames. + * Refcounted (via the RefStruct API), since we need one reference + * owned by the QSVFramesContext (i.e. by the encoder/decoder) and + * another one given to the MFX session from the frame allocator. + */ QSVMid *mids; int nb_mids; } QSVFramesContext; diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index bacb21afd..039ba6248 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -42,6 +42,7 @@ #include "libavutil/imgutils.h" #include "libavutil/film_grain_params.h" #include "libavutil/mastering_display_metadata.h" +#include "libavutil/avassert.h" #include "avcodec.h" #include "codec_internal.h" @@ -50,6 +51,7 @@ #include "hwconfig.h" #include "qsv.h" #include "qsv_internal.h" +#include "refstruct.h" #if QSV_ONEVPL #include @@ -67,6 +69,8 @@ static const AVRational mfx_tb = { 1, 90000 }; AV_NOPTS_VALUE : pts_tb.num ? \ av_rescale_q(mfx_pts, mfx_tb, pts_tb) : mfx_pts) +#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl)) + typedef struct QSVAsyncFrame { mfxSyncPoint *sync; QSVFrame *frame; @@ -76,6 +80,7 @@ typedef struct QSVContext { // the session used for decoding mfxSession session; mfxVersion ver; + mfxHandleType handle_type; // the session we allocated internally, in case the caller did not provide // one @@ -132,26 +137,26 @@ static int qsv_get_continuous_buffer(AVCodecContext *avctx, AVFrame *frame, if (ret < 0) return ret; - frame->width = avctx->width; - frame->height = avctx->height; + frame->width = avctx->coded_width; + frame->height = avctx->coded_height; switch (avctx->pix_fmt) { case AV_PIX_FMT_NV12: - frame->linesize[0] = FFALIGN(avctx->width, 128); + frame->linesize[0] = FFALIGN(avctx->coded_width, 128); break; case AV_PIX_FMT_P010: case AV_PIX_FMT_P012: case AV_PIX_FMT_YUYV422: - frame->linesize[0] = 2 * FFALIGN(avctx->width, 128); + frame->linesize[0] = 2 * FFALIGN(avctx->coded_width, 128); break; case AV_PIX_FMT_Y210: case AV_PIX_FMT_VUYX: case AV_PIX_FMT_XV30: case AV_PIX_FMT_Y212: - frame->linesize[0] = 4 * FFALIGN(avctx->width, 128); + frame->linesize[0] = 4 * FFALIGN(avctx->coded_width, 128); break; case AV_PIX_FMT_XV36: - frame->linesize[0] = 8 * FFALIGN(avctx->width, 128); + frame->linesize[0] = 8 * FFALIGN(avctx->coded_width, 128); break; default: av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format.\n"); @@ -168,7 +173,7 @@ static int qsv_get_continuous_buffer(AVCodecContext *avctx, AVFrame *frame, avctx->pix_fmt == AV_PIX_FMT_P012) { frame->linesize[1] = frame->linesize[0]; frame->data[1] = frame->data[0] + - frame->linesize[0] * FFALIGN(avctx->height, 64); + frame->linesize[0] * FFALIGN(avctx->coded_height, 64); } ret = ff_attach_decode_data(frame); @@ -182,6 +187,7 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses AVBufferRef *hw_frames_ref, AVBufferRef *hw_device_ref) { int ret; + mfxIMPL impl; if (q->gpu_copy == MFX_GPUCOPY_ON && !(q->iopattern & MFX_IOPATTERN_OUT_SYSTEM_MEMORY)) { @@ -239,27 +245,52 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses q->session = q->internal_qs.session; } + if (MFXQueryIMPL(q->session, &impl) == MFX_ERR_NONE) { + switch (MFX_IMPL_VIA_MASK(impl)) { + case MFX_IMPL_VIA_VAAPI: + q->handle_type = MFX_HANDLE_VA_DISPLAY; + break; + + case MFX_IMPL_VIA_D3D11: + q->handle_type = MFX_HANDLE_D3D11_DEVICE; + break; + + case MFX_IMPL_VIA_D3D9: + q->handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER; + break; + + default: + av_assert0(!"should not reach here"); + } + } else { + av_log(avctx, AV_LOG_ERROR, "Error querying the implementation. \n"); + goto fail; + } + if (MFXQueryVersion(q->session, &q->ver) != MFX_ERR_NONE) { av_log(avctx, AV_LOG_ERROR, "Error querying the session version. \n"); - q->session = NULL; - - if (q->internal_qs.session) { - MFXClose(q->internal_qs.session); - q->internal_qs.session = NULL; - } - - if (q->internal_qs.loader) { - MFXUnload(q->internal_qs.loader); - q->internal_qs.loader = NULL; - } - - return AVERROR_EXTERNAL; + goto fail; } /* make sure the decoder is uninitialized */ MFXVideoDECODE_Close(q->session); return 0; + +fail: + q->session = NULL; + + if (q->internal_qs.session) { + MFXClose(q->internal_qs.session); + q->internal_qs.session = NULL; + } + + if (q->internal_qs.loader) { + MFXUnload(q->internal_qs.loader); + q->internal_qs.loader = NULL; + } + + return AVERROR_EXTERNAL; } static int qsv_decode_preinit(AVCodecContext *avctx, QSVContext *q, enum AVPixelFormat pix_fmt, mfxVideoParam *param) @@ -309,7 +340,10 @@ static int qsv_decode_preinit(AVCodecContext *avctx, QSVContext *q, enum AVPixel hwframes_ctx->height = FFALIGN(avctx->coded_height, 32); hwframes_ctx->format = AV_PIX_FMT_QSV; hwframes_ctx->sw_format = avctx->sw_pix_fmt; - hwframes_ctx->initial_pool_size = q->suggest_pool_size + 16 + avctx->extra_hw_frames; + if (QSV_RUNTIME_VERSION_ATLEAST(q->ver, 2, 9) && q->handle_type != MFX_HANDLE_D3D9_DEVICE_MANAGER) + hwframes_ctx->initial_pool_size = 0; + else + hwframes_ctx->initial_pool_size = q->suggest_pool_size + 16 + avctx->extra_hw_frames; frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); @@ -379,7 +413,7 @@ static int qsv_decode_init_context(AVCodecContext *avctx, QSVContext *q, mfxVide q->frame_info = param->mfx.FrameInfo; if (!avctx->hw_frames_ctx) { - ret = av_image_get_buffer_size(avctx->pix_fmt, FFALIGN(avctx->width, 128), FFALIGN(avctx->height, 64), 1); + ret = av_image_get_buffer_size(avctx->pix_fmt, FFALIGN(avctx->coded_width, 128), FFALIGN(avctx->coded_height, 64), 1); if (ret < 0) return ret; q->pool = av_buffer_pool_init(ret, av_buffer_allocz); @@ -443,6 +477,11 @@ static int qsv_decode_header(AVCodecContext *avctx, QSVContext *q, param->ExtParam = q->ext_buffers; param->NumExtParam = q->nb_ext_buffers; + if (param->mfx.FrameInfo.FrameRateExtN == 0 || param->mfx.FrameInfo.FrameRateExtD == 0) { + param->mfx.FrameInfo.FrameRateExtN = 25; + param->mfx.FrameInfo.FrameRateExtD = 1; + } + #if QSV_VERSION_ATLEAST(1, 34) if (QSV_RUNTIME_VERSION_ATLEAST(q->ver, 1, 34) && avctx->codec_id == AV_CODEC_ID_AV1) param->mfx.FilmGrain = (avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) ? 0 : param->mfx.FilmGrain; @@ -499,7 +538,8 @@ static int alloc_frame(AVCodecContext *avctx, QSVContext *q, QSVFrame *frame) #endif #if QSV_VERSION_ATLEAST(1, 35) - if (QSV_RUNTIME_VERSION_ATLEAST(q->ver, 1, 35) && avctx->codec_id == AV_CODEC_ID_HEVC) { + if ((QSV_RUNTIME_VERSION_ATLEAST(q->ver, 1, 35) && avctx->codec_id == AV_CODEC_ID_HEVC) || + (QSV_RUNTIME_VERSION_ATLEAST(q->ver, 2, 9) && avctx->codec_id == AV_CODEC_ID_AV1)) { frame->mdcv.Header.BufferId = MFX_EXTBUFF_MASTERING_DISPLAY_COLOUR_VOLUME; frame->mdcv.Header.BufferSz = sizeof(frame->mdcv); // The data in mdcv is valid when this flag is 1 @@ -703,6 +743,45 @@ static int qsv_export_hdr_side_data(AVCodecContext *avctx, mfxExtMasteringDispla return 0; } +static int qsv_export_hdr_side_data_av1(AVCodecContext *avctx, mfxExtMasteringDisplayColourVolume *mdcv, + mfxExtContentLightLevelInfo *clli, AVFrame *frame) +{ + if (mdcv->InsertPayloadToggle) { + AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame); + const int chroma_den = 1 << 16; + const int max_luma_den = 1 << 8; + const int min_luma_den = 1 << 14; + + if (!mastering) + return AVERROR(ENOMEM); + + for (int i = 0; i < 3; i++) { + mastering->display_primaries[i][0] = av_make_q(mdcv->DisplayPrimariesX[i], chroma_den); + mastering->display_primaries[i][1] = av_make_q(mdcv->DisplayPrimariesY[i], chroma_den); + } + + mastering->white_point[0] = av_make_q(mdcv->WhitePointX, chroma_den); + mastering->white_point[1] = av_make_q(mdcv->WhitePointY, chroma_den); + + mastering->max_luminance = av_make_q(mdcv->MaxDisplayMasteringLuminance, max_luma_den); + mastering->min_luminance = av_make_q(mdcv->MinDisplayMasteringLuminance, min_luma_den); + + mastering->has_luminance = 1; + mastering->has_primaries = 1; + } + + if (clli->InsertPayloadToggle) { + AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame); + if (!light) + return AVERROR(ENOMEM); + + light->MaxCLL = clli->MaxContentLightLevel; + light->MaxFALL = clli->MaxPicAverageLightLevel; + } + + return 0; +} + #endif static int qsv_decode(AVCodecContext *avctx, QSVContext *q, @@ -835,6 +914,12 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q, if (ret < 0) return ret; } + + if (QSV_RUNTIME_VERSION_ATLEAST(q->ver, 2, 9) && avctx->codec_id == AV_CODEC_ID_AV1) { + ret = qsv_export_hdr_side_data_av1(avctx, &aframe.frame->mdcv, &aframe.frame->clli, frame); + if (ret < 0) + return ret; + } #endif frame->repeat_pict = @@ -846,13 +931,24 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q, frame->flags |= AV_FRAME_FLAG_INTERLACED * !(outsurf->Info.PicStruct & MFX_PICSTRUCT_PROGRESSIVE); frame->pict_type = ff_qsv_map_pictype(aframe.frame->dec_info.FrameType); - //Key frame is IDR frame is only suitable for H264. For HEVC, IRAPs are key frames. - if (avctx->codec_id == AV_CODEC_ID_H264) { + + if (avctx->codec_id == AV_CODEC_ID_H264 || + avctx->codec_id == AV_CODEC_ID_HEVC || + avctx->codec_id == AV_CODEC_ID_VVC) { if (aframe.frame->dec_info.FrameType & MFX_FRAMETYPE_IDR) frame->flags |= AV_FRAME_FLAG_KEY; else frame->flags &= ~AV_FRAME_FLAG_KEY; + } else { + if (aframe.frame->dec_info.FrameType & MFX_FRAMETYPE_I) + frame->flags |= AV_FRAME_FLAG_KEY; + else + frame->flags &= ~AV_FRAME_FLAG_KEY; } + frame->crop_left = outsurf->Info.CropX; + frame->crop_top = outsurf->Info.CropY; + frame->crop_right = outsurf->Info.Width - (outsurf->Info.CropX + outsurf->Info.CropW); + frame->crop_bottom = outsurf->Info.Height - (outsurf->Info.CropY + outsurf->Info.CropH); /* update the surface properties */ if (avctx->pix_fmt == AV_PIX_FMT_QSV) @@ -888,7 +984,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); - av_buffer_unref(&q->frames_ctx.mids_buf); + ff_refstruct_unref(&q->frames_ctx.mids); av_buffer_pool_uninit(&q->pool); } @@ -1142,7 +1238,7 @@ const FFCodec ff_##x##_qsv_decoder = { \ .p.priv_class = &x##_qsv_class, \ .hw_configs = qsv_hw_configs, \ .p.wrapper_name = "qsv", \ - .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, \ + .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING, \ }; \ #define DEFINE_QSV_DECODER(x, X, bsf_name) DEFINE_QSV_DECODER_WITH_OPTION(x, X, bsf_name, options) @@ -1205,3 +1301,7 @@ DEFINE_QSV_DECODER(vp9, VP9, NULL) #if CONFIG_AV1_QSV_DECODER DEFINE_QSV_DECODER(av1, AV1, NULL) #endif + +#if CONFIG_VVC_QSV_DECODER +DEFINE_QSV_DECODER(vvc, VVC, "vvc_mp4toannexb") +#endif diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c index 3a8607fca..8200a1401 100644 --- a/libavcodec/qsvenc.c +++ b/libavcodec/qsvenc.c @@ -31,6 +31,7 @@ #include "libavutil/hwcontext_qsv.h" #include "libavutil/mem.h" #include "libavutil/log.h" +#include "libavutil/dict.h" #include "libavutil/time.h" #include "libavutil/imgutils.h" @@ -41,6 +42,7 @@ #include "qsv.h" #include "qsv_internal.h" #include "qsvenc.h" +#include "refstruct.h" struct profile_names { mfxU16 profile; @@ -743,8 +745,9 @@ static int init_video_param_jpeg(AVCodecContext *avctx, QSVEncContext *q) if (avctx->hw_frames_ctx) { AVHWFramesContext *frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; - q->param.mfx.FrameInfo.Width = frames_hwctx->surfaces[0].Info.Width; - q->param.mfx.FrameInfo.Height = frames_hwctx->surfaces[0].Info.Height; + mfxFrameInfo *info = frames_hwctx->nb_surfaces ? &frames_hwctx->surfaces[0].Info : frames_hwctx->info; + q->param.mfx.FrameInfo.Width = info->Width; + q->param.mfx.FrameInfo.Height = info->Height; } if (avctx->framerate.den > 0 && avctx->framerate.num > 0) { @@ -867,8 +870,9 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) if (avctx->hw_frames_ctx) { AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; - q->param.mfx.FrameInfo.Width = frames_hwctx->surfaces[0].Info.Width; - q->param.mfx.FrameInfo.Height = frames_hwctx->surfaces[0].Info.Height; + mfxFrameInfo *info = frames_hwctx->nb_surfaces ? &frames_hwctx->surfaces[0].Info : frames_hwctx->info; + q->param.mfx.FrameInfo.Width = info->Width; + q->param.mfx.FrameInfo.Height = info->Height; } if (avctx->framerate.den > 0 && avctx->framerate.num > 0) { @@ -1633,6 +1637,12 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) int iopattern = 0; int opaque_alloc = 0; int ret; + void *tmp; +#if HAVE_STRUCT_MFXCONFIGINTERFACE + mfxExtBuffer ext_buf; + mfxConfigInterface *iface = NULL; + const AVDictionaryEntry *param = NULL; +#endif q->param.AsyncDepth = q->async_depth; @@ -1693,35 +1703,92 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) if (ret < 0) return ret; + tmp = av_realloc_array(q->extparam, q->nb_extparam_internal, sizeof(*q->extparam)); + if (!tmp) + return AVERROR(ENOMEM); + + q->extparam = tmp; + q->nb_extparam = q->nb_extparam_internal; + memcpy(q->extparam, q->extparam_internal, q->nb_extparam * sizeof(*q->extparam)); + if (avctx->hwaccel_context) { AVQSVContext *qsv = avctx->hwaccel_context; int i, j; - q->extparam = av_calloc(qsv->nb_ext_buffers + q->nb_extparam_internal, - sizeof(*q->extparam)); - if (!q->extparam) - return AVERROR(ENOMEM); - - q->param.ExtParam = q->extparam; - for (i = 0; i < qsv->nb_ext_buffers; i++) - q->param.ExtParam[i] = qsv->ext_buffers[i]; - q->param.NumExtParam = qsv->nb_ext_buffers; - - for (i = 0; i < q->nb_extparam_internal; i++) { - for (j = 0; j < qsv->nb_ext_buffers; j++) { - if (qsv->ext_buffers[j]->BufferId == q->extparam_internal[i]->BufferId) + for (i = 0; i < qsv->nb_ext_buffers; i++) { + for (j = 0; j < q->nb_extparam_internal; j++) { + if (qsv->ext_buffers[i]->BufferId == q->extparam_internal[j]->BufferId) { + q->extparam[j] = qsv->ext_buffers[i]; break; + } } - if (j < qsv->nb_ext_buffers) - continue; - q->param.ExtParam[q->param.NumExtParam++] = q->extparam_internal[i]; + if (j == q->nb_extparam_internal) { + tmp = av_realloc_array(q->extparam, q->nb_extparam + 1, sizeof(*q->extparam)); + if (!tmp) + return AVERROR(ENOMEM); + + q->extparam = tmp; + q->extparam[q->nb_extparam++] = qsv->ext_buffers[i]; + } } - } else { - q->param.ExtParam = q->extparam_internal; - q->param.NumExtParam = q->nb_extparam_internal; } + q->param.ExtParam = q->extparam; + q->param.NumExtParam = q->nb_extparam; + +#if HAVE_STRUCT_MFXCONFIGINTERFACE + ret = MFXVideoCORE_GetHandle(q->session, MFX_HANDLE_CONFIG_INTERFACE, (mfxHDL *)(&iface)); + if (ret < 0) + return ff_qsv_print_error(avctx, ret, + "Error getting mfx config interface handle"); + + while ((param = av_dict_get(q->qsv_params, "", param, AV_DICT_IGNORE_SUFFIX))) { + const char *param_key = param->key; + const char *param_value = param->value; + mfxExtBuffer *new_ext_buf; + void *tmp; + + av_log(avctx, AV_LOG_VERBOSE, "Parameter key: %s, value: %s\n", param_key, param_value); + + // Set encoding parameters using MFXSetParameter + for (int i = 0; i < 2; i++) { + ret = iface->SetParameter(iface, (mfxU8*)param_key, (mfxU8*)param_value, MFX_STRUCTURE_TYPE_VIDEO_PARAM, &q->param, &ext_buf); + if (ret == MFX_ERR_NONE) { + break; + } else if (i == 0 && ret == MFX_ERR_MORE_EXTBUFFER) { + tmp = av_realloc_array(q->extparam_str, q->nb_extparam_str + 1, sizeof(*q->extparam_str)); + if (!tmp) + return AVERROR(ENOMEM); + q->extparam_str = tmp; + + tmp = av_realloc_array(q->extparam, q->nb_extparam + 1, sizeof(*q->extparam)); + if (!tmp) + return AVERROR(ENOMEM); + q->extparam = tmp; + + new_ext_buf = (mfxExtBuffer*)av_mallocz(ext_buf.BufferSz); + if (!new_ext_buf) + return AVERROR(ENOMEM); + + new_ext_buf->BufferId = ext_buf.BufferId; + new_ext_buf->BufferSz = ext_buf.BufferSz; + q->extparam_str[q->nb_extparam_str++] = new_ext_buf; + q->extparam[q->nb_extparam++] = new_ext_buf; + q->param.ExtParam = q->extparam; + q->param.NumExtParam = q->nb_extparam; + } else { + av_log(avctx, AV_LOG_ERROR, "Failed to set parameter: %s\n", param_key); + return AVERROR_UNKNOWN; + } + } + } +#else + if (q->qsv_params) { + av_log(avctx, AV_LOG_WARNING, "MFX string API is not supported, ignore qsv_params option\n"); + } +#endif + ret = MFXVideoENCODE_Query(q->session, &q->param, &q->param); if (ret == MFX_WRN_PARTIAL_ACCELERATION) { av_log(avctx, AV_LOG_WARNING, "Encoder will work with partial HW acceleration\n"); @@ -2415,7 +2482,7 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, if (frame->pict_type == AV_PICTURE_TYPE_I) { enc_ctrl->FrameType = MFX_FRAMETYPE_I | MFX_FRAMETYPE_REF; - if (q->forced_idr) + if ((frame->flags & AV_FRAME_FLAG_KEY) || q->forced_idr) enc_ctrl->FrameType |= MFX_FRAMETYPE_IDR; } } @@ -2649,7 +2716,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); - av_buffer_unref(&q->frames_ctx.mids_buf); + ff_refstruct_unref(&q->frames_ctx.mids); cur = q->work_frames; while (cur) { @@ -2681,6 +2748,10 @@ int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q) av_buffer_unref(&q->opaque_alloc_buf); #endif + for (int i = 0; i < q->nb_extparam_str; i++) + av_free(q->extparam_str[i]); + + av_freep(&q->extparam_str); av_freep(&q->extparam); return 0; diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h index c71bf2ed5..4bc77f2f7 100644 --- a/libavcodec/qsvenc.h +++ b/libavcodec/qsvenc.h @@ -26,8 +26,6 @@ #include #include -#include - #include "libavutil/common.h" #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_qsv.h" @@ -64,7 +62,8 @@ { "slower", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_2 }, INT_MIN, INT_MAX, VE, .unit = "preset" }, \ { "veryslow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BEST_QUALITY }, INT_MIN, INT_MAX, VE, .unit = "preset" }, \ { "forced_idr", "Forcing I frames as IDR frames", OFFSET(qsv.forced_idr), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, \ -{ "low_power", "enable low power mode(experimental: many limitations by mfx version, BRC modes, etc.)", OFFSET(qsv.low_power), AV_OPT_TYPE_BOOL, { .i64 = -1}, -1, 1, VE}, +{ "low_power", "enable low power mode(experimental: many limitations by mfx version, BRC modes, etc.)", OFFSET(qsv.low_power), AV_OPT_TYPE_BOOL, { .i64 = -1}, -1, 1, VE},\ +{ "qsv_params", "Set QSV encoder parameters as key1=value1:key2=value2:...", OFFSET(qsv.qsv_params), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, #if QSV_HAVE_HE #define QSV_HE_OPTIONS \ @@ -195,7 +194,11 @@ typedef struct QSVEncContext { mfxExtBuffer *extparam_internal[5 + (QSV_HAVE_MF * 2) + (QSV_HAVE_EXT_AV1_PARAM * 2) + QSV_HAVE_HE]; int nb_extparam_internal; + mfxExtBuffer **extparam_str; + int nb_extparam_str; + mfxExtBuffer **extparam; + int nb_extparam; AVFifo *async_fifo; @@ -314,6 +317,8 @@ typedef struct QSVEncContext { int skip_frame; // This is used for Hyper Encode int dual_gfx; + + AVDictionary *qsv_params; } QSVEncContext; int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q); diff --git a/libavcodec/qsvenc_av1.c b/libavcodec/qsvenc_av1.c index 33727bb07..a86b409be 100644 --- a/libavcodec/qsvenc_av1.c +++ b/libavcodec/qsvenc_av1.c @@ -22,9 +22,9 @@ #include #include -#include - #include "libavutil/common.h" +#include "libavutil/mastering_display_metadata.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" @@ -39,6 +39,75 @@ typedef struct QSVAV1EncContext { QSVEncContext qsv; } QSVAV1EncContext; +static int qsv_av1_set_encode_ctrl(AVCodecContext *avctx, + const AVFrame *frame, mfxEncodeCtrl *enc_ctrl) +{ + QSVAV1EncContext *q = avctx->priv_data; + AVFrameSideData *sd; + + if (!frame || !QSV_RUNTIME_VERSION_ATLEAST(q->qsv.ver, 2, 11)) + return 0; + + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + if (sd) { + AVMasteringDisplayMetadata *mdm = (AVMasteringDisplayMetadata *)sd->data; + if (mdm->has_primaries && mdm->has_luminance) { + const int chroma_den = 1 << 16; + const int max_luma_den = 1 << 8; + const int min_luma_den = 1 << 14; + mfxExtMasteringDisplayColourVolume *mdcv = av_mallocz(sizeof(*mdcv)); + if (!mdcv) + return AVERROR(ENOMEM); + + mdcv->Header.BufferId = MFX_EXTBUFF_MASTERING_DISPLAY_COLOUR_VOLUME; + mdcv->Header.BufferSz = sizeof(*mdcv); + + for (int i = 0; i < 3; i++) { + mdcv->DisplayPrimariesX[i] = + av_rescale(mdm->display_primaries[i][0].num, chroma_den, + mdm->display_primaries[i][0].den); + mdcv->DisplayPrimariesY[i] = + av_rescale(mdm->display_primaries[i][1].num, chroma_den, + mdm->display_primaries[i][1].den); + } + + mdcv->WhitePointX = + av_rescale(mdm->white_point[0].num, chroma_den, + mdm->white_point[0].den); + mdcv->WhitePointY = + av_rescale(mdm->white_point[1].num, chroma_den, + mdm->white_point[1].den); + + mdcv->MaxDisplayMasteringLuminance = + av_rescale(mdm->max_luminance.num, max_luma_den, + mdm->max_luminance.den); + mdcv->MinDisplayMasteringLuminance = + av_rescale(mdm->min_luminance.num, min_luma_den, + mdm->min_luminance.den); + + enc_ctrl->ExtParam[enc_ctrl->NumExtParam++] = (mfxExtBuffer *)mdcv; + } + } + + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + if (sd) { + AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data; + mfxExtContentLightLevelInfo *clli = av_mallocz(sizeof(*clli)); + if (!clli) + return AVERROR(ENOMEM); + + clli->Header.BufferId = MFX_EXTBUFF_CONTENT_LIGHT_LEVEL_INFO; + clli->Header.BufferSz = sizeof(*clli); + + clli->MaxContentLightLevel = clm->MaxCLL; + clli->MaxPicAverageLightLevel = clm->MaxFALL; + + enc_ctrl->ExtParam[enc_ctrl->NumExtParam++] = (mfxExtBuffer *)clli; + } + + return 0; +} + static av_cold int qsv_enc_init(AVCodecContext *avctx) { QSVAV1EncContext *q = avctx->priv_data; @@ -61,6 +130,8 @@ static av_cold int qsv_enc_init(AVCodecContext *avctx) return ret; } + q->qsv.set_encode_ctrl_cb = qsv_av1_set_encode_ctrl; + return ff_qsv_enc_init(avctx, &q->qsv); } @@ -150,6 +221,7 @@ FFCodec ff_av1_qsv_encoder = { AV_PIX_FMT_P010, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c index 53e4e744b..304d1e7dc 100644 --- a/libavcodec/qsvenc_h264.c +++ b/libavcodec/qsvenc_h264.c @@ -202,6 +202,7 @@ const FFCodec ff_h264_qsv_encoder = { .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c index 4920b0bca..80fdf782a 100644 --- a/libavcodec/qsvenc_hevc.c +++ b/libavcodec/qsvenc_hevc.c @@ -25,6 +25,7 @@ #include #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/mastering_display_metadata.h" @@ -32,12 +33,13 @@ #include "bytestream.h" #include "codec_internal.h" #include "get_bits.h" -#include "hevc.h" -#include "hevcdec.h" #include "h2645_parse.h" #include "qsv.h" #include "qsvenc.h" +#include "hevc/hevc.h" +#include "hevc/ps.h" + enum LoadPlugin { LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_SW, @@ -97,7 +99,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) } get_bits(&gb, 9); - ret = ff_hevc_parse_sps(&sps, &gb, &sps_id, 0, NULL, avctx); + ret = ff_hevc_parse_sps(&sps, &gb, &sps_id, 0, 0, NULL, avctx); av_freep(&sps_rbsp.rbsp_buffer); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error parsing the SPS\n"); @@ -107,7 +109,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) /* generate the VPS */ vps.vps_max_layers = 1; vps.vps_max_sub_layers = sps.max_sub_layers; - vps.vps_temporal_id_nesting_flag = sps.temporal_id_nesting_flag; + vps.vps_temporal_id_nesting_flag = sps.temporal_id_nesting; memcpy(&vps.ptl, &sps.ptl, sizeof(vps.ptl)); vps.vps_sub_layer_ordering_info_present_flag = 1; for (i = 0; i < HEVC_MAX_SUB_LAYERS; i++) { @@ -405,6 +407,7 @@ const FFCodec ff_hevc_qsv_encoder = { AV_PIX_FMT_VUYX, AV_PIX_FMT_XV30, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | diff --git a/libavcodec/qsvenc_jpeg.c b/libavcodec/qsvenc_jpeg.c index 2add12adc..b2458eee0 100644 --- a/libavcodec/qsvenc_jpeg.c +++ b/libavcodec/qsvenc_jpeg.c @@ -93,6 +93,7 @@ const FFCodec ff_mjpeg_qsv_encoder = { AV_PIX_FMT_BGRA, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, .p.wrapper_name = "qsv", diff --git a/libavcodec/qsvenc_mpeg2.c b/libavcodec/qsvenc_mpeg2.c index fabf461fe..ad3da6d67 100644 --- a/libavcodec/qsvenc_mpeg2.c +++ b/libavcodec/qsvenc_mpeg2.c @@ -105,6 +105,7 @@ const FFCodec ff_mpeg2_qsv_encoder = { .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | diff --git a/libavcodec/qsvenc_vp9.c b/libavcodec/qsvenc_vp9.c index a760e4932..b247c39c8 100644 --- a/libavcodec/qsvenc_vp9.c +++ b/libavcodec/qsvenc_vp9.c @@ -117,6 +117,7 @@ const FFCodec ff_vp9_qsv_encoder = { AV_PIX_FMT_QSV, AV_PIX_FMT_XV30, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .p.priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | diff --git a/libavcodec/qtrleenc.c b/libavcodec/qtrleenc.c index 92e6e8438..71d57d7eb 100644 --- a/libavcodec/qtrleenc.c +++ b/libavcodec/qtrleenc.c @@ -23,6 +23,7 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/r210dec.c b/libavcodec/r210dec.c index fe6a02598..7405da68e 100644 --- a/libavcodec/r210dec.c +++ b/libavcodec/r210dec.c @@ -56,8 +56,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->pict_type = AV_PICTURE_TYPE_I; - pic->flags |= AV_FRAME_FLAG_KEY; g_line = pic->data[0]; b_line = pic->data[1]; r_line = pic->data[2]; diff --git a/libavcodec/ra288.c b/libavcodec/ra288.c index e4b14ef2a..5b186a7a3 100644 --- a/libavcodec/ra288.c +++ b/libavcodec/ra288.c @@ -22,6 +22,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #define BITSTREAM_READER_LE diff --git a/libavcodec/rangecoder.h b/libavcodec/rangecoder.h index 89d178ac3..110908d6b 100644 --- a/libavcodec/rangecoder.h +++ b/libavcodec/rangecoder.h @@ -62,7 +62,6 @@ void ff_build_rac_states(RangeCoder *c, int factor, int max_p); static inline void renorm_encoder(RangeCoder *c) { // FIXME: optimize - while (c->range < 0x100) { if (c->outstanding_byte < 0) { c->outstanding_byte = c->low >> 8; } else if (c->low <= 0xFF00) { @@ -81,7 +80,6 @@ static inline void renorm_encoder(RangeCoder *c) c->low = (c->low & 0xFF) << 8; c->range <<= 8; - } } static inline int get_rac_count(RangeCoder *c) @@ -108,7 +106,8 @@ static inline void put_rac(RangeCoder *c, uint8_t *const state, int bit) *state = c->one_state[*state]; } - renorm_encoder(c); + while (c->range < 0x100) + renorm_encoder(c); } static inline void refill(RangeCoder *c) diff --git a/libavcodec/rasc.c b/libavcodec/rasc.c index 21c1829fc..7b0251ca3 100644 --- a/libavcodec/rasc.c +++ b/libavcodec/rasc.c @@ -23,6 +23,7 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" diff --git a/libavcodec/ratecontrol.c b/libavcodec/ratecontrol.c index 55ce05473..86ec7a344 100644 --- a/libavcodec/ratecontrol.c +++ b/libavcodec/ratecontrol.c @@ -28,10 +28,10 @@ #include "libavutil/attributes.h" #include "libavutil/emms.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "ratecontrol.h" -#include "mpegutils.h" #include "mpegvideoenc.h" #include "libavutil/eval.h" @@ -39,11 +39,11 @@ void ff_write_pass1_stats(MpegEncContext *s) { snprintf(s->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 skipcount:%d hbits:%d;\n", - s->current_picture_ptr->display_picture_number, - s->current_picture_ptr->coded_picture_number, + "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->current_picture.f->quality, + s->cur_pic.ptr->f->quality, s->i_tex_bits, s->p_tex_bits, s->mv_bits, @@ -52,25 +52,30 @@ void ff_write_pass1_stats(MpegEncContext *s) s->b_code, s->mc_mb_var_sum, s->mb_var_sum, - s->i_count, s->skip_count, + s->i_count, s->header_bits); } +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) { - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) - return av_q2d(avctx->framerate); - -FF_DISABLE_DEPRECATION_WARNINGS - return 1.0 / av_q2d(avctx->time_base) -#if FF_API_TICKS_PER_FRAME - / FFMAX(avctx->ticks_per_frame, 1) -#endif - ; -FF_ENABLE_DEPRECATION_WARNINGS + return av_q2d(get_fpsQ(avctx)); } -static inline double qp2bits(RateControlEntry *rce, double qp) +static inline double qp2bits(const RateControlEntry *rce, double qp) { if (qp <= 0.0) { av_log(NULL, AV_LOG_ERROR, "qp<=0.0\n"); @@ -78,7 +83,12 @@ static inline double qp2bits(RateControlEntry *rce, double qp) return rce->qscale * (double)(rce->i_tex_bits + rce->p_tex_bits + 1) / qp; } -static inline double bits2qp(RateControlEntry *rce, double bits) +static double qp2bits_cb(void *rce, double qp) +{ + return qp2bits(rce, qp); +} + +static inline double bits2qp(const RateControlEntry *rce, double bits) { if (bits < 0.9) { av_log(NULL, AV_LOG_ERROR, "bits<0.9\n"); @@ -86,7 +96,12 @@ static inline double bits2qp(RateControlEntry *rce, double bits) return rce->qscale * (double)(rce->i_tex_bits + rce->p_tex_bits + 1) / bits; } -static double get_diff_limited_q(MpegEncContext *s, RateControlEntry *rce, double q) +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) { RateControlContext *rcc = &s->rc_context; AVCodecContext *a = s->avctx; @@ -153,7 +168,7 @@ static void get_qminmax(int *qmin_ret, int *qmax_ret, MpegEncContext *s, int pic *qmax_ret = qmax; } -static double modify_qscale(MpegEncContext *s, RateControlEntry *rce, +static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce, double q, int frame_num) { RateControlContext *rcc = &s->rc_context; @@ -322,12 +337,13 @@ static int init_pass2(MpegEncContext *s) RateControlContext *rcc = &s->rc_context; AVCodecContext *a = s->avctx; int i, toobig; - double fps = get_fps(s->avctx); + AVRational fps = get_fpsQ(s->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 = (uint64_t)(s->bit_rate * - (double)rcc->num_entries / fps); + uint64_t all_available_bits = av_rescale_q(s->bit_rate, + (AVRational){rcc->num_entries,1}, + fps); double rate_factor = 0; double step; const int filter_size = (int)(a->qblur * 4) | 1; @@ -375,7 +391,7 @@ static int init_pass2(MpegEncContext *s) /* find qscale */ for (i = 0; i < rcc->num_entries; i++) { - RateControlEntry *rce = &rcc->entry[i]; + const RateControlEntry *rce = &rcc->entry[i]; qscale[i] = get_qscale(s, &rcc->entry[i], rate_factor, i); rcc->last_qscale_for[rce->pict_type] = qscale[i]; @@ -384,20 +400,20 @@ static int init_pass2(MpegEncContext *s) /* fixed I/B QP relative to P mode */ for (i = FFMAX(0, rcc->num_entries - 300); i < rcc->num_entries; i++) { - RateControlEntry *rce = &rcc->entry[i]; + const RateControlEntry *rce = &rcc->entry[i]; qscale[i] = get_diff_limited_q(s, rce, qscale[i]); } for (i = rcc->num_entries - 1; i >= 0; i--) { - RateControlEntry *rce = &rcc->entry[i]; + const RateControlEntry *rce = &rcc->entry[i]; qscale[i] = get_diff_limited_q(s, rce, qscale[i]); } /* smooth curve */ for (i = 0; i < rcc->num_entries; i++) { - RateControlEntry *rce = &rcc->entry[i]; + const RateControlEntry *rce = &rcc->entry[i]; const int pict_type = rce->new_pict_type; int j; double q = 0.0, sum = 0.0; @@ -506,8 +522,8 @@ av_cold int ff_rate_control_init(MpegEncContext *s) NULL }; static double (* const func1[])(void *, double) = { - (double (*)(void *, double)) bits2qp, - (double (*)(void *, double)) qp2bits, + bits2qp_cb, + qp2bits_cb, NULL }; static const char * const func1_names[] = { @@ -596,13 +612,17 @@ av_cold int ff_rate_control_init(MpegEncContext *s) av_assert0(picture_number < rcc->num_entries); rce = &rcc->entry[picture_number]; - e += sscanf(p, " in:%*d out:%*d type:%d q:%f itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%"SCNd64" var:%"SCNd64" icount:%d skipcount:%d hbits:%d", + e += sscanf(p, " in:%*d out:%*d type:%d q:%f itex:%d ptex:%d " + "mv:%d misc:%d " + "fcode:%d bcode:%d " + "mc-var:%"SCNd64" var:%"SCNd64" " + "icount:%d hbits:%d", &rce->pict_type, &rce->qscale, &rce->i_tex_bits, &rce->p_tex_bits, &rce->mv_bits, &rce->misc_bits, &rce->f_code, &rce->b_code, &rce->mc_mb_var_sum, &rce->mb_var_sum, - &rce->i_count, &rce->skip_count, &rce->header_bits); - if (e != 14) { + &rce->i_count, &rce->header_bits); + if (e != 13) { av_log(s->avctx, AV_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e); @@ -612,10 +632,9 @@ av_cold int ff_rate_control_init(MpegEncContext *s) p = next; } - if (init_pass2(s) < 0) { - ff_rate_control_uninit(s); - return -1; - } + res = init_pass2(s); + if (res < 0) + return res; } if (!(s->avctx->flags & AV_CODEC_FLAG_PASS2)) { @@ -678,12 +697,12 @@ av_cold int ff_rate_control_init(MpegEncContext *s) return 0; } -av_cold void ff_rate_control_uninit(MpegEncContext *s) +av_cold void ff_rate_control_uninit(RateControlContext *rcc) { - RateControlContext *rcc = &s->rc_context; emms_c(); av_expr_free(rcc->rc_eq_eval); + rcc->rc_eq_eval = NULL; av_freep(&rcc->entry); } @@ -864,8 +883,8 @@ static void adaptive_quantization(MpegEncContext *s, double q) void ff_get_2pass_fcode(MpegEncContext *s) { - RateControlContext *rcc = &s->rc_context; - RateControlEntry *rce = &rcc->entry[s->picture_number]; + const RateControlContext *rcc = &s->rc_context; + const RateControlEntry *rce = &rcc->entry[s->picture_number]; s->f_code = rce->f_code; s->b_code = rce->b_code; @@ -916,21 +935,27 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) rce = &rcc->entry[picture_number]; wanted_bits = rce->expected_bits; } else { - Picture *dts_pic; + const MPVPicture *dts_pic; + double wanted_bits_double; rce = &local_rce; /* 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->current_picture_ptr; + dts_pic = s->cur_pic.ptr; else - dts_pic = s->last_picture_ptr; + dts_pic = s->last_pic.ptr; if (!dts_pic || dts_pic->f->pts == AV_NOPTS_VALUE) - wanted_bits = (uint64_t)(s->bit_rate * (double)picture_number / fps); + wanted_bits_double = s->bit_rate * (double)picture_number / fps; else - wanted_bits = (uint64_t)(s->bit_rate * (double)dts_pic->f->pts / fps); + wanted_bits_double = s->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"); + wanted_bits = INT64_MAX; + } else + wanted_bits = (int64_t)wanted_bits_double; } diff = s->total_bits - wanted_bits; diff --git a/libavcodec/ratecontrol.h b/libavcodec/ratecontrol.h index 4de80fad9..4d71a181b 100644 --- a/libavcodec/ratecontrol.h +++ b/libavcodec/ratecontrol.h @@ -28,9 +28,7 @@ * ratecontrol header. */ -#include #include -#include "libavutil/eval.h" typedef struct Predictor{ double coeff; @@ -41,6 +39,9 @@ typedef struct Predictor{ typedef struct RateControlEntry{ int pict_type; float qscale; + int i_count; + int f_code; + int b_code; int mv_bits; int i_tex_bits; int p_tex_bits; @@ -51,10 +52,6 @@ typedef struct RateControlEntry{ float new_qscale; int64_t mc_mb_var_sum; int64_t mb_var_sum; - int i_count; - int skip_count; - int f_code; - int b_code; }RateControlEntry; /** @@ -80,7 +77,7 @@ typedef struct RateControlContext{ int frame_count[5]; int last_non_b_pict_type; - AVExpr * rc_eq_eval; + struct AVExpr *rc_eq_eval; }RateControlContext; struct MpegEncContext; @@ -89,8 +86,8 @@ struct MpegEncContext; 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); -void ff_rate_control_uninit(struct MpegEncContext *s); int ff_vbv_update(struct MpegEncContext *s, int frame_size); void ff_get_2pass_fcode(struct MpegEncContext *s); +void ff_rate_control_uninit(RateControlContext *rcc); #endif /* AVCODEC_RATECONTROL_H */ diff --git a/libavcodec/rawdec.c b/libavcodec/rawdec.c index 8e9358f95..b02edac37 100644 --- a/libavcodec/rawdec.c +++ b/libavcodec/rawdec.c @@ -29,13 +29,12 @@ #include "codec_internal.h" #include "decode.h" #include "get_bits.h" -#include "internal.h" #include "raw.h" #include "libavutil/avassert.h" #include "libavutil/buffer.h" -#include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" typedef struct RawVideoContext { @@ -226,9 +225,6 @@ static int raw_decode(AVCodecContext *avctx, AVFrame *frame, need_copy = !avpkt->buf || context->is_1_2_4_8_bpp || context->is_yuv2 || context->is_lt_16bpp; - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; - res = ff_decode_frame_props(avctx, frame); if (res < 0) return res; diff --git a/libavcodec/riscv/Makefile b/libavcodec/riscv/Makefile index 6c2ce3001..27befce92 100644 --- a/libavcodec/riscv/Makefile +++ b/libavcodec/riscv/Makefile @@ -5,16 +5,17 @@ RVV-OBJS-$(CONFIG_AAC_ENCODER) += riscv/aacencdsp_rvv.o OBJS-$(CONFIG_AC3DSP) += riscv/ac3dsp_init.o RV-OBJS-$(CONFIG_AC3DSP) += riscv/ac3dsp_rvb.o RVV-OBJS-$(CONFIG_AC3DSP) += riscv/ac3dsp_rvv.o +RVVB-OBJS-$(CONFIG_AC3DSP) += riscv/ac3dsp_rvvb.o OBJS-$(CONFIG_ALAC_DECODER) += riscv/alacdsp_init.o RVV-OBJS-$(CONFIG_ALAC_DECODER) += riscv/alacdsp_rvv.o OBJS-$(CONFIG_AUDIODSP) += riscv/audiodsp_init.o -RV-OBJS-$(CONFIG_AUDIODSP) += riscv/audiodsp_rvf.o RVV-OBJS-$(CONFIG_AUDIODSP) += riscv/audiodsp_rvv.o OBJS-$(CONFIG_BLOCKDSP) += riscv/blockdsp_init.o RVV-OBJS-$(CONFIG_BLOCKDSP) += riscv/blockdsp_rvv.o OBJS-$(CONFIG_BSWAPDSP) += riscv/bswapdsp_init.o RV-OBJS-$(CONFIG_BSWAPDSP) += riscv/bswapdsp_rvb.o RVV-OBJS-$(CONFIG_BSWAPDSP) += riscv/bswapdsp_rvv.o +RVVB-OBJS-$(CONFIG_BSWAPDSP) += riscv/bswapdsp_rvvb.o OBJS-$(CONFIG_EXR_DECODER) += riscv/exrdsp_init.o RVV-OBJS-$(CONFIG_EXR_DECODER) += riscv/exrdsp_rvv.o OBJS-$(CONFIG_FLAC_DECODER) += riscv/flacdsp_init.o @@ -25,8 +26,13 @@ OBJS-$(CONFIG_G722DSP) += riscv/g722dsp_init.o RVV-OBJS-$(CONFIG_G722DSP) += riscv/g722dsp_rvv.o OBJS-$(CONFIG_JPEG2000_DECODER) += riscv/jpeg2000dsp_init.o RVV-OBJS-$(CONFIG_JPEG2000_DECODER) += riscv/jpeg2000dsp_rvv.o +OBJS-$(CONFIG_H263DSP) += riscv/h263dsp_init.o +RVV-OBJS-$(CONFIG_H263DSP) += riscv/h263dsp_rvv.o 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 OBJS-$(CONFIG_HUFFYUV_DECODER) += riscv/huffyuvdsp_init.o RVV-OBJS-$(CONFIG_HUFFYUV_DECODER) += riscv/huffyuvdsp_rvv.o OBJS-$(CONFIG_IDCTDSP) += riscv/idctdsp_init.o @@ -41,6 +47,8 @@ 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_OPUS_DECODER) += riscv/opusdsp_init.o RVV-OBJS-$(CONFIG_OPUS_DECODER) += riscv/opusdsp_rvv.o OBJS-$(CONFIG_PIXBLOCKDSP) += riscv/pixblockdsp_init.o @@ -48,6 +56,10 @@ RV-OBJS-$(CONFIG_PIXBLOCKDSP) += riscv/pixblockdsp_rvi.o RVV-OBJS-$(CONFIG_PIXBLOCKDSP) += riscv/pixblockdsp_rvv.o OBJS-$(CONFIG_RV34DSP) += riscv/rv34dsp_init.o RVV-OBJS-$(CONFIG_RV34DSP) += riscv/rv34dsp_rvv.o +OBJS-$(CONFIG_RV40_DECODER) += riscv/rv40dsp_init.o +RVV-OBJS-$(CONFIG_RV40_DECODER) += riscv/rv40dsp_rvv.o +RV-OBJS-$(CONFIG_STARTCODE) += riscv/startcode_rvb.o +RVV-OBJS-$(CONFIG_STARTCODE) += riscv/startcode_rvv.o OBJS-$(CONFIG_SVQ1_ENCODER) += riscv/svqenc_init.o RVV-OBJS-$(CONFIG_SVQ1_ENCODER) += riscv/svqenc_rvv.o OBJS-$(CONFIG_TAK_DECODER) += riscv/takdsp_init.o @@ -55,8 +67,20 @@ RVV-OBJS-$(CONFIG_TAK_DECODER) += riscv/takdsp_rvv.o OBJS-$(CONFIG_UTVIDEO_DECODER) += riscv/utvideodsp_init.o RVV-OBJS-$(CONFIG_UTVIDEO_DECODER) += riscv/utvideodsp_rvv.o OBJS-$(CONFIG_VC1DSP) += riscv/vc1dsp_init.o +RV-OBJS-$(CONFIG_VC1DSP) += riscv/vc1dsp_rvi.o RVV-OBJS-$(CONFIG_VC1DSP) += riscv/vc1dsp_rvv.o +OBJS-$(CONFIG_VIDEODSP) += riscv/videodsp_init.o +RV-OBJS-$(CONFIG_VIDEODSP) += riscv/videodsp.o +OBJS-$(CONFIG_VP7_DECODER) += riscv/vp7dsp_init.o +RVV-OBJS-$(CONFIG_VP7_DECODER) += riscv/vp7dsp_rvv.o OBJS-$(CONFIG_VP8DSP) += riscv/vp8dsp_init.o +RV-OBJS-$(CONFIG_VP8DSP) += riscv/vp8dsp_rvi.o RVV-OBJS-$(CONFIG_VP8DSP) += riscv/vp8dsp_rvv.o +OBJS-$(CONFIG_VP9_DECODER) += riscv/vp9dsp_init.o +RV-OBJS-$(CONFIG_VP9_DECODER) += riscv/vp9_mc_rvi.o +RVV-OBJS-$(CONFIG_VP9_DECODER) += riscv/vp9_intra_rvv.o \ + riscv/vp9_mc_rvv.o OBJS-$(CONFIG_VORBIS_DECODER) += riscv/vorbisdsp_init.o RVV-OBJS-$(CONFIG_VORBIS_DECODER) += riscv/vorbisdsp_rvv.o + +SHLIBOBJS += riscv/cpu_common.o diff --git a/libavcodec/riscv/aacencdsp_init.c b/libavcodec/riscv/aacencdsp_init.c index b27af9d97..a2dc0a8d3 100644 --- a/libavcodec/riscv/aacencdsp_init.c +++ b/libavcodec/riscv/aacencdsp_init.c @@ -26,6 +26,8 @@ #include "libavcodec/aacencdsp.h" void ff_abs_pow34_rvv(float *out, const float *in, const int size); +void ff_aac_quant_bands_rvv(int *, const float *, const float *, int, int, + int, const float, const float); av_cold void ff_aacenc_dsp_init_riscv(AACEncDSPContext *s) { @@ -33,8 +35,9 @@ av_cold void ff_aacenc_dsp_init_riscv(AACEncDSPContext *s) int flags = av_get_cpu_flags(); if (flags & AV_CPU_FLAG_RVV_F32) { - if (flags & AV_CPU_FLAG_RVB_ADDR) { + if (flags & AV_CPU_FLAG_RVB) { s->abs_pow34 = ff_abs_pow34_rvv; + s->quant_bands = ff_aac_quant_bands_rvv; } } #endif diff --git a/libavcodec/riscv/aacencdsp_rvv.S b/libavcodec/riscv/aacencdsp_rvv.S index 4c7a874d7..83d186807 100644 --- a/libavcodec/riscv/aacencdsp_rvv.S +++ b/libavcodec/riscv/aacencdsp_rvv.S @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright © 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. * @@ -20,7 +21,8 @@ #include "libavutil/riscv/asm.S" -func ff_abs_pow34_rvv, zve32f +func ff_abs_pow34_rvv, zve32f, zba + lpad 0 1: vsetvli t0, a2, e32, m8, ta, ma sub a2, a2, t0 @@ -36,3 +38,34 @@ func ff_abs_pow34_rvv, zve32f ret endfunc + +func ff_aac_quant_bands_rvv, zve32f, zba + lpad 0 +NOHWF fmv.w.x fa0, a6 +NOHWF fmv.w.x fa1, a7 + fcvt.s.w ft0, a5 + bnez a4, .L1 # signed? + .irp signed, 0, 1 +.L\signed: + vsetvli t0, a3, e32, m8, ta, ma + vle32.v v16, (a2) + sub a3, a3, t0 + .if \signed + vle32.v v8, (a1) + sh2add a1, t0, a1 + .endif + vfmul.vf v16, v16, fa0 + sh2add a2, t0, a2 + vfadd.vf v16, v16, fa1 + vfmin.vf v16, v16, ft0 + .if \signed + vfsgnjx.vv v16, v16, v8 + .endif + vfcvt.rtz.x.f.v v16, v16 + vse32.v v16, (a0) + sh2add a0, t0, a0 + bnez a3, .L\signed + + ret + .endr +endfunc diff --git a/libavcodec/riscv/aacpsdsp_init.c b/libavcodec/riscv/aacpsdsp_init.c index e094660cf..b37c93f52 100644 --- a/libavcodec/riscv/aacpsdsp_init.c +++ b/libavcodec/riscv/aacpsdsp_init.c @@ -42,20 +42,25 @@ av_cold void ff_psdsp_init_riscv(PSDSPContext *c) #if HAVE_RVV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVV_F32) { - c->hybrid_analysis = ff_ps_hybrid_analysis_rvv; + if (flags & AV_CPU_FLAG_RVV_I32) { + if (flags & AV_CPU_FLAG_RVV_F32) { + if (flags & AV_CPU_FLAG_RVB) { + if (flags & AV_CPU_FLAG_RVV_I64) + c->add_squares = ff_ps_add_squares_rvv; - if (flags & AV_CPU_FLAG_RVB_ADDR) { - if (flags & AV_CPU_FLAG_RVV_I64) { - c->add_squares = ff_ps_add_squares_rvv; - c->hybrid_synthesis_deint = ff_ps_hybrid_synthesis_deint_rvv; + c->mul_pair_single = ff_ps_mul_pair_single_rvv; } - c->mul_pair_single = ff_ps_mul_pair_single_rvv; - c->stereo_interpolate[0] = ff_ps_stereo_interpolate_rvv; + c->hybrid_analysis = ff_ps_hybrid_analysis_rvv; + } + + if (flags & AV_CPU_FLAG_RVB) { + c->hybrid_analysis_ileave = ff_ps_hybrid_analysis_ileave_rvv; + + if (flags & AV_CPU_FLAG_RVV_I64) + c->hybrid_synthesis_deint = ff_ps_hybrid_synthesis_deint_rvv; + if (flags & AV_CPU_FLAG_RVV_F32) + c->stereo_interpolate[0] = ff_ps_stereo_interpolate_rvv; } } - - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) - c->hybrid_analysis_ileave = ff_ps_hybrid_analysis_ileave_rvv; #endif } diff --git a/libavcodec/riscv/aacpsdsp_rvv.S b/libavcodec/riscv/aacpsdsp_rvv.S index a79d7d781..5f169dd6d 100644 --- a/libavcodec/riscv/aacpsdsp_rvv.S +++ b/libavcodec/riscv/aacpsdsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_ps_add_squares_rvv, zve64f +func ff_ps_add_squares_rvv, zve64f, zba + lpad 0 li t1, 32 1: vsetvli t0, a2, e32, m4, ta, ma @@ -39,7 +40,8 @@ func ff_ps_add_squares_rvv, zve64f ret endfunc -func ff_ps_mul_pair_single_rvv, zve32f +func ff_ps_mul_pair_single_rvv, zve32f, zba + lpad 0 1: vsetvli t0, a3, e32, m4, ta, ma vlseg2e32.v v24, (a1) @@ -57,6 +59,7 @@ func ff_ps_mul_pair_single_rvv, zve32f endfunc func ff_ps_hybrid_analysis_rvv, zve32f + lpad 0 /* We need 26 FP registers, for 20 scratch ones. Spill fs0-fs5. */ addi sp, sp, -48 .irp n, 0, 1, 2, 3, 4, 5 @@ -134,7 +137,8 @@ NOHWD flw fs\n, (4 * \n)(sp) .purgem filter endfunc -func ff_ps_hybrid_analysis_ileave_rvv, zve32x /* no needs for zve32f here */ +func ff_ps_hybrid_analysis_ileave_rvv, zve32x /* no zve32f here */, zba + lpad 0 slli t0, a2, 5 + 1 + 2 // ctz(32 * 2 * 4) sh2add a1, a2, a1 add a0, a0, t0 @@ -169,7 +173,7 @@ func ff_ps_hybrid_analysis_ileave_rvv, zve32x /* no needs for zve32f here */ ret endfunc -func ff_ps_hybrid_synthesis_deint_rvv, zve64x +func ff_ps_hybrid_synthesis_deint_rvv, zve64x, zba slli t0, a2, 5 + 1 + 2 sh2add a0, a2, a0 add a1, a1, t0 @@ -207,7 +211,8 @@ func ff_ps_hybrid_synthesis_deint_rvv, zve64x ret endfunc -func ff_ps_stereo_interpolate_rvv, zve32f +func ff_ps_stereo_interpolate_rvv, zve32f, b + lpad 0 vsetvli t0, zero, e32, m2, ta, ma vid.v v24 flw ft0, (a2) diff --git a/libavcodec/riscv/ac3dsp_init.c b/libavcodec/riscv/ac3dsp_init.c index b9e14d56c..24b388185 100644 --- a/libavcodec/riscv/ac3dsp_init.c +++ b/libavcodec/riscv/ac3dsp_init.c @@ -26,19 +26,47 @@ #include "libavutil/cpu.h" #include "libavcodec/ac3dsp.h" +void ff_ac3_exponent_min_rvb(uint8_t *exp, int, int); +void ff_ac3_exponent_min_rvv(uint8_t *exp, int, int); void ff_extract_exponents_rvb(uint8_t *exp, int32_t *coef, int nb_coefs); +void ff_extract_exponents_rvvb(uint8_t *exp, int32_t *coef, int nb_coefs); void ff_float_to_fixed24_rvv(int32_t *dst, const float *src, size_t len); +void ff_sum_square_butterfly_int32_rvv(int64_t *, const int32_t *, + const int32_t *, int); +void ff_sum_square_butterfly_float_rvv(float *, const float *, + const float *, int); av_cold void ff_ac3dsp_init_riscv(AC3DSPContext *c) { #if HAVE_RV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVB_ADDR) { - if (flags & AV_CPU_FLAG_RVB_BASIC) - c->extract_exponents = ff_extract_exponents_rvb; - if (flags & AV_CPU_FLAG_RVV_F32) - c->float_to_fixed24 = ff_float_to_fixed24_rvv; + if (flags & AV_CPU_FLAG_RVB_BASIC) { + c->ac3_exponent_min = ff_ac3_exponent_min_rvb; + c->extract_exponents = ff_extract_exponents_rvb; + } + +# if HAVE_RVV + if (flags & AV_CPU_FLAG_RVV_I32) { + c->ac3_exponent_min = ff_ac3_exponent_min_rvv; + + if (flags & AV_CPU_FLAG_RVB) { +# if HAVE_RV_ZVBB + if (flags & AV_CPU_FLAG_RV_ZVBB) + c->extract_exponents = ff_extract_exponents_rvvb; +# endif + if (flags & AV_CPU_FLAG_RVV_F32) { + c->float_to_fixed24 = ff_float_to_fixed24_rvv; + c->sum_square_butterfly_float = + ff_sum_square_butterfly_float_rvv; + } +# if __riscv_xlen >= 64 + if (flags & AV_CPU_FLAG_RVV_I64) + c->sum_square_butterfly_int32 = + ff_sum_square_butterfly_int32_rvv; +# endif +# endif + } } #endif } diff --git a/libavcodec/riscv/ac3dsp_rvb.S b/libavcodec/riscv/ac3dsp_rvb.S index 48f8bb101..a3c5187cf 100644 --- a/libavcodec/riscv/ac3dsp_rvb.S +++ b/libavcodec/riscv/ac3dsp_rvb.S @@ -21,7 +21,30 @@ #include "config.h" #include "libavutil/riscv/asm.S" +func ff_ac3_exponent_min_rvb, zbb + lpad 0 + beqz a1, 3f +1: + addi a2, a2, -1 + lb t3, (a0) + addi t0, a0, 256 + mv t1, a1 +2: + lb t4, (t0) + addi t1, t1, -1 + addi t0, t0, 256 + minu t3, t3, t4 + bnez t1, 2b + + sb t3, (a0) + addi a0, a0, 1 + bnez a2, 1b +3: + ret +endfunc + func ff_extract_exponents_rvb, zbb + lpad 0 1: lw t0, (a1) addi a0, a0, 1 diff --git a/libavcodec/riscv/ac3dsp_rvv.S b/libavcodec/riscv/ac3dsp_rvv.S index b8d32c467..261cb9628 100644 --- a/libavcodec/riscv/ac3dsp_rvv.S +++ b/libavcodec/riscv/ac3dsp_rvv.S @@ -21,7 +21,31 @@ #include "config.h" #include "libavutil/riscv/asm.S" -func ff_float_to_fixed24_rvv, zve32f +func ff_ac3_exponent_min_rvv, zve32x + lpad 0 + beqz a1, 3f +1: + vsetvli t2, a2, e8, m8, ta, ma + vle8.v v8, (a0) + addi t0, a0, 256 + sub a2, a2, t2 + mv t1, a1 +2: + vle8.v v16, (t0) + addi t1, t1, -1 + vminu.vv v8, v8, v16 + addi t0, t0, 256 + bnez t1, 2b + + vse8.v v8, (a0) + add a0, a0, t2 + bnez a2, 1b +3: + ret +endfunc + +func ff_float_to_fixed24_rvv, zve32f, zba + lpad 0 li t1, 1 << 24 fcvt.s.w f0, t1 1: @@ -37,3 +61,85 @@ func ff_float_to_fixed24_rvv, zve32f ret endfunc + +#if __riscv_xlen >= 64 +func ff_sum_square_butterfly_int32_rvv, zve64x, zba + lpad 0 + vsetvli t0, zero, e64, m8, ta, ma + vmv.v.x v0, zero + vmv.v.x v8, zero +1: + vsetvli t0, a3, e32, m2, tu, ma + vle32.v v16, (a1) + sub a3, a3, t0 + vle32.v v20, (a2) + sh2add a1, t0, a1 + vadd.vv v24, v16, v20 + sh2add a2, t0, a2 + vsub.vv v28, v16, v20 + vwmacc.vv v0, v16, v16 + vwmacc.vv v4, v20, v20 + vwmacc.vv v8, v24, v24 + vwmacc.vv v12, v28, v28 + bnez a3, 1b + + vsetvli t0, zero, e64, m4, ta, ma + vmv.s.x v16, zero + vmv.s.x v17, zero + vredsum.vs v16, v0, v16 + vmv.s.x v18, zero + vredsum.vs v17, v4, v17 + vmv.s.x v19, zero + vredsum.vs v18, v8, v18 + vmv.x.s t0, v16 + vredsum.vs v19, v12, v19 + vmv.x.s t1, v17 + sd t0, (a0) + vmv.x.s t2, v18 + sd t1, 8(a0) + vmv.x.s t3, v19 + sd t2, 16(a0) + sd t3, 24(a0) + ret +endfunc +#endif + +func ff_sum_square_butterfly_float_rvv, zve32f, zba + lpad 0 + vsetvli t0, zero, e32, m8, ta, ma + vmv.v.x v0, zero + vmv.v.x v8, zero +1: + vsetvli t0, a3, e32, m4, tu, ma + vle32.v v16, (a1) + sub a3, a3, t0 + vle32.v v20, (a2) + sh2add a1, t0, a1 + vfadd.vv v24, v16, v20 + sh2add a2, t0, a2 + vfsub.vv v28, v16, v20 + vfmacc.vv v0, v16, v16 + vfmacc.vv v4, v20, v20 + vfmacc.vv v8, v24, v24 + vfmacc.vv v12, v28, v28 + bnez a3, 1b + + vsetvli t0, zero, e32, m4, ta, ma + vmv.s.x v16, zero + vmv.s.x v17, zero + vfredsum.vs v16, v0, v16 + vmv.s.x v18, zero + vfredsum.vs v17, v4, v17 + vmv.s.x v19, zero + vfredsum.vs v18, v8, v18 + vfmv.f.s ft0, v16 + vfredsum.vs v19, v12, v19 + vfmv.f.s ft1, v17 + fsw ft0, (a0) + vfmv.f.s ft2, v18 + fsw ft1, 4(a0) + vfmv.f.s ft3, v19 + fsw ft2, 8(a0) + fsw ft3, 12(a0) + ret +endfunc diff --git a/libavutil/riscv/timer.h b/libavcodec/riscv/ac3dsp_rvvb.S similarity index 54% rename from libavutil/riscv/timer.h rename to libavcodec/riscv/ac3dsp_rvvb.S index 174b469cb..2f4e64455 100644 --- a/libavutil/riscv/timer.h +++ b/libavcodec/riscv/ac3dsp_rvvb.S @@ -1,4 +1,6 @@ /* + * Copyright © 2023 Rémi Denis-Courmont. + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -16,39 +18,27 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVUTIL_RISCV_TIMER_H -#define AVUTIL_RISCV_TIMER_H - #include "config.h" +#include "libavutil/riscv/asm.S" -#if HAVE_INLINE_ASM -#include +func ff_extract_exponents_rvvb, zve32x, zvbb, zba + lpad 0 +1: + vsetvli t0, a2, e32, m8, ta, ma + vle32.v v8, (a1) + sub a2, a2, t0 + vneg.v v16, v8 + sh2add a1, t0, a1 + vmax.vv v8, v8, v16 + vclz.v v8, v8 + vsetvli zero, zero, e16, m4, ta, ma + vncvt.x.x.w v4, v8 + vsetvli zero, zero, e8, m2, ta, ma + vncvt.x.x.w v2, v4 + vadd.vi v2, v2, 24 - 32 + vse8.v v2, (a0) + add a0, a0, t0 + bnez a2, 1b -static inline uint64_t ff_read_time(void) -{ -#if (__riscv_xlen >= 64) - uintptr_t cycles; - - __asm__ volatile ("rdtime %0" : "=r" (cycles)); - -#else - uint64_t cycles; - uint32_t hi, lo, check; - - __asm__ volatile ( - "1: rdtimeh %0\n" - " rdtime %1\n" - " rdtimeh %2\n" - " bne %0, %2, 1b\n" : "=r" (hi), "=r" (lo), "=r" (check)); - - cycles = (((uint64_t)hi) << 32) | lo; - -#endif - return cycles; -} - -#define AV_READ_TIME ff_read_time -#define FF_TIMER_UNITS "ticks" - -#endif -#endif /* AVUTIL_RISCV_TIMER_H */ + ret +endfunc diff --git a/libavcodec/riscv/alacdsp_init.c b/libavcodec/riscv/alacdsp_init.c index cd6dc4f8a..c71b00c32 100644 --- a/libavcodec/riscv/alacdsp_init.c +++ b/libavcodec/riscv/alacdsp_init.c @@ -41,7 +41,7 @@ av_cold void ff_alacdsp_init_riscv(ALACDSPContext *c) #if HAVE_RVV && (__riscv_xlen == 64) int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { c->decorrelate_stereo = ff_alac_decorrelate_stereo_rvv; c->append_extra_bits[0] = ff_alac_append_extra_bits_mono_rvv; c->append_extra_bits[1] = ff_alac_append_extra_bits_stereo_rvv; diff --git a/libavcodec/riscv/alacdsp_rvv.S b/libavcodec/riscv/alacdsp_rvv.S index 8efb04e0c..118a1f291 100644 --- a/libavcodec/riscv/alacdsp_rvv.S +++ b/libavcodec/riscv/alacdsp_rvv.S @@ -21,7 +21,8 @@ #include "libavutil/riscv/asm.S" #if (__riscv_xlen == 64) -func ff_alac_decorrelate_stereo_rvv, zve32x +func ff_alac_decorrelate_stereo_rvv, zve32x, zba + lpad 0 ld a4, 8(a0) ld a0, 0(a0) 1: @@ -43,7 +44,8 @@ func ff_alac_decorrelate_stereo_rvv, zve32x ret endfunc -func ff_alac_append_extra_bits_mono_rvv, zve32x +func ff_alac_append_extra_bits_mono_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a1, (a1) 1: @@ -61,7 +63,8 @@ func ff_alac_append_extra_bits_mono_rvv, zve32x ret endfunc -func ff_alac_append_extra_bits_stereo_rvv, zve32x +func ff_alac_append_extra_bits_stereo_rvv, zve32x, zba + lpad 0 ld a6, 8(a0) ld a0, (a0) ld a7, 8(a1) diff --git a/libavcodec/riscv/audiodsp_init.c b/libavcodec/riscv/audiodsp_init.c index f60640642..e2d829ed5 100644 --- a/libavcodec/riscv/audiodsp_init.c +++ b/libavcodec/riscv/audiodsp_init.c @@ -24,8 +24,6 @@ #include "libavutil/cpu.h" #include "libavcodec/audiodsp.h" -void ff_vector_clipf_rvf(float *dst, const float *src, int len, float min, float max); - int32_t ff_scalarproduct_int16_rvv(const int16_t *v1, const int16_t *v2, int len); void ff_vector_clip_int32_rvv(int32_t *dst, const int32_t *src, int32_t min, int32_t max, unsigned int len); @@ -33,20 +31,15 @@ void ff_vector_clipf_rvv(float *dst, const float *src, int len, float min, float av_cold void ff_audiodsp_init_riscv(AudioDSPContext *c) { -#if HAVE_RV +#if HAVE_RVV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVF) - c->vector_clipf = ff_vector_clipf_rvf; -#if HAVE_RVV - if (flags & AV_CPU_FLAG_RVB_ADDR) { - if (flags & AV_CPU_FLAG_RVV_I32) { - c->scalarproduct_int16 = ff_scalarproduct_int16_rvv; - c->vector_clip_int32 = ff_vector_clip_int32_rvv; - } + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { + c->scalarproduct_int16 = ff_scalarproduct_int16_rvv; + c->vector_clip_int32 = ff_vector_clip_int32_rvv; + if (flags & AV_CPU_FLAG_RVV_F32) c->vector_clipf = ff_vector_clipf_rvv; } #endif -#endif } diff --git a/libavcodec/riscv/audiodsp_rvv.S b/libavcodec/riscv/audiodsp_rvv.S index f0b23bab5..7ba64bae7 100644 --- a/libavcodec/riscv/audiodsp_rvv.S +++ b/libavcodec/riscv/audiodsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_scalarproduct_int16_rvv, zve32x +func ff_scalarproduct_int16_rvv, zve32x, zba + lpad 0 vsetvli t0, zero, e32, m8, ta, ma vmv.v.x v8, zero vmv.s.x v0, zero @@ -40,7 +41,7 @@ func ff_scalarproduct_int16_rvv, zve32x ret endfunc -func ff_vector_clip_int32_rvv, zve32x +func ff_vector_clip_int32_rvv, zve32x, zba 1: vsetvli t0, a4, e32, m8, ta, ma vle32.v v8, (a1) @@ -55,7 +56,8 @@ func ff_vector_clip_int32_rvv, zve32x ret endfunc -func ff_vector_clipf_rvv, zve32f +func ff_vector_clipf_rvv, zve32f, zba + lpad 0 NOHWF fmv.w.x fa0, a3 NOHWF fmv.w.x fa1, a4 1: diff --git a/libavcodec/riscv/blockdsp_init.c b/libavcodec/riscv/blockdsp_init.c index 59b2f9d47..adde0b890 100644 --- a/libavcodec/riscv/blockdsp_init.c +++ b/libavcodec/riscv/blockdsp_init.c @@ -27,15 +27,21 @@ void ff_clear_block_rvv(int16_t *block); void ff_clear_blocks_rvv(int16_t *block); +void ff_fill_block16_rvv(uint8_t *block, uint8_t value, ptrdiff_t line_size, + int h); +void ff_fill_block8_rvv(uint8_t *block, uint8_t value, ptrdiff_t line_size, + int h); av_cold void ff_blockdsp_init_riscv(BlockDSPContext *c) { #if HAVE_RVV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVV_I64 && ff_get_rv_vlenb() >= 16) { + if (flags & AV_CPU_FLAG_RVV_I64 && ff_rv_vlen_least(128)) { c->clear_block = ff_clear_block_rvv; c->clear_blocks = ff_clear_blocks_rvv; + c->fill_block_tab[0] = ff_fill_block16_rvv; + c->fill_block_tab[1] = ff_fill_block8_rvv; } #endif } diff --git a/libavcodec/riscv/blockdsp_rvv.S b/libavcodec/riscv/blockdsp_rvv.S index 8bb00bb46..04da26541 100644 --- a/libavcodec/riscv/blockdsp_rvv.S +++ b/libavcodec/riscv/blockdsp_rvv.S @@ -21,6 +21,7 @@ #include "libavutil/riscv/asm.S" func ff_clear_block_rvv, zve64x + lpad 0 vsetivli zero, 16, e64, m8, ta, ma vmv.v.i v0, 0 vse64.v v0, (a0) @@ -29,6 +30,7 @@ func ff_clear_block_rvv, zve64x endfunc func ff_clear_blocks_rvv, zve64x + lpad 0 vsetivli zero, 16, e64, m8, ta, ma vmv.v.i v0, 0 @@ -40,3 +42,26 @@ func ff_clear_blocks_rvv, zve64x ret endfunc + +func ff_fill_block16_rvv, zve32x + lpad 0 + vsetivli t0, 16, e8, m1, ta, ma + vmv.v.x v8, a1 +1: + addi a3, a3, -1 + vse8.v v8, (a0) + add a0, a0, a2 + bnez a3, 1b + + ret +endfunc + +func ff_fill_block8_rvv, zve64x + lpad 0 + vsetvli t0, zero, e8, m4, ta, ma + vmv.v.x v8, a1 + vsetvli t0, a3, e64, m4, ta, ma + vsse64.v v8, (a0), a2 + + ret +endfunc diff --git a/libavcodec/riscv/bswapdsp_init.c b/libavcodec/riscv/bswapdsp_init.c index d490c434e..43d74a4e9 100644 --- a/libavcodec/riscv/bswapdsp_init.c +++ b/libavcodec/riscv/bswapdsp_init.c @@ -27,21 +27,28 @@ void ff_bswap32_buf_rvb(uint32_t *dst, const uint32_t *src, int len); void ff_bswap16_buf_rvv(uint16_t *dst, const uint16_t *src, int len); +void ff_bswap32_buf_rvvb(uint32_t *dst, const uint32_t *src, int len); +void ff_bswap16_buf_rvvb(uint16_t *dst, const uint16_t *src, int len); av_cold void ff_bswapdsp_init_riscv(BswapDSPContext *c) { #if HAVE_RV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVB_ADDR) { #if (__riscv_xlen >= 64) - if (flags & AV_CPU_FLAG_RVB_BASIC) - c->bswap_buf = ff_bswap32_buf_rvb; + if (flags & AV_CPU_FLAG_RVB_BASIC) + c->bswap_buf = ff_bswap32_buf_rvb; #endif #if HAVE_RVV - if (flags & AV_CPU_FLAG_RVV_I32) - c->bswap16_buf = ff_bswap16_buf_rvv; + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { + c->bswap16_buf = ff_bswap16_buf_rvv; +#if HAVE_RV_ZVBB + if (flags & AV_CPU_FLAG_RV_ZVBB) { + c->bswap_buf = ff_bswap32_buf_rvvb; + c->bswap16_buf = ff_bswap16_buf_rvvb; + } #endif } #endif +#endif } diff --git a/libavcodec/riscv/bswapdsp_rvb.S b/libavcodec/riscv/bswapdsp_rvb.S index 0786bd3f3..8c7c791fe 100644 --- a/libavcodec/riscv/bswapdsp_rvb.S +++ b/libavcodec/riscv/bswapdsp_rvb.S @@ -24,6 +24,8 @@ #if (__riscv_xlen >= 64) func ff_bswap32_buf_rvb, zbb + lpad 0 + slli a2, a2, 2 bswap32_rvb a0, a1, a2 endfunc #endif diff --git a/libavcodec/riscv/bswapdsp_rvv.S b/libavcodec/riscv/bswapdsp_rvv.S index b37fe2625..b4911bf0e 100644 --- a/libavcodec/riscv/bswapdsp_rvv.S +++ b/libavcodec/riscv/bswapdsp_rvv.S @@ -21,7 +21,8 @@ #include "config.h" #include "libavutil/riscv/asm.S" -func ff_bswap16_buf_rvv, zve32x +func ff_bswap16_buf_rvv, zve32x, zba + lpad 0 1: vsetvli t0, a2, e16, m8, ta, ma vle16.v v8, (a1) diff --git a/libavcodec/riscv/audiodsp_rvf.S b/libavcodec/riscv/bswapdsp_rvvb.S similarity index 56% rename from libavcodec/riscv/audiodsp_rvf.S rename to libavcodec/riscv/bswapdsp_rvvb.S index 2ec8a1169..165ac104a 100644 --- a/libavcodec/riscv/audiodsp_rvf.S +++ b/libavcodec/riscv/bswapdsp_rvvb.S @@ -1,5 +1,5 @@ /* - * Copyright © 2022 Rémi Denis-Courmont. + * Copyright © 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. * @@ -18,31 +18,34 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" #include "libavutil/riscv/asm.S" -func ff_vector_clipf_rvf, f -NOHWF fmv.w.x fa0, a3 -NOHWF fmv.w.x fa1, a4 +func ff_bswap32_buf_rvvb, zve32x, zvbb, zba + lpad 0 1: - flw ft0, (a1) - flw ft1, 4(a1) - fmax.s ft0, ft0, fa0 - flw ft2, 8(a1) - fmax.s ft1, ft1, fa0 - flw ft3, 12(a1) - fmax.s ft2, ft2, fa0 - addi a2, a2, -4 - fmax.s ft3, ft3, fa0 - addi a1, a1, 16 - fmin.s ft0, ft0, fa1 - fmin.s ft1, ft1, fa1 - fsw ft0, (a0) - fmin.s ft2, ft2, fa1 - fsw ft1, 4(a0) - fmin.s ft3, ft3, fa1 - fsw ft2, 8(a0) - fsw ft3, 12(a0) - addi a0, a0, 16 + vsetvli t0, a2, e32, m8, ta, ma + vle32.v v8, (a1) + sub a2, a2, t0 + vrev8.v v8, v8 + sh2add a1, t0, a1 + vse32.v v8, (a0) + sh2add a0, t0, a0 + bnez a2, 1b + + ret +endfunc + +func ff_bswap16_buf_rvvb, zve32x, zvbb, zba + lpad 0 +1: + vsetvli t0, a2, e16, m8, ta, ma + vle16.v v8, (a1) + sub a2, a2, t0 + vrev8.v v8, v8 + sh1add a1, t0, a1 + vse16.v v8, (a0) + sh1add a0, t0, a0 bnez a2, 1b ret diff --git a/libavcodec/riscv/cpu_common.c b/libavcodec/riscv/cpu_common.c new file mode 100644 index 000000000..17c9b392c --- /dev/null +++ b/libavcodec/riscv/cpu_common.c @@ -0,0 +1 @@ +#include "libavutil/riscv/cpu_common.c" diff --git a/libavcodec/riscv/exrdsp_init.c b/libavcodec/riscv/exrdsp_init.c index 690a2231c..f074c71c5 100644 --- a/libavcodec/riscv/exrdsp_init.c +++ b/libavcodec/riscv/exrdsp_init.c @@ -31,8 +31,7 @@ av_cold void ff_exrdsp_init_riscv(ExrDSPContext *c) #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) c->reorder_pixels = ff_reorder_pixels_rvv; - } #endif } diff --git a/libavcodec/riscv/exrdsp_rvv.S b/libavcodec/riscv/exrdsp_rvv.S index f4a35f58f..e58ed70b9 100644 --- a/libavcodec/riscv/exrdsp_rvv.S +++ b/libavcodec/riscv/exrdsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_reorder_pixels_rvv, zve32x +func ff_reorder_pixels_rvv, zve32x, zba + lpad 0 srai a2, a2, 1 add t1, a1, a2 1: diff --git a/libavcodec/riscv/fixed_vtype.S b/libavcodec/riscv/fixed_vtype.S new file mode 100644 index 000000000..7aac70bda --- /dev/null +++ b/libavcodec/riscv/fixed_vtype.S @@ -0,0 +1,48 @@ +/* + * 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 + */ + +#define VILL -0x8000 + + .data +ff_vtype_e8: +ff_vtype_e8_1: + .half VILL +ff_vtype_e8_2: + .half VILL +ff_vtype_e8_4: + .half VILL +ff_vtype_e8_8: + .half VILL +ff_vtype_e8_16: + .half VILL +ff_vtype_e8_32: + .half VILL + +ff_vtype_e16: +ff_vtype_e16_1: + .half VILL +ff_vtype_e16_2: + .half VILL +ff_vtype_e16_4: + .half VILL +ff_vtype_e16_8: + .half VILL +ff_vtype_e16_16: + .half VILL diff --git a/libavcodec/riscv/flacdsp_init.c b/libavcodec/riscv/flacdsp_init.c index 6cfb50ead..2689ebf2d 100644 --- a/libavcodec/riscv/flacdsp_init.c +++ b/libavcodec/riscv/flacdsp_init.c @@ -31,6 +31,10 @@ void ff_flac_lpc32_rvv(int32_t *decoded, const int coeffs[32], int pred_order, int qlevel, int len); void ff_flac_lpc32_rvv_simple(int32_t *decoded, const int coeffs[32], int pred_order, int qlevel, int len); +void ff_flac_lpc33_rvv(int64_t *, const int32_t *, const int coeffs[32], + int pred_order, int qlevel, int len); +void ff_flac_wasted32_rvv(int32_t *, int shift, int len); +void ff_flac_wasted33_rvv(int64_t *, const int32_t *, int shift, int len); void ff_flac_decorrelate_indep2_16_rvv(uint8_t **out, int32_t **in, int channels, int len, int shift); void ff_flac_decorrelate_indep4_16_rvv(uint8_t **out, int32_t **in, @@ -66,18 +70,29 @@ av_cold void ff_flacdsp_init_riscv(FLACDSPContext *c, enum AVSampleFormat fmt, #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { int vlenb = ff_get_rv_vlenb(); if (vlenb >= 16) { c->lpc16 = ff_flac_lpc16_rvv; + # if (__riscv_xlen >= 64) - if (vlenb > 16) - c->lpc32 = ff_flac_lpc32_rvv_simple; - else - c->lpc32 = ff_flac_lpc32_rvv; + if (flags & AV_CPU_FLAG_RVV_I64) { + if (vlenb > 16) { + c->lpc32 = ff_flac_lpc32_rvv_simple; + c->lpc33 = ff_flac_lpc33_rvv; + } else + c->lpc32 = ff_flac_lpc32_rvv; + } +# endif } + c->wasted32 = ff_flac_wasted32_rvv; + + if (flags & AV_CPU_FLAG_RVV_I64) + c->wasted33 = ff_flac_wasted33_rvv; + +# if (__riscv_xlen >= 64) switch (fmt) { case AV_SAMPLE_FMT_S16: switch (channels) { @@ -117,8 +132,8 @@ av_cold void ff_flacdsp_init_riscv(FLACDSPContext *c, enum AVSampleFormat fmt, c->decorrelate[2] = ff_flac_decorrelate_rs_32_rvv; c->decorrelate[3] = ff_flac_decorrelate_ms_32_rvv; break; -# endif } +# endif } #endif } diff --git a/libavcodec/riscv/flacdsp_rvv.S b/libavcodec/riscv/flacdsp_rvv.S index 5eb3c5bd5..a927f188d 100644 --- a/libavcodec/riscv/flacdsp_rvv.S +++ b/libavcodec/riscv/flacdsp_rvv.S @@ -20,8 +20,10 @@ #include "libavutil/riscv/asm.S" -func ff_flac_lpc16_rvv, zve32x - vsetvli zero, a2, e32, m8, ta, ma +func ff_flac_lpc16_rvv, zve32x, b + lpad 0 + vtype_vli t0, a2, t2, e32, ta, ma + vsetvl zero, a2, t0 vle32.v v8, (a1) sub a4, a4, a2 vle32.v v16, (a0) @@ -44,7 +46,8 @@ func ff_flac_lpc16_rvv, zve32x endfunc #if (__riscv_xlen == 64) -func ff_flac_lpc32_rvv, zve32x +func ff_flac_lpc32_rvv, zve64x, zba + lpad 0 addi t2, a2, -16 ble t2, zero, ff_flac_lpc32_rvv_simple vsetivli zero, 1, e64, m1, ta, ma @@ -75,22 +78,25 @@ func ff_flac_lpc32_rvv, zve32x ret endfunc -func ff_flac_lpc32_rvv_simple, zve32x - vsetivli zero, 1, e64, m1, ta, ma +func ff_flac_lpc32_rvv_simple, zve64x, b + lpad 0 + vtype_vli t3, a2, t1, e64, ta, ma + vntypei t2, t3 + vsetvl zero, a2, t3 // e64 vmv.s.x v0, zero - vsetvli zero, a2, e32, m4, ta, ma + vsetvl zero, zero, t2 // e32 vle32.v v8, (a1) sub a4, a4, a2 vle32.v v16, (a0) sh2add a0, a2, a0 1: vwmul.vv v24, v8, v16 - vsetvli zero, zero, e64, m8, ta, ma + vsetvl zero, zero, t3 // e64 vredsum.vs v24, v24, v0 lw t0, (a0) addi a4, a4, -1 vmv.x.s t1, v24 - vsetvli zero, zero, e32, m4, ta, ma + vsetvl zero, zero, t2 // e32 sra t1, t1, a3 add t0, t0, t1 vslide1down.vx v16, v16, t0 @@ -101,7 +107,84 @@ func ff_flac_lpc32_rvv_simple, zve32x ret endfunc -func ff_flac_decorrelate_indep2_16_rvv, zve32x +func ff_flac_lpc33_rvv, zve64x, b + lpad 0 + vtype_vli t0, a3, t1, e64, ta, ma + vsetvl zero, a3, t0 + vmv.s.x v0, zero + sh2add a1, a3, a1 + vle32.v v24, (a2) + sub a5, a5, a3 + vle64.v v16, (a0) + sh3add a0, a3, a0 + vsext.vf2 v8, v24 +1: + vmul.vv v24, v8, v16 + lw t0, (a1) + addi a1, a1, 4 + vredsum.vs v24, v24, v0 + addi a5, a5, -1 + vmv.x.s t1, v24 + sra t1, t1, a4 + add t0, t0, t1 + vslide1down.vx v16, v16, t0 + sd t0, (a0) + addi a0, a0, 8 + bnez a5, 1b + + ret +endfunc +#endif + +func ff_flac_wasted32_rvv, zve32x, zba + lpad 0 +1: + vsetvli t0, a2, e32, m8, ta, ma + vle32.v v8, (a0) + sub a2, a2, t0 + vsll.vx v8, v8, a1 + vse32.v v8, (a0) + sh2add a0, t0, a0 + bnez a2, 1b + + ret +endfunc + +func ff_flac_wasted33_rvv, zve64x, zba + lpad 0 + srli t0, a2, 5 + li t1, 1 + bnez t0, 2f + sll a2, t1, a2 +1: + vsetvli t0, a3, e32, m4, ta, ma + vle32.v v8, (a1) + sub a3, a3, t0 + vwmulsu.vx v16, v8, a2 + sh2add a1, t0, a1 + vse64.v v16, (a0) + sh3add a0, t0, a0 + bnez a3, 1b + + ret + +2: // Pessimistic case: wasted >= 32 + vsetvli t0, a3, e64, m8, ta, ma + vle32.v v8, (a1) + sub a3, a3, t0 + vsext.vf2 v16, v8 + sh2add a1, t0, a1 + vsll.vx v16, v16, a2 + vse64.v v16, (a0) + sh3add a0, t0, a0 + bnez a3, 2b + + ret +endfunc + +#if (__riscv_xlen == 64) +func ff_flac_decorrelate_indep2_16_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld a1, (a1) @@ -124,7 +207,8 @@ func ff_flac_decorrelate_indep2_16_rvv, zve32x ret endfunc -func ff_flac_decorrelate_indep4_16_rvv, zve32x +func ff_flac_decorrelate_indep4_16_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld t1, 16(a1) @@ -157,7 +241,8 @@ func ff_flac_decorrelate_indep4_16_rvv, zve32x ret endfunc -func ff_flac_decorrelate_indep6_16_rvv, zve32x +func ff_flac_decorrelate_indep6_16_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld t1, 16(a1) @@ -202,7 +287,8 @@ func ff_flac_decorrelate_indep6_16_rvv, zve32x ret endfunc -func ff_flac_decorrelate_indep8_16_rvv, zve32x +func ff_flac_decorrelate_indep8_16_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld t1, 16(a1) @@ -256,9 +342,8 @@ func ff_flac_decorrelate_indep8_16_rvv, zve32x ret endfunc - - -func ff_flac_decorrelate_ls_16_rvv, zve32x +func ff_flac_decorrelate_ls_16_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld a1, (a1) @@ -282,7 +367,8 @@ func ff_flac_decorrelate_ls_16_rvv, zve32x ret endfunc -func ff_flac_decorrelate_rs_16_rvv, zve32x +func ff_flac_decorrelate_rs_16_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld a1, (a1) @@ -306,7 +392,8 @@ func ff_flac_decorrelate_rs_16_rvv, zve32x ret endfunc -func ff_flac_decorrelate_ms_16_rvv, zve32x +func ff_flac_decorrelate_ms_16_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld a1, (a1) @@ -332,7 +419,8 @@ func ff_flac_decorrelate_ms_16_rvv, zve32x ret endfunc -func ff_flac_decorrelate_indep2_32_rvv, zve32x +func ff_flac_decorrelate_indep2_32_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld a1, (a1) @@ -352,7 +440,8 @@ func ff_flac_decorrelate_indep2_32_rvv, zve32x ret endfunc -func ff_flac_decorrelate_indep4_32_rvv, zve32x +func ff_flac_decorrelate_indep4_32_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld t1, 16(a1) @@ -381,7 +470,8 @@ func ff_flac_decorrelate_indep4_32_rvv, zve32x ret endfunc -func ff_flac_decorrelate_indep6_32_rvv, zve32x +func ff_flac_decorrelate_indep6_32_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld t1, 16(a1) @@ -419,7 +509,8 @@ func ff_flac_decorrelate_indep6_32_rvv, zve32x ret endfunc -func ff_flac_decorrelate_indep8_32_rvv, zve32x +func ff_flac_decorrelate_indep8_32_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld t1, 16(a1) @@ -464,7 +555,8 @@ func ff_flac_decorrelate_indep8_32_rvv, zve32x ret endfunc -func ff_flac_decorrelate_ls_32_rvv, zve32x +func ff_flac_decorrelate_ls_32_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld a1, (a1) @@ -485,7 +577,8 @@ func ff_flac_decorrelate_ls_32_rvv, zve32x ret endfunc -func ff_flac_decorrelate_rs_32_rvv, zve32x +func ff_flac_decorrelate_rs_32_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld a1, (a1) @@ -506,7 +599,8 @@ func ff_flac_decorrelate_rs_32_rvv, zve32x ret endfunc -func ff_flac_decorrelate_ms_32_rvv, zve32x +func ff_flac_decorrelate_ms_32_rvv, zve32x, zba + lpad 0 ld a0, (a0) ld a2, 8(a1) ld a1, (a1) diff --git a/libavcodec/riscv/fmtconvert_init.c b/libavcodec/riscv/fmtconvert_init.c index f5eeafba4..4d3f0f646 100644 --- a/libavcodec/riscv/fmtconvert_init.c +++ b/libavcodec/riscv/fmtconvert_init.c @@ -36,7 +36,7 @@ av_cold void ff_fmt_convert_init_riscv(FmtConvertContext *c) #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_F32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_F32) && (flags & AV_CPU_FLAG_RVB)) { c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_rvv; c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_rvv; } diff --git a/libavcodec/riscv/fmtconvert_rvv.S b/libavcodec/riscv/fmtconvert_rvv.S index d0e2f106d..cedeab4e5 100644 --- a/libavcodec/riscv/fmtconvert_rvv.S +++ b/libavcodec/riscv/fmtconvert_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_int32_to_float_fmul_scalar_rvv, zve32f +func ff_int32_to_float_fmul_scalar_rvv, zve32f, zba + lpad 0 NOHWF fmv.w.x fa0, a2 NOHWF mv a2, a3 1: @@ -37,7 +38,8 @@ NOHWF mv a2, a3 ret endfunc -func ff_int32_to_float_fmul_array8_rvv, zve32f +func ff_int32_to_float_fmul_array8_rvv, zve32f, zba + lpad 0 srai a4, a4, 3 1: vsetvli t0, a4, e32, m1, ta, ma diff --git a/libavcodec/riscv/g722dsp_init.c b/libavcodec/riscv/g722dsp_init.c index 77e29bfb5..0c7e7919e 100644 --- a/libavcodec/riscv/g722dsp_init.c +++ b/libavcodec/riscv/g722dsp_init.c @@ -34,7 +34,7 @@ av_cold void ff_g722dsp_init_riscv(G722DSPContext *dsp) #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && ff_get_rv_vlenb() >= 16) + if ((flags & AV_CPU_FLAG_RVV_I32) && ff_rv_vlen_least(128)) dsp->apply_qmf = ff_g722_apply_qmf_rvv; #endif } diff --git a/libavcodec/riscv/g722dsp_rvv.S b/libavcodec/riscv/g722dsp_rvv.S index 981d5cecd..6ceb70fde 100644 --- a/libavcodec/riscv/g722dsp_rvv.S +++ b/libavcodec/riscv/g722dsp_rvv.S @@ -21,6 +21,7 @@ #include "libavutil/riscv/asm.S" func ff_g722_apply_qmf_rvv, zve32x + lpad 0 lla t0, qmf_coeffs vsetivli zero, 12, e16, m2, ta, ma vlseg2e16.v v28, (a0) diff --git a/libavcodec/alpha/blockdsp_alpha.c b/libavcodec/riscv/h263dsp_init.c similarity index 57% rename from libavcodec/alpha/blockdsp_alpha.c rename to libavcodec/riscv/h263dsp_init.c index c6f096460..21b536366 100644 --- a/libavcodec/alpha/blockdsp_alpha.c +++ b/libavcodec/riscv/h263dsp_init.c @@ -1,6 +1,5 @@ /* - * Alpha optimised block operations - * Copyright (c) 2002 Falk Hueffner + * Copyright © 2022 Rémi Denis-Courmont. * * This file is part of FFmpeg. * @@ -19,31 +18,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include "config.h" #include "libavutil/attributes.h" -#include "libavcodec/blockdsp.h" -#include "asm.h" +#include "libavutil/cpu.h" +#include "libavutil/riscv/cpu.h" +#include "libavcodec/h263dsp.h" -static void clear_blocks_axp(int16_t *blocks) { - uint64_t *p = (uint64_t *) blocks; - int n = sizeof(int16_t) * 6 * 64; +void ff_h263_h_loop_filter_rvv(uint8_t *src, int stride, int q); +void ff_h263_v_loop_filter_rvv(uint8_t *src, int stride, int q); - do { - p[0] = 0; - p[1] = 0; - p[2] = 0; - p[3] = 0; - p[4] = 0; - p[5] = 0; - p[6] = 0; - p[7] = 0; - p += 8; - n -= 8 * 8; - } while (n); -} - -av_cold void ff_blockdsp_init_alpha(BlockDSPContext *c) +av_cold void ff_h263dsp_init_riscv(H263DSPContext *c) { - c->clear_blocks = clear_blocks_axp; +#if HAVE_RVV + int flags = av_get_cpu_flags(); + + if ((flags & AV_CPU_FLAG_RVV_I32) && ff_rv_vlen_least(128)) { + c->h263_h_loop_filter = ff_h263_h_loop_filter_rvv; + c->h263_v_loop_filter = ff_h263_v_loop_filter_rvv; + } +#endif } diff --git a/libavcodec/riscv/h263dsp_rvv.S b/libavcodec/riscv/h263dsp_rvv.S new file mode 100644 index 000000000..e9cb4ec07 --- /dev/null +++ b/libavcodec/riscv/h263dsp_rvv.S @@ -0,0 +1,101 @@ +/* + * 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" + + .option push + .option norelax +func ff_h263_h_loop_filter_rvv, zve32x + lpad 0 + addi a0, a0, -2 + vsetivli zero, 8, e8, mf2, ta, ma + vlsseg4e8.v v8, (a0), a1 + jal t0, 1f + vssseg4e8.v v8, (a0), a1 + ret +1: + auipc t1, %pcrel_hi(ff_h263_loop_filter_strength) + vwsubu.vv v14, v10, v9 # p2 - p1 + add t1, t1, a2 + vwsubu.vv v12, v8, v11 # p0 - p3 + vsetvli zero, zero, e16, m1, ta, mu + vsll.vi v14, v14, 2 + lbu t1, %pcrel_lo(1b)(t1) # strength + vadd.vv v16, v12, v14 + # Divide by 8 toward 0. v16 is a signed 10-bit value at this point. + 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. + vsra.vi v16, v16, 3 # d + vmv.v.x v20, t2 + vmslt.vi v0, v16, 0 + vneg.v v18, v16 + vneg.v v20, v20, v0.t # sign(d) * 2 * strength + vmax.vv v18, v16, v18 # |d| + vsub.vv v20, v20, v16 # d1 if strength <= |d| <= 2 * strength + vmsge.vx v0, v18, t2 + vsrl.vi v14, v12, 16 - 2 # v14 = (v12 < 0) ? 3 : 0 + vmerge.vxm v20, v20, zero, v0 # d1 if strength <= |d| + vadd.vv v12, v12, v14 + vmsge.vx v0, v18, t1 + vsra.vi v12, v12, 2 # (p0 - p3) / 4 + vmerge.vvm v16, v16, v20, v0 # d1 + vzext.vf2 v24, v8 # p0 as u16 (because vwrsubu.wv does not exist) + vneg.v v14, v16 + vzext.vf2 v26, v9 # p1 as u16 + vmax.vv v14, v16, v14 # |d1| + vzext.vf2 v28, v10 # p2 as u16 + vsra.vi v14, v14, 1 # ad1 + vadd.vv v26, v26, v16 # p1 + d1 + vneg.v v18, v14 # -ad1 + vmin.vv v12, v12, v14 + vsub.vv v28, v28, v16 # p2 - d1 + vmax.vv v12, v12, v18 # d2 + vmax.vx v26, v26, zero + vsub.vv v24, v24, v12 # p0 - d2 + vmax.vx v28, v28, zero + vsetvli zero, zero, e8, mf2, ta, ma + vwaddu.wv v30, v12, v11 # p3 + d2 + vncvt.x.x.w v8, v24 + vnclipu.wi v9, v26, 0 + vnclipu.wi v10, v28, 0 + vncvt.x.x.w v11, v30 + jr t0 +endfunc + .option pop + +func ff_h263_v_loop_filter_rvv, zve32x + lpad 0 + sub a4, a0, a1 + vsetivli zero, 8, e8, mf2, ta, ma + vle8.v v10, (a0) + sub a3, a4, a1 + vle8.v v9, (a4) + add a5, a0, a1 + vle8.v v8, (a3) + vle8.v v11, (a5) + jal t0, 1b + vse8.v v8, (a3) + vse8.v v9, (a4) + vse8.v v10, (a0) + vse8.v v11, (a5) + ret +endfunc diff --git a/libavcodec/riscv/h264_chroma_init_riscv.c b/libavcodec/riscv/h264_chroma_init_riscv.c index e6fe5f6ed..b6bde42c0 100644 --- a/libavcodec/riscv/h264_chroma_init_riscv.c +++ b/libavcodec/riscv/h264_chroma_init_riscv.c @@ -38,7 +38,7 @@ av_cold void ff_h264chroma_init_riscv(H264ChromaContext *c, int bit_depth) int flags = av_get_cpu_flags(); if (bit_depth == 8 && (flags & AV_CPU_FLAG_RVV_I32) && - (flags & AV_CPU_FLAG_RVB_ADDR) && ff_get_rv_vlenb() >= 16) { + (flags & AV_CPU_FLAG_RVB) && ff_rv_vlen_least(128)) { c->put_h264_chroma_pixels_tab[0] = h264_put_chroma_mc8_rvv; c->avg_h264_chroma_pixels_tab[0] = h264_avg_chroma_mc8_rvv; c->put_h264_chroma_pixels_tab[1] = h264_put_chroma_mc4_rvv; diff --git a/libavcodec/riscv/h264_mc_chroma.S b/libavcodec/riscv/h264_mc_chroma.S index ce99bda44..79394b987 100644 --- a/libavcodec/riscv/h264_mc_chroma.S +++ b/libavcodec/riscv/h264_mc_chroma.S @@ -325,7 +325,8 @@ ret .endm -func h264_put_chroma_mc_rvv, zve32x + .variant_cc h264_put_chroma_mc_rvv +func h264_put_chroma_mc_rvv, zve32x, zba 11: li a7, 3 blt a3, a7, 12f @@ -334,7 +335,8 @@ func h264_put_chroma_mc_rvv, zve32x do_chroma_mc put 0 endfunc -func h264_avg_chroma_mc_rvv, zve32x + .variant_cc h264_avg_chroma_mc_rvv +func h264_avg_chroma_mc_rvv, zve32x, zba 21: li a7, 3 blt a3, a7, 22f @@ -344,31 +346,37 @@ func h264_avg_chroma_mc_rvv, zve32x endfunc func h264_put_chroma_mc8_rvv, zve32x + lpad 0 li t6, 8 j 11b endfunc func h264_put_chroma_mc4_rvv, zve32x + lpad 0 li t6, 4 j 11b endfunc func h264_put_chroma_mc2_rvv, zve32x + lpad 0 li t6, 2 j 11b endfunc func h264_avg_chroma_mc8_rvv, zve32x + lpad 0 li t6, 8 j 21b endfunc func h264_avg_chroma_mc4_rvv, zve32x + lpad 0 li t6, 4 j 21b endfunc func h264_avg_chroma_mc2_rvv, zve32x + lpad 0 li t6, 2 j 21b endfunc diff --git a/libavcodec/riscv/h264addpx_rvv.S b/libavcodec/riscv/h264addpx_rvv.S new file mode 100644 index 000000000..82739881d --- /dev/null +++ b/libavcodec/riscv/h264addpx_rvv.S @@ -0,0 +1,115 @@ +/* + * Copyright © 2024 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" + + .macro sx rd, addr +#if (__riscv_xlen == 32) + sw \rd, \addr +#elif (__riscv_xlen == 64) + sd \rd, \addr +#else + sq \rd, \addr +#endif + .endm + +func ff_h264_add_pixels4_8_rvv, zve32x + lpad 0 + vsetivli zero, 4, e8, mf4, ta, ma + vlse32.v v8, (a0), a2 + vsetivli zero, 4 * 4, e8, m1, ta, ma + vle16.v v16, (a1) + .equ offset, 0 + .rept 256 / __riscv_xlen + sx zero, offset(a1) + .equ offset, offset + (__riscv_xlen / 8) + .endr + vncvt.x.x.w v24, v16 + vadd.vv v8, v8, v24 + vsetivli zero, 4, e8, mf4, ta, ma + vsse32.v v8, (a0), a2 + ret +endfunc + +func ff_h264_add_pixels4_16_rvv, zve64x + lpad 0 + vsetivli zero, 4, e16, mf2, ta, ma + vlse64.v v8, (a0), a2 + vsetivli zero, 4 * 4, e16, m2, ta, ma + vle32.v v16, (a1) + .equ offset, 0 + .rept 512 / __riscv_xlen + sx zero, offset(a1) + .equ offset, offset + (__riscv_xlen / 8) + .endr + vncvt.x.x.w v24, v16 + vadd.vv v8, v8, v24 + vsetivli zero, 4, e16, mf2, ta, ma + vsse64.v v8, (a0), a2 + ret +endfunc + +func ff_h264_add_pixels8_8_rvv, zve64x + lpad 0 + li t0, 8 * 8 + vsetivli zero, 8, e8, mf2, ta, ma + vlse64.v v8, (a0), a2 + vsetvli zero, t0, e8, m4, ta, ma + vle16.v v16, (a1) + .equ offset, 0 + .rept 1024 / __riscv_xlen + sx zero, offset(a1) + .equ offset, offset + (__riscv_xlen / 8) + .endr + vncvt.x.x.w v24, v16 + vadd.vv v8, v8, v24 + vsetivli zero, 8, e8, mf2, ta, ma + vsse64.v v8, (a0), a2 + ret +endfunc + +func ff_h264_add_pixels8_16_rvv, zve32x + lpad 0 + li t0, 8 + vsetivli zero, 8, e16, m1, ta, ma +1: + vle32.v v16, (a1) + addi t0, t0, -1 + vle16.v v8, (a0) + .equ offset, 0 + .rept 256 / __riscv_xlen + sx zero, offset(a1) + .equ offset, offset + (__riscv_xlen / 8) + .endr + vncvt.x.x.w v24, v16 + addi a1, a1, 8 * 4 + vadd.vv v8, v8, v24 + vse16.v v8, (a0) + add a0, a0, a2 + bnez t0, 1b + + ret +endfunc diff --git a/libavcodec/riscv/h264dsp_init.c b/libavcodec/riscv/h264dsp_init.c new file mode 100644 index 000000000..9ffc9b033 --- /dev/null +++ b/libavcodec/riscv/h264dsp_init.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2024 J. Dekker + * 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 "config.h" + +#include +#include + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/riscv/cpu.h" +#include "libavcodec/h264dsp.h" + +extern const struct { + const h264_weight_func weight; + const h264_biweight_func biweight; +} ff_h264_weight_funcs_8_rvv[]; + +void ff_h264_v_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_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_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, + int alpha, int beta, int8_t *tc0); +void ff_h264_h_loop_filter_chroma_mbaff_8_rvv(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta, + int8_t *tc0); + +#define IDCT_DEPTH(depth) \ +void ff_h264_idct_add_##depth##_rvv(uint8_t *d, int16_t *s, int stride); \ +void ff_h264_idct8_add_##depth##_rvv(uint8_t *d, int16_t *s, int stride); \ +void ff_h264_idct4_dc_add_##depth##_rvv(uint8_t *, int16_t *, int); \ +void ff_h264_idct8_dc_add_##depth##_rvv(uint8_t *, int16_t *, int); \ +void ff_h264_idct_add16_##depth##_rvv(uint8_t *d, const int *soffset, \ + int16_t *s, int stride, \ + const uint8_t nnzc[5 * 8]); \ +void ff_h264_idct_add16intra_##depth##_rvv(uint8_t *d, const int *soffset, \ + int16_t *s, int stride, \ + const uint8_t nnzc[5 * 8]); \ +void ff_h264_idct8_add4_##depth##_rvv(uint8_t *d, const int *soffset, \ + int16_t *s, int stride, \ + const uint8_t nnzc[5 * 8]); \ +void ff_h264_idct4_add8_##depth##_rvv(uint8_t **d, const int *soffset, \ + int16_t *s, int stride, \ + 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]); + +IDCT_DEPTH(8) +IDCT_DEPTH(9) +IDCT_DEPTH(10) +IDCT_DEPTH(12) +IDCT_DEPTH(14) +#undef IDCT_DEPTH + +void ff_h264_add_pixels8_8_rvv(uint8_t *dst, int16_t *block, int stride); +void ff_h264_add_pixels4_8_rvv(uint8_t *dst, int16_t *block, int stride); +void ff_h264_add_pixels8_16_rvv(uint8_t *dst, int16_t *block, int stride); +void ff_h264_add_pixels4_16_rvv(uint8_t *dst, int16_t *block, int stride); + +extern int ff_startcode_find_candidate_rvb(const uint8_t *, int); +extern int ff_startcode_find_candidate_rvv(const uint8_t *, int); + +av_cold void ff_h264dsp_init_riscv(H264DSPContext *dsp, const int bit_depth, + const int chroma_format_idc) +{ +#if HAVE_RV + int flags = av_get_cpu_flags(); + + if (flags & AV_CPU_FLAG_RVB_BASIC) + dsp->startcode_find_candidate = ff_startcode_find_candidate_rvb; +# if HAVE_RVV + 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 (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->h264_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 (flags & AV_CPU_FLAG_RVB) \ + dsp->h264_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 = \ + ff_h264_idct_add16intra_##depth##_rvv; \ + if (__riscv_xlen == 64) { \ + if (chroma_format_idc <= 1) \ + dsp->h264_idct_add8 = \ + ff_h264_idct4_add8_##depth##_rvv; \ + else \ + dsp->h264_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; \ + } + + IDCT_DEPTH(9) + IDCT_DEPTH(10) + IDCT_DEPTH(12) + IDCT_DEPTH(14) + + if (bit_depth > 8 && zvl128b) { + dsp->h264_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->startcode_find_candidate = ff_startcode_find_candidate_rvv; + } +# endif +#endif +} diff --git a/libavcodec/riscv/h264dsp_rvv.S b/libavcodec/riscv/h264dsp_rvv.S new file mode 100644 index 000000000..97c670830 --- /dev/null +++ b/libavcodec/riscv/h264dsp_rvv.S @@ -0,0 +1,393 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright © 2024 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" + +func ff_h264_weight_pixels_simple_8_rvv, zve32x + csrwi vxrm, 0 + sll a5, a5, a3 +1: + vsetvli zero, a6, e16, m2, ta, ma + vle8.v v8, (a0) + addi a2, a2, -1 + vzext.vf2 v24, v8 + vmul.vx v16, v24, a4 + vsadd.vx v16, v16, a5 + vmax.vx v16, v16, zero + vsetvli zero, zero, e8, m1, ta, ma + vnclipu.wx v8, v16, a3 + vse8.v v8, (a0) + add a0, a0, a1 + bnez a2, 1b + + ret +endfunc + + .variant_cc ff_h264_biweight_pixels_simple_8_rvv +func ff_h264_biweight_pixels_simple_8_rvv, zve32x + csrwi vxrm, 2 + addi a7, a7, 1 + ori a7, a7, 1 + sll a7, a7, a4 + addi a4, a4, 1 +1: + vsetvli zero, t6, e16, m2, ta, ma + vle8.v v8, (a0) + addi a3, a3, -1 + vle8.v v12, (a1) + add a1, a1, a2 + vmv.v.x v16, a7 + vsetvli zero, zero, e8, m1, ta, ma + vwmaccsu.vx v16, a5, v8 + vwmaccsu.vx v16, a6, v12 + vsetvli zero, zero, e16, m2, ta, ma + vmax.vx v16, v16, zero + vsetvli zero, zero, e8, m1, ta, ma + vnclipu.wx v8, v16, a4 + vse8.v v8, (a0) + add a0, a0, a2 + bnez a3, 1b + + ret +endfunc + +func ff_h264_weight_pixels_8_rvv, zve32x + 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 + 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 + bnez a2, 1b + + ret +endfunc + + .variant_cc ff_h264_biweight_pixels_8_rvv +func ff_h264_biweight_pixels_8_rvv, zve32x + 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 + 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 + bnez a3, 1b + + ret +endfunc + +.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 + + .global ff_h264_weight_funcs_8_rvv + .hidden ff_h264_weight_funcs_8_rvv +const ff_h264_weight_funcs_8_rvv, relocate=1 + .irp w, 16, 8, 4, 2 +#if __riscv_xlen == 32 + .word ff_h264_weight_pixels\w\()_8_rvv + .word ff_h264_biweight_pixels\w\()_8_rvv +#elif __riscv_xlen == 64 + .dword ff_h264_weight_pixels\w\()_8_rvv + .dword ff_h264_biweight_pixels\w\()_8_rvv +#else + .qword ff_h264_weight_pixels\w\()_8_rvv + .qword ff_h264_biweight_pixels\w\()_8_rvv +#endif + .endr +endconst + +.macro loop_filter type, inners, e8mul, e16mul + .variant_cc ff_h264_loop_filter_\type\()_8_rvv +func ff_h264_loop_filter_\type\()_8_rvv, zve32x + # p2: v8, p1: v9, p0: v10, q0: v11, q1: v12, q2: v13 + # alpha: a2, beta: a3, tc_orig: v6 + csrwi vxrm, 0 +.ifc \type, luma + vaaddu.vv v14, v10, v11 # (p0 + q0 + 1) / 2 +.endif + vwsubu.vv v16, v9, v12 +.ifc \type, luma + vwaddu.vv v18, v8, v14 + vwaddu.vv v20, v13, v14 +.endif + vnsra.wi v24, v16, 2 # (p1 - q1) / 4 +.ifc \type, luma + vnsrl.wi v14, v18, 1 + vnsrl.wi v15, v20, 1 + vneg.v v5, v6 # -tc_orig +.endif + vwsubu.vv v22, v11, v10 # q0 - p0 +.ifc \type, luma + vwsubu.vv v18, v14, v9 + vwsubu.vv v20, v15, v12 +.endif + vwadd.wv v16, v22, v24 + vmsge.vi v7, v6, 0 # tc_orig >= 0 +.ifc \type, luma + vnclip.wi v14, v18, 0 + vnclip.wi v15, v20, 0 +.endif + vnclip.wi v16, v16, 1 # clip8((q0 - p0 + (p1 - q1) / 4 + 1) >> 1) +.ifc \type, luma + vmin.vv v14, v14, v6 + vmin.vv v15, v15, v6 + vmax.vv v14, v14, v5 # clip(p2 + ... - p1, +/-tc_orig) + vmax.vv v15, v15, v5 # clip(q2 + ... - q1, +/-tc_orig) +.endif + vwsubu.vv v20, v10, v11 + vwsubu.vv v24, v9, v10 + vwsubu.vv v26, v10, v9 + vwsubu.vv v28, v12, v11 + vwsubu.vv v30, v11, v12 +.ifc \type, luma + vwsubu.vv v0, v8, v10 + vwsubu.vv v2, v10, v8 + vwsubu.vv v4, v13, v11 + vwsubu.vv v18, v11, v13 +.endif + vsetvli zero, zero, e16, \e16mul, ta, ma + vmax.vv v20, v20, v22 # abs(p0 - q0) + vmax.vv v24, v24, v26 # abs(p1 - p0) + vmax.vv v28, v28, v30 # abs(q1 - q0) +.ifc \type, luma + vmax.vv v22, v0, v2 # abs(p2 - p0) + vmax.vv v26, v4, v18 # abs(q2 - q0) +.endif + vmslt.vx v1, v20, a2 + vmslt.vx v2, v24, a3 + vmand.mm v7, v7, v1 + vmslt.vx v3, v28, a3 + vmand.mm v7, v7, v2 +.ifc \type, luma + vmslt.vx v0, v22, a3 + vmand.mm v7, v7, v3 # whether to update p0 and q0 + vmslt.vx v1, v26, a3 + vmand.mm v0, v0, v7 +.else + vmand.mm v0, v7, v3 # whether to update p0 and q0 +.endif + vsetvli zero, zero, e8, \e8mul, ta, mu +.ifc \type, luma + vadd.vi v6, v6, 1, v0.t # tc++ + vadd.vv v9, v9, v14, v0.t # p1' + vmand.mm v0, v1, v7 + vadd.vi v6, v6, 1, v0.t # tc++ + vadd.vv v12, v12, v15, v0.t # q1' + vmmv.m v0, v7 +.endif + vneg.v v5, v6 # -tc + vmin.vv v16, v16, v6 + vwcvtu.x.x.v v18, v10 + vmax.vv v16, v16, v5 + vwcvtu.x.x.v v20, v11 + vwadd.wv v18, v18, v16 + vwsub.wv v20, v20, v16 + vsetvli zero, zero, e16, \e16mul, ta, ma + vmax.vx v18, v18, zero + vmax.vx v20, v20, zero + vsetvli zero, zero, e8, \e8mul, ta, mu + vnclipu.wi v10, v18, 0, v0.t # p0' + vnclipu.wi v11, v20, 0, v0.t # q0' + jr t0 +endfunc + +func ff_h264_v_loop_filter_\type\()_8_rvv, zve32x + lpad 0 +.ifc \type, luma + vsetivli zero, 4, e32, m1, ta, ma + vle8.v v4, (a4) + li t0, 0x01010101 + vzext.vf4 v6, v4 +.else + vsetivli zero, 4, e16, mf2, ta, ma + vle8.v v4, (a4) + li t0, 0x0101 + vzext.vf2 v6, v4 +.endif + sub t3, a0, a1 + vmul.vx v6, v6, t0 + 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) +.ifc \type, luma + sub t1, t2, a1 +.endif + vle8.v v12, (t5) +.ifc \type, luma + add t6, t5, a1 + vle8.v v8, (t1) + vle8.v v13, (t6) +.endif + jal t0, ff_h264_loop_filter_\type\()_8_rvv +.ifc \type, luma + vse8.v v9, (t2) + vse8.v v12, (t5) +.endif + vse8.v v10, (t3) + vse8.v v11, (a0) + ret +endfunc +.endm + +loop_filter luma, 4, m1, m2 +loop_filter chroma, 2, mf2, m1 + +func ff_h264_h_loop_filter_luma_8_rvv, zve32x + lpad 0 + vsetivli zero, 4, e32, m1, ta, ma + vle8.v v4, (a4) + li t0, 0x01010101 + vzext.vf4 v6, v4 + addi a0, a0, -3 + vmul.vx v6, v6, t0 + vsetivli zero, 16, e8, m1, ta, ma + vlsseg6e8.v v8, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_luma_8_rvv + vssseg4e8.v v9, (a0), a1 + ret +endfunc + +func ff_h264_h_loop_filter_luma_mbaff_8_rvv, zve32x + lpad 0 + vsetivli zero, 4, e16, mf2, ta, ma + vle8.v v4, (a4) + li t0, 0x0101 + vzext.vf2 v6, v4 + addi a0, a0, -3 + vmul.vx v6, v6, t0 # tc_orig + vsetivli zero, 8, e8, m1, ta, ma + vlsseg6e8.v v8, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_luma_8_rvv + vssseg4e8.v v9, (a0), a1 + ret +endfunc + +func ff_h264_h_loop_filter_chroma_8_rvv, zve32x + lpad 0 + vsetivli zero, 4, e16, mf2, ta, ma + vle8.v v4, (a4) + li t0, 0x0101 + vzext.vf2 v6, v4 + addi a0, a0, -2 + vmul.vx v6, v6, t0 + vsetivli zero, 8, e8, mf2, ta, ma + vlsseg4e8.v v9, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_chroma_8_rvv + vssseg2e8.v v10, (a0), a1 + ret +endfunc + +func ff_h264_h_loop_filter_chroma_mbaff_8_rvv, zve32x + lpad 0 + vsetivli zero, 4, e8, mf4, ta, ma + vle8.v v6, (a4) + addi a0, a0, -2 + vsetivli zero, 4, e8, mf2, ta, ma + vlsseg4e8.v v9, (a0), a1 + addi a0, a0, 1 + jal t0, ff_h264_loop_filter_chroma_8_rvv + vssseg2e8.v v10, (a0), a1 + ret +endfunc diff --git a/libavcodec/riscv/h264idct_rvv.S b/libavcodec/riscv/h264idct_rvv.S new file mode 100644 index 000000000..b1e06d93f --- /dev/null +++ b/libavcodec/riscv/h264idct_rvv.S @@ -0,0 +1,805 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 J. Dekker + * Copyright © 2024 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" + + .macro sx rd, addr +#if (__riscv_xlen == 32) + sw \rd, \addr +#elif (__riscv_xlen == 64) + sd \rd, \addr +#else + sq \rd, \addr +#endif + .endm + + .variant_cc ff_h264_idct4_rvv +func ff_h264_idct4_rvv, zve32x + vsra.vi v5, v1, 1 + vsra.vi v7, v3, 1 + vadd.vv v8, v0, v2 # z0 + vsub.vv v9, v0, v2 # z1 + vsub.vv v10, v5, v3 # z2 + vadd.vv v11, v1, v7 # z3 + vadd.vv v1, v9, v10 + vsub.vv v2, v9, v10 + vadd.vv v0, v8, v11 + vsub.vv v3, v8, v11 + jr t0 +endfunc + +func ff_h264_idct_add_8_rvv, zve32x + lpad 0 + csrwi vxrm, 0 +.Lidct4_add_8_rvv: + vsetivli zero, 4, e16, mf2, ta, ma + addi t1, a1, 1 * 4 * 2 + vle16.v v0, (a1) + addi t2, a1, 2 * 4 * 2 + vle16.v v1, (t1) + addi t3, a1, 3 * 4 * 2 + vle16.v v2, (t2) + vle16.v v3, (t3) + jal t0, ff_h264_idct4_rvv + vse16.v v0, (a1) + vse16.v v1, (t1) + vse16.v v2, (t2) + vse16.v v3, (t3) + vlseg4e16.v v0, (a1) + .equ offset, 0 + .rept 256 / __riscv_xlen + sx zero, offset(a1) + .equ offset, offset + (__riscv_xlen / 8) + .endr + jal t0, ff_h264_idct4_rvv + add t1, a0, a2 + vle8.v v4, (a0) + add t2, t1, a2 + vle8.v v5, (t1) + add t3, t2, a2 + vle8.v v6, (t2) + vle8.v v7, (t3) + .irp n,0,1,2,3 + vssra.vi v\n, v\n, 6 + .endr + vsetvli zero, zero, e8, mf4, ta, ma + vwaddu.wv v0, v0, v4 + vwaddu.wv v1, v1, v5 + vwaddu.wv v2, v2, v6 + vwaddu.wv v3, v3, v7 + vsetvli zero, zero, e16, mf2, ta, ma + .irp n,0,1,2,3 + vmax.vx v\n, v\n, zero + .endr + vsetvli zero, zero, e8, mf4, ta, ma + vnclipu.wi v4, v0, 0 + vnclipu.wi v5, v1, 0 + vnclipu.wi v6, v2, 0 + vnclipu.wi v7, v3, 0 + vse8.v v4, (a0) + vse8.v v5, (t1) + vse8.v v6, (t2) + vse8.v v7, (t3) + ret +endfunc + +func ff_h264_idct_add_16_rvv, zve32x + csrwi vxrm, 0 +.Lidct4_add_16_rvv: + vsetivli zero, 4, e32, m1, ta, ma + addi t1, a1, 1 * 4 * 4 + vle32.v v0, (a1) + addi t2, a1, 2 * 4 * 4 + vle32.v v1, (t1) + addi t3, a1, 3 * 4 * 4 + vle32.v v2, (t2) + vle32.v v3, (t3) + jal t0, ff_h264_idct4_rvv + vse32.v v0, (a1) + vse32.v v1, (t1) + vse32.v v2, (t2) + vse32.v v3, (t3) + vlseg4e32.v v0, (a1) + .equ offset, 0 + .rept 512 / __riscv_xlen + sx zero, offset(a1) + .equ offset, offset + (__riscv_xlen / 8) + .endr + jal t0, ff_h264_idct4_rvv + add t1, a0, a2 + vle16.v v4, (a0) + add t2, t1, a2 + vle16.v v5, (t1) + add t3, t2, a2 + vle16.v v6, (t2) + vle16.v v7, (t3) + .irp n,0,1,2,3 + vssra.vi v\n, v\n, 6 + .endr + vsetvli zero, zero, e16, mf2, ta, ma + vwaddu.wv v0, v0, v4 + vwaddu.wv v1, v1, v5 + vwaddu.wv v2, v2, v6 + vwaddu.wv v3, v3, v7 + vsetvli zero, zero, e32, m1, ta, ma + .irp n,0,1,2,3 + vmax.vx v\n, v\n, zero + .endr + .irp n,0,1,2,3 + vmin.vx v\n, v\n, a5 + .endr + vsetvli zero, zero, e16, mf2, ta, ma + vncvt.x.x.w v4, v0 + vncvt.x.x.w v5, v1 + vncvt.x.x.w v6, v2 + vncvt.x.x.w v7, v3 + vse16.v v4, (a0) + vse16.v v5, (t1) + vse16.v v6, (t2) + vse16.v v7, (t3) + ret +endfunc + + .variant_cc ff_h264_idct8_rvv +func ff_h264_idct8_rvv, zve32x + vsra.vi v9, v7, 1 + vsra.vi v11, v3, 1 + vsra.vi v12, v2, 1 + vsra.vi v13, v5, 1 + vsra.vi v14, v6, 1 + vsra.vi v15, v1, 1 + vadd.vv v9, v3, v9 + vsub.vv v11, v1, v11 + vsub.vv v13, v13, v1 + vadd.vv v15, v3, v15 + vsub.vv v9, v5, v9 + vadd.vv v11, v11, v7 + vadd.vv v13, v13, v7 + vadd.vv v15, v15, v5 + vadd.vv v8, v0, v4 # a0 + vsub.vv v9, v9, v7 # a1 + vsub.vv v10, v0, v4 # a2 + vsub.vv v11, v11, v3 # a3 + vsub.vv v12, v12, v6 # a4 + vadd.vv v13, v13, v5 # a5 + vadd.vv v14, v14, v2 # a6 + vadd.vv v15, v15, v1 # a7 + vsra.vi v7, v9, 2 + vsra.vi v5, v11, 2 + vsra.vi v3, v13, 2 + vsra.vi v1, v15, 2 + vadd.vv v0, v8, v14 # b0 + vadd.vv v6, v10, v12 # b2 + vsub.vv v2, v10, v12 # b4 + vsub.vv v4, v8, v14 # b6 + vsub.vv v8, v15, v7 # b7 + vsub.vv v14, v5, v13 # b5 + vadd.vv v12, v1, v9 # b1 + vadd.vv v10, v11, v3 # b3 + vadd.vv v1, v6, v14 + vsub.vv v6, v6, v14 + vsub.vv v7, v0, v8 + vadd.vv v0, v0, v8 + vsub.vv v5, v2, v10 + vadd.vv v2, v2, v10 + vadd.vv v3, v4, v12 + vsub.vv v4, v4, v12 + jr t0 +endfunc + +func ff_h264_idct8_add_8_rvv, zve32x + lpad 0 + csrwi vxrm, 0 +.Lidct8_add_8_rvv: + vsetivli zero, 8, e16, m1, ta, ma + addi t1, a1, 1 * 8 * 2 + vle16.v v0, (a1) + addi t2, a1, 2 * 8 * 2 + vle16.v v1, (t1) + addi t3, a1, 3 * 8 * 2 + vle16.v v2, (t2) + addi t4, a1, 4 * 8 * 2 + vle16.v v3, (t3) + addi t5, a1, 5 * 8 * 2 + vle16.v v4, (t4) + addi t6, a1, 6 * 8 * 2 + vle16.v v5, (t5) + addi a7, a1, 7 * 8 * 2 + vle16.v v6, (t6) + vle16.v v7, (a7) + jal t0, ff_h264_idct8_rvv + vse16.v v0, (a1) + vse16.v v1, (t1) + vse16.v v2, (t2) + vse16.v v3, (t3) + vse16.v v4, (t4) + vse16.v v5, (t5) + vse16.v v6, (t6) + vse16.v v7, (a7) + vlseg8e16.v v0, (a1) + .equ offset, 0 + .rept 1024 / __riscv_xlen + sx zero, offset(a1) + .equ offset, offset + (__riscv_xlen / 8) + .endr + jal t0, ff_h264_idct8_rvv + add t1, a0, a2 + vle8.v v16, (a0) + add t2, t1, a2 + vle8.v v17, (t1) + add t3, t2, a2 + vle8.v v18, (t2) + add t4, t3, a2 + vle8.v v19, (t3) + add t5, t4, a2 + vle8.v v20, (t4) + add t6, t5, a2 + vle8.v v21, (t5) + add a7, t6, a2 + vle8.v v22, (t6) + vle8.v v23, (a7) + .irp n,0,1,2,3,4,5,6,7 + vssra.vi v\n, v\n, 6 + .endr + vsetvli zero, zero, e8, mf2, ta, ma + vwaddu.wv v0, v0, v16 + vwaddu.wv v1, v1, v17 + vwaddu.wv v2, v2, v18 + vwaddu.wv v3, v3, v19 + vwaddu.wv v4, v4, v20 + vwaddu.wv v5, v5, v21 + vwaddu.wv v6, v6, v22 + vwaddu.wv v7, v7, v23 + vsetvli zero, zero, e16, m1, ta, ma + .irp n,0,1,2,3,4,5,6,7 + vmax.vx v\n, v\n, zero + .endr + vsetvli zero, zero, e8, mf2, ta, ma + vnclipu.wi v16, v0, 0 + vnclipu.wi v17, v1, 0 + vnclipu.wi v18, v2, 0 + vnclipu.wi v19, v3, 0 + vnclipu.wi v20, v4, 0 + vnclipu.wi v21, v5, 0 + vnclipu.wi v22, v6, 0 + vnclipu.wi v23, v7, 0 + vse8.v v16, (a0) + vse8.v v17, (t1) + vse8.v v18, (t2) + vse8.v v19, (t3) + vse8.v v20, (t4) + vse8.v v21, (t5) + vse8.v v22, (t6) + vse8.v v23, (a7) + ret +endfunc + +func ff_h264_idct8_add_16_rvv, zve32x, zba + csrwi vxrm, 0 +.Lidct8_add_16_rvv: + li a4, 8 + vsetivli a3, 8, e32, m1, ta, ma +1: + addi t1, a1, 1 * 8 * 4 + vle32.v v0, (a1) + addi t2, a1, 2 * 8 * 4 + vle32.v v1, (t1) + addi t3, a1, 3 * 8 * 4 + vle32.v v2, (t2) + addi t4, a1, 4 * 8 * 4 + vle32.v v3, (t3) + addi t5, a1, 5 * 8 * 4 + vle32.v v4, (t4) + addi t6, a1, 6 * 8 * 4 + vle32.v v5, (t5) + addi a7, a1, 7 * 8 * 4 + vle32.v v6, (t6) + sub a4, a4, a3 + vle32.v v7, (a7) + jal t0, ff_h264_idct8_rvv + vse32.v v0, (a1) + sh2add a1, a3, a1 + vse32.v v1, (t1) + vse32.v v2, (t2) + vse32.v v3, (t3) + vse32.v v4, (t4) + vse32.v v5, (t5) + vse32.v v6, (t6) + vse32.v v7, (a7) + bnez a4, 1b + + addi a1, a1, -8 * 4 + li a4, 8 + slli a6, a3, 3 + 2 +2: + vsetvli zero, zero, e32, m1, ta, ma + vlseg8e32.v v0, (a1) + jal t0, ff_h264_idct8_rvv + add t1, a0, a2 + vle16.v v16, (a0) + add t2, t1, a2 + vle16.v v17, (t1) + add t3, t2, a2 + vle16.v v18, (t2) + add t4, t3, a2 + vle16.v v19, (t3) + add t5, t4, a2 + vle16.v v20, (t4) + add t6, t5, a2 + vle16.v v21, (t5) + add a7, t6, a2 + vle16.v v22, (t6) + sub a4, a4, a3 + vle16.v v23, (a7) + .irp n,0,1,2,3,4,5,6,7 + vssra.vi v\n, v\n, 6 + .endr + vsetvli zero, zero, e16, mf2, ta, ma + vwaddu.wv v0, v0, v16 + add a1, a6, a1 + vwaddu.wv v1, v1, v17 + vwaddu.wv v2, v2, v18 + vwaddu.wv v3, v3, v19 + vwaddu.wv v4, v4, v20 + vwaddu.wv v5, v5, v21 + vwaddu.wv v6, v6, v22 + vwaddu.wv v7, v7, v23 + vsetvli zero, zero, e32, m1, ta, ma + .irp n,0,1,2,3,4,5,6,7 + vmax.vx v\n, v\n, zero + .endr + .irp n,0,1,2,3,4,5,6,7 + vmin.vx v\n, v\n, a5 + .endr + vsetvli zero, zero, e16, mf2, ta, ma + vncvt.x.x.w v16, v0 + vncvt.x.x.w v17, v1 + vncvt.x.x.w v18, v2 + vncvt.x.x.w v19, v3 + vncvt.x.x.w v20, v4 + vncvt.x.x.w v21, v5 + vncvt.x.x.w v22, v6 + vncvt.x.x.w v23, v7 + vse16.v v16, (a0) + sh1add a0, a3, a0 + vse16.v v17, (t1) + vse16.v v18, (t2) + vse16.v v19, (t3) + vse16.v v20, (t4) + vse16.v v21, (t5) + vse16.v v22, (t6) + vse16.v v23, (a7) + bnez a4, 2b + + .equ offset, 0 + .rept 2048 / __riscv_xlen + sx zero, offset - 8 * 8 * 4(a1) + .equ offset, offset + (__riscv_xlen / 8) + .endr + ret +endfunc + +.irp depth, 9, 10, 12, 14 +func ff_h264_idct_add_\depth\()_rvv, zve32x + lpad 0 + li a5, (1 << \depth) - 1 + j ff_h264_idct_add_16_rvv +endfunc + +func ff_h264_idct8_add_\depth\()_rvv, zve32x + lpad 0 + li a5, (1 << \depth) - 1 + j ff_h264_idct8_add_16_rvv +endfunc +.endr + +.macro idct_dc_add8 width +func ff_h264_idct\width\()_dc_add_8_rvv, zve64x, b + lpad 0 +.if \width == 8 + vsetivli zero, \width, e8, mf2, ta, ma +.else + vsetivli zero, \width, e8, mf4, ta, ma +.endif + lh t0, 0(a1) + li t1, 255 + addi t0, t0, 32 + srai t0, t0, 6 + sh zero, 0(a1) +.if \width == 8 + li a6, \width * \width + vlse64.v v24, (a0), a2 + vsetvli zero, a6, e8, m4, ta, ma +.else + vlse32.v v24, (a0), a2 + vsetivli zero, \width * \width, e8, m1, ta, ma +.endif + bgez t0, 1f + + neg t0, t0 + minu t0, t0, t1 + vssubu.vx v24, v24, t0 + .if \width == 8 + vsetivli zero, \width, e8, mf2, ta, ma + vsse64.v v24, (a0), a2 +.else + vsetivli zero, \width, e8, mf4, ta, ma + vsse32.v v24, (a0), a2 +.endif + ret +1: + minu t0, t0, t1 + vsaddu.vx v24, v24, t0 +.if \width == 8 + vsetivli zero, \width, e8, mf2, ta, ma + vsse64.v v24, (a0), a2 +.else + vsetivli zero, \width, e8, mf4, ta, ma + vsse32.v v24, (a0), a2 +.endif + ret +endfunc +.endm + +idct_dc_add8 4 +idct_dc_add8 8 + +.macro idct_dc_add width +func ff_h264_idct\width\()_dc_add_16_rvv, zve64x, zba +.if \width == 8 + vsetivli zero, \width, e16, m1, ta, ma +.else + vsetivli zero, \width, e16, mf2, ta, ma +.endif + lw t0, 0(a1) + addi t0, t0, 32 + srai t0, t0, 6 + sw zero, 0(a1) + add t1, a0, a2 + sh1add t2, a2, a0 + sh1add t3, a2, t1 +.if \width == 8 + sh2add t4, a2, a0 + sh2add t5, a2, t1 + sh2add t6, a2, t2 + sh2add a7, a2, t3 +.endif + vle16.v v0, (a0) + vle16.v v1, (t1) + vle16.v v2, (t2) + vle16.v v3, (t3) +.if \width == 8 + vle16.v v4, (t4) + vle16.v v5, (t5) + vle16.v v6, (t6) + vle16.v v7, (a7) + vsetvli a6, zero, e16, m8, ta, ma +.else + vsetvli a6, zero, e16, m4, ta, ma +.endif + vadd.vx v0, v0, t0 + vmax.vx v0, v0, zero + vmin.vx v0, v0, a5 +.if \width == 8 + vsetivli zero, \width, e16, m1, ta, ma +.else + vsetivli zero, \width, e16, mf2, ta, ma +.endif + vse16.v v0, (a0) + vse16.v v1, (t1) + vse16.v v2, (t2) + vse16.v v3, (t3) +.if \width == 8 + vse16.v v4, (t4) + vse16.v v5, (t5) + vse16.v v6, (t6) + vse16.v v7, (a7) +.endif + ret +endfunc +.endm + +idct_dc_add 4 +idct_dc_add 8 + +.irp depth,9,10,12,14 +func ff_h264_idct4_dc_add_\depth\()_rvv, zve64x + lpad 0 + li a5, (1 << \depth) - 1 + j ff_h264_idct4_dc_add_16_rvv +endfunc + +func ff_h264_idct8_dc_add_\depth\()_rvv, zve64x + lpad 0 + li a5, (1 << \depth) - 1 + j ff_h264_idct8_dc_add_16_rvv +endfunc +.endr + +const ff_h264_scan8 + .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 + .byte 0104, 0105, 0114, 0115, 0106, 0107, 0116, 0117 + .byte 0134, 0135, 0144, 0145, 0136, 0137, 0146, 0147 + .byte 0154, 0155, 0164, 0165, 0156, 0157, 0166, 0167 +endconst + +.macro idct4_add16 type, depth +func ff_h264_idct_add\type\()_\depth\()_rvv, zve32x, b +.if \depth == 8 + lpad 0 +.endif + csrwi vxrm, 0 + lla t0, ff_h264_scan8 + vsetivli zero, 16, e8, m1, ta, ma +.ifc \type, 16intra +.Lidct4_add4_\depth\()_rvv: +.endif + li t1, 32 * (\depth / 8) + vle8.v v8, (t0) +.if \depth == 8 + vlse16.v v16, (a2), t1 +.else + vlse32.v v16, (a2), t1 +.endif + vluxei8.v v12, (a4), v8 +.if \depth == 8 + vsetvli zero, zero, e16, m2, ta, ma +.else + vsetvli zero, zero, e32, m4, ta, ma +.endif + vmsne.vi v1, v16, 0 + vsetvli zero, zero, e8, m1, ta, ma +.ifc \type, 16 + vmseq.vi v2, v12, 1 +.endif + vmsne.vi v0, v12, 0 +.ifc \type, 16 + vmand.mm v1, v1, v2 +.endif + vsetvli zero, zero, e16, m2, ta, ma + vmv.x.s a4, v0 + vmv.x.s a7, v1 + zext.h a4, a4 + slli a7, a7, 16 + mv t4, a0 + or a4, a4, a7 + mv t5, a1 + mv a1, a2 + mv a2, a3 + csrr a3, vl + mv a7, ra +1: + andi t0, a4, 1 + addi a3, a3, -1 +.ifc \type, 16 + beqz t0, 3f # if (nnz) +.endif + lw t2, (t5) # block_offset[i] + bexti t1, a4, 16 + add a0, t4, t2 +.ifc \type, 16 + bnez t1, 2f # if (nnz == 1 && block[i * 16]) +.else + beqz t0, 2f # if (nnzc[scan8[i]]) +.endif + jal .Lidct4_add_\depth\()_rvv + j 3f +2: +.ifnc \type, 16 + beqz t1, 3f # if (block[i * 16]) +.endif + jal ff_h264_idct4_dc_add_\depth\()_rvv +3: + srli a4, a4, 1 + addi t5, t5, 4 + addi a1, a1, 16 * 2 * (\depth / 8) + bnez a3, 1b + + mv ra, a7 + ret +endfunc +.endm + +.macro idct4_add8 type, depth +func ff_h264_idct4_add\type\()_\depth\()_rvv, zve32x +.if \depth == 8 + lpad 0 +.endif + csrwi vxrm, 0 + addi sp, sp, -32 + addi a2, a2, 16 * 16 * 2 * (\depth / 8) # &block[16 * 16] + lla t0, ff_h264_scan8 + 16 + sd s0, 0(sp) + sd ra, 8(sp) + mv s0, sp + sd a0, 16(sp) + sd a4, 24(sp) + ld a0, 0(a0) # dest[0] + addi a1, a1, 16 * 4 # &block_offset[16] + vsetivli zero, 4, e8, m1, ta, ma + jal .Lidct4_add4_\depth\()_rvv + + ld a4, 24(sp) # nnzc + ld a0, 16(sp) + mv a3, a2 # stride + addi a2, a1, (16 - 4) * 16 * 2 * (\depth / 8) # &block[32 * 16] + addi a1, t5, (16 - 4) * 4 # &block_offset[32] + ld a0, 8(a0) # dest[1] + lla t0, ff_h264_scan8 + 32 +.ifc \type, 8_422 + vsetivli zero, 4, e8, m1, ta, ma + jal .Lidct4_add4_\depth\()_rvv + + ld a4, 24(sp) # nnzc + ld a0, 16(sp) + mv a3, a2 # stride + addi a2, a1, (-12- 4) * 16 * 2 * (\depth / 8) # &block[20 * 16] + addi a1, t5, (-8 - 4) * 4 # &block_offset[24] + ld a0, 0(a0) # dest[0] + lla t0, ff_h264_scan8 + 24 + vsetivli zero, 4, e8, m1, ta, ma + jal .Lidct4_add4_\depth\()_rvv + + ld a4, 24(sp) # nnzc + ld a0, 16(sp) + mv a3, a2 # stride + addi a2, a1, (16 - 4) * 16 * 2 * (\depth / 8) # &block[36 * 16] + addi a1, t5, (16 - 4) * 4 # &block_offset[40] + ld a0, 8(a0) # dest[1] + lla t0, ff_h264_scan8 + 40 +.endif + ld ra, 8(sp) + ld s0, 0(sp) + addi sp, sp, 32 + vsetivli zero, 4, e8, m1, ta, ma + j .Lidct4_add4_\depth\()_rvv +endfunc +.endm + +.irp depth, 8, 16 +idct4_add16 16, \depth +idct4_add16 16intra, \depth +idct4_add8 8, \depth +idct4_add8 8_422, \depth + +#if (__riscv_xlen == 64) +func ff_h264_idct8_add4_\depth\()_rvv, zve32x, b +.if \depth == 8 + lpad 0 +.endif + csrwi vxrm, 0 + addi sp, sp, -48 + lla t0, ff_h264_scan8 + sd s0, (sp) + li t1, 4 * 32 * (\depth / 8) + mv s0, sp + li t2, 4 + sd ra, 8(sp) + sd s1, 16(sp) + sd s2, 24(sp) + sd s4, 32(sp) + sd s5, 40(sp) + vsetivli zero, 4, e8, mf4, ta, ma + vlse8.v v8, (t0), t2 +.if \depth == 8 + vlse16.v v16, (a2), t1 +.else + vlse32.v v16, (a2), t1 +.endif + vluxei8.v v12, (a4), v8 +.if \depth == 8 + vsetvli zero, zero, e16, mf2, ta, ma +.else + vsetvli zero, zero, e32, m1, ta, ma +.endif + vmsne.vi v1, v16, 0 + vsetvli zero, zero, e8, mf4, ta, ma + vmseq.vi v2, v12, 1 + vmsne.vi v0, v12, 0 + vmand.mm v1, v1, v2 + vmv.x.s s2, v0 + vmv.x.s a7, v1 + zext.h s2, s2 + slli a7, a7, 16 + li s1, 4 + or s2, s2, a7 + mv s4, a0 + mv s5, a1 + mv a1, a2 + mv a2, a3 +1: + andi t0, s2, 1 + addi s1, s1, -1 + beqz t0, 3f # if (nnz) + lw t2, (s5) # block_offset[i] + bexti t1, s2, 16 + add a0, s4, t2 + bnez t1, 2f # if (nnz == 1 && block[i * 16]) + jal .Lidct8_add_\depth\()_rvv +.if \depth == 8 + j 3f +.else + j 4f # idct8_add_16 updates a1 +.endif +2: + jal ff_h264_idct8_dc_add_\depth\()_rvv +3: + addi a1, a1, 4 * 16 * 2 * (\depth / 8) +4: + srli s2, s2, 1 + addi s5, s5, 4 * 4 + bnez s1, 1b + + ld s5, 40(sp) + ld s4, 32(sp) + ld s2, 24(sp) + ld s1, 16(sp) + ld ra, 8(sp) + ld s0, 0(sp) + addi sp, sp, 48 + ret +endfunc +#endif +.endr + +.irp depth, 9, 10, 12, 14 +func ff_h264_idct_add16_\depth\()_rvv, zve32x + lpad 0 + li a5, (1 << \depth) - 1 + j ff_h264_idct_add16_16_rvv +endfunc + +func ff_h264_idct_add16intra_\depth\()_rvv, zve32x + lpad 0 + li a5, (1 << \depth) - 1 + j ff_h264_idct_add16intra_16_rvv +endfunc + +#if (__riscv_xlen == 64) +func ff_h264_idct8_add4_\depth\()_rvv, zve32x + lpad 0 + li a5, (1 << \depth) - 1 + j ff_h264_idct8_add4_16_rvv +endfunc + +func ff_h264_idct4_add8_\depth\()_rvv, zve32x + lpad 0 + li a5, (1 << \depth) - 1 + j ff_h264_idct4_add8_16_rvv +endfunc + +func ff_h264_idct4_add8_422_\depth\()_rvv, zve32x + lpad 0 + li a5, (1 << \depth) - 1 + j ff_h264_idct4_add8_422_16_rvv +endfunc +#endif +.endr diff --git a/libavcodec/riscv/huffyuvdsp_init.c b/libavcodec/riscv/huffyuvdsp_init.c index b49b3dc09..362ccb215 100644 --- a/libavcodec/riscv/huffyuvdsp_init.c +++ b/libavcodec/riscv/huffyuvdsp_init.c @@ -33,7 +33,7 @@ av_cold void ff_huffyuvdsp_init_riscv(HuffYUVDSPContext *c, #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { c->add_int16 = ff_add_int16_rvv; c->add_hfyu_left_pred_bgr32 = ff_add_hfyu_left_pred_bgr32_rvv; } diff --git a/libavcodec/riscv/huffyuvdsp_rvv.S b/libavcodec/riscv/huffyuvdsp_rvv.S index 9c4434907..02b022470 100644 --- a/libavcodec/riscv/huffyuvdsp_rvv.S +++ b/libavcodec/riscv/huffyuvdsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_add_int16_rvv, zve32x +func ff_add_int16_rvv, zve32x, zba + lpad 0 1: vsetvli t0, a3, e16, m8, ta, ma vle16.v v16, (a0) @@ -36,8 +37,11 @@ func ff_add_int16_rvv, zve32x ret endfunc -func ff_add_hfyu_left_pred_bgr32_rvv, zve32x - vsetivli zero, 4, e8, m1, ta, ma +func ff_add_hfyu_left_pred_bgr32_rvv, zve32x, b + lpad 0 + vtype_ivli t1, 4, e8, ta, ma + li t0, 4 + vsetvl zero, t0, t1 vle8.v v8, (a3) sh2add a2, a2, a1 1: diff --git a/libavcodec/riscv/idctdsp_init.c b/libavcodec/riscv/idctdsp_init.c index 4106d90c5..0decc1595 100644 --- a/libavcodec/riscv/idctdsp_init.c +++ b/libavcodec/riscv/idctdsp_init.c @@ -39,7 +39,7 @@ av_cold void ff_idctdsp_init_riscv(IDCTDSPContext *c, AVCodecContext *avctx, #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I64) && ff_get_rv_vlenb() >= 16) { + if ((flags & AV_CPU_FLAG_RVV_I64) && ff_rv_vlen_least(128)) { c->put_pixels_clamped = ff_put_pixels_clamped_rvv; c->put_signed_pixels_clamped = ff_put_signed_pixels_clamped_rvv; c->add_pixels_clamped = ff_add_pixels_clamped_rvv; diff --git a/libavcodec/riscv/idctdsp_rvv.S b/libavcodec/riscv/idctdsp_rvv.S index e93e6b5e7..de229a9ae 100644 --- a/libavcodec/riscv/idctdsp_rvv.S +++ b/libavcodec/riscv/idctdsp_rvv.S @@ -21,6 +21,7 @@ #include "libavutil/riscv/asm.S" func ff_put_pixels_clamped_rvv, zve64x + lpad 0 li t0, 8 * 8 vsetvli zero, t0, e16, m8, ta, ma vle16.v v24, (a0) @@ -35,6 +36,7 @@ func ff_put_pixels_clamped_rvv, zve64x endfunc func ff_put_signed_pixels_clamped_rvv, zve64x + lpad 0 li t0, 8 * 8 vsetvli zero, t0, e8, m4, ta, ma vle16.v v24, (a0) @@ -47,6 +49,7 @@ func ff_put_signed_pixels_clamped_rvv, zve64x endfunc func ff_add_pixels_clamped_rvv, zve64x + lpad 0 vsetivli zero, 8, e8, mf2, ta, ma li t0, 8 * 8 vlse64.v v16, (a1), a2 diff --git a/libavcodec/riscv/jpeg2000dsp_init.c b/libavcodec/riscv/jpeg2000dsp_init.c index e82ec47bd..d6930721c 100644 --- a/libavcodec/riscv/jpeg2000dsp_init.c +++ b/libavcodec/riscv/jpeg2000dsp_init.c @@ -31,7 +31,7 @@ av_cold void ff_jpeg2000dsp_init_riscv(Jpeg2000DSPContext *c) #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { if (flags & AV_CPU_FLAG_RVV_F32) c->mct_decode[FF_DWT97] = ff_ict_float_rvv; c->mct_decode[FF_DWT53] = ff_rct_int_rvv; diff --git a/libavcodec/riscv/jpeg2000dsp_rvv.S b/libavcodec/riscv/jpeg2000dsp_rvv.S index 10efe6b0d..5079df69c 100644 --- a/libavcodec/riscv/jpeg2000dsp_rvv.S +++ b/libavcodec/riscv/jpeg2000dsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_ict_float_rvv, zve32f +func ff_ict_float_rvv, zve32f, zba + lpad 0 lla t0, ff_jpeg2000_f_ict_params flw ft0, 0(t0) flw ft1, 4(t0) @@ -48,7 +49,8 @@ func ff_ict_float_rvv, zve32f ret endfunc -func ff_rct_int_rvv, zve32x +func ff_rct_int_rvv, zve32x, zba + lpad 0 1: vsetvli t0, a3, e32, m8, ta, ma vle32.v v16, (a1) diff --git a/libavcodec/riscv/llauddsp_init.c b/libavcodec/riscv/llauddsp_init.c index 1924b3682..e2c1edb40 100644 --- a/libavcodec/riscv/llauddsp_init.c +++ b/libavcodec/riscv/llauddsp_init.c @@ -36,7 +36,7 @@ av_cold void ff_llauddsp_init_riscv(LLAudDSPContext *c) #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_rvv; c->scalarproduct_and_madd_int32 = ff_scalarproduct_and_madd_int32_rvv; } diff --git a/libavcodec/riscv/llauddsp_rvv.S b/libavcodec/riscv/llauddsp_rvv.S index 556986483..594e553b5 100644 --- a/libavcodec/riscv/llauddsp_rvv.S +++ b/libavcodec/riscv/llauddsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_scalarproduct_and_madd_int16_rvv, zve32x +func ff_scalarproduct_and_madd_int16_rvv, zve32x, zba + lpad 0 vsetvli t0, zero, e32, m8, ta, ma vmv.v.x v0, zero 1: @@ -44,7 +45,8 @@ func ff_scalarproduct_and_madd_int16_rvv, zve32x ret endfunc -func ff_scalarproduct_and_madd_int32_rvv, zve32x +func ff_scalarproduct_and_madd_int32_rvv, zve32x, zba + lpad 0 vsetvli t0, zero, e32, m8, ta, ma vmv.v.x v0, zero 1: diff --git a/libavcodec/riscv/llviddsp_rvv.S b/libavcodec/riscv/llviddsp_rvv.S index a4814837b..9572e92dc 100644 --- a/libavcodec/riscv/llviddsp_rvv.S +++ b/libavcodec/riscv/llviddsp_rvv.S @@ -21,6 +21,7 @@ #include "libavutil/riscv/asm.S" func ff_llvid_add_bytes_rvv, zve32x + lpad 0 1: vsetvli t0, a2, e8, m8, ta, ma vle8.v v0, (a1) diff --git a/libavcodec/riscv/llvidencdsp_rvv.S b/libavcodec/riscv/llvidencdsp_rvv.S index 034216512..44bf3ac7e 100644 --- a/libavcodec/riscv/llvidencdsp_rvv.S +++ b/libavcodec/riscv/llvidencdsp_rvv.S @@ -21,6 +21,7 @@ #include "libavutil/riscv/asm.S" func ff_llvidenc_diff_bytes_rvv, zve32x + lpad 0 1: vsetvli t0, a3, e8, m8, ta, ma vle8.v v0, (a1) diff --git a/libavcodec/riscv/lpc_init.c b/libavcodec/riscv/lpc_init.c index 08efae4da..b09327107 100644 --- a/libavcodec/riscv/lpc_init.c +++ b/libavcodec/riscv/lpc_init.c @@ -33,7 +33,7 @@ av_cold void ff_lpc_init_riscv(LPCContext *c) #if HAVE_RVV && (__riscv_xlen >= 64) int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_F64) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_F64) && (flags & AV_CPU_FLAG_RVB)) { c->lpc_apply_welch_window = ff_lpc_apply_welch_window_rvv; if (ff_get_rv_vlenb() > c->max_order) diff --git a/libavcodec/riscv/lpc_rvv.S b/libavcodec/riscv/lpc_rvv.S index 3fdf80ebe..cc6d6ddd2 100644 --- a/libavcodec/riscv/lpc_rvv.S +++ b/libavcodec/riscv/lpc_rvv.S @@ -21,7 +21,8 @@ #include "libavutil/riscv/asm.S" #if __riscv_xlen >= 64 -func ff_lpc_apply_welch_window_rvv, zve64d +func ff_lpc_apply_welch_window_rvv, zve64d, zba + lpad 0 vsetvli t0, zero, e64, m8, ta, ma vid.v v0 addi t2, a1, -1 @@ -86,10 +87,12 @@ func ff_lpc_apply_welch_window_rvv, zve64d ret endfunc -func ff_lpc_compute_autocorr_rvv, zve64d +func ff_lpc_compute_autocorr_rvv, zve64d, b + lpad 0 + vtype_vli t1, a2, t2, e64, ta, ma, 1 addi a2, a2, 1 li t0, 1 - vsetvli zero, a2, e64, m8, ta, ma + vsetvl zero, a2, t1 fcvt.d.l ft0, t0 vle64.v v0, (a0) sh3add a0, a2, a0 # data += lag diff --git a/libavcodec/riscv/me_cmp_init.c b/libavcodec/riscv/me_cmp_init.c index 858e2ccdb..f246e55cb 100644 --- a/libavcodec/riscv/me_cmp_init.c +++ b/libavcodec/riscv/me_cmp_init.c @@ -82,7 +82,7 @@ av_cold void ff_me_cmp_init_riscv(MECmpContext *c, AVCodecContext *avctx) #if HAVE_RVV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVV_I32 && ff_get_rv_vlenb() >= 16) { + if (flags & AV_CPU_FLAG_RVV_I32 && ff_rv_vlen_least(128)) { c->pix_abs[0][0] = ff_pix_abs16_rvv; c->sad[0] = ff_pix_abs16_rvv; c->pix_abs[1][0] = ff_pix_abs8_rvv; diff --git a/libavcodec/riscv/me_cmp_rvv.S b/libavcodec/riscv/me_cmp_rvv.S index c9ae5bb6f..8989c91dd 100644 --- a/libavcodec/riscv/me_cmp_rvv.S +++ b/libavcodec/riscv/me_cmp_rvv.S @@ -27,6 +27,7 @@ .endm func ff_pix_abs16_rvv, zve32x + lpad 0 vsetivli zero, 1, e32, m1, ta, ma vmv.s.x v0, zero 1: @@ -47,6 +48,7 @@ func ff_pix_abs16_rvv, zve32x endfunc func ff_pix_abs8_rvv, zve32x + lpad 0 vsetivli zero, 1, e32, m1, ta, ma vmv.s.x v0, zero 1: @@ -67,6 +69,7 @@ func ff_pix_abs8_rvv, zve32x endfunc func ff_pix_abs16_x2_rvv, zve32x + lpad 0 csrwi vxrm, 0 vsetivli zero, 1, e32, m1, ta, ma li t5, 1 @@ -92,6 +95,7 @@ func ff_pix_abs16_x2_rvv, zve32x endfunc func ff_pix_abs8_x2_rvv, zve32x + lpad 0 csrwi vxrm, 0 vsetivli zero, 1, e32, m1, ta, ma li t5, 1 @@ -117,6 +121,7 @@ func ff_pix_abs8_x2_rvv, zve32x endfunc func ff_pix_abs16_y2_rvv, zve32x + lpad 0 csrwi vxrm, 0 vsetivli zero, 1, e32, m1, ta, ma add t1, a2, a3 @@ -142,6 +147,7 @@ func ff_pix_abs16_y2_rvv, zve32x endfunc func ff_pix_abs8_y2_rvv, zve32x + lpad 0 csrwi vxrm, 0 vsetivli zero, 1, e32, m1, ta, ma add t1, a2, a3 @@ -167,6 +173,7 @@ func ff_pix_abs8_y2_rvv, zve32x endfunc func ff_sse16_rvv, zve32x + lpad 0 vsetivli t0, 16, e32, m4, ta, ma vmv.v.x v24, zero vmv.s.x v0, zero @@ -189,6 +196,7 @@ func ff_sse16_rvv, zve32x endfunc func ff_sse8_rvv, zve32x + lpad 0 vsetivli t0, 8, e32, m2, ta, ma vmv.v.x v24, zero vmv.s.x v0, zero @@ -211,6 +219,7 @@ func ff_sse8_rvv, zve32x endfunc func ff_sse4_rvv, zve32x + lpad 0 vsetivli t0, 4, e32, m1, ta, ma vmv.v.x v24, zero vmv.s.x v0, zero @@ -239,6 +248,7 @@ endfunc .endm .macro vsad_vsse16 type + lpad 0 vsetivli t0, 16, e32, m4, ta, ma addi a4, a4, -1 add t1, a1, a3 @@ -277,6 +287,7 @@ endfunc .endm .macro vsad_vsse8 type + lpad 0 vsetivli t0, 8, e32, m2, ta, ma addi a4, a4, -1 add t1, a1, a3 @@ -315,6 +326,7 @@ endfunc .endm .macro vsad_vsse_intra16 type + lpad 0 vsetivli t0, 16, e32, m4, ta, ma addi a4, a4, -1 add t1, a1, a3 @@ -346,6 +358,7 @@ endfunc .endm .macro vsad_vsse_intra8 type + lpad 0 vsetivli t0, 8, e32, m2, ta, ma addi a4, a4, -1 add t1, a1, a3 @@ -409,6 +422,8 @@ func ff_vsad_intra8_rvv, zve32x endfunc func ff_nsse16_rvv, zve32x + lpad 0 + .macro squarediff16 vsetivli zero, 16, e8, m1, tu, ma vle8.v v4, (a1) @@ -468,6 +483,8 @@ func ff_nsse16_rvv, zve32x endfunc func ff_nsse8_rvv, zve32x + lpad 0 + .macro squarediff8 vsetivli zero, 8, e8, mf2, tu, ma vle8.v v4, (a1) diff --git a/libavcodec/riscv/mpegvideoencdsp_init.c b/libavcodec/riscv/mpegvideoencdsp_init.c new file mode 100644 index 000000000..3ae38cf92 --- /dev/null +++ b/libavcodec/riscv/mpegvideoencdsp_init.c @@ -0,0 +1,51 @@ +/* + * 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 + +#include "libavutil/cpu.h" +#include "libavcodec/mpegvideoencdsp.h" + +int ff_try_8x8basis_rvv(const int16_t rem[64], const int16_t weight[64], + const int16_t basis[16], int scale); +void ff_add_8x8basis_rvv(int16_t rem[64], const int16_t basis[16], int scale); +int ff_pix_sum_rvv(const uint8_t *pix, ptrdiff_t line_size); +int ff_pix_norm1_rvv(const uint8_t *pix, ptrdiff_t line_size); + +av_cold void ff_mpegvideoencdsp_init_riscv(MpegvideoEncDSPContext *c, + AVCodecContext *avctx) +{ +#if HAVE_RVV + int flags = av_get_cpu_flags(); + + if (flags & AV_CPU_FLAG_RVV_I32) { + if (flags & AV_CPU_FLAG_RVB) { + c->try_8x8basis = ff_try_8x8basis_rvv; + c->add_8x8basis = ff_add_8x8basis_rvv; + } + + if (flags & AV_CPU_FLAG_RVV_I64) { + if ((flags & AV_CPU_FLAG_RVB) && ff_rv_vlen_least(128)) + c->pix_sum = ff_pix_sum_rvv; + c->pix_norm1 = ff_pix_norm1_rvv; + } + } +#endif +} diff --git a/libavcodec/riscv/mpegvideoencdsp_rvv.S b/libavcodec/riscv/mpegvideoencdsp_rvv.S new file mode 100644 index 000000000..7c5052693 --- /dev/null +++ b/libavcodec/riscv/mpegvideoencdsp_rvv.S @@ -0,0 +1,127 @@ +/* + * 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" + +.equ BASIS_SHIFT, 16 +.equ RECON_SHIFT, 6 + +func ff_try_8x8basis_rvv, zve32x, b + li t1, 64 + csrwi vxrm, 0 + vsetvli t0, t1, e32, m8, ta, ma + vmv.v.x v24, zero + vmv.s.x v1, zero +1: + vsetvli zero, zero, e16, m4, ta, ma + vle16.v v4, (a2) + sub t1, t1, t0 + vwmul.vx v16, v4, a3 + sh1add a2, t0, a2 + vle16.v v8, (a0) + sh1add a0, t0, a0 + vnclip.wi v4, v16, BASIS_SHIFT - RECON_SHIFT + vle16.v v12, (a1) + sh1add a1, t0, a1 + vadd.vv v4, v8, v4 + vsra.vi v4, v4, RECON_SHIFT + vwmul.vv v16, v12, v4 + vsetvli zero, zero, e32, m8, ta, ma + vmul.vv v16, v16, v16 + vsra.vi v16, v16, 4 + vadd.vv v24, v24, v16 + bnez t1, 1b + + vredsum.vs v1, v24, v1 + vmv.x.s a0, v1 + srai a0, a0, 2 + ret +endfunc + +func ff_add_8x8basis_rvv, zve32x, b + li t1, 64 + csrwi vxrm, 0 +1: + vsetvli t0, t1, e16, m4, ta, ma + vle16.v v4, (a1) + sub t1, t1, t0 + vwmul.vx v16, v4, a2 + sh1add a1, t0, a1 + vle16.v v8, (a0) + vnclip.wi v4, v16, BASIS_SHIFT - RECON_SHIFT + vadd.vv v4, v8, v4 + vse16.v v4, (a0) + sh1add a0, t0, a0 + bnez t1, 1b + + ret +endfunc + +func ff_pix_sum_rvv, zve64x, b + lpad 0 + vsetivli t0, 16, e16, m1, ta, ma + slli t1, t0, 3 + vlsseg2e64.v v8, (a0), a1 # poor man's vlse128.v + li t2, 16 + vmv.s.x v1, zero + vsetvli zero, t1, e8, m4, ta, ma + vwaddu.vv v16, v8, v12 + beq t0, t2, 2f # VLEN >= 256 +1: + sh3add a0, a1, a0 + vsetivli zero, 8, e16, m1, ta, ma + vlsseg2e64.v v8, (a0), a1 + vsetvli zero, t1, e8, m4, ta, ma + vwaddu.wv v16, v16, v8 + vwaddu.wv v16, v16, v12 +2: + vsetvli zero, zero, e16, m8, ta, ma + vredsum.vs v1, v16, v1 + vmv.x.s a0, v1 + zext.h a0, a0 + ret +endfunc + +func ff_pix_norm1_rvv, zve64x + lpad 0 + li t1, 16 + vsetvli t0, zero, e32, m8, ta, ma + vmv.v.x v16, zero + vmv.s.x v1, zero +1: + vsetvli t0, t1, e64, m2, ta, ma + vlsseg2e64.v v8, (a0), a1 + slli t2, t0, 3 + vsetvli zero, t2, e8, m2, ta, ma + vwmulu.vv v24, v8, v8 + sub t1, t1, t0 + vwmulu.vv v28, v10, v10 + mul t3, a1, t0 + vsetvli zero, zero, e16, m4, tu, ma + vwaddu.wv v16, v16, v24 + add a0, t3, a0 + vwaddu.wv v16, v16, v28 + bnez t1, 1b + + vsetvli zero, zero, e32, m8, ta, ma + vredsum.vs v1, v16, v1 + vmv.x.s a0, v1 + ret +endfunc diff --git a/libavcodec/riscv/opusdsp_init.c b/libavcodec/riscv/opusdsp_init.c index 88d8e77f0..6fc5e3743 100644 --- a/libavcodec/riscv/opusdsp_init.c +++ b/libavcodec/riscv/opusdsp_init.c @@ -23,7 +23,7 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" #include "libavutil/riscv/cpu.h" -#include "libavcodec/opusdsp.h" +#include "libavcodec/opus/dsp.h" void ff_opus_postfilter_rvv(float *data, int period, float *g, int len); @@ -32,8 +32,7 @@ av_cold void ff_opus_dsp_init_riscv(OpusDSP *d) #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_F32) && (flags & AV_CPU_FLAG_RVB_ADDR) && - (flags & AV_CPU_FLAG_RVB_BASIC)) + if ((flags & AV_CPU_FLAG_RVV_F32) && (flags & AV_CPU_FLAG_RVB)) d->postfilter = ff_opus_postfilter_rvv; #endif } diff --git a/libavcodec/riscv/opusdsp_rvv.S b/libavcodec/riscv/opusdsp_rvv.S index 9a8914c78..f9a1d9d63 100644 --- a/libavcodec/riscv/opusdsp_rvv.S +++ b/libavcodec/riscv/opusdsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_opus_postfilter_rvv, zve32f +func ff_opus_postfilter_rvv, zve32f, b + lpad 0 flw fa0, 0(a2) // g0 slli t1, a1, 2 flw fa1, 4(a2) // g1 diff --git a/libavcodec/riscv/pixblockdsp_init.c b/libavcodec/riscv/pixblockdsp_init.c index 0584100cf..273577610 100644 --- a/libavcodec/riscv/pixblockdsp_init.c +++ b/libavcodec/riscv/pixblockdsp_init.c @@ -55,8 +55,15 @@ av_cold void ff_pixblockdsp_init_riscv(PixblockDSPContext *c, c->get_pixels = ff_get_pixels_8_rvi; } + if (cpu_flags & AV_CPU_FLAG_RV_MISALIGNED) { + if (high_bit_depth) + c->get_pixels_unaligned = ff_get_pixels_16_rvi; + else + c->get_pixels_unaligned = ff_get_pixels_8_rvi; + } + #if HAVE_RVV - if ((cpu_flags & AV_CPU_FLAG_RVV_I32) && ff_get_rv_vlenb() >= 16) { + 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; } diff --git a/libavcodec/riscv/pixblockdsp_rvi.S b/libavcodec/riscv/pixblockdsp_rvi.S index efdd42222..ed1af7025 100644 --- a/libavcodec/riscv/pixblockdsp_rvi.S +++ b/libavcodec/riscv/pixblockdsp_rvi.S @@ -21,6 +21,7 @@ #include "libavutil/riscv/asm.S" func ff_get_pixels_8_rvi + lpad 0 .irp row, 0, 1, 2, 3, 4, 5, 6, 7 ld t0, (a1) add a1, a1, a2 @@ -47,6 +48,7 @@ func ff_get_pixels_8_rvi endfunc func ff_get_pixels_16_rvi + lpad 0 .irp row, 0, 1, 2, 3, 4, 5, 6, 7 ld t0, 0(a1) ld t1, 8(a1) diff --git a/libavcodec/riscv/pixblockdsp_rvv.S b/libavcodec/riscv/pixblockdsp_rvv.S index 4213cd1b8..85233470c 100644 --- a/libavcodec/riscv/pixblockdsp_rvv.S +++ b/libavcodec/riscv/pixblockdsp_rvv.S @@ -21,6 +21,7 @@ #include "libavutil/riscv/asm.S" func ff_get_pixels_8_rvv, zve64x + lpad 0 vsetivli zero, 8, e8, mf2, ta, ma li t0, 8 * 8 1: @@ -32,6 +33,7 @@ func ff_get_pixels_8_rvv, zve64x endfunc func ff_get_pixels_unaligned_8_rvv, zve64x + lpad 0 andi t1, a1, 7 vsetivli zero, 8, e64, m4, ta, ma li t0, 8 * 8 @@ -52,6 +54,7 @@ func ff_get_pixels_unaligned_8_rvv, zve64x endfunc func ff_diff_pixels_rvv, zve64x + lpad 0 vsetivli zero, 8, e8, mf2, ta, ma li t0, 8 * 8 vlse64.v v16, (a1), a3 @@ -63,6 +66,7 @@ func ff_diff_pixels_rvv, zve64x endfunc func ff_diff_pixels_unaligned_rvv, zve32x + lpad 0 vsetivli zero, 8, e8, mf2, ta, ma vlsseg8e8.v v16, (a1), a3 vlsseg8e8.v v24, (a2), a3 diff --git a/libavcodec/riscv/rv34dsp_init.c b/libavcodec/riscv/rv34dsp_init.c index 7dcadc7e4..051dc7565 100644 --- a/libavcodec/riscv/rv34dsp_init.c +++ b/libavcodec/riscv/rv34dsp_init.c @@ -33,7 +33,7 @@ av_cold void ff_rv34dsp_init_riscv(RV34DSPContext *c) #if HAVE_RVV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVV_I32 && ff_get_rv_vlenb() >= 16) { + if (flags & AV_CPU_FLAG_RVV_I32 && ff_rv_vlen_least(128)) { c->rv34_inv_transform_dc = ff_rv34_inv_transform_dc_rvv; c->rv34_idct_dc_add = ff_rv34_idct_dc_add_rvv; } diff --git a/libavcodec/riscv/rv34dsp_rvv.S b/libavcodec/riscv/rv34dsp_rvv.S index f1f634501..fc0ffec4f 100644 --- a/libavcodec/riscv/rv34dsp_rvv.S +++ b/libavcodec/riscv/rv34dsp_rvv.S @@ -21,6 +21,7 @@ #include "libavutil/riscv/asm.S" func ff_rv34_inv_transform_dc_rvv, zve32x + lpad 0 lh t1, 0(a0) li t0, 13 * 13 * 3 mul t2, t0, t1 @@ -33,21 +34,24 @@ func ff_rv34_inv_transform_dc_rvv, zve32x endfunc func ff_rv34_idct_dc_add_rvv, zve32x + lpad 0 vsetivli zero, 4, e8, mf4, ta, ma vlse32.v v0, (a0), a1 li t1, 169 mul t1, t1, a2 - li a2, 255 addi t1, t1, 512 srai t1, t1, 10 - vsetivli zero, 4*4, e16, m2, ta, ma - vzext.vf2 v2, v0 - vadd.vx v2, v2, t1 - vmax.vx v2, v2, zero - vsetvli zero, zero, e8, m1, ta, ma - vnclipu.wi v0, v2, 0 - vsetivli zero, 4, e8, mf4, ta, ma - vsse32.v v0, (a0), a1 + vsetivli zero, 4*4, e8, m2, ta, ma + bgez t1, 1f + neg t1, t1 + vssubu.vx v0, v0, t1 + vsetivli zero, 4, e8, mf4, ta, ma + vsse32.v v0, (a0), a1 + ret +1: + vsaddu.vx v0, v0, t1 + vsetivli zero, 4, e8, mf4, ta, ma + vsse32.v v0, (a0), a1 ret endfunc diff --git a/libavcodec/riscv/rv40dsp_init.c b/libavcodec/riscv/rv40dsp_init.c new file mode 100644 index 000000000..6aba57179 --- /dev/null +++ b/libavcodec/riscv/rv40dsp_init.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 Institue 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/rv34dsp.h" + +void ff_put_rv40_chroma_mc8_rvv(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_put_rv40_chroma_mc4_rvv(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + +void ff_avg_rv40_chroma_mc8_rvv(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_avg_rv40_chroma_mc4_rvv(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + +av_cold void ff_rv40dsp_init_riscv(RV34DSPContext *c) +{ +#if HAVE_RVV + int flags = av_get_cpu_flags(); + + if ((flags & AV_CPU_FLAG_RVV_I32) && ff_rv_vlen_least(128) && + (flags & AV_CPU_FLAG_RVB)) { + c->put_chroma_pixels_tab[0] = ff_put_rv40_chroma_mc8_rvv; + c->put_chroma_pixels_tab[1] = ff_put_rv40_chroma_mc4_rvv; + c->avg_chroma_pixels_tab[0] = ff_avg_rv40_chroma_mc8_rvv; + c->avg_chroma_pixels_tab[1] = ff_avg_rv40_chroma_mc4_rvv; + } +#endif +} diff --git a/libavcodec/riscv/rv40dsp_rvv.S b/libavcodec/riscv/rv40dsp_rvv.S new file mode 100644 index 000000000..ca431eb8a --- /dev/null +++ b/libavcodec/riscv/rv40dsp_rvv.S @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2024 Institue 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 manual_avg dst src1 src2 + vadd.vv \dst, \src1, \src2 + vadd.vi \dst, \dst, 1 + vsrl.vi \dst, \dst, 1 +.endm + +.macro do_chroma_mc type unroll + csrwi vxrm, 2 + slli t2, a5, 3 + mul t1, a5, a4 + sh3add a5, a4, t2 + slli a4, a4, 3 + sub a5, t1, a5 + sub a7, a4, t1 + addi a6, a5, 64 + sub t0, t2, t1 + vsetvli t3, t6, e8, m1, ta, mu + beqz t1, 2f + blez a3, 8f + li t4, 0 + li t2, 0 + li t5, 1 + addi a5, t3, 1 + slli t3, a2, (1 + \unroll) +1: # if (xy != 0) + add a4, a1, t4 + vsetvli zero, a5, e8, m1, ta, ma + .ifc \unroll,1 + addi t2, t2, 4 + .else + addi t2, t2, 2 + .endif + vle8.v v10, (a4) + add a4, a4, a2 + vslide1down.vx v11, v10, t5 + vsetvli zero, t6, e8, m1, ta, ma + vwmulu.vx v8, v10, a6 + vwmaccu.vx v8, a7, v11 + vsetvli zero, a5, e8, m1, ta, ma + vle8.v v12, (a4) + vsetvli zero, t6, e8, m1, ta, ma + add a4, a4, a2 + vwmaccu.vx v8, t0, v12 + vsetvli zero, a5, e8, m1, ta, ma + vslide1down.vx v13, v12, t5 + vsetvli zero, t6, e8, m1, ta, ma + vwmulu.vx v10, v12, a6 + vwmaccu.vx v8, t1, v13 + vwmaccu.vx v10, a7, v13 + vsetvli zero, a5, e8, m1, ta, ma + vle8.v v14, (a4) + vsetvli zero, t6, e8, m1, ta, ma + add a4, a4, a2 + vwmaccu.vx v10, t0, v14 + vsetvli zero, a5, e8, m1, ta, ma + vslide1down.vx v15, v14, t5 + vsetvli zero, t6, e8, m1, ta, ma + vwmulu.vx v12, v14, a6 + vwmaccu.vx v10, t1, v15 + vwmaccu.vx v12, a7, v15 + vnclipu.wi v15, v8, 6 + .ifc \type,avg + vle8.v v9, (a0) + manual_avg v15, v15, v9 + .endif + vse8.v v15, (a0) + add a0, a0, a2 + vnclipu.wi v8, v10, 6 + .ifc \type,avg + vle8.v v9, (a0) + manual_avg v8, v8, v9 + .endif + add t4, t4, t3 + vse8.v v8, (a0) + add a0, a0, a2 + .ifc \unroll,1 + vsetvli zero, a5, e8, m1, ta, ma + vle8.v v14, (a4) + vsetvli zero, t6, e8, m1, ta, ma + add a4, a4, a2 + vwmaccu.vx v12, t0, v14 + vsetvli zero, a5, e8, m1, ta, ma + vslide1down.vx v15, v14, t5 + vsetvli zero, t6, e8, m1, ta, ma + vwmulu.vx v16, v14, a6 + vwmaccu.vx v12, t1, v15 + vwmaccu.vx v16, a7, v15 + vsetvli zero, a5, e8, m1, ta, ma + vle8.v v14, (a4) + vsetvli zero, t6, e8, m1, ta, ma + vwmaccu.vx v16, t0, v14 + vsetvli zero, a5, e8, m1, ta, ma + vslide1down.vx v14, v14, t5 + vsetvli zero, t6, e8, m1, ta, ma + vwmaccu.vx v16, t1, v14 + vnclipu.wi v8, v12, 6 + .ifc \type,avg + vle8.v v9, (a0) + manual_avg v8, v8, v9 + .endif + vse8.v v8, (a0) + add a0, a0, a2 + vnclipu.wi v8, v16, 6 + .ifc \type,avg + vle8.v v9, (a0) + manual_avg v8, v8, v9 + .endif + vse8.v v8, (a0) + add a0, a0, a2 + .endif + blt t2, a3, 1b + j 8f +2: + bnez a4, 4f + beqz t2, 4f + blez a3, 8f + li a4, 0 + li t1, 0 + slli a7, a2, (1 + \unroll) +3: # if ((x8 - xy) == 0 && (y8 -xy) != 0) + add a5, a1, a4 + vsetvli zero, zero, e8, m1, ta, ma + .ifc \unroll,1 + addi t1, t1, 4 + .else + addi t1, t1, 2 + .endif + vle8.v v8, (a5) + add a5, a5, a2 + add t2, a5, a2 + vwmulu.vx v10, v8, a6 + vle8.v v8, (a5) + vwmulu.vx v12, v8, a6 + vle8.v v9, (t2) + add t2, t2, a2 + add a5, t2, a2 + vwmaccu.vx v10, t0, v8 + add a4, a4, a7 + vwmaccu.vx v12, t0, v9 + vnclipu.wi v15, v10, 6 + vwmulu.vx v10, v9, a6 + vnclipu.wi v9, v12, 6 + .ifc \type,avg + vle8.v v16, (a0) + manual_avg v15, v15, v16 + .endif + vse8.v v15, (a0) + add a0, a0, a2 + .ifc \type,avg + vle8.v v16, (a0) + manual_avg v9, v9, v16 + .endif + vse8.v v9, (a0) + add a0, a0, a2 + .ifc \unroll,1 + vle8.v v8, (t2) + vle8.v v14, (a5) + vwmaccu.vx v10, t0, v8 + vwmulu.vx v12, v8, a6 + vnclipu.wi v8, v10, 6 + vwmaccu.vx v12, t0, v14 + .ifc \type,avg + vle8.v v16, (a0) + manual_avg v8, v8, v16 + .endif + vse8.v v8, (a0) + add a0, a0, a2 + vnclipu.wi v8, v12, 6 + .ifc \type,avg + vle8.v v16, (a0) + manual_avg v8, v8, v16 + .endif + vse8.v v8, (a0) + add a0, a0, a2 + .endif + blt t1, a3, 3b + j 8f +4: + beqz a4, 6f + bnez t2, 6f + blez a3, 8f + li a4, 0 + li t2, 0 + addi t0, t3, 1 + slli t1, a2, (1 + \unroll) +5: # if ((x8 - xy) != 0 && (y8 -xy) == 0) + add a5, a1, a4 + vsetvli zero, t0, e8, m1, ta, ma + .ifc \unroll,1 + addi t2, t2, 4 + .else + addi t2, t2, 2 + .endif + vle8.v v8, (a5) + add a5, a5, a2 + vslide1down.vx v9, v8, t5 + vsetvli zero, t6, e8, m1, ta, ma + vwmulu.vx v10, v8, a6 + vwmaccu.vx v10, a7, v9 + vsetvli zero, t0, e8, m1, ta, ma + vle8.v v8, (a5) + add a5, a5, a2 + vslide1down.vx v9, v8, t5 + vsetvli zero, t6, e8, m1, ta, ma + vwmulu.vx v12, v8, a6 + vwmaccu.vx v12, a7, v9 + vnclipu.wi v16, v10, 6 + .ifc \type,avg + vle8.v v18, (a0) + manual_avg v16, v16, v18 + .endif + vse8.v v16, (a0) + add a0, a0, a2 + vnclipu.wi v10, v12, 6 + .ifc \type,avg + vle8.v v18, (a0) + manual_avg v10, v10, v18 + .endif + add a4, a4, t1 + vse8.v v10, (a0) + add a0, a0, a2 + .ifc \unroll,1 + vsetvli zero, t0, e8, m1, ta, ma + vle8.v v8, (a5) + add a5, a5, a2 + vslide1down.vx v9, v8, t5 + vsetvli zero, t6, e8, m1, ta, ma + vwmulu.vx v14, v8, a6 + vwmaccu.vx v14, a7, v9 + vsetvli zero, t0, e8, m1, ta, ma + vle8.v v8, (a5) + vslide1down.vx v9, v8, t5 + vsetvli zero, t6, e8, m1, ta, ma + vwmulu.vx v12, v8, a6 + vnclipu.wi v8, v14, 6 + vwmaccu.vx v12, a7, v9 + .ifc \type,avg + vle8.v v18, (a0) + manual_avg v8, v8, v18 + .endif + vse8.v v8, (a0) + add a0, a0, a2 + vnclipu.wi v8, v12, 6 + .ifc \type,avg + vle8.v v18, (a0) + manual_avg v8, v8, v18 + .endif + vse8.v v8, (a0) + add a0, a0, a2 + .endif + blt t2, a3, 5b + j 8f +6: + blez a3, 8f + li a4, 0 + li t2, 0 + slli a7, a2, (1 + \unroll) +7: # the final else, none of the above conditions are met + add t0, a1, a4 + vsetvli zero, zero, e8, m1, ta, ma + add a5, a0, a4 + add a4, a4, a7 + .ifc \unroll,1 + addi t2, t2, 4 + .else + addi t2, t2, 2 + .endif + vle8.v v8, (t0) + add t0, t0, a2 + add t1, t0, a2 + vwmulu.vx v10, v8, a6 + vle8.v v8, (t0) + add t0, t1, a2 + vnclipu.wi v13, v10, 6 + vwmulu.vx v10, v8, a6 + .ifc \type,avg + vle8.v v18, (a5) + manual_avg v13, v13, v18 + .endif + vse8.v v13, (a5) + add a5, a5, a2 + vnclipu.wi v8, v10, 6 + .ifc \type,avg + vle8.v v18, (a5) + manual_avg v8, v8, v18 + .endif + vse8.v v8, (a5) + add a5, a5, a2 + .ifc \unroll,1 + vle8.v v9, (t1) + vle8.v v12, (t0) + vwmulu.vx v10, v9, a6 + vnclipu.wi v8, v10, 6 + vwmulu.vx v10, v12, a6 + .ifc \type,avg + vle8.v v18, (a5) + manual_avg v8, v8, v18 + .endif + vse8.v v8, (a5) + add a5, a5, a2 + vnclipu.wi v8, v10, 6 + .ifc \type,avg + vle8.v v18, (a5) + manual_avg v8, v8, v18 + .endif + vse8.v v8, (a5) + .endif + blt t2, a3, 7b +8: + ret +.endm + +func ff_put_rv40_chroma_mc_rvv, zve32x, zba +11: + li a7, 3 + blt a3, a7, 12f + do_chroma_mc put 1 +12: + do_chroma_mc put 0 +endfunc + +func ff_avg_rv40_chroma_mc_rvv, zve32x, zba +21: + li a7, 3 + blt a3, a7, 22f + do_chroma_mc avg 1 +22: + do_chroma_mc avg 0 +endfunc + +func ff_put_rv40_chroma_mc8_rvv, zve32x + lpad 0 + li t6, 8 + j 11b +endfunc + +func ff_put_rv40_chroma_mc4_rvv, zve32x + lpad 0 + li t6, 4 + j 11b +endfunc + +func ff_avg_rv40_chroma_mc8_rvv, zve32x + lpad 0 + li t6, 8 + j 21b +endfunc + +func ff_avg_rv40_chroma_mc4_rvv, zve32x + lpad 0 + li t6, 4 + j 21b +endfunc diff --git a/libavcodec/riscv/sbrdsp_init.c b/libavcodec/riscv/sbrdsp_init.c index 2ed46153e..0915fe996 100644 --- a/libavcodec/riscv/sbrdsp_init.c +++ b/libavcodec/riscv/sbrdsp_init.c @@ -26,7 +26,6 @@ void ff_sbr_sum64x5_rvv(float *z); float ff_sbr_sum_square_rvv(float (*x)[2], int n); -void ff_sbr_neg_odd_64_rvv(float *x); void ff_sbr_autocorrelate_rvv(const float x[40][2], float phi[3][2][2]); void ff_sbr_hf_gen_rvv(float (*X_high)[2], const float (*X_low)[2], const float alpha0[2], const float alpha1[2], @@ -48,25 +47,19 @@ av_cold void ff_sbrdsp_init_riscv(SBRDSPContext *c) int flags = av_get_cpu_flags(); if (flags & AV_CPU_FLAG_RVV_F32) { - if (flags & AV_CPU_FLAG_RVB_ADDR) { + if (flags & AV_CPU_FLAG_RVB) { c->sum64x5 = ff_sbr_sum64x5_rvv; c->sum_square = ff_sbr_sum_square_rvv; c->hf_gen = ff_sbr_hf_gen_rvv; c->hf_g_filt = ff_sbr_hf_g_filt_rvv; - if (ff_get_rv_vlenb() <= 16) { + if (ff_get_rv_vlenb() <= 32) { c->hf_apply_noise[0] = ff_sbr_hf_apply_noise_0_rvv; c->hf_apply_noise[2] = ff_sbr_hf_apply_noise_2_rvv; - if (flags & AV_CPU_FLAG_RVB_BASIC) { - c->hf_apply_noise[1] = ff_sbr_hf_apply_noise_1_rvv; - c->hf_apply_noise[3] = ff_sbr_hf_apply_noise_3_rvv; - } + c->hf_apply_noise[1] = ff_sbr_hf_apply_noise_1_rvv; + c->hf_apply_noise[3] = ff_sbr_hf_apply_noise_3_rvv; } } c->autocorrelate = ff_sbr_autocorrelate_rvv; } -#if __riscv_xlen >= 64 - if ((flags & AV_CPU_FLAG_RVV_I64) && (flags & AV_CPU_FLAG_RVB_ADDR)) - c->neg_odd_64 = ff_sbr_neg_odd_64_rvv; -#endif #endif } diff --git a/libavcodec/riscv/sbrdsp_rvv.S b/libavcodec/riscv/sbrdsp_rvv.S index 02feb6451..23e1a8f9c 100644 --- a/libavcodec/riscv/sbrdsp_rvv.S +++ b/libavcodec/riscv/sbrdsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_sbr_sum64x5_rvv, zve32f +func ff_sbr_sum64x5_rvv, zve32f, zba + lpad 0 li a5, 64 addi a1, a0, 64 * 4 addi a2, a0, 128 * 4 @@ -49,7 +50,8 @@ func ff_sbr_sum64x5_rvv, zve32f ret endfunc -func ff_sbr_sum_square_rvv, zve32f +func ff_sbr_sum_square_rvv, zve32f, zba + lpad 0 vsetvli t0, zero, e32, m8, ta, ma slli a1, a1, 1 vmv.v.x v8, zero @@ -68,24 +70,8 @@ NOHWF fmv.x.w a0, fa0 ret endfunc -#if __riscv_xlen >= 64 -func ff_sbr_neg_odd_64_rvv, zve64x - li a1, 32 - li t1, 1 << 63 -1: - vsetvli t0, a1, e64, m8, ta, ma - vle64.v v8, (a0) - sub a1, a1, t0 - vxor.vx v8, v8, t1 - vse64.v v8, (a0) - sh3add a0, t0, a0 - bnez t0, 1b - - ret -endfunc -#endif - func ff_sbr_autocorrelate_rvv, zve32f + lpad 0 vsetvli t0, zero, e32, m4, ta, ma vmv.v.x v0, zero flw fa0, (a0) @@ -174,7 +160,8 @@ func ff_sbr_autocorrelate_rvv, zve32f ret endfunc -func ff_sbr_hf_gen_rvv, zve32f +func ff_sbr_hf_gen_rvv, zve32f, zba + lpad 0 NOHWF fmv.w.x fa0, a4 NOHWF mv a4, a5 NOHWF mv a5, a6 @@ -224,7 +211,8 @@ NOHWF mv a5, a6 ret endfunc -func ff_sbr_hf_g_filt_rvv, zve32f +func ff_sbr_hf_g_filt_rvv, zve32f, zba + lpad 0 li t1, 40 * 2 * 4 sh3add a1, a4, a1 1: @@ -245,9 +233,8 @@ func ff_sbr_hf_g_filt_rvv, zve32f endfunc .macro hf_apply_noise n - lla a6, ff_sbr_noise_table + lla a6, ff_sbr_noise_table + 8 fmv.s.x ft0, zero - addi a6, a6, 8 1: .if \n & 1 min t0, t0, a5 // preserve parity of t0 for v4 sign injector @@ -290,16 +277,19 @@ endfunc ret .endm -func ff_sbr_hf_apply_noise_0_rvv, zve32f +func ff_sbr_hf_apply_noise_0_rvv, zve32f, b + lpad 0 hf_apply_noise 0 endfunc -func ff_sbr_hf_apply_noise_3_rvv, zve32f +func ff_sbr_hf_apply_noise_3_rvv, zve32f, b + lpad 0 not a4, a4 // invert parity of kx // fall through endfunc -func ff_sbr_hf_apply_noise_1_rvv, zve32f +func ff_sbr_hf_apply_noise_1_rvv, zve32f, b + lpad 0 vsetvli t0, zero, e32, m4, ta, ma vid.v v4 vxor.vx v4, v4, a4 @@ -307,6 +297,7 @@ func ff_sbr_hf_apply_noise_1_rvv, zve32f hf_apply_noise 1 endfunc -func ff_sbr_hf_apply_noise_2_rvv, zve32f +func ff_sbr_hf_apply_noise_2_rvv, zve32f, b + lpad 0 hf_apply_noise 2 endfunc diff --git a/libavcodec/riscv/startcode_rvb.S b/libavcodec/riscv/startcode_rvb.S new file mode 100644 index 000000000..eec92d334 --- /dev/null +++ b/libavcodec/riscv/startcode_rvb.S @@ -0,0 +1,84 @@ +/* + * Copyright © 2024 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" + + .macro lx rd, addr +#if (__riscv_xlen == 32) + lw \rd, \addr +#elif (__riscv_xlen == 64) + ld \rd, \addr +#else + lq \rd, \addr +#endif + .endm + +func ff_startcode_find_candidate_rvb, zbb + lpad 0 + add a1, a0, a1 + + // Potentially unaligned head + andi t0, a0, -(__riscv_xlen / 8) + beq a0, a1, 2f + + andi t1, a0, (__riscv_xlen / 8) - 1 + lx t2, (t0) + li t3, __riscv_xlen + orc.b t2, t2 + slli t1, t1, 3 + not t2, t2 + sub t3, t3, t1 + srl t2, t2, t1 + addi t0, t0, __riscv_xlen / 8 + sll t2, t2, t1 + bnez t2, 4f + + // Main loop (including potentially short tail) + bge t0, a1, 2f + li t3, -1 +1: + lx t2, (t0) + addi t0, t0, __riscv_xlen / 8 + orc.b t2, t2 + bne t2, t3, 3f // t2 != -1 iff (at least one) zero byte + blt t0, a1, 1b + +2: // No zero byte found + sub a0, a1, a0 + ret + +3: // Zero byte found in main loop + not t2, t2 +4: // Zero byte found in head + ctz t2, t2 + addi t0, t0, -(__riscv_xlen / 8) // back-track + srl t2, t2, 3 + add t0, t0, t2 + // Uncomment the following line for exact POSIX C strnlen() semantics. + //minu t0, t0, a1 // ignore zero byte in tail + sub a0, t0, a0 + ret +endfunc diff --git a/libavcodec/riscv/startcode_rvv.S b/libavcodec/riscv/startcode_rvv.S new file mode 100644 index 000000000..f4d0a0f08 --- /dev/null +++ b/libavcodec/riscv/startcode_rvv.S @@ -0,0 +1,47 @@ +/* + * Copyright © 2024 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" + +func ff_startcode_find_candidate_rvv, zve32x + lpad 0 + mv t0, a0 +1: + vsetvli t1, a1, e8, m8, ta, ma + vle8.v v8, (t0) + sub a1, a1, t1 + vmseq.vi v0, v8, 0 + vfirst.m t2, v0 + bgez t2, 2f + add t0, t0, t1 + bnez a1, 1b + + mv t2, zero +2: + add t0, t0, t2 + sub a0, t0, a0 + ret +endfunc diff --git a/libavcodec/riscv/svqenc_init.c b/libavcodec/riscv/svqenc_init.c index f4c398960..5021849e4 100644 --- a/libavcodec/riscv/svqenc_init.c +++ b/libavcodec/riscv/svqenc_init.c @@ -33,7 +33,7 @@ av_cold void ff_svq1enc_init_riscv(SVQ1EncDSPContext *c) int flags = av_get_cpu_flags(); if (flags & AV_CPU_FLAG_RVV_I32) { - if (flags & AV_CPU_FLAG_RVB_ADDR) { + if (flags & AV_CPU_FLAG_RVB) { c->ssd_int8_vs_int16 = ff_ssd_int8_vs_int16_rvv; } } diff --git a/libavcodec/riscv/svqenc_rvv.S b/libavcodec/riscv/svqenc_rvv.S index cfc27154d..d37c319db 100644 --- a/libavcodec/riscv/svqenc_rvv.S +++ b/libavcodec/riscv/svqenc_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_ssd_int8_vs_int16_rvv, zve32x +func ff_ssd_int8_vs_int16_rvv, zve32x, zba + lpad 0 vsetvli t0, zero, e32, m8, ta, ma vmv.v.x v24, zero 1: diff --git a/libavcodec/riscv/takdsp_init.c b/libavcodec/riscv/takdsp_init.c index 58be83860..12d2d8dab 100644 --- a/libavcodec/riscv/takdsp_init.c +++ b/libavcodec/riscv/takdsp_init.c @@ -35,7 +35,7 @@ av_cold void ff_takdsp_init_riscv(TAKDSPContext *dsp) #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { dsp->decorrelate_ls = ff_decorrelate_ls_rvv; dsp->decorrelate_sr = ff_decorrelate_sr_rvv; dsp->decorrelate_sm = ff_decorrelate_sm_rvv; diff --git a/libavcodec/riscv/takdsp_rvv.S b/libavcodec/riscv/takdsp_rvv.S index fa942a3be..a914ab818 100644 --- a/libavcodec/riscv/takdsp_rvv.S +++ b/libavcodec/riscv/takdsp_rvv.S @@ -21,7 +21,8 @@ #include "libavutil/riscv/asm.S" -func ff_decorrelate_ls_rvv, zve32x +func ff_decorrelate_ls_rvv, zve32x, zba + lpad 0 1: vsetvli t0, a2, e32, m8, ta, ma sub a2, a2, t0 @@ -35,7 +36,8 @@ func ff_decorrelate_ls_rvv, zve32x ret endfunc -func ff_decorrelate_sr_rvv, zve32x +func ff_decorrelate_sr_rvv, zve32x, zba + lpad 0 1: vsetvli t0, a2, e32, m8, ta, ma vle32.v v0, (a0) @@ -49,7 +51,8 @@ func ff_decorrelate_sr_rvv, zve32x ret endfunc -func ff_decorrelate_sm_rvv, zve32x +func ff_decorrelate_sm_rvv, zve32x, zba + lpad 0 1: vsetvli t0, a2, e32, m8, ta, ma vle32.v v8, (a1) @@ -67,7 +70,8 @@ func ff_decorrelate_sm_rvv, zve32x ret endfunc -func ff_decorrelate_sf_rvv, zve32x +func ff_decorrelate_sf_rvv, zve32x, zba + lpad 0 csrwi vxrm, 0 1: vsetvli t0, a2, e32, m8, ta, ma diff --git a/libavcodec/riscv/utvideodsp_init.c b/libavcodec/riscv/utvideodsp_init.c index f5038c473..9d7469f38 100644 --- a/libavcodec/riscv/utvideodsp_init.c +++ b/libavcodec/riscv/utvideodsp_init.c @@ -38,7 +38,7 @@ av_cold void ff_utvideodsp_init_riscv(UTVideoDSPContext *c) if (flags & AV_CPU_FLAG_RVV_I32) { c->restore_rgb_planes = ff_restore_rgb_planes_rvv; - if (flags & AV_CPU_FLAG_RVB_ADDR) + if (flags & AV_CPU_FLAG_RVB) c->restore_rgb_planes10 = ff_restore_rgb_planes10_rvv; } #endif diff --git a/libavcodec/riscv/utvideodsp_rvv.S b/libavcodec/riscv/utvideodsp_rvv.S index fa70d0eb3..30e195120 100644 --- a/libavcodec/riscv/utvideodsp_rvv.S +++ b/libavcodec/riscv/utvideodsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_restore_rgb_planes_rvv, zve32x +func ff_restore_rgb_planes_rvv, zve32x, zba + lpad 0 li t1, -0x80 sub a3, a3, a6 sub a4, a4, a6 @@ -52,7 +53,8 @@ func ff_restore_rgb_planes_rvv, zve32x ret endfunc -func ff_restore_rgb_planes10_rvv, zve32x +func ff_restore_rgb_planes10_rvv, zve32x, zba + lpad 0 li t1, -0x200 li t2, 0x3FF sub a3, a3, a6 diff --git a/libavcodec/riscv/vc1dsp_init.c b/libavcodec/riscv/vc1dsp_init.c index e47b644f8..de9002f39 100644 --- a/libavcodec/riscv/vc1dsp_init.c +++ b/libavcodec/riscv/vc1dsp_init.c @@ -26,22 +26,53 @@ #include "libavcodec/vc1.h" void ff_vc1_inv_trans_8x8_dc_rvv(uint8_t *dest, ptrdiff_t stride, int16_t *block); +void ff_vc1_inv_trans_8x8_rvv(int16_t block[64]); void ff_vc1_inv_trans_4x8_dc_rvv(uint8_t *dest, ptrdiff_t stride, int16_t *block); +void ff_vc1_inv_trans_4x8_rvv(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_8x4_dc_rvv(uint8_t *dest, ptrdiff_t stride, int16_t *block); +void ff_vc1_inv_trans_8x4_rvv(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_4x4_dc_rvv(uint8_t *dest, ptrdiff_t stride, int16_t *block); +void ff_vc1_inv_trans_4x4_rvv(uint8_t *dest, ptrdiff_t stride, int16_t *block); +void ff_put_pixels16x16_rvi(uint8_t *dst, const uint8_t *src, ptrdiff_t line_size, int rnd); +void ff_put_pixels8x8_rvi(uint8_t *dst, const uint8_t *src, ptrdiff_t line_size, int rnd); +void ff_avg_pixels16x16_rvv(uint8_t *dst, const uint8_t *src, ptrdiff_t line_size, int rnd); +void ff_avg_pixels8x8_rvv(uint8_t *dst, const uint8_t *src, ptrdiff_t line_size, int rnd); +int ff_startcode_find_candidate_rvb(const uint8_t *, int); +int ff_startcode_find_candidate_rvv(const uint8_t *, int); +int ff_vc1_unescape_buffer_rvv(const uint8_t *, int, uint8_t *); av_cold void ff_vc1dsp_init_riscv(VC1DSPContext *dsp) { -#if HAVE_RVV +#if HAVE_RV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVV_I32 && ff_get_rv_vlenb() >= 16) { - dsp->vc1_inv_trans_4x8_dc = ff_vc1_inv_trans_4x8_dc_rvv; - dsp->vc1_inv_trans_4x4_dc = ff_vc1_inv_trans_4x4_dc_rvv; - if (flags & AV_CPU_FLAG_RVV_I64) { - dsp->vc1_inv_trans_8x8_dc = ff_vc1_inv_trans_8x8_dc_rvv; - dsp->vc1_inv_trans_8x4_dc = ff_vc1_inv_trans_8x4_dc_rvv; - } +# if __riscv_xlen >= 64 + if (flags & AV_CPU_FLAG_RVI) { + dsp->put_vc1_mspel_pixels_tab[1][0] = ff_put_pixels8x8_rvi; + dsp->put_vc1_mspel_pixels_tab[0][0] = ff_put_pixels16x16_rvi; } +# endif + if (flags & AV_CPU_FLAG_RVB_BASIC) + dsp->startcode_find_candidate = ff_startcode_find_candidate_rvb; +# if HAVE_RVV + if (flags & AV_CPU_FLAG_RVV_I32) { + if (ff_rv_vlen_least(128)) { + dsp->vc1_inv_trans_8x8 = ff_vc1_inv_trans_8x8_rvv; + dsp->vc1_inv_trans_8x4 = ff_vc1_inv_trans_8x4_rvv; + dsp->vc1_inv_trans_4x8 = ff_vc1_inv_trans_4x8_rvv; + dsp->vc1_inv_trans_4x4 = ff_vc1_inv_trans_4x4_rvv; + dsp->vc1_inv_trans_4x8_dc = ff_vc1_inv_trans_4x8_dc_rvv; + dsp->vc1_inv_trans_4x4_dc = ff_vc1_inv_trans_4x4_dc_rvv; + dsp->avg_vc1_mspel_pixels_tab[0][0] = ff_avg_pixels16x16_rvv; + dsp->avg_vc1_mspel_pixels_tab[1][0] = ff_avg_pixels8x8_rvv; + if (flags & AV_CPU_FLAG_RVV_I64) { + dsp->vc1_inv_trans_8x8_dc = ff_vc1_inv_trans_8x8_dc_rvv; + dsp->vc1_inv_trans_8x4_dc = ff_vc1_inv_trans_8x4_dc_rvv; + } + } + dsp->startcode_find_candidate = ff_startcode_find_candidate_rvv; + dsp->vc1_unescape_buffer = ff_vc1_unescape_buffer_rvv; + } +# endif #endif } diff --git a/libavcodec/riscv/vc1dsp_rvi.S b/libavcodec/riscv/vc1dsp_rvi.S new file mode 100644 index 000000000..7725bfb62 --- /dev/null +++ b/libavcodec/riscv/vc1dsp_rvi.S @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 Institue 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" + +#if __riscv_xlen >= 64 +func ff_put_pixels8x8_rvi + lpad 0 +.rept 8 + ld t0, (a1) + sd t0, (a0) + add a1, a1, a2 + add a0, a0, a2 +.endr + + ret +endfunc + +func ff_put_pixels16x16_rvi + lpad 0 +.rept 16 + ld t0, (a1) + ld t1, 8(a1) + sd t0, (a0) + sd t1, 8(a0) + add a1, a1, a2 + add a0, a0, a2 +.endr + + ret +endfunc +#endif diff --git a/libavcodec/riscv/vc1dsp_rvv.S b/libavcodec/riscv/vc1dsp_rvv.S index 4a00945ea..f9b59688a 100644 --- a/libavcodec/riscv/vc1dsp_rvv.S +++ b/libavcodec/riscv/vc1dsp_rvv.S @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. * @@ -20,94 +21,435 @@ #include "libavutil/riscv/asm.S" -func ff_vc1_inv_trans_8x8_dc_rvv, zve64x - lh t2, (a2) - vsetivli zero, 8, e8, mf2, ta, ma - vlse64.v v0, (a0), a1 - sh1add t2, t2, t2 - addi t2, t2, 1 - srai t2, t2, 1 - sh1add t2, t2, t2 - addi t2, t2, 16 - srai t2, t2, 5 - li t0, 8*8 - vsetvli zero, t0, e16, m8, ta, ma - vzext.vf2 v8, v0 - vadd.vx v8, v8, t2 - vmax.vx v8, v8, zero - vsetvli zero, zero, e8, m4, ta, ma - vnclipu.wi v0, v8, 0 - vsetivli zero, 8, e8, mf2, ta, ma - vsse64.v v0, (a0), a1 +.macro inv_trans_dc rows, cols, w, mat_lmul, row_lmul +func ff_vc1_inv_trans_\cols\()x\rows\()_dc_rvv, zve64x, zba + lpad 0 + lh t2, (a2) + li a4, 22 - (5 * \cols) / 4 + mul t2, t2, a4 + vsetivli zero, \rows, e8, m\row_lmul, ta, ma + vlse\w\().v v0, (a0), a1 + addi t2, t2, 4 + li a5, 22 - (5 * \rows) / 4 + srai t2, t2, 3 + mul t2, t2, a5 +.if \cols * \rows >= 32 + li t0, \cols * \rows +.endif + addi t2, t2, 64 + srai t2, t2, 7 +.if \rows * \cols >= 32 + vsetvli zero, t0, e8, m\mat_lmul, ta, ma +.else + vsetivli zero, \rows * \cols, e8, m\mat_lmul, ta, ma +.endif + bgez t2, 1f + + neg t2, t2 + vssubu.vx v0, v0, t2 + vsetivli zero, \rows, e8, m\row_lmul, ta, ma + vsse\w\().v v0, (a0), a1 + ret +1: + vsaddu.vx v0, v0, t2 + vsetivli zero, \rows, e8, m\row_lmul, ta, ma + vsse\w\().v v0, (a0), a1 + ret +endfunc +.endm + +inv_trans_dc 8, 8, 64, 4, f2 +inv_trans_dc 4, 8, 64, 2, f4 +inv_trans_dc 8, 4, 32, 2, f2 +inv_trans_dc 4, 4, 32, 1, f4 + + .variant_cc ff_vc1_inv_trans_8_rvv +func ff_vc1_inv_trans_8_rvv, zve32x + li t4, 12 + vsll.vi v14, v6, 4 + li t2, 6 + vsll.vi v12, v2, 4 + li t5, 15 + vmul.vx v8, v0, t4 + li t3, 9 + # t[2..5] = [6 9 12 15] + vmul.vx v10, v4, t4 + vmul.vx v16, v2, t2 + vmacc.vx v12, t2, v6 # t3 + vnmsac.vx v14, t2, v2 # -t4 + vadd.vv v24, v8, v10 # t1 + vsub.vv v25, v8, v10 # t2 + vadd.vv v28, v24, v12 # t5 + vsub.vv v31, v24, v12 # t8 + vsub.vv v29, v25, v14 # t6 + vadd.vv v30, v25, v14 # t7 + vsll.vi v20, v1, 4 + vsll.vi v22, v7, 2 + vmacc.vx v20, t5, v3 + vmacc.vx v22, t3, v5 + vsll.vi v21, v3, 2 + vsll.vi v23, v5, 4 + vadd.vv v24, v20, v22 # t1 + vnmsac.vx v21, t5, v1 + vmacc.vx v23, t3, v7 + vsll.vi v20, v3, 4 + vsll.vi v22, v5, 2 + vadd.vv v25, v21, v23 # -t2 + vnmsac.vx v20, t3, v1 + vmacc.vx v22, t5, v7 + vsll.vi v21, v1, 2 + vsll.vi v23, v7, 4 + vsub.vv v26, v22, v20 # t3 + vnmsac.vx v21, t3, v3 + vnmsac.vx v23, t5, v5 + srli t2, t1, 2 + vwadd.vv v8, v28, v24 + vwsub.vv v10, v29, v25 + vsub.vv v27, v21, v23 # t4 + vwadd.vv v12, v30, v26 + vwadd.vv v14, v31, v27 + beqz t2, 1f # faster than 4x add t2=zero + .irp n,31,30,29,28 + vadd.vi v\n, v\n, 1 + .endr +1: + vwsub.vv v16, v31, v27 + vwsub.vv v18, v30, v26 + vwadd.vv v20, v29, v25 + vwsub.vv v22, v28, v24 + vnclip.wx v0, v8, t1 + vnclip.wx v1, v10, t1 + vnclip.wx v2, v12, t1 + vnclip.wx v3, v14, t1 + vnclip.wx v4, v16, t1 + vnclip.wx v5, v18, t1 + vnclip.wx v6, v20, t1 + vnclip.wx v7, v22, t1 + jr t0 +endfunc + + .variant_cc ff_vc1_inv_trans_4_rvv +func ff_vc1_inv_trans_4_rvv, zve32x + li t3, 17 + vmul.vx v8, v0, t3 + li t4, 22 + vmul.vx v10, v2, t3 + li t2, 10 + vmul.vx v26, v1, t4 + vmul.vx v27, v3, t4 + vadd.vv v24, v8, v10 # t1 + vsub.vv v25, v8, v10 # t2 + vmacc.vx v26, t2, v3 # t3 + vnmsac.vx v27, t2, v1 # t4 + vwadd.vv v8, v24, v26 + vwsub.vv v10, v25, v27 + vwadd.vv v12, v25, v27 + vwsub.vv v14, v24, v26 + vnclip.wx v0, v8, t1 + vnclip.wx v1, v10, t1 + vnclip.wx v2, v12, t1 + vnclip.wx v3, v14, t1 + jr t0 +endfunc + +func ff_vc1_inv_trans_8x8_rvv, zve32x + lpad 0 + csrwi vxrm, 0 + vsetivli zero, 8, e16, m1, ta, ma + addi a1, a0, 1 * 8 * 2 + vle16.v v0, (a0) + addi a2, a0, 2 * 8 * 2 + vle16.v v1, (a1) + addi a3, a0, 3 * 8 * 2 + vle16.v v2, (a2) + addi a4, a0, 4 * 8 * 2 + vle16.v v3, (a3) + addi a5, a0, 5 * 8 * 2 + vle16.v v4, (a4) + addi a6, a0, 6 * 8 * 2 + vle16.v v5, (a5) + addi a7, a0, 7 * 8 * 2 + vle16.v v6, (a6) + vle16.v v7, (a7) + li t1, 3 + jal t0, ff_vc1_inv_trans_8_rvv + vsseg8e16.v v0, (a0) + .irp n,0,1,2,3,4,5,6,7 + vle16.v v\n, (a\n) + .endr + li t1, 7 + jal t0, ff_vc1_inv_trans_8_rvv + vse16.v v0, (a0) + vse16.v v1, (a1) + vse16.v v2, (a2) + vse16.v v3, (a3) + vse16.v v4, (a4) + vse16.v v5, (a5) + vse16.v v6, (a6) + vse16.v v7, (a7) ret endfunc -func ff_vc1_inv_trans_4x8_dc_rvv, zve32x - lh t2, (a2) - vsetivli zero, 8, e8, mf2, ta, ma - vlse32.v v0, (a0), a1 - slli t1, t2, 4 - add t2, t2, t1 - addi t2, t2, 4 - srai t2, t2, 3 - sh1add t2, t2, t2 - slli t2, t2, 2 - addi t2, t2, 64 - srai t2, t2, 7 - li t0, 4*8 - vsetvli zero, t0, e16, m4, ta, ma - vzext.vf2 v4, v0 - vadd.vx v4, v4, t2 - vmax.vx v4, v4, zero - vsetvli zero, zero, e8, m2, ta, ma - vnclipu.wi v0, v4, 0 - vsetivli zero, 8, e8, mf2, ta, ma - vsse32.v v0, (a0), a1 +func ff_vc1_inv_trans_8x4_rvv, zve32x + lpad 0 + csrwi vxrm, 0 + vsetivli zero, 4, e16, mf2, ta, ma + vlseg8e16.v v0, (a2) + li t1, 3 + jal t0, ff_vc1_inv_trans_8_rvv + vsseg8e16.v v0, (a2) + addi a3, a2, 1 * 8 * 2 + vsetivli zero, 8, e16, m1, ta, ma + vle16.v v0, (a2) + addi a4, a2, 2 * 8 * 2 + vle16.v v1, (a3) + addi a5, a2, 3 * 8 * 2 + vle16.v v2, (a4) + vle16.v v3, (a5) + li t1, 7 + jal t0, ff_vc1_inv_trans_4_rvv + add a3, a1, a0 + vle8.v v8, (a0) + add a4, a1, a3 + vle8.v v9, (a3) + add a5, a1, a4 + vle8.v v10, (a4) + vle8.v v11, (a5) + vsetvli zero, zero, e8, mf2, ta, ma + vwaddu.wv v0, v0, v8 + vwaddu.wv v1, v1, v9 + vwaddu.wv v2, v2, v10 + vwaddu.wv v3, v3, v11 + vsetvli zero, zero, e16, m1, ta, ma + .irp n,0,1,2,3 + vmax.vx v\n, v\n, zero + .endr + vsetvli zero, zero, e8, mf2, ta, ma + vnclipu.wi v8, v0, 0 + vnclipu.wi v9, v1, 0 + vse8.v v8, (a0) + vnclipu.wi v10, v2, 0 + vse8.v v9, (a3) + vnclipu.wi v11, v3, 0 + vse8.v v10, (a4) + vse8.v v11, (a5) ret endfunc -func ff_vc1_inv_trans_8x4_dc_rvv, zve64x - lh t2, (a2) - vsetivli zero, 4, e8, mf4, ta, ma - vlse64.v v0, (a0), a1 - sh1add t2, t2, t2 - addi t2, t2, 1 - srai t2, t2, 1 - slli t1, t2, 4 - add t2, t2, t1 - addi t2, t2, 64 - srai t2, t2, 7 - li t0, 8*4 - vsetvli zero, t0, e16, m4, ta, ma - vzext.vf2 v4, v0 - vadd.vx v4, v4, t2 - vmax.vx v4, v4, zero - vsetvli zero, zero, e8, m2, ta, ma - vnclipu.wi v0, v4, 0 - vsetivli zero, 4, e8, mf4, ta, ma - vsse64.v v0, (a0), a1 +func ff_vc1_inv_trans_4x8_rvv, zve32x + lpad 0 + li a3, 8 * 2 + csrwi vxrm, 0 + vsetivli zero, 8, e16, m1, ta, ma + vlsseg4e16.v v0, (a2), a3 + li t1, 3 + jal t0, ff_vc1_inv_trans_4_rvv + vssseg4e16.v v0, (a2), a3 + vsetivli zero, 4, e16, mf2, ta, ma + addi t1, a2, 1 * 8 * 2 + vle16.v v0, (a2) + addi t2, a2, 2 * 8 * 2 + vle16.v v1, (t1) + addi t3, a2, 3 * 8 * 2 + vle16.v v2, (t2) + addi t4, a2, 4 * 8 * 2 + vle16.v v3, (t3) + addi t5, a2, 5 * 8 * 2 + vle16.v v4, (t4) + addi t6, a2, 6 * 8 * 2 + vle16.v v5, (t5) + addi t1, a2, 7 * 8 * 2 + vle16.v v6, (t6) + vle16.v v7, (t1) + li t1, 7 + jal t0, ff_vc1_inv_trans_8_rvv + add t0, a1, a0 + vle8.v v8, (a0) + add t1, a1, t0 + vle8.v v9, (t0) + add t2, a1, t1 + vle8.v v10, (t1) + add t3, a1, t2 + vle8.v v11, (t2) + add t4, a1, t3 + vle8.v v12, (t3) + add t5, a1, t4 + vle8.v v13, (t4) + add t6, a1, t5 + vle8.v v14, (t5) + vle8.v v15, (t6) + vsetvli zero, zero, e8, mf4, ta, ma + vwaddu.wv v0, v0, v8 + vwaddu.wv v1, v1, v9 + vwaddu.wv v2, v2, v10 + vwaddu.wv v3, v3, v11 + vwaddu.wv v4, v4, v12 + vwaddu.wv v5, v5, v13 + vwaddu.wv v6, v6, v14 + vwaddu.wv v7, v7, v15 + vsetvli zero, zero, e16, mf2, ta, ma + .irp n,0,1,2,3,4,5,6,7 + vmax.vx v\n, v\n, zero + .endr + vsetvli zero, zero, e8, mf4, ta, ma + vnclipu.wi v8, v0, 0 + vnclipu.wi v9, v1, 0 + vse8.v v8, (a0) + vnclipu.wi v10, v2, 0 + vse8.v v9, (t0) + vnclipu.wi v11, v3, 0 + vse8.v v10, (t1) + vnclipu.wi v12, v4, 0 + vse8.v v11, (t2) + vnclipu.wi v13, v5, 0 + vse8.v v12, (t3) + vnclipu.wi v14, v6, 0 + vse8.v v13, (t4) + vnclipu.wi v15, v7, 0 + vse8.v v14, (t5) + vse8.v v15, (t6) ret endfunc -func ff_vc1_inv_trans_4x4_dc_rvv, zve32x - lh t2, (a2) - vsetivli zero, 4, e8, mf4, ta, ma - vlse32.v v0, (a0), a1 - slli t1, t2, 4 - add t2, t2, t1 - addi t2, t2, 4 - srai t2, t2, 3 - slli t1, t2, 4 - add t2, t2, t1 - addi t2, t2, 64 - srai t2, t2, 7 - vsetivli zero, 4*4, e16, m2, ta, ma - vzext.vf2 v2, v0 - vadd.vx v2, v2, t2 - vmax.vx v2, v2, zero - vsetvli zero, zero, e8, m1, ta, ma - vnclipu.wi v0, v2, 0 - vsetivli zero, 4, e8, mf4, ta, ma - vsse32.v v0, (a0), a1 +func ff_vc1_inv_trans_4x4_rvv, zve32x + lpad 0 + li a3, 8 * 2 + csrwi vxrm, 0 + vsetivli zero, 4, e16, mf2, ta, ma + vlsseg4e16.v v0, (a2), a3 + li t1, 3 + jal t0, ff_vc1_inv_trans_4_rvv + vssseg4e16.v v0, (a2), a3 + addi t1, a2, 2 * 4 * 2 + vle16.v v0, (a2) + addi t2, a2, 4 * 4 * 2 + vle16.v v1, (t1) + addi t3, a2, 6 * 4 * 2 + vle16.v v2, (t2) + vle16.v v3, (t3) + li t1, 7 + jal t0, ff_vc1_inv_trans_4_rvv + add t1, a1, a0 + vle8.v v8, (a0) + add t2, a1, t1 + vle8.v v9, (t1) + add t3, a1, t2 + vle8.v v10, (t2) + vle8.v v11, (t3) + vsetvli zero, zero, e8, mf4, ta, ma + vwaddu.wv v0, v0, v8 + vwaddu.wv v1, v1, v9 + vwaddu.wv v2, v2, v10 + vwaddu.wv v3, v3, v11 + vsetvli zero, zero, e16, mf2, ta, ma + .irp n,0,1,2,3 + vmax.vx v\n, v\n, zero + .endr + vsetvli zero, zero, e8, mf4, ta, ma + vnclipu.wi v8, v0, 0 + vnclipu.wi v9, v1, 0 + vse8.v v8, (a0) + vnclipu.wi v10, v2, 0 + vse8.v v9, (t1) + vnclipu.wi v11, v3, 0 + vse8.v v10, (t2) + vse8.v v11, (t3) ret endfunc + +.macro mspel_op op pos n1 n2 + add t1, \pos, a2 + v\op\()e8.v v\n1, (\pos) + sh1add \pos, a2, \pos + v\op\()e8.v v\n2, (t1) +.endm + +.macro mspel_op_all op pos a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 + mspel_op \op \pos \a1 \a2 + mspel_op \op \pos \a3 \a4 + mspel_op \op \pos \a5 \a6 + mspel_op \op \pos \a7 \a8 + mspel_op \op \pos \a9 \a10 + mspel_op \op \pos \a11 \a12 + mspel_op \op \pos \a13 \a14 + mspel_op \op \pos \a15 \a16 +.endm + +func ff_avg_pixels16x16_rvv, zve32x + lpad 0 + li t0, 16 + vsetivli zero, 16, e8, m1, ta, ma + j 1f +endfunc + +func ff_avg_pixels8x8_rvv, zve32x + lpad 0 + li t0, 8 + vsetivli zero, 8, e8, mf2, ta, ma +1: + csrwi vxrm, 0 +2: + vle8.v v16, (a1) + addi t0, t0, -1 + vle8.v v8, (a0) + add a1, a1, a2 + vaaddu.vv v16, v16, v8 + vse8.v v16, (a0) + add a0, a0, a2 + bnez t0, 2b + + ret +endfunc + +func ff_vc1_unescape_buffer_rvv, zve32x + lpad 0 + vsetivli zero, 2, e8, m1, ta, ma + vmv.v.i v8, -1 + li t4, 1 + vmv.v.i v12, -1 + li t3, -1 + mv t5, a2 + blez a1, 3f +1: + vsetvli t0, a1, e8, m4, ta, ma + vle8.v v16, (a0) + vslideup.vi v8, v16, 2 + addi t0, t0, -1 # we cannot fully process the last element + vslideup.vi v12, v16, 1 + vslide1down.vx v20, v16, t3 + vsetvli zero, t0, e8, m4, ta, ma + vmseq.vi v0, v8, 0 + vmseq.vi v1, v12, 0 + vmseq.vi v2, v16, 3 + vmand.mm v0, v0, v1 + vmsltu.vi v3, v20, 4 + vmand.mm v0, v0, v2 + vmand.mm v0, v0, v3 + vfirst.m t2, v0 + bgez t2, 4f # found an escape byte? + + vse8.v v16, (a2) + addi t2, t0, -2 + add a2, a2, t0 +2: + vslidedown.vx v8, v16, t2 + sub a1, a1, t0 + vslidedown.vi v12, v8, 1 + add a0, a0, t0 + bgtu a1, t4, 1b // size > 1 + + lb t0, (a0) + sb t0, (a2) # copy last byte (cannot be escaped) + addi a2, a2, 1 +3: + sub a0, a2, t5 + ret +4: + vsetvli zero, t2, e8, m4, ta, ma + vse8.v v16, (a2) + addi t0, t2, 1 + add a2, a2, t2 + addi t2, t2, -1 + vsetvli zero, t0, e8, m4, ta, ma + j 2b +endfunc diff --git a/libavcodec/riscv/videodsp.S b/libavcodec/riscv/videodsp.S new file mode 100644 index 000000000..011b85ffc --- /dev/null +++ b/libavcodec/riscv/videodsp.S @@ -0,0 +1,34 @@ +/* + * 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/riscv/asm.S" + +#if HAVE_RV_ZICBOP +func ff_prefetch_rv_zicbop, zicbop +1: + addi a2, a2, -1 + prefetch.r 0(a0) + add a0, a0, a1 + bnez a2, 1b + + ret +endfunc +#endif diff --git a/libavutil/sh4/bswap.h b/libavcodec/riscv/videodsp_init.c similarity index 59% rename from libavutil/sh4/bswap.h rename to libavcodec/riscv/videodsp_init.c index 48dd27f80..f2c9aae3c 100644 --- a/libavutil/sh4/bswap.h +++ b/libavcodec/riscv/videodsp_init.c @@ -16,33 +16,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file - * byte swapping routines - */ - -#ifndef AVUTIL_SH4_BSWAP_H -#define AVUTIL_SH4_BSWAP_H - -#include #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavcodec/videodsp.h" -#define av_bswap16 av_bswap16 -static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +void ff_prefetch_rv_zicbop(const uint8_t *mem, ptrdiff_t stride, int h); + +av_cold void ff_videodsp_init_riscv(VideoDSPContext *ctx, int bpc) { - __asm__("swap.b %0,%0" : "+r"(x)); - return x; +#if HAVE_RV_ZICBOP + /* TODO: Since we pay for the indirect function call anyway, we should + * only set this if Cache-Block Operation Prefetch (Zicbop) is actually + * supported and otherwise save a few cycles of NOPs. + * But so far there are no means to detect Zicbop (in user mode). + */ + ctx->prefetch = ff_prefetch_rv_zicbop; +#endif } - -#define av_bswap32 av_bswap32 -static av_always_inline av_const uint32_t av_bswap32(uint32_t x) -{ - __asm__("swap.b %0,%0\n" - "swap.w %0,%0\n" - "swap.b %0,%0\n" - : "+r"(x)); - return x; -} - -#endif /* AVUTIL_SH4_BSWAP_H */ diff --git a/libavcodec/riscv/vorbisdsp_init.c b/libavcodec/riscv/vorbisdsp_init.c index 0bbbcb68d..64c858dcb 100644 --- a/libavcodec/riscv/vorbisdsp_init.c +++ b/libavcodec/riscv/vorbisdsp_init.c @@ -31,7 +31,7 @@ av_cold void ff_vorbisdsp_init_riscv(VorbisDSPContext *c) #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) c->vorbis_inverse_coupling = ff_vorbis_inverse_coupling_rvv; #endif } diff --git a/libavcodec/riscv/vorbisdsp_rvv.S b/libavcodec/riscv/vorbisdsp_rvv.S index 81a6c62a6..82e577995 100644 --- a/libavcodec/riscv/vorbisdsp_rvv.S +++ b/libavcodec/riscv/vorbisdsp_rvv.S @@ -20,7 +20,8 @@ #include "libavutil/riscv/asm.S" -func ff_vorbis_inverse_coupling_rvv, zve32f +func ff_vorbis_inverse_coupling_rvv, zve32f, zba + lpad 0 fmv.w.x ft0, zero 1: vsetvli t0, a2, e32, m4, ta, ma diff --git a/libavcodec/riscv/vp7dsp_init.c b/libavcodec/riscv/vp7dsp_init.c new file mode 100644 index 000000000..e2771379e --- /dev/null +++ b/libavcodec/riscv/vp7dsp_init.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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 "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/riscv/cpu.h" +#include "libavcodec/vp8dsp.h" + +void ff_vp7_luma_dc_wht_rvv(int16_t block[4][4][16], int16_t dc[16]); +void ff_vp7_idct_add_rvv(uint8_t *dst, int16_t block[16], ptrdiff_t stride); +void ff_vp78_idct_dc_add_rvv(uint8_t *, int16_t block[16], ptrdiff_t, int dc); +void ff_vp7_idct_dc_add4y_rvv(uint8_t *dst, int16_t block[4][16], ptrdiff_t); +void ff_vp7_idct_dc_add4uv_rvv(uint8_t *dst, int16_t block[4][16], ptrdiff_t); + +static void ff_vp7_idct_dc_add_rvv(uint8_t *dst, int16_t block[16], + ptrdiff_t stride) +{ + int dc = (23170 * (23170 * block[0] >> 14) + 0x20000) >> 18; + + ff_vp78_idct_dc_add_rvv(dst, block, stride, dc); +} + +av_cold void ff_vp7dsp_init_riscv(VP8DSPContext *c) +{ +#if HAVE_RVV + int flags = av_get_cpu_flags(); + + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB) && + ff_rv_vlen_least(128)) { +#if __riscv_xlen >= 64 + c->vp8_luma_dc_wht = ff_vp7_luma_dc_wht_rvv; + c->vp8_idct_add = ff_vp7_idct_add_rvv; +#endif + c->vp8_idct_dc_add = ff_vp7_idct_dc_add_rvv; + c->vp8_idct_dc_add4y = ff_vp7_idct_dc_add4y_rvv; + if (flags & AV_CPU_FLAG_RVV_I64) + c->vp8_idct_dc_add4uv = ff_vp7_idct_dc_add4uv_rvv; + } +#endif +} diff --git a/libavcodec/riscv/vp7dsp_rvv.S b/libavcodec/riscv/vp7dsp_rvv.S new file mode 100644 index 000000000..aa0223bcb --- /dev/null +++ b/libavcodec/riscv/vp7dsp_rvv.S @@ -0,0 +1,150 @@ +/* + * Copyright (c) 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" + +#if __riscv_xlen >= 64 +func ff_vp7_luma_dc_wht_rvv, zve32x, zba + lpad 0 + li a2, 4 * 16 * 2 + li a7, 16 * 2 + jal t0, 1f + vsse16.v v4, (a0), a7 + vsse16.v v5, (t1), a7 + vsse16.v v6, (t2), a7 + vsse16.v v7, (t3), a7 + ret +1: + csrwi vxrm, 0 + li t4, 12540 + vsetivli zero, 4, e16, mf2, ta, ma + vlseg4e16.v v0, (a1) + li t6, 30274 + vwmul.vx v8, v1, t4 + li t5, 23170 + vwmul.vx v9, v3, t6 + addi t1, sp, -12 * 2 + vwmul.vx v10, v1, t6 + addi t2, sp, -8 * 2 + vwmul.vx v11, v3, t4 + addi t3, sp, -4 * 2 + vwadd.vv v4, v0, v2 + addi sp, sp, -16 * 2 + vwsub.vv v5, v0, v2 + vsetvli zero, zero, e32, m1, ta, ma + vadd.vv v7, v10, v11 + vmul.vx v4, v4, t5 + vsub.vv v6, v8, v9 + vmul.vx v5, v5, t5 + vadd.vv v0, v4, v7 + vsub.vv v3, v4, v7 + vadd.vv v1, v5, v6 + vsub.vv v2, v5, v6 + vsetvli zero, zero, e16, mf2, ta, ma + vnsra.wi v4, v0, 14 + vnsra.wi v7, v3, 14 + vnsra.wi v5, v1, 14 + vnsra.wi v6, v2, 14 + vsseg4e16.v v4, (sp) + vle16.v v0, (sp) + vle16.v v1, (t1) + vle16.v v2, (t2) + vle16.v v3, (t3) + vwmul.vx v8, v1, t4 + vwmul.vx v9, v3, t6 + add t1, a2, a0 + vwmul.vx v10, v1, t6 + sh1add t2, a2, a0 + vwmul.vx v11, v3, t4 + sh1add a2, a2, a2 # a2 *= 3 + vwadd.vv v4, v0, v2 + add t3, a2, a0 + vwsub.vv v5, v0, v2 + vsetvli zero, zero, e32, m1, ta, ma + vmul.vx v4, v4, t5 + sd zero, (a1) + vadd.vv v7, v10, v11 + sd zero, 8(a1) + vmul.vx v5, v5, t5 + sd zero, 16(a1) + vsub.vv v6, v8, v9 + sd zero, 24(a1) + vadd.vv v0, v4, v7 + addi sp, sp, 16 * 2 + vsub.vv v3, v4, v7 + vadd.vv v1, v5, v6 + vsub.vv v2, v5, v6 + vsetvli zero, zero, e16, mf2, ta, ma + vnclip.wi v4, v0, 18 + vnclip.wi v5, v1, 18 + vnclip.wi v6, v2, 18 + vnclip.wi v7, v3, 18 + jr t0 +endfunc + +func ff_vp7_idct_add_rvv, zve32x + lpad 0 + jal t0, 1b + csrwi vxrm, 2 + vsetvli zero, zero, e8, mf4, ta, ma + vle8.v v12, (a0) + vle8.v v13, (t1) + vwaddu.wv v4, v4, v12 + vle8.v v14, (t2) + vwaddu.wv v5, v5, v13 + vle8.v v15, (t3) + vwaddu.wv v6, v6, v14 + vwaddu.wv v7, v7, v15 + vsetvli zero, zero, e16, mf2, ta, ma + vmax.vx v4, v4, zero + vmax.vx v5, v5, zero + vmax.vx v6, v6, zero + vmax.vx v7, v7, zero + vsetvli zero, zero, e8, mf4, ta, ma + vnclipu.wi v0, v4, 0 + vnclipu.wi v1, v5, 0 + vse8.v v0, (a0) + vnclipu.wi v2, v6, 0 + vse8.v v1, (t1) + vnclipu.wi v3, v7, 0 + vse8.v v2, (t2) + vse8.v v3, (t3) + ret +endfunc +#endif + +.irp type, y, uv +func ff_vp7_idct_dc_add4\type\()_rvv, zve32x + lpad 0 + li t0, 32 + vsetivli zero, 4, e16, mf2, ta, ma + li t1, 23170 + vlse16.v v8, (a1), t0 # block[0..3][0] + vwmul.vx v0, v8, t1 + li t2, 0x20000 - (128 << 18) + vsetvli zero, zero, e32, m1, ta, ma + vsra.vi v0, v0, 14 + vmul.vx v0, v0, t1 + vadd.vx v0, v0, t2 + vsetvli zero, zero, e16, mf2, ta, ma + vnsra.wi v8, v0, 18 # 4x DC + tail ff_vp78_idct_dc_add4\type\()_rvv +endfunc +.endr diff --git a/libavcodec/riscv/vp8dsp.h b/libavcodec/riscv/vp8dsp.h new file mode 100644 index 000000000..971c5c0a9 --- /dev/null +++ b/libavcodec/riscv/vp8dsp.h @@ -0,0 +1,75 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_VP8DSP_H +#define AVCODEC_RISCV_VP8DSP_H + +#include "libavcodec/vp8dsp.h" + +#define VP8_LF_Y(hv, inner, opt) \ + void ff_vp8_##hv##_loop_filter16##inner##_##opt(uint8_t *dst, \ + ptrdiff_t stride, \ + int flim_E, int flim_I, \ + int hev_thresh) + +#define VP8_LF_UV(hv, inner, opt) \ + void ff_vp8_##hv##_loop_filter8uv##inner##_##opt(uint8_t *dstU, \ + uint8_t *dstV, \ + ptrdiff_t stride, \ + int flim_E, int flim_I, \ + int hev_thresh) + +#define VP8_LF_SIMPLE(hv, opt) \ + void ff_vp8_##hv##_loop_filter16_simple_##opt(uint8_t *dst, \ + ptrdiff_t stride, \ + int flim) + +#define VP8_LF_HV(inner, opt) \ + VP8_LF_Y(h, inner, opt); \ + VP8_LF_Y(v, inner, opt); \ + VP8_LF_UV(h, inner, opt); \ + VP8_LF_UV(v, inner, opt) + +#define VP8_LF(opt) \ + VP8_LF_HV(, opt); \ + VP8_LF_HV(_inner, opt); \ + VP8_LF_SIMPLE(h, opt); \ + VP8_LF_SIMPLE(v, opt) + +#define VP8_MC(n, opt) \ + void ff_put_vp8_##n##_##opt(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride,\ + int h, int x, int y) + +#define VP8_EPEL(w, opt) \ + VP8_MC(pixels ## w, opt); \ + VP8_MC(epel ## w ## _h4, opt); \ + VP8_MC(epel ## w ## _h6, opt); \ + VP8_MC(epel ## w ## _v4, opt); \ + VP8_MC(epel ## w ## _h4v4, opt); \ + VP8_MC(epel ## w ## _h6v4, opt); \ + VP8_MC(epel ## w ## _v6, opt); \ + VP8_MC(epel ## w ## _h4v6, opt); \ + VP8_MC(epel ## w ## _h6v6, opt) + +#define VP8_BILIN(w, opt) \ + VP8_MC(bilin ## w ## _h, opt); \ + VP8_MC(bilin ## w ## _v, opt); \ + VP8_MC(bilin ## w ## _hv, opt) + +#endif /* AVCODEC_RISCV_VP8DSP_H */ diff --git a/libavcodec/riscv/vp8dsp_init.c b/libavcodec/riscv/vp8dsp_init.c index af57aabb7..250fecb2f 100644 --- a/libavcodec/riscv/vp8dsp_init.c +++ b/libavcodec/riscv/vp8dsp_init.c @@ -24,22 +24,117 @@ #include "libavutil/cpu.h" #include "libavutil/riscv/cpu.h" #include "libavcodec/vp8dsp.h" +#include "vp8dsp.h" +void ff_vp8_luma_dc_wht_rvv(int16_t block[4][4][16], int16_t dc[16]); +void ff_vp8_idct_add_rvv(uint8_t *dst, int16_t block[16], ptrdiff_t stride); void ff_vp8_idct_dc_add_rvv(uint8_t *dst, int16_t block[16], ptrdiff_t stride); void ff_vp8_idct_dc_add4y_rvv(uint8_t *dst, int16_t block[4][16], ptrdiff_t stride); void ff_vp8_idct_dc_add4uv_rvv(uint8_t *dst, int16_t block[4][16], ptrdiff_t stride); +VP8_EPEL(16, rvi); +VP8_EPEL(8, rvi); +VP8_EPEL(4, rvi); +VP8_EPEL(16, rvv); +VP8_EPEL(8, rvv); +VP8_EPEL(4, rvv); + +VP8_BILIN(16, rvv); +VP8_BILIN(8, rvv); +VP8_BILIN(4, rvv); + +av_cold void ff_vp78dsp_init_riscv(VP8DSPContext *c) +{ +#if HAVE_RV + int flags = av_get_cpu_flags(); + if (flags & AV_CPU_FLAG_RV_MISALIGNED) { +#if __riscv_xlen >= 64 + c->put_vp8_epel_pixels_tab[0][0][0] = ff_put_vp8_pixels16_rvi; + c->put_vp8_epel_pixels_tab[1][0][0] = ff_put_vp8_pixels8_rvi; + c->put_vp8_bilinear_pixels_tab[0][0][0] = ff_put_vp8_pixels16_rvi; + c->put_vp8_bilinear_pixels_tab[1][0][0] = ff_put_vp8_pixels8_rvi; +#endif + c->put_vp8_epel_pixels_tab[2][0][0] = ff_put_vp8_pixels4_rvi; + c->put_vp8_bilinear_pixels_tab[2][0][0] = ff_put_vp8_pixels4_rvi; + } +#if HAVE_RVV + if (flags & AV_CPU_FLAG_RVV_I32 && ff_rv_vlen_least(128)) { + c->put_vp8_bilinear_pixels_tab[0][0][1] = ff_put_vp8_bilin16_h_rvv; + c->put_vp8_bilinear_pixels_tab[0][0][2] = ff_put_vp8_bilin16_h_rvv; + c->put_vp8_bilinear_pixels_tab[1][0][1] = ff_put_vp8_bilin8_h_rvv; + c->put_vp8_bilinear_pixels_tab[1][0][2] = ff_put_vp8_bilin8_h_rvv; + c->put_vp8_bilinear_pixels_tab[2][0][1] = ff_put_vp8_bilin4_h_rvv; + c->put_vp8_bilinear_pixels_tab[2][0][2] = ff_put_vp8_bilin4_h_rvv; + + c->put_vp8_bilinear_pixels_tab[0][1][0] = ff_put_vp8_bilin16_v_rvv; + c->put_vp8_bilinear_pixels_tab[0][2][0] = ff_put_vp8_bilin16_v_rvv; + c->put_vp8_bilinear_pixels_tab[1][1][0] = ff_put_vp8_bilin8_v_rvv; + c->put_vp8_bilinear_pixels_tab[1][2][0] = ff_put_vp8_bilin8_v_rvv; + c->put_vp8_bilinear_pixels_tab[2][1][0] = ff_put_vp8_bilin4_v_rvv; + c->put_vp8_bilinear_pixels_tab[2][2][0] = ff_put_vp8_bilin4_v_rvv; + + c->put_vp8_bilinear_pixels_tab[0][1][1] = ff_put_vp8_bilin16_hv_rvv; + c->put_vp8_bilinear_pixels_tab[0][1][2] = ff_put_vp8_bilin16_hv_rvv; + c->put_vp8_bilinear_pixels_tab[0][2][1] = ff_put_vp8_bilin16_hv_rvv; + c->put_vp8_bilinear_pixels_tab[0][2][2] = ff_put_vp8_bilin16_hv_rvv; + c->put_vp8_bilinear_pixels_tab[1][1][1] = ff_put_vp8_bilin8_hv_rvv; + c->put_vp8_bilinear_pixels_tab[1][1][2] = ff_put_vp8_bilin8_hv_rvv; + c->put_vp8_bilinear_pixels_tab[1][2][1] = ff_put_vp8_bilin8_hv_rvv; + c->put_vp8_bilinear_pixels_tab[1][2][2] = ff_put_vp8_bilin8_hv_rvv; + c->put_vp8_bilinear_pixels_tab[2][1][1] = ff_put_vp8_bilin4_hv_rvv; + c->put_vp8_bilinear_pixels_tab[2][1][2] = ff_put_vp8_bilin4_hv_rvv; + c->put_vp8_bilinear_pixels_tab[2][2][1] = ff_put_vp8_bilin4_hv_rvv; + c->put_vp8_bilinear_pixels_tab[2][2][2] = ff_put_vp8_bilin4_hv_rvv; + + if (flags & AV_CPU_FLAG_RVB) { + 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 + } + } +#endif +#endif +} + av_cold void ff_vp8dsp_init_riscv(VP8DSPContext *c) { #if HAVE_RVV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVV_I32 && ff_get_rv_vlenb() >= 16) { + if (flags & AV_CPU_FLAG_RVV_I32 && ff_rv_vlen_least(128)) { +#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; 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_RVB_ADDR) { + if (flags & AV_CPU_FLAG_RVV_I64) c->vp8_idct_dc_add4uv = ff_vp8_idct_dc_add4uv_rvv; - } } #endif } diff --git a/libavcodec/riscv/vp8dsp_rvi.S b/libavcodec/riscv/vp8dsp_rvi.S new file mode 100644 index 000000000..07d5c8503 --- /dev/null +++ b/libavcodec/riscv/vp8dsp_rvi.S @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Institue 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" + +#if __riscv_xlen >= 64 +func ff_put_vp8_pixels16_rvi + lpad 0 +1: + addi a4, a4, -1 + ld t0, (a2) + ld t1, 8(a2) + sd t0, (a0) + sd t1, 8(a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc + +func ff_put_vp8_pixels8_rvi + lpad 0 +1: + addi a4, a4, -1 + ld t0, (a2) + sd t0, (a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc +#endif + +func ff_put_vp8_pixels4_rvi + lpad 0 +1: + addi a4, a4, -1 + lw t0, (a2) + sw t0, (a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc diff --git a/libavcodec/riscv/vp8dsp_rvv.S b/libavcodec/riscv/vp8dsp_rvv.S index 8a0773f96..a8b3e239b 100644 --- a/libavcodec/riscv/vp8dsp_rvv.S +++ b/libavcodec/riscv/vp8dsp_rvv.S @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright © 2024 Rémi Denis-Courmont. * * This file is part of FFmpeg. * @@ -20,54 +21,531 @@ #include "libavutil/riscv/asm.S" -.macro vp8_idct_dc_add - vlse32.v v0, (a0), a2 - lh a5, 0(a1) - sh zero, 0(a1) - addi a5, a5, 4 - srai t1, a5, 3 - vsetivli zero, 4*4, e16, m2, ta, ma - vzext.vf2 v2, v0 - vadd.vx v2, v2, t1 - vmax.vx v2, v2, zero - vsetvli zero, zero, e8, m1, ta, ma - vnclipu.wi v0, v2, 0 - vsetivli zero, 4, e8, mf4, ta, ma - vsse32.v v0, (a0), a2 +.macro vsetvlstatic8 len +.if \len <= 4 + vsetivli zero, \len, e8, mf4, ta, ma +.elseif \len <= 8 + vsetivli zero, \len, e8, mf2, ta, ma +.elseif \len <= 16 + vsetivli zero, \len, e8, m1, ta, ma +.elseif \len <= 31 + vsetivli zero, \len, e8, m2, ta, ma +.endif .endm -.macro vp8_idct_dc_addy - vp8_idct_dc_add - addi a0, a0, 4 - addi a1, a1, 32 +.macro vsetvlstatic16 len +.if \len <= 4 + vsetivli zero, \len, e16, mf2, ta, ma +.elseif \len <= 8 + vsetivli zero, \len, e16, m1, ta, ma +.elseif \len <= 16 + vsetivli zero, \len, e16, m2, ta, ma +.endif .endm +#if __riscv_xlen >= 64 +func ff_vp8_luma_dc_wht_rvv, zve64x + lpad 0 + vsetivli zero, 1, e64, m1, ta, ma + vlseg4e64.v v4, (a1) + vsetivli zero, 4, e16, mf2, ta, ma + vwadd.vv v1, v5, v6 + addi t1, sp, -48 + vwadd.vv v0, v4, v7 + addi t2, sp, -32 + vwsub.vv v2, v5, v6 + addi t3, sp, -16 + vwsub.vv v3, v4, v7 + addi sp, sp, -64 + vsetvli zero, zero, e32, m1, ta, ma + vadd.vv v4, v0, v1 + vadd.vv v5, v3, v2 + vse32.v v4, (sp) + vsub.vv v6, v0, v1 + vse32.v v5, (t1) + vsub.vv v7, v3, v2 + vse32.v v6, (t2) + vse32.v v7, (t3) + vlseg4e32.v v4, (sp) + vadd.vv v0, v4, v7 + sd zero, (a1) + vadd.vv v1, v5, v6 + sd zero, 8(a1) + vsub.vv v2, v5, v6 + sd zero, 16(a1) + vsub.vv v3, v4, v7 + sd zero, 24(a1) + vadd.vi v0, v0, 3 # rounding mode not supported, do it manually + li t0, 4 * 16 * 2 + vadd.vi v3, v3, 3 + addi t1, a0, 16 * 2 + vadd.vv v4, v0, v1 + addi t2, a0, 16 * 2 * 2 + vadd.vv v5, v3, v2 + addi t3, a0, 16 * 2 * 3 + vsub.vv v6, v0, v1 + vsub.vv v7, v3, v2 + vsetvli zero, zero, e16, mf2, ta, ma + vnsra.wi v0, v4, 3 + addi sp, sp, 64 + vnsra.wi v1, v5, 3 + vsse16.v v0, (a0), t0 + vnsra.wi v2, v6, 3 + vsse16.v v1, (t1), t0 + vnsra.wi v3, v7, 3 + vsse16.v v2, (t2), t0 + vsse16.v v3, (t3), t0 + ret +endfunc +#endif + +func ff_vp8_idct_add_rvv, zve32x + lpad 0 + csrwi vxrm, 0 + vsetivli zero, 4, e16, mf2, ta, ma + addi a3, a1, 1 * 4 * 2 + addi a4, a1, 2 * 4 * 2 + addi a5, a1, 3 * 4 * 2 + li t1, 20091 + li t2, 35468 + jal t0, 1f + vsseg4e16.v v0, (a1) + jal t0, 1f + vlsseg4e8.v v4, (a0), a2 + vssra.vi v0, v0, 3 + sd zero, (a1) + vssra.vi v1, v1, 3 + sd zero, 8(a1) + vssra.vi v2, v2, 3 + sd zero, 16(a1) + vssra.vi v3, v3, 3 + sd zero, 24(a1) + vsetvli zero, zero, e8, mf4, ta, ma + vwaddu.wv v0, v0, v4 + vwaddu.wv v1, v1, v5 + vwaddu.wv v2, v2, v6 + vwaddu.wv v3, v3, v7 + vsetvli zero, zero, e16, mf2, ta, ma + vmax.vx v0, v0, zero + vmax.vx v1, v1, zero + vmax.vx v2, v2, zero + vmax.vx v3, v3, zero + vsetvli zero, zero, e8, mf4, ta, ma + vnclipu.wi v4, v0, 0 + vnclipu.wi v5, v1, 0 + vnclipu.wi v6, v2, 0 + vnclipu.wi v7, v3, 0 + vssseg4e8.v v4, (a0), a2 + ret +1: + vle16.v v0, (a1) + vle16.v v2, (a4) + vle16.v v1, (a3) + vle16.v v3, (a5) + vadd.vv v4, v0, v2 # t0 + vsub.vv v5, v0, v2 # t1 + vmulhsu.vx v8, v3, t1 + vmulhsu.vx v6, v1, t2 + vadd.vv v8, v8, v3 + vmulhsu.vx v7, v1, t1 + vmulhsu.vx v9, v3, t2 + vadd.vv v7, v7, v1 + vsub.vv v6, v6, v8 # t2 + vadd.vv v7, v7, v9 # t3 + vadd.vv v1, v5, v6 + vsub.vv v2, v5, v6 + vadd.vv v0, v4, v7 + vsub.vv v3, v4, v7 + jr t0 +endfunc + func ff_vp8_idct_dc_add_rvv, zve32x - vsetivli zero, 4, e8, mf4, ta, ma - vp8_idct_dc_add + lpad 0 + lh a3, (a1) + addi a3, a3, 4 + srai a3, a3, 3 + # fall through +endfunc +# a3 = DC +func ff_vp78_idct_dc_add_rvv, zve32x + vsetivli zero, 4, e8, mf4, ta, ma + sh zero, (a1) + vlse32.v v8, (a0), a2 + vsetivli zero, 16, e8, m1, ta, ma + bgez a3, 1f + + # block[0] < 0 + neg a3, a3 + vssubu.vx v8, v8, a3 + vsetivli zero, 4, e8, mf4, ta, ma + vsse32.v v8, (a0), a2 + ret + +1: # block[0] >= 0 + vsaddu.vx v8, v8, a3 + vsetivli zero, 4, e8, mf4, ta, ma + vsse32.v v8, (a0), a2 ret endfunc func ff_vp8_idct_dc_add4y_rvv, zve32x - vsetivli zero, 4, e8, mf4, ta, ma - .rept 3 - vp8_idct_dc_addy - .endr - vp8_idct_dc_add + lpad 0 + li t0, 32 + vsetivli zero, 4, e16, mf2, ta, ma + li t1, 4 - (128 << 3) + vlse16.v v8, (a1), t0 + vadd.vx v8, v8, t1 + vsra.vi v8, v8, 3 + # fall through +endfunc + + .variant_cc ff_vp78_idct_dc_add4y_rvv +# v8 = [dc0 - 128, dc1 - 128, dc2 - 128, dc3 - 128] +func ff_vp78_idct_dc_add4y_rvv, zve32x + vsetivli zero, 16, e16, m2, ta, ma + vid.v v4 + li a4, 4 + vsrl.vi v4, v4, 2 + li t1, 128 + vrgather.vv v0, v8, v4 # replicate each DC four times + vsetvli zero, zero, e8, m1, ta, ma +1: + vle8.v v8, (a0) + addi a4, a4, -1 + vwaddu.wv v16, v0, v8 + sh zero, (a1) + vnclip.wi v8, v16, 0 + addi a1, a1, 32 + vxor.vx v8, v8, t1 + vse8.v v8, (a0) + add a0, a0, a2 + bnez a4, 1b ret endfunc func ff_vp8_idct_dc_add4uv_rvv, zve32x - vsetivli zero, 4, e8, mf4, ta, ma - vp8_idct_dc_addy - vp8_idct_dc_add - addi a0, a0, -4 - sh2add a0, a2, a0 - addi a1, a1, 32 - vp8_idct_dc_addy - vp8_idct_dc_add + lpad 0 + li t0, 32 + vsetivli zero, 4, e16, mf2, ta, ma + li t1, 4 - (128 << 3) + vlse16.v v8, (a1), t0 + vadd.vx v8, v8, t1 + vsra.vi v8, v8, 3 + # fall through +endfunc + + .variant_cc ff_vp78_idct_dc_add4uv_rvv +func ff_vp78_idct_dc_add4uv_rvv, zve64x + vsetivli zero, 16, e16, m2, ta, ma + vid.v v4 + li a4, 4 + vsrl.vi v4, v4, 2 + li t1, 128 + vrgather.vv v0, v8, v4 # replicate each DC four times + slli t2, a2, 2 + vsetivli zero, 2, e64, m1, ta, ma +1: + vlse64.v v8, (a0), t2 + addi a4, a4, -1 + vsetivli zero, 16, e8, m1, ta, ma + vwaddu.wv v16, v0, v8 + sh zero, (a1) + vnclip.wi v8, v16, 0 + addi a1, a1, 32 + vxor.vx v8, v8, t1 + vsetivli zero, 2, e64, m1, ta, ma + vsse64.v v8, (a0), t2 + add a0, a0, a2 + bnez a4, 1b ret endfunc + +.macro bilin_load_h dst mn + addi t5, a2, 1 + vle8.v \dst, (a2) + vle8.v v2, (t5) + vwmulu.vx v28, \dst, t1 + vwmaccu.vx v28, \mn, v2 + vwaddu.wx v24, v28, t4 + vnsra.wi \dst, v24, 3 +.endm + +.macro put_vp8_bilin_h_v type mn +func ff_put_vp8_bilin4_\type\()_rvv, zve32x + lpad 0 + vsetvlstatic8 4 +.Lbilin_\type: + li t1, 8 + li t4, 4 + sub t1, t1, \mn +1: + add t0, a2, a3 + add t2, a0, a1 + addi a4, a4, -2 +.ifc \type,v + add t3, t0, a3 +.else + addi t5, a2, 1 + addi t3, t0, 1 + vle8.v v2, (t5) +.endif + vle8.v v0, (a2) + vle8.v v4, (t0) + vle8.v v6, (t3) + vwmulu.vx v28, v0, t1 + vwmulu.vx v26, v4, t1 +.ifc \type,v + vwmaccu.vx v28, \mn, v4 +.else + vwmaccu.vx v28, \mn, v2 +.endif + vwmaccu.vx v26, \mn, v6 + vwaddu.wx v24, v28, t4 + vwaddu.wx v22, v26, t4 + vnsra.wi v30, v24, 3 + vnsra.wi v0, v22, 3 + vse8.v v30, (a0) + vse8.v v0, (t2) + add a2, t0, a3 + add a0, t2, a1 + bnez a4, 1b + + ret +endfunc +.endm + +put_vp8_bilin_h_v h a5 +put_vp8_bilin_h_v v a6 + +func ff_put_vp8_bilin4_hv_rvv, zve32x + lpad 0 + vsetvlstatic8 4 +.Lbilin_hv: + li t3, 8 + sub t1, t3, a5 + sub t2, t3, a6 + li t4, 4 + bilin_load_h v4, a5 + add a2, a2, a3 +1: + addi a4, a4, -1 + vwmulu.vx v20, v4, t2 + bilin_load_h v4, a5 + vwmaccu.vx v20, a6, v4 + vwaddu.wx v24, v20, t4 + vnsra.wi v0, v24, 3 + vse8.v v0, (a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc + +.irp len,16,8 +func ff_put_vp8_bilin\len\()_h_rvv, zve32x + lpad 0 + vsetvlstatic8 \len + j .Lbilin_h +endfunc + +func ff_put_vp8_bilin\len\()_v_rvv, zve32x + lpad 0 + vsetvlstatic8 \len + j .Lbilin_v +endfunc + +func ff_put_vp8_bilin\len\()_hv_rvv, zve32x + lpad 0 + vsetvlstatic8 \len + j .Lbilin_hv +endfunc +.endr + +const subpel_filters + .byte 0, -6, 123, 12, -1, 0 + .byte 2, -11, 108, 36, -8, 1 + .byte 0, -9, 93, 50, -6, 0 + .byte 3, -16, 77, 77, -16, 3 + .byte 0, -6, 50, 93, -9, 0 + .byte 1, -8, 36, 108, -11, 2 + .byte 0, -1, 12, 123, -6, 0 +endconst + +.macro epel_filter size type regtype +.ifc \type,v + addi \regtype\()0, a6, -1 +.else + addi \regtype\()0, a5, -1 +.endif + lla \regtype\()2, subpel_filters + sh1add \regtype\()0, \regtype\()0, \regtype\()0 + sh1add \regtype\()0, \regtype\()0, \regtype\()2 + .irp n,1,2,3,4 + lb \regtype\n, \n(\regtype\()0) + .endr +.ifc \size,6 + lb \regtype\()5, 5(\regtype\()0) + lb \regtype\()0, (\regtype\()0) +.endif +.endm + +.macro epel_load dst len size type from_mem regtype +.ifc \type,v + sub t6, a2, a3 + add a7, a2, a3 +.else + addi t6, a2, -1 + addi a7, a2, 1 +.endif + +.if \from_mem + vle8.v v24, (a2) + vle8.v v22, (t6) + vle8.v v26, (a7) +.ifc \type,v + add a7, a7, a3 +.else + addi a7, a7, 1 +.endif + vle8.v v28, (a7) + vwmulu.vx v16, v24, \regtype\()2 + vwmulu.vx v20, v26, \regtype\()3 +.ifc \size,6 +.ifc \type,v + sub t6, t6, a3 + add a7, a7, a3 +.else + addi t6, t6, -1 + addi a7, a7, 1 +.endif + vle8.v v24, (t6) + vle8.v v26, (a7) + vwmaccu.vx v16, \regtype\()0, v24 + vwmaccu.vx v16, \regtype\()5, v26 +.endif + vwmaccsu.vx v16, \regtype\()1, v22 + vwmaccsu.vx v16, \regtype\()4, v28 +.else + vwmulu.vx v16, v4, \regtype\()2 + vwmulu.vx v20, v6, \regtype\()3 + .ifc \size,6 + vwmaccu.vx v16, \regtype\()0, v0 + vwmaccu.vx v16, \regtype\()5, v10 + .endif + vwmaccsu.vx v16, \regtype\()1, v2 + vwmaccsu.vx v16, \regtype\()4, v8 +.endif + li t6, 64 + vwadd.wx v16, v16, t6 + vsetvlstatic16 \len + vwadd.vv v24, v16, v20 + vnsra.wi v24, v24, 7 + vmax.vx v24, v24, zero + vsetvlstatic8 \len + vnclipu.wi \dst, v24, 0 +.endm + +.macro epel_load_inc dst len size type from_mem regtype + epel_load \dst \len \size \type \from_mem \regtype + add a2, a2, a3 +.endm + +.macro epel len size type +func ff_put_vp8_epel\len\()_\type\()\size\()_rvv, zve32x, zba + lpad 0 + epel_filter \size \type t + vsetvlstatic8 \len +1: + addi a4, a4, -1 + epel_load_inc v30 \len \size \type 1 t + vse8.v v30, (a0) + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc +.endm + +.macro epel_hv len hsize vsize +func ff_put_vp8_epel\len\()_h\hsize\()v\vsize\()_rvv, zve32x, zba + lpad 0 +#if __riscv_xlen == 64 + addi sp, sp, -48 + .irp n,0,1,2,3,4,5 + sd s\n, (\n * 8)(sp) + .endr +#else + addi sp, sp, -32 + .irp n,0,1,2,3,4,5 + sw s\n, (\n * 4)(sp) + .endr +#endif + sub a2, a2, a3 + epel_filter \hsize h t + epel_filter \vsize v s + vsetvlstatic8 \len +.if \hsize == 6 || \vsize == 6 + sub a2, a2, a3 + epel_load_inc v0 \len \hsize h 1 t +.endif + epel_load_inc v2 \len \hsize h 1 t + epel_load_inc v4 \len \hsize h 1 t + epel_load_inc v6 \len \hsize h 1 t + epel_load_inc v8 \len \hsize h 1 t +.if \hsize == 6 || \vsize == 6 + epel_load_inc v10 \len \hsize h 1 t +.endif + addi a4, a4, -1 +1: + addi a4, a4, -1 + epel_load v30 \len \vsize v 0 s + vse8.v v30, (a0) +.if \hsize == 6 || \vsize == 6 + vmv.v.v v0, v2 +.endif + vmv.v.v v2, v4 + vmv.v.v v4, v6 + vmv.v.v v6, v8 +.if \hsize == 6 || \vsize == 6 + vmv.v.v v8, v10 + epel_load_inc v10 \len \hsize h 1 t +.else + epel_load_inc v8 \len 4 h 1 t +.endif + add a0, a0, a1 + bnez a4, 1b + epel_load v30 \len \vsize v 0 s + vse8.v v30, (a0) + +#if __riscv_xlen == 64 + .irp n,0,1,2,3,4,5 + ld s\n, (\n * 8)(sp) + .endr + addi sp, sp, 48 +#else + .irp n,0,1,2,3,4,5 + lw s\n, (\n * 4)(sp) + .endr + addi sp, sp, 32 +#endif + + ret +endfunc +.endm + +.irp len,16,8,4 +epel \len 6 h +epel \len 4 h +epel \len 6 v +epel \len 4 v +#if __riscv_xlen <= 64 +epel_hv \len 6 6 +epel_hv \len 4 4 +epel_hv \len 6 4 +epel_hv \len 4 6 +#endif +.endr diff --git a/libavcodec/riscv/vp9_intra_rvv.S b/libavcodec/riscv/vp9_intra_rvv.S new file mode 100644 index 000000000..13d695c83 --- /dev/null +++ b/libavcodec/riscv/vp9_intra_rvv.S @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2024 Institue 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 avgdc size + vwredsumu.vs v16, v8, v16 + vsetivli zero, 1, e16, m1, ta, ma + vmv.x.s t1, v16 + addi t1, t1, 1 << (\size - 1) + srai t1, t1, \size +.endm + +.macro getdc type size +.ifc \type,top + vmv.v.x v16, zero + vle8.v v8, (a3) + avgdc \size +.else +.ifc \type,left + vmv.v.x v16, zero + vle8.v v8, (a2) + avgdc \size +.else +.ifc \type,dc + vmv.v.x v16, zero + vle8.v v8, (a2) + vwredsumu.vs v16, v8, v16 + vle8.v v8, (a3) + avgdc \size +.else + li t1, \type +.endif +.endif +.endif +.endm + +.macro dc_e32 type size n restore +.ifc \size,32 + li t0, 32 + vsetvli zero, t0, e8, m2, ta, ma +.else + vsetivli zero, 16, e8, m1, ta, ma +.endif + getdc \type \n + +.if \restore == 1 && \size == 32 + vsetvli zero, t0, e8, m2, ta, ma +.elseif \restore == 1 && \size == 16 + vsetivli zero, 16, e8, m1, ta, ma +.endif + vmv.v.x v0, t1 + + .rept \size + vse8.v v0, (a0) + add a0, a0, a1 + .endr + + ret +.endm + +.macro dc_e64 type size n restore + vsetivli zero, 8, e8, mf2, ta, ma + getdc \type \n + + li t0, 64 + vsetvli zero, t0, e8, m4, ta, ma + vmv.v.x v0, t1 + vsetivli zero, 8, e8, mf2, ta, ma + vsse64.v v0, (a0), a1 + + ret +.endm + +.macro func_dc name size type n restore ext +func ff_\()\name\()_\()\size\()x\size\()_rvv, \ext + lpad 0 +.if \size == 8 + dc_e64 \type \size \n \restore +.else + dc_e32 \type \size \n \restore +.endif +endfunc +.endm + +func_dc dc_127 32 127 0 0 zve32x +func_dc dc_127 16 127 0 0 zve32x +func_dc dc_127 8 127 0 0 zve64x +func_dc dc_128 32 128 0 0 zve32x +func_dc dc_128 16 128 0 0 zve32x +func_dc dc_128 8 128 0 0 zve64x +func_dc dc_129 32 129 0 0 zve32x +func_dc dc_129 16 129 0 0 zve32x +func_dc dc_129 8 129 0 0 zve64x +func_dc dc 32 dc 6 1 zve32x +func_dc dc 16 dc 5 1 zve32x +func_dc dc 8 dc 4 0 zve64x +func_dc dc_left 32 left 5 1 zve32x +func_dc dc_left 16 left 4 1 zve32x +func_dc dc_left 8 left 3 0 zve64x +func_dc dc_top 32 top 5 1 zve32x +func_dc dc_top 16 top 4 1 zve32x +func_dc dc_top 8 top 3 0 zve64x + +func ff_h_32x32_rvv, zve32x + lpad 0 + li t0, 32 + addi a2, a2, 31 + vsetvli zero, t0, e8, m2, ta, ma + + .rept 2 + .irp n, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 + lbu t1, (a2) + addi a2, a2, -1 + vmv.v.x v\n, t1 + .endr + .irp n, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 + vse8.v v\n, (a0) + add a0, a0, a1 + .endr + .endr + + ret +endfunc + +func ff_h_16x16_rvv, zve32x + lpad 0 + addi a2, a2, 15 + vsetivli zero, 16, e8, m1, ta, ma + + .irp n, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 + lbu t1, (a2) + addi a2, a2, -1 + vmv.v.x v\n, t1 + .endr + .irp n, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 + vse8.v v\n, (a0) + add a0, a0, a1 + .endr + vse8.v v23, (a0) + + ret +endfunc + +func ff_h_8x8_rvv, zve32x + lpad 0 + addi a2, a2, 7 + vsetivli zero, 8, e8, mf2, ta, ma + + .irp n, 8, 9, 10, 11, 12, 13, 14, 15 + lbu t1, (a2) + addi a2, a2, -1 + vmv.v.x v\n, t1 + .endr + .irp n, 8, 9, 10, 11, 12, 13, 14 + vse8.v v\n, (a0) + add a0, a0, a1 + .endr + vse8.v v15, (a0) + + ret +endfunc + +.macro tm_sum4 dst1, dst2, dst3, dst4, top, n1 + lbu t1, \n1(a2) + lbu t2, (\n1-1)(a2) + lbu t3, (\n1-2)(a2) + lbu t4, (\n1-3)(a2) + sub t1, t1, a4 + sub t2, t2, a4 + sub t3, t3, a4 + sub t4, t4, a4 + vadd.vx \dst1, \top, t1 + vadd.vx \dst2, \top, t2 + vadd.vx \dst3, \top, t3 + vadd.vx \dst4, \top, t4 +.endm + +func ff_tm_32x32_rvv, zve32x + lpad 0 + lbu a4, -1(a3) + li t5, 32 + + .irp offset, 31, 23, 15, 7 + vsetvli zero, t5, e16, m4, ta, ma + vle8.v v8, (a3) + vzext.vf2 v28, v8 + + tm_sum4 v0, v4, v8, v12, v28, \offset + tm_sum4 v16, v20, v24, v28, v28, (\offset-4) + + .irp n, 0, 4, 8, 12, 16, 20, 24, 28 + vmax.vx v\n, v\n, zero + .endr + + vsetvli zero, zero, e8, m2, ta, ma + .irp n, 0, 4, 8, 12, 16, 20, 24, 28 + vnclipu.wi v\n, v\n, 0 + vse8.v v\n, (a0) + add a0, a0, a1 + .endr + .endr + + ret +endfunc + +func ff_tm_16x16_rvv, zve32x + vsetivli zero, 16, e16, m2, ta, ma + vle8.v v8, (a3) + vzext.vf2 v30, v8 + lbu a4, -1(a3) + + tm_sum4 v0, v2, v4, v6, v30, 15 + tm_sum4 v8, v10, v12, v14, v30, 11 + tm_sum4 v16, v18, v20, v22, v30, 7 + tm_sum4 v24, v26, v28, v30, v30, 3 + + .irp n, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 + vmax.vx v\n, v\n, zero + .endr + + vsetvli zero, zero, e8, m1, ta, ma + .irp n, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28 + vnclipu.wi v\n, v\n, 0 + vse8.v v\n, (a0) + add a0, a0, a1 + .endr + vnclipu.wi v30, v30, 0 + vse8.v v30, (a0) + + ret +endfunc + +func ff_tm_8x8_rvv, zve32x + lpad 0 + vsetivli zero, 8, e16, m1, ta, ma + vle8.v v8, (a3) + vzext.vf2 v28, v8 + lbu a4, -1(a3) + + tm_sum4 v16, v17, v18, v19, v28, 7 + tm_sum4 v20, v21, v22, v23, v28, 3 + + .irp n, 16, 17, 18, 19, 20, 21, 22, 23 + vmax.vx v\n, v\n, zero + .endr + + vsetvli zero, zero, e8, mf2, ta, ma + .irp n, 16, 17, 18, 19, 20, 21, 22 + vnclipu.wi v\n, v\n, 0 + vse8.v v\n, (a0) + add a0, a0, a1 + .endr + vnclipu.wi v24, v23, 0 + vse8.v v24, (a0) + + ret +endfunc + +func ff_tm_4x4_rvv, zve32x + lpad 0 + vsetivli zero, 4, e16, mf2, ta, ma + vle8.v v8, (a3) + vzext.vf2 v28, v8 + lbu a4, -1(a3) + + tm_sum4 v16, v17, v18, v19, v28, 3 + + .irp n, 16, 17, 18, 19 + vmax.vx v\n, v\n, zero + .endr + + vsetvli zero, zero, e8, mf4, ta, ma + .irp n, 16, 17, 18 + vnclipu.wi v\n, v\n, 0 + vse8.v v\n, (a0) + add a0, a0, a1 + .endr + vnclipu.wi v24, v19, 0 + vse8.v v24, (a0) + + ret +endfunc diff --git a/libavcodec/riscv/vp9_mc_rvi.S b/libavcodec/riscv/vp9_mc_rvi.S new file mode 100644 index 000000000..4a8371b23 --- /dev/null +++ b/libavcodec/riscv/vp9_mc_rvi.S @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2024 Institue 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" + +#if __riscv_xlen >= 64 +func ff_copy64_rvi + lpad 0 +1: + addi a4, a4, -1 + ld t0, (a2) + ld t1, 8(a2) + ld t2, 16(a2) + ld t3, 24(a2) + ld t4, 32(a2) + ld t5, 40(a2) + ld t6, 48(a2) + ld a7, 56(a2) + sd t0, (a0) + sd t1, 8(a0) + sd t2, 16(a0) + sd t3, 24(a0) + sd t4, 32(a0) + sd t5, 40(a0) + sd t6, 48(a0) + sd a7, 56(a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc + +func ff_copy32_rvi + lpad 0 +1: + addi a4, a4, -1 + ld t0, (a2) + ld t1, 8(a2) + ld t2, 16(a2) + ld t3, 24(a2) + sd t0, (a0) + sd t1, 8(a0) + sd t2, 16(a0) + sd t3, 24(a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc + +func ff_copy16_rvi + lpad 0 +1: + addi a4, a4, -1 + ld t0, (a2) + ld t1, 8(a2) + sd t0, (a0) + sd t1, 8(a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc + +func ff_copy8_rvi + lpad 0 +1: + addi a4, a4, -1 + ld t0, (a2) + sd t0, (a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc +#endif + +func ff_copy4_rvi + lpad 0 +1: + addi a4, a4, -1 + lw t0, (a2) + sw t0, (a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + + ret +endfunc diff --git a/libavcodec/riscv/vp9_mc_rvv.S b/libavcodec/riscv/vp9_mc_rvv.S new file mode 100644 index 000000000..d1ddbe007 --- /dev/null +++ b/libavcodec/riscv/vp9_mc_rvv.S @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2024 Institue 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 vsetvlstatic8 len an maxlen mn=m4 +.if \len == 4 + vsetivli zero, \len, e8, mf4, ta, ma +.elseif \len == 8 + vsetivli zero, \len, e8, mf2, ta, ma +.elseif \len == 16 + vsetivli zero, \len, e8, m1, ta, ma +.elseif \len == 32 + li \an, \len + vsetvli zero, \an, e8, m2, ta, ma +.elseif \len == 64 + li \an, \maxlen + vsetvli zero, \an, e8, \mn, ta, ma +.endif +.endm + +.macro copy_avg len +func ff_vp9_avg\len\()_rvv, zve32x + lpad 0 + csrwi vxrm, 0 + vsetvlstatic8 \len, t0, 64 +1: + vle8.v v8, (a2) + vle8.v v16, (a0) + vaaddu.vv v8, v8, v16 + addi a4, a4, -1 + vse8.v v8, (a0) + add a2, a2, a3 + add a0, a0, a1 + bnez a4, 1b + ret +endfunc +.endm + +.macro bilin_load dst, mn, type +.ifc \type,v + add t4, a2, a3 +.else + addi t4, a2, 1 +.endif + vle8.v v4, (a2) + vle8.v v0, (t4) + vwmulu.vx v16, v0, \mn + vwmaccsu.vx v16, t1, v4 + vwadd.wx v16, v16, t3 + vnsra.wi v16, v16, 4 + vadd.vv \dst, v16, v4 + add a2, a2, a3 +.endm + +.macro bilin_h_v op, type, mn +func ff_\op\()_vp9_bilin_64\type\()_rvv, zve32x + lpad 0 + vsetvlstatic8 64, t0, 64 +.ifc \op,avg + csrwi vxrm, 0 +.endif + li t3, 8 + neg t1, \mn +1: + addi a4, a4, -1 + bilin_load v0, \mn, \type +.ifc \op,avg + vle8.v v16, (a0) + vaaddu.vv v0, v0, v16 +.endif + vse8.v v0, (a0) + add a0, a0, a1 + bnez a4, 1b + ret + +.Lbilin_\type\op: +.ifc \op,avg + csrwi vxrm, 0 +.endif + li t4, 8 + neg t1, \mn +1: + addi a4, a4, -2 + add t6, a0, a1 + add t0, a2, a3 + vle8.v v8, (a2) + vle8.v v4, (t0) +.ifc \type,v + add t2, t0, a3 + vwmulu.vx v16, v4, \mn +.else + addi t3, a2, 1 + addi t2, t0, 1 + vle8.v v0, (t3) + vwmulu.vx v16, v0, \mn +.endif + vle8.v v12, (t2) + vwmulu.vx v20, v12, \mn + vwmaccsu.vx v16, t1, v8 + vwmaccsu.vx v20, t1, v4 + vwadd.wx v16, v16, t4 + vwadd.wx v20, v20, t4 + vnsra.wi v16, v16, 4 + vnsra.wi v20, v20, 4 + vadd.vv v0, v16, v8 + vadd.vv v12, v20, v4 +.ifc \op,avg + vle8.v v16, (a0) + vle8.v v20, (t6) + vaaddu.vv v0, v0, v16 + vaaddu.vv v12, v12, v20 +.endif + vse8.v v0, (a0) + vse8.v v12, (t6) + add a2, t0, a3 + add a0, t6, a1 + bnez a4, 1b + + ret +endfunc +.endm + +.macro bilin_hv op +func ff_\op\()_vp9_bilin_64hv_rvv, zve32x + lpad 0 + vsetvlstatic8 64, t0, 64 +.Lbilin_hv\op: +.ifc \op,avg + csrwi vxrm, 0 +.endif + neg t1, a5 + neg t2, a6 + li t3, 8 + bilin_load v24, a5, h +1: + addi a4, a4, -2 + bilin_load v8, a5, h + vwmulu.vx v16, v8, a6 + vwmaccsu.vx v16, t2, v24 + vwadd.wx v16, v16, t3 + vnsra.wi v16, v16, 4 + vadd.vv v12, v16, v24 + add t5, a0, a1 + bilin_load v24, a5, h + vwmulu.vx v16, v24, a6 + vwmaccsu.vx v16, t2, v8 + vwadd.wx v16, v16, t3 + vnsra.wi v16, v16, 4 + vadd.vv v0, v16, v8 +.ifc \op,avg + vle8.v v8, (a0) + vle8.v v16, (t5) + vaaddu.vv v12, v12, v8 + vaaddu.vv v0, v0, v16 +.endif + vse8.v v12, (a0) + vse8.v v0, (t5) + add a0, t5, a1 + bnez a4, 1b + + ret +endfunc +.endm + +.irp len, 64, 32, 16, 8, 4 + copy_avg \len +.endr + +bilin_h_v put, h, a5 +bilin_h_v avg, h, a5 +bilin_h_v put, v, a6 +bilin_h_v avg, v, a6 +bilin_hv put +bilin_hv avg + +.macro func_bilin_h_v len, op, type +func ff_\op\()_vp9_bilin_\len\()\type\()_rvv, zve32x + lpad 0 + vsetvlstatic8 \len, t0, 64 + j .Lbilin_\type\()\op +endfunc +.endm + +.irp len, 32, 16, 8, 4 + .irp op, put, avg + .irp type, h, v, hv + func_bilin_h_v \len, \op, \type + .endr + .endr +.endr diff --git a/libavcodec/riscv/vp9dsp.h b/libavcodec/riscv/vp9dsp.h new file mode 100644 index 000000000..601939882 --- /dev/null +++ b/libavcodec/riscv/vp9dsp.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2024 Institue 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_VP9DSP_H +#define AVCODEC_RISCV_VP9DSP_H + +#include +#include + +void ff_dc_32x32_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_16x16_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_8x8_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_top_32x32_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_top_16x16_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_top_8x8_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_left_32x32_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_left_16x16_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_left_8x8_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_127_32x32_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_127_16x16_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_127_8x8_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_128_32x32_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_128_16x16_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_128_8x8_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_129_32x32_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_129_16x16_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_dc_129_8x8_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_h_32x32_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_h_16x16_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_h_8x8_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_tm_32x32_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_tm_16x16_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_tm_8x8_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); +void ff_tm_4x4_rvv(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, + const uint8_t *a); + +#define VP9_8TAP_RISCV_RVV_FUNC(SIZE, type, type_idx) \ +void ff_put_8tap_##type##_##SIZE##h_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_put_8tap_##type##_##SIZE##v_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_put_8tap_##type##_##SIZE##hv_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_avg_8tap_##type##_##SIZE##h_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_avg_8tap_##type##_##SIZE##v_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_avg_8tap_##type##_##SIZE##hv_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); + +#define VP9_BILINEAR_RISCV_RVV_FUNC(SIZE) \ +void ff_put_vp9_bilin_##SIZE##h_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_put_vp9_bilin_##SIZE##v_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_put_vp9_bilin_##SIZE##hv_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_avg_vp9_bilin_##SIZE##h_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_avg_vp9_bilin_##SIZE##v_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_avg_vp9_bilin_##SIZE##hv_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride, \ + int h, int mx, int my); + +#define VP9_COPY_AVG_RISCV_RVV_FUNC(SIZE) \ +void ff_vp9_copy##SIZE##_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_vp9_avg##SIZE##_rvv(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride, \ + int h, int mx, int my); + +VP9_8TAP_RISCV_RVV_FUNC(64, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_RISCV_RVV_FUNC(32, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_RISCV_RVV_FUNC(16, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_RISCV_RVV_FUNC(8, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_RISCV_RVV_FUNC(4, regular, FILTER_8TAP_REGULAR); + +VP9_8TAP_RISCV_RVV_FUNC(64, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_RISCV_RVV_FUNC(32, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_RISCV_RVV_FUNC(16, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_RISCV_RVV_FUNC(8, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_RISCV_RVV_FUNC(4, sharp, FILTER_8TAP_SHARP); + +VP9_8TAP_RISCV_RVV_FUNC(64, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_RISCV_RVV_FUNC(32, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_RISCV_RVV_FUNC(16, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_RISCV_RVV_FUNC(8, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_RISCV_RVV_FUNC(4, smooth, FILTER_8TAP_SMOOTH); + +VP9_BILINEAR_RISCV_RVV_FUNC(64); +VP9_BILINEAR_RISCV_RVV_FUNC(32); +VP9_BILINEAR_RISCV_RVV_FUNC(16); +VP9_BILINEAR_RISCV_RVV_FUNC(8); +VP9_BILINEAR_RISCV_RVV_FUNC(4); + +VP9_COPY_AVG_RISCV_RVV_FUNC(64); +VP9_COPY_AVG_RISCV_RVV_FUNC(32); +VP9_COPY_AVG_RISCV_RVV_FUNC(16); +VP9_COPY_AVG_RISCV_RVV_FUNC(8); +VP9_COPY_AVG_RISCV_RVV_FUNC(4); + +#define VP9_COPY_RISCV_RVI_FUNC(SIZE) \ +void ff_copy##SIZE##_rvi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, ptrdiff_t srcstride, \ + int h, int mx, int my); + +VP9_COPY_RISCV_RVI_FUNC(64); +VP9_COPY_RISCV_RVI_FUNC(32); +VP9_COPY_RISCV_RVI_FUNC(16); +VP9_COPY_RISCV_RVI_FUNC(8); +VP9_COPY_RISCV_RVI_FUNC(4); + +#undef VP9_8TAP_RISCV_RVV_FUNC +#undef VP9_BILINEAR_RISCV_RVV_FUNC +#undef VP9_COPY_AVG_RISCV_RVV_FUNC + +#endif // #ifndef AVCODEC_RISCV_VP9DSP_H diff --git a/libavcodec/riscv/vp9dsp_init.c b/libavcodec/riscv/vp9dsp_init.c new file mode 100644 index 000000000..d53852f67 --- /dev/null +++ b/libavcodec/riscv/vp9dsp_init.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2024 Institue 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 Lervvr General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lervvr General Public License for more details. + * + * You should have received a copy of the GNU Lervvr General 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/riscv/cpu.h" +#include "libavcodec/vp9dsp.h" +#include "vp9dsp.h" + +static av_cold void vp9dsp_mc_init_riscv(VP9DSPContext *dsp, int bpp) +{ +#if HAVE_RV + int flags = av_get_cpu_flags(); + +# if __riscv_xlen >= 64 + if (bpp == 8 && (flags & AV_CPU_FLAG_RV_MISALIGNED)) { + +#define init_fpel(idx1, sz) \ + dsp->mc[idx1][FILTER_8TAP_SMOOTH ][0][0][0] = ff_copy##sz##_rvi; \ + dsp->mc[idx1][FILTER_8TAP_REGULAR][0][0][0] = ff_copy##sz##_rvi; \ + dsp->mc[idx1][FILTER_8TAP_SHARP ][0][0][0] = ff_copy##sz##_rvi; \ + dsp->mc[idx1][FILTER_BILINEAR ][0][0][0] = ff_copy##sz##_rvi + + init_fpel(0, 64); + init_fpel(1, 32); + init_fpel(2, 16); + init_fpel(3, 8); + init_fpel(4, 4); + +#undef init_fpel + } +# endif + +#if HAVE_RVV + if (bpp == 8 && (flags & AV_CPU_FLAG_RVV_I32) && ff_rv_vlen_least(128)) { + +#define init_fpel(idx1, sz) \ + dsp->mc[idx1][FILTER_8TAP_SMOOTH ][1][0][0] = ff_vp9_avg##sz##_rvv; \ + dsp->mc[idx1][FILTER_8TAP_REGULAR][1][0][0] = ff_vp9_avg##sz##_rvv; \ + dsp->mc[idx1][FILTER_8TAP_SHARP ][1][0][0] = ff_vp9_avg##sz##_rvv; \ + dsp->mc[idx1][FILTER_BILINEAR ][1][0][0] = ff_vp9_avg##sz##_rvv + + init_fpel(0, 64); + init_fpel(1, 32); + init_fpel(2, 16); + init_fpel(3, 8); + init_fpel(4, 4); + + dsp->mc[0][FILTER_BILINEAR ][0][0][1] = ff_put_vp9_bilin_64v_rvv; + dsp->mc[0][FILTER_BILINEAR ][0][1][0] = ff_put_vp9_bilin_64h_rvv; + dsp->mc[0][FILTER_BILINEAR ][1][0][1] = ff_avg_vp9_bilin_64v_rvv; + dsp->mc[0][FILTER_BILINEAR ][1][1][0] = ff_avg_vp9_bilin_64h_rvv; + dsp->mc[1][FILTER_BILINEAR ][0][0][1] = ff_put_vp9_bilin_32v_rvv; + dsp->mc[1][FILTER_BILINEAR ][0][1][0] = ff_put_vp9_bilin_32h_rvv; + dsp->mc[1][FILTER_BILINEAR ][1][0][1] = ff_avg_vp9_bilin_32v_rvv; + dsp->mc[1][FILTER_BILINEAR ][1][1][0] = ff_avg_vp9_bilin_32h_rvv; + dsp->mc[2][FILTER_BILINEAR ][0][0][1] = ff_put_vp9_bilin_16v_rvv; + dsp->mc[2][FILTER_BILINEAR ][0][1][0] = ff_put_vp9_bilin_16h_rvv; + dsp->mc[2][FILTER_BILINEAR ][1][0][1] = ff_avg_vp9_bilin_16v_rvv; + dsp->mc[2][FILTER_BILINEAR ][1][1][0] = ff_avg_vp9_bilin_16h_rvv; + dsp->mc[3][FILTER_BILINEAR ][0][0][1] = ff_put_vp9_bilin_8v_rvv; + dsp->mc[3][FILTER_BILINEAR ][0][1][0] = ff_put_vp9_bilin_8h_rvv; + dsp->mc[3][FILTER_BILINEAR ][1][0][1] = ff_avg_vp9_bilin_8v_rvv; + dsp->mc[3][FILTER_BILINEAR ][1][1][0] = ff_avg_vp9_bilin_8h_rvv; + dsp->mc[4][FILTER_BILINEAR ][0][0][1] = ff_put_vp9_bilin_4v_rvv; + dsp->mc[4][FILTER_BILINEAR ][0][1][0] = ff_put_vp9_bilin_4h_rvv; + dsp->mc[4][FILTER_BILINEAR ][1][0][1] = ff_avg_vp9_bilin_4v_rvv; + dsp->mc[4][FILTER_BILINEAR ][1][1][0] = ff_avg_vp9_bilin_4h_rvv; + dsp->mc[0][FILTER_BILINEAR ][0][1][1] = ff_put_vp9_bilin_64hv_rvv; + dsp->mc[0][FILTER_BILINEAR ][1][1][1] = ff_avg_vp9_bilin_64hv_rvv; + dsp->mc[1][FILTER_BILINEAR ][0][1][1] = ff_put_vp9_bilin_32hv_rvv; + dsp->mc[1][FILTER_BILINEAR ][1][1][1] = ff_avg_vp9_bilin_32hv_rvv; + dsp->mc[2][FILTER_BILINEAR ][0][1][1] = ff_put_vp9_bilin_16hv_rvv; + dsp->mc[2][FILTER_BILINEAR ][1][1][1] = ff_avg_vp9_bilin_16hv_rvv; + dsp->mc[3][FILTER_BILINEAR ][0][1][1] = ff_put_vp9_bilin_8hv_rvv; + dsp->mc[3][FILTER_BILINEAR ][1][1][1] = ff_avg_vp9_bilin_8hv_rvv; + dsp->mc[4][FILTER_BILINEAR ][0][1][1] = ff_put_vp9_bilin_4hv_rvv; + dsp->mc[4][FILTER_BILINEAR ][1][1][1] = ff_avg_vp9_bilin_4hv_rvv; + +#undef init_fpel + } +#endif +#endif +} + +static av_cold void vp9dsp_intrapred_init_riscv(VP9DSPContext *dsp, int bpp) +{ +#if HAVE_RV + int flags = av_get_cpu_flags(); + +#if HAVE_RVV + if (bpp == 8 && flags & AV_CPU_FLAG_RVV_I64 && ff_rv_vlen_least(128)) { + dsp->intra_pred[TX_8X8][DC_PRED] = ff_dc_8x8_rvv; + dsp->intra_pred[TX_8X8][LEFT_DC_PRED] = ff_dc_left_8x8_rvv; + dsp->intra_pred[TX_8X8][DC_127_PRED] = ff_dc_127_8x8_rvv; + dsp->intra_pred[TX_8X8][DC_128_PRED] = ff_dc_128_8x8_rvv; + dsp->intra_pred[TX_8X8][DC_129_PRED] = ff_dc_129_8x8_rvv; + dsp->intra_pred[TX_8X8][TOP_DC_PRED] = ff_dc_top_8x8_rvv; + } + + if (bpp == 8 && flags & AV_CPU_FLAG_RVV_I32 && ff_rv_vlen_least(128)) { + dsp->intra_pred[TX_32X32][DC_PRED] = ff_dc_32x32_rvv; + dsp->intra_pred[TX_16X16][DC_PRED] = ff_dc_16x16_rvv; + dsp->intra_pred[TX_32X32][LEFT_DC_PRED] = ff_dc_left_32x32_rvv; + dsp->intra_pred[TX_16X16][LEFT_DC_PRED] = ff_dc_left_16x16_rvv; + dsp->intra_pred[TX_32X32][DC_127_PRED] = ff_dc_127_32x32_rvv; + dsp->intra_pred[TX_16X16][DC_127_PRED] = ff_dc_127_16x16_rvv; + dsp->intra_pred[TX_32X32][DC_128_PRED] = ff_dc_128_32x32_rvv; + dsp->intra_pred[TX_16X16][DC_128_PRED] = ff_dc_128_16x16_rvv; + dsp->intra_pred[TX_32X32][DC_129_PRED] = ff_dc_129_32x32_rvv; + dsp->intra_pred[TX_16X16][DC_129_PRED] = ff_dc_129_16x16_rvv; + dsp->intra_pred[TX_32X32][TOP_DC_PRED] = ff_dc_top_32x32_rvv; + dsp->intra_pred[TX_16X16][TOP_DC_PRED] = ff_dc_top_16x16_rvv; + dsp->intra_pred[TX_32X32][HOR_PRED] = ff_h_32x32_rvv; + dsp->intra_pred[TX_16X16][HOR_PRED] = ff_h_16x16_rvv; + dsp->intra_pred[TX_8X8][HOR_PRED] = ff_h_8x8_rvv; + dsp->intra_pred[TX_32X32][TM_VP8_PRED] = ff_tm_32x32_rvv; + dsp->intra_pred[TX_16X16][TM_VP8_PRED] = ff_tm_16x16_rvv; + dsp->intra_pred[TX_8X8][TM_VP8_PRED] = ff_tm_8x8_rvv; + dsp->intra_pred[TX_4X4][TM_VP8_PRED] = ff_tm_4x4_rvv; + } +#endif +#endif +} + +av_cold void ff_vp9dsp_init_riscv(VP9DSPContext *dsp, int bpp, int bitexact) +{ + vp9dsp_intrapred_init_riscv(dsp, bpp); + vp9dsp_mc_init_riscv(dsp, bpp); +} diff --git a/libavcodec/rka.c b/libavcodec/rka.c index 724107f3e..600c16002 100644 --- a/libavcodec/rka.c +++ b/libavcodec/rka.c @@ -21,6 +21,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c index 53b6f6d5e..47b076dbd 100644 --- a/libavcodec/rkmppdec.c +++ b/libavcodec/rkmppdec.c @@ -30,6 +30,7 @@ #include "codec_internal.h" #include "decode.h" #include "hwconfig.h" +#include "refstruct.h" #include "libavutil/buffer.h" #include "libavutil/common.h" #include "libavutil/frame.h" @@ -37,6 +38,7 @@ #include "libavutil/hwcontext_drm.h" #include "libavutil/imgutils.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #define RECEIVE_FRAME_TIMEOUT 100 #define FRAMEGROUP_MAX_FRAMES 16 @@ -56,12 +58,12 @@ typedef struct { typedef struct { AVClass *av_class; - AVBufferRef *decoder_ref; + RKMPPDecoder *decoder; ///< RefStruct reference } RKMPPDecodeContext; typedef struct { MppFrame frame; - AVBufferRef *decoder_ref; + const RKMPPDecoder *decoder_ref; ///< RefStruct reference } RKMPPFrameContext; static MppCodingType rkmpp_get_codingtype(AVCodecContext *avctx) @@ -89,7 +91,7 @@ static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat) static int rkmpp_write_data(AVCodecContext *avctx, uint8_t *buffer, int size, int64_t pts) { RKMPPDecodeContext *rk_context = avctx->priv_data; - RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; + RKMPPDecoder *decoder = rk_context->decoder; int ret; MppPacket packet; @@ -124,13 +126,13 @@ static int rkmpp_write_data(AVCodecContext *avctx, uint8_t *buffer, int size, in static int rkmpp_close_decoder(AVCodecContext *avctx) { RKMPPDecodeContext *rk_context = avctx->priv_data; - av_buffer_unref(&rk_context->decoder_ref); + ff_refstruct_unref(&rk_context->decoder); return 0; } -static void rkmpp_release_decoder(void *opaque, uint8_t *data) +static void rkmpp_release_decoder(FFRefStructOpaque unused, void *obj) { - RKMPPDecoder *decoder = (RKMPPDecoder *)data; + RKMPPDecoder *decoder = obj; if (decoder->mpi) { decoder->mpi->reset(decoder->ctx); @@ -145,8 +147,6 @@ static void rkmpp_release_decoder(void *opaque, uint8_t *data) av_buffer_unref(&decoder->frames_ref); av_buffer_unref(&decoder->device_ref); - - av_free(decoder); } static int rkmpp_init_decoder(AVCodecContext *avctx) @@ -161,19 +161,13 @@ static int rkmpp_init_decoder(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME; // create a decoder and a ref to it - decoder = av_mallocz(sizeof(RKMPPDecoder)); + decoder = ff_refstruct_alloc_ext(sizeof(*decoder), 0, + NULL, rkmpp_release_decoder); if (!decoder) { ret = AVERROR(ENOMEM); goto fail; } - - rk_context->decoder_ref = av_buffer_create((uint8_t *)decoder, sizeof(*decoder), rkmpp_release_decoder, - NULL, AV_BUFFER_FLAG_READONLY); - if (!rk_context->decoder_ref) { - av_free(decoder); - ret = AVERROR(ENOMEM); - goto fail; - } + rk_context->decoder = decoder; av_log(avctx, AV_LOG_DEBUG, "Initializing RKMPP decoder.\n"); @@ -269,7 +263,7 @@ fail: static int rkmpp_send_packet(AVCodecContext *avctx, const AVPacket *avpkt) { RKMPPDecodeContext *rk_context = avctx->priv_data; - RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; + RKMPPDecoder *decoder = rk_context->decoder; int ret; // handle EOF @@ -307,12 +301,10 @@ static int rkmpp_send_packet(AVCodecContext *avctx, const AVPacket *avpkt) static void rkmpp_release_frame(void *opaque, uint8_t *data) { AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)data; - AVBufferRef *framecontextref = (AVBufferRef *)opaque; - RKMPPFrameContext *framecontext = (RKMPPFrameContext *)framecontextref->data; + RKMPPFrameContext *framecontext = opaque; mpp_frame_deinit(&framecontext->frame); - av_buffer_unref(&framecontext->decoder_ref); - av_buffer_unref(&framecontextref); + ff_refstruct_unref(&framecontext->decoder_ref); av_free(desc); } @@ -320,13 +312,10 @@ static void rkmpp_release_frame(void *opaque, uint8_t *data) static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) { RKMPPDecodeContext *rk_context = avctx->priv_data; - RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; - RKMPPFrameContext *framecontext = NULL; - AVBufferRef *framecontextref = NULL; + RKMPPDecoder *decoder = rk_context->decoder; int ret; MppFrame mppframe = NULL; MppBuffer buffer = NULL; - AVDRMFrameDescriptor *desc = NULL; AVDRMLayerDescriptor *layer = NULL; int mode; MppFrameFormat mppformat; @@ -415,11 +404,21 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) // now setup the frame buffer info buffer = mpp_frame_get_buffer(mppframe); if (buffer) { - desc = av_mallocz(sizeof(AVDRMFrameDescriptor)); - if (!desc) { + RKMPPFrameContext *framecontext; + AVDRMFrameDescriptor *desc; + // We allocate the descriptor in buf[0] jointly with a structure + // that will allow to hold additional information + // for properly releasing MPP frames and decoder. + struct { + AVDRMFrameDescriptor desc; + RKMPPFrameContext framecontext; + } *combined_desc = av_mallocz(sizeof(*combined_desc)); + if (!combined_desc) { ret = AVERROR(ENOMEM); goto fail; } + desc = &combined_desc->desc; + framecontext = &combined_desc->framecontext; desc->nb_objects = 1; desc->objects[0].fd = mpp_buffer_get_fd(buffer); @@ -438,32 +437,24 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) layer->planes[1].offset = layer->planes[0].pitch * mpp_frame_get_ver_stride(mppframe); layer->planes[1].pitch = layer->planes[0].pitch; - // we also allocate a struct in buf[0] that will allow to hold additionnal information - // for releasing properly MPP frames and decoder - framecontextref = av_buffer_allocz(sizeof(*framecontext)); - if (!framecontextref) { - ret = AVERROR(ENOMEM); - goto fail; - } - // MPP decoder needs to be closed only when all frames have been released. - framecontext = (RKMPPFrameContext *)framecontextref->data; - framecontext->decoder_ref = av_buffer_ref(rk_context->decoder_ref); framecontext->frame = mppframe; frame->data[0] = (uint8_t *)desc; frame->buf[0] = av_buffer_create((uint8_t *)desc, sizeof(*desc), rkmpp_release_frame, - framecontextref, AV_BUFFER_FLAG_READONLY); + framecontext, AV_BUFFER_FLAG_READONLY); if (!frame->buf[0]) { + av_free(combined_desc); ret = AVERROR(ENOMEM); goto fail; } + framecontext->decoder_ref = ff_refstruct_ref(rk_context->decoder); frame->hw_frames_ctx = av_buffer_ref(decoder->frames_ref); if (!frame->hw_frames_ctx) { - ret = AVERROR(ENOMEM); - goto fail; + av_frame_unref(frame); + return AVERROR(ENOMEM); } return 0; @@ -483,22 +474,13 @@ fail: if (mppframe) mpp_frame_deinit(&mppframe); - if (framecontext) - av_buffer_unref(&framecontext->decoder_ref); - - if (framecontextref) - av_buffer_unref(&framecontextref); - - if (desc) - av_free(desc); - return ret; } static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) { RKMPPDecodeContext *rk_context = avctx->priv_data; - RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; + RKMPPDecoder *decoder = rk_context->decoder; int ret = MPP_NOK; AVPacket pkt = {0}; RK_S32 usedslots, freeslots; @@ -538,7 +520,7 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) static void rkmpp_flush(AVCodecContext *avctx) { RKMPPDecodeContext *rk_context = avctx->priv_data; - RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; + RKMPPDecoder *decoder = rk_context->decoder; int ret = MPP_NOK; av_log(avctx, AV_LOG_DEBUG, "Flush.\n"); diff --git a/libavcodec/roqaudioenc.c b/libavcodec/roqaudioenc.c index 81dccd09b..8d08a1365 100644 --- a/libavcodec/roqaudioenc.c +++ b/libavcodec/roqaudioenc.c @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/roqvideoenc.c b/libavcodec/roqvideoenc.c index 0933abf4f..7cbe820f9 100644 --- a/libavcodec/roqvideoenc.c +++ b/libavcodec/roqvideoenc.c @@ -58,6 +58,7 @@ #include "libavutil/attributes.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "roqvideo.h" #include "bytestream.h" @@ -1127,6 +1128,7 @@ const FFCodec ff_roq_encoder = { .close = roq_encode_end, .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE }, + .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 d84555d6c..3a1924d38 100644 --- a/libavcodec/rpzaenc.c +++ b/libavcodec/rpzaenc.c @@ -749,20 +749,24 @@ post_skip : if (err > s->sixteen_color_thresh) { // DO SIXTEEN COLOR BLOCK const uint16_t *row_ptr; - int y_size, rgb555; + int y_size, x_size, rgb555; block_offset = get_block_info(&bi, block_counter, 0); pblock_offset = get_block_info(&bi, block_counter, 1); row_ptr = &src_pixels[block_offset]; y_size = FFMIN(4, bi.image_height - bi.row * 4); + x_size = FFMIN(4, bi.image_width - bi.col * 4); for (int y = 0; y < y_size; y++) { - for (int x = 0; x < 4; x++) { + for (int x = 0; x < x_size; x++) { rgb555 = row_ptr[x] & ~0x8000; put_bits(&s->pb, 16, rgb555); } + for (int x = x_size; x < 4; x++) + put_bits(&s->pb, 16, 0); + row_ptr += bi.rowstride; } diff --git a/libavcodec/rscc.c b/libavcodec/rscc.c index ace9aeeb4..e601ff39e 100644 --- a/libavcodec/rscc.c +++ b/libavcodec/rscc.c @@ -40,6 +40,7 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/rtv1.c b/libavcodec/rtv1.c index 807c8a346..c40f9ada5 100644 --- a/libavcodec/rtv1.c +++ b/libavcodec/rtv1.c @@ -132,9 +132,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, if (ret < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/rv10.c b/libavcodec/rv10.c index d32faa628..753c6c6cb 100644 --- a/libavcodec/rv10.c +++ b/libavcodec/rv10.c @@ -38,7 +38,6 @@ #include "h263data.h" #include "h263dec.h" #include "mpeg_er.h" -#include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "mpeg4video.h" @@ -171,7 +170,7 @@ static int rv20_decode_picture_header(RVDecContext *rv, int whole_size) av_log(s->avctx, AV_LOG_ERROR, "low delay B\n"); return -1; } - if (!s->last_picture_ptr && s->pict_type == AV_PICTURE_TYPE_B) { + if (!s->last_pic.ptr && s->pict_type == AV_PICTURE_TYPE_B) { av_log(s->avctx, AV_LOG_ERROR, "early B-frame\n"); return AVERROR_INVALIDDATA; } @@ -347,7 +346,6 @@ static av_cold void rv10_init_static(void) rv_dc_chrom.table[(0x1FE << (DC_VLC_BITS - 9)) + i].sym = 255; rv_dc_chrom.table[(0x1FE << (DC_VLC_BITS - 9)) + i].len = 18; } - ff_h263_decode_init_vlc(); } static av_cold int rv10_decode_init(AVCodecContext *avctx) @@ -365,14 +363,12 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) avctx->coded_height, 0, avctx)) < 0) return ret; - ff_mpv_decode_init(s, avctx); + ret = ff_h263_decode_init(avctx); + if (ret < 0) + return ret; - s->out_format = FMT_H263; - - rv->orig_width = - s->width = avctx->coded_width; - rv->orig_height = - s->height = avctx->coded_height; + 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); @@ -381,7 +377,6 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) minor_ver = RV_GET_MINOR_VER(rv->sub_id); micro_ver = RV_GET_MICRO_VER(rv->sub_id); - s->low_delay = 1; switch (major_ver) { case 1: s->rv10_version = micro_ver ? 3 : 1; @@ -390,11 +385,11 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) case 2: if (minor_ver >= 2) { s->low_delay = 0; - s->avctx->has_b_frames = 1; + avctx->has_b_frames = 1; } break; default: - av_log(s->avctx, AV_LOG_ERROR, "unknown header %X\n", rv->sub_id); + av_log(avctx, AV_LOG_ERROR, "unknown header %X\n", rv->sub_id); avpriv_request_sample(avctx, "RV1/2 version"); return AVERROR_PATCHWELCOME; } @@ -404,27 +399,12 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx) ((uint32_t *) avctx->extradata)[0]); } - avctx->pix_fmt = AV_PIX_FMT_YUV420P; - - if ((ret = ff_mpv_common_init(s)) < 0) - return ret; - - ff_h263dsp_init(&s->h263dsp); - /* init static VLCs */ ff_thread_once(&init_static_once, rv10_init_static); return 0; } -static av_cold int rv10_decode_end(AVCodecContext *avctx) -{ - MpegEncContext *s = avctx->priv_data; - - ff_mpv_common_end(s); - return 0; -} - static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf, int buf_size, int buf_size2, int whole_size) { @@ -459,9 +439,9 @@ static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf, if (whole_size < s->mb_width * s->mb_height / 8) return AVERROR_INVALIDDATA; - if ((s->mb_x == 0 && s->mb_y == 0) || !s->current_picture_ptr) { + if ((s->mb_x == 0 && s->mb_y == 0) || !s->cur_pic.ptr) { // FIXME write parser so we always have complete frames? - if (s->current_picture_ptr) { + 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; @@ -470,7 +450,7 @@ static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf, return ret; ff_mpeg_er_frame_start(s); } else { - if (s->current_picture_ptr->f->pict_type != s->pict_type) { + if (s->cur_pic.ptr->f->pict_type != s->pict_type) { av_log(s->avctx, AV_LOG_ERROR, "Slice type mismatch\n"); return AVERROR_INVALIDDATA; } @@ -505,12 +485,6 @@ static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf, s->rv10_first_dc_coded[0] = 0; s->rv10_first_dc_coded[1] = 0; s->rv10_first_dc_coded[2] = 0; - s->block_wrap[0] = - s->block_wrap[1] = - s->block_wrap[2] = - s->block_wrap[3] = s->b8_stride; - s->block_wrap[4] = - s->block_wrap[5] = s->mb_stride; ff_init_block_index(s); /* decode each macroblock */ @@ -633,28 +607,28 @@ static int rv10_decode_frame(AVCodecContext *avctx, AVFrame *pict, i++; } - if (s->current_picture_ptr && s->mb_y >= s->mb_height) { + if (s->cur_pic.ptr && s->mb_y >= s->mb_height) { ff_er_frame_end(&s->er, NULL); ff_mpv_frame_end(s); if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) { - if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0) + if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) return ret; - ff_print_debug_info(s, s->current_picture_ptr, pict); - ff_mpv_export_qp_table(s, pict, s->current_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG1); - } else if (s->last_picture_ptr) { - if ((ret = av_frame_ref(pict, s->last_picture_ptr->f)) < 0) + 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) return ret; - ff_print_debug_info(s, s->last_picture_ptr, pict); - ff_mpv_export_qp_table(s, pict,s->last_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG1); + 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); } - if (s->last_picture_ptr || s->low_delay) { + if (s->last_pic.ptr || s->low_delay) { *got_frame = 1; } // so we can detect if frame_end was not called (find some nicer solution...) - s->current_picture_ptr = NULL; + ff_mpv_unref_picture(&s->cur_pic); } return avpkt->size; @@ -667,10 +641,11 @@ const FFCodec ff_rv10_decoder = { .p.id = AV_CODEC_ID_RV10, .priv_data_size = sizeof(RVDecContext), .init = rv10_decode_init, - .close = rv10_decode_end, FF_CODEC_DECODE_CB(rv10_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DR1, .p.max_lowres = 3, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; const FFCodec ff_rv20_decoder = { @@ -680,9 +655,10 @@ const FFCodec ff_rv20_decoder = { .p.id = AV_CODEC_ID_RV20, .priv_data_size = sizeof(RVDecContext), .init = rv10_decode_init, - .close = rv10_decode_end, FF_CODEC_DECODE_CB(rv10_decode_frame), + .close = ff_mpv_decode_close, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .flush = ff_mpeg_flush, .p.max_lowres = 3, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/rv10enc.c b/libavcodec/rv10enc.c index 8a405b868..2104ee0a2 100644 --- a/libavcodec/rv10enc.c +++ b/libavcodec/rv10enc.c @@ -78,4 +78,5 @@ const FFCodec ff_rv10_encoder = { .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 }, + .color_ranges = AVCOL_RANGE_MPEG, }; diff --git a/libavcodec/rv20enc.c b/libavcodec/rv20enc.c index dc26877d5..d0e24f2f2 100644 --- a/libavcodec/rv20enc.c +++ b/libavcodec/rv20enc.c @@ -75,4 +75,5 @@ const FFCodec ff_rv20_encoder = { .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 }, + .color_ranges = AVCOL_RANGE_MPEG, }; diff --git a/libavcodec/rv30.c b/libavcodec/rv30.c index 9e13e7180..5e1dd01aa 100644 --- a/libavcodec/rv30.c +++ b/libavcodec/rv30.c @@ -160,7 +160,7 @@ static void rv30_loop_filter(RV34DecContext *r, int row) mb_pos = row * s->mb_stride; for(mb_x = 0; mb_x < s->mb_width; mb_x++, mb_pos++){ - int mbtype = s->current_picture_ptr->mb_type[mb_pos]; + int mbtype = s->cur_pic.mb_type[mb_pos]; if(IS_INTRA(mbtype) || IS_SEPARATE_DC(mbtype)) r->deblock_coefs[mb_pos] = 0xFFFF; if(IS_INTRA(mbtype)) @@ -172,11 +172,11 @@ static void rv30_loop_filter(RV34DecContext *r, int row) */ mb_pos = row * s->mb_stride; for(mb_x = 0; mb_x < s->mb_width; mb_x++, mb_pos++){ - cur_lim = rv30_loop_filt_lim[s->current_picture_ptr->qscale_table[mb_pos]]; + cur_lim = rv30_loop_filt_lim[s->cur_pic.qscale_table[mb_pos]]; if(mb_x) - left_lim = rv30_loop_filt_lim[s->current_picture_ptr->qscale_table[mb_pos - 1]]; + left_lim = rv30_loop_filt_lim[s->cur_pic.qscale_table[mb_pos - 1]]; for(j = 0; j < 16; j += 4){ - Y = s->current_picture_ptr->f->data[0] + mb_x*16 + (row*16 + j) * s->linesize + 4 * !mb_x; + Y = s->cur_pic.data[0] + mb_x*16 + (row*16 + j) * s->linesize + 4 * !mb_x; for(i = !mb_x; i < 4; i++, Y += 4){ int ij = i + j; loc_lim = 0; @@ -196,7 +196,7 @@ static void rv30_loop_filter(RV34DecContext *r, int row) if(mb_x) left_cbp = (r->cbp_chroma[mb_pos - 1] >> (k*4)) & 0xF; for(j = 0; j < 8; j += 4){ - C = s->current_picture_ptr->f->data[k + 1] + mb_x*8 + (row*8 + j) * s->uvlinesize + 4 * !mb_x; + C = s->cur_pic.data[k + 1] + mb_x*8 + (row*8 + j) * s->uvlinesize + 4 * !mb_x; for(i = !mb_x; i < 2; i++, C += 4){ int ij = i + (j >> 1); loc_lim = 0; @@ -214,11 +214,11 @@ static void rv30_loop_filter(RV34DecContext *r, int row) } mb_pos = row * s->mb_stride; for(mb_x = 0; mb_x < s->mb_width; mb_x++, mb_pos++){ - cur_lim = rv30_loop_filt_lim[s->current_picture_ptr->qscale_table[mb_pos]]; + cur_lim = rv30_loop_filt_lim[s->cur_pic.qscale_table[mb_pos]]; if(row) - top_lim = rv30_loop_filt_lim[s->current_picture_ptr->qscale_table[mb_pos - s->mb_stride]]; + top_lim = rv30_loop_filt_lim[s->cur_pic.qscale_table[mb_pos - s->mb_stride]]; for(j = 4*!row; j < 16; j += 4){ - Y = s->current_picture_ptr->f->data[0] + mb_x*16 + (row*16 + j) * s->linesize; + Y = s->cur_pic.data[0] + mb_x*16 + (row*16 + j) * s->linesize; for(i = 0; i < 4; i++, Y += 4){ int ij = i + j; loc_lim = 0; @@ -238,7 +238,7 @@ static void rv30_loop_filter(RV34DecContext *r, int row) if(row) top_cbp = (r->cbp_chroma[mb_pos - s->mb_stride] >> (k*4)) & 0xF; for(j = 4*!row; j < 8; j += 4){ - C = s->current_picture_ptr->f->data[k+1] + mb_x*8 + (row*8 + j) * s->uvlinesize; + C = s->cur_pic.data[k+1] + mb_x*8 + (row*8 + j) * s->uvlinesize; for(i = 0; i < 2; i++, C += 4){ int ij = i + (j >> 1); loc_lim = 0; @@ -302,7 +302,7 @@ const FFCodec ff_rv30_decoder = { FF_CODEC_DECODE_CB(ff_rv34_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .flush = ff_mpeg_flush, UPDATE_THREAD_CONTEXT(ff_rv34_decode_update_thread_context), - .caps_internal = FF_CODEC_CAP_ALLOCATE_PROGRESS, }; diff --git a/libavcodec/rv34.c b/libavcodec/rv34.c index ed630cd59..d94285431 100644 --- a/libavcodec/rv34.c +++ b/libavcodec/rv34.c @@ -27,6 +27,7 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" @@ -42,7 +43,7 @@ #include "qpeldsp.h" #include "rectangle.h" #include "thread.h" -#include "threadframe.h" +#include "threadprogress.h" #include "rv34vlc.h" #include "rv34data.h" @@ -58,16 +59,16 @@ static inline void ZERO8x2(void* dst, int stride) static const int rv34_mb_type_to_lavc[12] = { MB_TYPE_INTRA, MB_TYPE_INTRA16x16 | MB_TYPE_SEPARATE_DC, - MB_TYPE_16x16 | MB_TYPE_L0, - MB_TYPE_8x8 | MB_TYPE_L0, - MB_TYPE_16x16 | MB_TYPE_L0, - MB_TYPE_16x16 | MB_TYPE_L1, + MB_TYPE_16x16 | MB_TYPE_FORWARD_MV, + MB_TYPE_8x8 | MB_TYPE_FORWARD_MV, + MB_TYPE_16x16 | MB_TYPE_FORWARD_MV, + MB_TYPE_16x16 | MB_TYPE_BACKWARD_MV, MB_TYPE_SKIP, MB_TYPE_DIRECT2 | MB_TYPE_16x16, - MB_TYPE_16x8 | MB_TYPE_L0, - MB_TYPE_8x16 | MB_TYPE_L0, - MB_TYPE_16x16 | MB_TYPE_L0L1, - MB_TYPE_16x16 | MB_TYPE_L0 | MB_TYPE_SEPARATE_DC + MB_TYPE_16x8 | MB_TYPE_FORWARD_MV, + MB_TYPE_8x16 | MB_TYPE_FORWARD_MV, + MB_TYPE_16x16 | MB_TYPE_BIDIR_MV, + MB_TYPE_16x16 | MB_TYPE_FORWARD_MV | MB_TYPE_SEPARATE_DC }; @@ -368,7 +369,7 @@ static int rv34_decode_intra_mb_header(RV34DecContext *r, int8_t *intra_types) r->is16 = get_bits1(gb); if(r->is16){ - s->current_picture_ptr->mb_type[mb_pos] = MB_TYPE_INTRA16x16; + s->cur_pic.mb_type[mb_pos] = MB_TYPE_INTRA16x16; r->block_type = RV34_MB_TYPE_INTRA16x16; t = get_bits(gb, 2); fill_rectangle(intra_types, 4, 4, r->intra_types_stride, t, sizeof(intra_types[0])); @@ -378,7 +379,7 @@ static int rv34_decode_intra_mb_header(RV34DecContext *r, int8_t *intra_types) if(!get_bits1(gb)) av_log(s->avctx, AV_LOG_ERROR, "Need DQUANT\n"); } - s->current_picture_ptr->mb_type[mb_pos] = MB_TYPE_INTRA; + s->cur_pic.mb_type[mb_pos] = MB_TYPE_INTRA; r->block_type = RV34_MB_TYPE_INTRA; if(r->decode_intra_types(r, gb, intra_types) < 0) return -1; @@ -404,7 +405,7 @@ static int rv34_decode_inter_mb_header(RV34DecContext *r, int8_t *intra_types) r->block_type = r->decode_mb_info(r); if(r->block_type == -1) return -1; - s->current_picture_ptr->mb_type[mb_pos] = rv34_mb_type_to_lavc[r->block_type]; + s->cur_pic.mb_type[mb_pos] = rv34_mb_type_to_lavc[r->block_type]; r->mb_type[mb_pos] = r->block_type; if(r->block_type == RV34_MB_SKIP){ if(s->pict_type == AV_PICTURE_TYPE_P) @@ -412,7 +413,7 @@ static int rv34_decode_inter_mb_header(RV34DecContext *r, int8_t *intra_types) if(s->pict_type == AV_PICTURE_TYPE_B) r->mb_type[mb_pos] = RV34_MB_B_DIRECT; } - r->is16 = !!IS_INTRA16x16(s->current_picture_ptr->mb_type[mb_pos]); + r->is16 = !!IS_INTRA16x16(s->cur_pic.mb_type[mb_pos]); if (rv34_decode_mv(r, r->block_type) < 0) return -1; if(r->block_type == RV34_MB_SKIP){ @@ -422,7 +423,7 @@ static int rv34_decode_inter_mb_header(RV34DecContext *r, int8_t *intra_types) r->chroma_vlc = 1; r->luma_vlc = 0; - if(IS_INTRA(s->current_picture_ptr->mb_type[mb_pos])){ + if (IS_INTRA(s->cur_pic.mb_type[mb_pos])) { if(r->is16){ t = get_bits(gb, 2); fill_rectangle(intra_types, 4, 4, r->intra_types_stride, t, sizeof(intra_types[0])); @@ -481,33 +482,34 @@ static void rv34_pred_mv(RV34DecContext *r, int block_type, int subblock_no, int int mx, my; int* avail = r->avail_cache + avail_indexes[subblock_no]; int c_off = part_sizes_w[block_type]; + int16_t (*motion_val)[2] = s->cur_pic.motion_val[0]; mv_pos += (subblock_no & 1) + (subblock_no >> 1)*s->b8_stride; if(subblock_no == 3) c_off = -1; if(avail[-1]){ - A[0] = s->current_picture_ptr->motion_val[0][mv_pos-1][0]; - A[1] = s->current_picture_ptr->motion_val[0][mv_pos-1][1]; + A[0] = motion_val[mv_pos-1][0]; + A[1] = motion_val[mv_pos-1][1]; } if(avail[-4]){ - B[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride][0]; - B[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride][1]; + B[0] = motion_val[mv_pos-s->b8_stride][0]; + B[1] = motion_val[mv_pos-s->b8_stride][1]; }else{ B[0] = A[0]; B[1] = A[1]; } if(!avail[c_off-4]){ if(avail[-4] && (avail[-1] || r->rv30)){ - C[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride-1][0]; - C[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride-1][1]; + C[0] = motion_val[mv_pos-s->b8_stride-1][0]; + C[1] = motion_val[mv_pos-s->b8_stride-1][1]; }else{ C[0] = A[0]; C[1] = A[1]; } }else{ - C[0] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+c_off][0]; - C[1] = s->current_picture_ptr->motion_val[0][mv_pos-s->b8_stride+c_off][1]; + C[0] = motion_val[mv_pos-s->b8_stride+c_off][0]; + C[1] = motion_val[mv_pos-s->b8_stride+c_off][1]; } mx = mid_pred(A[0], B[0], C[0]); my = mid_pred(A[1], B[1], C[1]); @@ -515,8 +517,8 @@ static void rv34_pred_mv(RV34DecContext *r, int block_type, int subblock_no, int my += r->dmv[dmv_no][1]; for(j = 0; j < part_sizes_h[block_type]; j++){ for(i = 0; i < part_sizes_w[block_type]; i++){ - s->current_picture_ptr->motion_val[0][mv_pos + i + j*s->b8_stride][0] = mx; - s->current_picture_ptr->motion_val[0][mv_pos + i + j*s->b8_stride][1] = my; + motion_val[mv_pos + i + j*s->b8_stride][0] = mx; + motion_val[mv_pos + i + j*s->b8_stride][1] = my; } } } @@ -565,8 +567,8 @@ static void rv34_pred_mv_b(RV34DecContext *r, int block_type, int dir) int has_A = 0, has_B = 0, has_C = 0; int mx, my; int i, j; - Picture *cur_pic = s->current_picture_ptr; - const int mask = dir ? MB_TYPE_L1 : MB_TYPE_L0; + MPVWorkPicture *cur_pic = &s->cur_pic; + const int mask = dir ? MB_TYPE_BACKWARD_MV : MB_TYPE_FORWARD_MV; int type = cur_pic->mb_type[mb_pos]; if((r->avail_cache[6-1] & type) & mask){ @@ -618,27 +620,27 @@ static void rv34_pred_mv_rv3(RV34DecContext *r, int block_type, int dir) int* avail = r->avail_cache + avail_indexes[0]; if(avail[-1]){ - A[0] = s->current_picture_ptr->motion_val[0][mv_pos - 1][0]; - A[1] = s->current_picture_ptr->motion_val[0][mv_pos - 1][1]; + A[0] = s->cur_pic.motion_val[0][mv_pos - 1][0]; + A[1] = s->cur_pic.motion_val[0][mv_pos - 1][1]; } if(avail[-4]){ - B[0] = s->current_picture_ptr->motion_val[0][mv_pos - s->b8_stride][0]; - B[1] = s->current_picture_ptr->motion_val[0][mv_pos - s->b8_stride][1]; + B[0] = s->cur_pic.motion_val[0][mv_pos - s->b8_stride][0]; + B[1] = s->cur_pic.motion_val[0][mv_pos - s->b8_stride][1]; }else{ B[0] = A[0]; B[1] = A[1]; } if(!avail[-4 + 2]){ if(avail[-4] && (avail[-1])){ - C[0] = s->current_picture_ptr->motion_val[0][mv_pos - s->b8_stride - 1][0]; - C[1] = s->current_picture_ptr->motion_val[0][mv_pos - s->b8_stride - 1][1]; + C[0] = s->cur_pic.motion_val[0][mv_pos - s->b8_stride - 1][0]; + C[1] = s->cur_pic.motion_val[0][mv_pos - s->b8_stride - 1][1]; }else{ C[0] = A[0]; C[1] = A[1]; } }else{ - C[0] = s->current_picture_ptr->motion_val[0][mv_pos - s->b8_stride + 2][0]; - C[1] = s->current_picture_ptr->motion_val[0][mv_pos - s->b8_stride + 2][1]; + C[0] = s->cur_pic.motion_val[0][mv_pos - s->b8_stride + 2][0]; + C[1] = s->cur_pic.motion_val[0][mv_pos - s->b8_stride + 2][1]; } mx = mid_pred(A[0], B[0], C[0]); my = mid_pred(A[1], B[1], C[1]); @@ -647,8 +649,8 @@ static void rv34_pred_mv_rv3(RV34DecContext *r, int block_type, int dir) for(j = 0; j < 2; j++){ for(i = 0; i < 2; i++){ for(k = 0; k < 2; k++){ - s->current_picture_ptr->motion_val[k][mv_pos + i + j*s->b8_stride][0] = mx; - s->current_picture_ptr->motion_val[k][mv_pos + i + j*s->b8_stride][1] = my; + s->cur_pic.motion_val[k][mv_pos + i + j*s->b8_stride][0] = mx; + s->cur_pic.motion_val[k][mv_pos + i + j*s->b8_stride][1] = my; } } } @@ -679,32 +681,34 @@ static inline void rv34_mc(RV34DecContext *r, const int block_type, h264_chroma_mc_func (*chroma_mc)) { MpegEncContext *s = &r->s; - uint8_t *Y, *U, *V, *srcY, *srcU, *srcV; + uint8_t *Y, *U, *V; + const uint8_t *srcY, *srcU, *srcV; int dxy, mx, my, umx, umy, lx, ly, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y; int mv_pos = s->mb_x * 2 + s->mb_y * 2 * s->b8_stride + mv_off; int is16x16 = 1; int emu = 0; + int16_t *motion_val = s->cur_pic.motion_val[dir][mv_pos]; if(thirdpel){ int chroma_mx, chroma_my; - mx = (s->current_picture_ptr->motion_val[dir][mv_pos][0] + (3 << 24)) / 3 - (1 << 24); - my = (s->current_picture_ptr->motion_val[dir][mv_pos][1] + (3 << 24)) / 3 - (1 << 24); - lx = (s->current_picture_ptr->motion_val[dir][mv_pos][0] + (3 << 24)) % 3; - ly = (s->current_picture_ptr->motion_val[dir][mv_pos][1] + (3 << 24)) % 3; - chroma_mx = s->current_picture_ptr->motion_val[dir][mv_pos][0] / 2; - chroma_my = s->current_picture_ptr->motion_val[dir][mv_pos][1] / 2; + mx = (motion_val[0] + (3 << 24)) / 3 - (1 << 24); + my = (motion_val[1] + (3 << 24)) / 3 - (1 << 24); + lx = (motion_val[0] + (3 << 24)) % 3; + ly = (motion_val[1] + (3 << 24)) % 3; + chroma_mx = motion_val[0] / 2; + chroma_my = motion_val[1] / 2; umx = (chroma_mx + (3 << 24)) / 3 - (1 << 24); umy = (chroma_my + (3 << 24)) / 3 - (1 << 24); uvmx = chroma_coeffs[(chroma_mx + (3 << 24)) % 3]; uvmy = chroma_coeffs[(chroma_my + (3 << 24)) % 3]; }else{ int cx, cy; - mx = s->current_picture_ptr->motion_val[dir][mv_pos][0] >> 2; - my = s->current_picture_ptr->motion_val[dir][mv_pos][1] >> 2; - lx = s->current_picture_ptr->motion_val[dir][mv_pos][0] & 3; - ly = s->current_picture_ptr->motion_val[dir][mv_pos][1] & 3; - cx = s->current_picture_ptr->motion_val[dir][mv_pos][0] / 2; - cy = s->current_picture_ptr->motion_val[dir][mv_pos][1] / 2; + mx = motion_val[0] >> 2; + my = motion_val[1] >> 2; + lx = motion_val[0] & 3; + ly = motion_val[1] & 3; + cx = motion_val[0] / 2; + cy = motion_val[1] / 2; umx = cx >> 2; umy = cy >> 2; uvmx = (cx & 3) << 1; @@ -717,14 +721,14 @@ static inline void rv34_mc(RV34DecContext *r, const int block_type, if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) { /* wait for the referenced mb row to be finished */ int mb_row = s->mb_y + ((yoff + my + 5 + 8 * height) >> 4); - const ThreadFrame *f = dir ? &s->next_picture_ptr->tf : &s->last_picture_ptr->tf; - ff_thread_await_progress(f, mb_row, 0); + const ThreadProgress *p = dir ? &s->next_pic.ptr->progress : &s->last_pic.ptr->progress; + ff_thread_progress_await(p, mb_row); } dxy = ly*4 + lx; - srcY = dir ? s->next_picture_ptr->f->data[0] : s->last_picture_ptr->f->data[0]; - srcU = dir ? s->next_picture_ptr->f->data[1] : s->last_picture_ptr->f->data[1]; - srcV = dir ? s->next_picture_ptr->f->data[2] : s->last_picture_ptr->f->data[2]; + srcY = dir ? s->next_pic.data[0] : s->last_pic.data[0]; + srcU = dir ? s->next_pic.data[1] : s->last_pic.data[1]; + srcV = dir ? s->next_pic.data[2] : s->last_pic.data[2]; src_x = s->mb_x * 16 + xoff + mx; src_y = s->mb_y * 16 + yoff + my; uvsrc_x = s->mb_x * 8 + (xoff >> 1) + umx; @@ -885,11 +889,11 @@ static int rv34_decode_mv(RV34DecContext *r, int block_type) switch(block_type){ case RV34_MB_TYPE_INTRA: case RV34_MB_TYPE_INTRA16x16: - ZERO8x2(s->current_picture_ptr->motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); + ZERO8x2(s->cur_pic.motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); return 0; case RV34_MB_SKIP: if(s->pict_type == AV_PICTURE_TYPE_P){ - ZERO8x2(s->current_picture_ptr->motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); + ZERO8x2(s->cur_pic.motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); rv34_mc_1mv (r, block_type, 0, 0, 0, 2, 2, 0); break; } @@ -897,23 +901,23 @@ static int rv34_decode_mv(RV34DecContext *r, int block_type) //surprisingly, it uses motion scheme from next reference frame /* wait for the current mb row to be finished */ if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) - ff_thread_await_progress(&s->next_picture_ptr->tf, FFMAX(0, s->mb_y-1), 0); + ff_thread_progress_await(&s->next_pic.ptr->progress, FFMAX(0, s->mb_y-1)); - next_bt = s->next_picture_ptr->mb_type[s->mb_x + s->mb_y * s->mb_stride]; + next_bt = s->next_pic.mb_type[s->mb_x + s->mb_y * s->mb_stride]; if(IS_INTRA(next_bt) || IS_SKIP(next_bt)){ - ZERO8x2(s->current_picture_ptr->motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); - ZERO8x2(s->current_picture_ptr->motion_val[1][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); + ZERO8x2(s->cur_pic.motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); + ZERO8x2(s->cur_pic.motion_val[1][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); }else for(j = 0; j < 2; j++) for(i = 0; i < 2; i++) for(k = 0; k < 2; k++) for(l = 0; l < 2; l++) - s->current_picture_ptr->motion_val[l][mv_pos + i + j*s->b8_stride][k] = calc_add_mv(r, l, s->next_picture_ptr->motion_val[0][mv_pos + i + j*s->b8_stride][k]); + s->cur_pic.motion_val[l][mv_pos + i + j*s->b8_stride][k] = calc_add_mv(r, l, s->next_pic.motion_val[0][mv_pos + i + j*s->b8_stride][k]); if(!(IS_16X8(next_bt) || IS_8X16(next_bt) || IS_8X8(next_bt))) //we can use whole macroblock MC rv34_mc_2mv(r, block_type); else rv34_mc_2mv_skip(r); - ZERO8x2(s->current_picture_ptr->motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); + ZERO8x2(s->cur_pic.motion_val[0][s->mb_x * 2 + s->mb_y * 2 * s->b8_stride], s->b8_stride); break; case RV34_MB_P_16x16: case RV34_MB_P_MIX16x16: @@ -1181,7 +1185,7 @@ static int rv34_set_deblock_coef(RV34DecContext *r) MpegEncContext *s = &r->s; int hmvmask = 0, vmvmask = 0, i, j; int midx = s->mb_x * 2 + s->mb_y * 2 * s->b8_stride; - int16_t (*motion_val)[2] = &s->current_picture_ptr->motion_val[0][midx]; + int16_t (*motion_val)[2] = &s->cur_pic.motion_val[0][midx]; for(j = 0; j < 16; j += 8){ for(i = 0; i < 2; i++){ if(is_mv_diff_gt_3(motion_val + i, 1)) @@ -1224,26 +1228,26 @@ static int rv34_decode_inter_macroblock(RV34DecContext *r, int8_t *intra_types) dist = (s->mb_x - s->resync_mb_x) + (s->mb_y - s->resync_mb_y) * s->mb_width; if(s->mb_x && dist) r->avail_cache[5] = - r->avail_cache[9] = s->current_picture_ptr->mb_type[mb_pos - 1]; + r->avail_cache[9] = s->cur_pic.mb_type[mb_pos - 1]; if(dist >= s->mb_width) r->avail_cache[2] = - r->avail_cache[3] = s->current_picture_ptr->mb_type[mb_pos - s->mb_stride]; + r->avail_cache[3] = s->cur_pic.mb_type[mb_pos - s->mb_stride]; if(((s->mb_x+1) < s->mb_width) && dist >= s->mb_width - 1) - r->avail_cache[4] = s->current_picture_ptr->mb_type[mb_pos - s->mb_stride + 1]; + r->avail_cache[4] = s->cur_pic.mb_type[mb_pos - s->mb_stride + 1]; if(s->mb_x && dist > s->mb_width) - r->avail_cache[1] = s->current_picture_ptr->mb_type[mb_pos - s->mb_stride - 1]; + r->avail_cache[1] = s->cur_pic.mb_type[mb_pos - s->mb_stride - 1]; s->qscale = r->si.quant; cbp = cbp2 = rv34_decode_inter_mb_header(r, intra_types); r->cbp_luma [mb_pos] = cbp; r->cbp_chroma[mb_pos] = cbp >> 16; r->deblock_coefs[mb_pos] = rv34_set_deblock_coef(r) | r->cbp_luma[mb_pos]; - s->current_picture_ptr->qscale_table[mb_pos] = s->qscale; + s->cur_pic.qscale_table[mb_pos] = s->qscale; if(cbp == -1) return -1; - if (IS_INTRA(s->current_picture_ptr->mb_type[mb_pos])){ + if (IS_INTRA(s->cur_pic.mb_type[mb_pos])) { if(r->is16) rv34_output_i16x16(r, intra_types, cbp); else rv34_output_intra(r, intra_types, cbp); return 0; @@ -1326,21 +1330,21 @@ static int rv34_decode_intra_macroblock(RV34DecContext *r, int8_t *intra_types) dist = (s->mb_x - s->resync_mb_x) + (s->mb_y - s->resync_mb_y) * s->mb_width; if(s->mb_x && dist) r->avail_cache[5] = - r->avail_cache[9] = s->current_picture_ptr->mb_type[mb_pos - 1]; + r->avail_cache[9] = s->cur_pic.mb_type[mb_pos - 1]; if(dist >= s->mb_width) r->avail_cache[2] = - r->avail_cache[3] = s->current_picture_ptr->mb_type[mb_pos - s->mb_stride]; + r->avail_cache[3] = s->cur_pic.mb_type[mb_pos - s->mb_stride]; if(((s->mb_x+1) < s->mb_width) && dist >= s->mb_width - 1) - r->avail_cache[4] = s->current_picture_ptr->mb_type[mb_pos - s->mb_stride + 1]; + r->avail_cache[4] = s->cur_pic.mb_type[mb_pos - s->mb_stride + 1]; if(s->mb_x && dist > s->mb_width) - r->avail_cache[1] = s->current_picture_ptr->mb_type[mb_pos - s->mb_stride - 1]; + r->avail_cache[1] = s->cur_pic.mb_type[mb_pos - s->mb_stride - 1]; s->qscale = r->si.quant; cbp = rv34_decode_intra_mb_header(r, intra_types); r->cbp_luma [mb_pos] = cbp; r->cbp_chroma[mb_pos] = cbp >> 16; r->deblock_coefs[mb_pos] = 0xFFFF; - s->current_picture_ptr->qscale_table[mb_pos] = s->qscale; + s->cur_pic.qscale_table[mb_pos] = s->qscale; if(cbp == -1) return -1; @@ -1481,8 +1485,8 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int r->loop_filter(r, s->mb_y - 2); if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) - ff_thread_report_progress(&s->current_picture_ptr->tf, - s->mb_y - 2, 0); + ff_thread_progress_report(&s->cur_pic.ptr->progress, + s->mb_y - 2); } if(s->mb_x == s->resync_mb_x) @@ -1506,7 +1510,9 @@ av_cold int ff_rv34_decode_init(AVCodecContext *avctx) MpegEncContext *s = &r->s; int ret; - ff_mpv_decode_init(s, avctx); + ret = ff_mpv_decode_init(s, avctx); + if (ret < 0) + return ret; s->out_format = FMT_H263; avctx->pix_fmt = AV_PIX_FMT_YUV420P; @@ -1518,10 +1524,9 @@ av_cold int ff_rv34_decode_init(AVCodecContext *avctx) ff_h264_pred_init(&r->h, AV_CODEC_ID_RV40, 8, 1); - if ((ret = rv34_decoder_alloc(r)) < 0) { - ff_mpv_common_end(&r->s); + ret = rv34_decoder_alloc(r); + if (ret < 0) return ret; - } ff_thread_once(&init_static_once, rv34_init_tables); @@ -1579,19 +1584,19 @@ static int finish_frame(AVCodecContext *avctx, AVFrame *pict) s->mb_num_left = 0; if (HAVE_THREADS && (s->avctx->active_thread_type & FF_THREAD_FRAME)) - ff_thread_report_progress(&s->current_picture_ptr->tf, INT_MAX, 0); + ff_thread_progress_report(&s->cur_pic.ptr->progress, INT_MAX); if (s->pict_type == AV_PICTURE_TYPE_B) { - if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0) + if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) return ret; - ff_print_debug_info(s, s->current_picture_ptr, pict); - ff_mpv_export_qp_table(s, pict, s->current_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG1); + 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); got_picture = 1; - } else if (s->last_picture_ptr) { - if ((ret = av_frame_ref(pict, s->last_picture_ptr->f)) < 0) + } else if (s->last_pic.ptr) { + if ((ret = av_frame_ref(pict, s->last_pic.ptr->f)) < 0) return ret; - ff_print_debug_info(s, s->last_picture_ptr, pict); - ff_mpv_export_qp_table(s, pict, s->last_picture_ptr, FF_MPV_QSCALE_TYPE_MPEG1); + 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); got_picture = 1; } @@ -1626,10 +1631,10 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, /* no supplementary picture */ if (buf_size == 0) { /* special case for last picture */ - if (s->next_picture_ptr) { - if ((ret = av_frame_ref(pict, s->next_picture_ptr->f)) < 0) + if (s->next_pic.ptr) { + if ((ret = av_frame_ref(pict, s->next_pic.ptr->f)) < 0) return ret; - s->next_picture_ptr = NULL; + ff_mpv_unref_picture(&s->next_pic); *got_picture_ptr = 1; } @@ -1652,8 +1657,7 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, av_log(avctx, AV_LOG_ERROR, "First slice header is incorrect\n"); return AVERROR_INVALIDDATA; } - if ((!s->last_picture_ptr || !s->last_picture_ptr->f->data[0]) && - si.type == AV_PICTURE_TYPE_B) { + if (!s->last_pic.ptr && si.type == AV_PICTURE_TYPE_B) { av_log(avctx, AV_LOG_ERROR, "Invalid decoder state: B-frame without " "reference data.\n"); faulty_b = 1; @@ -1665,7 +1669,7 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, /* first slice */ if (si.start == 0) { - if (s->mb_num_left > 0 && s->current_picture_ptr) { + if (s->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); if (!s->context_reinit) @@ -1790,7 +1794,7 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, break; } - if (s->current_picture_ptr) { + if (s->cur_pic.ptr) { if (last) { if(r->loop_filter) r->loop_filter(r, s->mb_height - 1); @@ -1807,7 +1811,7 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, AVFrame *pict, ff_er_frame_end(&s->er, NULL); ff_mpv_frame_end(s); s->mb_num_left = 0; - ff_thread_report_progress(&s->current_picture_ptr->tf, INT_MAX, 0); + ff_thread_progress_report(&s->cur_pic.ptr->progress, INT_MAX); return AVERROR_INVALIDDATA; } } @@ -1819,8 +1823,7 @@ av_cold int ff_rv34_decode_end(AVCodecContext *avctx) { RV34DecContext *r = avctx->priv_data; - ff_mpv_common_end(&r->s); rv34_decoder_free(r); - return 0; + return ff_mpv_decode_close(avctx); } diff --git a/libavcodec/rv34dsp.h b/libavcodec/rv34dsp.h index b15424d4a..d59b3c273 100644 --- a/libavcodec/rv34dsp.h +++ b/libavcodec/rv34dsp.h @@ -83,6 +83,7 @@ void ff_rv34dsp_init_riscv(RV34DSPContext *c); void ff_rv34dsp_init_x86(RV34DSPContext *c); void ff_rv40dsp_init_aarch64(RV34DSPContext *c); +void ff_rv40dsp_init_riscv(RV34DSPContext *c); void ff_rv40dsp_init_x86(RV34DSPContext *c); void ff_rv40dsp_init_arm(RV34DSPContext *c); diff --git a/libavcodec/rv40.c b/libavcodec/rv40.c index e48aa1f68..0a5136d12 100644 --- a/libavcodec/rv40.c +++ b/libavcodec/rv40.c @@ -371,7 +371,7 @@ static void rv40_loop_filter(RV34DecContext *r, int row) mb_pos = row * s->mb_stride; for(mb_x = 0; mb_x < s->mb_width; mb_x++, mb_pos++){ - int mbtype = s->current_picture_ptr->mb_type[mb_pos]; + int mbtype = s->cur_pic.mb_type[mb_pos]; if(IS_INTRA(mbtype) || IS_SEPARATE_DC(mbtype)) r->cbp_luma [mb_pos] = r->deblock_coefs[mb_pos] = 0xFFFF; if(IS_INTRA(mbtype)) @@ -386,7 +386,7 @@ static void rv40_loop_filter(RV34DecContext *r, int row) unsigned y_to_deblock; int c_to_deblock[2]; - q = s->current_picture_ptr->qscale_table[mb_pos]; + q = s->cur_pic.qscale_table[mb_pos]; alpha = rv40_alpha_tab[q]; beta = rv40_beta_tab [q]; betaY = betaC = beta * 3; @@ -401,7 +401,7 @@ static void rv40_loop_filter(RV34DecContext *r, int row) if(avail[i]){ int pos = mb_pos + neighbour_offs_x[i] + neighbour_offs_y[i]*s->mb_stride; mvmasks[i] = r->deblock_coefs[pos]; - mbtype [i] = s->current_picture_ptr->mb_type[pos]; + mbtype [i] = s->cur_pic.mb_type[pos]; cbp [i] = r->cbp_luma[pos]; uvcbp[i][0] = r->cbp_chroma[pos] & 0xF; uvcbp[i][1] = r->cbp_chroma[pos] >> 4; @@ -460,7 +460,7 @@ static void rv40_loop_filter(RV34DecContext *r, int row) } for(j = 0; j < 16; j += 4){ - Y = s->current_picture_ptr->f->data[0] + mb_x*16 + (row*16 + j) * s->linesize; + Y = s->cur_pic.data[0] + mb_x*16 + (row*16 + j) * s->linesize; for(i = 0; i < 4; i++, Y += 4){ int ij = i + j; int clip_cur = y_to_deblock & (MASK_CUR << ij) ? clip[POS_CUR] : 0; @@ -505,7 +505,7 @@ static void rv40_loop_filter(RV34DecContext *r, int row) } for(k = 0; k < 2; k++){ for(j = 0; j < 2; j++){ - C = s->current_picture_ptr->f->data[k + 1] + mb_x*8 + (row*8 + j*4) * s->uvlinesize; + C = s->cur_pic.data[k + 1] + mb_x*8 + (row*8 + j*4) * s->uvlinesize; for(i = 0; i < 2; i++, C += 4){ int ij = i + j*2; int clip_cur = c_to_deblock[k] & (MASK_CUR << ij) ? clip[POS_CUR] : 0; @@ -580,7 +580,7 @@ const FFCodec ff_rv40_decoder = { FF_CODEC_DECODE_CB(ff_rv34_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .flush = ff_mpeg_flush, UPDATE_THREAD_CONTEXT(ff_rv34_decode_update_thread_context), - .caps_internal = FF_CODEC_CAP_ALLOCATE_PROGRESS, }; diff --git a/libavcodec/rv40dsp.c b/libavcodec/rv40dsp.c index f0208b16e..970faec5d 100644 --- a/libavcodec/rv40dsp.c +++ b/libavcodec/rv40dsp.c @@ -709,6 +709,8 @@ av_cold void ff_rv40dsp_init(RV34DSPContext *c) ff_rv40dsp_init_aarch64(c); #elif ARCH_ARM ff_rv40dsp_init_arm(c); +#elif ARCH_RISCV + ff_rv40dsp_init_riscv(c); #elif ARCH_X86 ff_rv40dsp_init_x86(c); #endif diff --git a/libavcodec/samidec.c b/libavcodec/samidec.c index e84c4bc6b..6576ce93f 100644 --- a/libavcodec/samidec.c +++ b/libavcodec/samidec.c @@ -27,6 +27,7 @@ #include "ass.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" +#include "libavutil/mem.h" #include "codec_internal.h" #include "htmlsubtitles.h" diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c index b70daab7a..8b7c0d955 100644 --- a/libavcodec/sanm.c +++ b/libavcodec/sanm.c @@ -21,6 +21,7 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/sbr.h b/libavcodec/sbr.h index fe3a39603..40bb30e04 100644 --- a/libavcodec/sbr.h +++ b/libavcodec/sbr.h @@ -68,9 +68,9 @@ typedef struct SBRData { unsigned bs_frame_class; unsigned bs_add_harmonic_flag; AAC_SIGNE bs_num_env; - uint8_t bs_freq_res[7]; + uint8_t bs_freq_res[9]; AAC_SIGNE bs_num_noise; - uint8_t bs_df_env[5]; + uint8_t bs_df_env[9]; uint8_t bs_df_noise[2]; uint8_t bs_invf_mode[2][5]; uint8_t bs_add_harmonic[48]; @@ -95,21 +95,24 @@ typedef struct SBRData { DECLARE_ALIGNED(16, INTFLOAT, Y)[2][38][64][2]; DECLARE_ALIGNED(16, AAC_FLOAT, g_temp)[42][48]; AAC_FLOAT q_temp[42][48]; - uint8_t s_indexmapped[8][48]; + uint8_t s_indexmapped[9][48]; ///Envelope scalefactors - uint8_t env_facs_q[6][48]; - AAC_FLOAT env_facs[6][48]; + uint8_t env_facs_q[9][48]; + AAC_FLOAT env_facs[9][48]; ///Noise scalefactors uint8_t noise_facs_q[3][5]; AAC_FLOAT noise_facs[3][5]; ///Envelope time borders - uint8_t t_env[8]; + uint8_t t_env[9]; ///Envelope time border of the last envelope of the previous frame uint8_t t_env_num_env_old; ///Noise time borders uint8_t t_q[3]; unsigned f_indexnoise; unsigned f_indexsine; + //inter_tes (USAC) + uint8_t temp_shape[6]; + uint8_t temp_shape_mode[6]; /** @} */ } SBRData; @@ -142,9 +145,12 @@ struct SpectralBandReplication { int start; int ready_for_dequant; int id_aac; + int usac; + int inter_tes; // USAC-only int reset; SpectrumParameters spectrum_params; int bs_amp_res_header; + int bs_sbr_preprocessing; // USAC-only /** * @name Variables associated with bs_header_extra_2 * @{ @@ -196,18 +202,18 @@ struct SpectralBandReplication { ///First coefficient used to filter the subband signals DECLARE_ALIGNED(16, INTFLOAT, alpha1)[64][2]; ///Dequantized envelope scalefactors, remapped - AAC_FLOAT e_origmapped[7][48]; + AAC_FLOAT e_origmapped[8][48]; ///Dequantized noise scalefactors, remapped - AAC_FLOAT q_mapped[7][48]; + AAC_FLOAT q_mapped[8][48]; ///Sinusoidal presence, remapped - uint8_t s_mapped[7][48]; + uint8_t s_mapped[8][48]; ///Estimated envelope - AAC_FLOAT e_curr[7][48]; + AAC_FLOAT e_curr[8][48]; ///Amplitude adjusted noise scalefactors - AAC_FLOAT q_m[7][48]; + AAC_FLOAT q_m[8][48]; ///Sinusoidal levels - AAC_FLOAT s_m[7][48]; - AAC_FLOAT gain[7][48]; + AAC_FLOAT s_m[8][48]; + AAC_FLOAT gain[8][48]; DECLARE_ALIGNED(32, INTFLOAT, qmf_filter_scratch)[5][64]; AVTXContext *mdct_ana; av_tx_fn mdct_ana_fn; diff --git a/libavcodec/sbrdsp.h b/libavcodec/sbrdsp.h index 49782202a..09b2cbfc1 100644 --- a/libavcodec/sbrdsp.h +++ b/libavcodec/sbrdsp.h @@ -50,6 +50,5 @@ void ff_sbrdsp_init_arm(SBRDSPContext *s); void ff_sbrdsp_init_aarch64(SBRDSPContext *s); void ff_sbrdsp_init_riscv(SBRDSPContext *s); void ff_sbrdsp_init_x86(SBRDSPContext *s); -void ff_sbrdsp_init_mips(SBRDSPContext *s); #endif /* AVCODEC_SBRDSP_H */ diff --git a/libavcodec/sbrdsp_template.c b/libavcodec/sbrdsp_template.c index 75cf3dbdf..9a94af867 100644 --- a/libavcodec/sbrdsp_template.c +++ b/libavcodec/sbrdsp_template.c @@ -104,8 +104,6 @@ av_cold void AAC_RENAME(ff_sbrdsp_init)(SBRDSPContext *s) ff_sbrdsp_init_riscv(s); #elif ARCH_X86 ff_sbrdsp_init_x86(s); -#elif ARCH_MIPS - ff_sbrdsp_init_mips(s); #endif #endif /* !USE_FIXED */ } @@ -378,5 +376,13 @@ const attribute_visibility_hidden DECLARE_ALIGNED(16, INTFLOAT, AAC_RENAME(ff_sb {Q31(-0.99867974711855f), Q31(-0.88147068645358f)}, {Q31(-0.95531076805040f), Q31( 0.90908757154593f)}, {Q31(-0.45725933317144f), Q31(-0.56716323646760f)}, {Q31(-0.72929675029275f), Q31(-0.98008272727324f)}, {Q31( 0.75622801399036f), Q31( 0.20950329995549f)}, {Q31( 0.07069442601050f), Q31(-0.78247898470706f)}, +{Q31( 0.74496252926055f), Q31(-0.91169004445807f)}, {Q31(-0.96440182703856f), Q31(-0.94739918296622f)}, +{Q31( 0.30424629369539f), Q31(-0.49438267012479f)}, {Q31( 0.66565033746925f), Q31( 0.64652935542491f)}, +{Q31( 0.91697008020594f), Q31( 0.17514097332009f)}, {Q31(-0.70774918760427f), Q31( 0.52548653416543f)}, +{Q31(-0.70051415345560f), Q31(-0.45340028808763f)}, {Q31(-0.99496513054797f), Q31(-0.90071908066973f)}, +{Q31( 0.98164490790123f), Q31(-0.77463155528697f)}, {Q31(-0.54671580548181f), Q31(-0.02570928536004f)}, +{Q31(-0.01689629065389f), Q31( 0.00287506445732f)}, {Q31(-0.86110349531986f), Q31( 0.42548583726477f)}, +{Q31(-0.98892980586032f), Q31(-0.87881132267556f)}, {Q31( 0.51756627678691f), Q31( 0.66926784710139f)}, +{Q31(-0.99635026409640f), Q31(-0.58107730574765f)}, {Q31(-0.99969370862163f), Q31( 0.98369989360250f)}, #endif }; diff --git a/libavcodec/scpr.c b/libavcodec/scpr.c index b096965de..9a6e8bdcb 100644 --- a/libavcodec/scpr.c +++ b/libavcodec/scpr.c @@ -22,6 +22,7 @@ #include +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/sga.c b/libavcodec/sga.c index f474ffba9..c828f7147 100644 --- a/libavcodec/sga.c +++ b/libavcodec/sga.c @@ -19,6 +19,7 @@ */ #include "libavutil/common.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "get_bits.h" #include "bytestream.h" @@ -253,11 +254,13 @@ static int decode_palmapdata(AVCodecContext *avctx) const int bits = (s->nb_pal + 1) / 2; GetByteContext *gb = &s->gb; GetBitContext pm; + int ret; bytestream2_seek(gb, s->palmapdata_offset, SEEK_SET); if (bytestream2_get_bytes_left(gb) < s->palmapdata_size) return AVERROR_INVALIDDATA; - init_get_bits8(&pm, gb->buffer, s->palmapdata_size); + ret = init_get_bits8(&pm, gb->buffer, s->palmapdata_size); + av_assert1(ret >= 0); for (int y = 0; y < s->tiles_h; y++) { uint8_t *dst = s->palmapindex_data + y * s->tiles_w; @@ -276,11 +279,13 @@ static int decode_tiledata(AVCodecContext *avctx) SGAVideoContext *s = avctx->priv_data; GetByteContext *gb = &s->gb; GetBitContext tm; + int ret; bytestream2_seek(gb, s->tiledata_offset, SEEK_SET); if (bytestream2_get_bytes_left(gb) < s->tiledata_size) return AVERROR_INVALIDDATA; - init_get_bits8(&tm, gb->buffer, s->tiledata_size); + ret = init_get_bits8(&tm, gb->buffer, s->tiledata_size); + av_assert1(ret >= 0); for (int n = 0; n < s->nb_tiles; n++) { uint8_t *dst = s->tileindex_data + n * 64; diff --git a/libavcodec/sgidec.c b/libavcodec/sgidec.c index 04a347c51..40186dcdb 100644 --- a/libavcodec/sgidec.c +++ b/libavcodec/sgidec.c @@ -248,8 +248,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, MAP(2, 1); break; } - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; /* Skip header. */ bytestream2_seek(&g, SGI_HEADER_SIZE, SEEK_SET); diff --git a/libavcodec/sgienc.c b/libavcodec/sgienc.c index 5bbb72c03..0901cf58b 100644 --- a/libavcodec/sgienc.c +++ b/libavcodec/sgienc.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" diff --git a/libavcodec/sgirledec.c b/libavcodec/sgirledec.c index 18bf8081f..3bd31b734 100644 --- a/libavcodec/sgirledec.c +++ b/libavcodec/sgirledec.c @@ -115,6 +115,9 @@ static int sgirle_decode_frame(AVCodecContext *avctx, AVFrame *frame, { int ret; + if (avpkt->size * 192ll / 2 < avctx->width * avctx->height) + return AVERROR_INVALIDDATA; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; @@ -123,9 +126,6 @@ static int sgirle_decode_frame(AVCodecContext *avctx, AVFrame *frame, if (ret < 0) return ret; - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/sh4/README b/libavcodec/sh4/README deleted file mode 100644 index 8dd61fe87..000000000 --- a/libavcodec/sh4/README +++ /dev/null @@ -1,6 +0,0 @@ -SH4 optimizations have been removed in -commit d6096a67422534918405abb46dafbbac4608cbc3 -The last revission with the optimizations is cbfc9046e1c7e295b74f252902ae6f255eef4e78 - -If you want to maintain these (or other) SH4 optimizations in ffmpeg, then please -contact ffmpeg-devel@ffmpeg.org diff --git a/libavcodec/sheervideo.c b/libavcodec/sheervideo.c index 660e2661a..ef20633e1 100644 --- a/libavcodec/sheervideo.c +++ b/libavcodec/sheervideo.c @@ -1972,9 +1972,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, return AVERROR_INVALIDDATA; } - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; - if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0) return ret; diff --git a/libavcodec/shorten.c b/libavcodec/shorten.c index 0ad95bf97..46d3b7a61 100644 --- a/libavcodec/shorten.c +++ b/libavcodec/shorten.c @@ -26,6 +26,7 @@ */ #include +#include "libavutil/mem.h" #include "avcodec.h" #include "bswapdsp.h" #include "bytestream.h" @@ -581,10 +582,9 @@ static int shorten_decode_frame(AVCodecContext *avctx, AVFrame *frame, return ret; if (avpkt->size) { - int max_framesize; + int max_framesize = s->blocksize * s->channels * 8; void *tmp_ptr; - max_framesize = FFMAX(s->max_framesize, s->blocksize * s->channels * 8); tmp_ptr = av_fast_realloc(s->bitstream, &s->allocated_bitstream_size, max_framesize + AV_INPUT_BUFFER_PADDING_SIZE); if (!tmp_ptr) { @@ -592,7 +592,10 @@ static int shorten_decode_frame(AVCodecContext *avctx, AVFrame *frame, return AVERROR(ENOMEM); } s->bitstream = tmp_ptr; - s->max_framesize = max_framesize; + if (max_framesize > s->max_framesize) + memset(s->bitstream + s->max_framesize, 0, (max_framesize - s->max_framesize) + + AV_INPUT_BUFFER_PADDING_SIZE); + s->max_framesize = FFMAX(s->max_framesize, max_framesize); *got_frame_ptr = 0; goto finish_frame; } diff --git a/libavcodec/sinewin_fixed_tablegen.c b/libavcodec/sinewin_fixed_tablegen.c index 15f0cc207..86e9dfb1e 100644 --- a/libavcodec/sinewin_fixed_tablegen.c +++ b/libavcodec/sinewin_fixed_tablegen.c @@ -35,10 +35,12 @@ int main(void) printf("SINETABLE("#size") = {\n"); \ write_int32_t_array(sine_ ## size ## _fixed, size); \ printf("};\n") + PRINT_TABLE(96); PRINT_TABLE(120); PRINT_TABLE(128); PRINT_TABLE(480); PRINT_TABLE(512); + PRINT_TABLE(768); PRINT_TABLE(960); PRINT_TABLE(1024); return 0; diff --git a/libavcodec/sinewin_fixed_tablegen.h b/libavcodec/sinewin_fixed_tablegen.h index 056735704..660c0056b 100644 --- a/libavcodec/sinewin_fixed_tablegen.h +++ b/libavcodec/sinewin_fixed_tablegen.h @@ -44,10 +44,12 @@ #include "libavutil/attributes.h" #define SINETABLE_CONST +SINETABLE( 96); SINETABLE( 120); SINETABLE( 128); SINETABLE( 480); SINETABLE( 512); +SINETABLE( 768); SINETABLE( 960); SINETABLE(1024); @@ -62,10 +64,12 @@ static av_cold void sine_window_init_fixed(int *window, int n) static av_cold void init_sine_windows_fixed(void) { + sine_window_init_fixed(sine_96_fixed, 96); sine_window_init_fixed(sine_120_fixed, 120); sine_window_init_fixed(sine_128_fixed, 128); sine_window_init_fixed(sine_480_fixed, 480); sine_window_init_fixed(sine_512_fixed, 512); + sine_window_init_fixed(sine_768_fixed, 768); sine_window_init_fixed(sine_960_fixed, 960); sine_window_init_fixed(sine_1024_fixed, 1024); } diff --git a/libavcodec/siren.c b/libavcodec/siren.c index fa8636946..e76f21bc7 100644 --- a/libavcodec/siren.c +++ b/libavcodec/siren.c @@ -22,6 +22,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "libavutil/float_dsp.h" #include "libavutil/mem_internal.h" diff --git a/libavcodec/smacker.c b/libavcodec/smacker.c index ffa0820f5..8f198d695 100644 --- a/libavcodec/smacker.c +++ b/libavcodec/smacker.c @@ -31,6 +31,7 @@ #include #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "avcodec.h" diff --git a/libavcodec/smcenc.c b/libavcodec/smcenc.c index 789aef4f7..f8a3322bb 100644 --- a/libavcodec/smcenc.c +++ b/libavcodec/smcenc.c @@ -184,8 +184,8 @@ static void smc_encode_stream(SMCContext *s, const AVFrame *frame, const ptrdiff_t offset = xpixel_ptr - src_pixels; const int sy = offset / stride; const int sx = offset % stride; - const int ny = sx < 4 ? sy - 4 : sy; - const int nx = sx < 4 ? width - 4 + (width & 3) : sx - 4; + const int ny = sx < 4 ? FFMAX(sy - 4, 0) : sy; + const int nx = sx < 4 ? FFMAX(width - 4 + (width & 3), 0) : sx - 4; const uint8_t *old_pixel_ptr = src_pixels + nx + ny * stride; int compare = 0; diff --git a/libavcodec/snow.c b/libavcodec/snow.c index 1b0fc6dc7..af6214d07 100644 --- a/libavcodec/snow.c +++ b/libavcodec/snow.c @@ -19,6 +19,7 @@ */ #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "avcodec.h" #include "snow_dwt.h" diff --git a/libavcodec/snow_dwt.c b/libavcodec/snow_dwt.c index 965f40900..1250597ee 100644 --- a/libavcodec/snow_dwt.c +++ b/libavcodec/snow_dwt.c @@ -22,6 +22,7 @@ #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "me_cmp.h" #include "snow_dwt.h" diff --git a/libavcodec/snowdec.c b/libavcodec/snowdec.c index 70fbab9a4..50dcaf8b9 100644 --- a/libavcodec/snowdec.c +++ b/libavcodec/snowdec.c @@ -21,7 +21,7 @@ #include "libavutil/emms.h" #include "libavutil/intmath.h" #include "libavutil/log.h" -#include "libavutil/opt.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 70a2de167..0623c9d19 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -22,6 +22,7 @@ #include "libavutil/intmath.h" #include "libavutil/libm.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avcodec.h" @@ -61,6 +62,7 @@ typedef struct SnowEncContext { 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) + MPVPicture cur_pic, last_pic; #define ME_CACHE_SIZE 1024 unsigned me_cache[ME_CACHE_SIZE]; unsigned me_cache_generation; @@ -215,6 +217,9 @@ 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); + if (ret < 0) + return ret; ff_mpegvideoencdsp_init(&enc->mpvencdsp, avctx); ff_snow_alloc_blocks(s); @@ -276,11 +281,6 @@ static av_cold int encode_init(AVCodecContext *avctx) if (ret) return ret; - ret = ff_set_cmp(&enc->mecc, enc->mecc.me_cmp, s->avctx->me_cmp); - ret |= ff_set_cmp(&enc->mecc, enc->mecc.me_sub_cmp, s->avctx->me_sub_cmp); - if (ret < 0) - return AVERROR(EINVAL); - s->input_picture = av_frame_alloc(); if (!s->input_picture) return AVERROR(ENOMEM); @@ -715,7 +715,7 @@ static int get_dc(SnowEncContext *enc, int mb_x, int mb_y, int plane_index) } *b= backup; - return av_clip_uint8( ROUNDED_DIV(ab<>1))*ref_stride; - distortion += enc->mecc.me_cmp[0](&enc->m, src + off, dst + off, ref_stride, 16); + distortion += enc->m.me.me_cmp[0](&enc->m, src + off, dst + off, ref_stride, 16); } } }else{ av_assert2(block_w==8); - distortion = enc->mecc.me_cmp[0](&enc->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, block_w*2); + distortion = enc->m.me.me_cmp[0](&enc->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, block_w*2); } if(plane_index==0){ @@ -909,7 +909,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->mecc.me_cmp[block_w==8](&enc->m, src + x + y*ref_stride, dst + x + y*ref_stride, ref_stride, block_h); + 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); } if(plane_index==0){ @@ -1839,9 +1839,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, if (ret < 0) return ret; - mpv->current_picture_ptr = &mpv->current_picture; - mpv->current_picture.f = s->current_picture; - mpv->current_picture.f->pts = pict->pts; + mpv->cur_pic.ptr = &enc->cur_pic; + mpv->cur_pic.ptr->f = s->current_picture; + mpv->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; @@ -1851,9 +1851,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, av_assert0(s->last_picture[0]->data[0]); mpv->avctx = s->avctx; - mpv->last_picture.f = s->last_picture[0]; - mpv-> new_picture = s->input_picture; - mpv->last_picture_ptr = &mpv->last_picture; + mpv->last_pic.ptr = &enc->last_pic; + mpv->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; @@ -1875,12 +1875,10 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, mpv->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->mecc = enc->mecc; //move mpv->qdsp = enc->qdsp; //move mpv->hdsp = s->hdsp; - ff_init_me(&enc->m); + ff_me_init_pic(&enc->m); s->hdsp = mpv->hdsp; - enc->mecc = mpv->mecc; } if (enc->pass1_rc) { @@ -2048,9 +2046,9 @@ redo_frame: 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); - mpv->current_picture.display_picture_number = - mpv->current_picture.coded_picture_number = avctx->frame_num; - mpv->current_picture.f->quality = pic->quality; + 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; @@ -2082,7 +2080,7 @@ static av_cold int encode_end(AVCodecContext *avctx) SnowContext *const s = &enc->com; ff_snow_common_end(s); - ff_rate_control_uninit(&enc->m); + ff_rate_control_uninit(&enc->m.rc_context); av_frame_free(&s->input_picture); for (int i = 0; i < MAX_REF_FRAMES; i++) { @@ -2148,6 +2146,7 @@ const FFCodec ff_snow_encoder = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }, + .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 0544fecf4..46c15b5fb 100644 --- a/libavcodec/sonic.c +++ b/libavcodec/sonic.c @@ -21,6 +21,7 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/sp5xdec.c b/libavcodec/sp5xdec.c index dfed72550..8dda5b615 100644 --- a/libavcodec/sp5xdec.c +++ b/libavcodec/sp5xdec.c @@ -26,9 +26,9 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" -#include "mjpeg.h" #include "mjpegdec.h" #include "sp5x.h" diff --git a/libavcodec/speedhqdec.c b/libavcodec/speedhqdec.c index d3605b064..76c9e7c48 100644 --- a/libavcodec/speedhqdec.c +++ b/libavcodec/speedhqdec.c @@ -40,6 +40,7 @@ #include "mpeg12data.h" #include "mpeg12vlc.h" #include "speedhq.h" +#include "thread.h" #define MAX_INDEX (64 - 1) @@ -57,6 +58,8 @@ typedef struct SHQContext { enum { SHQ_SUBSAMPLING_420, SHQ_SUBSAMPLING_422, SHQ_SUBSAMPLING_444 } subsampling; enum { SHQ_NO_ALPHA, SHQ_RLE_ALPHA, SHQ_DCT_ALPHA } alpha_type; + AVPacket *avpkt; + uint32_t second_field_offset; } SHQContext; /* NOTE: The first element is always 16, unscaled. */ @@ -265,9 +268,10 @@ static int decode_speedhq_border(const SHQContext *s, GetBitContext *gb, AVFrame return 0; } -static int decode_speedhq_field(const SHQContext *s, const uint8_t *buf, int buf_size, AVFrame *frame, int field_number, int start, int end, int line_stride) +static int decode_speedhq_field(const SHQContext *s, const uint8_t *buf, int buf_size, AVFrame *frame, int field_number, int start, int end, int line_stride, int slice_number) { - int ret, slice_number, slice_offsets[5]; + int ret, x, y, slice_offsets[5]; + uint32_t slice_begin, slice_end; int linesize_y = frame->linesize[0] * line_stride; int linesize_cb = frame->linesize[1] * line_stride; int linesize_cr = frame->linesize[2] * line_stride; @@ -282,121 +286,137 @@ static int decode_speedhq_field(const SHQContext *s, const uint8_t *buf, int buf slice_offsets[0] = start; slice_offsets[4] = end; - for (slice_number = 1; slice_number < 4; slice_number++) { + for (x = 1; x < 4; x++) { uint32_t last_offset, slice_len; - last_offset = slice_offsets[slice_number - 1]; + last_offset = slice_offsets[x - 1]; slice_len = AV_RL24(buf + last_offset); - slice_offsets[slice_number] = last_offset + slice_len; + slice_offsets[x] = last_offset + slice_len; - if (slice_len < 3 || slice_offsets[slice_number] > end - 3) + if (slice_len < 3 || slice_offsets[x] > end - 3) return AVERROR_INVALIDDATA; } - for (slice_number = 0; slice_number < 4; slice_number++) { - uint32_t slice_begin, slice_end; - int x, y; + slice_begin = slice_offsets[slice_number]; + slice_end = slice_offsets[slice_number + 1]; - slice_begin = slice_offsets[slice_number]; - slice_end = slice_offsets[slice_number + 1]; + if ((ret = init_get_bits8(&gb, buf + slice_begin + 3, slice_end - slice_begin - 3)) < 0) + return ret; - if ((ret = init_get_bits8(&gb, buf + slice_begin + 3, slice_end - slice_begin - 3)) < 0) - return ret; + for (y = slice_number * 16 * line_stride; y < frame->height; y += line_stride * 64) { + uint8_t *dest_y, *dest_cb, *dest_cr, *dest_a; + int last_dc[4] = { 1024, 1024, 1024, 1024 }; + uint8_t last_alpha[16]; - for (y = slice_number * 16 * line_stride; y < frame->height; y += line_stride * 64) { - uint8_t *dest_y, *dest_cb, *dest_cr, *dest_a; - int last_dc[4] = { 1024, 1024, 1024, 1024 }; - uint8_t last_alpha[16]; + memset(last_alpha, 255, sizeof(last_alpha)); - memset(last_alpha, 255, sizeof(last_alpha)); + dest_y = frame->data[0] + frame->linesize[0] * (y + field_number); + if (s->subsampling == SHQ_SUBSAMPLING_420) { + dest_cb = frame->data[1] + frame->linesize[1] * (y/2 + field_number); + dest_cr = frame->data[2] + frame->linesize[2] * (y/2 + field_number); + } else { + dest_cb = frame->data[1] + frame->linesize[1] * (y + field_number); + dest_cr = frame->data[2] + frame->linesize[2] * (y + field_number); + } + if (s->alpha_type != SHQ_NO_ALPHA) { + dest_a = frame->data[3] + frame->linesize[3] * (y + field_number); + } - dest_y = frame->data[0] + frame->linesize[0] * (y + field_number); - if (s->subsampling == SHQ_SUBSAMPLING_420) { - dest_cb = frame->data[1] + frame->linesize[1] * (y/2 + field_number); - dest_cr = frame->data[2] + frame->linesize[2] * (y/2 + field_number); - } else { - dest_cb = frame->data[1] + frame->linesize[1] * (y + field_number); - dest_cr = frame->data[2] + frame->linesize[2] * (y + field_number); - } - if (s->alpha_type != SHQ_NO_ALPHA) { - dest_a = frame->data[3] + frame->linesize[3] * (y + field_number); - } + for (x = 0; x < frame->width - 8 * (s->subsampling != SHQ_SUBSAMPLING_444); x += 16) { + /* Decode the four luma blocks. */ + if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y, linesize_y)) < 0) + return ret; + if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y + 8, linesize_y)) < 0) + return ret; + if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y + 8 * linesize_y, linesize_y)) < 0) + return ret; + if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y + 8 * linesize_y + 8, linesize_y)) < 0) + return ret; - for (x = 0; x < frame->width - 8 * (s->subsampling != SHQ_SUBSAMPLING_444); x += 16) { - /* Decode the four luma blocks. */ - if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y, linesize_y)) < 0) + /* + * Decode the first chroma block. For 4:2:0, this is the only one; + * for 4:2:2, it's the top block; for 4:4:4, it's the top-left block. + */ + if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb, linesize_cb)) < 0) + return ret; + if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr, linesize_cr)) < 0) + return ret; + + if (s->subsampling != SHQ_SUBSAMPLING_420) { + /* For 4:2:2, this is the bottom block; for 4:4:4, it's the bottom-left block. */ + if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb + 8 * linesize_cb, linesize_cb)) < 0) return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y + 8, linesize_y)) < 0) - return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y + 8 * linesize_y, linesize_y)) < 0) - return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 0, dest_y + 8 * linesize_y + 8, linesize_y)) < 0) + if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr + 8 * linesize_cr, linesize_cr)) < 0) return ret; - /* - * Decode the first chroma block. For 4:2:0, this is the only one; - * for 4:2:2, it's the top block; for 4:4:4, it's the top-left block. - */ - if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb, linesize_cb)) < 0) - return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr, linesize_cr)) < 0) - return ret; - - if (s->subsampling != SHQ_SUBSAMPLING_420) { - /* For 4:2:2, this is the bottom block; for 4:4:4, it's the bottom-left block. */ - if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb + 8 * linesize_cb, linesize_cb)) < 0) + if (s->subsampling == SHQ_SUBSAMPLING_444) { + /* Top-right and bottom-right blocks. */ + if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb + 8, linesize_cb)) < 0) return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr + 8 * linesize_cr, linesize_cr)) < 0) + if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr + 8, linesize_cr)) < 0) + return ret; + if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb + 8 * linesize_cb + 8, linesize_cb)) < 0) + return ret; + if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr + 8 * linesize_cr + 8, linesize_cr)) < 0) return ret; - if (s->subsampling == SHQ_SUBSAMPLING_444) { - /* Top-right and bottom-right blocks. */ - if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb + 8, linesize_cb)) < 0) - return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr + 8, linesize_cr)) < 0) - return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 1, dest_cb + 8 * linesize_cb + 8, linesize_cb)) < 0) - return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 2, dest_cr + 8 * linesize_cr + 8, linesize_cr)) < 0) - return ret; - - dest_cb += 8; - dest_cr += 8; - } + dest_cb += 8; + dest_cr += 8; } - dest_y += 16; - dest_cb += 8; - dest_cr += 8; + } + dest_y += 16; + dest_cb += 8; + dest_cr += 8; - if (s->alpha_type == SHQ_RLE_ALPHA) { - /* Alpha coded using 16x8 RLE blocks. */ - if ((ret = decode_alpha_block(s, &gb, last_alpha, dest_a, linesize_a)) < 0) - return ret; - if ((ret = decode_alpha_block(s, &gb, last_alpha, dest_a + 8 * linesize_a, linesize_a)) < 0) - return ret; - dest_a += 16; - } else if (s->alpha_type == SHQ_DCT_ALPHA) { - /* Alpha encoded exactly like luma. */ - if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a, linesize_a)) < 0) - return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a + 8, linesize_a)) < 0) - return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a + 8 * linesize_a, linesize_a)) < 0) - return ret; - if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a + 8 * linesize_a + 8, linesize_a)) < 0) - return ret; - dest_a += 16; - } + if (s->alpha_type == SHQ_RLE_ALPHA) { + /* Alpha coded using 16x8 RLE blocks. */ + if ((ret = decode_alpha_block(s, &gb, last_alpha, dest_a, linesize_a)) < 0) + return ret; + if ((ret = decode_alpha_block(s, &gb, last_alpha, dest_a + 8 * linesize_a, linesize_a)) < 0) + return ret; + dest_a += 16; + } else if (s->alpha_type == SHQ_DCT_ALPHA) { + /* Alpha encoded exactly like luma. */ + if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a, linesize_a)) < 0) + return ret; + if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a + 8, linesize_a)) < 0) + return ret; + if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a + 8 * linesize_a, linesize_a)) < 0) + return ret; + if ((ret = decode_dct_block(s, &gb, last_dc, 3, dest_a + 8 * linesize_a + 8, linesize_a)) < 0) + return ret; + dest_a += 16; } } } - if (s->subsampling != SHQ_SUBSAMPLING_444 && (frame->width & 15)) + if (s->subsampling != SHQ_SUBSAMPLING_444 && (frame->width & 15) && slice_number == 3) return decode_speedhq_border(s, &gb, frame, field_number, line_stride); return 0; } +static int decode_slice_progressive(AVCodecContext *avctx, void *arg, int jobnr, int threadnr) +{ + SHQContext *s = avctx->priv_data; + (void)threadnr; + + return decode_speedhq_field(avctx->priv_data, s->avpkt->data, s->avpkt->size, arg, 0, 4, s->avpkt->size, 1, jobnr); +} + +static int decode_slice_interlaced(AVCodecContext *avctx, void *arg, int jobnr, int threadnr) +{ + SHQContext *s = avctx->priv_data; + int field_number = jobnr / 4; + int slice_number = jobnr % 4; + (void)threadnr; + + if (field_number == 0) + return decode_speedhq_field(avctx->priv_data, s->avpkt->data, s->avpkt->size, arg, 0, 4, s->second_field_offset, 2, slice_number); + else + return decode_speedhq_field(avctx->priv_data, s->avpkt->data, s->avpkt->size, arg, 1, s->second_field_offset, s->avpkt->size, 2, slice_number); +} + static void compute_quant_matrix(int *output, int qscale) { int i; @@ -410,7 +430,6 @@ static int speedhq_decode_frame(AVCodecContext *avctx, AVFrame *frame, const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; uint8_t quality; - uint32_t second_field_offset; int ret; if (buf_size < 4 || avctx->width < 8 || avctx->width % 8 != 0) @@ -423,22 +442,26 @@ static int speedhq_decode_frame(AVCodecContext *avctx, AVFrame *frame, return AVERROR_INVALIDDATA; } + if (avctx->skip_frame >= AVDISCARD_ALL) + return avpkt->size; + compute_quant_matrix(s->quant_matrix, 100 - quality); - second_field_offset = AV_RL24(buf + 1); - if (second_field_offset >= buf_size - 3) { + s->second_field_offset = AV_RL24(buf + 1); + if (s->second_field_offset >= buf_size - 3) { return AVERROR_INVALIDDATA; } avctx->coded_width = FFALIGN(avctx->width, 16); avctx->coded_height = FFALIGN(avctx->height, 16); - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) { + if ((ret = ff_thread_get_buffer(avctx, frame, 0)) < 0) { return ret; } - frame->flags |= AV_FRAME_FLAG_KEY; - if (second_field_offset == 4 || second_field_offset == (buf_size-4)) { + s->avpkt = avpkt; + + if (s->second_field_offset == 4 || s->second_field_offset == (buf_size-4)) { /* * Overlapping first and second fields is used to signal * encoding only a single field. In this case, "height" @@ -448,12 +471,10 @@ static int speedhq_decode_frame(AVCodecContext *avctx, AVFrame *frame, * but this matches the convention used in NDI, which is * the primary user of this trick. */ - if ((ret = decode_speedhq_field(s, buf, buf_size, frame, 0, 4, buf_size, 1)) < 0) + if ((ret = avctx->execute2(avctx, decode_slice_progressive, frame, NULL, 4)) < 0) return ret; } else { - if ((ret = decode_speedhq_field(s, buf, buf_size, frame, 0, 4, second_field_offset, 2)) < 0) - return ret; - if ((ret = decode_speedhq_field(s, buf, buf_size, frame, 1, second_field_offset, buf_size, 2)) < 0) + if ((ret = avctx->execute2(avctx, decode_slice_interlaced, frame, NULL, 8)) < 0) return ret; } @@ -649,5 +670,5 @@ const FFCodec ff_speedhq_decoder = { .priv_data_size = sizeof(SHQContext), .init = speedhq_decode_init, FF_CODEC_DECODE_CB(speedhq_decode_frame), - .p.capabilities = AV_CODEC_CAP_DR1, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS, }; diff --git a/libavcodec/speedhqenc.c b/libavcodec/speedhqenc.c index 5b4ff4c13..81a5151b7 100644 --- a/libavcodec/speedhqenc.c +++ b/libavcodec/speedhqenc.c @@ -82,12 +82,12 @@ static av_cold void speedhq_init_static_data(void) bits = ff_mpeg12_vlc_dc_lum_bits[index] + index; code = mpeg12_vlc_dc_lum_code_reversed[index] + - (av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_lum_bits[index]); + (av_zero_extend(diff, index) << ff_mpeg12_vlc_dc_lum_bits[index]); speedhq_lum_dc_uni[i + 255] = bits + (code << 8); bits = ff_mpeg12_vlc_dc_chroma_bits[index] + index; code = mpeg12_vlc_dc_chroma_code_reversed[index] + - (av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_chroma_bits[index]); + (av_zero_extend(diff, index) << ff_mpeg12_vlc_dc_chroma_bits[index]); speedhq_chr_dc_uni[i + 255] = bits + (code << 8); } @@ -104,6 +104,12 @@ av_cold int ff_speedhq_encode_init(MpegEncContext *s) return AVERROR(EINVAL); } + // 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; @@ -176,12 +182,12 @@ static inline void encode_dc(PutBitContext *pb, int diff, int component) put_bits_le(pb, ff_mpeg12_vlc_dc_lum_bits[index] + index, mpeg12_vlc_dc_lum_code_reversed[index] + - (av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_lum_bits[index])); + (av_zero_extend(diff, index) << ff_mpeg12_vlc_dc_lum_bits[index])); else put_bits_le(pb, ff_mpeg12_vlc_dc_chroma_bits[index] + index, mpeg12_vlc_dc_chroma_code_reversed[index] + - (av_mod_uintp2(diff, index) << ff_mpeg12_vlc_dc_chroma_bits[index])); + (av_zero_extend(diff, index) << ff_mpeg12_vlc_dc_chroma_bits[index])); } else { if (component == 0) put_bits_le(pb, @@ -294,6 +300,7 @@ const FFCodec ff_speedhq_encoder = { 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 diff --git a/libavcodec/speexdec.c b/libavcodec/speexdec.c index ba0df687d..d25823ef6 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/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/sunrast.c b/libavcodec/sunrast.c index 3668d2be7..9e49c4f27 100644 --- a/libavcodec/sunrast.c +++ b/libavcodec/sunrast.c @@ -22,6 +22,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/svq1dec.c b/libavcodec/svq1dec.c index d2cfe4cf4..57cac8ee7 100644 --- a/libavcodec/svq1dec.c +++ b/libavcodec/svq1dec.c @@ -33,6 +33,7 @@ */ #include "libavutil/crc.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "avcodec.h" diff --git a/libavcodec/svq1enc.c b/libavcodec/svq1enc.c index 77dbf0727..d969be25c 100644 --- a/libavcodec/svq1enc.c +++ b/libavcodec/svq1enc.c @@ -27,6 +27,7 @@ */ #include "libavutil/emms.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" @@ -325,13 +326,11 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, if (s->pict_type == AV_PICTURE_TYPE_P) { s->m.avctx = s->avctx; - s->m.current_picture_ptr = &s->m.current_picture; - s->m.last_picture_ptr = &s->m.last_picture; - s->m.last_picture.f->data[0] = ref_plane; + s->m.last_pic.data[0] = ref_plane; s->m.linesize = - s->m.last_picture.f->linesize[0] = - s->m.new_picture->linesize[0] = - s->m.current_picture.f->linesize[0] = stride; + s->m.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; @@ -369,18 +368,17 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, 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.current_picture.mb_type = s->dummy; + s->m.cur_pic.mb_type = s->dummy; - s->m.current_picture.motion_val[0] = s->motion_val8[plane] + 2; + 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; - s->m.mecc = s->mecc; // move - ff_init_me(&s->m); + ff_me_init_pic(&s->m); s->m.me.dia_size = s->avctx->dia_size; s->m.first_slice_line = 1; for (y = 0; y < block_height; y++) { - s->m.new_picture->data[0] = src - y * 16 * stride; // ugly + s->m.new_pic->data[0] = src - y * 16 * stride; // ugly s->m.mb_y = y; for (i = 0; i < 16 && i + 16 * y < height; i++) { @@ -470,16 +468,14 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, put_bits(&s->reorder_pb[5], SVQ1_BLOCK_INTER_LEN, SVQ1_BLOCK_INTER_CODE); - s->m.pb = s->reorder_pb[5]; mx = motion_ptr[0]; my = motion_ptr[1]; av_assert1(mx >= -32 && mx <= 31); av_assert1(my >= -32 && my <= 31); av_assert1(pred_x >= -32 && pred_x <= 31); av_assert1(pred_y >= -32 && pred_y <= 31); - ff_h263_encode_motion(&s->m.pb, mx - pred_x, 1); - ff_h263_encode_motion(&s->m.pb, my - pred_y, 1); - s->reorder_pb[5] = s->m.pb; + ff_h263_encode_motion(&s->reorder_pb[5], mx - pred_x, 1); + ff_h263_encode_motion(&s->reorder_pb[5], my - pred_y, 1); score[1] += lambda * put_bits_count(&s->reorder_pb[5]); dxy = (mx & 1) + 2 * (my & 1); @@ -544,15 +540,15 @@ static av_cold int svq1_encode_end(AVCodecContext *avctx) s->rd_total / (double)(avctx->width * avctx->height * avctx->frame_num)); - s->m.mb_type = NULL; - ff_mpv_common_end(&s->m); - 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]); @@ -560,7 +556,7 @@ static av_cold int svq1_encode_end(AVCodecContext *avctx) av_frame_free(&s->current_picture); av_frame_free(&s->last_picture); - av_frame_free(&s->m.new_picture); + av_frame_free(&s->m.new_pic); return 0; } @@ -590,6 +586,9 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) ff_hpeldsp_init(&s->hdsp, avctx->flags); ff_me_cmp_init(&s->mecc, avctx); + ret = ff_me_init(&s->m.me, avctx, &s->mecc, 0); + if (ret < 0) + return ret; ff_mpegvideoencdsp_init(&s->m.mpvencdsp, avctx); s->current_picture = av_frame_alloc(); @@ -623,10 +622,10 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx) 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_picture = av_frame_alloc(); + s->m.new_pic = av_frame_alloc(); if (!s->m.me.scratchpad || !s->m.me.map || - !s->mb_type || !s->dummy || !s->m.new_picture) + !s->mb_type || !s->dummy || !s->m.new_pic) return AVERROR(ENOMEM); s->m.me.score_map = s->m.me.map + ME_MAP_SIZE; @@ -748,5 +747,6 @@ const FFCodec ff_svq1_encoder = { .close = svq1_encode_end, .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV410P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c index d2f53742e..f730358e2 100644 --- a/libavcodec/svq3.c +++ b/libavcodec/svq3.c @@ -44,6 +44,7 @@ #include "libavutil/attributes.h" #include "libavutil/crc.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "codec_internal.h" @@ -1399,6 +1400,9 @@ static int svq3_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (svq3_decode_slice_header(avctx)) return -1; + if (avpkt->size < s->mb_width * s->mb_height / 8) + return AVERROR_INVALIDDATA; + s->pict_type = s->slice_type; if (s->pict_type != AV_PICTURE_TYPE_B) diff --git a/libavcodec/takdec.c b/libavcodec/takdec.c index 5cbc2de6b..cfa69f421 100644 --- a/libavcodec/takdec.c +++ b/libavcodec/takdec.c @@ -26,6 +26,7 @@ */ #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/samplefmt.h" diff --git a/libavcodec/targa_y216dec.c b/libavcodec/targa_y216dec.c index 2874a51aa..08f85391d 100644 --- a/libavcodec/targa_y216dec.c +++ b/libavcodec/targa_y216dec.c @@ -47,9 +47,6 @@ static int y216_decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - y = (uint16_t *)pic->data[0]; u = (uint16_t *)pic->data[1]; v = (uint16_t *)pic->data[2]; diff --git a/libavcodec/tdsc.c b/libavcodec/tdsc.c index 624e219cb..ab0a70859 100644 --- a/libavcodec/tdsc.c +++ b/libavcodec/tdsc.c @@ -37,6 +37,7 @@ #include #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/tests/aarch64/dct.c b/libavcodec/tests/aarch64/dct.c index 9e477328d..e98a887cd 100644 --- a/libavcodec/tests/aarch64/dct.c +++ b/libavcodec/tests/aarch64/dct.c @@ -19,9 +19,11 @@ #include "config.h" #include "libavutil/cpu.h" +#include "libavcodec/aarch64/fdct.h" #include "libavcodec/aarch64/idct.h" static const struct algo fdct_tab_arch[] = { + { "neon", ff_fdct_neon, FF_IDCT_PERM_NONE, AV_CPU_FLAG_NEON }, { 0 } }; diff --git a/libavcodec/tests/avcodec.c b/libavcodec/tests/avcodec.c index 08ca507bf..cd949f638 100644 --- a/libavcodec/tests/avcodec.c +++ b/libavcodec/tests/avcodec.c @@ -141,7 +141,7 @@ int main(void){ ret = 1; } } - if (codec2->caps_internal & (FF_CODEC_CAP_ALLOCATE_PROGRESS | + if (codec2->caps_internal & (FF_CODEC_CAP_USES_PROGRESSFRAMES | FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_EXPORTS_CROPPING | @@ -171,10 +171,6 @@ int main(void){ AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE | AV_CODEC_CAP_ENCODER_FLUSH)) ERR("Decoder %s has encoder-only capabilities\n"); - if (codec2->caps_internal & FF_CODEC_CAP_ALLOCATE_PROGRESS && - !(codec->capabilities & AV_CODEC_CAP_FRAME_THREADS)) - ERR("Decoder %s wants allocated progress without supporting" - "frame threads\n"); if (codec2->cb_type != FF_CODEC_CB_TYPE_DECODE && codec2->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS) ERR("Decoder %s is marked as setting pkt_dts when it doesn't have" diff --git a/libavcodec/tests/avpacket.c b/libavcodec/tests/avpacket.c index 7a70ade4c..fed700b4b 100644 --- a/libavcodec/tests/avpacket.c +++ b/libavcodec/tests/avpacket.c @@ -22,6 +22,7 @@ #include #include "libavcodec/avcodec.h" #include "libavutil/error.h" +#include "libavutil/mem.h" diff --git a/libavcodec/tests/iirfilter.c b/libavcodec/tests/iirfilter.c index 60cc6fc43..e03e842b8 100644 --- a/libavcodec/tests/iirfilter.c +++ b/libavcodec/tests/iirfilter.c @@ -23,10 +23,25 @@ #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; @@ -43,7 +58,7 @@ int main(void) for (i = 0; i < SIZE; i++) x[i] = lrint(0.75 * INT16_MAX * sin(0.5 * M_PI * i * i / SIZE)); - ff_iir_filter(fcoeffs, fstate, SIZE, x, 1, y, 1); + iir_filter_int16(fcoeffs, fstate, SIZE, x, 1, y, 1); for (i = 0; i < SIZE; i++) printf("%6d %6d\n", x[i], y[i]); diff --git a/libavcodec/tests/motion.c b/libavcodec/tests/motion.c index caa8ecb8b..c37fc551c 100644 --- a/libavcodec/tests/motion.c +++ b/libavcodec/tests/motion.c @@ -131,12 +131,10 @@ int main(int argc, char **argv) ctx = avcodec_alloc_context3(NULL); ctx->flags |= AV_CODEC_FLAG_BITEXACT; av_force_cpu_flags(0); - memset(&cctx, 0, sizeof(cctx)); ff_me_cmp_init(&cctx, ctx); for (c = 0; c < flags_size; c++) { int x; av_force_cpu_flags(flags[c]); - memset(&mmxctx, 0, sizeof(mmxctx)); ff_me_cmp_init(&mmxctx, ctx); for (x = 0; x < 2; x++) { diff --git a/libavcodec/tests/snowenc.c b/libavcodec/tests/snowenc.c index 3dad07d3a..eb4e64f37 100644 --- a/libavcodec/tests/snowenc.c +++ b/libavcodec/tests/snowenc.c @@ -26,6 +26,7 @@ #include "libavutil/lfg.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" int main(void){ #define width 256 diff --git a/libavcodec/tests/x86/dct.c b/libavcodec/tests/x86/dct.c index ef0662ae3..7800abc7f 100644 --- a/libavcodec/tests/x86/dct.c +++ b/libavcodec/tests/x86/dct.c @@ -26,7 +26,7 @@ #include "libavcodec/x86/xvididct.h" #include "libavcodec/x86/simple_idct.h" -#if (CONFIG_PRORES_DECODER || CONFIG_PRORES_LGPL_DECODER) && ARCH_X86_64 && HAVE_X86ASM +#if CONFIG_PRORES_DECODER && ARCH_X86_64 && HAVE_X86ASM void ff_prores_idct_put_10_sse2(uint16_t *dst, int linesize, int16_t *block, int16_t *qmat); @@ -70,7 +70,7 @@ static const struct algo idct_tab_arch[] = { { "XVID-SSE2", ff_xvid_idct_sse2, FF_IDCT_PERM_SSE2, AV_CPU_FLAG_SSE2, 1 }, #endif #endif /* CONFIG_MPEG4_DECODER && HAVE_X86ASM */ -#if (CONFIG_PRORES_DECODER || CONFIG_PRORES_LGPL_DECODER) && ARCH_X86_64 && HAVE_X86ASM +#if CONFIG_PRORES_DECODER && ARCH_X86_64 && HAVE_X86ASM { "PR-SSE2", ff_prores_idct_put_10_sse2_wrap, FF_IDCT_PERM_TRANSPOSE, AV_CPU_FLAG_SSE2, 1 }, # if HAVE_AVX_EXTERNAL { "PR-AVX", ff_prores_idct_put_10_avx_wrap, FF_IDCT_PERM_TRANSPOSE, AV_CPU_FLAG_AVX, 1 }, diff --git a/libavcodec/thread.h b/libavcodec/thread.h index f772d7ff1..7df5839ed 100644 --- a/libavcodec/thread.h +++ b/libavcodec/thread.h @@ -20,7 +20,7 @@ /** * @file - * Multithreading support functions + * Multithreading API for decoders * @author Alexander Strange */ @@ -31,27 +31,6 @@ #include "avcodec.h" -/** - * Wait for decoding threads to finish and reset internal state. - * Called by avcodec_flush_buffers(). - * - * @param avctx The context. - */ -void ff_thread_flush(AVCodecContext *avctx); - -/** - * Submit a new frame to a decoding thread. - * Returns the next available frame in picture. *got_picture_ptr - * will be 0 if none is available. - * The return value on success is the size of the consumed packet for - * compatibility with FFCodec.decode. This means the decoder - * has to consume the full packet. - * - * Parameters are the same as FFCodec.decode. - */ -int ff_thread_decode_frame(AVCodecContext *avctx, AVFrame *picture, - int *got_picture_ptr, AVPacket *avpkt); - int ff_thread_can_start_frame(AVCodecContext *avctx); /** @@ -74,14 +53,38 @@ void ff_thread_finish_setup(AVCodecContext *avctx); */ int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f, int flags); -int ff_thread_init(AVCodecContext *s); int ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx, int (*action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr), int (*main_func)(AVCodecContext *c), void *arg, int *ret, int job_count); -void ff_thread_free(AVCodecContext *s); -int ff_slice_thread_allocz_entries(AVCodecContext *avctx, int count); -int ff_slice_thread_init_progress(AVCodecContext *avctx); -void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n); -void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift); + +enum ThreadingStatus { + FF_THREAD_IS_COPY, + FF_THREAD_IS_FIRST_THREAD, + FF_THREAD_NO_FRAME_THREADING, +}; + +/** + * Allows to synchronize objects whose lifetime is the whole decoding + * process among all frame threads. + * + * When called from a non-copy thread, do nothing. + * When called from another thread, place a new RefStruct reference + * at the given offset in the calling thread's private data from + * the RefStruct reference in the private data of the first decoding thread. + * The first thread must have a valid RefStruct reference at the given + * offset in its private data; the calling thread must not have + * a reference at this offset in its private data (must be NULL). + * + * @param avctx an AVCodecContext + * @param offset offset of the RefStruct reference in avctx's private data + * + * @retval FF_THREAD_IS_COPY if frame-threading is in use and the + * calling thread is a copy; in this case, the RefStruct reference + * will be set. + * @retval FF_THREAD_IS_MAIN_THREAD if frame-threading is in use + * and the calling thread is the main thread. + * @retval FF_THREAD_NO_FRAME_THREADING if frame-threading is not in use. + */ +enum ThreadingStatus ff_thread_sync_ref(AVCodecContext *avctx, size_t offset); #endif /* AVCODEC_THREAD_H */ diff --git a/libavcodec/threadprogress.c b/libavcodec/threadprogress.c new file mode 100644 index 000000000..62c4fd898 --- /dev/null +++ b/libavcodec/threadprogress.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022 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 +#include + +#include "pthread_internal.h" +#include "threadprogress.h" +#include "libavutil/attributes.h" +#include "libavutil/thread.h" + +DEFINE_OFFSET_ARRAY(ThreadProgress, thread_progress, init, + (offsetof(ThreadProgress, progress_mutex)), + (offsetof(ThreadProgress, progress_cond))); + +av_cold int ff_thread_progress_init(ThreadProgress *pro, int init_mode) +{ + atomic_init(&pro->progress, init_mode ? -1 : INT_MAX); +#if HAVE_THREADS + if (init_mode) + return ff_pthread_init(pro, thread_progress_offsets); +#endif + pro->init = init_mode; + return 0; +} + +av_cold void ff_thread_progress_destroy(ThreadProgress *pro) +{ +#if HAVE_THREADS + ff_pthread_free(pro, thread_progress_offsets); +#else + pro->init = 0; +#endif +} + +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); + ff_cond_broadcast(&pro->progress_cond); + ff_mutex_unlock(&pro->progress_mutex); +} + +void ff_thread_progress_await(const ThreadProgress *pro_c, int n) +{ + /* Casting const away here is safe, because we only read from progress + * and will leave pro_c in the same state upon leaving the function + * as it had at the beginning. */ + ThreadProgress *pro = (ThreadProgress*)pro_c; + + if (atomic_load_explicit(&pro->progress, memory_order_acquire) >= n) + return; + + ff_mutex_lock(&pro->progress_mutex); + while (atomic_load_explicit(&pro->progress, memory_order_relaxed) < n) + ff_cond_wait(&pro->progress_cond, &pro->progress_mutex); + ff_mutex_unlock(&pro->progress_mutex); +} diff --git a/libavcodec/threadprogress.h b/libavcodec/threadprogress.h new file mode 100644 index 000000000..cc3414c2c --- /dev/null +++ b/libavcodec/threadprogress.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2022 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 + */ + +#ifndef AVCODEC_THREADPROGRESS_H +#define AVCODEC_THREADPROGRESS_H + +/** + * ThreadProgress is an API to easily notify other threads about progress + * of any kind as long as it can be packaged into an int and is consistent + * with the natural ordering of integers. + * + * Each initialized ThreadProgress can be in one of two modes: No-op mode + * or ordinary mode. In the former mode, ff_thread_report_progress() and + * ff_thread_await_progress() are no-ops to simply support usecases like + * non-frame-threading. Only in the latter case perform these functions + * what their name already implies. + */ + +#include +#include +#include "libavutil/thread.h" + +/** + * This struct should be treated as opaque by users. + */ +typedef struct ThreadProgress { + atomic_int progress; + unsigned init; + AVMutex progress_mutex; + AVCond progress_cond; +} ThreadProgress; + +/** + * Initialize a ThreadProgress. + * + * @param init_mode If zero, the ThreadProgress will be initialized + * to be in no-op mode as described above. Otherwise + * it is initialized to be in ordinary mode. + */ +int ff_thread_progress_init(ThreadProgress *pro, int init_mode); + +/** + * Destroy a ThreadProgress. Can be called on a ThreadProgress that + * has never been initialized provided that the ThreadProgress struct + * has been initially zeroed. Must be called even if ff_thread_progress_init() + * failed. + */ +void ff_thread_progress_destroy(ThreadProgress *pro); + +/** + * Reset the ::ThreadProgress.progress counter; must only be called + * if the ThreadProgress is not in use in any way (e.g. no thread + * may wait on it via ff_thread_progress_await()). + */ +static inline void ff_thread_progress_reset(ThreadProgress *pro) +{ + atomic_init(&pro->progress, pro->init ? -1 : INT_MAX); +} + +/** + * This function is a no-op in no-op mode; otherwise it notifies + * other threads that a certain level of progress has been reached. + * Later calls with lower values of progress have no effect. + */ +void ff_thread_progress_report(ThreadProgress *pro, int progress); + +/** + * This function is a no-op in no-op mode; otherwise it waits + * until other threads have reached a certain level of progress: + * This function will return after another thread has called + * ff_thread_progress_report() with the same or higher value for progress. + */ +void ff_thread_progress_await(const ThreadProgress *pro, int progress); + +#endif /* AVCODEC_THREADPROGRESS_H */ diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c index bfa345b3d..37b56e975 100644 --- a/libavcodec/tiff.c +++ b/libavcodec/tiff.c @@ -39,6 +39,7 @@ #include "libavutil/avstring.h" #include "libavutil/error.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/reverse.h" #include "avcodec.h" @@ -175,7 +176,7 @@ static int cmp_id_key(const void *id, const void *k) static const char *search_keyval(const TiffGeoTagKeyName *keys, int n, int id) { - TiffGeoTagKeyName *r = bsearch(&id, keys, n, sizeof(keys[0]), cmp_id_key); + const TiffGeoTagKeyName *r = bsearch(&id, keys, n, sizeof(keys[0]), cmp_id_key); if(r) return r->name; @@ -421,7 +422,7 @@ static void av_always_inline horizontal_fill(TiffContext *s, uint8_t shift = is_dng ? 0 : 16 - bpp; GetBitContext gb; - int ret = init_get_bits8(&gb, src, width); + av_unused int ret = init_get_bits8(&gb, src, width); av_assert1(ret >= 0); for (int i = 0; i < s->width; i++) { dst16[i] = get_bits(&gb, bpp) << shift; @@ -456,7 +457,7 @@ static void unpack_gray(TiffContext *s, AVFrame *p, GetBitContext gb; uint16_t *dst = (uint16_t *)(p->data[0] + lnum * p->linesize[0]); - int ret = init_get_bits8(&gb, src, width); + av_unused int ret = init_get_bits8(&gb, src, width); av_assert1(ret >= 0); for (int i = 0; i < s->width; i++) { @@ -2284,8 +2285,10 @@ again: group_size = s->width * channels; tmpbuf = av_malloc(ssize); - if (!tmpbuf) + if (!tmpbuf) { + av_free(five_planes); return AVERROR(ENOMEM); + } if (s->avctx->pix_fmt == AV_PIX_FMT_RGBF32LE || s->avctx->pix_fmt == AV_PIX_FMT_RGBAF32LE) { @@ -2398,7 +2401,6 @@ again: } } - p->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/tiff_common.c b/libavcodec/tiff_common.c index 2b872ea7e..22ebca814 100644 --- a/libavcodec/tiff_common.c +++ b/libavcodec/tiff_common.c @@ -26,6 +26,7 @@ */ #include "libavutil/bprint.h" +#include "libavutil/mem.h" #include "tiff_common.h" diff --git a/libavcodec/tiffenc.c b/libavcodec/tiffenc.c index 7c3c03f1f..5e65979c7 100644 --- a/libavcodec/tiffenc.c +++ b/libavcodec/tiffenc.c @@ -31,6 +31,7 @@ #endif #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avcodec.h" @@ -588,5 +589,6 @@ const FFCodec ff_tiff_encoder = { AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &tiffenc_class, }; diff --git a/libavcodec/tmv.c b/libavcodec/tmv.c index 2a7e1a105..2ff1424bd 100644 --- a/libavcodec/tmv.c +++ b/libavcodec/tmv.c @@ -56,8 +56,6 @@ static int tmv_decode_frame(AVCodecContext *avctx, AVFrame *frame, return AVERROR_INVALIDDATA; } - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; dst = frame->data[0]; #if FF_API_PALETTE_HAS_CHANGED diff --git a/libavcodec/truemotion2.c b/libavcodec/truemotion2.c index 366d8aefc..7ae9a67ec 100644 --- a/libavcodec/truemotion2.c +++ b/libavcodec/truemotion2.c @@ -26,6 +26,7 @@ #include +#include "libavutil/mem.h" #include "avcodec.h" #include "bswapdsp.h" #include "bytestream.h" diff --git a/libavcodec/truemotion2rt.c b/libavcodec/truemotion2rt.c index 4f8590fc8..438f96f6b 100644 --- a/libavcodec/truemotion2rt.c +++ b/libavcodec/truemotion2rt.c @@ -201,8 +201,6 @@ static int truemotion2rt_decode_frame(AVCodecContext *avctx, AVFrame *p, dst += p->linesize[2]; } - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/tscc.c b/libavcodec/tscc.c index 346d93e1f..575173698 100644 --- a/libavcodec/tscc.c +++ b/libavcodec/tscc.c @@ -34,6 +34,7 @@ * Supports: BGR8,BGR555,BGR24 - only BGR8 and BGR555 tested */ +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/tscc2.c b/libavcodec/tscc2.c index 168efe93f..cfe5a6e75 100644 --- a/libavcodec/tscc2.c +++ b/libavcodec/tscc2.c @@ -26,6 +26,7 @@ #include +#include "libavutil/mem.h" #include "libavutil/thread.h" #define BITSTREAM_READER_LE diff --git a/libavcodec/tta.c b/libavcodec/tta.c index 7763ed7ff..467c78514 100644 --- a/libavcodec/tta.c +++ b/libavcodec/tta.c @@ -32,6 +32,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/crc.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #define BITSTREAM_READER_LE diff --git a/libavcodec/ttaenc.c b/libavcodec/ttaenc.c index db79c38b4..1b9aeec8f 100644 --- a/libavcodec/ttaenc.c +++ b/libavcodec/ttaenc.c @@ -26,6 +26,7 @@ #include "encode.h" #include "put_bits.h" #include "libavutil/crc.h" +#include "libavutil/mem.h" typedef struct TTAEncContext { const AVCRC *crc_table; diff --git a/libavcodec/ttmlenc.c b/libavcodec/ttmlenc.c index 779cb7519..897e16ebb 100644 --- a/libavcodec/ttmlenc.c +++ b/libavcodec/ttmlenc.c @@ -31,6 +31,7 @@ #include "codec_internal.h" #include "libavutil/bprint.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "ass_split.h" #include "ttmlenc.h" diff --git a/libavcodec/twinvq.c b/libavcodec/twinvq.c index 4cc0583f8..69d8f5536 100644 --- a/libavcodec/twinvq.c +++ b/libavcodec/twinvq.c @@ -24,6 +24,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "decode.h" #include "lsp.h" diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 7914f7990..6909a5ba2 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -723,7 +723,7 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, case AV_CODEC_ID_ADPCM_IMA_WAV: if (bps < 2 || bps > 5) return 0; - tmp = blocks * (1LL + (ba - 4 * ch) / (bps * ch) * 8); + tmp = blocks * (1LL + (ba - 4 * ch) / (bps * ch) * 8LL); break; case AV_CODEC_ID_ADPCM_IMA_DK3: tmp = blocks * (((ba - 16LL) * 2 / 3 * 4) / ch); @@ -809,14 +809,6 @@ int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes) return FFMAX(0, duration); } -#if !HAVE_THREADS -int ff_thread_init(AVCodecContext *s) -{ - return -1; -} - -#endif - unsigned int av_xiphlacing(unsigned char *s, unsigned int v) { unsigned int n = 0; @@ -921,25 +913,6 @@ int ff_thread_can_start_frame(AVCodecContext *avctx) { return 1; } - -int ff_slice_thread_init_progress(AVCodecContext *avctx) -{ - return 0; -} - -int ff_slice_thread_allocz_entries(AVCodecContext *avctx, int count) -{ - return 0; -} - -void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift) -{ -} - -void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n) -{ -} - #endif const uint8_t *avpriv_find_start_code(const uint8_t *restrict p, diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 0c2e67e28..4c0fa2ca6 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -31,6 +31,7 @@ #define UNCHECKED_BITSTREAM_READER 1 #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "avcodec.h" #include "bswapdsp.h" @@ -889,8 +890,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, break; } - frame->flags |= AV_FRAME_FLAG_KEY; - frame->pict_type = AV_PICTURE_TYPE_I; if (c->interlaced) frame->flags |= AV_FRAME_FLAG_INTERLACED; diff --git a/libavcodec/utvideoenc.c b/libavcodec/utvideoenc.c index ad8d73fbb..54b1caa9e 100644 --- a/libavcodec/utvideoenc.c +++ b/libavcodec/utvideoenc.c @@ -26,6 +26,7 @@ #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" @@ -35,7 +36,6 @@ #include "bytestream.h" #include "lossless_videoencdsp.h" #include "put_bits.h" -#include "mathops.h" #include "utvideo.h" #include "huffman.h" @@ -675,5 +675,6 @@ const FFCodec ff_utvideo_encoder = { AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE }, + .color_ranges = AVCOL_RANGE_MPEG, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/v210dec.c b/libavcodec/v210dec.c index d80fb4e7c..8b370e565 100644 --- a/libavcodec/v210dec.c +++ b/libavcodec/v210dec.c @@ -29,6 +29,7 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "thread.h" typedef struct ThreadData { @@ -186,9 +187,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->pict_type = AV_PICTURE_TYPE_I; - pic->flags |= AV_FRAME_FLAG_KEY; - if (stride) { td.stride = stride; td.buf = psrc; diff --git a/libavcodec/v210x.c b/libavcodec/v210x.c index 55630fa2f..a4b43883e 100644 --- a/libavcodec/v210x.c +++ b/libavcodec/v210x.c @@ -61,8 +61,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *pic, udst = (uint16_t *)pic->data[1]; vdst = (uint16_t *)pic->data[2]; yend = ydst + width; - pic->pict_type = AV_PICTURE_TYPE_I; - pic->flags |= AV_FRAME_FLAG_KEY; for (;;) { uint32_t v = av_be2ne32(*src++); diff --git a/libavcodec/v308dec.c b/libavcodec/v308dec.c index 4bc4ea4e2..b591a79dd 100644 --- a/libavcodec/v308dec.c +++ b/libavcodec/v308dec.c @@ -48,9 +48,6 @@ static int v308_decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - y = pic->data[0]; u = pic->data[1]; v = pic->data[2]; diff --git a/libavcodec/v408dec.c b/libavcodec/v408dec.c index 4d8bccd65..2433c6de1 100644 --- a/libavcodec/v408dec.c +++ b/libavcodec/v408dec.c @@ -19,8 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config_components.h" - #include "avcodec.h" #include "codec_internal.h" #include "decode.h" @@ -47,9 +45,6 @@ static int v408_decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - y = pic->data[0]; u = pic->data[1]; v = pic->data[2]; @@ -74,7 +69,6 @@ static int v408_decode_frame(AVCodecContext *avctx, AVFrame *pic, return avpkt->size; } -#if CONFIG_V408_DECODER const FFCodec ff_v408_decoder = { .p.name = "v408", CODEC_LONG_NAME("Uncompressed packed QT 4:4:4:4"), @@ -84,4 +78,3 @@ const FFCodec ff_v408_decoder = { FF_CODEC_DECODE_CB(v408_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, }; -#endif diff --git a/libavcodec/v408enc.c b/libavcodec/v408enc.c index c1bf0f615..c173f650e 100644 --- a/libavcodec/v408enc.c +++ b/libavcodec/v408enc.c @@ -20,9 +20,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config_components.h" - -#include "libavutil/intreadwrite.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" @@ -72,7 +69,6 @@ static int v408_encode_frame(AVCodecContext *avctx, AVPacket *pkt, static const enum AVPixelFormat pix_fmt[] = { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE }; -#if CONFIG_V408_ENCODER const FFCodec ff_v408_encoder = { .p.name = "v408", CODEC_LONG_NAME("Uncompressed packed QT 4:4:4:4"), @@ -83,4 +79,3 @@ const FFCodec ff_v408_encoder = { FF_CODEC_ENCODE_CB(v408_encode_frame), .p.pix_fmts = pix_fmt, }; -#endif diff --git a/libavcodec/v410dec.c b/libavcodec/v410dec.c index 35e4a8ae0..04be830ad 100644 --- a/libavcodec/v410dec.c +++ b/libavcodec/v410dec.c @@ -102,9 +102,6 @@ static int v410_decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - td.buf = src; td.frame = pic; avctx->execute2(avctx, v410_decode_slice, &td, NULL, thread_count); diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c index 227713569..23474ee14 100644 --- a/libavcodec/v4l2_buffers.c +++ b/libavcodec/v4l2_buffers.c @@ -29,6 +29,7 @@ #include #include "libavcodec/avcodec.h" #include "libavutil/pixdesc.h" +#include "refstruct.h" #include "v4l2_context.h" #include "v4l2_buffers.h" #include "v4l2_m2m.h" @@ -229,7 +230,7 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused) ff_v4l2_buffer_enqueue(avbuf); } - av_buffer_unref(&avbuf->context_ref); + ff_refstruct_unref(&avbuf->context_ref); } } @@ -240,9 +241,7 @@ static int v4l2_buf_increase_ref(V4L2Buffer *in) if (in->context_ref) atomic_fetch_add(&in->context_refcount, 1); else { - in->context_ref = av_buffer_ref(s->self_ref); - if (!in->context_ref) - return AVERROR(ENOMEM); + in->context_ref = ff_refstruct_ref(s->self_ref); in->context_refcount = 1; } diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h index 3d2ff1b9a..e35b16130 100644 --- a/libavcodec/v4l2_buffers.h +++ b/libavcodec/v4l2_buffers.h @@ -28,7 +28,6 @@ #include #include -#include "libavutil/buffer.h" #include "libavutil/frame.h" #include "packet.h" @@ -46,8 +45,9 @@ typedef struct V4L2Buffer { struct V4L2Context *context; /* This object is refcounted per-plane, so we need to keep track - * of how many context-refs we are holding. */ - AVBufferRef *context_ref; + * of how many context-refs we are holding. + * This pointer is a RefStruct reference. */ + const struct V4L2m2mContext *context_ref; atomic_uint context_refcount; /* keep track of the mmap address and mmap length */ diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c index f20f713e1..be1df3785 100644 --- a/libavcodec/v4l2_context.c +++ b/libavcodec/v4l2_context.c @@ -27,6 +27,7 @@ #include #include #include +#include "libavutil/mem.h" #include "libavcodec/avcodec.h" #include "decode.h" #include "v4l2_buffers.h" diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c index bac3eb058..15415cfc4 100644 --- a/libavcodec/v4l2_m2m.c +++ b/libavcodec/v4l2_m2m.c @@ -28,9 +28,11 @@ #include #include #include "libavcodec/avcodec.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" #include "libavutil/pixfmt.h" +#include "refstruct.h" #include "v4l2_context.h" #include "v4l2_fmt.h" #include "v4l2_m2m.h" @@ -246,9 +248,9 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mContext *s) return 0; } -static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context) +static void v4l2_m2m_destroy_context(FFRefStructOpaque unused, void *context) { - V4L2m2mContext *s = (V4L2m2mContext*)context; + V4L2m2mContext *s = context; ff_v4l2_context_release(&s->capture); sem_destroy(&s->refsync); @@ -257,8 +259,6 @@ static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context) close(s->fd); av_frame_free(&s->frame); av_packet_unref(&s->buf_pkt); - - av_free(s); } int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv) @@ -282,7 +282,7 @@ int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv) ff_v4l2_context_release(&s->output); s->self_ref = NULL; - av_buffer_unref(&priv->context_ref); + ff_refstruct_unref(&priv->context); return 0; } @@ -327,17 +327,11 @@ int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv) int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s) { - *s = av_mallocz(sizeof(V4L2m2mContext)); + *s = ff_refstruct_alloc_ext(sizeof(**s), 0, NULL, + &v4l2_m2m_destroy_context); if (!*s) return AVERROR(ENOMEM); - priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext), - &v4l2_m2m_destroy_context, NULL, 0); - if (!priv->context_ref) { - av_freep(s); - return AVERROR(ENOMEM); - } - /* assign the context */ priv->context = *s; (*s)->priv = priv; @@ -345,13 +339,13 @@ int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s) /* populate it */ priv->context->capture.num_buffers = priv->num_capture_buffers; priv->context->output.num_buffers = priv->num_output_buffers; - priv->context->self_ref = priv->context_ref; + priv->context->self_ref = priv->context; priv->context->fd = -1; priv->context->frame = av_frame_alloc(); if (!priv->context->frame) { - av_buffer_unref(&priv->context_ref); - *s = NULL; /* freed when unreferencing context_ref */ + ff_refstruct_unref(&priv->context); + *s = NULL; /* freed when unreferencing context */ return AVERROR(ENOMEM); } diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h index 04d86d7b9..4ba33dc33 100644 --- a/libavcodec/v4l2_m2m.h +++ b/libavcodec/v4l2_m2m.h @@ -62,7 +62,7 @@ typedef struct V4L2m2mContext { AVFrame *frame; /* Reference to self; only valid while codec is active. */ - AVBufferRef *self_ref; + struct V4L2m2mContext *self_ref; /* reference back to V4L2m2mPriv */ void *priv; @@ -71,8 +71,7 @@ typedef struct V4L2m2mContext { typedef struct V4L2m2mPriv { AVClass *class; - V4L2m2mContext *context; - AVBufferRef *context_ref; + V4L2m2mContext *context; ///< RefStruct reference int num_output_buffers; int num_capture_buffers; diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c index e08db5d5d..5770e87ea 100644 --- a/libavcodec/v4l2_m2m_enc.c +++ b/libavcodec/v4l2_m2m_enc.c @@ -433,6 +433,7 @@ static const FFCodecDefault v4l2_m2m_defaults[] = { .close = v4l2_encode_close, \ .defaults = v4l2_m2m_defaults, \ .p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ + .color_ranges = AVCOL_RANGE_MPEG, \ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | \ FF_CODEC_CAP_INIT_CLEANUP, \ .p.wrapper_name = "v4l2m2m", \ diff --git a/libavcodec/vaapi_av1.c b/libavcodec/vaapi_av1.c index 5bf81fc97..5451b6055 100644 --- a/libavcodec/vaapi_av1.c +++ b/libavcodec/vaapi_av1.c @@ -19,6 +19,7 @@ */ #include "libavutil/frame.h" +#include "libavutil/mem.h" #include "hwaccel_internal.h" #include "vaapi_decode.h" #include "internal.h" @@ -42,11 +43,14 @@ typedef struct VAAPIAV1DecContext { */ VAAPIAV1FrameRef ref_tab[AV1_NUM_REF_FRAMES]; AVFrame *tmp_frame; + + int nb_slice_params; + VASliceParameterBufferAV1 *slice_params; } VAAPIAV1DecContext; static VASurfaceID vaapi_av1_surface_id(AV1Frame *vf) { - if (vf) + if (vf->f) return ff_vaapi_get_surface_id(vf->f); else return VA_INVALID_SURFACE; @@ -97,6 +101,8 @@ static int vaapi_av1_decode_uninit(AVCodecContext *avctx) for (int i = 0; i < FF_ARRAY_ELEMS(ctx->ref_tab); i++) av_frame_free(&ctx->ref_tab[i].frame); + av_freep(&ctx->slice_params); + return ff_vaapi_decode_uninit(avctx); } @@ -132,7 +138,7 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx, goto fail; pic->output_surface = ff_vaapi_get_surface_id(ctx->tmp_frame); } else { - pic->output_surface = vaapi_av1_surface_id(&s->cur_frame); + pic->output_surface = ff_vaapi_get_surface_id(s->cur_frame.f); } memset(&pic_param, 0, sizeof(VADecPictureParameterBufferAV1)); @@ -142,7 +148,7 @@ static int vaapi_av1_start_frame(AVCodecContext *avctx, .bit_depth_idx = bit_depth_idx, .matrix_coefficients = seq->color_config.matrix_coefficients, .current_frame = pic->output_surface, - .current_display_picture = vaapi_av1_surface_id(&s->cur_frame), + .current_display_picture = ff_vaapi_get_surface_id(s->cur_frame.f), .frame_width_minus1 = frame_header->frame_width_minus_1, .frame_height_minus1 = frame_header->frame_height_minus_1, .primary_ref_frame = frame_header->primary_ref_frame, @@ -393,13 +399,25 @@ static int vaapi_av1_decode_slice(AVCodecContext *avctx, { const AV1DecContext *s = avctx->priv_data; VAAPIDecodePicture *pic = s->cur_frame.hwaccel_picture_private; - VASliceParameterBufferAV1 slice_param; - int err = 0; + VAAPIAV1DecContext *ctx = avctx->internal->hwaccel_priv_data; + int err, nb_params; + + nb_params = s->tg_end - s->tg_start + 1; + if (ctx->nb_slice_params < nb_params) { + VASliceParameterBufferAV1 *tmp = av_realloc_array(ctx->slice_params, + nb_params, + sizeof(*ctx->slice_params)); + if (!tmp) { + ctx->nb_slice_params = 0; + err = AVERROR(ENOMEM); + goto fail; + } + ctx->slice_params = tmp; + ctx->nb_slice_params = nb_params; + } for (int i = s->tg_start; i <= s->tg_end; i++) { - memset(&slice_param, 0, sizeof(VASliceParameterBufferAV1)); - - slice_param = (VASliceParameterBufferAV1) { + ctx->slice_params[i - s->tg_start] = (VASliceParameterBufferAV1) { .slice_data_size = s->tile_group_info[i].tile_size, .slice_data_offset = s->tile_group_info[i].tile_offset, .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, @@ -408,18 +426,20 @@ static int vaapi_av1_decode_slice(AVCodecContext *avctx, .tg_start = s->tg_start, .tg_end = s->tg_end, }; - - err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &slice_param, - sizeof(VASliceParameterBufferAV1), - buffer, - size); - if (err) { - ff_vaapi_decode_cancel(avctx, pic); - return err; - } } + err = ff_vaapi_decode_make_slice_buffer(avctx, pic, ctx->slice_params, nb_params, + sizeof(VASliceParameterBufferAV1), + buffer, + size); + if (err) + goto fail; + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, pic); + return err; } const FFHWAccel ff_av1_vaapi_hwaccel = { diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c index cca94b533..a59194340 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -20,6 +20,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "avcodec.h" @@ -62,6 +63,7 @@ int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx, int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, VAAPIDecodePicture *pic, const void *params_data, + int nb_params, size_t params_size, const void *slice_data, size_t slice_size) @@ -72,13 +74,14 @@ int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, av_assert0(pic->nb_slices <= pic->slices_allocated); if (pic->nb_slices == pic->slices_allocated) { - pic->slice_buffers = + VABufferID *tmp = av_realloc_array(pic->slice_buffers, pic->slices_allocated ? pic->slices_allocated * 2 : 64, 2 * sizeof(*pic->slice_buffers)); - if (!pic->slice_buffers) + if (!tmp) return AVERROR(ENOMEM); + pic->slice_buffers = tmp; pic->slices_allocated = pic->slices_allocated ? pic->slices_allocated * 2 : 64; } av_assert0(pic->nb_slices + 1 <= pic->slices_allocated); @@ -87,7 +90,7 @@ int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, VASliceParameterBufferType, - params_size, 1, (void*)params_data, + params_size, nb_params, (void*)params_data, &pic->slice_buffers[index]); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create slice " @@ -155,6 +158,11 @@ int ff_vaapi_decode_issue(AVCodecContext *avctx, VAStatus vas; int err; + if (pic->nb_slices <= 0) { + err = AVERROR(EINVAL); + goto fail; + } + av_log(avctx, AV_LOG_DEBUG, "Decode to surface %#x.\n", pic->output_surface); @@ -598,22 +606,26 @@ static int vaapi_decode_make_config(AVCodecContext *avctx, if (err < 0) goto fail; - frames->initial_pool_size = 1; - // Add per-codec number of surfaces used for storing reference frames. - switch (avctx->codec_id) { - case AV_CODEC_ID_H264: - case AV_CODEC_ID_HEVC: - case AV_CODEC_ID_AV1: - frames->initial_pool_size += 16; - break; - case AV_CODEC_ID_VP9: - frames->initial_pool_size += 8; - break; - case AV_CODEC_ID_VP8: - frames->initial_pool_size += 3; - break; - default: - frames->initial_pool_size += 2; + if (CONFIG_VAAPI_1) + frames->initial_pool_size = 0; + else { + frames->initial_pool_size = 1; + // Add per-codec number of surfaces used for storing reference frames. + switch (avctx->codec_id) { + case AV_CODEC_ID_H264: + case AV_CODEC_ID_HEVC: + case AV_CODEC_ID_AV1: + frames->initial_pool_size += 16; + break; + case AV_CODEC_ID_VP9: + frames->initial_pool_size += 8; + break; + case AV_CODEC_ID_VP8: + frames->initial_pool_size += 3; + break; + default: + frames->initial_pool_size += 2; + } } } diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h index 6beda14e5..702171e10 100644 --- a/libavcodec/vaapi_decode.h +++ b/libavcodec/vaapi_decode.h @@ -73,6 +73,7 @@ int ff_vaapi_decode_make_param_buffer(AVCodecContext *avctx, int ff_vaapi_decode_make_slice_buffer(AVCodecContext *avctx, VAAPIDecodePicture *pic, const void *params_data, + int nb_params, size_t params_size, const void *slice_data, size_t slice_size); diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index b8765a19c..16a9a364f 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -25,6 +25,7 @@ #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "vaapi_encode.h" @@ -37,8 +38,6 @@ const AVCodecHWConfigInternal *const ff_vaapi_encode_hw_configs[] = { NULL, }; -static const char * const picture_type_name[] = { "IDR", "I", "P", "B" }; - static int vaapi_encode_make_packed_header(AVCodecContext *avctx, VAAPIEncodePicture *pic, int type, char *data, size_t bit_len) @@ -136,25 +135,28 @@ static int vaapi_encode_make_misc_param_buffer(AVCodecContext *avctx, buffer, buffer_size); } -static int vaapi_encode_wait(AVCodecContext *avctx, - VAAPIEncodePicture *pic) +static int vaapi_encode_wait(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic) { +#if VA_CHECK_VERSION(1, 9, 0) + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; +#endif VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodePicture *pic = base_pic->priv; VAStatus vas; - av_assert0(pic->encode_issued); + av_assert0(base_pic->encode_issued); - if (pic->encode_complete) { + if (base_pic->encode_complete) { // Already waited for this picture. return 0; } av_log(avctx, AV_LOG_DEBUG, "Sync to pic %"PRId64"/%"PRId64" " - "(input surface %#x).\n", pic->display_order, - pic->encode_order, pic->input_surface); + "(input surface %#x).\n", base_pic->display_order, + base_pic->encode_order, pic->input_surface); #if VA_CHECK_VERSION(1, 9, 0) - if (ctx->has_sync_buffer_func) { + if (base_ctx->async_encode) { vas = vaSyncBuffer(ctx->hwctx->display, pic->output_buffer, VA_TIMEOUT_INFINITE); @@ -175,9 +177,9 @@ static int vaapi_encode_wait(AVCodecContext *avctx, } // Input is definitely finished with now. - av_frame_free(&pic->input_image); + av_frame_free(&base_pic->input_image); - pic->encode_complete = 1; + base_pic->encode_complete = 1; return 0; } @@ -264,63 +266,54 @@ static int vaapi_encode_make_tile_slice(AVCodecContext *avctx, } static int vaapi_encode_issue(AVCodecContext *avctx, - VAAPIEncodePicture *pic) + FFHWBaseEncodePicture *base_pic) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodePicture *pic = base_pic->priv; VAAPIEncodeSlice *slice; VAStatus vas; - int err, i; + int err = 0, i; char data[MAX_PARAM_BUFFER_SIZE]; size_t bit_len; av_unused AVFrameSideData *sd; av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" " - "as type %s.\n", pic->display_order, pic->encode_order, - picture_type_name[pic->type]); - if (pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0) { + "as type %s.\n", base_pic->display_order, base_pic->encode_order, + ff_hw_base_encode_get_pictype_name(base_pic->type)); + if (base_pic->nb_refs[0] == 0 && base_pic->nb_refs[1] == 0) { av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n"); } else { av_log(avctx, AV_LOG_DEBUG, "L0 refers to"); - for (i = 0; i < pic->nb_refs[0]; i++) { + for (i = 0; i < base_pic->nb_refs[0]; i++) { av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, - pic->refs[0][i]->display_order, pic->refs[0][i]->encode_order); + base_pic->refs[0][i]->display_order, base_pic->refs[0][i]->encode_order); } av_log(avctx, AV_LOG_DEBUG, ".\n"); - if (pic->nb_refs[1]) { + if (base_pic->nb_refs[1]) { av_log(avctx, AV_LOG_DEBUG, "L1 refers to"); - for (i = 0; i < pic->nb_refs[1]; i++) { + for (i = 0; i < base_pic->nb_refs[1]; i++) { av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64, - pic->refs[1][i]->display_order, pic->refs[1][i]->encode_order); + base_pic->refs[1][i]->display_order, base_pic->refs[1][i]->encode_order); } av_log(avctx, AV_LOG_DEBUG, ".\n"); } } - av_assert0(!pic->encode_issued); - for (i = 0; i < pic->nb_refs[0]; i++) { - av_assert0(pic->refs[0][i]); - av_assert0(pic->refs[0][i]->encode_issued); + av_assert0(!base_pic->encode_issued); + for (i = 0; i < base_pic->nb_refs[0]; i++) { + av_assert0(base_pic->refs[0][i]); + av_assert0(base_pic->refs[0][i]->encode_issued); } - for (i = 0; i < pic->nb_refs[1]; i++) { - av_assert0(pic->refs[1][i]); - av_assert0(pic->refs[1][i]->encode_issued); + for (i = 0; i < base_pic->nb_refs[1]; i++) { + av_assert0(base_pic->refs[1][i]); + av_assert0(base_pic->refs[1][i]->encode_issued); } av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", pic->input_surface); - pic->recon_image = av_frame_alloc(); - if (!pic->recon_image) { - err = AVERROR(ENOMEM); - goto fail; - } - - err = av_hwframe_get_buffer(ctx->recon_frames_ref, pic->recon_image, 0); - if (err < 0) { - err = AVERROR(ENOMEM); - goto fail; - } - pic->recon_surface = (VASurfaceID)(uintptr_t)pic->recon_image->data[3]; + 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); @@ -344,7 +337,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, pic->nb_param_buffers = 0; - if (pic->type == PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) { + if (base_pic->type == FF_HW_PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) { err = vaapi_encode_make_param_buffer(avctx, pic, VAEncSequenceParameterBufferType, ctx->codec_sequence_params, @@ -353,7 +346,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, goto fail; } - if (pic->type == PICTURE_TYPE_IDR) { + if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) { for (i = 0; i < ctx->nb_global_params; i++) { err = vaapi_encode_make_misc_param_buffer(avctx, pic, ctx->global_params_type[i], @@ -365,7 +358,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, } if (ctx->codec->init_picture_params) { - err = ctx->codec->init_picture_params(avctx, pic); + err = ctx->codec->init_picture_params(avctx, base_pic); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise picture " "parameters: %d.\n", err); @@ -390,7 +383,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, } #endif - if (pic->type == PICTURE_TYPE_IDR) { + if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) { if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE && ctx->codec->write_sequence_header) { bit_len = 8 * sizeof(data); @@ -411,7 +404,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_PICTURE && ctx->codec->write_picture_header) { bit_len = 8 * sizeof(data); - err = ctx->codec->write_picture_header(avctx, pic, data, &bit_len); + err = ctx->codec->write_picture_header(avctx, base_pic, data, &bit_len); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to write per-picture " "header: %d.\n", err); @@ -428,7 +421,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, for (i = 0;; i++) { size_t len = sizeof(data); int type; - err = ctx->codec->write_extra_buffer(avctx, pic, i, &type, + err = ctx->codec->write_extra_buffer(avctx, base_pic, i, &type, data, &len); if (err == AVERROR_EOF) break; @@ -450,7 +443,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, for (i = 0;; i++) { int type; bit_len = 8 * sizeof(data); - err = ctx->codec->write_extra_header(avctx, pic, i, &type, + err = ctx->codec->write_extra_header(avctx, base_pic, i, &type, data, &bit_len); if (err == AVERROR_EOF) break; @@ -494,7 +487,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, } if (ctx->codec->init_slice_params) { - err = ctx->codec->init_slice_params(avctx, pic, slice); + err = ctx->codec->init_slice_params(avctx, base_pic, slice); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise slice " "parameters: %d.\n", err); @@ -530,9 +523,9 @@ static int vaapi_encode_issue(AVCodecContext *avctx, } #if VA_CHECK_VERSION(1, 0, 0) - sd = av_frame_get_side_data(pic->input_image, + sd = av_frame_get_side_data(base_pic->input_image, AV_FRAME_DATA_REGIONS_OF_INTEREST); - if (sd && ctx->roi_allowed) { + if (sd && base_ctx->roi_allowed) { const AVRegionOfInterest *roi; uint32_t roi_size; VAEncMiscParameterBufferROI param_roi; @@ -543,11 +536,11 @@ static int vaapi_encode_issue(AVCodecContext *avctx, av_assert0(roi_size && sd->size % roi_size == 0); nb_roi = sd->size / roi_size; if (nb_roi > ctx->roi_max_regions) { - if (!ctx->roi_warned) { + if (!base_ctx->roi_warned) { av_log(avctx, AV_LOG_WARNING, "More ROIs set than " "supported by driver (%d > %d).\n", nb_roi, ctx->roi_max_regions); - ctx->roi_warned = 1; + base_ctx->roi_warned = 1; } nb_roi = ctx->roi_max_regions; } @@ -640,8 +633,6 @@ static int vaapi_encode_issue(AVCodecContext *avctx, } } - pic->encode_issued = 1; - return 0; fail_with_picture: @@ -658,52 +649,11 @@ fail_at_end: av_freep(&pic->param_buffers); av_freep(&pic->slices); av_freep(&pic->roi); - av_frame_free(&pic->recon_image); ff_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; return err; } -static int vaapi_encode_set_output_property(AVCodecContext *avctx, - VAAPIEncodePicture *pic, - AVPacket *pkt) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - - if (pic->type == PICTURE_TYPE_IDR) - pkt->flags |= AV_PKT_FLAG_KEY; - - pkt->pts = pic->pts; - pkt->duration = pic->duration; - - // for no-delay encoders this is handled in generic codec - if (avctx->codec->capabilities & AV_CODEC_CAP_DELAY && - avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { - pkt->opaque = pic->opaque; - pkt->opaque_ref = pic->opaque_ref; - pic->opaque_ref = NULL; - } - - if (ctx->codec->flags & FLAG_TIMESTAMP_NO_DELAY) { - pkt->dts = pkt->pts; - return 0; - } - - if (ctx->output_delay == 0) { - pkt->dts = pkt->pts; - } else if (pic->encode_order < ctx->decode_delay) { - if (ctx->ts_ring[pic->encode_order] < INT64_MIN + ctx->dts_pts_diff) - pkt->dts = INT64_MIN; - else - pkt->dts = ctx->ts_ring[pic->encode_order] - ctx->dts_pts_diff; - } else { - pkt->dts = ctx->ts_ring[(pic->encode_order - ctx->decode_delay) % - (3 * ctx->output_delay + ctx->async_depth)]; - } - - return 0; -} - static int vaapi_encode_get_coded_buffer_size(AVCodecContext *avctx, VABufferID buf_id) { VAAPIEncodeContext *ctx = avctx->priv_data; @@ -817,13 +767,15 @@ end: } static int vaapi_encode_output(AVCodecContext *avctx, - VAAPIEncodePicture *pic, AVPacket *pkt) + FFHWBaseEncodePicture *base_pic, AVPacket *pkt) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodePicture *pic = base_pic->priv; AVPacket *pkt_ptr = pkt; int err; - err = vaapi_encode_wait(avctx, pic); + err = vaapi_encode_wait(avctx, base_pic); if (err < 0) return err; @@ -832,17 +784,17 @@ static int vaapi_encode_output(AVCodecContext *avctx, ctx->coded_buffer_ref = ff_refstruct_ref(pic->output_buffer_ref); if (pic->tail_size) { - if (ctx->tail_pkt->size) { + if (base_ctx->tail_pkt->size) { err = AVERROR_BUG; goto end; } - err = ff_get_encode_buffer(avctx, ctx->tail_pkt, pic->tail_size, 0); + err = ff_get_encode_buffer(avctx, base_ctx->tail_pkt, pic->tail_size, 0); if (err < 0) goto end; - memcpy(ctx->tail_pkt->data, pic->tail_data, pic->tail_size); - pkt_ptr = ctx->tail_pkt; + memcpy(base_ctx->tail_pkt->data, pic->tail_data, pic->tail_size); + pkt_ptr = base_ctx->tail_pkt; } } else { err = vaapi_encode_get_coded_data(avctx, pic, pkt); @@ -851,9 +803,10 @@ static int vaapi_encode_output(AVCodecContext *avctx, } av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n", - pic->display_order, pic->encode_order); + base_pic->display_order, base_pic->encode_order); - vaapi_encode_set_output_property(avctx, pic, pkt_ptr); + ff_hw_base_encode_set_output_property(base_ctx, avctx, (FFHWBaseEncodePicture*)base_pic, pkt_ptr, + ctx->codec->flags & FLAG_TIMESTAMP_NO_DELAY); end: ff_refstruct_unref(&pic->output_buffer_ref); @@ -861,15 +814,16 @@ end: return err; } -static int vaapi_encode_discard(AVCodecContext *avctx, - VAAPIEncodePicture *pic) +static int vaapi_encode_discard(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic) { - vaapi_encode_wait(avctx, pic); + VAAPIEncodePicture *pic = base_pic->priv; + + vaapi_encode_wait(avctx, base_pic); if (pic->output_buffer_ref) { av_log(avctx, AV_LOG_DEBUG, "Discard output for pic " "%"PRId64"/%"PRId64".\n", - pic->display_order, pic->encode_order); + base_pic->display_order, base_pic->encode_order); ff_refstruct_unref(&pic->output_buffer_ref); pic->output_buffer = VA_INVALID_ID; @@ -878,616 +832,45 @@ static int vaapi_encode_discard(AVCodecContext *avctx, return 0; } -static VAAPIEncodePicture *vaapi_encode_alloc(AVCodecContext *avctx) +static int vaapi_encode_init(AVCodecContext *avctx, FFHWBaseEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic; - - pic = av_mallocz(sizeof(*pic)); - if (!pic) - return NULL; + VAAPIEncodePicture *priv = pic->priv; + AVFrame *frame = pic->input_image; if (ctx->codec->picture_priv_data_size > 0) { - pic->priv_data = av_mallocz(ctx->codec->picture_priv_data_size); - if (!pic->priv_data) { - av_freep(&pic); - return NULL; - } + pic->codec_priv = av_mallocz(ctx->codec->picture_priv_data_size); + if (!pic->codec_priv) + return AVERROR(ENOMEM); } - pic->input_surface = VA_INVALID_ID; - pic->recon_surface = VA_INVALID_ID; - pic->output_buffer = VA_INVALID_ID; + priv->input_surface = (VASurfaceID)(uintptr_t)frame->data[3]; + priv->recon_surface = VA_INVALID_ID; + priv->output_buffer = VA_INVALID_ID; - return pic; + return 0; } -static int vaapi_encode_free(AVCodecContext *avctx, - VAAPIEncodePicture *pic) +static int vaapi_encode_free(AVCodecContext *avctx, FFHWBaseEncodePicture *pic) { + VAAPIEncodePicture *priv = pic->priv; int i; if (pic->encode_issued) vaapi_encode_discard(avctx, pic); - if (pic->slices) { - for (i = 0; i < pic->nb_slices; i++) - av_freep(&pic->slices[i].codec_slice_params); + if (priv->slices) { + for (i = 0; i < priv->nb_slices; i++) + av_freep(&priv->slices[i].codec_slice_params); } - av_frame_free(&pic->input_image); - av_frame_free(&pic->recon_image); - - av_buffer_unref(&pic->opaque_ref); - - av_freep(&pic->param_buffers); - av_freep(&pic->slices); + av_freep(&priv->param_buffers); + av_freep(&priv->slices); // Output buffer should already be destroyed. - av_assert0(pic->output_buffer == VA_INVALID_ID); + av_assert0(priv->output_buffer == VA_INVALID_ID); - av_freep(&pic->priv_data); - av_freep(&pic->codec_picture_params); - av_freep(&pic->roi); - - av_free(pic); - - return 0; -} - -static void vaapi_encode_add_ref(AVCodecContext *avctx, - VAAPIEncodePicture *pic, - VAAPIEncodePicture *target, - int is_ref, int in_dpb, int prev) -{ - int refs = 0; - - if (is_ref) { - av_assert0(pic != target); - av_assert0(pic->nb_refs[0] < MAX_PICTURE_REFERENCES && - pic->nb_refs[1] < MAX_PICTURE_REFERENCES); - if (target->display_order < pic->display_order) - pic->refs[0][pic->nb_refs[0]++] = target; - else - pic->refs[1][pic->nb_refs[1]++] = target; - ++refs; - } - - if (in_dpb) { - av_assert0(pic->nb_dpb_pics < MAX_DPB_SIZE); - pic->dpb[pic->nb_dpb_pics++] = target; - ++refs; - } - - if (prev) { - av_assert0(!pic->prev); - pic->prev = target; - ++refs; - } - - target->ref_count[0] += refs; - target->ref_count[1] += refs; -} - -static void vaapi_encode_remove_refs(AVCodecContext *avctx, - VAAPIEncodePicture *pic, - int level) -{ - int i; - - if (pic->ref_removed[level]) - return; - - for (i = 0; i < pic->nb_refs[0]; i++) { - av_assert0(pic->refs[0][i]); - --pic->refs[0][i]->ref_count[level]; - av_assert0(pic->refs[0][i]->ref_count[level] >= 0); - } - - for (i = 0; i < pic->nb_refs[1]; i++) { - av_assert0(pic->refs[1][i]); - --pic->refs[1][i]->ref_count[level]; - av_assert0(pic->refs[1][i]->ref_count[level] >= 0); - } - - for (i = 0; i < pic->nb_dpb_pics; i++) { - av_assert0(pic->dpb[i]); - --pic->dpb[i]->ref_count[level]; - av_assert0(pic->dpb[i]->ref_count[level] >= 0); - } - - av_assert0(pic->prev || pic->type == PICTURE_TYPE_IDR); - if (pic->prev) { - --pic->prev->ref_count[level]; - av_assert0(pic->prev->ref_count[level] >= 0); - } - - pic->ref_removed[level] = 1; -} - -static void vaapi_encode_set_b_pictures(AVCodecContext *avctx, - VAAPIEncodePicture *start, - VAAPIEncodePicture *end, - VAAPIEncodePicture *prev, - int current_depth, - VAAPIEncodePicture **last) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic, *next, *ref; - int i, len; - - av_assert0(start && end && start != end && start->next != end); - - // If we are at the maximum depth then encode all pictures as - // non-referenced B-pictures. Also do this if there is exactly one - // picture left, since there will be nothing to reference it. - if (current_depth == ctx->max_b_depth || start->next->next == end) { - for (pic = start->next; pic; pic = pic->next) { - if (pic == end) - break; - pic->type = PICTURE_TYPE_B; - pic->b_depth = current_depth; - - vaapi_encode_add_ref(avctx, pic, start, 1, 1, 0); - vaapi_encode_add_ref(avctx, pic, end, 1, 1, 0); - vaapi_encode_add_ref(avctx, pic, prev, 0, 0, 1); - - for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0]) - vaapi_encode_add_ref(avctx, pic, ref, 0, 1, 0); - } - *last = prev; - - } else { - // Split the current list at the midpoint with a referenced - // B-picture, then descend into each side separately. - len = 0; - for (pic = start->next; pic != end; pic = pic->next) - ++len; - for (pic = start->next, i = 1; 2 * i < len; pic = pic->next, i++); - - pic->type = PICTURE_TYPE_B; - pic->b_depth = current_depth; - - pic->is_reference = 1; - - vaapi_encode_add_ref(avctx, pic, pic, 0, 1, 0); - vaapi_encode_add_ref(avctx, pic, start, 1, 1, 0); - vaapi_encode_add_ref(avctx, pic, end, 1, 1, 0); - vaapi_encode_add_ref(avctx, pic, prev, 0, 0, 1); - - for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0]) - vaapi_encode_add_ref(avctx, pic, ref, 0, 1, 0); - - if (i > 1) - vaapi_encode_set_b_pictures(avctx, start, pic, pic, - current_depth + 1, &next); - else - next = pic; - - vaapi_encode_set_b_pictures(avctx, pic, end, next, - current_depth + 1, last); - } -} - -static void vaapi_encode_add_next_prev(AVCodecContext *avctx, - VAAPIEncodePicture *pic) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - int i; - - if (!pic) - return; - - if (pic->type == PICTURE_TYPE_IDR) { - for (i = 0; i < ctx->nb_next_prev; i++) { - --ctx->next_prev[i]->ref_count[0]; - ctx->next_prev[i] = NULL; - } - ctx->next_prev[0] = pic; - ++pic->ref_count[0]; - ctx->nb_next_prev = 1; - - return; - } - - if (ctx->nb_next_prev < MAX_PICTURE_REFERENCES) { - 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++) - ctx->next_prev[i] = ctx->next_prev[i + 1]; - ctx->next_prev[i] = pic; - ++pic->ref_count[0]; - } -} - -static int vaapi_encode_pick_next(AVCodecContext *avctx, - VAAPIEncodePicture **pic_out) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic = NULL, *prev = NULL, *next, *start; - int i, b_counter, closed_gop_end; - - // If there are any B-frames already queued, the next one to encode - // is the earliest not-yet-issued frame for which all references are - // available. - for (pic = ctx->pic_start; pic; pic = pic->next) { - if (pic->encode_issued) - continue; - if (pic->type != PICTURE_TYPE_B) - continue; - for (i = 0; i < pic->nb_refs[0]; i++) { - if (!pic->refs[0][i]->encode_issued) - break; - } - if (i != pic->nb_refs[0]) - continue; - - for (i = 0; i < pic->nb_refs[1]; i++) { - if (!pic->refs[1][i]->encode_issued) - break; - } - if (i == pic->nb_refs[1]) - break; - } - - if (pic) { - av_log(avctx, AV_LOG_DEBUG, "Pick B-picture at depth %d to " - "encode next.\n", pic->b_depth); - *pic_out = pic; - return 0; - } - - // Find the B-per-Pth available picture to become the next picture - // on the top layer. - start = NULL; - b_counter = 0; - closed_gop_end = ctx->closed_gop || - ctx->idr_counter == ctx->gop_per_idr; - for (pic = ctx->pic_start; pic; pic = next) { - next = pic->next; - if (pic->encode_issued) { - start = pic; - continue; - } - // If the next available picture is force-IDR, encode it to start - // a new GOP immediately. - if (pic->force_idr) - break; - if (b_counter == ctx->b_per_p) - break; - // If this picture ends a closed GOP or starts a new GOP then it - // needs to be in the top layer. - if (ctx->gop_counter + b_counter + closed_gop_end >= ctx->gop_size) - break; - // If the picture after this one is force-IDR, we need to encode - // this one in the top layer. - if (next && next->force_idr) - break; - ++b_counter; - } - - // At the end of the stream the last picture must be in the top layer. - if (!pic && ctx->end_of_stream) { - --b_counter; - pic = ctx->pic_end; - if (pic->encode_complete) - return AVERROR_EOF; - else if (pic->encode_issued) - return AVERROR(EAGAIN); - } - - if (!pic) { - av_log(avctx, AV_LOG_DEBUG, "Pick nothing to encode next - " - "need more input for reference pictures.\n"); - return AVERROR(EAGAIN); - } - if (ctx->input_order <= ctx->decode_delay && !ctx->end_of_stream) { - av_log(avctx, AV_LOG_DEBUG, "Pick nothing to encode next - " - "need more input for timestamps.\n"); - return AVERROR(EAGAIN); - } - - if (pic->force_idr) { - av_log(avctx, AV_LOG_DEBUG, "Pick forced IDR-picture to " - "encode next.\n"); - pic->type = PICTURE_TYPE_IDR; - ctx->idr_counter = 1; - ctx->gop_counter = 1; - - } else if (ctx->gop_counter + b_counter >= ctx->gop_size) { - if (ctx->idr_counter == ctx->gop_per_idr) { - av_log(avctx, AV_LOG_DEBUG, "Pick new-GOP IDR-picture to " - "encode next.\n"); - pic->type = PICTURE_TYPE_IDR; - ctx->idr_counter = 1; - } else { - av_log(avctx, AV_LOG_DEBUG, "Pick new-GOP I-picture to " - "encode next.\n"); - pic->type = PICTURE_TYPE_I; - ++ctx->idr_counter; - } - ctx->gop_counter = 1; - - } else { - if (ctx->gop_counter + b_counter + closed_gop_end == ctx->gop_size) { - av_log(avctx, AV_LOG_DEBUG, "Pick group-end P-picture to " - "encode next.\n"); - } else { - av_log(avctx, AV_LOG_DEBUG, "Pick normal P-picture to " - "encode next.\n"); - } - pic->type = PICTURE_TYPE_P; - av_assert0(start); - ctx->gop_counter += 1 + b_counter; - } - pic->is_reference = 1; - *pic_out = pic; - - vaapi_encode_add_ref(avctx, pic, pic, 0, 1, 0); - if (pic->type != PICTURE_TYPE_IDR) { - // TODO: apply both previous and forward multi reference for all vaapi encoders. - // And L0/L1 reference frame number can be set dynamically through query - // VAConfigAttribEncMaxRefFrames attribute. - if (avctx->codec_id == AV_CODEC_ID_AV1) { - for (i = 0; i < ctx->nb_next_prev; i++) - vaapi_encode_add_ref(avctx, pic, ctx->next_prev[i], - pic->type == PICTURE_TYPE_P, - b_counter > 0, 0); - } else - vaapi_encode_add_ref(avctx, pic, start, - pic->type == PICTURE_TYPE_P, - b_counter > 0, 0); - - vaapi_encode_add_ref(avctx, pic, ctx->next_prev[ctx->nb_next_prev - 1], 0, 0, 1); - } - - if (b_counter > 0) { - vaapi_encode_set_b_pictures(avctx, start, pic, pic, 1, - &prev); - } else { - prev = pic; - } - vaapi_encode_add_next_prev(avctx, prev); - - return 0; -} - -static int vaapi_encode_clear_old(AVCodecContext *avctx) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic, *prev, *next; - - av_assert0(ctx->pic_start); - - // Remove direct references once each picture is complete. - for (pic = ctx->pic_start; pic; pic = pic->next) { - if (pic->encode_complete && pic->next) - vaapi_encode_remove_refs(avctx, pic, 0); - } - - // Remove indirect references once a picture has no direct references. - for (pic = ctx->pic_start; pic; pic = pic->next) { - if (pic->encode_complete && pic->ref_count[0] == 0) - vaapi_encode_remove_refs(avctx, pic, 1); - } - - // Clear out all complete pictures with no remaining references. - prev = NULL; - for (pic = ctx->pic_start; pic; pic = next) { - next = pic->next; - if (pic->encode_complete && pic->ref_count[1] == 0) { - av_assert0(pic->ref_removed[0] && pic->ref_removed[1]); - if (prev) - prev->next = next; - else - ctx->pic_start = next; - vaapi_encode_free(avctx, pic); - } else { - prev = pic; - } - } - - return 0; -} - -static int vaapi_encode_check_frame(AVCodecContext *avctx, - const AVFrame *frame) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - - if ((frame->crop_top || frame->crop_bottom || - frame->crop_left || frame->crop_right) && !ctx->crop_warned) { - av_log(avctx, AV_LOG_WARNING, "Cropping information on input " - "frames ignored due to lack of API support.\n"); - ctx->crop_warned = 1; - } - - if (!ctx->roi_allowed) { - AVFrameSideData *sd = - av_frame_get_side_data(frame, AV_FRAME_DATA_REGIONS_OF_INTEREST); - - if (sd && !ctx->roi_warned) { - av_log(avctx, AV_LOG_WARNING, "ROI side data on input " - "frames ignored due to lack of driver support.\n"); - ctx->roi_warned = 1; - } - } - - return 0; -} - -static int vaapi_encode_send_frame(AVCodecContext *avctx, AVFrame *frame) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic; - int err; - - if (frame) { - av_log(avctx, AV_LOG_DEBUG, "Input frame: %ux%u (%"PRId64").\n", - frame->width, frame->height, frame->pts); - - err = vaapi_encode_check_frame(avctx, frame); - if (err < 0) - return err; - - pic = vaapi_encode_alloc(avctx); - if (!pic) - return AVERROR(ENOMEM); - - pic->input_image = av_frame_alloc(); - if (!pic->input_image) { - err = AVERROR(ENOMEM); - goto fail; - } - - if (ctx->input_order == 0 || frame->pict_type == AV_PICTURE_TYPE_I) - pic->force_idr = 1; - - pic->input_surface = (VASurfaceID)(uintptr_t)frame->data[3]; - pic->pts = frame->pts; - pic->duration = frame->duration; - - if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) { - err = av_buffer_replace(&pic->opaque_ref, frame->opaque_ref); - if (err < 0) - goto fail; - - pic->opaque = frame->opaque; - } - - av_frame_move_ref(pic->input_image, frame); - - if (ctx->input_order == 0) - ctx->first_pts = pic->pts; - if (ctx->input_order == ctx->decode_delay) - ctx->dts_pts_diff = pic->pts - ctx->first_pts; - if (ctx->output_delay > 0) - ctx->ts_ring[ctx->input_order % - (3 * ctx->output_delay + ctx->async_depth)] = pic->pts; - - pic->display_order = ctx->input_order; - ++ctx->input_order; - - if (ctx->pic_start) { - ctx->pic_end->next = pic; - ctx->pic_end = pic; - } else { - ctx->pic_start = pic; - ctx->pic_end = pic; - } - - } else { - ctx->end_of_stream = 1; - - // Fix timestamps if we hit end-of-stream before the initial decode - // delay has elapsed. - if (ctx->input_order < ctx->decode_delay) - ctx->dts_pts_diff = ctx->pic_end->pts - ctx->first_pts; - } - - return 0; - -fail: - vaapi_encode_free(avctx, pic); - return err; -} - -int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic = NULL; - AVFrame *frame = ctx->frame; - int err; - -start: - /** if no B frame before repeat P frame, sent repeat P frame out. */ - if (ctx->tail_pkt->size) { - for (VAAPIEncodePicture *tmp = ctx->pic_start; tmp; tmp = tmp->next) { - if (tmp->type == PICTURE_TYPE_B && tmp->pts < ctx->tail_pkt->pts) - break; - else if (!tmp->next) { - av_packet_move_ref(pkt, ctx->tail_pkt); - goto end; - } - } - } - - err = ff_encode_get_frame(avctx, frame); - if (err < 0 && err != AVERROR_EOF) - return err; - - if (err == AVERROR_EOF) - frame = NULL; - - err = vaapi_encode_send_frame(avctx, frame); - if (err < 0) - return err; - - if (!ctx->pic_start) { - if (ctx->end_of_stream) - return AVERROR_EOF; - else - return AVERROR(EAGAIN); - } - - if (ctx->has_sync_buffer_func) { - if (av_fifo_can_write(ctx->encode_fifo)) { - err = vaapi_encode_pick_next(avctx, &pic); - if (!err) { - av_assert0(pic); - pic->encode_order = ctx->encode_order + - av_fifo_can_read(ctx->encode_fifo); - err = vaapi_encode_issue(avctx, pic); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); - return err; - } - av_fifo_write(ctx->encode_fifo, &pic, 1); - } - } - - if (!av_fifo_can_read(ctx->encode_fifo)) - return err; - - // More frames can be buffered - if (av_fifo_can_write(ctx->encode_fifo) && !ctx->end_of_stream) - return AVERROR(EAGAIN); - - av_fifo_read(ctx->encode_fifo, &pic, 1); - ctx->encode_order = pic->encode_order + 1; - } else { - err = vaapi_encode_pick_next(avctx, &pic); - if (err < 0) - return err; - av_assert0(pic); - - pic->encode_order = ctx->encode_order++; - - err = vaapi_encode_issue(avctx, pic); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); - return err; - } - } - - err = vaapi_encode_output(avctx, pic, pkt); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Output failed: %d.\n", err); - return err; - } - - ctx->output_order = pic->encode_order; - vaapi_encode_clear_old(avctx); - - /** loop to get an available pkt in encoder flushing. */ - if (ctx->end_of_stream && !pkt->size) - goto start; - -end: - if (pkt->size) - av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64", dts %"PRId64", " - "size %d bytes.\n", pkt->pts, pkt->dts, pkt->size); + av_freep(&priv->codec_picture_params); + av_freep(&priv->roi); return 0; } @@ -1551,9 +934,10 @@ static const VAEntrypoint vaapi_encode_entrypoints_low_power[] = { static av_cold int vaapi_encode_profile_entrypoint(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAProfile *va_profiles = NULL; - VAEntrypoint *va_entrypoints = NULL; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAProfile *va_profiles = NULL; + VAEntrypoint *va_entrypoints = NULL; VAStatus vas; const VAEntrypoint *usable_entrypoints; const VAAPIEncodeProfile *profile; @@ -1576,10 +960,10 @@ static av_cold int vaapi_encode_profile_entrypoint(AVCodecContext *avctx) usable_entrypoints = vaapi_encode_entrypoints_normal; } - desc = av_pix_fmt_desc_get(ctx->input_frames->sw_format); + desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); if (!desc) { av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%d).\n", - ctx->input_frames->sw_format); + base_ctx->input_frames->sw_format); return AVERROR(EINVAL); } depth = desc->comp[0].depth; @@ -1874,7 +1258,7 @@ static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx) if (ctx->explicit_qp) TRY_RC_MODE(RC_MODE_CQP, 1); - if (ctx->codec->flags & FLAG_CONSTANT_QUALITY_ONLY) + if (ctx->codec->flags & FF_HW_FLAG_CONSTANT_QUALITY_ONLY) TRY_RC_MODE(RC_MODE_CQP, 1); if (avctx->flags & AV_CODEC_FLAG_QSCALE) @@ -2187,11 +1571,12 @@ static av_cold int vaapi_encode_init_max_frame_size(AVCodecContext *avctx) static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; VAConfigAttrib attr = { VAConfigAttribEncMaxRefFrames }; uint32_t ref_l0, ref_l1; - int prediction_pre_only; + int prediction_pre_only, err; vas = vaGetConfigAttributes(ctx->hwctx->display, ctx->va_profile, @@ -2210,11 +1595,11 @@ static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx) ref_l1 = attr.value >> 16 & 0xffff; } - ctx->p_to_gpb = 0; + base_ctx->p_to_gpb = 0; prediction_pre_only = 0; #if VA_CHECK_VERSION(1, 9, 0) - if (!(ctx->codec->flags & FLAG_INTRA_ONLY || + if (!(ctx->codec->flags & FF_HW_FLAG_INTRA_ONLY || avctx->gop_size <= 1)) { attr = (VAConfigAttrib) { VAConfigAttribPredictionDirection }; vas = vaGetConfigAttributes(ctx->hwctx->display, @@ -2246,7 +1631,7 @@ static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx) if (attr.value & VA_PREDICTION_DIRECTION_BI_NOT_EMPTY) { if (ref_l0 > 0 && ref_l1 > 0) { - ctx->p_to_gpb = 1; + base_ctx->p_to_gpb = 1; av_log(avctx, AV_LOG_VERBOSE, "Driver does not support P-frames, " "replacing them with B-frames.\n"); } @@ -2255,53 +1640,10 @@ static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx) } #endif - if (ctx->codec->flags & FLAG_INTRA_ONLY || - avctx->gop_size <= 1) { - av_log(avctx, AV_LOG_VERBOSE, "Using intra frames only.\n"); - ctx->gop_size = 1; - } else if (ref_l0 < 1) { - av_log(avctx, AV_LOG_ERROR, "Driver does not support any " - "reference frames.\n"); - return AVERROR(EINVAL); - } else if (!(ctx->codec->flags & FLAG_B_PICTURES) || - ref_l1 < 1 || avctx->max_b_frames < 1 || - prediction_pre_only) { - if (ctx->p_to_gpb) - av_log(avctx, AV_LOG_VERBOSE, "Using intra and B-frames " - "(supported references: %d / %d).\n", - ref_l0, ref_l1); - else - av_log(avctx, AV_LOG_VERBOSE, "Using intra and P-frames " - "(supported references: %d / %d).\n", ref_l0, ref_l1); - ctx->gop_size = avctx->gop_size; - ctx->p_per_i = INT_MAX; - ctx->b_per_p = 0; - } else { - if (ctx->p_to_gpb) - av_log(avctx, AV_LOG_VERBOSE, "Using intra and B-frames " - "(supported references: %d / %d).\n", - ref_l0, ref_l1); - else - av_log(avctx, AV_LOG_VERBOSE, "Using intra, P- and B-frames " - "(supported references: %d / %d).\n", ref_l0, ref_l1); - ctx->gop_size = avctx->gop_size; - ctx->p_per_i = INT_MAX; - ctx->b_per_p = avctx->max_b_frames; - if (ctx->codec->flags & FLAG_B_PICTURE_REFERENCES) { - ctx->max_b_depth = FFMIN(ctx->desired_b_depth, - av_log2(ctx->b_per_p) + 1); - } else { - ctx->max_b_depth = 1; - } - } - - if (ctx->codec->flags & FLAG_NON_IDR_KEY_PICTURES) { - ctx->closed_gop = !!(avctx->flags & AV_CODEC_FLAG_CLOSED_GOP); - ctx->gop_per_idr = ctx->idr_interval + 1; - } else { - ctx->closed_gop = 1; - ctx->gop_per_idr = 1; - } + err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1, + ctx->codec->flags, prediction_pre_only); + if (err < 0) + return err; return 0; } @@ -2414,6 +1756,7 @@ static av_cold int vaapi_encode_init_tile_slice_structure(AVCodecContext *avctx, static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeContext *ctx = avctx->priv_data; VAConfigAttrib attr[3] = { { VAConfigAttribEncMaxSlices }, { VAConfigAttribEncSliceStructure }, @@ -2425,7 +1768,7 @@ static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) uint32_t max_slices, slice_structure; int ret; - if (!(ctx->codec->flags & FLAG_SLICE_CONTROL)) { + if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL)) { if (avctx->slices > 0) { av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested " "but this codec does not support controlling slices.\n"); @@ -2433,12 +1776,12 @@ static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) return 0; } - av_assert0(ctx->slice_block_height > 0 && ctx->slice_block_width > 0); + av_assert0(base_ctx->slice_block_height > 0 && base_ctx->slice_block_width > 0); - ctx->slice_block_rows = (avctx->height + ctx->slice_block_height - 1) / - ctx->slice_block_height; - ctx->slice_block_cols = (avctx->width + ctx->slice_block_width - 1) / - ctx->slice_block_width; + ctx->slice_block_rows = (avctx->height + base_ctx->slice_block_height - 1) / + base_ctx->slice_block_height; + ctx->slice_block_cols = (avctx->width + base_ctx->slice_block_width - 1) / + base_ctx->slice_block_width; if (avctx->slices <= 1 && !ctx->tile_rows && !ctx->tile_cols) { ctx->nb_slices = 1; @@ -2613,7 +1956,8 @@ static av_cold int vaapi_encode_init_quality(AVCodecContext *avctx) static av_cold int vaapi_encode_init_roi(AVCodecContext *avctx) { #if VA_CHECK_VERSION(1, 0, 0) - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; VAConfigAttrib attr = { VAConfigAttribEncROI }; @@ -2628,14 +1972,14 @@ static av_cold int vaapi_encode_init_roi(AVCodecContext *avctx) } if (attr.value == VA_ATTRIB_NOT_SUPPORTED) { - ctx->roi_allowed = 0; + base_ctx->roi_allowed = 0; } else { VAConfigAttribValEncROI roi = { .value = attr.value, }; ctx->roi_max_regions = roi.bits.num_roi_regions; - ctx->roi_allowed = ctx->roi_max_regions > 0 && + base_ctx->roi_allowed = ctx->roi_max_regions > 0 && (ctx->va_rc_mode == VA_RC_CQP || roi.bits.roi_rc_qp_delta_support); } @@ -2659,7 +2003,8 @@ static void vaapi_encode_free_output_buffer(FFRefStructOpaque opaque, static int vaapi_encode_alloc_output_buffer(FFRefStructOpaque opaque, void *obj) { AVCodecContext *avctx = opaque.nc; - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; VABufferID *buffer_id = obj; VAStatus vas; @@ -2669,7 +2014,7 @@ static int vaapi_encode_alloc_output_buffer(FFRefStructOpaque opaque, void *obj) // bound on that. vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, VAEncCodedBufferType, - 3 * ctx->surface_width * ctx->surface_height + + 3 * base_ctx->surface_width * base_ctx->surface_height + (1 << 16), 1, 0, buffer_id); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create bitstream " @@ -2684,79 +2029,36 @@ static int vaapi_encode_alloc_output_buffer(FFRefStructOpaque opaque, void *obj) static av_cold int vaapi_encode_create_recon_frames(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; AVVAAPIHWConfig *hwconfig = NULL; - AVHWFramesConstraints *constraints = NULL; enum AVPixelFormat recon_format; - int err, i; + int err; - hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref); + hwconfig = av_hwdevice_hwconfig_alloc(base_ctx->device_ref); if (!hwconfig) { err = AVERROR(ENOMEM); goto fail; } hwconfig->config_id = ctx->va_config; - constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref, - hwconfig); - if (!constraints) { + err = ff_hw_base_get_recon_format(base_ctx, (const void*)hwconfig, &recon_format); + if (err < 0) + goto fail; + + base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref); + if (!base_ctx->recon_frames_ref) { err = AVERROR(ENOMEM); goto fail; } + base_ctx->recon_frames = (AVHWFramesContext*)base_ctx->recon_frames_ref->data; - // Probably we can use the input surface format as the surface format - // of the reconstructed frames. If not, we just pick the first (only?) - // format in the valid list and hope that it all works. - recon_format = AV_PIX_FMT_NONE; - if (constraints->valid_sw_formats) { - for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { - if (ctx->input_frames->sw_format == - constraints->valid_sw_formats[i]) { - recon_format = ctx->input_frames->sw_format; - break; - } - } - if (recon_format == AV_PIX_FMT_NONE) { - // No match. Just use the first in the supported list and - // hope for the best. - recon_format = constraints->valid_sw_formats[0]; - } - } else { - // No idea what to use; copy input format. - recon_format = ctx->input_frames->sw_format; - } - av_log(avctx, AV_LOG_DEBUG, "Using %s as format of " - "reconstructed frames.\n", av_get_pix_fmt_name(recon_format)); + base_ctx->recon_frames->format = AV_PIX_FMT_VAAPI; + base_ctx->recon_frames->sw_format = recon_format; + base_ctx->recon_frames->width = base_ctx->surface_width; + base_ctx->recon_frames->height = base_ctx->surface_height; - if (ctx->surface_width < constraints->min_width || - ctx->surface_height < constraints->min_height || - ctx->surface_width > constraints->max_width || - ctx->surface_height > constraints->max_height) { - av_log(avctx, AV_LOG_ERROR, "Hardware does not support encoding at " - "size %dx%d (constraints: width %d-%d height %d-%d).\n", - ctx->surface_width, ctx->surface_height, - constraints->min_width, constraints->max_width, - constraints->min_height, constraints->max_height); - err = AVERROR(EINVAL); - goto fail; - } - - av_freep(&hwconfig); - av_hwframe_constraints_free(&constraints); - - ctx->recon_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref); - if (!ctx->recon_frames_ref) { - err = AVERROR(ENOMEM); - goto fail; - } - ctx->recon_frames = (AVHWFramesContext*)ctx->recon_frames_ref->data; - - ctx->recon_frames->format = AV_PIX_FMT_VAAPI; - ctx->recon_frames->sw_format = recon_format; - ctx->recon_frames->width = ctx->surface_width; - ctx->recon_frames->height = ctx->surface_height; - - err = av_hwframe_ctx_init(ctx->recon_frames_ref); + err = av_hwframe_ctx_init(base_ctx->recon_frames_ref); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise reconstructed " "frame context: %d.\n", err); @@ -2766,53 +2068,44 @@ static av_cold int vaapi_encode_create_recon_frames(AVCodecContext *avctx) err = 0; fail: av_freep(&hwconfig); - av_hwframe_constraints_free(&constraints); return err; } +static const FFHWEncodePictureOperation vaapi_op = { + .priv_size = sizeof(VAAPIEncodePicture), + + .init = &vaapi_encode_init, + + .issue = &vaapi_encode_issue, + + .output = &vaapi_encode_output, + + .free = &vaapi_encode_free, +}; + +int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt) +{ + return ff_hw_base_encode_receive_packet(avctx->priv_data, avctx, pkt); +} + av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; AVVAAPIFramesContext *recon_hwctx = NULL; VAStatus vas; int err; + err = ff_hw_base_encode_init(avctx, base_ctx); + if (err < 0) + goto fail; + ctx->va_config = VA_INVALID_ID; ctx->va_context = VA_INVALID_ID; - /* If you add something that can fail above this av_frame_alloc(), - * modify ff_vaapi_encode_close() accordingly. */ - ctx->frame = av_frame_alloc(); - if (!ctx->frame) { - return AVERROR(ENOMEM); - } + base_ctx->op = &vaapi_op; - if (!avctx->hw_frames_ctx) { - av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " - "required to associate the encoding device.\n"); - return AVERROR(EINVAL); - } - - ctx->input_frames_ref = av_buffer_ref(avctx->hw_frames_ctx); - if (!ctx->input_frames_ref) { - err = AVERROR(ENOMEM); - goto fail; - } - ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data; - - ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref); - if (!ctx->device_ref) { - err = AVERROR(ENOMEM); - goto fail; - } - ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; - ctx->hwctx = ctx->device->hwctx; - - ctx->tail_pkt = av_packet_alloc(); - if (!ctx->tail_pkt) { - err = AVERROR(ENOMEM); - goto fail; - } + ctx->hwctx = base_ctx->device->hwctx; err = vaapi_encode_profile_entrypoint(avctx); if (err < 0) @@ -2824,11 +2117,11 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) goto fail; } else { // Assume 16x16 blocks. - ctx->surface_width = FFALIGN(avctx->width, 16); - ctx->surface_height = FFALIGN(avctx->height, 16); - if (ctx->codec->flags & FLAG_SLICE_CONTROL) { - ctx->slice_block_width = 16; - ctx->slice_block_height = 16; + base_ctx->surface_width = FFALIGN(avctx->width, 16); + base_ctx->surface_height = FFALIGN(avctx->height, 16); + if (ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) { + base_ctx->slice_block_width = 16; + base_ctx->slice_block_height = 16; } } @@ -2879,9 +2172,9 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) if (err < 0) goto fail; - recon_hwctx = ctx->recon_frames->hwctx; + recon_hwctx = base_ctx->recon_frames->hwctx; vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, - ctx->surface_width, ctx->surface_height, + base_ctx->surface_width, base_ctx->surface_height, VA_PROGRESSIVE, recon_hwctx->surface_ids, recon_hwctx->nb_surfaces, @@ -2908,8 +2201,8 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) goto fail; } - ctx->output_delay = ctx->b_per_p; - ctx->decode_delay = ctx->max_b_depth; + base_ctx->output_delay = base_ctx->b_per_p; + base_ctx->decode_delay = base_ctx->max_b_depth; if (ctx->codec->sequence_params_size > 0) { ctx->codec_sequence_params = @@ -2964,11 +2257,11 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) // check vaSyncBuffer function vas = vaSyncBuffer(ctx->hwctx->display, VA_INVALID_ID, 0); if (vas != VA_STATUS_ERROR_UNIMPLEMENTED) { - ctx->has_sync_buffer_func = 1; - ctx->encode_fifo = av_fifo_alloc2(ctx->async_depth, - sizeof(VAAPIEncodePicture *), - 0); - if (!ctx->encode_fifo) + base_ctx->async_encode = 1; + base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth, + sizeof(VAAPIEncodePicture*), + 0); + if (!base_ctx->encode_fifo) return AVERROR(ENOMEM); } #endif @@ -2981,15 +2274,16 @@ fail: av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic, *next; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodePicture *pic, *next; /* We check ctx->frame to know whether ff_vaapi_encode_init() * has been called and va_config/va_context initialized. */ - if (!ctx->frame) + if (!base_ctx->frame) return 0; - for (pic = ctx->pic_start; pic; pic = next) { + for (pic = base_ctx->pic_start; pic; pic = next) { next = pic->next; vaapi_encode_free(avctx, pic); } @@ -3008,16 +2302,10 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) ctx->va_config = VA_INVALID_ID; } - av_frame_free(&ctx->frame); - av_packet_free(&ctx->tail_pkt); - av_freep(&ctx->codec_sequence_params); av_freep(&ctx->codec_picture_params); - av_fifo_freep2(&ctx->encode_fifo); - av_buffer_unref(&ctx->recon_frames_ref); - av_buffer_unref(&ctx->input_frames_ref); - av_buffer_unref(&ctx->device_ref); + ff_hw_base_encode_close(base_ctx); return 0; } diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h index 0eed9691c..c4f85397a 100644 --- a/libavcodec/vaapi_encode.h +++ b/libavcodec/vaapi_encode.h @@ -29,38 +29,30 @@ #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_vaapi.h" -#include "libavutil/fifo.h" #include "avcodec.h" #include "hwconfig.h" +#include "hw_base_encode.h" struct VAAPIEncodeType; struct VAAPIEncodePicture; +// Codec output packet without timestamp delay, which means the +// output packet has same PTS and DTS. +#define FLAG_TIMESTAMP_NO_DELAY 1 << 6 + enum { MAX_CONFIG_ATTRIBUTES = 4, MAX_GLOBAL_PARAMS = 4, - MAX_DPB_SIZE = 16, - MAX_PICTURE_REFERENCES = 2, - MAX_REORDER_DELAY = 16, MAX_PARAM_BUFFER_SIZE = 1024, // A.4.1: table A.6 allows at most 22 tile rows for any level. MAX_TILE_ROWS = 22, // A.4.1: table A.6 allows at most 20 tile columns for any level. MAX_TILE_COLS = 20, - MAX_ASYNC_DEPTH = 64, - MAX_REFERENCE_LIST_NUM = 2, }; extern const AVCodecHWConfigInternal *const ff_vaapi_encode_hw_configs[]; -enum { - PICTURE_TYPE_IDR = 0, - PICTURE_TYPE_I = 1, - PICTURE_TYPE_P = 2, - PICTURE_TYPE_B = 3, -}; - typedef struct VAAPIEncodeSlice { int index; int row_start; @@ -71,17 +63,6 @@ typedef struct VAAPIEncodeSlice { } VAAPIEncodeSlice; typedef struct VAAPIEncodePicture { - struct VAAPIEncodePicture *next; - - int64_t display_order; - int64_t encode_order; - int64_t pts; - int64_t duration; - int force_idr; - - void *opaque; - AVBufferRef *opaque_ref; - #if VA_CHECK_VERSION(1, 0, 0) // ROI regions. VAEncROI *roi; @@ -89,15 +70,7 @@ typedef struct VAAPIEncodePicture { void *roi; #endif - int type; - int b_depth; - int encode_issued; - int encode_complete; - - AVFrame *input_image; VASurfaceID input_surface; - - AVFrame *recon_image; VASurfaceID recon_surface; int nb_param_buffers; @@ -107,31 +80,8 @@ typedef struct VAAPIEncodePicture { VABufferID *output_buffer_ref; VABufferID output_buffer; - void *priv_data; void *codec_picture_params; - // Whether this picture is a reference picture. - int is_reference; - - // The contents of the DPB after this picture has been decoded. - // This will contain the picture itself if it is a reference picture, - // but not if it isn't. - int nb_dpb_pics; - struct VAAPIEncodePicture *dpb[MAX_DPB_SIZE]; - // The reference pictures used in decoding this picture. If they are - // used by later pictures they will also appear in the DPB. ref[0][] for - // previous reference frames. ref[1][] for future reference frames. - int nb_refs[MAX_REFERENCE_LIST_NUM]; - struct VAAPIEncodePicture *refs[MAX_REFERENCE_LIST_NUM][MAX_PICTURE_REFERENCES]; - // The previous reference picture in encode order. Must be in at least - // one of the reference list and DPB list. - struct VAAPIEncodePicture *prev; - // Reference count for other pictures referring to this one through - // the above pointers, directly from incomplete pictures and indirectly - // through completed pictures. - int ref_count[2]; - int ref_removed[2]; - int nb_slices; VAAPIEncodeSlice *slices; @@ -193,22 +143,15 @@ typedef struct VAAPIEncodeRCMode { } VAAPIEncodeRCMode; typedef struct VAAPIEncodeContext { - const AVClass *class; + // Base context. + FFHWBaseEncodeContext base; // Codec-specific hooks. const struct VAAPIEncodeType *codec; - // Global options. - // Use low power encoding mode. int low_power; - // Number of I frames between IDR frames. - int idr_interval; - - // Desired B frame reference depth. - int desired_b_depth; - // Max Frame Size int max_frame_size; @@ -226,16 +169,6 @@ typedef struct VAAPIEncodeContext { // Desired packed headers. unsigned int desired_packed_headers; - // The required size of surfaces. This is probably the input - // size (AVCodecContext.width|height) aligned up to whatever - // block size is required by the codec. - int surface_width; - int surface_height; - - // The block size for slice calculations. - int slice_block_width; - int slice_block_height; - // Everything above this point must be set before calling // ff_vaapi_encode_init(). @@ -266,18 +199,8 @@ typedef struct VAAPIEncodeContext { VAConfigID va_config; VAContextID va_context; - AVBufferRef *device_ref; - AVHWDeviceContext *device; AVVAAPIDeviceContext *hwctx; - // The hardware frame context containing the input frames. - AVBufferRef *input_frames_ref; - AVHWFramesContext *input_frames; - - // The hardware frame context containing the reconstructed frames. - AVBufferRef *recon_frames_ref; - AVHWFramesContext *recon_frames; - // Pool of (reusable) bitstream output buffers. struct FFRefStructPool *output_buffer_pool; @@ -304,30 +227,6 @@ typedef struct VAAPIEncodeContext { // structure (VAEncPictureParameterBuffer*). void *codec_picture_params; - // Current encoding window, in display (input) order. - VAAPIEncodePicture *pic_start, *pic_end; - // The next picture to use as the previous reference picture in - // encoding order. Order from small to large in encoding order. - VAAPIEncodePicture *next_prev[MAX_PICTURE_REFERENCES]; - int nb_next_prev; - - // Next input order index (display order). - int64_t input_order; - // Number of frames that output is behind input. - int64_t output_delay; - // Next encode order index. - int64_t encode_order; - // Number of frames decode output will need to be delayed. - int64_t decode_delay; - // Next output order index (in encode order). - int64_t output_order; - - // Timestamp handling. - int64_t first_pts; - int64_t dts_pts_diff; - int64_t ts_ring[MAX_REORDER_DELAY * 3 + - MAX_ASYNC_DEPTH]; - // Slice structure. int slice_block_rows; int slice_block_cols; @@ -346,43 +245,12 @@ typedef struct VAAPIEncodeContext { // Location of the i-th tile row boundary. int row_bd[MAX_TILE_ROWS + 1]; - // Frame type decision. - int gop_size; - int closed_gop; - int gop_per_idr; - int p_per_i; - int max_b_depth; - int b_per_p; - int force_idr; - int idr_counter; - int gop_counter; - int end_of_stream; - int p_to_gpb; - - // Whether the driver supports ROI at all. - int roi_allowed; // Maximum number of regions supported by the driver. int roi_max_regions; // Quantisation range for offset calculations. Set by codec-specific // code, as it may change based on parameters. int roi_quant_range; - // The encoder does not support cropping information, so warn about - // it the first time we encounter any nonzero crop fields. - int crop_warned; - // If the driver does not support ROI then warn the first time we - // encounter a frame with ROI side data. - int roi_warned; - - AVFrame *frame; - - // Whether the driver support vaSyncBuffer - int has_sync_buffer_func; - // Store buffered pic - AVFifo *encode_fifo; - // Max number of frame buffered in encoder. - int async_depth; - /** Head data for current output pkt, used only for AV1. */ //void *header_data; //size_t header_data_size; @@ -392,30 +260,8 @@ typedef struct VAAPIEncodeContext { * This is a RefStruct reference. */ VABufferID *coded_buffer_ref; - - /** Tail data of a pic, now only used for av1 repeat frame header. */ - AVPacket *tail_pkt; } VAAPIEncodeContext; -enum { - // Codec supports controlling the subdivision of pictures into slices. - FLAG_SLICE_CONTROL = 1 << 0, - // Codec only supports constant quality (no rate control). - FLAG_CONSTANT_QUALITY_ONLY = 1 << 1, - // Codec is intra-only. - FLAG_INTRA_ONLY = 1 << 2, - // Codec supports B-pictures. - FLAG_B_PICTURES = 1 << 3, - // Codec supports referencing B-pictures. - FLAG_B_PICTURE_REFERENCES = 1 << 4, - // Codec supports non-IDR key pictures (that is, key pictures do - // not necessarily empty the DPB). - FLAG_NON_IDR_KEY_PICTURES = 1 << 5, - // Codec output packet without timestamp delay, which means the - // output packet has same PTS and DTS. - FLAG_TIMESTAMP_NO_DELAY = 1 << 6, -}; - typedef struct VAAPIEncodeType { // List of supported profiles and corresponding VAAPI profiles. // (Must end with AV_PROFILE_UNKNOWN.) @@ -453,9 +299,9 @@ typedef struct VAAPIEncodeType { // Fill the parameter structures. int (*init_sequence_params)(AVCodecContext *avctx); int (*init_picture_params)(AVCodecContext *avctx, - VAAPIEncodePicture *pic); + FFHWBaseEncodePicture *pic); int (*init_slice_params)(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *pic, VAAPIEncodeSlice *slice); // The type used by the packed header: this should look like @@ -470,7 +316,7 @@ typedef struct VAAPIEncodeType { int (*write_sequence_header)(AVCodecContext *avctx, char *data, size_t *data_len); int (*write_picture_header)(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *pic, char *data, size_t *data_len); int (*write_slice_header)(AVCodecContext *avctx, VAAPIEncodePicture *pic, @@ -482,7 +328,7 @@ typedef struct VAAPIEncodeType { // with increasing index argument until AVERROR_EOF is // returned. int (*write_extra_buffer)(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *pic, int index, int *type, char *data, size_t *data_len); @@ -490,12 +336,11 @@ typedef struct VAAPIEncodeType { // with increasing index argument until AVERROR_EOF is // returned. int (*write_extra_header)(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *pic, int index, int *type, char *data, size_t *data_len); } VAAPIEncodeType; - int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt); int ff_vaapi_encode_init(AVCodecContext *avctx); @@ -508,19 +353,6 @@ int ff_vaapi_encode_close(AVCodecContext *avctx); "may not support all encoding features)", \ OFFSET(common.low_power), AV_OPT_TYPE_BOOL, \ { .i64 = 0 }, 0, 1, FLAGS }, \ - { "idr_interval", \ - "Distance (in I-frames) between IDR frames", \ - OFFSET(common.idr_interval), AV_OPT_TYPE_INT, \ - { .i64 = 0 }, 0, INT_MAX, FLAGS }, \ - { "b_depth", \ - "Maximum B-frame reference depth", \ - OFFSET(common.desired_b_depth), AV_OPT_TYPE_INT, \ - { .i64 = 1 }, 1, INT_MAX, FLAGS }, \ - { "async_depth", "Maximum processing parallelism. " \ - "Increase this to improve single channel performance. This option " \ - "doesn't work if driver doesn't implement vaSyncBuffer function.", \ - OFFSET(common.async_depth), AV_OPT_TYPE_INT, \ - { .i64 = 2 }, 1, MAX_ASYNC_DEPTH, FLAGS }, \ { "max_frame_size", \ "Maximum frame size (in bytes)",\ OFFSET(common.max_frame_size), AV_OPT_TYPE_INT, \ diff --git a/libavcodec/vaapi_encode_av1.c b/libavcodec/vaapi_encode_av1.c index a46b882ab..1b350cd93 100644 --- a/libavcodec/vaapi_encode_av1.c +++ b/libavcodec/vaapi_encode_av1.c @@ -23,6 +23,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" +#include "libavutil/mastering_display_metadata.h" #include "cbs_av1.h" #include "put_bits.h" @@ -41,6 +42,8 @@ typedef struct VAAPIEncodeAV1Context { VAAPIEncodeContext common; AV1RawOBU sh; /**< sequence header.*/ AV1RawOBU fh; /**< frame header.*/ + AV1RawOBU mh[4]; /**< metadata header.*/ + int nb_mh; CodedBitstreamContext *cbc; CodedBitstreamFragment current_obu; VAConfigAttribValEncAV1 attr; @@ -109,12 +112,12 @@ static void vaapi_encode_av1_trace_write_log(void *ctx, static av_cold int vaapi_encode_av1_get_encoder_caps(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeAV1Context *priv = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeAV1Context *priv = avctx->priv_data; // Surfaces must be aligned to superblock boundaries. - ctx->surface_width = FFALIGN(avctx->width, priv->use_128x128_superblock ? 128 : 64); - ctx->surface_height = FFALIGN(avctx->height, priv->use_128x128_superblock ? 128 : 64); + base_ctx->surface_width = FFALIGN(avctx->width, priv->use_128x128_superblock ? 128 : 64); + base_ctx->surface_height = FFALIGN(avctx->height, priv->use_128x128_superblock ? 128 : 64); return 0; } @@ -155,6 +158,8 @@ static av_cold int vaapi_encode_av1_configure(AVCodecContext *avctx) priv->q_idx_idr = priv->q_idx_p = priv->q_idx_b = 128; } + ctx->roi_quant_range = AV1_MAX_QUANT; + return 0; } @@ -355,6 +360,7 @@ static int vaapi_encode_av1_write_sequence_header(AVCodecContext *avctx, static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeAV1Context *priv = avctx->priv_data; AV1RawOBU *sh_obu = &priv->sh; @@ -367,7 +373,7 @@ static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx) memset(sh_obu, 0, sizeof(*sh_obu)); sh_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER; - desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format); + desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); av_assert0(desc); sh->seq_profile = avctx->profile; @@ -419,7 +425,7 @@ static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx) framerate = 0; level = ff_av1_guess_level(avctx->bit_rate, priv->tier, - ctx->surface_width, ctx->surface_height, + base_ctx->surface_width, base_ctx->surface_height, priv->tile_rows * priv->tile_cols, priv->tile_cols, framerate); if (level) { @@ -436,8 +442,8 @@ static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx) vseq->seq_level_idx = sh->seq_level_idx[0]; vseq->seq_tier = sh->seq_tier[0]; vseq->order_hint_bits_minus_1 = sh->order_hint_bits_minus_1; - vseq->intra_period = ctx->gop_size; - vseq->ip_period = ctx->b_per_p + 1; + vseq->intra_period = base_ctx->gop_size; + vseq->ip_period = base_ctx->b_per_p + 1; vseq->seq_fields.bits.enable_order_hint = sh->enable_order_hint; @@ -460,16 +466,17 @@ end: } static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic) + FFHWBaseEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeAV1Context *priv = avctx->priv_data; - VAAPIEncodeAV1Picture *hpic = pic->priv_data; + VAAPIEncodePicture *vaapi_pic = pic->priv; + VAAPIEncodeAV1Picture *hpic = pic->codec_priv; AV1RawOBU *fh_obu = &priv->fh; AV1RawFrameHeader *fh = &fh_obu->obu.frame.header; - VAEncPictureParameterBufferAV1 *vpic = pic->codec_picture_params; + VAEncPictureParameterBufferAV1 *vpic = vaapi_pic->codec_picture_params; CodedBitstreamFragment *obu = &priv->current_obu; - VAAPIEncodePicture *ref; + FFHWBaseEncodePicture *ref; VAAPIEncodeAV1Picture *href; int slot, i; int ret; @@ -477,13 +484,13 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, { 1, 0, 0, 0, -1, 0, -1, -1 }; memset(fh_obu, 0, sizeof(*fh_obu)); - pic->nb_slices = priv->tile_groups; - pic->non_independent_frame = pic->encode_order < pic->display_order; + vaapi_pic->nb_slices = priv->tile_groups; + vaapi_pic->non_independent_frame = pic->encode_order < pic->display_order; fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER; fh_obu->header.obu_has_size_field = 1; switch (pic->type) { - case PICTURE_TYPE_IDR: + case FF_HW_PICTURE_TYPE_IDR: av_assert0(pic->nb_refs[0] == 0 || pic->nb_refs[1]); fh->frame_type = AV1_FRAME_KEY; fh->refresh_frame_flags = 0xFF; @@ -491,12 +498,12 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, hpic->slot = 0; hpic->last_idr_frame = pic->display_order; break; - case PICTURE_TYPE_P: + case FF_HW_PICTURE_TYPE_P: av_assert0(pic->nb_refs[0]); fh->frame_type = AV1_FRAME_INTER; fh->base_q_idx = priv->q_idx_p; ref = pic->refs[0][pic->nb_refs[0] - 1]; - href = ref->priv_data; + href = ref->codec_priv; hpic->slot = !href->slot; hpic->last_idr_frame = href->last_idr_frame; fh->refresh_frame_flags = 1 << hpic->slot; @@ -512,13 +519,13 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, /** 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->priv_data; + href = ref->codec_priv; 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; } break; - case PICTURE_TYPE_B: + case FF_HW_PICTURE_TYPE_B: av_assert0(pic->nb_refs[0] && pic->nb_refs[1]); fh->frame_type = AV1_FRAME_INTER; fh->base_q_idx = priv->q_idx_b; @@ -533,7 +540,7 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, vpic->ref_frame_ctrl_l1.fields.search_idx0 = AV1_REF_FRAME_BWDREF; ref = pic->refs[0][pic->nb_refs[0] - 1]; - href = ref->priv_data; + href = ref->codec_priv; hpic->last_idr_frame = href->last_idr_frame; fh->primary_ref_frame = href->slot; fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; @@ -542,7 +549,7 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, } ref = pic->refs[1][pic->nb_refs[1] - 1]; - href = ref->priv_data; + href = ref->codec_priv; fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame; for (i = AV1_REF_FRAME_GOLDEN; i < AV1_REFS_PER_FRAME; i++) { fh->ref_frame_idx[i] = href->slot; @@ -596,8 +603,8 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, vpic->frame_width_minus_1 = fh->frame_width_minus_1; vpic->frame_height_minus_1 = fh->frame_height_minus_1; vpic->primary_ref_frame = fh->primary_ref_frame; - vpic->reconstructed_frame = pic->recon_surface; - vpic->coded_buf = pic->output_buffer; + vpic->reconstructed_frame = vaapi_pic->recon_surface; + vpic->coded_buf = vaapi_pic->output_buffer; vpic->tile_cols = fh->tile_cols; vpic->tile_rows = fh->tile_rows; vpic->order_hint = fh->order_hint; @@ -625,12 +632,12 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) { for (int j = 0; j < pic->nb_refs[i]; j++) { - VAAPIEncodePicture *ref_pic = pic->refs[i][j]; + FFHWBaseEncodePicture *ref_pic = pic->refs[i][j]; - slot = ((VAAPIEncodeAV1Picture*)ref_pic->priv_data)->slot; + slot = ((VAAPIEncodeAV1Picture*)ref_pic->codec_priv)->slot; av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE); - vpic->reference_frames[slot] = ref_pic->recon_surface; + vpic->reference_frames[slot] = ((VAAPIEncodePicture *)ref_pic->priv)->recon_surface; } } @@ -651,19 +658,81 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, vpic->bit_offset_cdef_params = priv->cdef_start_offset; vpic->size_in_bits_cdef_params = priv->cdef_param_size; vpic->size_in_bits_frame_hdr_obu = priv->fh_data_len; - vpic->byte_offset_frame_hdr_obu_size = (((pic->type == PICTURE_TYPE_IDR) ? + vpic->byte_offset_frame_hdr_obu_size = (((pic->type == FF_HW_PICTURE_TYPE_IDR) ? priv->sh_data_len / 8 : 0) + (fh_obu->header.obu_extension_flag ? 2 : 1)); } + priv->nb_mh = 0; + + if (pic->type == FF_HW_PICTURE_TYPE_IDR) { + AVFrameSideData *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 = &priv->mh[priv->nb_mh++]; + 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 (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); + } + } + + sd = av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + if (sd) { + AVContentLightMetadata *cllm = (AVContentLightMetadata *)sd->data; + AV1RawOBU *obu = &priv->mh[priv->nb_mh++]; + 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; + } + } + end: ff_cbs_fragment_reset(obu); return ret; } static int vaapi_encode_av1_init_slice_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *base, VAAPIEncodeSlice *slice) { VAAPIEncodeAV1Context *priv = avctx->priv_data; @@ -685,7 +754,7 @@ static int vaapi_encode_av1_init_slice_params(AVCodecContext *avctx, } static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *pic, char *data, size_t *data_len) { VAAPIEncodeAV1Context *priv = avctx->priv_data; @@ -693,14 +762,15 @@ static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx, CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data; AV1RawOBU *fh_obu = &priv->fh; AV1RawFrameHeader *rep_fh = &fh_obu->obu.frame_header; + VAAPIEncodePicture *vaapi_pic = pic->priv; VAAPIEncodeAV1Picture *href; int ret = 0; - pic->tail_size = 0; + vaapi_pic->tail_size = 0; /** Pack repeat frame header. */ if (pic->display_order > pic->encode_order) { memset(fh_obu, 0, sizeof(*fh_obu)); - href = pic->refs[0][pic->nb_refs[0] - 1]->priv_data; + href = pic->refs[0][pic->nb_refs[0] - 1]->codec_priv; fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER; fh_obu->header.obu_has_size_field = 1; @@ -718,11 +788,11 @@ static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx, if (ret < 0) goto end; - ret = vaapi_encode_av1_write_obu(avctx, pic->tail_data, &pic->tail_size, obu); + ret = vaapi_encode_av1_write_obu(avctx, vaapi_pic->tail_data, &vaapi_pic->tail_size, obu); if (ret < 0) goto end; - pic->tail_size /= 8; + vaapi_pic->tail_size /= 8; } memcpy(data, &priv->fh_data, MAX_PARAM_BUFFER_SIZE * sizeof(char)); @@ -733,6 +803,39 @@ end: return ret; } +static int vaapi_encode_av1_write_extra_header(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + int index, int *type, + char *data, size_t *data_len) +{ + VAAPIEncodeAV1Context *priv = avctx->priv_data; + CodedBitstreamFragment *obu = &priv->current_obu; + AV1RawOBU *mh_obu; + char mh_data[MAX_PARAM_BUFFER_SIZE]; + size_t mh_data_len; + int ret = 0; + + if (index >= priv->nb_mh) + return AVERROR_EOF; + + mh_obu = &priv->mh[index]; + ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_METADATA, mh_obu); + if (ret < 0) + goto end; + + ret = vaapi_encode_av1_write_obu(avctx, mh_data, &mh_data_len, obu); + if (ret < 0) + goto end; + + memcpy(data, mh_data, MAX_PARAM_BUFFER_SIZE * sizeof(char)); + *data_len = mh_data_len; + *type = VAEncPackedHeaderRawData; + +end: + ff_cbs_fragment_reset(obu); + return ret; +} + static const VAAPIEncodeProfile vaapi_encode_av1_profiles[] = { { AV_PROFILE_AV1_MAIN, 8, 3, 1, 1, VAProfileAV1Profile0 }, { AV_PROFILE_AV1_MAIN, 10, 3, 1, 1, VAProfileAV1Profile0 }, @@ -741,7 +844,7 @@ static const VAAPIEncodeProfile vaapi_encode_av1_profiles[] = { static const VAAPIEncodeType vaapi_encode_type_av1 = { .profiles = vaapi_encode_av1_profiles, - .flags = FLAG_B_PICTURES | FLAG_TIMESTAMP_NO_DELAY, + .flags = FF_HW_FLAG_B_PICTURES | FLAG_TIMESTAMP_NO_DELAY, .default_quality = 25, .get_encoder_caps = &vaapi_encode_av1_get_encoder_caps, @@ -760,6 +863,8 @@ static const VAAPIEncodeType vaapi_encode_type_av1 = { .slice_params_size = sizeof(VAEncTileGroupBufferAV1), .init_slice_params = &vaapi_encode_av1_init_slice_params, + + .write_extra_header = &vaapi_encode_av1_write_extra_header, }; static av_cold int vaapi_encode_av1_init(AVCodecContext *avctx) @@ -774,7 +879,8 @@ static av_cold int vaapi_encode_av1_init(AVCodecContext *avctx) ctx->desired_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE | - VA_ENC_PACKED_HEADER_PICTURE; + VA_ENC_PACKED_HEADER_PICTURE | + VA_ENC_PACKED_HEADER_MISC; // Metadata if (avctx->profile == AV_PROFILE_UNKNOWN) avctx->profile = priv->profile; @@ -862,6 +968,7 @@ static av_cold int vaapi_encode_av1_close(AVCodecContext *avctx) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_av1_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_RC_OPTIONS, { "profile", "Set profile (seq_profile)", @@ -946,6 +1053,7 @@ const FFCodec ff_av1_vaapi_encoder = { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .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 37df9103a..ed20b9cd2 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -23,8 +23,8 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" -#include "libavutil/internal.h" #include "libavutil/opt.h" #include "atsc_a53.h" @@ -33,8 +33,8 @@ #include "cbs_h264.h" #include "codec_internal.h" #include "h264.h" +#include "hw_base_encode_h264.h" #include "h264_levels.h" -#include "h264_sei.h" #include "h2645data.h" #include "vaapi_encode.h" #include "version.h" @@ -68,6 +68,7 @@ typedef struct VAAPIEncodeH264Picture { typedef struct VAAPIEncodeH264Context { VAAPIEncodeContext common; + FFHWBaseEncodeH264 units; // User options. int qp; @@ -86,18 +87,13 @@ typedef struct VAAPIEncodeH264Context { int fixed_qp_p; int fixed_qp_b; - int dpb_frames; - // Writer structures. CodedBitstreamContext *cbc; CodedBitstreamFragment current_access_unit; H264RawAUD raw_aud; - H264RawSPS raw_sps; - H264RawPPS raw_pps; H264RawSlice raw_slice; - H264RawSEIBufferingPeriod sei_buffering_period; H264RawSEIPicTiming sei_pic_timing; H264RawSEIRecoveryPoint sei_recovery_point; SEIRawUserDataUnregistered sei_identifier; @@ -169,11 +165,11 @@ static int vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx, priv->aud_needed = 0; } - err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_sps); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->units.raw_sps); if (err < 0) goto fail; - err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_pps); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->units.raw_pps); if (err < 0) goto fail; @@ -210,7 +206,7 @@ fail: } static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *base, int index, int *type, char *data, size_t *data_len) { @@ -234,10 +230,10 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, goto fail; } if (priv->sei_needed & SEI_TIMING) { - if (pic->type == PICTURE_TYPE_IDR) { + if (base->type == FF_HW_PICTURE_TYPE_IDR) { err = ff_cbs_sei_add_message(priv->cbc, au, 1, SEI_TYPE_BUFFERING_PERIOD, - &priv->sei_buffering_period, NULL); + &priv->units.sei_buffering_period, NULL); if (err < 0) goto fail; } @@ -296,249 +292,36 @@ fail: static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH264Context *priv = avctx->priv_data; - H264RawSPS *sps = &priv->raw_sps; - H264RawPPS *pps = &priv->raw_pps; + H264RawSPS *sps = &priv->units.raw_sps; + H264RawPPS *pps = &priv->units.raw_pps; VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; VAEncPictureParameterBufferH264 *vpic = ctx->codec_picture_params; - const AVPixFmtDescriptor *desc; - int bit_depth; - memset(sps, 0, sizeof(*sps)); - memset(pps, 0, sizeof(*pps)); + FFHWBaseEncodeH264Opts unit_opts = { + .flags = (priv->sei & SEI_TIMING) ? FF_HW_H264_SEI_TIMING : 0, + .mb_width = priv->mb_width, + .mb_height = priv->mb_height, + .cabac = priv->coder, + .hrd_buffer_size = ctx->hrd_params.buffer_size, + .fixed_qp_idr = priv->fixed_qp_idr, + .initial_buffer_fullness = ctx->hrd_params.initial_buffer_fullness, + .bit_rate = ctx->va_bit_rate, + }; - desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format); - av_assert0(desc); - if (desc->nb_components == 1 || desc->log2_chroma_w != 1 || desc->log2_chroma_h != 1) { - 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; - - sps->nal_unit_header.nal_ref_idc = 3; - sps->nal_unit_header.nal_unit_type = H264_NAL_SPS; - - sps->profile_idc = avctx->profile & 0xff; - - if (avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE || - avctx->profile == AV_PROFILE_H264_MAIN) - sps->constraint_set1_flag = 1; - - if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10) - sps->constraint_set3_flag = ctx->gop_size == 1; - - if (avctx->profile == AV_PROFILE_H264_MAIN || - avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10) { - sps->constraint_set4_flag = 1; - sps->constraint_set5_flag = ctx->b_per_p == 0; - } - - if (ctx->gop_size == 1) - priv->dpb_frames = 0; - else - priv->dpb_frames = 1 + ctx->max_b_depth; - - if (avctx->level != AV_LEVEL_UNKNOWN) { - sps->level_idc = avctx->level; - } else { - const H264LevelDescriptor *level; - int framerate; - - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) - framerate = avctx->framerate.num / avctx->framerate.den; - else - framerate = 0; - - level = ff_h264_guess_level(sps->profile_idc, - avctx->bit_rate, - framerate, - priv->mb_width * 16, - priv->mb_height * 16, - priv->dpb_frames); - if (level) { - av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); - if (level->constraint_set3_flag) - sps->constraint_set3_flag = 1; - sps->level_idc = level->level_idc; - } else { - av_log(avctx, AV_LOG_WARNING, "Stream will not conform " - "to any level: using level 6.2.\n"); - sps->level_idc = 62; - } - } - - sps->seq_parameter_set_id = 0; - sps->chroma_format_idc = 1; - sps->bit_depth_luma_minus8 = bit_depth - 8; - sps->bit_depth_chroma_minus8 = bit_depth - 8; - - sps->log2_max_frame_num_minus4 = 4; - sps->pic_order_cnt_type = ctx->max_b_depth ? 0 : 2; - if (sps->pic_order_cnt_type == 0) { - sps->log2_max_pic_order_cnt_lsb_minus4 = 4; - } - - sps->max_num_ref_frames = priv->dpb_frames; - - sps->pic_width_in_mbs_minus1 = priv->mb_width - 1; - sps->pic_height_in_map_units_minus1 = priv->mb_height - 1; - - sps->frame_mbs_only_flag = 1; - sps->direct_8x8_inference_flag = 1; - - if (avctx->width != 16 * priv->mb_width || - avctx->height != 16 * priv->mb_height) { - sps->frame_cropping_flag = 1; - - sps->frame_crop_left_offset = 0; - sps->frame_crop_right_offset = - (16 * priv->mb_width - avctx->width) / 2; - sps->frame_crop_top_offset = 0; - sps->frame_crop_bottom_offset = - (16 * priv->mb_height - avctx->height) / 2; - } else { - sps->frame_cropping_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) { - sps->vui.aspect_ratio_idc = i; - break; - } - } - if (i >= FF_ARRAY_ELEMS(ff_h2645_pixel_aspect)) { - sps->vui.aspect_ratio_idc = 255; - sps->vui.sar_width = num; - sps->vui.sar_height = den; - } - sps->vui.aspect_ratio_info_present_flag = 1; - } - - // Unspecified video format, from table E-2. - sps->vui.video_format = 5; - sps->vui.video_full_range_flag = - avctx->color_range == AVCOL_RANGE_JPEG; - sps->vui.colour_primaries = avctx->color_primaries; - sps->vui.transfer_characteristics = avctx->color_trc; - sps->vui.matrix_coefficients = avctx->colorspace; - if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || - avctx->color_trc != AVCOL_TRC_UNSPECIFIED || - avctx->colorspace != AVCOL_SPC_UNSPECIFIED) - sps->vui.colour_description_present_flag = 1; - if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED || - sps->vui.colour_description_present_flag) - sps->vui.video_signal_type_present_flag = 1; - - if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) { - sps->vui.chroma_loc_info_present_flag = 1; - sps->vui.chroma_sample_loc_type_top_field = - sps->vui.chroma_sample_loc_type_bottom_field = - avctx->chroma_sample_location - 1; - } - - sps->vui.timing_info_present_flag = 1; - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { - sps->vui.num_units_in_tick = avctx->framerate.den; - sps->vui.time_scale = 2 * avctx->framerate.num; - sps->vui.fixed_frame_rate_flag = 1; - } else { - sps->vui.num_units_in_tick = avctx->time_base.num; - sps->vui.time_scale = 2 * avctx->time_base.den; - sps->vui.fixed_frame_rate_flag = 0; - } - - if (priv->sei & SEI_TIMING) { - H264RawHRD *hrd = &sps->vui.nal_hrd_parameters; - H264RawSEIBufferingPeriod *bp = &priv->sei_buffering_period; - - sps->vui.nal_hrd_parameters_present_flag = 1; - - hrd->cpb_cnt_minus1 = 0; - - // Try to scale these to a sensible range so that the - // golomb encode of the value is not overlong. - hrd->bit_rate_scale = - av_clip_uintp2(av_log2(ctx->va_bit_rate) - 15 - 6, 4); - hrd->bit_rate_value_minus1[0] = - (ctx->va_bit_rate >> hrd->bit_rate_scale + 6) - 1; - - hrd->cpb_size_scale = - av_clip_uintp2(av_log2(ctx->hrd_params.buffer_size) - 15 - 4, 4); - hrd->cpb_size_value_minus1[0] = - (ctx->hrd_params.buffer_size >> hrd->cpb_size_scale + 4) - 1; - - // CBR mode as defined for the HRD cannot be achieved without filler - // data, so this flag cannot be set even with VAAPI CBR modes. - hrd->cbr_flag[0] = 0; - - hrd->initial_cpb_removal_delay_length_minus1 = 23; - hrd->cpb_removal_delay_length_minus1 = 23; - hrd->dpb_output_delay_length_minus1 = 7; - hrd->time_offset_length = 0; - - bp->seq_parameter_set_id = sps->seq_parameter_set_id; - - // This calculation can easily overflow 32 bits. - bp->nal.initial_cpb_removal_delay[0] = 90000 * - (uint64_t)ctx->hrd_params.initial_buffer_fullness / - ctx->hrd_params.buffer_size; - bp->nal.initial_cpb_removal_delay_offset[0] = 0; - } else { - sps->vui.nal_hrd_parameters_present_flag = 0; - sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag; - } - - sps->vui.bitstream_restriction_flag = 1; - sps->vui.motion_vectors_over_pic_boundaries_flag = 1; - sps->vui.log2_max_mv_length_horizontal = 15; - sps->vui.log2_max_mv_length_vertical = 15; - sps->vui.max_num_reorder_frames = ctx->max_b_depth; - sps->vui.max_dec_frame_buffering = ctx->max_b_depth + 1; - - pps->nal_unit_header.nal_ref_idc = 3; - pps->nal_unit_header.nal_unit_type = H264_NAL_PPS; - - pps->pic_parameter_set_id = 0; - pps->seq_parameter_set_id = 0; - - pps->entropy_coding_mode_flag = - !(sps->profile_idc == AV_PROFILE_H264_BASELINE || - sps->profile_idc == AV_PROFILE_H264_EXTENDED || - sps->profile_idc == AV_PROFILE_H264_CAVLC_444); - if (!priv->coder && pps->entropy_coding_mode_flag) - pps->entropy_coding_mode_flag = 0; - - pps->num_ref_idx_l0_default_active_minus1 = 0; - pps->num_ref_idx_l1_default_active_minus1 = 0; - - pps->pic_init_qp_minus26 = priv->fixed_qp_idr - 26; - - if (sps->profile_idc == AV_PROFILE_H264_BASELINE || - sps->profile_idc == AV_PROFILE_H264_EXTENDED || - sps->profile_idc == AV_PROFILE_H264_MAIN) { - pps->more_rbsp_data = 0; - } else { - pps->more_rbsp_data = 1; - - pps->transform_8x8_mode_flag = 1; - } + int err = ff_hw_base_encode_init_params_h264(base_ctx, avctx, + &priv->units, &unit_opts); + if (err < 0) + return err; *vseq = (VAEncSequenceParameterBufferH264) { .seq_parameter_set_id = sps->seq_parameter_set_id, .level_idc = sps->level_idc, - .intra_period = ctx->gop_size, - .intra_idr_period = ctx->gop_size, - .ip_period = ctx->b_per_p + 1, + .intra_period = base_ctx->gop_size, + .intra_idr_period = base_ctx->gop_size, + .ip_period = base_ctx->b_per_p + 1, .bits_per_second = ctx->va_bit_rate, .max_num_ref_frames = sps->max_num_ref_frames, @@ -620,17 +403,21 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) } static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic) + FFHWBaseEncodePicture *pic) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; +#if !CONFIG_VAAPI_1 VAAPIEncodeContext *ctx = avctx->priv_data; +#endif VAAPIEncodeH264Context *priv = avctx->priv_data; - VAAPIEncodeH264Picture *hpic = pic->priv_data; - VAAPIEncodePicture *prev = pic->prev; - VAAPIEncodeH264Picture *hprev = prev ? prev->priv_data : NULL; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; + VAAPIEncodePicture *vaapi_pic = pic->priv; + VAAPIEncodeH264Picture *hpic = pic->codec_priv; + FFHWBaseEncodePicture *prev = pic->prev; + VAAPIEncodeH264Picture *hprev = prev ? prev->codec_priv : NULL; + VAEncPictureParameterBufferH264 *vpic = vaapi_pic->codec_picture_params; int i, j = 0; - if (pic->type == PICTURE_TYPE_IDR) { + if (pic->type == FF_HW_PICTURE_TYPE_IDR) { av_assert0(pic->display_order == pic->encode_order); hpic->frame_num = 0; @@ -647,10 +434,10 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, hpic->last_idr_frame = hprev->last_idr_frame; hpic->idr_pic_id = hprev->idr_pic_id; - if (pic->type == PICTURE_TYPE_I) { + if (pic->type == FF_HW_PICTURE_TYPE_I) { hpic->slice_type = 7; hpic->primary_pic_type = 0; - } else if (pic->type == PICTURE_TYPE_P) { + } else if (pic->type == FF_HW_PICTURE_TYPE_P) { hpic->slice_type = 5; hpic->primary_pic_type = 1; } else { @@ -659,11 +446,11 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, } } hpic->pic_order_cnt = pic->display_order - hpic->last_idr_frame; - if (priv->raw_sps.pic_order_cnt_type == 2) { + if (priv->units.raw_sps.pic_order_cnt_type == 2) { hpic->pic_order_cnt *= 2; } - hpic->dpb_delay = pic->display_order - pic->encode_order + ctx->max_b_depth; + hpic->dpb_delay = pic->display_order - pic->encode_order + base_ctx->max_b_depth; hpic->cpb_delay = pic->encode_order - hpic->last_idr_frame; if (priv->aud) { @@ -696,11 +483,11 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, priv->sei_needed |= SEI_TIMING; } - if (priv->sei & SEI_RECOVERY_POINT && pic->type == PICTURE_TYPE_I) { + if (priv->sei & SEI_RECOVERY_POINT && pic->type == FF_HW_PICTURE_TYPE_I) { priv->sei_recovery_point = (H264RawSEIRecoveryPoint) { .recovery_frame_cnt = 0, .exact_match_flag = 1, - .broken_link_flag = ctx->b_per_p > 0, + .broken_link_flag = base_ctx->b_per_p > 0, }; priv->sei_needed |= SEI_RECOVERY_POINT; @@ -723,7 +510,7 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, } vpic->CurrPic = (VAPictureH264) { - .picture_id = pic->recon_surface, + .picture_id = vaapi_pic->recon_surface, .frame_idx = hpic->frame_num, .flags = 0, .TopFieldOrderCnt = hpic->pic_order_cnt, @@ -731,14 +518,14 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, }; for (int k = 0; k < MAX_REFERENCE_LIST_NUM; k++) { for (i = 0; i < pic->nb_refs[k]; i++) { - VAAPIEncodePicture *ref = pic->refs[k][i]; + FFHWBaseEncodePicture *ref = pic->refs[k][i]; VAAPIEncodeH264Picture *href; av_assert0(ref && ref->encode_order < pic->encode_order); - href = ref->priv_data; + href = ref->codec_priv; vpic->ReferenceFrames[j++] = (VAPictureH264) { - .picture_id = ref->recon_surface, + .picture_id = ((VAAPIEncodePicture *)ref->priv)->recon_surface, .frame_idx = href->frame_num, .flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE, .TopFieldOrderCnt = href->pic_order_cnt, @@ -754,37 +541,37 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, }; } - vpic->coded_buf = pic->output_buffer; + vpic->coded_buf = vaapi_pic->output_buffer; vpic->frame_num = hpic->frame_num; - vpic->pic_fields.bits.idr_pic_flag = (pic->type == PICTURE_TYPE_IDR); - vpic->pic_fields.bits.reference_pic_flag = (pic->type != PICTURE_TYPE_B); + vpic->pic_fields.bits.idr_pic_flag = (pic->type == FF_HW_PICTURE_TYPE_IDR); + vpic->pic_fields.bits.reference_pic_flag = pic->is_reference; return 0; } static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx, - VAAPIEncodePicture *pic, - VAAPIEncodePicture **rpl0, - VAAPIEncodePicture **rpl1, + FFHWBaseEncodePicture *pic, + FFHWBaseEncodePicture **rpl0, + FFHWBaseEncodePicture **rpl1, int *rpl_size) { - VAAPIEncodePicture *prev; + FFHWBaseEncodePicture *prev; VAAPIEncodeH264Picture *hp, *hn, *hc; int i, j, n = 0; prev = pic->prev; av_assert0(prev); - hp = pic->priv_data; + hp = pic->codec_priv; for (i = 0; i < pic->prev->nb_dpb_pics; i++) { - hn = prev->dpb[i]->priv_data; + hn = prev->dpb[i]->codec_priv; av_assert0(hn->frame_num < hp->frame_num); - if (pic->type == PICTURE_TYPE_P) { + if (pic->type == FF_HW_PICTURE_TYPE_P) { for (j = n; j > 0; j--) { - hc = rpl0[j - 1]->priv_data; + hc = rpl0[j - 1]->codec_priv; av_assert0(hc->frame_num != hn->frame_num); if (hc->frame_num > hn->frame_num) break; @@ -792,9 +579,9 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx, } rpl0[j] = prev->dpb[i]; - } else if (pic->type == PICTURE_TYPE_B) { + } else if (pic->type == FF_HW_PICTURE_TYPE_B) { for (j = n; j > 0; j--) { - hc = rpl0[j - 1]->priv_data; + hc = rpl0[j - 1]->codec_priv; av_assert0(hc->pic_order_cnt != hp->pic_order_cnt); if (hc->pic_order_cnt < hp->pic_order_cnt) { if (hn->pic_order_cnt > hp->pic_order_cnt || @@ -809,7 +596,7 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx, rpl0[j] = prev->dpb[i]; for (j = n; j > 0; j--) { - hc = rpl1[j - 1]->priv_data; + hc = rpl1[j - 1]->codec_priv; av_assert0(hc->pic_order_cnt != hp->pic_order_cnt); if (hc->pic_order_cnt > hp->pic_order_cnt) { if (hn->pic_order_cnt < hp->pic_order_cnt || @@ -827,31 +614,31 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx, ++n; } - if (pic->type == PICTURE_TYPE_B) { + if (pic->type == FF_HW_PICTURE_TYPE_B) { for (i = 0; i < n; i++) { if (rpl0[i] != rpl1[i]) break; } if (i == n) - FFSWAP(VAAPIEncodePicture*, rpl1[0], rpl1[1]); + FFSWAP(FFHWBaseEncodePicture *, rpl1[0], rpl1[1]); } - if (pic->type == PICTURE_TYPE_P || - pic->type == PICTURE_TYPE_B) { + if (pic->type == FF_HW_PICTURE_TYPE_P || + pic->type == FF_HW_PICTURE_TYPE_B) { av_log(avctx, AV_LOG_DEBUG, "Default RefPicList0 for fn=%d/poc=%d:", hp->frame_num, hp->pic_order_cnt); for (i = 0; i < n; i++) { - hn = rpl0[i]->priv_data; + hn = rpl0[i]->codec_priv; av_log(avctx, AV_LOG_DEBUG, " fn=%d/poc=%d", hn->frame_num, hn->pic_order_cnt); } av_log(avctx, AV_LOG_DEBUG, "\n"); } - if (pic->type == PICTURE_TYPE_B) { + if (pic->type == FF_HW_PICTURE_TYPE_B) { av_log(avctx, AV_LOG_DEBUG, "Default RefPicList1 for fn=%d/poc=%d:", hp->frame_num, hp->pic_order_cnt); for (i = 0; i < n; i++) { - hn = rpl1[i]->priv_data; + hn = rpl1[i]->codec_priv; av_log(avctx, AV_LOG_DEBUG, " fn=%d/poc=%d", hn->frame_num, hn->pic_order_cnt); } @@ -862,20 +649,21 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx, } static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *pic, VAAPIEncodeSlice *slice) { VAAPIEncodeH264Context *priv = avctx->priv_data; - VAAPIEncodeH264Picture *hpic = pic->priv_data; - VAAPIEncodePicture *prev = pic->prev; - H264RawSPS *sps = &priv->raw_sps; - H264RawPPS *pps = &priv->raw_pps; + VAAPIEncodePicture *vaapi_pic = pic->priv; + VAAPIEncodeH264Picture *hpic = pic->codec_priv; + FFHWBaseEncodePicture *prev = pic->prev; + H264RawSPS *sps = &priv->units.raw_sps; + H264RawPPS *pps = &priv->units.raw_pps; H264RawSliceHeader *sh = &priv->raw_slice.header; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; + VAEncPictureParameterBufferH264 *vpic = vaapi_pic->codec_picture_params; VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; int i, j; - if (pic->type == PICTURE_TYPE_IDR) { + if (pic->type == FF_HW_PICTURE_TYPE_IDR) { sh->nal_unit_header.nal_unit_type = H264_NAL_IDR_SLICE; sh->nal_unit_header.nal_ref_idc = 3; } else { @@ -896,15 +684,15 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, sh->direct_spatial_mv_pred_flag = 1; - if (pic->type == PICTURE_TYPE_B) + if (pic->type == FF_HW_PICTURE_TYPE_B) sh->slice_qp_delta = priv->fixed_qp_b - (pps->pic_init_qp_minus26 + 26); - else if (pic->type == PICTURE_TYPE_P) + else if (pic->type == FF_HW_PICTURE_TYPE_P) sh->slice_qp_delta = priv->fixed_qp_p - (pps->pic_init_qp_minus26 + 26); else sh->slice_qp_delta = priv->fixed_qp_idr - (pps->pic_init_qp_minus26 + 26); - if (pic->is_reference && pic->type != PICTURE_TYPE_IDR) { - VAAPIEncodePicture *discard_list[MAX_DPB_SIZE]; + if (pic->is_reference && pic->type != FF_HW_PICTURE_TYPE_IDR) { + FFHWBaseEncodePicture *discard_list[MAX_DPB_SIZE]; int discard = 0, keep = 0; // Discard everything which is in the DPB of the previous frame but @@ -921,14 +709,14 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, ++keep; } } - av_assert0(keep <= priv->dpb_frames); + av_assert0(keep <= priv->units.dpb_frames); if (discard == 0) { sh->adaptive_ref_pic_marking_mode_flag = 0; } else { sh->adaptive_ref_pic_marking_mode_flag = 1; for (i = 0; i < discard; i++) { - VAAPIEncodeH264Picture *old = discard_list[i]->priv_data; + VAAPIEncodeH264Picture *old = discard_list[i]->codec_priv; av_assert0(old->frame_num < hpic->frame_num); sh->mmco[i].memory_management_control_operation = 1; sh->mmco[i].difference_of_pic_nums_minus1 = @@ -940,19 +728,19 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, // If the intended references are not the first entries of RefPicListN // by default, use ref-pic-list-modification to move them there. - if (pic->type == PICTURE_TYPE_P || pic->type == PICTURE_TYPE_B) { - VAAPIEncodePicture *def_l0[MAX_DPB_SIZE], *def_l1[MAX_DPB_SIZE]; + if (pic->type == FF_HW_PICTURE_TYPE_P || pic->type == FF_HW_PICTURE_TYPE_B) { + FFHWBaseEncodePicture *def_l0[MAX_DPB_SIZE], *def_l1[MAX_DPB_SIZE]; VAAPIEncodeH264Picture *href; int n; vaapi_encode_h264_default_ref_pic_list(avctx, pic, def_l0, def_l1, &n); - if (pic->type == PICTURE_TYPE_P) { + if (pic->type == FF_HW_PICTURE_TYPE_P) { int need_rplm = 0; for (i = 0; i < pic->nb_refs[0]; i++) { av_assert0(pic->refs[0][i]); - if (pic->refs[0][i] != def_l0[i]) + if (pic->refs[0][i] != (FFHWBaseEncodePicture *)def_l0[i]) need_rplm = 1; } @@ -960,7 +748,7 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, if (need_rplm) { int pic_num = hpic->frame_num; for (i = 0; i < pic->nb_refs[0]; i++) { - href = pic->refs[0][i]->priv_data; + href = pic->refs[0][i]->codec_priv; av_assert0(href->frame_num != pic_num); if (href->frame_num < pic_num) { sh->rplm_l0[i].modification_of_pic_nums_idc = 0; @@ -981,18 +769,18 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, int n0 = 0, n1 = 0; for (i = 0; i < pic->nb_refs[0]; i++) { av_assert0(pic->refs[0][i]); - href = pic->refs[0][i]->priv_data; + href = pic->refs[0][i]->codec_priv; av_assert0(href->pic_order_cnt < hpic->pic_order_cnt); - if (pic->refs[0][i] != def_l0[n0]) + if (pic->refs[0][i] != (FFHWBaseEncodePicture *)def_l0[n0]) need_rplm_l0 = 1; ++n0; } for (i = 0; i < pic->nb_refs[1]; i++) { av_assert0(pic->refs[1][i]); - href = pic->refs[1][i]->priv_data; + href = pic->refs[1][i]->codec_priv; av_assert0(href->pic_order_cnt > hpic->pic_order_cnt); - if (pic->refs[1][i] != def_l1[n1]) + if (pic->refs[1][i] != (FFHWBaseEncodePicture *)def_l1[n1]) need_rplm_l1 = 1; ++n1; } @@ -1001,7 +789,7 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, if (need_rplm_l0) { int pic_num = hpic->frame_num; for (i = j = 0; i < pic->nb_refs[0]; i++) { - href = pic->refs[0][i]->priv_data; + href = pic->refs[0][i]->codec_priv; av_assert0(href->frame_num != pic_num); if (href->frame_num < pic_num) { sh->rplm_l0[j].modification_of_pic_nums_idc = 0; @@ -1023,7 +811,7 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, if (need_rplm_l1) { int pic_num = hpic->frame_num; for (i = j = 0; i < pic->nb_refs[1]; i++) { - href = pic->refs[1][i]->priv_data; + href = pic->refs[1][i]->codec_priv; av_assert0(href->frame_num != pic_num); if (href->frame_num < pic_num) { sh->rplm_l1[j].modification_of_pic_nums_idc = 0; @@ -1065,13 +853,13 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, if (pic->nb_refs[0]) { // Backward reference for P- or B-frame. - av_assert0(pic->type == PICTURE_TYPE_P || - pic->type == PICTURE_TYPE_B); + av_assert0(pic->type == FF_HW_PICTURE_TYPE_P || + pic->type == FF_HW_PICTURE_TYPE_B); vslice->RefPicList0[0] = vpic->ReferenceFrames[0]; } if (pic->nb_refs[1]) { // Forward reference for B-frame. - av_assert0(pic->type == PICTURE_TYPE_B); + av_assert0(pic->type == FF_HW_PICTURE_TYPE_B); vslice->RefPicList1[0] = vpic->ReferenceFrames[1]; } @@ -1171,10 +959,10 @@ static const VAAPIEncodeProfile vaapi_encode_h264_profiles[] = { static const VAAPIEncodeType vaapi_encode_type_h264 = { .profiles = vaapi_encode_h264_profiles, - .flags = FLAG_SLICE_CONTROL | - FLAG_B_PICTURES | - FLAG_B_PICTURE_REFERENCES | - FLAG_NON_IDR_KEY_PICTURES, + .flags = FF_HW_FLAG_SLICE_CONTROL | + FF_HW_FLAG_B_PICTURES | + FF_HW_FLAG_B_PICTURE_REFERENCES | + FF_HW_FLAG_NON_IDR_KEY_PICTURES, .default_quality = 20, @@ -1202,8 +990,9 @@ static const VAAPIEncodeType vaapi_encode_type_h264 = { static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = avctx->priv_data; ctx->codec = &vaapi_encode_type_h264; @@ -1251,10 +1040,10 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) VA_ENC_PACKED_HEADER_SLICE | // Slice headers. VA_ENC_PACKED_HEADER_MISC; // SEI. - ctx->surface_width = FFALIGN(avctx->width, 16); - ctx->surface_height = FFALIGN(avctx->height, 16); + base_ctx->surface_width = FFALIGN(avctx->width, 16); + base_ctx->surface_height = FFALIGN(avctx->height, 16); - ctx->slice_block_height = ctx->slice_block_width = 16; + base_ctx->slice_block_height = base_ctx->slice_block_width = 16; if (priv->qp > 0) ctx->explicit_qp = priv->qp; @@ -1277,6 +1066,7 @@ static av_cold int vaapi_encode_h264_close(AVCodecContext *avctx) #define OFFSET(x) offsetof(VAAPIEncodeH264Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_h264_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_RC_OPTIONS, @@ -1392,6 +1182,7 @@ const FFCodec ff_h264_vaapi_encoder = { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .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 c4aabbf5e..2283bcc0b 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -23,6 +23,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "libavutil/mastering_display_metadata.h" @@ -31,14 +32,14 @@ #include "avcodec.h" #include "cbs.h" #include "cbs_h265.h" +#include "hw_base_encode_h265.h" #include "codec_internal.h" #include "h2645data.h" #include "h265_profile_level.h" -#include "hevc.h" -#include "hevc_sei.h" -#include "put_bits.h" #include "vaapi_encode.h" +#include "hevc/hevc.h" + enum { SEI_MASTERING_DISPLAY = 0x08, SEI_CONTENT_LIGHT_LEVEL = 0x10, @@ -69,20 +70,17 @@ typedef struct VAAPIEncodeH265Context { int qp; int aud; int profile; - int tier; int level; int sei; // Derived settings. - int fixed_qp_idr; int fixed_qp_p; int fixed_qp_b; // Writer structures. + FFHWBaseEncodeH265 units; + FFHWBaseEncodeH265Opts unit_opts; H265RawAUD raw_aud; - H265RawVPS raw_vps; - H265RawSPS raw_sps; - H265RawPPS raw_pps; H265RawSlice raw_slice; SEIRawMasteringDisplayColourVolume sei_mastering_display; @@ -155,15 +153,15 @@ static int vaapi_encode_h265_write_sequence_header(AVCodecContext *avctx, priv->aud_needed = 0; } - err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_vps); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->units.raw_vps); if (err < 0) goto fail; - err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_sps); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->units.raw_sps); if (err < 0) goto fail; - err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_pps); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->units.raw_pps); if (err < 0) goto fail; @@ -200,7 +198,7 @@ fail: } static int vaapi_encode_h265_write_extra_header(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *base, int index, int *type, char *data, size_t *data_len) { @@ -260,210 +258,36 @@ fail: static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = avctx->priv_data; - 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; + H265RawVPS *vps = &priv->units.raw_vps; + H265RawSPS *sps = &priv->units.raw_sps; + H265RawPPS *pps = &priv->units.raw_pps; VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; - const AVPixFmtDescriptor *desc; - int chroma_format, bit_depth; - int i; + int i, err; - memset(vps, 0, sizeof(*vps)); - memset(sps, 0, sizeof(*sps)); - memset(pps, 0, sizeof(*pps)); + // priv->unit_opts.tier already set + // priv->unit_opts.fixed_qp_idr already set + priv->unit_opts.cu_qp_delta_enabled_flag = (ctx->va_rc_mode != VA_RC_CQP); + priv->unit_opts.tile_rows = ctx->tile_rows; + priv->unit_opts.tile_cols = ctx->tile_cols; + priv->unit_opts.nb_slices = ctx->nb_slices; + priv->unit_opts.slice_block_rows = ctx->slice_block_rows; + priv->unit_opts.slice_block_cols = ctx->slice_block_cols; + memcpy(priv->unit_opts.col_width, ctx->col_width, + ctx->tile_rows*sizeof(*priv->unit_opts.col_width)); + memcpy(priv->unit_opts.row_height, ctx->row_height, + ctx->tile_cols*sizeof(*priv->unit_opts.row_height)); + err = ff_hw_base_encode_init_params_h265(base_ctx, avctx, + &priv->units, &priv->unit_opts); + if (err < 0) + return err; - desc = av_pix_fmt_desc_get(priv->common.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; - - - // VPS - - vps->nal_unit_header = (H265RawNALUnitHeader) { - .nal_unit_type = HEVC_NAL_VPS, - .nuh_layer_id = 0, - .nuh_temporal_id_plus1 = 1, - }; - - 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; - - if (ptl->general_profile_compatibility_flag[1]) - ptl->general_profile_compatibility_flag[2] = 1; - if (ptl->general_profile_compatibility_flag[3]) { - ptl->general_profile_compatibility_flag[1] = 1; - ptl->general_profile_compatibility_flag[2] = 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 = ctx->gop_size == 1; - ptl->general_one_picture_only_constraint_flag = 0; - - ptl->general_lower_bit_rate_constraint_flag = 1; - - if (avctx->level != AV_LEVEL_UNKNOWN) { - ptl->general_level_idc = avctx->level; - } else { - const H265LevelDescriptor *level; - - level = ff_h265_guess_level(ptl, avctx->bit_rate, - ctx->surface_width, ctx->surface_height, - ctx->nb_slices, ctx->tile_rows, ctx->tile_cols, - (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; - } - } - - vps->vps_sub_layer_ordering_info_present_flag = 0; - vps->vps_max_dec_pic_buffering_minus1[0] = ctx->max_b_depth + 1; - vps->vps_max_num_reorder_pics[0] = 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; - - sps->pic_width_in_luma_samples = ctx->surface_width; - sps->pic_height_in_luma_samples = ctx->surface_height; - - if (avctx->width != ctx->surface_width || - avctx->height != ctx->surface_height) { - sps->conformance_window_flag = 1; - sps->conf_win_left_offset = 0; - sps->conf_win_right_offset = - (ctx->surface_width - avctx->width) >> desc->log2_chroma_w; - sps->conf_win_top_offset = 0; - sps->conf_win_bottom_offset = - (ctx->surface_height - avctx->height) >> desc->log2_chroma_h; - } else { - 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 = 8; - - 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]; - } - - // These values come from the capabilities of the first encoder - // implementation in the i965 driver on Intel Skylake. They may - // fail badly with other platforms or drivers. - // CTB size from 8x8 to 32x32. - sps->log2_min_luma_coding_block_size_minus3 = 0; - sps->log2_diff_max_min_luma_coding_block_size = 2; - // Transform size from 4x4 to 32x32. - sps->log2_min_luma_transform_block_size_minus2 = 0; - sps->log2_diff_max_min_luma_transform_block_size = 3; - // Full transform hierarchy allowed (2-5). - sps->max_transform_hierarchy_depth_inter = 3; - sps->max_transform_hierarchy_depth_intra = 3; - // AMP works. - sps->amp_enabled_flag = 1; - // SAO and temporal MVP do not work. - sps->sample_adaptive_offset_enabled_flag = 0; - sps->sps_temporal_mvp_enabled_flag = 0; - - sps->pcm_enabled_flag = 0; - -// update sps setting according to queried result #if VA_CHECK_VERSION(1, 13, 0) + // update sps setting according to queried result if (priv->va_features) { VAConfigAttribValEncHEVCFeatures features = { .value = priv->va_features }; @@ -496,95 +320,8 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) sps->max_transform_hierarchy_depth_intra = bs.bits.max_max_transform_hierarchy_depth_intra; } -#endif - // STRPSs should ideally be here rather than defined individually in - // each slice, but the structure isn't completely fixed so for now - // don't bother. - sps->num_short_term_ref_pic_sets = 0; - sps->long_term_ref_pics_present_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->num_ref_idx_l0_default_active_minus1 = 0; - pps->num_ref_idx_l1_default_active_minus1 = 0; - - pps->init_qp_minus26 = priv->fixed_qp_idr - 26; - - pps->cu_qp_delta_enabled_flag = (ctx->va_rc_mode != VA_RC_CQP); - pps->diff_cu_qp_delta_depth = 0; - -// update pps setting according to queried result -#if VA_CHECK_VERSION(1, 13, 0) + // update pps setting according to queried result if (priv->va_features) { VAConfigAttribValEncHEVCFeatures features = { .value = priv->va_features }; if (ctx->va_rc_mode != VA_RC_CQP) @@ -600,42 +337,6 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) } #endif - if (ctx->tile_rows && ctx->tile_cols) { - int uniform_spacing; - - pps->tiles_enabled_flag = 1; - pps->num_tile_columns_minus1 = ctx->tile_cols - 1; - pps->num_tile_rows_minus1 = ctx->tile_rows - 1; - - // Test whether the spacing provided matches the H.265 uniform - // spacing, and set the flag if it does. - uniform_spacing = 1; - for (i = 0; i <= pps->num_tile_columns_minus1 && - uniform_spacing; i++) { - if (ctx->col_width[i] != - (i + 1) * ctx->slice_block_cols / ctx->tile_cols - - i * ctx->slice_block_cols / ctx->tile_cols) - uniform_spacing = 0; - } - for (i = 0; i <= pps->num_tile_rows_minus1 && - uniform_spacing; i++) { - if (ctx->row_height[i] != - (i + 1) * ctx->slice_block_rows / ctx->tile_rows - - i * ctx->slice_block_rows / ctx->tile_rows) - uniform_spacing = 0; - } - pps->uniform_spacing_flag = uniform_spacing; - - for (i = 0; i <= pps->num_tile_columns_minus1; i++) - pps->column_width_minus1[i] = ctx->col_width[i] - 1; - for (i = 0; i <= pps->num_tile_rows_minus1; i++) - pps->row_height_minus1[i] = ctx->row_height[i] - 1; - - pps->loop_filter_across_tiles_enabled_flag = 1; - } - - pps->pps_loop_filter_across_slices_enabled_flag = 1; - // Fill VAAPI parameter buffers. *vseq = (VAEncSequenceParameterBufferHEVC) { @@ -643,9 +344,9 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) .general_level_idc = vps->profile_tier_level.general_level_idc, .general_tier_flag = vps->profile_tier_level.general_tier_flag, - .intra_period = ctx->gop_size, - .intra_idr_period = ctx->gop_size, - .ip_period = ctx->b_per_p + 1, + .intra_period = base_ctx->gop_size, + .intra_idr_period = base_ctx->gop_size, + .ip_period = base_ctx->b_per_p + 1, .bits_per_second = ctx->va_bit_rate, .pic_width_in_luma_samples = sps->pic_width_in_luma_samples, @@ -756,17 +457,18 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) } static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic) + FFHWBaseEncodePicture *pic) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = avctx->priv_data; - VAAPIEncodeH265Picture *hpic = pic->priv_data; - VAAPIEncodePicture *prev = pic->prev; - VAAPIEncodeH265Picture *hprev = prev ? prev->priv_data : NULL; - VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; + VAAPIEncodePicture *vaapi_pic = pic->priv; + VAAPIEncodeH265Picture *hpic = pic->codec_priv; + FFHWBaseEncodePicture *prev = pic->prev; + VAAPIEncodeH265Picture *hprev = prev ? prev->codec_priv : NULL; + VAEncPictureParameterBufferHEVC *vpic = vaapi_pic->codec_picture_params; int i, j = 0; - if (pic->type == PICTURE_TYPE_IDR) { + if (pic->type == FF_HW_PICTURE_TYPE_IDR) { av_assert0(pic->display_order == pic->encode_order); hpic->last_idr_frame = pic->display_order; @@ -778,23 +480,23 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, av_assert0(prev); hpic->last_idr_frame = hprev->last_idr_frame; - if (pic->type == PICTURE_TYPE_I) { + if (pic->type == FF_HW_PICTURE_TYPE_I) { hpic->slice_nal_unit = HEVC_NAL_CRA_NUT; hpic->slice_type = HEVC_SLICE_I; hpic->pic_type = 0; - } else if (pic->type == PICTURE_TYPE_P) { + } else if (pic->type == FF_HW_PICTURE_TYPE_P) { av_assert0(pic->refs[0]); hpic->slice_nal_unit = HEVC_NAL_TRAIL_R; hpic->slice_type = HEVC_SLICE_P; hpic->pic_type = 1; } else { - VAAPIEncodePicture *irap_ref; + FFHWBaseEncodePicture *irap_ref; av_assert0(pic->refs[0][0] && pic->refs[1][0]); for (irap_ref = pic; irap_ref; irap_ref = irap_ref->refs[1][0]) { - if (irap_ref->type == PICTURE_TYPE_I) + if (irap_ref->type == FF_HW_PICTURE_TYPE_I) break; } - if (pic->b_depth == ctx->max_b_depth) { + if (pic->b_depth == base_ctx->max_b_depth) { hpic->slice_nal_unit = irap_ref ? HEVC_NAL_RASL_N : HEVC_NAL_TRAIL_N; } else { @@ -827,7 +529,7 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, // may force an IDR frame on the output where the medadata gets // changed on the input frame. if ((priv->sei & SEI_MASTERING_DISPLAY) && - (pic->type == PICTURE_TYPE_I || pic->type == PICTURE_TYPE_IDR)) { + (pic->type == FF_HW_PICTURE_TYPE_I || pic->type == FF_HW_PICTURE_TYPE_IDR)) { AVFrameSideData *sd = av_frame_get_side_data(pic->input_image, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); @@ -875,7 +577,7 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, } if ((priv->sei & SEI_CONTENT_LIGHT_LEVEL) && - (pic->type == PICTURE_TYPE_I || pic->type == PICTURE_TYPE_IDR)) { + (pic->type == FF_HW_PICTURE_TYPE_I || pic->type == FF_HW_PICTURE_TYPE_IDR)) { AVFrameSideData *sd = av_frame_get_side_data(pic->input_image, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); @@ -910,21 +612,21 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, } vpic->decoded_curr_pic = (VAPictureHEVC) { - .picture_id = pic->recon_surface, + .picture_id = vaapi_pic->recon_surface, .pic_order_cnt = hpic->pic_order_cnt, .flags = 0, }; for (int k = 0; k < MAX_REFERENCE_LIST_NUM; k++) { for (i = 0; i < pic->nb_refs[k]; i++) { - VAAPIEncodePicture *ref = pic->refs[k][i]; + FFHWBaseEncodePicture *ref = pic->refs[k][i]; VAAPIEncodeH265Picture *href; av_assert0(ref && ref->encode_order < pic->encode_order); - href = ref->priv_data; + href = ref->codec_priv; vpic->reference_frames[j++] = (VAPictureHEVC) { - .picture_id = ref->recon_surface, + .picture_id = ((VAAPIEncodePicture *)ref->priv)->recon_surface, .pic_order_cnt = href->pic_order_cnt, .flags = (ref->display_order < pic->display_order ? VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) | @@ -941,30 +643,27 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, }; } - vpic->coded_buf = pic->output_buffer; + vpic->coded_buf = vaapi_pic->output_buffer; vpic->nal_unit_type = hpic->slice_nal_unit; + vpic->pic_fields.bits.reference_pic_flag = pic->is_reference; switch (pic->type) { - case PICTURE_TYPE_IDR: + case FF_HW_PICTURE_TYPE_IDR: vpic->pic_fields.bits.idr_pic_flag = 1; vpic->pic_fields.bits.coding_type = 1; - vpic->pic_fields.bits.reference_pic_flag = 1; break; - case PICTURE_TYPE_I: + case FF_HW_PICTURE_TYPE_I: vpic->pic_fields.bits.idr_pic_flag = 0; vpic->pic_fields.bits.coding_type = 1; - vpic->pic_fields.bits.reference_pic_flag = 1; break; - case PICTURE_TYPE_P: + case FF_HW_PICTURE_TYPE_P: vpic->pic_fields.bits.idr_pic_flag = 0; vpic->pic_fields.bits.coding_type = 2; - vpic->pic_fields.bits.reference_pic_flag = 1; break; - case PICTURE_TYPE_B: + case FF_HW_PICTURE_TYPE_B: vpic->pic_fields.bits.idr_pic_flag = 0; vpic->pic_fields.bits.coding_type = 3; - vpic->pic_fields.bits.reference_pic_flag = 0; break; default: av_assert0(0 && "invalid picture type"); @@ -974,16 +673,17 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, } static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *pic, VAAPIEncodeSlice *slice) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = avctx->priv_data; - VAAPIEncodeH265Picture *hpic = pic->priv_data; - const H265RawSPS *sps = &priv->raw_sps; - const H265RawPPS *pps = &priv->raw_pps; + VAAPIEncodePicture *vaapi_pic = pic->priv; + VAAPIEncodeH265Picture *hpic = pic->codec_priv; + const H265RawSPS *sps = &priv->units.raw_sps; + const H265RawPPS *pps = &priv->units.raw_pps; H265RawSliceHeader *sh = &priv->raw_slice.header; - VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; + VAEncPictureParameterBufferHEVC *vpic = vaapi_pic->codec_picture_params; VAEncSliceParameterBufferHEVC *vslice = slice->codec_slice_params; int i; @@ -1000,13 +700,13 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, sh->slice_type = hpic->slice_type; - if (sh->slice_type == HEVC_SLICE_P && ctx->p_to_gpb) + if (sh->slice_type == HEVC_SLICE_P && base_ctx->p_to_gpb) sh->slice_type = HEVC_SLICE_B; sh->slice_pic_order_cnt_lsb = hpic->pic_order_cnt & (1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1; - if (pic->type != PICTURE_TYPE_IDR) { + if (pic->type != FF_HW_PICTURE_TYPE_IDR) { H265RawSTRefPicSet *rps; const VAAPIEncodeH265Picture *strp; int rps_poc[MAX_DPB_SIZE]; @@ -1021,7 +721,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, rps_pics = 0; for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) { for (j = 0; j < pic->nb_refs[i]; j++) { - strp = pic->refs[i][j]->priv_data; + strp = pic->refs[i][j]->codec_priv; rps_poc[rps_pics] = strp->pic_order_cnt; rps_used[rps_pics] = 1; ++rps_pics; @@ -1046,7 +746,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, if (j < pic->nb_refs[1]) continue; - strp = pic->dpb[i]->priv_data; + strp = pic->dpb[i]->codec_priv; rps_poc[rps_pics] = strp->pic_order_cnt; rps_used[rps_pics] = 0; ++rps_pics; @@ -1113,12 +813,12 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, sh->slice_sao_luma_flag = sh->slice_sao_chroma_flag = sps->sample_adaptive_offset_enabled_flag; - if (pic->type == PICTURE_TYPE_B) + if (pic->type == FF_HW_PICTURE_TYPE_B) sh->slice_qp_delta = priv->fixed_qp_b - (pps->init_qp_minus26 + 26); - else if (pic->type == PICTURE_TYPE_P) + else if (pic->type == FF_HW_PICTURE_TYPE_P) sh->slice_qp_delta = priv->fixed_qp_p - (pps->init_qp_minus26 + 26); else - sh->slice_qp_delta = priv->fixed_qp_idr - (pps->init_qp_minus26 + 26); + sh->slice_qp_delta = priv->unit_opts.fixed_qp_idr - (pps->init_qp_minus26 + 26); *vslice = (VAEncSliceParameterBufferHEVC) { @@ -1144,7 +844,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, .slice_tc_offset_div2 = sh->slice_tc_offset_div2, .slice_fields.bits = { - .last_slice_of_pic_flag = slice->index == pic->nb_slices - 1, + .last_slice_of_pic_flag = slice->index == vaapi_pic->nb_slices - 1, .dependent_slice_segment_flag = sh->dependent_slice_segment_flag, .colour_plane_id = sh->colour_plane_id, .slice_temporal_mvp_enabled_flag = @@ -1172,20 +872,20 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, if (pic->nb_refs[0]) { // Backward reference for P- or B-frame. - av_assert0(pic->type == PICTURE_TYPE_P || - pic->type == PICTURE_TYPE_B); + av_assert0(pic->type == FF_HW_PICTURE_TYPE_P || + pic->type == FF_HW_PICTURE_TYPE_B); vslice->ref_pic_list0[0] = vpic->reference_frames[0]; - if (ctx->p_to_gpb && pic->type == PICTURE_TYPE_P) + if (base_ctx->p_to_gpb && pic->type == FF_HW_PICTURE_TYPE_P) // Reference for GPB B-frame, L0 == L1 vslice->ref_pic_list1[0] = vpic->reference_frames[0]; } if (pic->nb_refs[1]) { // Forward reference for B-frame. - av_assert0(pic->type == PICTURE_TYPE_B); + av_assert0(pic->type == FF_HW_PICTURE_TYPE_B); vslice->ref_pic_list1[0] = vpic->reference_frames[1]; } - if (pic->type == PICTURE_TYPE_P && ctx->p_to_gpb) { + if (pic->type == FF_HW_PICTURE_TYPE_P && base_ctx->p_to_gpb) { vslice->slice_type = HEVC_SLICE_B; for (i = 0; i < FF_ARRAY_ELEMS(vslice->ref_pic_list0); i++) { vslice->ref_pic_list1[i].picture_id = vslice->ref_pic_list0[i].picture_id; @@ -1198,11 +898,12 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, static av_cold int vaapi_encode_h265_get_encoder_caps(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = avctx->priv_data; #if VA_CHECK_VERSION(1, 13, 0) { + VAAPIEncodeContext *ctx = avctx->priv_data; VAConfigAttribValEncHEVCBlockSizes block_size; VAConfigAttrib attr; VAStatus vas; @@ -1250,10 +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); - ctx->surface_width = FFALIGN(avctx->width, priv->min_cb_size); - ctx->surface_height = FFALIGN(avctx->height, 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); - ctx->slice_block_width = ctx->slice_block_height = priv->ctu_size; + base_ctx->slice_block_width = base_ctx->slice_block_height = priv->ctu_size; return 0; } @@ -1275,11 +976,11 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) priv->fixed_qp_p = av_clip(ctx->rc_quality, 1, 51); if (avctx->i_quant_factor > 0.0) - priv->fixed_qp_idr = + priv->unit_opts.fixed_qp_idr = av_clip((avctx->i_quant_factor * priv->fixed_qp_p + avctx->i_quant_offset) + 0.5, 1, 51); else - priv->fixed_qp_idr = priv->fixed_qp_p; + priv->unit_opts.fixed_qp_idr = priv->fixed_qp_p; if (avctx->b_quant_factor > 0.0) priv->fixed_qp_b = av_clip((avctx->b_quant_factor * priv->fixed_qp_p + @@ -1289,11 +990,11 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " "%d / %d / %d for IDR- / P- / B-frames.\n", - priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); + priv->unit_opts.fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); } else { // These still need to be set for init_qp/slice_qp_delta. - priv->fixed_qp_idr = 30; + priv->unit_opts.fixed_qp_idr = 30; priv->fixed_qp_p = 30; priv->fixed_qp_b = 30; } @@ -1325,10 +1026,10 @@ static const VAAPIEncodeProfile vaapi_encode_h265_profiles[] = { static const VAAPIEncodeType vaapi_encode_type_h265 = { .profiles = vaapi_encode_h265_profiles, - .flags = FLAG_SLICE_CONTROL | - FLAG_B_PICTURES | - FLAG_B_PICTURE_REFERENCES | - FLAG_NON_IDR_KEY_PICTURES, + .flags = FF_HW_FLAG_SLICE_CONTROL | + FF_HW_FLAG_B_PICTURES | + FF_HW_FLAG_B_PICTURE_REFERENCES | + FF_HW_FLAG_NON_IDR_KEY_PICTURES, .default_quality = 25, @@ -1398,6 +1099,7 @@ static av_cold int vaapi_encode_h265_close(AVCodecContext *avctx) #define OFFSET(x) offsetof(VAAPIEncodeH265Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_h265_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_RC_OPTIONS, @@ -1419,7 +1121,7 @@ static const AVOption vaapi_encode_h265_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, .unit = "tier" }, { "main", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, .unit = "tier" }, @@ -1509,6 +1211,7 @@ const FFCodec ff_hevc_vaapi_encoder = { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .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 c17747e3a..5f8266e98 100644 --- a/libavcodec/vaapi_encode_mjpeg.c +++ b/libavcodec/vaapi_encode_mjpeg.c @@ -147,7 +147,7 @@ fail: } static int vaapi_encode_mjpeg_write_extra_buffer(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *base, int index, int *type, char *data, size_t *data_len) { @@ -220,21 +220,23 @@ static int vaapi_encode_mjpeg_write_extra_buffer(AVCodecContext *avctx, } static int vaapi_encode_mjpeg_init_picture_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic) + FFHWBaseEncodePicture *pic) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeMJPEGContext *priv = avctx->priv_data; + VAAPIEncodePicture *vaapi_pic = pic->priv; JPEGRawFrameHeader *fh = &priv->frame_header; JPEGRawScanHeader *sh = &priv->scan.header; - VAEncPictureParameterBufferJPEG *vpic = pic->codec_picture_params; + VAEncPictureParameterBufferJPEG *vpic = vaapi_pic->codec_picture_params; const AVPixFmtDescriptor *desc; const uint8_t components_rgb[3] = { 'R', 'G', 'B' }; const uint8_t components_yuv[3] = { 1, 2, 3 }; const uint8_t *components; int t, i, quant_scale, len; - av_assert0(pic->type == PICTURE_TYPE_IDR); + av_assert0(pic->type == FF_HW_PICTURE_TYPE_IDR); - desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format); + desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); av_assert0(desc); if (desc->flags & AV_PIX_FMT_FLAG_RGB) components = components_rgb; @@ -377,8 +379,8 @@ static int vaapi_encode_mjpeg_init_picture_params(AVCodecContext *avctx, *vpic = (VAEncPictureParameterBufferJPEG) { - .reconstructed_picture = pic->recon_surface, - .coded_buf = pic->output_buffer, + .reconstructed_picture = vaapi_pic->recon_surface, + .coded_buf = vaapi_pic->output_buffer, .picture_width = fh->X, .picture_height = fh->Y, @@ -406,13 +408,13 @@ static int vaapi_encode_mjpeg_init_picture_params(AVCodecContext *avctx, vpic->quantiser_table_selector[i] = fh->Tq[i]; } - pic->nb_slices = 1; + vaapi_pic->nb_slices = 1; return 0; } static int vaapi_encode_mjpeg_init_slice_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *base, VAAPIEncodeSlice *slice) { VAAPIEncodeMJPEGContext *priv = avctx->priv_data; @@ -436,14 +438,14 @@ static int vaapi_encode_mjpeg_init_slice_params(AVCodecContext *avctx, static av_cold int vaapi_encode_mjpeg_get_encoder_caps(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; const AVPixFmtDescriptor *desc; - desc = av_pix_fmt_desc_get(ctx->input_frames->sw_format); + desc = av_pix_fmt_desc_get(base_ctx->input_frames->sw_format); av_assert0(desc); - ctx->surface_width = FFALIGN(avctx->width, 8 << desc->log2_chroma_w); - ctx->surface_height = FFALIGN(avctx->height, 8 << desc->log2_chroma_h); + base_ctx->surface_width = FFALIGN(avctx->width, 8 << desc->log2_chroma_w); + base_ctx->surface_height = FFALIGN(avctx->height, 8 << desc->log2_chroma_h); return 0; } @@ -494,8 +496,8 @@ static const VAAPIEncodeProfile vaapi_encode_mjpeg_profiles[] = { static const VAAPIEncodeType vaapi_encode_type_mjpeg = { .profiles = vaapi_encode_mjpeg_profiles, - .flags = FLAG_CONSTANT_QUALITY_ONLY | - FLAG_INTRA_ONLY, + .flags = FF_HW_FLAG_CONSTANT_QUALITY_ONLY | + FF_HW_FLAG_INTRA_ONLY, .get_encoder_caps = &vaapi_encode_mjpeg_get_encoder_caps, .configure = &vaapi_encode_mjpeg_configure, @@ -540,6 +542,7 @@ static av_cold int vaapi_encode_mjpeg_close(AVCodecContext *avctx) #define OFFSET(x) offsetof(VAAPIEncodeMJPEGContext, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_mjpeg_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_COMMON_OPTIONS, { "jfif", "Include JFIF header", @@ -583,6 +586,7 @@ const FFCodec ff_mjpeg_vaapi_encoder = { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .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 c9b16fbcf..5701e2e80 100644 --- a/libavcodec/vaapi_encode_mpeg2.c +++ b/libavcodec/vaapi_encode_mpeg2.c @@ -141,7 +141,7 @@ fail: } static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *pic, char *data, size_t *data_len) { VAAPIEncodeMPEG2Context *priv = avctx->priv_data; @@ -166,6 +166,7 @@ fail: static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeMPEG2Context *priv = avctx->priv_data; MPEG2RawSequenceHeader *sh = &priv->sequence_header; @@ -281,7 +282,7 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) se->bit_rate_extension = priv->bit_rate >> 18; se->vbv_buffer_size_extension = priv->vbv_buffer_size >> 10; - se->low_delay = ctx->b_per_p == 0; + se->low_delay = base_ctx->b_per_p == 0; se->frame_rate_extension_n = ext_n; se->frame_rate_extension_d = ext_d; @@ -353,8 +354,8 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) *vseq = (VAEncSequenceParameterBufferMPEG2) { - .intra_period = ctx->gop_size, - .ip_period = ctx->b_per_p + 1, + .intra_period = base_ctx->gop_size, + .ip_period = base_ctx->b_per_p + 1, .picture_width = avctx->width, .picture_height = avctx->height, @@ -417,30 +418,31 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) } static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic) + FFHWBaseEncodePicture *pic) { VAAPIEncodeMPEG2Context *priv = avctx->priv_data; + VAAPIEncodePicture *vaapi_pic = pic->priv; MPEG2RawPictureHeader *ph = &priv->picture_header; MPEG2RawPictureCodingExtension *pce = &priv->picture_coding_extension.data.picture_coding; - VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; + VAEncPictureParameterBufferMPEG2 *vpic = vaapi_pic->codec_picture_params; - if (pic->type == PICTURE_TYPE_IDR || pic->type == PICTURE_TYPE_I) { + if (pic->type == FF_HW_PICTURE_TYPE_IDR || pic->type == FF_HW_PICTURE_TYPE_I) { ph->temporal_reference = 0; ph->picture_coding_type = 1; priv->last_i_frame = pic->display_order; } else { ph->temporal_reference = pic->display_order - priv->last_i_frame; - ph->picture_coding_type = pic->type == PICTURE_TYPE_B ? 3 : 2; + ph->picture_coding_type = pic->type == FF_HW_PICTURE_TYPE_B ? 3 : 2; } - if (pic->type == PICTURE_TYPE_P || pic->type == PICTURE_TYPE_B) { + if (pic->type == FF_HW_PICTURE_TYPE_P || pic->type == FF_HW_PICTURE_TYPE_B) { pce->f_code[0][0] = priv->f_code_horizontal; pce->f_code[0][1] = priv->f_code_vertical; } else { pce->f_code[0][0] = 15; pce->f_code[0][1] = 15; } - if (pic->type == PICTURE_TYPE_B) { + if (pic->type == FF_HW_PICTURE_TYPE_B) { pce->f_code[1][0] = priv->f_code_horizontal; pce->f_code[1][1] = priv->f_code_vertical; } else { @@ -448,22 +450,22 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, pce->f_code[1][1] = 15; } - vpic->reconstructed_picture = pic->recon_surface; - vpic->coded_buf = pic->output_buffer; + vpic->reconstructed_picture = vaapi_pic->recon_surface; + vpic->coded_buf = vaapi_pic->output_buffer; switch (pic->type) { - case PICTURE_TYPE_IDR: - case PICTURE_TYPE_I: + case FF_HW_PICTURE_TYPE_IDR: + case FF_HW_PICTURE_TYPE_I: vpic->picture_type = VAEncPictureTypeIntra; break; - case PICTURE_TYPE_P: + case FF_HW_PICTURE_TYPE_P: vpic->picture_type = VAEncPictureTypePredictive; - vpic->forward_reference_picture = pic->refs[0][0]->recon_surface; + vpic->forward_reference_picture = ((VAAPIEncodePicture *)pic->refs[0][0]->priv)->recon_surface; break; - case PICTURE_TYPE_B: + case FF_HW_PICTURE_TYPE_B: vpic->picture_type = VAEncPictureTypeBidirectional; - vpic->forward_reference_picture = pic->refs[0][0]->recon_surface; - vpic->backward_reference_picture = pic->refs[1][0]->recon_surface; + vpic->forward_reference_picture = ((VAAPIEncodePicture *)pic->refs[0][0]->priv)->recon_surface; + vpic->backward_reference_picture = ((VAAPIEncodePicture *)pic->refs[1][0]->priv)->recon_surface; break; default: av_assert0(0 && "invalid picture type"); @@ -479,25 +481,25 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, } static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic, - VAAPIEncodeSlice *slice) + FFHWBaseEncodePicture *pic, + VAAPIEncodeSlice *slice) { - VAAPIEncodeMPEG2Context *priv = avctx->priv_data; - VAEncSliceParameterBufferMPEG2 *vslice = slice->codec_slice_params; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; + VAEncSliceParameterBufferMPEG2 *vslice = slice->codec_slice_params; int qp; vslice->macroblock_address = slice->block_start; vslice->num_macroblocks = slice->block_size; switch (pic->type) { - case PICTURE_TYPE_IDR: - case PICTURE_TYPE_I: + case FF_HW_PICTURE_TYPE_IDR: + case FF_HW_PICTURE_TYPE_I: qp = priv->quant_i; break; - case PICTURE_TYPE_P: + case FF_HW_PICTURE_TYPE_P: qp = priv->quant_p; break; - case PICTURE_TYPE_B: + case FF_HW_PICTURE_TYPE_B: qp = priv->quant_b; break; default: @@ -505,8 +507,8 @@ static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx, } vslice->quantiser_scale_code = qp; - vslice->is_intra_slice = (pic->type == PICTURE_TYPE_IDR || - pic->type == PICTURE_TYPE_I); + vslice->is_intra_slice = (pic->type == FF_HW_PICTURE_TYPE_IDR || + pic->type == FF_HW_PICTURE_TYPE_I); return 0; } @@ -566,7 +568,7 @@ static const VAAPIEncodeProfile vaapi_encode_mpeg2_profiles[] = { static const VAAPIEncodeType vaapi_encode_type_mpeg2 = { .profiles = vaapi_encode_mpeg2_profiles, - .flags = FLAG_B_PICTURES, + .flags = FF_HW_FLAG_B_PICTURES, .configure = &vaapi_encode_mpeg2_configure, @@ -639,6 +641,7 @@ static av_cold int vaapi_encode_mpeg2_close(AVCodecContext *avctx) #define OFFSET(x) offsetof(VAAPIEncodeMPEG2Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_mpeg2_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_RC_OPTIONS, @@ -706,6 +709,7 @@ const FFCodec ff_mpeg2_vaapi_encoder = { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .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 8a557b967..ad88af63e 100644 --- a/libavcodec/vaapi_encode_vp8.c +++ b/libavcodec/vaapi_encode_vp8.c @@ -52,6 +52,7 @@ typedef struct VAAPIEncodeVP8Context { static int vaapi_encode_vp8_init_sequence_params(AVCodecContext *avctx) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeContext *ctx = avctx->priv_data; VAEncSequenceParameterBufferVP8 *vseq = ctx->codec_sequence_params; @@ -66,26 +67,27 @@ static int vaapi_encode_vp8_init_sequence_params(AVCodecContext *avctx) if (!(ctx->va_rc_mode & VA_RC_CQP)) { vseq->bits_per_second = ctx->va_bit_rate; - vseq->intra_period = ctx->gop_size; + vseq->intra_period = base_ctx->gop_size; } return 0; } static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic) + FFHWBaseEncodePicture *pic) { + VAAPIEncodePicture *vaapi_pic = pic->priv; VAAPIEncodeVP8Context *priv = avctx->priv_data; - VAEncPictureParameterBufferVP8 *vpic = pic->codec_picture_params; + VAEncPictureParameterBufferVP8 *vpic = vaapi_pic->codec_picture_params; int i; - vpic->reconstructed_frame = pic->recon_surface; + vpic->reconstructed_frame = vaapi_pic->recon_surface; - vpic->coded_buf = pic->output_buffer; + vpic->coded_buf = vaapi_pic->output_buffer; switch (pic->type) { - case PICTURE_TYPE_IDR: - case PICTURE_TYPE_I: + case FF_HW_PICTURE_TYPE_IDR: + case FF_HW_PICTURE_TYPE_I: av_assert0(pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0); vpic->ref_flags.bits.force_kf = 1; vpic->ref_last_frame = @@ -93,7 +95,7 @@ static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx, vpic->ref_arf_frame = VA_INVALID_SURFACE; break; - case PICTURE_TYPE_P: + case FF_HW_PICTURE_TYPE_P: av_assert0(!pic->nb_refs[1]); vpic->ref_flags.bits.no_ref_last = 0; vpic->ref_flags.bits.no_ref_gf = 1; @@ -101,13 +103,13 @@ static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx, vpic->ref_last_frame = vpic->ref_gf_frame = vpic->ref_arf_frame = - pic->refs[0][0]->recon_surface; + ((VAAPIEncodePicture *)pic->refs[0][0]->priv)->recon_surface; break; default: av_assert0(0 && "invalid picture type"); } - vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR); + vpic->pic_flags.bits.frame_type = (pic->type != FF_HW_PICTURE_TYPE_IDR); vpic->pic_flags.bits.show_frame = 1; vpic->pic_flags.bits.refresh_last = 1; @@ -127,7 +129,7 @@ static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx, } static int vaapi_encode_vp8_write_quant_table(AVCodecContext *avctx, - VAAPIEncodePicture *pic, + FFHWBaseEncodePicture *base_pic, int index, int *type, char *data, size_t *data_len) { @@ -145,7 +147,7 @@ static int vaapi_encode_vp8_write_quant_table(AVCodecContext *avctx, memset(&quant, 0, sizeof(quant)); - if (pic->type == PICTURE_TYPE_P) + if (base_pic->type == FF_HW_PICTURE_TYPE_P) q = priv->q_index_p; else q = priv->q_index_i; @@ -216,6 +218,7 @@ static av_cold int vaapi_encode_vp8_init(AVCodecContext *avctx) #define OFFSET(x) offsetof(VAAPIEncodeVP8Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_vp8_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_RC_OPTIONS, @@ -261,6 +264,7 @@ const FFCodec ff_vp8_vaapi_encoder = { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .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 c2a8dec71..ab925e24b 100644 --- a/libavcodec/vaapi_encode_vp9.c +++ b/libavcodec/vaapi_encode_vp9.c @@ -53,6 +53,7 @@ typedef struct VAAPIEncodeVP9Context { static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx) { + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeContext *ctx = avctx->priv_data; VAEncSequenceParameterBufferVP9 *vseq = ctx->codec_sequence_params; VAEncPictureParameterBufferVP9 *vpic = ctx->codec_picture_params; @@ -64,7 +65,7 @@ static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx) if (!(ctx->va_rc_mode & VA_RC_CQP)) { vseq->bits_per_second = ctx->va_bit_rate; - vseq->intra_period = ctx->gop_size; + vseq->intra_period = base_ctx->gop_size; } vpic->frame_width_src = avctx->width; @@ -76,17 +77,18 @@ static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx) } static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, - VAAPIEncodePicture *pic) + FFHWBaseEncodePicture *pic) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; VAAPIEncodeVP9Context *priv = avctx->priv_data; - VAAPIEncodeVP9Picture *hpic = pic->priv_data; - VAEncPictureParameterBufferVP9 *vpic = pic->codec_picture_params; + VAAPIEncodePicture *vaapi_pic = pic->priv; + VAAPIEncodeVP9Picture *hpic = pic->codec_priv; + VAEncPictureParameterBufferVP9 *vpic = vaapi_pic->codec_picture_params; int i; int num_tile_columns; - vpic->reconstructed_frame = pic->recon_surface; - vpic->coded_buf = pic->output_buffer; + vpic->reconstructed_frame = vaapi_pic->recon_surface; + vpic->coded_buf = vaapi_pic->output_buffer; // Maximum width of a tile in units of superblocks is MAX_TILE_WIDTH_B64(64) // So the number of tile columns is related to the width of the picture. @@ -95,19 +97,19 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, vpic->log2_tile_columns = num_tile_columns == 1 ? 0 : av_log2(num_tile_columns - 1) + 1; switch (pic->type) { - case PICTURE_TYPE_IDR: + case FF_HW_PICTURE_TYPE_IDR: av_assert0(pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0); vpic->ref_flags.bits.force_kf = 1; vpic->refresh_frame_flags = 0xff; hpic->slot = 0; break; - case PICTURE_TYPE_P: + case FF_HW_PICTURE_TYPE_P: av_assert0(!pic->nb_refs[1]); { - VAAPIEncodeVP9Picture *href = pic->refs[0][0]->priv_data; + VAAPIEncodeVP9Picture *href = pic->refs[0][0]->codec_priv; av_assert0(href->slot == 0 || href->slot == 1); - if (ctx->max_b_depth > 0) { + if (base_ctx->max_b_depth > 0) { hpic->slot = !href->slot; vpic->refresh_frame_flags = 1 << hpic->slot | 0xfc; } else { @@ -119,15 +121,15 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, vpic->ref_flags.bits.ref_last_sign_bias = 1; } break; - case PICTURE_TYPE_B: + case FF_HW_PICTURE_TYPE_B: av_assert0(pic->nb_refs[0] && pic->nb_refs[1]); { - VAAPIEncodeVP9Picture *href0 = pic->refs[0][0]->priv_data, - *href1 = pic->refs[1][0]->priv_data; + VAAPIEncodeVP9Picture *href0 = pic->refs[0][0]->codec_priv, + *href1 = pic->refs[1][0]->codec_priv; av_assert0(href0->slot < pic->b_depth + 1 && href1->slot < pic->b_depth + 1); - if (pic->b_depth == ctx->max_b_depth) { + if (pic->b_depth == base_ctx->max_b_depth) { // Unreferenced frame. vpic->refresh_frame_flags = 0x00; hpic->slot = 8; @@ -159,20 +161,20 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) { for (int j = 0; j < pic->nb_refs[i]; j++) { - VAAPIEncodePicture *ref_pic = pic->refs[i][j]; + FFHWBaseEncodePicture *ref_pic = pic->refs[i][j]; int slot; - slot = ((VAAPIEncodeVP9Picture*)ref_pic->priv_data)->slot; + slot = ((VAAPIEncodeVP9Picture*)ref_pic->codec_priv)->slot; av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE); - vpic->reference_frames[slot] = ref_pic->recon_surface; + vpic->reference_frames[slot] = ((VAAPIEncodePicture *)ref_pic->priv)->recon_surface; } } - vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR); + vpic->pic_flags.bits.frame_type = (pic->type != FF_HW_PICTURE_TYPE_IDR); vpic->pic_flags.bits.show_frame = pic->display_order <= pic->encode_order; - if (pic->type == PICTURE_TYPE_IDR) + if (pic->type == FF_HW_PICTURE_TYPE_IDR) vpic->luma_ac_qindex = priv->q_idx_idr; - else if (pic->type == PICTURE_TYPE_P) + else if (pic->type == FF_HW_PICTURE_TYPE_P) vpic->luma_ac_qindex = priv->q_idx_p; else vpic->luma_ac_qindex = priv->q_idx_b; @@ -188,11 +190,11 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, static av_cold int vaapi_encode_vp9_get_encoder_caps(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = avctx->priv_data; // Surfaces must be aligned to 64x64 superblock boundaries. - ctx->surface_width = FFALIGN(avctx->width, 64); - ctx->surface_height = FFALIGN(avctx->height, 64); + base_ctx->surface_width = FFALIGN(avctx->width, 64); + base_ctx->surface_height = FFALIGN(avctx->height, 64); return 0; } @@ -239,8 +241,8 @@ static const VAAPIEncodeProfile vaapi_encode_vp9_profiles[] = { static const VAAPIEncodeType vaapi_encode_type_vp9 = { .profiles = vaapi_encode_vp9_profiles, - .flags = FLAG_B_PICTURES | - FLAG_B_PICTURE_REFERENCES, + .flags = FF_HW_FLAG_B_PICTURES | + FF_HW_FLAG_B_PICTURE_REFERENCES, .default_quality = 100, @@ -273,6 +275,7 @@ static av_cold int vaapi_encode_vp9_init(AVCodecContext *avctx) #define OFFSET(x) offsetof(VAAPIEncodeVP9Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_vp9_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_COMMON_OPTIONS, VAAPI_ENCODE_RC_OPTIONS, @@ -314,6 +317,7 @@ const FFCodec ff_vp9_vaapi_encoder = { .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | 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, diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c index 55cf5a05e..398e92568 100644 --- a/libavcodec/vaapi_h264.c +++ b/libavcodec/vaapi_h264.c @@ -93,14 +93,19 @@ typedef struct DPB { */ static int dpb_add(DPB *dpb, const H264Picture *pic) { - int i; + int i, pic_frame_idx, merged = 0; if (dpb->size >= dpb->max_size) return -1; + pic_frame_idx = pic->long_ref ? pic->pic_id : pic->frame_num; + for (i = 0; i < dpb->size; i++) { VAPictureH264 * const va_pic = &dpb->va_pics[i]; - if (va_pic->picture_id == ff_vaapi_get_surface_id(pic->f)) { + int va_pic_long_ref = !!(va_pic->flags & VA_PICTURE_H264_LONG_TERM_REFERENCE); + if (va_pic->picture_id == ff_vaapi_get_surface_id(pic->f) && + va_pic_long_ref == pic->long_ref && + va_pic->frame_idx == pic_frame_idx) { VAPictureH264 temp_va_pic; fill_vaapi_pic(&temp_va_pic, pic, 0); @@ -112,11 +117,14 @@ static int dpb_add(DPB *dpb, const H264Picture *pic) } else { va_pic->BottomFieldOrderCnt = temp_va_pic.BottomFieldOrderCnt; } + merged = 1; } - return 0; } } + if (merged) + return 0; + fill_vaapi_pic(&dpb->va_pics[dpb->size++], pic, 0); return 0; } @@ -375,7 +383,7 @@ static int vaapi_h264_decode_slice(AVCodecContext *avctx, slice_param.chroma_offset_l1); err = ff_vaapi_decode_make_slice_buffer(avctx, pic, - &slice_param, sizeof(slice_param), + &slice_param, 1, sizeof(slice_param), buffer, size); if (err) { ff_vaapi_decode_cancel(avctx, pic); diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c index 3bdd2dd1b..0c5a82922 100644 --- a/libavcodec/vaapi_hevc.c +++ b/libavcodec/vaapi_hevc.c @@ -24,12 +24,13 @@ #include #include "avcodec.h" -#include "hevcdec.h" #include "hwaccel_internal.h" #include "vaapi_decode.h" #include "vaapi_hevc.h" #include "h265_profile_level.h" +#include "hevc/hevcdec.h" + typedef struct VAAPIDecodePictureHEVC { #if VA_CHECK_VERSION(1, 2, 0) VAPictureParameterBufferHEVCExtension pic_param; @@ -53,60 +54,61 @@ static void init_vaapi_pic(VAPictureHEVC *va_pic) static void fill_vaapi_pic(VAPictureHEVC *va_pic, const HEVCFrame *pic, int rps_type) { - va_pic->picture_id = ff_vaapi_get_surface_id(pic->frame); + va_pic->picture_id = ff_vaapi_get_surface_id(pic->f); va_pic->pic_order_cnt = pic->poc; va_pic->flags = rps_type; if (pic->flags & HEVC_FRAME_FLAG_LONG_REF) va_pic->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE; - if (pic->frame->flags & AV_FRAME_FLAG_INTERLACED) { + if (pic->f->flags & AV_FRAME_FLAG_INTERLACED) { va_pic->flags |= VA_PICTURE_HEVC_FIELD_PIC; - if (!(pic->frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)) + if (!(pic->f->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST)) va_pic->flags |= VA_PICTURE_HEVC_BOTTOM_FIELD; } } static int find_frame_rps_type(const HEVCContext *h, const HEVCFrame *pic) { - VASurfaceID pic_surf = ff_vaapi_get_surface_id(pic->frame); - const HEVCFrame *current_picture = h->ref; + VASurfaceID pic_surf = ff_vaapi_get_surface_id(pic->f); + const HEVCFrame *current_picture = h->cur_frame; int i; for (i = 0; i < h->rps[ST_CURR_BEF].nb_refs; i++) { - if (pic_surf == ff_vaapi_get_surface_id(h->rps[ST_CURR_BEF].ref[i]->frame)) + if (pic_surf == ff_vaapi_get_surface_id(h->rps[ST_CURR_BEF].ref[i]->f)) return VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE; } for (i = 0; i < h->rps[ST_CURR_AFT].nb_refs; i++) { - if (pic_surf == ff_vaapi_get_surface_id(h->rps[ST_CURR_AFT].ref[i]->frame)) + if (pic_surf == ff_vaapi_get_surface_id(h->rps[ST_CURR_AFT].ref[i]->f)) return VA_PICTURE_HEVC_RPS_ST_CURR_AFTER; } for (i = 0; i < h->rps[LT_CURR].nb_refs; i++) { - if (pic_surf == ff_vaapi_get_surface_id(h->rps[LT_CURR].ref[i]->frame)) + if (pic_surf == ff_vaapi_get_surface_id(h->rps[LT_CURR].ref[i]->f)) return VA_PICTURE_HEVC_RPS_LT_CURR; } - if (h->ps.pps->pps_curr_pic_ref_enabled_flag && current_picture->poc == pic->poc) + if (h->pps->pps_curr_pic_ref_enabled_flag && current_picture->poc == pic->poc) return VA_PICTURE_HEVC_LONG_TERM_REFERENCE; return 0; } -static void fill_vaapi_reference_frames(const HEVCContext *h, VAPictureParameterBufferHEVC *pp) +static void fill_vaapi_reference_frames(const HEVCContext *h, const HEVCLayerContext *l, + VAPictureParameterBufferHEVC *pp) { - const HEVCFrame *current_picture = h->ref; + const HEVCFrame *current_picture = h->cur_frame; int i, j, rps_type; for (i = 0, j = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) { const HEVCFrame *frame = NULL; - while (!frame && j < FF_ARRAY_ELEMS(h->DPB)) { - if ((&h->DPB[j] != current_picture || h->ps.pps->pps_curr_pic_ref_enabled_flag) && - (h->DPB[j].flags & (HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF))) - frame = &h->DPB[j]; + while (!frame && j < FF_ARRAY_ELEMS(l->DPB)) { + if ((&l->DPB[j] != current_picture || h->pps->pps_curr_pic_ref_enabled_flag) && + (l->DPB[j].flags & (HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF))) + frame = &l->DPB[j]; j++; } @@ -124,9 +126,10 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, av_unused uint32_t size) { const HEVCContext *h = avctx->priv_data; - VAAPIDecodePictureHEVC *pic = h->ref->hwaccel_picture_private; - const HEVCSPS *sps = h->ps.sps; - const HEVCPPS *pps = h->ps.pps; + const HEVCLayerContext *l = &h->layers[h->cur_layer]; + VAAPIDecodePictureHEVC *pic = h->cur_frame->hwaccel_picture_private; + const HEVCPPS *pps = h->pps; + const HEVCSPS *sps = pps->sps; const ScalingList *scaling_list = NULL; int pic_param_size, err, i; @@ -137,7 +140,7 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, VAPictureParameterBufferHEVC *pic_param = (VAPictureParameterBufferHEVC *)&pic->pic_param; - pic->pic.output_surface = ff_vaapi_get_surface_id(h->ref->frame); + pic->pic.output_surface = ff_vaapi_get_surface_id(h->cur_frame->f); *pic_param = (VAPictureParameterBufferHEVC) { .pic_width_in_luma_samples = sps->width, @@ -171,12 +174,12 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, .pic_fields.bits = { .chroma_format_idc = sps->chroma_format_idc, .tiles_enabled_flag = pps->tiles_enabled_flag, - .separate_colour_plane_flag = sps->separate_colour_plane_flag, - .pcm_enabled_flag = sps->pcm_enabled_flag, - .scaling_list_enabled_flag = sps->scaling_list_enable_flag, + .separate_colour_plane_flag = sps->separate_colour_plane, + .pcm_enabled_flag = sps->pcm_enabled, + .scaling_list_enabled_flag = sps->scaling_list_enabled, .transform_skip_enabled_flag = pps->transform_skip_enabled_flag, - .amp_enabled_flag = sps->amp_enabled_flag, - .strong_intra_smoothing_enabled_flag = sps->sps_strong_intra_smoothing_enable_flag, + .amp_enabled_flag = sps->amp_enabled, + .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled, .sign_data_hiding_enabled_flag = pps->sign_data_hiding_flag, .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag, @@ -186,12 +189,12 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag, .pps_loop_filter_across_slices_enabled_flag = pps->seq_loop_filter_across_slices_enabled_flag, .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag, - .pcm_loop_filter_disabled_flag = sps->pcm.loop_filter_disable_flag, + .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled, }, .slice_parsing_fields.bits = { .lists_modification_present_flag = pps->lists_modification_present_flag, - .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag, - .sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag, + .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present, + .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled, .cabac_init_present_flag = pps->cabac_init_present_flag, .output_flag_present_flag = pps->output_flag_present_flag, .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag, @@ -206,8 +209,8 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, }, }; - fill_vaapi_pic(&pic_param->CurrPic, h->ref, 0); - fill_vaapi_reference_frames(h, pic_param); + fill_vaapi_pic(&pic_param->CurrPic, h->cur_frame, 0); + fill_vaapi_reference_frames(h, l, pic_param); if (pps->tiles_enabled_flag) { pic_param->num_tile_columns_minus1 = pps->num_tile_columns - 1; @@ -231,15 +234,15 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, avctx->profile == AV_PROFILE_HEVC_SCC) { pic->pic_param.rext = (VAPictureParameterBufferHEVCRext) { .range_extension_pic_fields.bits = { - .transform_skip_rotation_enabled_flag = sps->transform_skip_rotation_enabled_flag, - .transform_skip_context_enabled_flag = sps->transform_skip_context_enabled_flag, - .implicit_rdpcm_enabled_flag = sps->implicit_rdpcm_enabled_flag, - .explicit_rdpcm_enabled_flag = sps->explicit_rdpcm_enabled_flag, - .extended_precision_processing_flag = sps->extended_precision_processing_flag, - .intra_smoothing_disabled_flag = sps->intra_smoothing_disabled_flag, - .high_precision_offsets_enabled_flag = sps->high_precision_offsets_enabled_flag, - .persistent_rice_adaptation_enabled_flag = sps->persistent_rice_adaptation_enabled_flag, - .cabac_bypass_alignment_enabled_flag = sps->cabac_bypass_alignment_enabled_flag, + .transform_skip_rotation_enabled_flag = sps->transform_skip_rotation_enabled, + .transform_skip_context_enabled_flag = sps->transform_skip_context_enabled, + .implicit_rdpcm_enabled_flag = sps->implicit_rdpcm_enabled, + .explicit_rdpcm_enabled_flag = sps->explicit_rdpcm_enabled, + .extended_precision_processing_flag = sps->extended_precision_processing, + .intra_smoothing_disabled_flag = sps->intra_smoothing_disabled, + .high_precision_offsets_enabled_flag = sps->high_precision_offsets_enabled, + .persistent_rice_adaptation_enabled_flag = sps->persistent_rice_adaptation_enabled, + .cabac_bypass_alignment_enabled_flag = sps->cabac_bypass_alignment_enabled, .cross_component_prediction_enabled_flag = pps->cross_component_prediction_enabled_flag, .chroma_qp_offset_list_enabled_flag = pps->chroma_qp_offset_list_enabled_flag, }, @@ -258,7 +261,7 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, pre_palette_size = pps->pps_palette_predictor_initializers_present_flag ? pps->pps_num_palette_predictor_initializers : - (sps->sps_palette_predictor_initializers_present_flag ? + (sps->palette_predictor_initializers_present ? sps->sps_num_palette_predictor_initializers : 0); @@ -266,9 +269,9 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, pic->pic_param.scc = (VAPictureParameterBufferHEVCScc) { .screen_content_pic_fields.bits = { .pps_curr_pic_ref_enabled_flag = pps->pps_curr_pic_ref_enabled_flag, - .palette_mode_enabled_flag = sps->palette_mode_enabled_flag, + .palette_mode_enabled_flag = sps->palette_mode_enabled, .motion_vector_resolution_control_idc = sps->motion_vector_resolution_control_idc, - .intra_boundary_filtering_disabled_flag = sps->intra_boundary_filtering_disabled_flag, + .intra_boundary_filtering_disabled_flag = sps->intra_boundary_filtering_disabled, .residual_adaptive_colour_transform_enabled_flag = pps->residual_adaptive_colour_transform_enabled_flag, .pps_slice_act_qp_offsets_present_flag = pps->pps_slice_act_qp_offsets_present_flag, @@ -305,7 +308,7 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, if (pps->scaling_list_data_present_flag) scaling_list = &pps->scaling_list; - else if (sps->scaling_list_enable_flag) + else if (sps->scaling_list_enabled) scaling_list = &sps->scaling_list; if (scaling_list) { @@ -343,7 +346,7 @@ fail: static int vaapi_hevc_end_frame(AVCodecContext *avctx) { const HEVCContext *h = avctx->priv_data; - VAAPIDecodePictureHEVC *pic = h->ref->hwaccel_picture_private; + VAAPIDecodePictureHEVC *pic = h->cur_frame->hwaccel_picture_private; VASliceParameterBufferHEVC *last_slice_param = (VASliceParameterBufferHEVC *)&pic->last_slice_param; int ret; @@ -353,7 +356,7 @@ static int vaapi_hevc_end_frame(AVCodecContext *avctx) if (pic->last_size) { last_slice_param->LongSliceFlags.fields.LastSliceOfPic = 1; ret = ff_vaapi_decode_make_slice_buffer(avctx, &pic->pic, - &pic->last_slice_param, slice_param_size, + &pic->last_slice_param, 1, slice_param_size, pic->last_buffer, pic->last_size); if (ret < 0) goto fail; @@ -398,13 +401,13 @@ static void fill_pred_weight_table(AVCodecContext *avctx, slice_param->luma_log2_weight_denom = 0; if (sh->slice_type == HEVC_SLICE_I || - (sh->slice_type == HEVC_SLICE_P && !h->ps.pps->weighted_pred_flag) || - (sh->slice_type == HEVC_SLICE_B && !h->ps.pps->weighted_bipred_flag)) + (sh->slice_type == HEVC_SLICE_P && !h->pps->weighted_pred_flag) || + (sh->slice_type == HEVC_SLICE_B && !h->pps->weighted_bipred_flag)) return; slice_param->luma_log2_weight_denom = sh->luma_log2_weight_denom; - if (h->ps.sps->chroma_format_idc) { + if (h->pps->sps->chroma_format_idc) { slice_param->delta_chroma_log2_weight_denom = sh->chroma_log2_weight_denom - sh->luma_log2_weight_denom; } @@ -435,7 +438,7 @@ static void fill_pred_weight_table(AVCodecContext *avctx, static uint8_t get_ref_pic_index(const HEVCContext *h, const HEVCFrame *frame) { - VAAPIDecodePictureHEVC *pic = h->ref->hwaccel_picture_private; + VAAPIDecodePictureHEVC *pic = h->cur_frame->hwaccel_picture_private; VAPictureParameterBufferHEVC *pp = (VAPictureParameterBufferHEVC *)&pic->pic_param; uint8_t i; @@ -445,7 +448,7 @@ static uint8_t get_ref_pic_index(const HEVCContext *h, const HEVCFrame *frame) 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) + if (pid != VA_INVALID_ID && pid == ff_vaapi_get_surface_id(frame->f) && poc == frame->poc) return i; } @@ -458,7 +461,7 @@ static int vaapi_hevc_decode_slice(AVCodecContext *avctx, { const HEVCContext *h = avctx->priv_data; const SliceHeader *sh = &h->sh; - VAAPIDecodePictureHEVC *pic = h->ref->hwaccel_picture_private; + VAAPIDecodePictureHEVC *pic = h->cur_frame->hwaccel_picture_private; VASliceParameterBufferHEVC *last_slice_param = (VASliceParameterBufferHEVC *)&pic->last_slice_param; int slice_param_size = avctx->profile >= AV_PROFILE_HEVC_REXT ? @@ -471,7 +474,7 @@ static int vaapi_hevc_decode_slice(AVCodecContext *avctx, if (!sh->first_slice_in_pic_flag) { err = ff_vaapi_decode_make_slice_buffer(avctx, &pic->pic, - &pic->last_slice_param, slice_param_size, + &pic->last_slice_param, 1, slice_param_size, pic->last_buffer, pic->last_size); pic->last_buffer = NULL; pic->last_size = 0; @@ -485,9 +488,7 @@ static int vaapi_hevc_decode_slice(AVCodecContext *avctx, .slice_data_size = size, .slice_data_offset = 0, .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, - /* Add 1 to the bits count here to account for the byte_alignment bit, which - * always is at least one bit and not accounted for otherwise. */ - .slice_data_byte_offset = (get_bits_count(&h->HEVClc->gb) + 1 + 7) / 8, + .slice_data_byte_offset = sh->data_offset, .slice_segment_address = sh->slice_segment_addr, .slice_qp_delta = sh->slice_qp_delta, .slice_cb_qp_offset = sh->slice_cb_qp_offset, @@ -517,7 +518,7 @@ static int vaapi_hevc_decode_slice(AVCodecContext *avctx, memset(last_slice_param->RefPicList, 0xFF, sizeof(last_slice_param->RefPicList)); for (list_idx = 0; list_idx < nb_list; list_idx++) { - RefPicList *rpl = &h->ref->refPicList[list_idx]; + RefPicList *rpl = &h->cur_frame->refPicList[list_idx]; for (i = 0; i < rpl->nb_refs; i++) last_slice_param->RefPicList[list_idx][i] = get_ref_pic_index(h, rpl->ref[i]); @@ -595,7 +596,7 @@ static int ptl_convert(const PTLCommon *general_ptl, H265RawProfileTierLevel *h2 VAProfile ff_vaapi_parse_hevc_rext_scc_profile(AVCodecContext *avctx) { const HEVCContext *h = avctx->priv_data; - const HEVCSPS *sps = h->ps.sps; + const HEVCSPS *sps = h->pps->sps; const PTL *ptl = &sps->ptl; const PTLCommon *general_ptl = &ptl->general_ptl; const H265ProfileDescriptor *profile; diff --git a/libavcodec/vaapi_mjpeg.c b/libavcodec/vaapi_mjpeg.c index 5b8d47bb2..9557cf5f9 100644 --- a/libavcodec/vaapi_mjpeg.c +++ b/libavcodec/vaapi_mjpeg.c @@ -131,7 +131,7 @@ static int vaapi_mjpeg_decode_slice(AVCodecContext *avctx, sp.components[i].ac_table_selector = s->ac_index[i]; } - err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, sizeof(sp), buffer, size); + err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, 1, sizeof(sp), buffer, size); if (err) goto fail; diff --git a/libavcodec/vaapi_mpeg2.c b/libavcodec/vaapi_mpeg2.c index eeb4e8732..d4304dfdd 100644 --- a/libavcodec/vaapi_mpeg2.c +++ b/libavcodec/vaapi_mpeg2.c @@ -42,12 +42,12 @@ static inline int mpeg2_get_is_frame_start(const MpegEncContext *s) static int vaapi_mpeg2_start_frame(AVCodecContext *avctx, av_unused const uint8_t *buffer, av_unused uint32_t size) { const MpegEncContext *s = avctx->priv_data; - VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; + VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; VAPictureParameterBufferMPEG2 pic_param; VAIQMatrixBufferMPEG2 iq_matrix; int i, err; - pic->output_surface = ff_vaapi_get_surface_id(s->current_picture_ptr->f); + pic->output_surface = ff_vaapi_get_surface_id(s->cur_pic.ptr->f); pic_param = (VAPictureParameterBufferMPEG2) { .horizontal_size = s->width, @@ -73,10 +73,10 @@ static int vaapi_mpeg2_start_frame(AVCodecContext *avctx, av_unused const uint8_ switch (s->pict_type) { case AV_PICTURE_TYPE_B: - pic_param.backward_reference_picture = ff_vaapi_get_surface_id(s->next_picture.f); + pic_param.backward_reference_picture = ff_vaapi_get_surface_id(s->next_pic.ptr->f); // fall-through case AV_PICTURE_TYPE_P: - pic_param.forward_reference_picture = ff_vaapi_get_surface_id(s->last_picture.f); + pic_param.forward_reference_picture = ff_vaapi_get_surface_id(s->last_pic.ptr->f); break; } @@ -115,7 +115,7 @@ fail: static int vaapi_mpeg2_end_frame(AVCodecContext *avctx) { MpegEncContext *s = avctx->priv_data; - VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; + VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; int ret; ret = ff_vaapi_decode_issue(avctx, pic); @@ -131,7 +131,7 @@ fail: static int vaapi_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { const MpegEncContext *s = avctx->priv_data; - VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; + VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; VASliceParameterBufferMPEG2 slice_param; GetBitContext gb; uint32_t quantiser_scale_code, intra_slice_flag, macroblock_offset; @@ -162,7 +162,7 @@ static int vaapi_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer }; err = ff_vaapi_decode_make_slice_buffer(avctx, pic, - &slice_param, sizeof(slice_param), + &slice_param, 1, sizeof(slice_param), buffer, size); if (err < 0) { ff_vaapi_decode_cancel(avctx, pic); diff --git a/libavcodec/vaapi_mpeg4.c b/libavcodec/vaapi_mpeg4.c index 363b686e4..2c9dfbe42 100644 --- a/libavcodec/vaapi_mpeg4.c +++ b/libavcodec/vaapi_mpeg4.c @@ -49,11 +49,11 @@ static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, av_unused const uint8_ { Mpeg4DecContext *ctx = avctx->priv_data; MpegEncContext *s = &ctx->m; - VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; + VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; VAPictureParameterBufferMPEG4 pic_param; int i, err; - pic->output_surface = ff_vaapi_get_surface_id(s->current_picture_ptr->f); + pic->output_surface = ff_vaapi_get_surface_id(s->cur_pic.ptr->f); pic_param = (VAPictureParameterBufferMPEG4) { .vop_width = s->width, @@ -74,11 +74,11 @@ static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, av_unused const uint8_ .resync_marker_disable = !ctx->resync_marker, }, .no_of_sprite_warping_points = ctx->num_sprite_warping_points, - .quant_precision = s->quant_precision, + .quant_precision = ctx->quant_precision, .vop_fields.bits = { .vop_coding_type = s->pict_type - AV_PICTURE_TYPE_I, .backward_reference_vop_coding_type = - s->pict_type == AV_PICTURE_TYPE_B ? s->next_picture.f->pict_type - AV_PICTURE_TYPE_I : 0, + s->pict_type == AV_PICTURE_TYPE_B ? s->next_pic.ptr->f->pict_type - AV_PICTURE_TYPE_I : 0, .vop_rounding_type = s->no_rounding, .intra_dc_vlc_thr = mpeg4_get_intra_dc_vlc_thr(ctx), .top_field_first = s->top_field_first, @@ -100,9 +100,9 @@ static int vaapi_mpeg4_start_frame(AVCodecContext *avctx, av_unused const uint8_ } if (s->pict_type == AV_PICTURE_TYPE_B) - pic_param.backward_reference_picture = ff_vaapi_get_surface_id(s->next_picture.f); + pic_param.backward_reference_picture = ff_vaapi_get_surface_id(s->next_pic.ptr->f); if (s->pict_type != AV_PICTURE_TYPE_I) - pic_param.forward_reference_picture = ff_vaapi_get_surface_id(s->last_picture.f); + pic_param.forward_reference_picture = ff_vaapi_get_surface_id(s->last_pic.ptr->f); err = ff_vaapi_decode_make_param_buffer(avctx, pic, VAPictureParameterBufferType, @@ -139,7 +139,7 @@ fail: static int vaapi_mpeg4_end_frame(AVCodecContext *avctx) { MpegEncContext *s = avctx->priv_data; - VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; + VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; int ret; ret = ff_vaapi_decode_issue(avctx, pic); @@ -155,7 +155,7 @@ fail: static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { MpegEncContext *s = avctx->priv_data; - VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; + VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; VASliceParameterBufferMPEG4 slice_param; int err; @@ -169,7 +169,7 @@ static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer }; err = ff_vaapi_decode_make_slice_buffer(avctx, pic, - &slice_param, sizeof(slice_param), + &slice_param, 1, sizeof(slice_param), buffer, size); if (err < 0) { ff_vaapi_decode_cancel(avctx, pic); diff --git a/libavcodec/vaapi_vc1.c b/libavcodec/vaapi_vc1.c index 09a5c852f..7d001882f 100644 --- a/libavcodec/vaapi_vc1.c +++ b/libavcodec/vaapi_vc1.c @@ -22,6 +22,7 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "hwaccel_internal.h" #include "mpegvideodec.h" #include "vaapi_decode.h" @@ -252,11 +253,11 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t { const VC1Context *v = avctx->priv_data; const MpegEncContext *s = &v->s; - VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; + VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; VAPictureParameterBufferVC1 pic_param; int err; - pic->output_surface = ff_vaapi_get_surface_id(s->current_picture_ptr->f); + pic->output_surface = ff_vaapi_get_surface_id(s->cur_pic.ptr->f); pic_param = (VAPictureParameterBufferVC1) { .forward_reference_picture = VA_INVALID_ID, @@ -373,10 +374,12 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t switch (s->pict_type) { case AV_PICTURE_TYPE_B: - pic_param.backward_reference_picture = ff_vaapi_get_surface_id(s->next_picture.f); + if (s->next_pic.ptr) + pic_param.backward_reference_picture = ff_vaapi_get_surface_id(s->next_pic.ptr->f); // fall-through case AV_PICTURE_TYPE_P: - pic_param.forward_reference_picture = ff_vaapi_get_surface_id(s->last_picture.f); + if (s->last_pic.ptr) + pic_param.forward_reference_picture = ff_vaapi_get_surface_id(s->last_pic.ptr->f); break; } @@ -449,7 +452,7 @@ static int vaapi_vc1_end_frame(AVCodecContext *avctx) { VC1Context *v = avctx->priv_data; MpegEncContext *s = &v->s; - VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; + VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; int ret; ret = ff_vaapi_decode_issue(avctx, pic); @@ -464,7 +467,7 @@ static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, { const VC1Context *v = avctx->priv_data; const MpegEncContext *s = &v->s; - VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; + VAAPIDecodePicture *pic = s->cur_pic.ptr->hwaccel_picture_private; VASliceParameterBufferVC1 slice_param; int mb_height; int err; @@ -489,7 +492,7 @@ static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, }; err = ff_vaapi_decode_make_slice_buffer(avctx, pic, - &slice_param, sizeof(slice_param), + &slice_param, 1, sizeof(slice_param), buffer, size); if (err < 0) { ff_vaapi_decode_cancel(avctx, pic); diff --git a/libavcodec/vaapi_vp8.c b/libavcodec/vaapi_vp8.c index 31137a45b..66fdde1f3 100644 --- a/libavcodec/vaapi_vp8.c +++ b/libavcodec/vaapi_vp8.c @@ -209,7 +209,7 @@ static int vaapi_vp8_decode_slice(AVCodecContext *avctx, for (i = 0; i < 8; i++) sp.partition_size[i+1] = s->coeff_partition_size[i]; - err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, sizeof(sp), data, data_size); + err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, 1, sizeof(sp), data, data_size); if (err) goto fail; diff --git a/libavcodec/vaapi_vp9.c b/libavcodec/vaapi_vp9.c index 9dc7d5e72..a28fc75a5 100644 --- a/libavcodec/vaapi_vp9.c +++ b/libavcodec/vaapi_vp9.c @@ -100,7 +100,7 @@ static int vaapi_vp9_start_frame(AVCodecContext *avctx, } for (i = 0; i < 8; i++) { - if (h->refs[i].f->buf[0]) + if (h->refs[i].f) pic_param.reference_frames[i] = ff_vaapi_get_surface_id(h->refs[i].f); else pic_param.reference_frames[i] = VA_INVALID_ID; @@ -158,7 +158,7 @@ static int vaapi_vp9_decode_slice(AVCodecContext *avctx, } err = ff_vaapi_decode_make_slice_buffer(avctx, pic, - &slice_param, sizeof(slice_param), + &slice_param, 1, sizeof(slice_param), buffer, size); if (err) { ff_vaapi_decode_cancel(avctx, pic); diff --git a/libavcodec/vb.c b/libavcodec/vb.c index 5744faa98..0a9528a8d 100644 --- a/libavcodec/vb.c +++ b/libavcodec/vb.c @@ -24,6 +24,7 @@ * VB Video decoder */ +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/vble.c b/libavcodec/vble.c index d27ab658d..c48feb9a5 100644 --- a/libavcodec/vble.c +++ b/libavcodec/vble.c @@ -25,13 +25,13 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #define BITSTREAM_READER_LE #include "avcodec.h" #include "codec_internal.h" #include "get_bits.h" #include "lossless_videodsp.h" -#include "mathops.h" #include "thread.h" typedef struct VBLEContext { @@ -130,14 +130,6 @@ static int vble_decode_frame(AVCodecContext *avctx, AVFrame *pic, return AVERROR_INVALIDDATA; } - /* Allocate buffer */ - if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0) - return ret; - - /* Set flags */ - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - /* Version should always be 1 */ version = AV_RL32(src); @@ -152,6 +144,10 @@ static int vble_decode_frame(AVCodecContext *avctx, AVFrame *pic, return AVERROR_INVALIDDATA; } + /* Allocate buffer */ + if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0) + return ret; + /* Restore planes. Should be almost identical to Huffyuv's. */ vble_restore_plane(ctx, pic, &gb, 0, offset, avctx->width, avctx->height); diff --git a/libavcodec/vbndec.c b/libavcodec/vbndec.c index 68b223612..a96843f21 100644 --- a/libavcodec/vbndec.c +++ b/libavcodec/vbndec.c @@ -30,6 +30,7 @@ #include "texturedsp.h" #include "vbn.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" typedef struct VBNContext { TextureDSPContext texdsp; @@ -150,9 +151,6 @@ static int vbn_decode_frame(AVCodecContext *avctx, if (ret < 0) goto out; - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; - if (format == VBN_FORMAT_RAW) { uint8_t *flipped = frame->data[0] + frame->linesize[0] * (frame->height - 1); av_image_copy_plane(flipped, -frame->linesize[0], image_buf ? image_buf : gb->buffer, linesize, linesize, frame->height); diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c index e234192fd..d263c70be 100644 --- a/libavcodec/vc1.c +++ b/libavcodec/vc1.c @@ -583,21 +583,23 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex static void rotate_luts(VC1Context *v) { -#define ROTATE(DEF, L, N, C, A) do { \ - if (v->s.pict_type == AV_PICTURE_TYPE_BI || v->s.pict_type == AV_PICTURE_TYPE_B) { \ - C = A; \ - } else { \ + if (v->s.pict_type == AV_PICTURE_TYPE_BI || v->s.pict_type == AV_PICTURE_TYPE_B) { + v->curr_use_ic = &v->aux_use_ic; + v->curr_luty = v->aux_luty; + v->curr_lutuv = v->aux_lutuv; + } else { +#define ROTATE(DEF, L, N, C) do { \ DEF; \ memcpy(&tmp, L , sizeof(tmp)); \ memcpy(L , N , sizeof(tmp)); \ memcpy(N , &tmp, sizeof(tmp)); \ C = N; \ - } \ } while(0) - ROTATE(int tmp, &v->last_use_ic, &v->next_use_ic, v->curr_use_ic, &v->aux_use_ic); - ROTATE(uint8_t tmp[2][256], v->last_luty, v->next_luty, v->curr_luty, v->aux_luty); - ROTATE(uint8_t tmp[2][256], v->last_lutuv, v->next_lutuv, v->curr_lutuv, v->aux_lutuv); + ROTATE(int tmp, &v->last_use_ic, &v->next_use_ic, v->curr_use_ic); + ROTATE(uint8_t tmp[2][256], v->last_luty, v->next_luty, v->curr_luty); + ROTATE(uint8_t tmp[2][256], v->last_lutuv, v->next_lutuv, v->curr_lutuv); + } INIT_LUT(32, 0, v->curr_luty[0], v->curr_lutuv[0], 0); INIT_LUT(32, 0, v->curr_luty[1], v->curr_lutuv[1], 0); @@ -856,7 +858,7 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) v->s.pict_type = (v->fptype & 1) ? AV_PICTURE_TYPE_BI : AV_PICTURE_TYPE_B; else v->s.pict_type = (v->fptype & 1) ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I; - v->s.current_picture_ptr->f->pict_type = v->s.pict_type; + v->s.cur_pic.ptr->f->pict_type = v->s.pict_type; if (!v->pic_header_flag) goto parse_common_info; } diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h index 0e01458c8..185236662 100644 --- a/libavcodec/vc1.h +++ b/libavcodec/vc1.h @@ -293,6 +293,7 @@ typedef struct VC1Context{ uint8_t next_luty[2][256], next_lutuv[2][256]; ///< lookup tables used for intensity compensation uint8_t (*curr_luty)[256] ,(*curr_lutuv)[256]; int last_use_ic, *curr_use_ic, next_use_ic, aux_use_ic; + int last_interlaced, next_interlaced; ///< whether last_pic, next_pic is interlaced int rnd; ///< rounding control int cbptab; diff --git a/libavcodec/vc1_block.c b/libavcodec/vc1_block.c index a6ee4922f..1c422d902 100644 --- a/libavcodec/vc1_block.c +++ b/libavcodec/vc1_block.c @@ -59,9 +59,9 @@ static inline void init_block_index(VC1Context *v) MpegEncContext *s = &v->s; ff_init_block_index(s); if (v->field_mode && !(v->second_field ^ v->tff)) { - s->dest[0] += s->current_picture_ptr->f->linesize[0]; - s->dest[1] += s->current_picture_ptr->f->linesize[1]; - s->dest[2] += s->current_picture_ptr->f->linesize[2]; + s->dest[0] += s->cur_pic.ptr->f->linesize[0]; + s->dest[1] += s->cur_pic.ptr->f->linesize[1]; + s->dest[2] += s->cur_pic.ptr->f->linesize[2]; } } @@ -417,7 +417,7 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, int dqscale_index; /* scale predictors if needed */ - q1 = FFABS(s->current_picture.qscale_table[mb_pos]); + q1 = FFABS(s->cur_pic.qscale_table[mb_pos]); dqscale_index = s->y_dc_scale_table[q1] - 1; if (dqscale_index < 0) return 0; @@ -433,12 +433,12 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, a = dc_val[ - wrap]; if (c_avail && (n != 1 && n != 3)) { - q2 = FFABS(s->current_picture.qscale_table[mb_pos - 1]); + 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; } if (a_avail && (n != 2 && n != 3)) { - q2 = FFABS(s->current_picture.qscale_table[mb_pos - s->mb_stride]); + 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; } @@ -448,7 +448,7 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, off--; if (n != 2) off -= s->mb_stride; - q2 = FFABS(s->current_picture.qscale_table[off]); + 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; } @@ -771,19 +771,19 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, else // top ac_val -= 16 * s->block_wrap[n]; - q1 = s->current_picture.qscale_table[mb_pos]; + q1 = s->cur_pic.qscale_table[mb_pos]; if (n == 3) q2 = q1; else if (dc_pred_dir) { if (n == 1) q2 = q1; else if (c_avail && mb_pos) - q2 = s->current_picture.qscale_table[mb_pos - 1]; + q2 = s->cur_pic.qscale_table[mb_pos - 1]; } else { if (n == 2) q2 = q1; else if (a_avail && mb_pos >= s->mb_stride) - q2 = s->current_picture.qscale_table[mb_pos - s->mb_stride]; + q2 = s->cur_pic.qscale_table[mb_pos - s->mb_stride]; } //AC Decoding @@ -973,11 +973,11 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, else //top ac_val -= 16 * s->block_wrap[n]; - q1 = s->current_picture.qscale_table[mb_pos]; + q1 = s->cur_pic.qscale_table[mb_pos]; if (dc_pred_dir && c_avail && mb_pos) - q2 = s->current_picture.qscale_table[mb_pos - 1]; + q2 = s->cur_pic.qscale_table[mb_pos - 1]; if (!dc_pred_dir && a_avail && mb_pos >= s->mb_stride) - q2 = s->current_picture.qscale_table[mb_pos - s->mb_stride]; + q2 = s->cur_pic.qscale_table[mb_pos - s->mb_stride]; if (dc_pred_dir && n == 1) q2 = q1; if (!dc_pred_dir && n == 2) @@ -1297,6 +1297,7 @@ static int vc1_decode_p_mb(VC1Context *v) int dst_idx, off; int skipped, fourmv; int block_cbp = 0, pat, block_tt = 0, block_intra = 0; + int ret; mquant = v->pq; /* lossy initialization */ @@ -1314,10 +1315,10 @@ static int vc1_decode_p_mb(VC1Context *v) GET_MVDATA(dmv_x, dmv_y); if (s->mb_intra) { - s->current_picture.motion_val[1][s->block_index[0]][0] = 0; - s->current_picture.motion_val[1][s->block_index[0]][1] = 0; + s->cur_pic.motion_val[1][s->block_index[0]][0] = 0; + s->cur_pic.motion_val[1][s->block_index[0]][1] = 0; } - s->current_picture.mb_type[mb_pos] = s->mb_intra ? MB_TYPE_INTRA : MB_TYPE_16x16; + 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); /* FIXME Set DC val for inter block ? */ @@ -1334,7 +1335,7 @@ static int vc1_decode_p_mb(VC1Context *v) mquant = v->pq; cbp = 0; } - s->current_picture.qscale_table[mb_pos] = mquant; + s->cur_pic.qscale_table[mb_pos] = mquant; if (!v->ttmbf && !s->mb_intra && mb_has_coeffs) ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index], @@ -1355,8 +1356,10 @@ static int vc1_decode_p_mb(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, - (i & 4) ? v->codingset2 : v->codingset); + ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[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(v->block[v->cur_blk_idx][block_map[i]]); @@ -1383,8 +1386,8 @@ static int vc1_decode_p_mb(VC1Context *v) v->mb_type[0][s->block_index[i]] = 0; s->dc_val[0][s->block_index[i]] = 0; } - s->current_picture.mb_type[mb_pos] = MB_TYPE_SKIP; - s->current_picture.qscale_table[mb_pos] = 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_mc_1mv(v, 0); } @@ -1427,7 +1430,7 @@ static int vc1_decode_p_mb(VC1Context *v) if (!intra_count && !coded_inter) goto end; GET_MQUANT(); - s->current_picture.qscale_table[mb_pos] = mquant; + s->cur_pic.qscale_table[mb_pos] = mquant; /* test if block is intra and has pred */ { int intrapred = 0; @@ -1458,8 +1461,10 @@ static int vc1_decode_p_mb(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - 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); + 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); + if (ret < 0) + return ret; if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[i]]); @@ -1484,7 +1489,7 @@ static int vc1_decode_p_mb(VC1Context *v) } } else { // skipped MB s->mb_intra = 0; - s->current_picture.qscale_table[mb_pos] = 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; @@ -1494,7 +1499,7 @@ static int vc1_decode_p_mb(VC1Context *v) ff_vc1_mc_4mv_luma(v, i, 0, 0); } ff_vc1_mc_4mv_chroma(v, 0); - s->current_picture.qscale_table[mb_pos] = 0; + s->cur_pic.qscale_table[mb_pos] = 0; } } end: @@ -1530,6 +1535,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) int block_cbp = 0, pat, block_tt = 0; int idx_mbmode = 0, mvbp; int fieldtx; + int ret; mquant = v->pq; /* Lossy initialization */ @@ -1574,19 +1580,19 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) } if (ff_vc1_mbmode_intfrp[v->fourmvswitch][idx_mbmode][0] == MV_PMODE_INTFR_INTRA) { // intra MB for (i = 0; i < 4; i++) { - s->current_picture.motion_val[1][s->block_index[i]][0] = 0; - s->current_picture.motion_val[1][s->block_index[i]][1] = 0; + s->cur_pic.motion_val[1][s->block_index[i]][0] = 0; + s->cur_pic.motion_val[1][s->block_index[i]][1] = 0; } v->is_intra[s->mb_x] = 0x3f; // Set the bitfield to all 1. s->mb_intra = 1; - s->current_picture.mb_type[mb_pos] = MB_TYPE_INTRA; + s->cur_pic.mb_type[mb_pos] = MB_TYPE_INTRA; 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); v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); GET_MQUANT(); - s->current_picture.qscale_table[mb_pos] = 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)]; @@ -1602,15 +1608,13 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, - (i & 4) ? v->codingset2 : v->codingset); + ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[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(v->block[v->cur_blk_idx][block_map[i]]); - if (i < 4) - off = (fieldtx) ? ((i & 1) * 8) + ((i & 2) >> 1) * s->linesize : (i & 1) * 8 + 4 * (i & 2) * s->linesize; - else - off = 0; block_cbp |= 0xf << (i << 2); } @@ -1670,7 +1674,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) } if (cbp) GET_MQUANT(); // p. 227 - s->current_picture.qscale_table[mb_pos] = mquant; + s->cur_pic.qscale_table[mb_pos] = mquant; 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++) { @@ -1701,8 +1705,8 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) v->mb_type[0][s->block_index[i]] = 0; s->dc_val[0][s->block_index[i]] = 0; } - s->current_picture.mb_type[mb_pos] = MB_TYPE_SKIP; - s->current_picture.qscale_table[mb_pos] = 0; + s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP; + s->cur_pic.qscale_table[mb_pos] = 0; v->blk_mv_type[s->block_index[0]] = 0; v->blk_mv_type[s->block_index[1]] = 0; v->blk_mv_type[s->block_index[2]] = 0; @@ -1739,6 +1743,7 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) int pred_flag = 0; int block_cbp = 0, pat, block_tt = 0; int idx_mbmode = 0; + int ret; mquant = v->pq; /* Lossy initialization */ @@ -1746,11 +1751,11 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) if (idx_mbmode <= 1) { // intra MB v->is_intra[s->mb_x] = 0x3f; // Set the bitfield to all 1. s->mb_intra = 1; - s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][0] = 0; - s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][1] = 0; - s->current_picture.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; + s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][0] = 0; + s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][1] = 0; + s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; GET_MQUANT(); - s->current_picture.qscale_table[mb_pos] = 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)]; @@ -1770,17 +1775,18 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, - (i & 4) ? v->codingset2 : v->codingset); + ret = vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[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(v->block[v->cur_blk_idx][block_map[i]]); - off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize); block_cbp |= 0xf << (i << 2); } } else { s->mb_intra = v->is_intra[s->mb_x] = 0; - s->current_picture.mb_type[mb_pos + v->mb_off] = MB_TYPE_16x16; + 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; if (idx_mbmode <= 5) { // 1-MV @@ -1808,7 +1814,7 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) if (cbp) { GET_MQUANT(); } - s->current_picture.qscale_table[mb_pos] = mquant; + s->cur_pic.qscale_table[mb_pos] = mquant; if (!v->ttmbf && cbp) { ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index], VC1_TTMB_VLC_BITS, 2); } @@ -1862,6 +1868,7 @@ static int vc1_decode_b_mb(VC1Context *v) int skipped, direct; int dmv_x[2], dmv_y[2]; int bmvtype = BMV_TYPE_BACKWARD; + int ret; mquant = v->pq; /* lossy initialization */ s->mb_intra = 0; @@ -1880,7 +1887,7 @@ static int vc1_decode_b_mb(VC1Context *v) v->mb_type[0][s->block_index[i]] = 0; s->dc_val[0][s->block_index[i]] = 0; } - s->current_picture.qscale_table[mb_pos] = 0; + s->cur_pic.qscale_table[mb_pos] = 0; if (!direct) { if (!skipped) { @@ -1917,7 +1924,7 @@ static int vc1_decode_b_mb(VC1Context *v) cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); GET_MQUANT(); s->mb_intra = 0; - s->current_picture.qscale_table[mb_pos] = mquant; + s->cur_pic.qscale_table[mb_pos] = mquant; if (!v->ttmbf) ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index], VC1_TTMB_VLC_BITS, 2); dmv_x[0] = dmv_y[0] = dmv_x[1] = dmv_y[1] = 0; @@ -1932,7 +1939,7 @@ static int vc1_decode_b_mb(VC1Context *v) } if (s->mb_intra && !mb_has_coeffs) { GET_MQUANT(); - s->current_picture.qscale_table[mb_pos] = mquant; + s->cur_pic.qscale_table[mb_pos] = mquant; s->ac_pred = get_bits1(gb); cbp = 0; ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype); @@ -1954,7 +1961,7 @@ static int vc1_decode_b_mb(VC1Context *v) s->ac_pred = get_bits1(gb); cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc, VC1_CBPCY_P_VLC_BITS, 2); GET_MQUANT(); - s->current_picture.qscale_table[mb_pos] = mquant; + s->cur_pic.qscale_table[mb_pos] = mquant; if (!v->ttmbf && !s->mb_intra && mb_has_coeffs) ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index], VC1_TTMB_VLC_BITS, 2); } @@ -1974,8 +1981,10 @@ static int vc1_decode_b_mb(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, s->block[i], i, val, mquant, - (i & 4) ? v->codingset2 : v->codingset); + ret = vc1_decode_intra_block(v, s->block[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]); @@ -2021,6 +2030,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) int bmvtype = BMV_TYPE_BACKWARD; int block_cbp = 0, pat, block_tt = 0; int idx_mbmode; + int ret; mquant = v->pq; /* Lossy initialization */ s->mb_intra = 0; @@ -2029,11 +2039,11 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) if (idx_mbmode <= 1) { // intra MB v->is_intra[s->mb_x] = 0x3f; // Set the bitfield to all 1. s->mb_intra = 1; - s->current_picture.motion_val[1][s->block_index[0]][0] = 0; - s->current_picture.motion_val[1][s->block_index[0]][1] = 0; - s->current_picture.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; + s->cur_pic.motion_val[1][s->block_index[0]][0] = 0; + s->cur_pic.motion_val[1][s->block_index[0]][1] = 0; + s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; GET_MQUANT(); - s->current_picture.qscale_table[mb_pos] = 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)]; @@ -2053,8 +2063,10 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, s->block[i], i, val, mquant, - (i & 4) ? v->codingset2 : v->codingset); + ret = vc1_decode_intra_block(v, s->block[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]); @@ -2069,7 +2081,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) } } else { s->mb_intra = v->is_intra[s->mb_x] = 0; - s->current_picture.mb_type[mb_pos + v->mb_off] = MB_TYPE_16x16; + 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; if (v->fmb_is_raw) @@ -2106,7 +2118,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) if (bmvtype == BMV_TYPE_DIRECT) { dmv_x[0] = dmv_y[0] = pred_flag[0] = 0; dmv_x[1] = dmv_y[1] = pred_flag[0] = 0; - if (!s->next_picture_ptr->field_picture) { + if (!s->next_pic.ptr->field_picture) { av_log(s->avctx, AV_LOG_ERROR, "Mixed field/frame direct mode not supported\n"); return AVERROR_INVALIDDATA; } @@ -2138,7 +2150,7 @@ static int vc1_decode_b_mb_intfi(VC1Context *v) if (cbp) { GET_MQUANT(); } - s->current_picture.qscale_table[mb_pos] = mquant; + s->cur_pic.qscale_table[mb_pos] = mquant; if (!v->ttmbf && cbp) { ttmb = get_vlc2(gb, ff_vc1_ttmb_vlc[v->tt_index], VC1_TTMB_VLC_BITS, 2); } @@ -2191,6 +2203,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) int stride_y, fieldtx; int bmvtype = BMV_TYPE_BACKWARD; int dir, dir2; + int ret; mquant = v->pq; /* Lossy initialization */ s->mb_intra = 0; @@ -2217,21 +2230,21 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) if (ff_vc1_mbmode_intfrp[0][idx_mbmode][0] == MV_PMODE_INTFR_INTRA) { // intra MB for (i = 0; i < 4; i++) { - s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = 0; - s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = 0; - s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = 0; - s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = 0; + s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0] = 0; + s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1] = 0; + s->mv[1][i][0] = s->cur_pic.motion_val[1][s->block_index[i]][0] = 0; + s->mv[1][i][1] = s->cur_pic.motion_val[1][s->block_index[i]][1] = 0; } v->is_intra[s->mb_x] = 0x3f; // Set the bitfield to all 1. s->mb_intra = 1; - s->current_picture.mb_type[mb_pos] = MB_TYPE_INTRA; + s->cur_pic.mb_type[mb_pos] = MB_TYPE_INTRA; 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); v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); GET_MQUANT(); - s->current_picture.qscale_table[mb_pos] = 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)]; @@ -2247,8 +2260,10 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, s->block[i], i, val, mquant, - (i & 4) ? v->codingset2 : v->codingset); + ret = vc1_decode_intra_block(v, s->block[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]); @@ -2272,31 +2287,31 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) direct = v->direct_mb_plane[mb_pos]; if (direct) { - if (s->next_picture_ptr->field_picture) + if (s->next_pic.ptr->field_picture) av_log(s->avctx, AV_LOG_WARNING, "Mixed frame/field direct mode not supported\n"); - s->mv[0][0][0] = s->current_picture.motion_val[0][s->block_index[0]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][0], v->bfraction, 0, s->quarter_sample); - s->mv[0][0][1] = s->current_picture.motion_val[0][s->block_index[0]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][1], v->bfraction, 0, s->quarter_sample); - s->mv[1][0][0] = s->current_picture.motion_val[1][s->block_index[0]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][0], v->bfraction, 1, s->quarter_sample); - s->mv[1][0][1] = s->current_picture.motion_val[1][s->block_index[0]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][1], v->bfraction, 1, s->quarter_sample); + s->mv[0][0][0] = s->cur_pic.motion_val[0][s->block_index[0]][0] = scale_mv(s->next_pic.motion_val[1][s->block_index[0]][0], v->bfraction, 0, s->quarter_sample); + s->mv[0][0][1] = s->cur_pic.motion_val[0][s->block_index[0]][1] = scale_mv(s->next_pic.motion_val[1][s->block_index[0]][1], v->bfraction, 0, s->quarter_sample); + s->mv[1][0][0] = s->cur_pic.motion_val[1][s->block_index[0]][0] = scale_mv(s->next_pic.motion_val[1][s->block_index[0]][0], v->bfraction, 1, s->quarter_sample); + s->mv[1][0][1] = s->cur_pic.motion_val[1][s->block_index[0]][1] = scale_mv(s->next_pic.motion_val[1][s->block_index[0]][1], v->bfraction, 1, s->quarter_sample); if (twomv) { - s->mv[0][2][0] = s->current_picture.motion_val[0][s->block_index[2]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][0], v->bfraction, 0, s->quarter_sample); - s->mv[0][2][1] = s->current_picture.motion_val[0][s->block_index[2]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][1], v->bfraction, 0, s->quarter_sample); - s->mv[1][2][0] = s->current_picture.motion_val[1][s->block_index[2]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][0], v->bfraction, 1, s->quarter_sample); - s->mv[1][2][1] = s->current_picture.motion_val[1][s->block_index[2]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][1], v->bfraction, 1, s->quarter_sample); + s->mv[0][2][0] = s->cur_pic.motion_val[0][s->block_index[2]][0] = scale_mv(s->next_pic.motion_val[1][s->block_index[2]][0], v->bfraction, 0, s->quarter_sample); + s->mv[0][2][1] = s->cur_pic.motion_val[0][s->block_index[2]][1] = scale_mv(s->next_pic.motion_val[1][s->block_index[2]][1], v->bfraction, 0, s->quarter_sample); + s->mv[1][2][0] = s->cur_pic.motion_val[1][s->block_index[2]][0] = scale_mv(s->next_pic.motion_val[1][s->block_index[2]][0], v->bfraction, 1, s->quarter_sample); + s->mv[1][2][1] = s->cur_pic.motion_val[1][s->block_index[2]][1] = scale_mv(s->next_pic.motion_val[1][s->block_index[2]][1], v->bfraction, 1, s->quarter_sample); for (i = 1; i < 4; i += 2) { - s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = s->mv[0][i-1][0]; - s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = s->mv[0][i-1][1]; - s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = s->mv[1][i-1][0]; - s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = s->mv[1][i-1][1]; + s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0] = s->mv[0][i-1][0]; + s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1] = s->mv[0][i-1][1]; + s->mv[1][i][0] = s->cur_pic.motion_val[1][s->block_index[i]][0] = s->mv[1][i-1][0]; + s->mv[1][i][1] = s->cur_pic.motion_val[1][s->block_index[i]][1] = s->mv[1][i-1][1]; } } else { for (i = 1; i < 4; i++) { - s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = s->mv[0][0][0]; - s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = s->mv[0][0][1]; - s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = s->mv[1][0][0]; - s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = s->mv[1][0][1]; + s->mv[0][i][0] = s->cur_pic.motion_val[0][s->block_index[i]][0] = s->mv[0][0][0]; + s->mv[0][i][1] = s->cur_pic.motion_val[0][s->block_index[i]][1] = s->mv[0][0][1]; + s->mv[1][i][0] = s->cur_pic.motion_val[1][s->block_index[i]][0] = s->mv[1][0][0]; + s->mv[1][i][1] = s->cur_pic.motion_val[1][s->block_index[i]][1] = s->mv[1][0][1]; } } } @@ -2398,10 +2413,10 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) if (mvsw) { for (i = 0; i < 2; i++) { - s->mv[dir][i+2][0] = s->mv[dir][i][0] = s->current_picture.motion_val[dir][s->block_index[i+2]][0] = s->current_picture.motion_val[dir][s->block_index[i]][0]; - s->mv[dir][i+2][1] = s->mv[dir][i][1] = s->current_picture.motion_val[dir][s->block_index[i+2]][1] = s->current_picture.motion_val[dir][s->block_index[i]][1]; - s->mv[dir2][i+2][0] = s->mv[dir2][i][0] = s->current_picture.motion_val[dir2][s->block_index[i]][0] = s->current_picture.motion_val[dir2][s->block_index[i+2]][0]; - s->mv[dir2][i+2][1] = s->mv[dir2][i][1] = s->current_picture.motion_val[dir2][s->block_index[i]][1] = s->current_picture.motion_val[dir2][s->block_index[i+2]][1]; + s->mv[dir][i+2][0] = s->mv[dir][i][0] = s->cur_pic.motion_val[dir][s->block_index[i+2]][0] = s->cur_pic.motion_val[dir][s->block_index[i]][0]; + s->mv[dir][i+2][1] = s->mv[dir][i][1] = s->cur_pic.motion_val[dir][s->block_index[i+2]][1] = s->cur_pic.motion_val[dir][s->block_index[i]][1]; + s->mv[dir2][i+2][0] = s->mv[dir2][i][0] = s->cur_pic.motion_val[dir2][s->block_index[i]][0] = s->cur_pic.motion_val[dir2][s->block_index[i+2]][0]; + s->mv[dir2][i+2][1] = s->mv[dir2][i][1] = s->cur_pic.motion_val[dir2][s->block_index[i]][1] = s->cur_pic.motion_val[dir2][s->block_index[i+2]][1]; } } else { ff_vc1_pred_mv_intfr(v, 0, 0, 0, 2, v->range_x, v->range_y, !dir); @@ -2428,15 +2443,15 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) v->blk_mv_type[s->block_index[3]] = 1; ff_vc1_pred_mv_intfr(v, 0, 0, 0, 2, v->range_x, v->range_y, !dir); for (i = 0; i < 2; i++) { - s->mv[!dir][i+2][0] = s->mv[!dir][i][0] = s->current_picture.motion_val[!dir][s->block_index[i+2]][0] = s->current_picture.motion_val[!dir][s->block_index[i]][0]; - s->mv[!dir][i+2][1] = s->mv[!dir][i][1] = s->current_picture.motion_val[!dir][s->block_index[i+2]][1] = s->current_picture.motion_val[!dir][s->block_index[i]][1]; + s->mv[!dir][i+2][0] = s->mv[!dir][i][0] = s->cur_pic.motion_val[!dir][s->block_index[i+2]][0] = s->cur_pic.motion_val[!dir][s->block_index[i]][0]; + s->mv[!dir][i+2][1] = s->mv[!dir][i][1] = s->cur_pic.motion_val[!dir][s->block_index[i+2]][1] = s->cur_pic.motion_val[!dir][s->block_index[i]][1]; } ff_vc1_mc_1mv(v, dir); } if (cbp) GET_MQUANT(); // p. 227 - s->current_picture.qscale_table[mb_pos] = mquant; + s->cur_pic.qscale_table[mb_pos] = mquant; 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++) { @@ -2467,8 +2482,8 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) v->mb_type[0][s->block_index[i]] = 0; s->dc_val[0][s->block_index[i]] = 0; } - s->current_picture.mb_type[mb_pos] = MB_TYPE_SKIP; - s->current_picture.qscale_table[mb_pos] = 0; + s->cur_pic.mb_type[mb_pos] = MB_TYPE_SKIP; + s->cur_pic.qscale_table[mb_pos] = 0; v->blk_mv_type[s->block_index[0]] = 0; v->blk_mv_type[s->block_index[1]] = 0; v->blk_mv_type[s->block_index[2]] = 0; @@ -2486,10 +2501,10 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) if (mvsw) dir2 = !dir; for (i = 0; i < 2; i++) { - s->mv[dir][i+2][0] = s->mv[dir][i][0] = s->current_picture.motion_val[dir][s->block_index[i+2]][0] = s->current_picture.motion_val[dir][s->block_index[i]][0]; - s->mv[dir][i+2][1] = s->mv[dir][i][1] = s->current_picture.motion_val[dir][s->block_index[i+2]][1] = s->current_picture.motion_val[dir][s->block_index[i]][1]; - s->mv[dir2][i+2][0] = s->mv[dir2][i][0] = s->current_picture.motion_val[dir2][s->block_index[i]][0] = s->current_picture.motion_val[dir2][s->block_index[i+2]][0]; - s->mv[dir2][i+2][1] = s->mv[dir2][i][1] = s->current_picture.motion_val[dir2][s->block_index[i]][1] = s->current_picture.motion_val[dir2][s->block_index[i+2]][1]; + s->mv[dir][i+2][0] = s->mv[dir][i][0] = s->cur_pic.motion_val[dir][s->block_index[i+2]][0] = s->cur_pic.motion_val[dir][s->block_index[i]][0]; + s->mv[dir][i+2][1] = s->mv[dir][i][1] = s->cur_pic.motion_val[dir][s->block_index[i+2]][1] = s->cur_pic.motion_val[dir][s->block_index[i]][1]; + s->mv[dir2][i+2][0] = s->mv[dir2][i][0] = s->cur_pic.motion_val[dir2][s->block_index[i]][0] = s->cur_pic.motion_val[dir2][s->block_index[i+2]][0]; + s->mv[dir2][i+2][1] = s->mv[dir2][i][1] = s->cur_pic.motion_val[dir2][s->block_index[i]][1] = s->cur_pic.motion_val[dir2][s->block_index[i+2]][1]; } } else { v->blk_mv_type[s->block_index[0]] = 1; @@ -2498,8 +2513,8 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) v->blk_mv_type[s->block_index[3]] = 1; ff_vc1_pred_mv_intfr(v, 0, 0, 0, 2, v->range_x, v->range_y, !dir); for (i = 0; i < 2; i++) { - s->mv[!dir][i+2][0] = s->mv[!dir][i][0] = s->current_picture.motion_val[!dir][s->block_index[i+2]][0] = s->current_picture.motion_val[!dir][s->block_index[i]][0]; - s->mv[!dir][i+2][1] = s->mv[!dir][i][1] = s->current_picture.motion_val[!dir][s->block_index[i+2]][1] = s->current_picture.motion_val[!dir][s->block_index[i]][1]; + s->mv[!dir][i+2][0] = s->mv[!dir][i][0] = s->cur_pic.motion_val[!dir][s->block_index[i+2]][0] = s->cur_pic.motion_val[!dir][s->block_index[i]][0]; + s->mv[!dir][i+2][1] = s->mv[!dir][i][1] = s->cur_pic.motion_val[!dir][s->block_index[i+2]][1] = s->cur_pic.motion_val[!dir][s->block_index[i]][1]; } } } @@ -2568,11 +2583,11 @@ static void vc1_decode_i_blocks(VC1Context *v) update_block_index(s); s->bdsp.clear_blocks(v->block[v->cur_blk_idx][0]); mb_pos = s->mb_x + s->mb_y * s->mb_width; - s->current_picture.mb_type[mb_pos] = MB_TYPE_INTRA; - s->current_picture.qscale_table[mb_pos] = v->pq; + s->cur_pic.mb_type[mb_pos] = MB_TYPE_INTRA; + s->cur_pic.qscale_table[mb_pos] = v->pq; for (int i = 0; i < 4; i++) { - s->current_picture.motion_val[1][s->block_index[i]][0] = 0; - s->current_picture.motion_val[1][s->block_index[i]][1] = 0; + s->cur_pic.motion_val[1][s->block_index[i]][0] = 0; + s->cur_pic.motion_val[1][s->block_index[i]][1] = 0; } // do actual MB decoding and displaying @@ -2680,14 +2695,12 @@ static int vc1_decode_i_blocks_adv(VC1Context *v) } // do frame decode - s->mb_x = s->mb_y = 0; s->mb_intra = 1; s->first_slice_line = 1; + s->mb_x = 0; s->mb_y = s->start_mb_y; if (s->start_mb_y) { - s->mb_x = 0; - init_block_index(v); - memset(&s->coded_block[s->block_index[0] - s->b8_stride], 0, + memset(&s->coded_block[(2 * s->mb_y - 1) * s->b8_stride - 2], 0, (1 + s->b8_stride) * sizeof(*s->coded_block)); } for (; s->mb_y < s->end_mb_y; s->mb_y++) { @@ -2698,10 +2711,10 @@ static int vc1_decode_i_blocks_adv(VC1Context *v) update_block_index(s); s->bdsp.clear_blocks(v->block[v->cur_blk_idx][0]); mb_pos = s->mb_x + s->mb_y * s->mb_stride; - s->current_picture.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; + s->cur_pic.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; for (int i = 0; i < 4; i++) { - s->current_picture.motion_val[1][s->block_index[i] + v->blocks_off][0] = 0; - s->current_picture.motion_val[1][s->block_index[i] + v->blocks_off][1] = 0; + s->cur_pic.motion_val[1][s->block_index[i] + v->blocks_off][0] = 0; + s->cur_pic.motion_val[1][s->block_index[i] + v->blocks_off][1] = 0; } // do actual MB decoding and displaying @@ -2724,7 +2737,7 @@ static int vc1_decode_i_blocks_adv(VC1Context *v) GET_MQUANT(); - s->current_picture.qscale_table[mb_pos] = 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)]; @@ -2782,6 +2795,7 @@ static void vc1_decode_p_blocks(VC1Context *v) { MpegEncContext *s = &v->s; int apply_loop_filter; + int ret; /* select coding mode used for VLC tables selection */ switch (v->c_ac_table_index) { @@ -2824,22 +2838,22 @@ static void vc1_decode_p_blocks(VC1Context *v) } if (v->fcm == ILACE_FIELD) { - vc1_decode_p_mb_intfi(v); + ret = vc1_decode_p_mb_intfi(v); if (apply_loop_filter) ff_vc1_p_loop_filter(v); } else if (v->fcm == ILACE_FRAME) { - vc1_decode_p_mb_intfr(v); + ret = vc1_decode_p_mb_intfr(v); if (apply_loop_filter) ff_vc1_p_intfr_loop_filter(v); } else { - vc1_decode_p_mb(v); + ret = vc1_decode_p_mb(v); if (apply_loop_filter) ff_vc1_p_loop_filter(v); } - if (get_bits_left(&s->gb) < 0 || get_bits_count(&s->gb) < 0) { + if (ret < 0 || get_bits_left(&s->gb) < 0 || get_bits_count(&s->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", + 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); return; } @@ -2948,7 +2962,7 @@ static void vc1_decode_skip_blocks(VC1Context *v) { MpegEncContext *s = &v->s; - if (!v->s.last_picture.f->data[0]) + if (!v->s.last_pic.data[0]) return; ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_width - 1, s->end_mb_y - 1, ER_MB_END); @@ -2957,9 +2971,9 @@ static void vc1_decode_skip_blocks(VC1Context *v) s->mb_x = 0; init_block_index(v); update_block_index(s); - memcpy(s->dest[0], s->last_picture.f->data[0] + s->mb_y * 16 * s->linesize, s->linesize * 16); - memcpy(s->dest[1], s->last_picture.f->data[1] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8); - memcpy(s->dest[2], s->last_picture.f->data[2] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8); + memcpy(s->dest[0], s->last_pic.data[0] + s->mb_y * 16 * s->linesize, s->linesize * 16); + memcpy(s->dest[1], s->last_pic.data[1] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8); + memcpy(s->dest[2], s->last_pic.data[2] + s->mb_y * 8 * s->uvlinesize, s->uvlinesize * 8); s->first_slice_line = 0; } } @@ -2969,7 +2983,7 @@ void ff_vc1_decode_blocks(VC1Context *v) v->s.esc3_level_length = 0; if (v->x8_type) { - ff_intrax8_decode_picture(&v->x8, &v->s.current_picture, + ff_intrax8_decode_picture(&v->x8, v->s.cur_pic.ptr, &v->s.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); diff --git a/libavcodec/vc1_loopfilter.c b/libavcodec/vc1_loopfilter.c index ee694ede2..e788d1890 100644 --- a/libavcodec/vc1_loopfilter.c +++ b/libavcodec/vc1_loopfilter.c @@ -413,9 +413,10 @@ static av_always_inline void vc1_p_h_loop_filter(VC1Context *v, uint8_t *dest, u } } -static av_always_inline void vc1_p_v_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, - uint8_t *is_intra, int16_t (*mv)[2], uint8_t *mv_f, - int *ttblk, uint32_t flags, int block_num) +static av_always_inline +void vc1_p_v_loop_filter(VC1Context *v, uint8_t *dest, const uint32_t *cbp, + const uint8_t *is_intra, int16_t (*mv)[2], const uint8_t *mv_f, + const int *ttblk, uint32_t flags, int block_num) { MpegEncContext *s = &v->s; int pq = v->pq; @@ -500,7 +501,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 1 + v->mb_off] : &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], ttblk, @@ -520,7 +521,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride + v->mb_off] : &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], ttblk, @@ -543,7 +544,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 1 + v->mb_off] : &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], ttblk, @@ -562,7 +563,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 2 + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 2 + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - 1 + v->mb_off] : &v->mv_f[0][s->block_index[i] - 2 + v->blocks_off], ttblk, @@ -583,7 +584,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride + v->mb_off] : &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], ttblk, @@ -602,7 +603,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] + v->mb_off] : &v->mv_f[0][s->block_index[i] + v->blocks_off], ttblk, @@ -625,7 +626,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 4 + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 4 + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 2 + v->mb_off] : &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 4 + v->blocks_off], ttblk, @@ -646,7 +647,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 1 + v->mb_off] : &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], ttblk, @@ -665,7 +666,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride + v->mb_off] : &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], ttblk, @@ -688,7 +689,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 4 + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 4 + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 2 + v->mb_off] : &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 4 + v->blocks_off], ttblk, @@ -709,7 +710,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 1 + v->mb_off] : &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], ttblk, @@ -728,7 +729,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride + v->mb_off] : &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], ttblk, @@ -749,7 +750,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 4 + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 4 + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - 2 + v->mb_off] : &v->mv_f[0][s->block_index[i] - 4 + v->blocks_off], ttblk, @@ -770,7 +771,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] - 2 + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] - 2 + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] - 1 + v->mb_off] : &v->mv_f[0][s->block_index[i] - 2 + v->blocks_off], ttblk, @@ -789,7 +790,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) cbp, is_intra, i > 3 ? uvmv : - &s->current_picture.motion_val[0][s->block_index[i] + v->blocks_off], + &s->cur_pic.motion_val[0][s->block_index[i] + v->blocks_off], i > 3 ? &v->mv_f[0][s->block_index[i] + v->mb_off] : &v->mv_f[0][s->block_index[i] + v->blocks_off], ttblk, @@ -799,7 +800,7 @@ void ff_vc1_p_loop_filter(VC1Context *v) } } -static av_always_inline void vc1_p_h_intfr_loop_filter(VC1Context *v, uint8_t *dest, int *ttblk, +static av_always_inline void vc1_p_h_intfr_loop_filter(VC1Context *v, uint8_t *dest, const int *ttblk, uint32_t flags, uint8_t fieldtx, int block_num) { MpegEncContext *s = &v->s; @@ -849,8 +850,9 @@ static av_always_inline void vc1_p_h_intfr_loop_filter(VC1Context *v, uint8_t *d } } -static av_always_inline void vc1_p_v_intfr_loop_filter(VC1Context *v, uint8_t *dest, int *ttblk, - uint32_t flags, uint8_t fieldtx, int block_num) +static av_always_inline +void vc1_p_v_intfr_loop_filter(VC1Context *v, uint8_t *dest, const int *ttblk, + uint32_t flags, uint8_t fieldtx, int block_num) { MpegEncContext *s = &v->s; int pq = v->pq; @@ -1109,8 +1111,9 @@ void ff_vc1_p_intfr_loop_filter(VC1Context *v) } } -static av_always_inline void vc1_b_h_intfi_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, - int *ttblk, uint32_t flags, int block_num) +static av_always_inline +void vc1_b_h_intfi_loop_filter(VC1Context *v, uint8_t *dest, const uint32_t *cbp, + const int *ttblk, uint32_t flags, int block_num) { MpegEncContext *s = &v->s; int pq = v->pq; @@ -1138,8 +1141,9 @@ static av_always_inline void vc1_b_h_intfi_loop_filter(VC1Context *v, uint8_t *d } } -static av_always_inline void vc1_b_v_intfi_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, - int *ttblk, uint32_t flags, int block_num) +static av_always_inline +void vc1_b_v_intfi_loop_filter(VC1Context *v, uint8_t *dest, const uint32_t *cbp, + const int *ttblk, uint32_t flags, int block_num) { MpegEncContext *s = &v->s; int pq = v->pq; @@ -1171,7 +1175,7 @@ void ff_vc1_b_intfi_loop_filter(VC1Context *v) MpegEncContext *s = &v->s; int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; uint8_t *dest; - uint32_t *cbp; + const uint32_t *cbp; int *ttblk; uint32_t flags = 0; int i; diff --git a/libavcodec/vc1_mc.c b/libavcodec/vc1_mc.c index 8f0b3f6fa..9adb71c7a 100644 --- a/libavcodec/vc1_mc.c +++ b/libavcodec/vc1_mc.c @@ -58,7 +58,7 @@ static av_always_inline void vc1_scale_chroma(uint8_t *srcU, uint8_t *srcV, } static av_always_inline void vc1_lut_scale_luma(uint8_t *srcY, - uint8_t *lut1, uint8_t *lut2, + const uint8_t *lut1, const uint8_t *lut2, int k, int linesize) { int i, j; @@ -78,7 +78,7 @@ static av_always_inline void vc1_lut_scale_luma(uint8_t *srcY, } static av_always_inline void vc1_lut_scale_chroma(uint8_t *srcU, uint8_t *srcV, - uint8_t *lut1, uint8_t *lut2, + const uint8_t *lut1, const uint8_t *lut2, int k, int uvlinesize) { int i, j; @@ -177,18 +177,18 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) int dxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y; int v_edge_pos = s->v_edge_pos >> v->field_mode; int i; - uint8_t (*luty)[256], (*lutuv)[256]; + const uint8_t (*luty)[256], (*lutuv)[256]; int use_ic; int interlace; int linesize, uvlinesize; if ((!v->field_mode || (v->ref_field_type[dir] == 1 && v->cur_field_type == 1)) && - !v->s.last_picture.f->data[0]) + !v->s.last_pic.data[0]) return; - linesize = s->current_picture_ptr->f->linesize[0]; - uvlinesize = s->current_picture_ptr->f->linesize[1]; + linesize = s->cur_pic.ptr->f->linesize[0]; + uvlinesize = s->cur_pic.ptr->f->linesize[1]; mx = s->mv[dir][0][0]; my = s->mv[dir][0][1]; @@ -196,8 +196,8 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) // store motion vectors for further use in B-frames if (s->pict_type == AV_PICTURE_TYPE_P) { for (i = 0; i < 4; i++) { - s->current_picture.motion_val[1][s->block_index[i] + v->blocks_off][0] = mx; - s->current_picture.motion_val[1][s->block_index[i] + v->blocks_off][1] = my; + s->cur_pic.motion_val[1][s->block_index[i] + v->blocks_off][0] = mx; + s->cur_pic.motion_val[1][s->block_index[i] + v->blocks_off][1] = my; } } @@ -219,30 +219,30 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) } if (!dir) { if (v->field_mode && (v->cur_field_type != v->ref_field_type[dir]) && v->second_field) { - srcY = s->current_picture.f->data[0]; - srcU = s->current_picture.f->data[1]; - srcV = s->current_picture.f->data[2]; + srcY = s->cur_pic.data[0]; + srcU = s->cur_pic.data[1]; + srcV = s->cur_pic.data[2]; luty = v->curr_luty; lutuv = v->curr_lutuv; use_ic = *v->curr_use_ic; interlace = 1; } else { - srcY = s->last_picture.f->data[0]; - srcU = s->last_picture.f->data[1]; - srcV = s->last_picture.f->data[2]; + srcY = s->last_pic.data[0]; + srcU = s->last_pic.data[1]; + srcV = s->last_pic.data[2]; luty = v->last_luty; lutuv = v->last_lutuv; use_ic = v->last_use_ic; - interlace = !!(s->last_picture.f->flags & AV_FRAME_FLAG_INTERLACED); + interlace = v->last_interlaced; } } else { - srcY = s->next_picture.f->data[0]; - srcU = s->next_picture.f->data[1]; - srcV = s->next_picture.f->data[2]; + srcY = s->next_pic.data[0]; + srcU = s->next_pic.data[1]; + srcV = s->next_pic.data[2]; luty = v->next_luty; lutuv = v->next_lutuv; use_ic = v->next_use_ic; - interlace = !!(s->next_picture.f->flags & AV_FRAME_FLAG_INTERLACED); + interlace = v->next_interlaced; } if (!srcY || !srcU) { @@ -457,38 +457,38 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg) int off; int fieldmv = (v->fcm == ILACE_FRAME) ? v->blk_mv_type[s->block_index[n]] : 0; int v_edge_pos = s->v_edge_pos >> v->field_mode; - uint8_t (*luty)[256]; + const uint8_t (*luty)[256]; int use_ic; int interlace; int linesize; if ((!v->field_mode || (v->ref_field_type[dir] == 1 && v->cur_field_type == 1)) && - !v->s.last_picture.f->data[0]) + !v->s.last_pic.data[0]) return; - linesize = s->current_picture_ptr->f->linesize[0]; + linesize = s->cur_pic.ptr->f->linesize[0]; mx = s->mv[dir][n][0]; my = s->mv[dir][n][1]; if (!dir) { if (v->field_mode && (v->cur_field_type != v->ref_field_type[dir]) && v->second_field) { - srcY = s->current_picture.f->data[0]; + srcY = s->cur_pic.data[0]; luty = v->curr_luty; use_ic = *v->curr_use_ic; interlace = 1; } else { - srcY = s->last_picture.f->data[0]; + srcY = s->last_pic.data[0]; luty = v->last_luty; use_ic = v->last_use_ic; - interlace = !!(s->last_picture.f->flags & AV_FRAME_FLAG_INTERLACED); + interlace = v->last_interlaced; } } else { - srcY = s->next_picture.f->data[0]; + srcY = s->next_pic.data[0]; luty = v->next_luty; use_ic = v->next_use_ic; - interlace = !!(s->next_picture.f->flags & AV_FRAME_FLAG_INTERLACED); + interlace = v->next_interlaced; } if (!srcY) { @@ -503,8 +503,8 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg) if (s->pict_type == AV_PICTURE_TYPE_P && n == 3 && v->field_mode) { int opp_count = get_luma_mv(v, 0, - &s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][0], - &s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][1]); + &s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][0], + &s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][1]); int k, f = opp_count > 2; for (k = 0; k < 4; k++) v->mv_f[1][s->block_index[k] + v->blocks_off] = f; @@ -515,8 +515,8 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg) int width = s->avctx->coded_width; int height = s->avctx->coded_height >> 1; if (s->pict_type == AV_PICTURE_TYPE_P) { - s->current_picture.motion_val[1][s->block_index[n] + v->blocks_off][0] = mx; - s->current_picture.motion_val[1][s->block_index[n] + v->blocks_off][1] = my; + s->cur_pic.motion_val[1][s->block_index[n] + v->blocks_off][0] = mx; + s->cur_pic.motion_val[1][s->block_index[n] + v->blocks_off][1] = my; } qx = (s->mb_x * 16) + (mx >> 2); qy = (s->mb_y * 8) + (my >> 3); @@ -640,12 +640,12 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) int16_t tx, ty; int chroma_ref_type; int v_edge_pos = s->v_edge_pos >> v->field_mode; - uint8_t (*lutuv)[256]; + const uint8_t (*lutuv)[256]; int use_ic; int interlace; int uvlinesize; - if (!v->field_mode && !v->s.last_picture.f->data[0]) + if (!v->field_mode && !v->s.last_pic.data[0]) return; if (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY) return; @@ -654,8 +654,8 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) if (!v->field_mode || !v->numref) { int valid_count = get_chroma_mv(v, dir, &tx, &ty); if (!valid_count) { - s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][0] = 0; - s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][1] = 0; + s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][0] = 0; + s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][1] = 0; v->luma_mv[s->mb_x][0] = v->luma_mv[s->mb_x][1] = 0; return; //no need to do MC for intra blocks } @@ -664,12 +664,12 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) int opp_count = get_luma_mv(v, dir, &tx, &ty); chroma_ref_type = v->cur_field_type ^ (opp_count > 2); } - if (v->field_mode && chroma_ref_type == 1 && v->cur_field_type == 1 && !v->s.last_picture.f->data[0]) + if (v->field_mode && chroma_ref_type == 1 && v->cur_field_type == 1 && !v->s.last_pic.data[0]) return; - s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][0] = tx; - s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][1] = ty; + s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][0] = tx; + s->cur_pic.motion_val[1][s->block_index[0] + v->blocks_off][1] = ty; - uvlinesize = s->current_picture_ptr->f->linesize[1]; + uvlinesize = s->cur_pic.ptr->f->linesize[1]; uvmx = (tx + ((tx & 3) == 3)) >> 1; uvmy = (ty + ((ty & 3) == 3)) >> 1; @@ -698,24 +698,24 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) if (!dir) { if (v->field_mode && (v->cur_field_type != chroma_ref_type) && v->second_field) { - srcU = s->current_picture.f->data[1]; - srcV = s->current_picture.f->data[2]; + srcU = s->cur_pic.data[1]; + srcV = s->cur_pic.data[2]; lutuv = v->curr_lutuv; use_ic = *v->curr_use_ic; interlace = 1; } else { - srcU = s->last_picture.f->data[1]; - srcV = s->last_picture.f->data[2]; + srcU = s->last_pic.data[1]; + srcV = s->last_pic.data[2]; lutuv = v->last_lutuv; use_ic = v->last_use_ic; - interlace = !!(s->last_picture.f->flags & AV_FRAME_FLAG_INTERLACED); + interlace = v->last_interlaced; } } else { - srcU = s->next_picture.f->data[1]; - srcV = s->next_picture.f->data[2]; + srcU = s->next_pic.data[1]; + srcV = s->next_pic.data[2]; lutuv = v->next_lutuv; use_ic = v->next_use_ic; - interlace = !!(s->next_picture.f->flags & AV_FRAME_FLAG_INTERLACED); + interlace = v->next_interlaced; } if (!srcU) { @@ -851,12 +851,12 @@ void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg) int use_ic; int interlace; int uvlinesize; - uint8_t (*lutuv)[256]; + const uint8_t (*lutuv)[256]; if (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY) return; - uvlinesize = s->current_picture_ptr->f->linesize[1]; + uvlinesize = s->cur_pic.ptr->f->linesize[1]; for (i = 0; i < 4; i++) { int d = i < 2 ? dir: dir2; @@ -880,17 +880,17 @@ void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg) else uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1); if (i < 2 ? dir : dir2) { - srcU = s->next_picture.f->data[1]; - srcV = s->next_picture.f->data[2]; + srcU = s->next_pic.data[1]; + srcV = s->next_pic.data[2]; lutuv = v->next_lutuv; use_ic = v->next_use_ic; - interlace = !!(s->next_picture.f->flags & AV_FRAME_FLAG_INTERLACED); + interlace = v->next_interlaced; } else { - srcU = s->last_picture.f->data[1]; - srcV = s->last_picture.f->data[2]; + srcU = s->last_pic.data[1]; + srcV = s->last_pic.data[2]; lutuv = v->last_lutuv; use_ic = v->last_use_ic; - interlace = !!(s->last_picture.f->flags & AV_FRAME_FLAG_INTERLACED); + interlace = v->last_interlaced; } if (!srcU) return; @@ -1009,14 +1009,14 @@ void ff_vc1_interp_mc(VC1Context *v) int dxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y; int v_edge_pos = s->v_edge_pos >> v->field_mode; int use_ic = v->next_use_ic; - int interlace; + int interlace = v->next_interlaced; int linesize, uvlinesize; - if (!v->field_mode && !v->s.next_picture.f->data[0]) + if (!v->field_mode && !v->s.next_pic.data[0]) return; - linesize = s->current_picture_ptr->f->linesize[0]; - uvlinesize = s->current_picture_ptr->f->linesize[1]; + linesize = s->cur_pic.ptr->f->linesize[0]; + uvlinesize = s->cur_pic.ptr->f->linesize[1]; mx = s->mv[1][0][0]; my = s->mv[1][0][1]; @@ -1030,11 +1030,9 @@ void ff_vc1_interp_mc(VC1Context *v) uvmx = uvmx + ((uvmx < 0) ? -(uvmx & 1) : (uvmx & 1)); uvmy = uvmy + ((uvmy < 0) ? -(uvmy & 1) : (uvmy & 1)); } - srcY = s->next_picture.f->data[0]; - srcU = s->next_picture.f->data[1]; - srcV = s->next_picture.f->data[2]; - - interlace = !!(s->next_picture.f->flags & AV_FRAME_FLAG_INTERLACED); + srcY = s->next_pic.data[0]; + srcU = s->next_pic.data[1]; + srcV = s->next_pic.data[2]; src_x = s->mb_x * 16 + (mx >> 2); src_y = s->mb_y * 16 + (my >> 2); @@ -1191,8 +1189,8 @@ void ff_vc1_interp_mc(VC1Context *v) } if (use_ic) { - uint8_t (*luty )[256] = v->next_luty; - uint8_t (*lutuv)[256] = v->next_lutuv; + const uint8_t (*luty )[256] = v->next_luty; + const uint8_t (*lutuv)[256] = v->next_lutuv; vc1_lut_scale_luma(srcY, luty[v->field_mode ? v->ref_field_type[1] : ((0+src_y - s->mspel) & 1)], luty[v->field_mode ? v->ref_field_type[1] : ((1+src_y - s->mspel) & 1)], diff --git a/libavcodec/vc1_parser.c b/libavcodec/vc1_parser.c index ec284dca0..a536a7bcf 100644 --- a/libavcodec/vc1_parser.c +++ b/libavcodec/vc1_parser.c @@ -26,6 +26,7 @@ */ #include "libavutil/attributes.h" +#include "libavutil/avassert.h" #include "parser.h" #include "vc1.h" #include "get_bits.h" @@ -66,7 +67,9 @@ static void vc1_extract_header(AVCodecParserContext *s, AVCodecContext *avctx, GetBitContext gb; int ret; vpc->v.s.avctx = avctx; - init_get_bits8(&gb, buf, buf_size); + ret = init_get_bits8(&gb, buf, buf_size); + av_assert1(ret >= 0); // buf_size is bounded by UNESCAPED_THRESHOLD + switch (vpc->prev_start_code) { case VC1_CODE_SEQHDR & 0xFF: ff_vc1_decode_sequence_header(avctx, &vpc->v, &gb); diff --git a/libavcodec/vc1_pred.c b/libavcodec/vc1_pred.c index ad2caf6db..87d9b6d6d 100644 --- a/libavcodec/vc1_pred.c +++ b/libavcodec/vc1_pred.c @@ -33,7 +33,7 @@ #include "vc1_pred.h" #include "vc1data.h" -static av_always_inline int scaleforsame_x(VC1Context *v, int n /* MV */, int dir) +static av_always_inline int scaleforsame_x(const VC1Context *v, int n /* MV */, int dir) { int scaledvalue, refdist; int scalesame1, scalesame2; @@ -66,7 +66,7 @@ static av_always_inline int scaleforsame_x(VC1Context *v, int n /* MV */, int di return av_clip(scaledvalue, -v->range_x, v->range_x - 1); } -static av_always_inline int scaleforsame_y(VC1Context *v, int i, int n /* MV */, int dir) +static av_always_inline int scaleforsame_y(const VC1Context *v, int n /* MV */, int dir) { int scaledvalue, refdist; int scalesame1, scalesame2; @@ -103,7 +103,7 @@ static av_always_inline int scaleforsame_y(VC1Context *v, int i, int n /* MV */, return av_clip(scaledvalue, -v->range_y / 2, v->range_y / 2 - 1); } -static av_always_inline int scaleforopp_x(VC1Context *v, int n /* MV */) +static av_always_inline int scaleforopp_x(const VC1Context *v, int n /* MV */) { int scalezone1_x, zone1offset_x; int scaleopp1, scaleopp2, brfd; @@ -130,7 +130,7 @@ static av_always_inline int scaleforopp_x(VC1Context *v, int n /* MV */) return av_clip(scaledvalue, -v->range_x, v->range_x - 1); } -static av_always_inline int scaleforopp_y(VC1Context *v, int n /* MV */, int dir) +static av_always_inline int scaleforopp_y(const VC1Context *v, int n /* MV */, int dir) { int scalezone1_y, zone1offset_y; int scaleopp1, scaleopp2, brfd; @@ -161,7 +161,7 @@ static av_always_inline int scaleforopp_y(VC1Context *v, int n /* MV */, int dir } } -static av_always_inline int scaleforsame(VC1Context *v, int i, int n /* MV */, +static av_always_inline int scaleforsame(const VC1Context *v, int n /* MV */, int dim, int dir) { int brfd, scalesame; @@ -170,7 +170,7 @@ static av_always_inline int scaleforsame(VC1Context *v, int i, int n /* MV */, n >>= hpel; if (v->s.pict_type != AV_PICTURE_TYPE_B || v->second_field || !dir) { if (dim) - n = scaleforsame_y(v, i, n, dir) * (1 << hpel); + n = scaleforsame_y(v, n, dir) * (1 << hpel); else n = scaleforsame_x(v, n, dir) * (1 << hpel); return n; @@ -182,7 +182,7 @@ static av_always_inline int scaleforsame(VC1Context *v, int i, int n /* MV */, return n; } -static av_always_inline int scaleforopp(VC1Context *v, int n /* MV */, +static av_always_inline int scaleforopp(const VC1Context *v, int n /* MV */, int dim, int dir) { int refdist, scaleopp; @@ -215,7 +215,6 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, { MpegEncContext *s = &v->s; int xy, wrap, off = 0; - int16_t *A, *B, *C; int px, py; int sum; int mixedmv_pic, num_samefield = 0, num_oppfield = 0; @@ -241,24 +240,24 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, xy = s->block_index[n]; if (s->mb_intra) { - s->mv[0][n][0] = s->current_picture.motion_val[0][xy + v->blocks_off][0] = 0; - s->mv[0][n][1] = s->current_picture.motion_val[0][xy + v->blocks_off][1] = 0; - s->current_picture.motion_val[1][xy + v->blocks_off][0] = 0; - s->current_picture.motion_val[1][xy + v->blocks_off][1] = 0; + s->mv[0][n][0] = s->cur_pic.motion_val[0][xy + v->blocks_off][0] = 0; + s->mv[0][n][1] = s->cur_pic.motion_val[0][xy + v->blocks_off][1] = 0; + s->cur_pic.motion_val[1][xy + v->blocks_off][0] = 0; + s->cur_pic.motion_val[1][xy + v->blocks_off][1] = 0; if (mv1) { /* duplicate motion data for 1-MV block */ - s->current_picture.motion_val[0][xy + 1 + v->blocks_off][0] = 0; - s->current_picture.motion_val[0][xy + 1 + v->blocks_off][1] = 0; - s->current_picture.motion_val[0][xy + wrap + v->blocks_off][0] = 0; - s->current_picture.motion_val[0][xy + wrap + v->blocks_off][1] = 0; - s->current_picture.motion_val[0][xy + wrap + 1 + v->blocks_off][0] = 0; - s->current_picture.motion_val[0][xy + wrap + 1 + v->blocks_off][1] = 0; + s->cur_pic.motion_val[0][xy + 1 + v->blocks_off][0] = 0; + s->cur_pic.motion_val[0][xy + 1 + v->blocks_off][1] = 0; + s->cur_pic.motion_val[0][xy + wrap + v->blocks_off][0] = 0; + s->cur_pic.motion_val[0][xy + wrap + v->blocks_off][1] = 0; + s->cur_pic.motion_val[0][xy + wrap + 1 + v->blocks_off][0] = 0; + s->cur_pic.motion_val[0][xy + wrap + 1 + v->blocks_off][1] = 0; v->luma_mv[s->mb_x][0] = v->luma_mv[s->mb_x][1] = 0; - s->current_picture.motion_val[1][xy + 1 + v->blocks_off][0] = 0; - s->current_picture.motion_val[1][xy + 1 + v->blocks_off][1] = 0; - s->current_picture.motion_val[1][xy + wrap + v->blocks_off][0] = 0; - s->current_picture.motion_val[1][xy + wrap + v->blocks_off][1] = 0; - s->current_picture.motion_val[1][xy + wrap + 1 + v->blocks_off][0] = 0; - s->current_picture.motion_val[1][xy + wrap + 1 + v->blocks_off][1] = 0; + s->cur_pic.motion_val[1][xy + 1 + v->blocks_off][0] = 0; + s->cur_pic.motion_val[1][xy + 1 + v->blocks_off][1] = 0; + s->cur_pic.motion_val[1][xy + wrap + v->blocks_off][0] = 0; + s->cur_pic.motion_val[1][xy + wrap + v->blocks_off][1] = 0; + s->cur_pic.motion_val[1][xy + wrap + 1 + v->blocks_off][0] = 0; + s->cur_pic.motion_val[1][xy + wrap + 1 + v->blocks_off][1] = 0; } return; } @@ -301,7 +300,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, } if (a_valid) { - A = s->current_picture.motion_val[dir][xy - wrap + v->blocks_off]; + const int16_t *A = s->cur_pic.motion_val[dir][xy - wrap + v->blocks_off]; a_f = v->mv_f[dir][xy - wrap + v->blocks_off]; num_oppfield += a_f; num_samefield += 1 - a_f; @@ -312,7 +311,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, a_f = 0; } if (b_valid) { - B = s->current_picture.motion_val[dir][xy - wrap + off + v->blocks_off]; + const int16_t *B = s->cur_pic.motion_val[dir][xy - wrap + off + v->blocks_off]; b_f = v->mv_f[dir][xy - wrap + off + v->blocks_off]; num_oppfield += b_f; num_samefield += 1 - b_f; @@ -323,7 +322,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, b_f = 0; } if (c_valid) { - C = s->current_picture.motion_val[dir][xy - 1 + v->blocks_off]; + const int16_t *C = s->cur_pic.motion_val[dir][xy - 1 + v->blocks_off]; c_f = v->mv_f[dir][xy - 1 + v->blocks_off]; num_oppfield += c_f; num_samefield += 1 - c_f; @@ -366,16 +365,16 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, v->mv_f[dir][xy + v->blocks_off] = 0; v->ref_field_type[dir] = v->cur_field_type; if (a_valid && a_f) { - field_predA[0] = scaleforsame(v, n, field_predA[0], 0, dir); - field_predA[1] = scaleforsame(v, n, field_predA[1], 1, dir); + field_predA[0] = scaleforsame(v, field_predA[0], 0, dir); + field_predA[1] = scaleforsame(v, field_predA[1], 1, dir); } if (b_valid && b_f) { - field_predB[0] = scaleforsame(v, n, field_predB[0], 0, dir); - field_predB[1] = scaleforsame(v, n, field_predB[1], 1, dir); + field_predB[0] = scaleforsame(v, field_predB[0], 0, dir); + field_predB[1] = scaleforsame(v, field_predB[1], 1, dir); } if (c_valid && c_f) { - field_predC[0] = scaleforsame(v, n, field_predC[0], 0, dir); - field_predC[1] = scaleforsame(v, n, field_predC[1], 1, dir); + field_predC[0] = scaleforsame(v, field_predC[0], 0, dir); + field_predC[1] = scaleforsame(v, field_predC[1], 1, dir); } } @@ -451,15 +450,15 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, if (v->field_mode && v->cur_field_type && v->ref_field_type[dir] == 0) y_bias = 1; /* store MV using signed modulus of MV range defined in 4.11 */ - s->mv[dir][n][0] = s->current_picture.motion_val[dir][xy + v->blocks_off][0] = ((px + dmv_x + r_x) & ((r_x << 1) - 1)) - r_x; - s->mv[dir][n][1] = s->current_picture.motion_val[dir][xy + v->blocks_off][1] = ((py + dmv_y + r_y - y_bias) & ((r_y << 1) - 1)) - r_y + y_bias; + s->mv[dir][n][0] = s->cur_pic.motion_val[dir][xy + v->blocks_off][0] = ((px + dmv_x + r_x) & ((r_x << 1) - 1)) - r_x; + s->mv[dir][n][1] = s->cur_pic.motion_val[dir][xy + v->blocks_off][1] = ((py + dmv_y + r_y - y_bias) & ((r_y << 1) - 1)) - r_y + y_bias; if (mv1) { /* duplicate motion data for 1-MV block */ - s->current_picture.motion_val[dir][xy + 1 + v->blocks_off][0] = s->current_picture.motion_val[dir][xy + v->blocks_off][0]; - s->current_picture.motion_val[dir][xy + 1 + v->blocks_off][1] = s->current_picture.motion_val[dir][xy + v->blocks_off][1]; - s->current_picture.motion_val[dir][xy + wrap + v->blocks_off][0] = s->current_picture.motion_val[dir][xy + v->blocks_off][0]; - s->current_picture.motion_val[dir][xy + wrap + v->blocks_off][1] = s->current_picture.motion_val[dir][xy + v->blocks_off][1]; - s->current_picture.motion_val[dir][xy + wrap + 1 + v->blocks_off][0] = s->current_picture.motion_val[dir][xy + v->blocks_off][0]; - s->current_picture.motion_val[dir][xy + wrap + 1 + v->blocks_off][1] = s->current_picture.motion_val[dir][xy + v->blocks_off][1]; + s->cur_pic.motion_val[dir][xy + 1 + v->blocks_off][0] = s->cur_pic.motion_val[dir][xy + v->blocks_off][0]; + s->cur_pic.motion_val[dir][xy + 1 + v->blocks_off][1] = s->cur_pic.motion_val[dir][xy + v->blocks_off][1]; + s->cur_pic.motion_val[dir][xy + wrap + v->blocks_off][0] = s->cur_pic.motion_val[dir][xy + v->blocks_off][0]; + s->cur_pic.motion_val[dir][xy + wrap + v->blocks_off][1] = s->cur_pic.motion_val[dir][xy + v->blocks_off][1]; + s->cur_pic.motion_val[dir][xy + wrap + 1 + v->blocks_off][0] = s->cur_pic.motion_val[dir][xy + v->blocks_off][0]; + s->cur_pic.motion_val[dir][xy + wrap + 1 + v->blocks_off][1] = s->cur_pic.motion_val[dir][xy + v->blocks_off][1]; v->mv_f[dir][xy + 1 + v->blocks_off] = v->mv_f[dir][xy + v->blocks_off]; v->mv_f[dir][xy + wrap + v->blocks_off] = v->mv_f[dir][xy + wrap + 1 + v->blocks_off] = v->mv_f[dir][xy + v->blocks_off]; } @@ -483,24 +482,24 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y, xy = s->block_index[n]; if (s->mb_intra) { - s->mv[0][n][0] = s->current_picture.motion_val[0][xy][0] = 0; - s->mv[0][n][1] = s->current_picture.motion_val[0][xy][1] = 0; - s->current_picture.motion_val[1][xy][0] = 0; - s->current_picture.motion_val[1][xy][1] = 0; + s->mv[0][n][0] = s->cur_pic.motion_val[0][xy][0] = 0; + s->mv[0][n][1] = s->cur_pic.motion_val[0][xy][1] = 0; + s->cur_pic.motion_val[1][xy][0] = 0; + s->cur_pic.motion_val[1][xy][1] = 0; if (mvn == 1) { /* duplicate motion data for 1-MV block */ - s->current_picture.motion_val[0][xy + 1][0] = 0; - s->current_picture.motion_val[0][xy + 1][1] = 0; - s->current_picture.motion_val[0][xy + wrap][0] = 0; - s->current_picture.motion_val[0][xy + wrap][1] = 0; - s->current_picture.motion_val[0][xy + wrap + 1][0] = 0; - s->current_picture.motion_val[0][xy + wrap + 1][1] = 0; + s->cur_pic.motion_val[0][xy + 1][0] = 0; + s->cur_pic.motion_val[0][xy + 1][1] = 0; + s->cur_pic.motion_val[0][xy + wrap][0] = 0; + s->cur_pic.motion_val[0][xy + wrap][1] = 0; + s->cur_pic.motion_val[0][xy + wrap + 1][0] = 0; + s->cur_pic.motion_val[0][xy + wrap + 1][1] = 0; v->luma_mv[s->mb_x][0] = v->luma_mv[s->mb_x][1] = 0; - s->current_picture.motion_val[1][xy + 1][0] = 0; - s->current_picture.motion_val[1][xy + 1][1] = 0; - s->current_picture.motion_val[1][xy + wrap][0] = 0; - s->current_picture.motion_val[1][xy + wrap][1] = 0; - s->current_picture.motion_val[1][xy + wrap + 1][0] = 0; - s->current_picture.motion_val[1][xy + wrap + 1][1] = 0; + s->cur_pic.motion_val[1][xy + 1][0] = 0; + s->cur_pic.motion_val[1][xy + 1][1] = 0; + s->cur_pic.motion_val[1][xy + wrap][0] = 0; + s->cur_pic.motion_val[1][xy + wrap][1] = 0; + s->cur_pic.motion_val[1][xy + wrap + 1][0] = 0; + s->cur_pic.motion_val[1][xy + wrap + 1][1] = 0; } return; } @@ -510,14 +509,14 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y, if (s->mb_x || (n == 1) || (n == 3)) { if ((v->blk_mv_type[xy]) // current block (MB) has a field MV || (!v->blk_mv_type[xy] && !v->blk_mv_type[xy - 1])) { // or both have frame MV - A[0] = s->current_picture.motion_val[dir][xy - 1][0]; - A[1] = s->current_picture.motion_val[dir][xy - 1][1]; + A[0] = s->cur_pic.motion_val[dir][xy - 1][0]; + A[1] = s->cur_pic.motion_val[dir][xy - 1][1]; a_valid = 1; } else { // current block has frame mv and cand. has field MV (so average) - A[0] = (s->current_picture.motion_val[dir][xy - 1][0] - + s->current_picture.motion_val[dir][xy - 1 + off * wrap][0] + 1) >> 1; - A[1] = (s->current_picture.motion_val[dir][xy - 1][1] - + s->current_picture.motion_val[dir][xy - 1 + off * wrap][1] + 1) >> 1; + A[0] = (s->cur_pic.motion_val[dir][xy - 1][0] + + s->cur_pic.motion_val[dir][xy - 1 + off * wrap][0] + 1) >> 1; + A[1] = (s->cur_pic.motion_val[dir][xy - 1][1] + + s->cur_pic.motion_val[dir][xy - 1 + off * wrap][1] + 1) >> 1; a_valid = 1; } if (!(n & 1) && v->is_intra[s->mb_x - 1]) { @@ -537,11 +536,11 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y, if (v->blk_mv_type[pos_b] && v->blk_mv_type[xy]) { n_adj = (n & 2) | (n & 1); } - B[0] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap][0]; - B[1] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap][1]; + B[0] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap][0]; + B[1] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap][1]; if (v->blk_mv_type[pos_b] && !v->blk_mv_type[xy]) { - B[0] = (B[0] + s->current_picture.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap][0] + 1) >> 1; - B[1] = (B[1] + s->current_picture.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap][1] + 1) >> 1; + B[0] = (B[0] + s->cur_pic.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap][0] + 1) >> 1; + B[1] = (B[1] + s->cur_pic.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap][1] + 1) >> 1; } } if (s->mb_width > 1) { @@ -552,11 +551,11 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y, if (v->blk_mv_type[pos_c] && v->blk_mv_type[xy]) { n_adj = n & 2; } - C[0] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap + 2][0]; - C[1] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap + 2][1]; + C[0] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap + 2][0]; + C[1] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap + 2][1]; if (v->blk_mv_type[pos_c] && !v->blk_mv_type[xy]) { - C[0] = (1 + C[0] + (s->current_picture.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap + 2][0])) >> 1; - C[1] = (1 + C[1] + (s->current_picture.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap + 2][1])) >> 1; + C[0] = (1 + C[0] + (s->cur_pic.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap + 2][0])) >> 1; + C[1] = (1 + C[1] + (s->cur_pic.motion_val[dir][s->block_index[n_adj ^ 2] - 2 * wrap + 2][1])) >> 1; } if (s->mb_x == s->mb_width - 1) { if (!v->is_intra[s->mb_x - s->mb_stride - 1]) { @@ -566,11 +565,11 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y, if (v->blk_mv_type[pos_c] && v->blk_mv_type[xy]) { n_adj = n | 1; } - C[0] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap - 2][0]; - C[1] = s->current_picture.motion_val[dir][s->block_index[n_adj] - 2 * wrap - 2][1]; + C[0] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap - 2][0]; + C[1] = s->cur_pic.motion_val[dir][s->block_index[n_adj] - 2 * wrap - 2][1]; if (v->blk_mv_type[pos_c] && !v->blk_mv_type[xy]) { - C[0] = (1 + C[0] + s->current_picture.motion_val[dir][s->block_index[1] - 2 * wrap - 2][0]) >> 1; - C[1] = (1 + C[1] + s->current_picture.motion_val[dir][s->block_index[1] - 2 * wrap - 2][1]) >> 1; + C[0] = (1 + C[0] + s->cur_pic.motion_val[dir][s->block_index[1] - 2 * wrap - 2][0]) >> 1; + C[1] = (1 + C[1] + s->cur_pic.motion_val[dir][s->block_index[1] - 2 * wrap - 2][1]) >> 1; } } else c_valid = 0; @@ -581,12 +580,12 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y, } else { pos_b = s->block_index[1]; b_valid = 1; - B[0] = s->current_picture.motion_val[dir][pos_b][0]; - B[1] = s->current_picture.motion_val[dir][pos_b][1]; + B[0] = s->cur_pic.motion_val[dir][pos_b][0]; + B[1] = s->cur_pic.motion_val[dir][pos_b][1]; pos_c = s->block_index[0]; c_valid = 1; - C[0] = s->current_picture.motion_val[dir][pos_c][0]; - C[1] = s->current_picture.motion_val[dir][pos_c][1]; + C[0] = s->cur_pic.motion_val[dir][pos_c][0]; + C[1] = s->cur_pic.motion_val[dir][pos_c][1]; } total_valid = a_valid + b_valid + c_valid; @@ -671,18 +670,18 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y, } /* store MV using signed modulus of MV range defined in 4.11 */ - s->mv[dir][n][0] = s->current_picture.motion_val[dir][xy][0] = ((px + dmv_x + r_x) & ((r_x << 1) - 1)) - r_x; - s->mv[dir][n][1] = s->current_picture.motion_val[dir][xy][1] = ((py + dmv_y + r_y) & ((r_y << 1) - 1)) - r_y; + s->mv[dir][n][0] = s->cur_pic.motion_val[dir][xy][0] = ((px + dmv_x + r_x) & ((r_x << 1) - 1)) - r_x; + s->mv[dir][n][1] = s->cur_pic.motion_val[dir][xy][1] = ((py + dmv_y + r_y) & ((r_y << 1) - 1)) - r_y; if (mvn == 1) { /* duplicate motion data for 1-MV block */ - s->current_picture.motion_val[dir][xy + 1 ][0] = s->current_picture.motion_val[dir][xy][0]; - s->current_picture.motion_val[dir][xy + 1 ][1] = s->current_picture.motion_val[dir][xy][1]; - s->current_picture.motion_val[dir][xy + wrap ][0] = s->current_picture.motion_val[dir][xy][0]; - s->current_picture.motion_val[dir][xy + wrap ][1] = s->current_picture.motion_val[dir][xy][1]; - s->current_picture.motion_val[dir][xy + wrap + 1][0] = s->current_picture.motion_val[dir][xy][0]; - s->current_picture.motion_val[dir][xy + wrap + 1][1] = s->current_picture.motion_val[dir][xy][1]; + s->cur_pic.motion_val[dir][xy + 1 ][0] = s->cur_pic.motion_val[dir][xy][0]; + s->cur_pic.motion_val[dir][xy + 1 ][1] = s->cur_pic.motion_val[dir][xy][1]; + s->cur_pic.motion_val[dir][xy + wrap ][0] = s->cur_pic.motion_val[dir][xy][0]; + s->cur_pic.motion_val[dir][xy + wrap ][1] = s->cur_pic.motion_val[dir][xy][1]; + s->cur_pic.motion_val[dir][xy + wrap + 1][0] = s->cur_pic.motion_val[dir][xy][0]; + s->cur_pic.motion_val[dir][xy + wrap + 1][1] = s->cur_pic.motion_val[dir][xy][1]; } else if (mvn == 2) { /* duplicate motion data for 2-Field MV block */ - s->current_picture.motion_val[dir][xy + 1][0] = s->current_picture.motion_val[dir][xy][0]; - s->current_picture.motion_val[dir][xy + 1][1] = s->current_picture.motion_val[dir][xy][1]; + s->cur_pic.motion_val[dir][xy + 1][0] = s->cur_pic.motion_val[dir][xy][0]; + s->cur_pic.motion_val[dir][xy + 1][1] = s->cur_pic.motion_val[dir][xy][1]; s->mv[dir][n + 1][0] = s->mv[dir][n][0]; s->mv[dir][n + 1][1] = s->mv[dir][n][1]; } @@ -692,8 +691,7 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], int direct, int mvtype) { MpegEncContext *s = &v->s; - int xy, wrap, off = 0; - int16_t *A, *B, *C; + int xy, wrap; int px, py; int sum; int r_x, r_y; @@ -715,38 +713,38 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], xy = s->block_index[0]; if (s->mb_intra) { - s->current_picture.motion_val[0][xy][0] = - s->current_picture.motion_val[0][xy][1] = - s->current_picture.motion_val[1][xy][0] = - s->current_picture.motion_val[1][xy][1] = 0; + s->cur_pic.motion_val[0][xy][0] = + s->cur_pic.motion_val[0][xy][1] = + s->cur_pic.motion_val[1][xy][0] = + s->cur_pic.motion_val[1][xy][1] = 0; return; } - if (direct && s->next_picture_ptr->field_picture) - av_log(s->avctx, AV_LOG_WARNING, "Mixed frame/field direct mode not supported\n"); + if (direct && s->next_pic.ptr->field_picture) + av_log(s->avctx, AV_LOG_WARNING, "Mixed frame/field direct mode not supported\n"); - s->mv[0][0][0] = scale_mv(s->next_picture.motion_val[1][xy][0], v->bfraction, 0, s->quarter_sample); - s->mv[0][0][1] = scale_mv(s->next_picture.motion_val[1][xy][1], v->bfraction, 0, s->quarter_sample); - s->mv[1][0][0] = scale_mv(s->next_picture.motion_val[1][xy][0], v->bfraction, 1, s->quarter_sample); - s->mv[1][0][1] = scale_mv(s->next_picture.motion_val[1][xy][1], v->bfraction, 1, s->quarter_sample); + s->mv[0][0][0] = scale_mv(s->next_pic.motion_val[1][xy][0], v->bfraction, 0, s->quarter_sample); + s->mv[0][0][1] = scale_mv(s->next_pic.motion_val[1][xy][1], v->bfraction, 0, s->quarter_sample); + s->mv[1][0][0] = scale_mv(s->next_pic.motion_val[1][xy][0], v->bfraction, 1, s->quarter_sample); + s->mv[1][0][1] = scale_mv(s->next_pic.motion_val[1][xy][1], v->bfraction, 1, s->quarter_sample); - /* Pullback predicted motion vectors as specified in 8.4.5.4 */ - s->mv[0][0][0] = av_clip(s->mv[0][0][0], -60 - (s->mb_x << 6), (s->mb_width << 6) - 4 - (s->mb_x << 6)); - s->mv[0][0][1] = av_clip(s->mv[0][0][1], -60 - (s->mb_y << 6), (s->mb_height << 6) - 4 - (s->mb_y << 6)); - s->mv[1][0][0] = av_clip(s->mv[1][0][0], -60 - (s->mb_x << 6), (s->mb_width << 6) - 4 - (s->mb_x << 6)); - s->mv[1][0][1] = av_clip(s->mv[1][0][1], -60 - (s->mb_y << 6), (s->mb_height << 6) - 4 - (s->mb_y << 6)); + /* Pullback predicted motion vectors as specified in 8.4.5.4 */ + s->mv[0][0][0] = av_clip(s->mv[0][0][0], -60 - (s->mb_x << 6), (s->mb_width << 6) - 4 - (s->mb_x << 6)); + s->mv[0][0][1] = av_clip(s->mv[0][0][1], -60 - (s->mb_y << 6), (s->mb_height << 6) - 4 - (s->mb_y << 6)); + s->mv[1][0][0] = av_clip(s->mv[1][0][0], -60 - (s->mb_x << 6), (s->mb_width << 6) - 4 - (s->mb_x << 6)); + s->mv[1][0][1] = av_clip(s->mv[1][0][1], -60 - (s->mb_y << 6), (s->mb_height << 6) - 4 - (s->mb_y << 6)); if (direct) { - s->current_picture.motion_val[0][xy][0] = s->mv[0][0][0]; - s->current_picture.motion_val[0][xy][1] = s->mv[0][0][1]; - s->current_picture.motion_val[1][xy][0] = s->mv[1][0][0]; - s->current_picture.motion_val[1][xy][1] = s->mv[1][0][1]; + s->cur_pic.motion_val[0][xy][0] = s->mv[0][0][0]; + s->cur_pic.motion_val[0][xy][1] = s->mv[0][0][1]; + s->cur_pic.motion_val[1][xy][0] = s->mv[1][0][0]; + s->cur_pic.motion_val[1][xy][1] = s->mv[1][0][1]; return; } if ((mvtype == BMV_TYPE_FORWARD) || (mvtype == BMV_TYPE_INTERPOLATED)) { - C = s->current_picture.motion_val[0][xy - 2]; - A = s->current_picture.motion_val[0][xy - wrap * 2]; - off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2; - B = s->current_picture.motion_val[0][xy - wrap * 2 + off]; + int16_t *C = s->cur_pic.motion_val[0][xy - 2]; + const int16_t *A = s->cur_pic.motion_val[0][xy - wrap * 2]; + int off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2; + const int16_t *B = s->cur_pic.motion_val[0][xy - wrap * 2 + off]; if (!s->mb_x) C[0] = C[1] = 0; if (!s->first_slice_line) { // predictor A is not out of bounds @@ -812,10 +810,10 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], s->mv[0][0][1] = ((py + dmv_y[0] + r_y) & ((r_y << 1) - 1)) - r_y; } if ((mvtype == BMV_TYPE_BACKWARD) || (mvtype == BMV_TYPE_INTERPOLATED)) { - C = s->current_picture.motion_val[1][xy - 2]; - A = s->current_picture.motion_val[1][xy - wrap * 2]; - off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2; - B = s->current_picture.motion_val[1][xy - wrap * 2 + off]; + int16_t *C = s->cur_pic.motion_val[1][xy - 2]; + const int16_t *A = s->cur_pic.motion_val[1][xy - wrap * 2]; + int off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2; + const int16_t *B = s->cur_pic.motion_val[1][xy - wrap * 2 + off]; if (!s->mb_x) C[0] = C[1] = 0; @@ -882,10 +880,10 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2], s->mv[1][0][0] = ((px + dmv_x[1] + r_x) & ((r_x << 1) - 1)) - r_x; s->mv[1][0][1] = ((py + dmv_y[1] + r_y) & ((r_y << 1) - 1)) - r_y; } - s->current_picture.motion_val[0][xy][0] = s->mv[0][0][0]; - s->current_picture.motion_val[0][xy][1] = s->mv[0][0][1]; - s->current_picture.motion_val[1][xy][0] = s->mv[1][0][0]; - s->current_picture.motion_val[1][xy][1] = s->mv[1][0][1]; + s->cur_pic.motion_val[0][xy][0] = s->mv[0][0][0]; + s->cur_pic.motion_val[0][xy][1] = s->mv[0][0][1]; + s->cur_pic.motion_val[1][xy][0] = s->mv[1][0][0]; + s->cur_pic.motion_val[1][xy][1] = s->mv[1][0][1]; } void ff_vc1_pred_b_mv_intfi(VC1Context *v, int n, int *dmv_x, int *dmv_y, @@ -897,14 +895,14 @@ void ff_vc1_pred_b_mv_intfi(VC1Context *v, int n, int *dmv_x, int *dmv_y, if (v->bmvtype == BMV_TYPE_DIRECT) { int total_opp, k, f; - if (s->next_picture.mb_type[mb_pos + v->mb_off] != MB_TYPE_INTRA) { - s->mv[0][0][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0] + v->blocks_off][0], + if (s->next_pic.mb_type[mb_pos + v->mb_off] != MB_TYPE_INTRA) { + s->mv[0][0][0] = scale_mv(s->next_pic.motion_val[1][s->block_index[0] + v->blocks_off][0], v->bfraction, 0, s->quarter_sample); - s->mv[0][0][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0] + v->blocks_off][1], + s->mv[0][0][1] = scale_mv(s->next_pic.motion_val[1][s->block_index[0] + v->blocks_off][1], v->bfraction, 0, s->quarter_sample); - s->mv[1][0][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0] + v->blocks_off][0], + s->mv[1][0][0] = scale_mv(s->next_pic.motion_val[1][s->block_index[0] + v->blocks_off][0], v->bfraction, 1, s->quarter_sample); - s->mv[1][0][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0] + v->blocks_off][1], + s->mv[1][0][1] = scale_mv(s->next_pic.motion_val[1][s->block_index[0] + v->blocks_off][1], v->bfraction, 1, s->quarter_sample); total_opp = v->mv_f_next[0][s->block_index[0] + v->blocks_off] @@ -919,10 +917,10 @@ void ff_vc1_pred_b_mv_intfi(VC1Context *v, int n, int *dmv_x, int *dmv_y, } v->ref_field_type[0] = v->ref_field_type[1] = v->cur_field_type ^ f; for (k = 0; k < 4; k++) { - s->current_picture.motion_val[0][s->block_index[k] + v->blocks_off][0] = s->mv[0][0][0]; - s->current_picture.motion_val[0][s->block_index[k] + v->blocks_off][1] = s->mv[0][0][1]; - s->current_picture.motion_val[1][s->block_index[k] + v->blocks_off][0] = s->mv[1][0][0]; - s->current_picture.motion_val[1][s->block_index[k] + v->blocks_off][1] = s->mv[1][0][1]; + s->cur_pic.motion_val[0][s->block_index[k] + v->blocks_off][0] = s->mv[0][0][0]; + s->cur_pic.motion_val[0][s->block_index[k] + v->blocks_off][1] = s->mv[0][0][1]; + s->cur_pic.motion_val[1][s->block_index[k] + v->blocks_off][0] = s->mv[1][0][0]; + s->cur_pic.motion_val[1][s->block_index[k] + v->blocks_off][1] = s->mv[1][0][1]; v->mv_f[0][s->block_index[k] + v->blocks_off] = f; v->mv_f[1][s->block_index[k] + v->blocks_off] = f; } diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c index 3ca478e82..2c314e7b5 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -33,10 +33,10 @@ #include "codec_internal.h" #include "decode.h" #include "get_bits.h" -#include "h263dec.h" #include "hwaccel_internal.h" #include "hwconfig.h" #include "mpeg_er.h" +#include "mpegutils.h" #include "mpegvideo.h" #include "mpegvideodec.h" #include "msmpeg4_vc1_data.h" @@ -48,6 +48,7 @@ #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" @@ -210,7 +211,7 @@ static void vc1_draw_sprites(VC1Context *v, SpriteData* sd) { int i, plane, row, sprite; int sr_cache[2][2] = { { -1, -1 }, { -1, -1 } }; - uint8_t* src_h[2][2]; + const uint8_t *src_h[2][2]; int xoff[2], xadv[2], yoff[2], yadv[2], alpha; int ysub[2]; MpegEncContext *s = &v->s; @@ -234,15 +235,15 @@ static void vc1_draw_sprites(VC1Context *v, SpriteData* sd) v->sprite_output_frame->linesize[plane] * row; for (sprite = 0; sprite <= v->two_sprites; sprite++) { - uint8_t *iplane = s->current_picture.f->data[plane]; - int iline = s->current_picture.f->linesize[plane]; + const uint8_t *iplane = s->cur_pic.data[plane]; + int iline = s->cur_pic.linesize[plane]; int ycoord = yoff[sprite] + yadv[sprite] * row; int yline = ycoord >> 16; int next_line; ysub[sprite] = ycoord & 0xFFFF; if (sprite) { - iplane = s->last_picture.f->data[plane]; - iline = s->last_picture.f->linesize[plane]; + iplane = s->last_pic.data[plane]; + iline = s->last_pic.linesize[plane]; } next_line = FFMIN(yline + 1, (v->sprite_height >> !!plane) - 1) * iline; if (!(xoff[sprite] & 0xFFFF) && xadv[sprite] == 1 << 16) { @@ -316,12 +317,12 @@ static int vc1_decode_sprites(VC1Context *v, GetBitContext* gb) if (ret < 0) return ret; - if (!s->current_picture.f || !s->current_picture.f->data[0]) { + if (!s->cur_pic.data[0]) { av_log(avctx, AV_LOG_ERROR, "Got no sprites\n"); return AVERROR_UNKNOWN; } - if (v->two_sprites && (!s->last_picture_ptr || !s->last_picture.f->data[0])) { + if (v->two_sprites && (!s->last_pic.ptr || !s->last_pic.data[0])) { av_log(avctx, AV_LOG_WARNING, "Need two sprites, only got one\n"); v->two_sprites = 0; } @@ -339,14 +340,14 @@ static void vc1_sprite_flush(AVCodecContext *avctx) { VC1Context *v = avctx->priv_data; MpegEncContext *s = &v->s; - AVFrame *f = s->current_picture.f; + MPVWorkPicture *f = &s->cur_pic; int plane, i; /* Windows Media Image codecs have a convergence interval of two keyframes. Since we can't enforce it, clear to black the missing sprite. This is wrong but it looks better than doing nothing. */ - if (f && f->data[0]) + if (f->data[0]) for (plane = 0; plane < (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY ? 1 : 3); plane++) for (i = 0; i < v->sprite_height>>!!plane; i++) memset(f->data[plane] + i * f->linesize[plane], @@ -378,7 +379,7 @@ static av_cold int vc1_decode_init_alloc_tables(VC1Context *v) if (!v->block || !v->cbp_base) return AVERROR(ENOMEM); v->cbp = v->cbp_base + 2 * s->mb_stride; - v->ttblk_base = av_malloc(sizeof(v->ttblk_base[0]) * 3 * s->mb_stride); + v->ttblk_base = av_mallocz(sizeof(v->ttblk_base[0]) * 3 * s->mb_stride); if (!v->ttblk_base) return AVERROR(ENOMEM); v->ttblk = v->ttblk_base + 2 * s->mb_stride; @@ -392,7 +393,7 @@ static av_cold int vc1_decode_init_alloc_tables(VC1Context *v) v->luma_mv = v->luma_mv_base + 2 * s->mb_stride; /* allocate block type info in that way so it could be used with s->block_index[] */ - v->mb_type_base = av_malloc(s->b8_stride * (mb_height * 2 + 1) + s->mb_stride * (mb_height + 1) * 2); + 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; @@ -448,6 +449,8 @@ static enum AVPixelFormat vc1_get_format(AVCodecContext *avctx) return ff_get_format(avctx, vc1_hwaccel_pixfmt_list_420); } +static void vc1_decode_reset(AVCodecContext *avctx); + av_cold int ff_vc1_decode_init(AVCodecContext *avctx) { VC1Context *const v = avctx->priv_data; @@ -458,7 +461,9 @@ av_cold int ff_vc1_decode_init(AVCodecContext *avctx) if (ret < 0) return ret; - ff_mpv_decode_init(s, avctx); + ret = ff_mpv_decode_init(s, avctx); + if (ret < 0) + return ret; avctx->pix_fmt = vc1_get_format(avctx); @@ -476,7 +481,7 @@ av_cold int ff_vc1_decode_init(AVCodecContext *avctx) ret = vc1_decode_init_alloc_tables(v); if (ret < 0) { - ff_vc1_decode_end(avctx); + vc1_decode_reset(avctx); return ret; } return 0; @@ -605,7 +610,7 @@ av_cold void ff_vc1_init_common(VC1Context *v) s->out_format = FMT_H263; s->h263_pred = 1; - s->msmpeg4_version = 6; + s->msmpeg4_version = MSMP4_VC1; ff_vc1dsp_init(&v->vc1dsp); @@ -666,7 +671,7 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) } } else { // VC1/WVC1/WVP2 const uint8_t *start = avctx->extradata; - uint8_t *end = avctx->extradata + avctx->extradata_size; + const uint8_t *end = avctx->extradata + avctx->extradata_size; const uint8_t *next; int size, buf2_size; uint8_t *buf2 = NULL; @@ -773,10 +778,7 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) return 0; } -/** Close a VC1/WMV3 decoder - * @warning Initial try at using MpegEncContext stuff - */ -av_cold int ff_vc1_decode_end(AVCodecContext *avctx) +static av_cold void vc1_decode_reset(AVCodecContext *avctx) { VC1Context *v = avctx->priv_data; int i; @@ -786,6 +788,7 @@ av_cold int ff_vc1_decode_end(AVCodecContext *avctx) for (i = 0; i < 4; i++) av_freep(&v->sr_rows[i >> 1][i & 1]); ff_mpv_common_end(&v->s); + memset(v->s.block_index, 0, sizeof(v->s.block_index)); av_freep(&v->mv_type_mb_plane); av_freep(&v->direct_mb_plane); av_freep(&v->forward_mb_plane); @@ -802,9 +805,16 @@ av_cold int ff_vc1_decode_end(AVCodecContext *avctx) av_freep(&v->is_intra_base); // FIXME use v->mb_type[] av_freep(&v->luma_mv_base); ff_intrax8_common_end(&v->x8); - return 0; } +/** + * Close a MSS2/VC1/WMV3 decoder + */ +av_cold int ff_vc1_decode_end(AVCodecContext *avctx) +{ + vc1_decode_reset(avctx); + return ff_mpv_decode_close(avctx); +} /** Decode a VC1/WMV3 frame * @todo TODO: Handle VC-1 IDUs (Transport level?) @@ -836,10 +846,10 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, /* no supplementary picture */ if (buf_size == 0 || (buf_size == 4 && AV_RB32(buf) == VC1_CODE_ENDOFSEQ)) { /* special case for last picture */ - if (s->low_delay == 0 && s->next_picture_ptr) { - if ((ret = av_frame_ref(pict, s->next_picture_ptr->f)) < 0) + if (s->low_delay == 0 && s->next_pic.ptr) { + if ((ret = av_frame_ref(pict, s->next_pic.ptr->f)) < 0) return ret; - s->next_picture_ptr = NULL; + ff_mpv_unref_picture(&s->next_pic); *got_frame = 1; } @@ -990,7 +1000,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, if (s->context_initialized && (s->width != avctx->coded_width || s->height != avctx->coded_height)) { - ff_vc1_decode_end(avctx); + vc1_decode_reset(avctx); } if (!s->context_initialized) { @@ -1046,7 +1056,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } /* skip B-frames if we don't have reference frames */ - if (!s->last_picture_ptr && s->pict_type == AV_PICTURE_TYPE_B) { + if (!s->last_pic.ptr && s->pict_type == AV_PICTURE_TYPE_B) { av_log(v->s.avctx, AV_LOG_DEBUG, "Skipping B frame without reference frames\n"); goto end; } @@ -1060,19 +1070,21 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, goto err; } - v->s.current_picture_ptr->field_picture = v->field_mode; - v->s.current_picture_ptr->f->flags |= AV_FRAME_FLAG_INTERLACED * (v->fcm != PROGRESSIVE); - v->s.current_picture_ptr->f->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * !!v->tff; + v->s.cur_pic.ptr->field_picture = v->field_mode; + v->s.cur_pic.ptr->f->flags |= AV_FRAME_FLAG_INTERLACED * (v->fcm != PROGRESSIVE); + v->s.cur_pic.ptr->f->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * !!v->tff; + v->last_interlaced = v->s.last_pic.ptr ? v->s.last_pic.ptr->f->flags & AV_FRAME_FLAG_INTERLACED : 0; + v->next_interlaced = v->s.next_pic.ptr ? v->s.next_pic.ptr->f->flags & AV_FRAME_FLAG_INTERLACED : 0; // process pulldown flags - s->current_picture_ptr->f->repeat_pict = 0; + s->cur_pic.ptr->f->repeat_pict = 0; // Pulldown flags are only valid when 'broadcast' has been set. if (v->rff) { // repeat field - s->current_picture_ptr->f->repeat_pict = 1; + s->cur_pic.ptr->f->repeat_pict = 1; } else if (v->rptfrm) { // repeat frames - s->current_picture_ptr->f->repeat_pict = v->rptfrm * 2; + s->cur_pic.ptr->f->repeat_pict = v->rptfrm * 2; } if (avctx->hwaccel) { @@ -1134,7 +1146,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, ret = AVERROR_INVALIDDATA; goto err; } - v->s.current_picture_ptr->f->pict_type = v->s.pict_type; + v->s.cur_pic.ptr->f->pict_type = v->s.pict_type; ret = hwaccel->start_frame(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field); @@ -1229,9 +1241,9 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, v->end_mb_x = s->mb_width; if (v->field_mode) { - s->current_picture.f->linesize[0] <<= 1; - s->current_picture.f->linesize[1] <<= 1; - s->current_picture.f->linesize[2] <<= 1; + s->cur_pic.linesize[0] <<= 1; + s->cur_pic.linesize[1] <<= 1; + s->cur_pic.linesize[2] <<= 1; s->linesize <<= 1; s->uvlinesize <<= 1; } @@ -1306,9 +1318,9 @@ static int vc1_decode_frame(AVCodecContext *avctx, AVFrame *pict, } if (v->field_mode) { v->second_field = 0; - s->current_picture.f->linesize[0] >>= 1; - s->current_picture.f->linesize[1] >>= 1; - s->current_picture.f->linesize[2] >>= 1; + s->cur_pic.linesize[0] >>= 1; + s->cur_pic.linesize[1] >>= 1; + s->cur_pic.linesize[2] >>= 1; s->linesize >>= 1; s->uvlinesize >>= 1; if (v->s.pict_type != AV_PICTURE_TYPE_BI && v->s.pict_type != AV_PICTURE_TYPE_B) { @@ -1352,16 +1364,16 @@ image: *got_frame = 1; } else { if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) { - if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0) + if ((ret = av_frame_ref(pict, s->cur_pic.ptr->f)) < 0) goto err; if (!v->field_mode) - ff_print_debug_info(s, s->current_picture_ptr, pict); + ff_print_debug_info(s, s->cur_pic.ptr, pict); *got_frame = 1; - } else if (s->last_picture_ptr) { - if ((ret = av_frame_ref(pict, s->last_picture_ptr->f)) < 0) + } 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_picture_ptr, pict); + ff_print_debug_info(s, s->last_pic.ptr, pict); *got_frame = 1; } } diff --git a/libavcodec/vc2enc.c b/libavcodec/vc2enc.c index 349174c8c..b82370a75 100644 --- a/libavcodec/vc2enc.c +++ b/libavcodec/vc2enc.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "libavutil/version.h" @@ -40,8 +41,9 @@ typedef struct VC2BaseVideoFormat { enum AVPixelFormat pix_fmt; AVRational time_base; - int width, height, interlaced, level; - const char *name; + int width, height; + uint8_t interlaced, level; + char name[13]; } VC2BaseVideoFormat; static const VC2BaseVideoFormat base_video_fmts[] = { @@ -103,9 +105,11 @@ typedef struct Plane { } Plane; typedef struct SliceArgs { - PutBitContext pb; - int cache[DIRAC_MAX_QUANT_INDEX]; - void *ctx; + const struct VC2EncContext *ctx; + union { + int cache[DIRAC_MAX_QUANT_INDEX]; + uint8_t *buf; + }; int x; int y; int quant_idx; @@ -115,7 +119,7 @@ typedef struct SliceArgs { } SliceArgs; typedef struct TransformArgs { - void *ctx; + const struct VC2EncContext *ctx; Plane *plane; const void *idata; ptrdiff_t istride; @@ -529,8 +533,8 @@ static void encode_picture_start(VC2EncContext *s) #define QUANT(c, mul, add, shift) (((mul) * (c) + (add)) >> (shift)) /* VC-2 13.5.5.2 - slice_band() */ -static void encode_subband(VC2EncContext *s, PutBitContext *pb, int sx, int sy, - SubBand *b, int quant) +static void encode_subband(const VC2EncContext *s, PutBitContext *pb, + int sx, int sy, const SubBand *b, int quant) { int x, y; @@ -560,7 +564,7 @@ static int count_hq_slice(SliceArgs *slice, int quant_idx) int x, y; uint8_t quants[MAX_DWT_LEVELS][4]; int bits = 0, p, level, orientation; - VC2EncContext *s = slice->ctx; + const VC2EncContext *s = slice->ctx; if (slice->cache[quant_idx]) return slice->cache[quant_idx]; @@ -578,7 +582,7 @@ static int count_hq_slice(SliceArgs *slice, int quant_idx) bits += 8; for (level = 0; level < s->wavelet_depth; level++) { for (orientation = !!level; orientation < 4; orientation++) { - SubBand *b = &s->plane[p].band[level][orientation]; + const SubBand *b = &s->plane[p].band[level][orientation]; const int q_idx = quants[level][orientation]; const uint64_t q_m = ((uint64_t)s->qmagic_lut[q_idx][0]) << 2; @@ -620,7 +624,7 @@ static int count_hq_slice(SliceArgs *slice, int quant_idx) static int rate_control(AVCodecContext *avctx, void *arg) { SliceArgs *slice_dat = arg; - VC2EncContext *s = slice_dat->ctx; + const VC2EncContext *s = slice_dat->ctx; const int top = slice_dat->bits_ceil; const int bottom = slice_dat->bits_floor; int quant_buf[2] = {-1, -1}; @@ -725,9 +729,9 @@ static int calc_slice_sizes(VC2EncContext *s) /* VC-2 13.5.3 - hq_slice */ static int encode_hq_slice(AVCodecContext *avctx, void *arg) { - SliceArgs *slice_dat = arg; - VC2EncContext *s = slice_dat->ctx; - PutBitContext *pb = &slice_dat->pb; + const SliceArgs *slice_dat = arg; + const VC2EncContext *s = slice_dat->ctx; + PutBitContext pb0, *const pb = &pb0; const int slice_x = slice_dat->x; const int slice_y = slice_dat->y; const int quant_idx = slice_dat->quant_idx; @@ -736,8 +740,9 @@ static int encode_hq_slice(AVCodecContext *avctx, void *arg) int p, level, orientation; /* The reference decoder ignores it, and its typical length is 0 */ - memset(put_bits_ptr(pb), 0, s->prefix_bytes); - skip_put_bytes(pb, s->prefix_bytes); + memset(slice_dat->buf, 0, s->prefix_bytes); + + init_put_bits(pb, slice_dat->buf + s->prefix_bytes, slice_dat->bytes - s->prefix_bytes); put_bits(pb, 8, quant_idx); @@ -790,7 +795,7 @@ static int encode_slices(VC2EncContext *s) for (slice_y = 0; slice_y < s->num_y; slice_y++) { for (slice_x = 0; slice_x < s->num_x; slice_x++) { SliceArgs *args = &enc_args[s->num_x*slice_y + slice_x]; - init_put_bits(&args->pb, buf + skip, args->bytes+s->prefix_bytes); + args->buf = buf + skip; skip += args->bytes; } } @@ -841,7 +846,7 @@ static int encode_slices(VC2EncContext *s) static int dwt_plane(AVCodecContext *avctx, void *arg) { TransformArgs *transform_dat = arg; - VC2EncContext *s = transform_dat->ctx; + const VC2EncContext *s = transform_dat->ctx; const void *frame_data = transform_dat->idata; const ptrdiff_t linesize = transform_dat->istride; const int field = transform_dat->field; @@ -920,10 +925,8 @@ static int encode_frame(VC2EncContext *s, AVPacket *avpkt, const AVFrame *frame, if (field < 2) { ret = ff_get_encode_buffer(s->avctx, avpkt, max_frame_bytes << s->interlaced, 0); - if (ret) { - av_log(s->avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + if (ret < 0) return ret; - } init_put_bits(&s->pb, avpkt->data, avpkt->size); } @@ -985,7 +988,7 @@ static av_cold int vc2_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } s->slice_min_bytes = s->slice_max_bytes - s->slice_max_bytes*(s->tolerance/100.0f); - if (s->slice_min_bytes < 0) + if (s->slice_min_bytes < 0 || s->slice_max_bytes > INT_MAX >> 3) return AVERROR(EINVAL); ret = encode_frame(s, avpkt, frame, aux_data, header_size, s->interlaced); @@ -1026,9 +1029,9 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) { Plane *p; SubBand *b; - int i, level, o, shift, ret; - const AVPixFmtDescriptor *fmt = av_pix_fmt_desc_get(avctx->pix_fmt); - const int depth = fmt->comp[0].depth; + int i, level, o, shift; + const AVPixFmtDescriptor *pixdesc; + int depth; VC2EncContext *s = avctx->priv_data; s->picture_number = 0; @@ -1100,12 +1103,13 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) s->base_vf, base_video_fmts[s->base_vf].name); } + pixdesc = av_pix_fmt_desc_get(avctx->pix_fmt); /* Chroma subsampling */ - ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); - if (ret) - return ret; + s->chroma_x_shift = pixdesc->log2_chroma_w; + s->chroma_y_shift = pixdesc->log2_chroma_h; /* Bit depth and color range index */ + depth = pixdesc->comp[0].depth; if (depth == 8 && avctx->color_range == AVCOL_RANGE_JPEG) { s->bpp = 1; s->bpp_idx = 1; @@ -1240,5 +1244,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 + .p.pix_fmts = allowed_pix_fmts, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, }; diff --git a/libavcodec/vcr1.c b/libavcodec/vcr1.c index 771337e26..c9ed62266 100644 --- a/libavcodec/vcr1.c +++ b/libavcodec/vcr1.c @@ -62,8 +62,6 @@ static int vcr1_decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; for (i = 0; i < 16; i++) { a->delta[i] = *bytestream++; diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c index 538c57f9e..0dd564160 100644 --- a/libavcodec/vdpau.c +++ b/libavcodec/vdpau.c @@ -23,14 +23,12 @@ #include "config_components.h" -#include - +#include "libavutil/mem.h" #include "avcodec.h" #include "decode.h" #include "hwaccel_internal.h" #include "internal.h" #include "mpegvideodec.h" -#include "vc1.h" #include "vdpau.h" #include "vdpau_internal.h" @@ -372,7 +370,7 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame, int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx) { MpegEncContext *s = avctx->priv_data; - Picture *pic = s->current_picture_ptr; + MPVPicture *pic = s->cur_pic.ptr; struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; int val; diff --git a/libavcodec/vdpau_av1.c b/libavcodec/vdpau_av1.c index 80923092b..a1aff79bb 100644 --- a/libavcodec/vdpau_av1.c +++ b/libavcodec/vdpau_av1.c @@ -91,9 +91,7 @@ static int vdpau_av1_start_frame(AVCodecContext *avctx, info->show_frame = frame_header->show_frame; info->disable_cdf_update = frame_header->disable_cdf_update; info->allow_screen_content_tools = frame_header->allow_screen_content_tools; - info->force_integer_mv = frame_header->force_integer_mv || - frame_header->frame_type == AV1_FRAME_INTRA_ONLY || - frame_header->frame_type == AV1_FRAME_KEY; + info->force_integer_mv = s->cur_frame.force_integer_mv; info->coded_denom = frame_header->coded_denom; info->allow_intrabc = frame_header->allow_intrabc; info->allow_high_precision_mv = frame_header->allow_high_precision_mv; @@ -219,7 +217,8 @@ static int vdpau_av1_start_frame(AVCodecContext *avctx, info->loop_filter_ref_deltas[i] = frame_header->loop_filter_ref_deltas[i]; /* Reference Frames */ - info->ref_frame_map[i] = ff_vdpau_get_surface_id(s->ref[i].f) ? ff_vdpau_get_surface_id(s->ref[i].f) : VDP_INVALID_HANDLE; + info->ref_frame_map[i] = s->ref[i].f && ff_vdpau_get_surface_id(s->ref[i].f) ? + ff_vdpau_get_surface_id(s->ref[i].f) : VDP_INVALID_HANDLE; } if (frame_header->primary_ref_frame == AV1_PRIMARY_REF_NONE) { @@ -235,8 +234,8 @@ static int vdpau_av1_start_frame(AVCodecContext *avctx, AVFrame *ref_frame = s->ref[ref_idx].f; info->ref_frame[i].index = info->ref_frame_map[ref_idx]; - info->ref_frame[i].width = ref_frame->width; - info->ref_frame[i].height = ref_frame->height; + info->ref_frame[i].width = ref_frame ? ref_frame->width : 0; + info->ref_frame[i].height = ref_frame ? ref_frame->height : 0; /* Global Motion */ info->global_motion[i].invalid = !frame_header->is_global[AV1_REF_FRAME_LAST + i]; diff --git a/libavcodec/vdpau_hevc.c b/libavcodec/vdpau_hevc.c index 4cd7ce562..0ddcafd89 100644 --- a/libavcodec/vdpau_hevc.c +++ b/libavcodec/vdpau_hevc.c @@ -23,8 +23,8 @@ #include #include "avcodec.h" -#include "hevc_data.h" -#include "hevcdec.h" +#include "hevc/data.h" +#include "hevc/hevcdec.h" #include "hwaccel_internal.h" #include "vdpau.h" #include "vdpau_internal.h" @@ -35,7 +35,8 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { HEVCContext *h = avctx->priv_data; - HEVCFrame *pic = h->ref; + const HEVCLayerContext *l = &h->layers[h->cur_layer]; + HEVCFrame *pic = h->cur_frame; struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; VdpPictureInfoHEVC *info = &pic_ctx->info.hevc; @@ -43,8 +44,8 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, VdpPictureInfoHEVC444 *info2 = &pic_ctx->info.hevc_444; #endif - const HEVCSPS *sps = h->ps.sps; - const HEVCPPS *pps = h->ps.pps; + const HEVCPPS *pps = h->pps; + const HEVCSPS *sps = pps->sps; const SliceHeader *sh = &h->sh; const ScalingList *sl = pps->scaling_list_data_present_flag ? &pps->scaling_list : &sps->scaling_list; @@ -53,7 +54,7 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, /* SPS */ info->chroma_format_idc = sps->chroma_format_idc; - info->separate_colour_plane_flag = sps->separate_colour_plane_flag; + info->separate_colour_plane_flag = sps->separate_colour_plane; info->pic_width_in_luma_samples = sps->width; info->pic_height_in_luma_samples = sps->height; info->bit_depth_luma_minus8 = sps->bit_depth - 8; @@ -68,7 +69,7 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, info->log2_diff_max_min_transform_block_size = sps->log2_max_trafo_size - sps->log2_min_tb_size; info->max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter; info->max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra; - info->scaling_list_enabled_flag = sps->scaling_list_enable_flag; + info->scaling_list_enabled_flag = sps->scaling_list_enabled; /* Scaling lists, in diagonal order, to be used for this frame. */ for (size_t i = 0; i < 6; i++) { for (size_t j = 0; j < 16; j++) { @@ -100,9 +101,9 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, info->ScalingListDCCoeff32x32[i] = sl->sl_dc[1][i * 3]; } } - info->amp_enabled_flag = sps->amp_enabled_flag; + info->amp_enabled_flag = sps->amp_enabled; info->sample_adaptive_offset_enabled_flag = sps->sao_enabled; - info->pcm_enabled_flag = sps->pcm_enabled_flag; + info->pcm_enabled_flag = sps->pcm_enabled; if (info->pcm_enabled_flag) { /* Only needs to be set if pcm_enabled_flag is set. Ignored otherwise. */ info->pcm_sample_bit_depth_luma_minus1 = sps->pcm.bit_depth - 1; @@ -113,17 +114,17 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, /* Only needs to be set if pcm_enabled_flag is set. Ignored otherwise. */ info->log2_diff_max_min_pcm_luma_coding_block_size = sps->pcm.log2_max_pcm_cb_size - sps->pcm.log2_min_pcm_cb_size; /* Only needs to be set if pcm_enabled_flag is set. Ignored otherwise. */ - info->pcm_loop_filter_disabled_flag = sps->pcm.loop_filter_disable_flag; + info->pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled; } /* Per spec, when zero, assume short_term_ref_pic_set_sps_flag is also zero. */ info->num_short_term_ref_pic_sets = sps->nb_st_rps; - info->long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag; + info->long_term_ref_pics_present_flag = sps->long_term_ref_pics_present; /* Only needed if long_term_ref_pics_present_flag is set. Ignored otherwise. */ info->num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps; - info->sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag; - info->strong_intra_smoothing_enabled_flag = sps->sps_strong_intra_smoothing_enable_flag; + info->sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled; + info->strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled; /* Copy the HEVC Picture Parameter Set bitstream fields. */ info->dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag; @@ -205,7 +206,7 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, } } /* See section 7.4.7.2 of the specification. */ - info->NumPocTotalCurr = ff_hevc_frame_nb_refs(h); + info->NumPocTotalCurr = ff_hevc_frame_nb_refs(&h->sh, pps, h->cur_layer); if (sh->short_term_ref_pic_set_sps_flag == 0 && sh->short_term_rps) { /* Corresponds to specification field, NumDeltaPocs[RefRpsIdx]. Only applicable when short_term_ref_pic_set_sps_flag == 0. @@ -236,9 +237,9 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, info->PicOrderCntVal[i] = 0; info->IsLongTerm[i] = 0; } - for (size_t i = 0, j = 0; i < FF_ARRAY_ELEMS(h->DPB); i++) { - const HEVCFrame *frame = &h->DPB[i]; - if (frame != h->ref && (frame->flags & (HEVC_FRAME_FLAG_LONG_REF | + for (size_t i = 0, j = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + const HEVCFrame *frame = &l->DPB[i]; + if (frame != h->cur_frame && (frame->flags & (HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF))) { if (j > 15) { av_log(avctx, AV_LOG_WARNING, @@ -248,7 +249,7 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, } /* Array of video reference surfaces. Set any unused positions to VDP_INVALID_HANDLE. */ - info->RefPics[j] = ff_vdpau_get_surface_id(frame->frame); + info->RefPics[j] = ff_vdpau_get_surface_id(frame->f); /* Array of picture order counts. These correspond to positions in the RefPics array. */ info->PicOrderCntVal[j] = frame->poc; @@ -295,7 +296,7 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, HEVCFrame *frame = h->rps[ST_CURR_BEF].ref[i]; if (frame) { uint8_t found = 0; - uintptr_t id = ff_vdpau_get_surface_id(frame->frame); + uintptr_t id = ff_vdpau_get_surface_id(frame->f); for (size_t k = 0; k < 16; k++) { if (id == info->RefPics[k]) { info->RefPicSetStCurrBefore[j] = k; @@ -318,7 +319,7 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, HEVCFrame *frame = h->rps[ST_CURR_AFT].ref[i]; if (frame) { uint8_t found = 0; - uintptr_t id = ff_vdpau_get_surface_id(frame->frame); + uintptr_t id = ff_vdpau_get_surface_id(frame->f); for (size_t k = 0; k < 16; k++) { if (id == info->RefPics[k]) { info->RefPicSetStCurrAfter[j] = k; @@ -341,7 +342,7 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, HEVCFrame *frame = h->rps[LT_CURR].ref[i]; if (frame) { uint8_t found = 0; - uintptr_t id = ff_vdpau_get_surface_id(frame->frame); + uintptr_t id = ff_vdpau_get_surface_id(frame->f); for (size_t k = 0; k < 16; k++) { if (id == info->RefPics[k]) { info->RefPicSetLtCurr[j] = k; @@ -360,17 +361,17 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, } #ifdef VDP_YCBCR_FORMAT_Y_U_V_444 - if (sps->sps_range_extension_flag) { + if (sps->range_extension) { info2->sps_range_extension_flag = 1; - info2->transformSkipRotationEnableFlag = sps->transform_skip_rotation_enabled_flag; - info2->transformSkipContextEnableFlag = sps->transform_skip_context_enabled_flag; - info2->implicitRdpcmEnableFlag = sps->implicit_rdpcm_enabled_flag; - info2->explicitRdpcmEnableFlag = sps->explicit_rdpcm_enabled_flag; - info2->extendedPrecisionProcessingFlag = sps->extended_precision_processing_flag; - info2->intraSmoothingDisabledFlag = sps->intra_smoothing_disabled_flag; - info2->highPrecisionOffsetsEnableFlag = sps->high_precision_offsets_enabled_flag; - info2->persistentRiceAdaptationEnableFlag = sps->persistent_rice_adaptation_enabled_flag; - info2->cabacBypassAlignmentEnableFlag = sps->cabac_bypass_alignment_enabled_flag; + info2->transformSkipRotationEnableFlag = sps->transform_skip_rotation_enabled; + info2->transformSkipContextEnableFlag = sps->transform_skip_context_enabled; + info2->implicitRdpcmEnableFlag = sps->implicit_rdpcm_enabled; + info2->explicitRdpcmEnableFlag = sps->explicit_rdpcm_enabled; + info2->extendedPrecisionProcessingFlag = sps->extended_precision_processing; + info2->intraSmoothingDisabledFlag = sps->intra_smoothing_disabled; + info2->highPrecisionOffsetsEnableFlag = sps->high_precision_offsets_enabled; + info2->persistentRiceAdaptationEnableFlag = sps->persistent_rice_adaptation_enabled; + info2->cabacBypassAlignmentEnableFlag = sps->cabac_bypass_alignment_enabled; } else { info2->sps_range_extension_flag = 0; } @@ -403,7 +404,7 @@ static int vdpau_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { HEVCContext *h = avctx->priv_data; - struct vdpau_picture_context *pic_ctx = h->ref->hwaccel_picture_private; + struct vdpau_picture_context *pic_ctx = h->cur_frame->hwaccel_picture_private; int val; val = ff_vdpau_add_buffer(pic_ctx, start_code_prefix, 3); @@ -420,10 +421,10 @@ static int vdpau_hevc_decode_slice(AVCodecContext *avctx, static int vdpau_hevc_end_frame(AVCodecContext *avctx) { HEVCContext *h = avctx->priv_data; - struct vdpau_picture_context *pic_ctx = h->ref->hwaccel_picture_private; + struct vdpau_picture_context *pic_ctx = h->cur_frame->hwaccel_picture_private; int val; - val = ff_vdpau_common_end_frame(avctx, h->ref->frame, pic_ctx); + val = ff_vdpau_common_end_frame(avctx, h->cur_frame->f, pic_ctx); if (val < 0) return val; @@ -469,7 +470,7 @@ static int ptl_convert(const PTLCommon *general_ptl, H265RawProfileTierLevel *h2 static int vdpau_hevc_parse_rext_profile(AVCodecContext *avctx, VdpDecoderProfile *vdp_profile) { const HEVCContext *h = avctx->priv_data; - const HEVCSPS *sps = h->ps.sps; + const HEVCSPS *sps = h->pps->sps; const PTL *ptl = &sps->ptl; const PTLCommon *general_ptl = &ptl->general_ptl; const H265ProfileDescriptor *profile; diff --git a/libavcodec/vdpau_mpeg12.c b/libavcodec/vdpau_mpeg12.c index bbf76eb46..1ce0bfaa0 100644 --- a/libavcodec/vdpau_mpeg12.c +++ b/libavcodec/vdpau_mpeg12.c @@ -35,7 +35,7 @@ static int vdpau_mpeg_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { MpegEncContext * const s = avctx->priv_data; - Picture *pic = s->current_picture_ptr; + MPVPicture *pic = s->cur_pic.ptr; struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; VdpPictureInfoMPEG1Or2 *info = &pic_ctx->info.mpeg; VdpVideoSurface ref; @@ -47,12 +47,12 @@ static int vdpau_mpeg_start_frame(AVCodecContext *avctx, switch (s->pict_type) { case AV_PICTURE_TYPE_B: - ref = ff_vdpau_get_surface_id(s->next_picture.f); + ref = ff_vdpau_get_surface_id(s->next_pic.ptr->f); assert(ref != VDP_INVALID_HANDLE); info->backward_reference = ref; /* fall through to forward prediction */ case AV_PICTURE_TYPE_P: - ref = ff_vdpau_get_surface_id(s->last_picture.f); + ref = ff_vdpau_get_surface_id(s->last_pic.ptr->f); info->forward_reference = ref; } @@ -87,7 +87,7 @@ static int vdpau_mpeg_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { MpegEncContext * const s = avctx->priv_data; - Picture *pic = s->current_picture_ptr; + MPVPicture *pic = s->cur_pic.ptr; struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; int val; diff --git a/libavcodec/vdpau_mpeg4.c b/libavcodec/vdpau_mpeg4.c index 055426b95..40af8655c 100644 --- a/libavcodec/vdpau_mpeg4.c +++ b/libavcodec/vdpau_mpeg4.c @@ -34,7 +34,7 @@ static int vdpau_mpeg4_start_frame(AVCodecContext *avctx, { Mpeg4DecContext *ctx = avctx->priv_data; MpegEncContext * const s = &ctx->m; - Picture *pic = s->current_picture_ptr; + MPVPicture *pic = s->cur_pic.ptr; struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; VdpPictureInfoMPEG4Part2 *info = &pic_ctx->info.mpeg4; VdpVideoSurface ref; @@ -47,13 +47,13 @@ static int vdpau_mpeg4_start_frame(AVCodecContext *avctx, switch (s->pict_type) { case AV_PICTURE_TYPE_B: - ref = ff_vdpau_get_surface_id(s->next_picture.f); + ref = ff_vdpau_get_surface_id(s->next_pic.ptr->f); assert(ref != VDP_INVALID_HANDLE); info->backward_reference = ref; info->vop_coding_type = 2; /* fall-through */ case AV_PICTURE_TYPE_P: - ref = ff_vdpau_get_surface_id(s->last_picture.f); + ref = ff_vdpau_get_surface_id(s->last_pic.ptr->f); assert(ref != VDP_INVALID_HANDLE); info->forward_reference = ref; } diff --git a/libavcodec/vdpau_vc1.c b/libavcodec/vdpau_vc1.c index 0eacc4477..d02a454bb 100644 --- a/libavcodec/vdpau_vc1.c +++ b/libavcodec/vdpau_vc1.c @@ -36,7 +36,7 @@ static int vdpau_vc1_start_frame(AVCodecContext *avctx, { VC1Context * const v = avctx->priv_data; MpegEncContext * const s = &v->s; - Picture *pic = s->current_picture_ptr; + MPVPicture *pic = s->cur_pic.ptr; struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; VdpPictureInfoVC1 *info = &pic_ctx->info.vc1; VdpVideoSurface ref; @@ -47,15 +47,15 @@ static int vdpau_vc1_start_frame(AVCodecContext *avctx, switch (s->pict_type) { case AV_PICTURE_TYPE_B: - if (s->next_picture_ptr) { - ref = ff_vdpau_get_surface_id(s->next_picture.f); + if (s->next_pic.ptr) { + ref = ff_vdpau_get_surface_id(s->next_pic.ptr->f); assert(ref != VDP_INVALID_HANDLE); info->backward_reference = ref; } /* fall-through */ case AV_PICTURE_TYPE_P: - if (s->last_picture_ptr) { - ref = ff_vdpau_get_surface_id(s->last_picture.f); + if (s->last_pic.ptr) { + ref = ff_vdpau_get_surface_id(s->last_pic.ptr->f); assert(ref != VDP_INVALID_HANDLE); info->forward_reference = ref; } @@ -104,7 +104,7 @@ static int vdpau_vc1_decode_slice(AVCodecContext *avctx, { VC1Context * const v = avctx->priv_data; MpegEncContext * const s = &v->s; - Picture *pic = s->current_picture_ptr; + MPVPicture *pic = s->cur_pic.ptr; struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; int val; diff --git a/libavcodec/version.c b/libavcodec/version.c index d7966b201..27f94323b 100644 --- a/libavcodec/version.c +++ b/libavcodec/version.c @@ -18,9 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "config.h" -#include "libavutil/avassert.h" #include "avcodec.h" #include "codec_id.h" #include "version.h" @@ -30,10 +31,15 @@ const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION; unsigned avcodec_version(void) { - av_assert0(AV_CODEC_ID_PCM_S8_PLANAR==65563); - av_assert0(AV_CODEC_ID_ADPCM_G722==69660); - av_assert0(AV_CODEC_ID_SRT==94216); - av_assert0(LIBAVCODEC_VERSION_MICRO >= 100); + static_assert(AV_CODEC_ID_LEAD == 269 && + AV_CODEC_ID_PCM_SGA == 65572 && + AV_CODEC_ID_ADPCM_XMD == 69683 && + AV_CODEC_ID_CBD2_DPCM == 81928 && + AV_CODEC_ID_QOA == 86121 && + AV_CODEC_ID_ARIB_CAPTION == 94233 && + AV_CODEC_ID_SMPTE_2038 == 98315, + "Don't insert new codec ids in the middle of a list"); + static_assert(LIBAVCODEC_VERSION_MICRO >= 100, "micro version starts at 100"); return LIBAVCODEC_VERSION_INT; } diff --git a/libavcodec/version.h b/libavcodec/version.h index 43794ea58..b6ca025fa 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,8 +29,8 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 3 -#define LIBAVCODEC_VERSION_MICRO 100 +#define LIBAVCODEC_VERSION_MINOR 19 +#define LIBAVCODEC_VERSION_MICRO 101 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ diff --git a/libavcodec/version_major.h b/libavcodec/version_major.h index ab1f4511b..63df40e9d 100644 --- a/libavcodec/version_major.h +++ b/libavcodec/version_major.h @@ -47,5 +47,6 @@ #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) #endif /* AVCODEC_VERSION_MAJOR_H */ diff --git a/libavcodec/videodsp.c b/libavcodec/videodsp.c index bdff2e76f..a19e87a81 100644 --- a/libavcodec/videodsp.c +++ b/libavcodec/videodsp.c @@ -51,6 +51,8 @@ av_cold void ff_videodsp_init(VideoDSPContext *ctx, int bpc) ff_videodsp_init_arm(ctx, bpc); #elif ARCH_PPC ff_videodsp_init_ppc(ctx, bpc); +#elif ARCH_RISCV + ff_videodsp_init_riscv(ctx, bpc); #elif ARCH_X86 ff_videodsp_init_x86(ctx, bpc); #elif ARCH_MIPS diff --git a/libavcodec/videodsp.h b/libavcodec/videodsp.h index e8960b609..1be3188d0 100644 --- a/libavcodec/videodsp.h +++ b/libavcodec/videodsp.h @@ -81,6 +81,7 @@ void ff_videodsp_init(VideoDSPContext *ctx, int bpc); void ff_videodsp_init_aarch64(VideoDSPContext *ctx, int bpc); void ff_videodsp_init_arm(VideoDSPContext *ctx, int bpc); void ff_videodsp_init_ppc(VideoDSPContext *ctx, int bpc); +void ff_videodsp_init_riscv(VideoDSPContext *ctx, int bpc); void ff_videodsp_init_x86(VideoDSPContext *ctx, int bpc); void ff_videodsp_init_mips(VideoDSPContext *ctx, int bpc); void ff_videodsp_init_loongarch(VideoDSPContext *ctx, int bpc); diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c index f4da80640..505483ef6 100644 --- a/libavcodec/videotoolbox.c +++ b/libavcodec/videotoolbox.c @@ -24,6 +24,7 @@ #include "config_components.h" #include "videotoolbox.h" #include "libavutil/hwcontext_videotoolbox.h" +#include "libavutil/mem.h" #include "vt_internal.h" #include "libavutil/avutil.h" #include "libavutil/hwcontext.h" @@ -32,7 +33,7 @@ #include "decode.h" #include "internal.h" #include "h264dec.h" -#include "hevcdec.h" +#include "hevc/hevcdec.h" #include "hwaccel_internal.h" #include "mpegvideo.h" #include "proresdec.h" @@ -232,9 +233,9 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) { HEVCContext *h = avctx->priv_data; int i, num_vps = 0, num_sps = 0, num_pps = 0; - const HEVCVPS *vps = h->ps.vps; - const HEVCSPS *sps = h->ps.sps; - const HEVCPPS *pps = h->ps.pps; + const HEVCPPS *pps = h->pps; + const HEVCSPS *sps = pps->sps; + const HEVCVPS *vps = sps->vps; PTLCommon ptlc = vps->ptl.general_ptl; VUI vui = sps->vui; uint8_t parallelismType; @@ -348,7 +349,7 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) */ AV_W8(p + 21, 0 << 6 | sps->max_sub_layers << 3 | - sps->temporal_id_nesting_flag << 2 | + sps->temporal_id_nesting << 2 | 3); /* unsigned int(8) numOfArrays; */ @@ -1052,6 +1053,14 @@ static int videotoolbox_hevc_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) { + HEVCContext *h = avctx->priv_data; + AVFrame *frame = h->cur_frame->f; + + frame->crop_right = 0; + frame->crop_left = 0; + frame->crop_top = 0; + frame->crop_bottom = 0; + return 0; } @@ -1074,15 +1083,10 @@ static int videotoolbox_hevc_decode_params(AVCodecContext *avctx, static int videotoolbox_hevc_end_frame(AVCodecContext *avctx) { HEVCContext *h = avctx->priv_data; - AVFrame *frame = h->ref->frame; + AVFrame *frame = h->cur_frame->f; VTContext *vtctx = avctx->internal->hwaccel_priv_data; int ret; - h->output_frame->crop_right = 0; - h->output_frame->crop_left = 0; - h->output_frame->crop_top = 0; - h->output_frame->crop_bottom = 0; - ret = ff_videotoolbox_common_end_frame(avctx, frame); vtctx->bitstream_size = 0; return ret; @@ -1107,7 +1111,7 @@ static int videotoolbox_mpeg_decode_slice(AVCodecContext *avctx, static int videotoolbox_mpeg_end_frame(AVCodecContext *avctx) { MpegEncContext *s = avctx->priv_data; - AVFrame *frame = s->current_picture_ptr->f; + AVFrame *frame = s->cur_pic.ptr->f; return ff_videotoolbox_common_end_frame(avctx, frame); } diff --git a/libavcodec/videotoolbox_vp9.c b/libavcodec/videotoolbox_vp9.c index f5489854e..da94ff4e5 100644 --- a/libavcodec/videotoolbox_vp9.c +++ b/libavcodec/videotoolbox_vp9.c @@ -23,6 +23,7 @@ #include "config.h" #include "videotoolbox.h" #include "libavutil/hwcontext_videotoolbox.h" +#include "libavutil/mem.h" #include "vt_internal.h" #include "libavutil/avassert.h" #include "libavutil/avutil.h" diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index 5ea9afee2..da7b291b0 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -24,6 +24,7 @@ #include #include #include "avcodec.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -226,9 +227,9 @@ typedef struct ExtraSEI { typedef struct BufNode { CMSampleBufferRef cm_buffer; - ExtraSEI *sei; + ExtraSEI sei; + AVBufferRef *frame_buf; struct BufNode* next; - int error; } BufNode; typedef struct VTEncContext { @@ -261,7 +262,7 @@ typedef struct VTEncContext { int realtime; int frames_before; int frames_after; - bool constant_bit_rate; + int constant_bit_rate; int allow_sw; int require_sw; @@ -280,6 +281,18 @@ typedef struct VTEncContext { int max_ref_frames; } VTEncContext; +static void vtenc_free_buf_node(BufNode *info) +{ + if (!info) + return; + + av_free(info->sei.data); + if (info->cm_buffer) + CFRelease(info->cm_buffer); + av_buffer_unref(&info->frame_buf); + av_free(info); +} + static int vt_dump_encoder(AVCodecContext *avctx) { VTEncContext *vtctx = avctx->priv_data; @@ -347,8 +360,7 @@ static void set_async_error(VTEncContext *vtctx, int err) while (info) { BufNode *next = info->next; - CFRelease(info->cm_buffer); - av_free(info); + vtenc_free_buf_node(info); info = next; } @@ -388,7 +400,7 @@ static void vtenc_reset(VTEncContext *vtctx) } } -static int vtenc_q_pop(VTEncContext *vtctx, bool wait, CMSampleBufferRef *buf, ExtraSEI **sei) +static int vtenc_q_pop(VTEncContext *vtctx, bool wait, CMSampleBufferRef *buf, ExtraSEI *sei) { BufNode *info; @@ -426,31 +438,18 @@ static int vtenc_q_pop(VTEncContext *vtctx, bool wait, CMSampleBufferRef *buf, E pthread_mutex_unlock(&vtctx->lock); *buf = info->cm_buffer; + info->cm_buffer = NULL; if (sei && *buf) { *sei = info->sei; - } else if (info->sei) { - if (info->sei->data) av_free(info->sei->data); - av_free(info->sei); + info->sei = (ExtraSEI) {0}; } - av_free(info); - + vtenc_free_buf_node(info); return 0; } -static void vtenc_q_push(VTEncContext *vtctx, CMSampleBufferRef buffer, ExtraSEI *sei) +static void vtenc_q_push(VTEncContext *vtctx, BufNode *info) { - BufNode *info = av_malloc(sizeof(BufNode)); - if (!info) { - set_async_error(vtctx, AVERROR(ENOMEM)); - return; - } - - CFRetain(buffer); - info->cm_buffer = buffer; - info->sei = sei; - info->next = NULL; - pthread_mutex_lock(&vtctx->lock); if (!vtctx->q_head) { @@ -735,13 +734,16 @@ static void vtenc_output_callback( { AVCodecContext *avctx = ctx; VTEncContext *vtctx = avctx->priv_data; - ExtraSEI *sei = sourceFrameCtx; + BufNode *info = sourceFrameCtx; + av_buffer_unref(&info->frame_buf); if (vtctx->async_error) { + vtenc_free_buf_node(info); return; } if (status) { + vtenc_free_buf_node(info); av_log(avctx, AV_LOG_ERROR, "Error encoding frame: %d\n", (int)status); set_async_error(vtctx, AVERROR_EXTERNAL); return; @@ -751,15 +753,19 @@ static void vtenc_output_callback( return; } + CFRetain(sample_buffer); + info->cm_buffer = sample_buffer; + if (!avctx->extradata && (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) { int set_status = set_extradata(avctx, sample_buffer); if (set_status) { + vtenc_free_buf_node(info); set_async_error(vtctx, set_status); return; } } - vtenc_q_push(vtctx, sample_buffer, sei); + vtenc_q_push(vtctx, info); } static int get_length_code_size( @@ -1199,6 +1205,10 @@ 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 (vtctx->supported_props) { + CFRelease(vtctx->supported_props); + vtctx->supported_props = NULL; + } status = VTCopySupportedPropertyDictionaryForEncoder(avctx->width, avctx->height, codec_type, @@ -2449,7 +2459,8 @@ static int copy_avframe_to_pixel_buffer(AVCodecContext *avctx, static int create_cv_pixel_buffer(AVCodecContext *avctx, const AVFrame *frame, - CVPixelBufferRef *cv_img) + CVPixelBufferRef *cv_img, + BufNode *node) { int plane_count; int color; @@ -2468,6 +2479,12 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, av_assert0(*cv_img); CFRetain(*cv_img); + if (frame->buf[0]) { + node->frame_buf = av_buffer_ref(frame->buf[0]); + if (!node->frame_buf) + return AVERROR(ENOMEM); + } + return 0; } @@ -2565,33 +2582,29 @@ static int vtenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) { CMTime time; - CFDictionaryRef frame_dict; + CFDictionaryRef frame_dict = NULL; CVPixelBufferRef cv_img = NULL; AVFrameSideData *side_data = NULL; - ExtraSEI *sei = NULL; - int status = create_cv_pixel_buffer(avctx, frame, &cv_img); + BufNode *node = av_mallocz(sizeof(*node)); + int status; - if (status) return status; + if (!node) + return AVERROR(ENOMEM); + + status = create_cv_pixel_buffer(avctx, frame, &cv_img, node); + if (status) + goto out; status = create_encoder_dict_h264(frame, &frame_dict); - if (status) { - CFRelease(cv_img); - return status; - } + if (status) + goto out; #if CONFIG_ATSC_A53 side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC); if (vtctx->a53_cc && side_data && side_data->size) { - sei = av_mallocz(sizeof(*sei)); - if (!sei) { - av_log(avctx, AV_LOG_ERROR, "Not enough memory for closed captions, skipping\n"); - } else { - int ret = ff_alloc_a53_sei(frame, 0, &sei->data, &sei->size); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Not enough memory for closed captions, skipping\n"); - av_free(sei); - sei = NULL; - } + status = ff_alloc_a53_sei(frame, 0, &node->sei.data, &node->sei.size); + if (status < 0) { + goto out; } } #endif @@ -2603,19 +2616,26 @@ static int vtenc_send_frame(AVCodecContext *avctx, time, kCMTimeInvalid, frame_dict, - sei, + node, NULL ); - if (frame_dict) CFRelease(frame_dict); - CFRelease(cv_img); - if (status) { av_log(avctx, AV_LOG_ERROR, "Error: cannot encode frame: %d\n", status); - return AVERROR_EXTERNAL; + status = AVERROR_EXTERNAL; + // Not necessary, just in case new code put after here + goto out; } - return 0; +out: + if (frame_dict) + CFRelease(frame_dict); + if (cv_img) + CFRelease(cv_img); + if (status) + vtenc_free_buf_node(node); + + return status; } static av_cold int vtenc_frame( @@ -2628,7 +2648,7 @@ static av_cold int vtenc_frame( bool get_frame; int status; CMSampleBufferRef buf = NULL; - ExtraSEI *sei = NULL; + ExtraSEI sei = {0}; if (frame) { status = vtenc_send_frame(avctx, vtctx, frame); @@ -2669,11 +2689,8 @@ static av_cold int vtenc_frame( if (status) goto end_nopkt; if (!buf) goto end_nopkt; - status = vtenc_cm_to_avpacket(avctx, buf, pkt, sei); - if (sei) { - if (sei->data) av_free(sei->data); - av_free(sei); - } + status = vtenc_cm_to_avpacket(avctx, buf, pkt, sei.data ? &sei : NULL); + av_free(sei.data); CFRelease(buf); if (status) goto end_nopkt; @@ -2698,6 +2715,10 @@ static int vtenc_populate_extradata(AVCodecContext *avctx, CVPixelBufferRef pix_buf = NULL; CMTime time; CMSampleBufferRef buf = NULL; + BufNode *node = av_mallocz(sizeof(*node)); + + if (!node) + return AVERROR(ENOMEM); status = vtenc_create_encoder(avctx, codec_type, @@ -2733,7 +2754,7 @@ static int vtenc_populate_extradata(AVCodecContext *avctx, time, kCMTimeInvalid, NULL, - NULL, + node, NULL); if (status) { @@ -2744,6 +2765,7 @@ static int vtenc_populate_extradata(AVCodecContext *avctx, status = AVERROR_EXTERNAL; goto pe_cleanup; } + node = NULL; //Populates extradata - output frames are flushed and param sets are available. status = VTCompressionSessionCompleteFrames(vtctx->session, @@ -2766,10 +2788,19 @@ static int vtenc_populate_extradata(AVCodecContext *avctx, pe_cleanup: CVPixelBufferRelease(pix_buf); - vtenc_reset(vtctx); + + if (status) { + vtenc_reset(vtctx); + } else if (vtctx->session) { + CFRelease(vtctx->session); + vtctx->session = NULL; + } + vtctx->frame_ct_out = 0; av_assert0(status != 0 || (avctx->extradata && avctx->extradata_size > 0)); + if (!status) + vtenc_free_buf_node(node); return status; } @@ -2906,6 +2937,7 @@ static const AVOption h264_options[] = { }; static const FFCodecDefault vt_defaults[] = { + {"b", "0"}, {"qmin", "-1"}, {"qmax", "-1"}, {NULL}, @@ -2965,6 +2997,7 @@ const FFCodec ff_hevc_videotoolbox_encoder = { .priv_data_size = sizeof(VTEncContext), .p.pix_fmts = hevc_pix_fmts, .defaults = vt_defaults, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .init = vtenc_init, FF_CODEC_ENCODE_CB(vtenc_frame), .close = vtenc_close, @@ -3005,6 +3038,7 @@ const FFCodec ff_prores_videotoolbox_encoder = { .priv_data_size = sizeof(VTEncContext), .p.pix_fmts = prores_pix_fmts, .defaults = vt_defaults, + .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, .init = vtenc_init, FF_CODEC_ENCODE_CB(vtenc_frame), .close = vtenc_close, diff --git a/libavcodec/vlc.c b/libavcodec/vlc.c index 7d940915d..f46ecbb55 100644 --- a/libavcodec/vlc.c +++ b/libavcodec/vlc.c @@ -440,8 +440,8 @@ static void add_level(VLC_MULTI_ELEM *table, const int is16bit, code = curcode + (buf[t].code >> curlen); newlimit = curlimit - l; l += curlen; - if (is16bit) AV_WN16(info.val+2*curlevel, sym); - else info.val[curlevel] = sym&0xFF; + if (is16bit) info.val16[curlevel] = sym; + else info.val8[curlevel] = sym&0xFF; if (curlevel) { // let's not add single entries uint32_t val = code >> (32 - numbits); @@ -468,7 +468,7 @@ static int vlc_multi_gen(VLC_MULTI_ELEM *table, const VLC *single, { int minbits, maxbits, max; unsigned count[VLC_MULTI_MAX_SYMBOLS-1] = { 0, }; - VLC_MULTI_ELEM info = { { 0, }, 0, 0, }; + VLC_MULTI_ELEM info = { 0 }; int count0 = 0; for (int j = 0; j < 1<table[j].len; table[j].num = single->table[j].len > 0 ? 1 : 0; if (is16bit) - AV_WN16(table[j].val, single->table[j].sym); + table[j].val16[0] = single->table[j].sym; else - table[j].val[0] = single->table[j].sym; + table[j].val8[0] = single->table[j].sym; } add_level(table, is16bit, nb_codes, numbits, buf, diff --git a/libavcodec/vlc.h b/libavcodec/vlc.h index 0cc106c49..bf7b0e65b 100644 --- a/libavcodec/vlc.h +++ b/libavcodec/vlc.h @@ -40,7 +40,10 @@ typedef struct VLC { } VLC; typedef struct VLC_MULTI_ELEM { - uint8_t val[VLC_MULTI_MAX_SYMBOLS]; + union { + uint8_t val8[VLC_MULTI_MAX_SYMBOLS]; + uint16_t val16[VLC_MULTI_MAX_SYMBOLS / 2]; + }; int8_t len; // -31,32 uint8_t num; } VLC_MULTI_ELEM; diff --git a/libavcodec/vmdvideo.c b/libavcodec/vmdvideo.c index 2da8af31f..b168a931c 100644 --- a/libavcodec/vmdvideo.c +++ b/libavcodec/vmdvideo.c @@ -37,6 +37,7 @@ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/vmixdec.c b/libavcodec/vmixdec.c index ab283d13d..46d817c7f 100644 --- a/libavcodec/vmixdec.c +++ b/libavcodec/vmixdec.c @@ -24,11 +24,11 @@ #include #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" #include "codec_internal.h" -#include "decode.h" #define CACHED_BITSTREAM_READER !ARCH_X86_32 #include "golomb.h" #include "get_bits.h" @@ -289,9 +289,6 @@ static int decode_frame(AVCodecContext *avctx, avctx->execute2(avctx, decode_slices, frame, NULL, s->nb_slices); - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/vmnc.c b/libavcodec/vmnc.c index 17e3a2f3c..6188aa715 100644 --- a/libavcodec/vmnc.c +++ b/libavcodec/vmnc.c @@ -26,6 +26,7 @@ */ #include "libavutil/common.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/vorbis_parser.c b/libavcodec/vorbis_parser.c index d2c9e647c..c6969f139 100644 --- a/libavcodec/vorbis_parser.c +++ b/libavcodec/vorbis_parser.c @@ -28,9 +28,9 @@ #include "config_components.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "get_bits.h" -#include "parser.h" #include "xiph.h" #include "vorbis_parser_internal.h" diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index 8462739c1..218e855f7 100644 --- a/libavcodec/vorbisdec.c +++ b/libavcodec/vorbisdec.c @@ -31,6 +31,7 @@ #include "libavutil/avassert.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/tx.h" #define BITSTREAM_READER_LE @@ -180,11 +181,11 @@ static const char idx_err_str[] = "Index value %d out of range (0 - %d) for %s a static float vorbisfloat2float(unsigned val) { - double mant = val & 0x1fffff; - long exp = (val & 0x7fe00000L) >> 21; + float mant = val & 0x1fffff; + int exp = (val & 0x7fe00000) >> 21; if (val & 0x80000000) mant = -mant; - return ldexp(mant, exp - 20 - 768); + return ldexpf(mant, exp - 20 - 768); } diff --git a/libavcodec/vorbisenc.c b/libavcodec/vorbisenc.c index 378a3b38d..62684a7d8 100644 --- a/libavcodec/vorbisenc.c +++ b/libavcodec/vorbisenc.c @@ -26,6 +26,7 @@ #include #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "avcodec.h" diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index 96b0b6600..d03a1c9db 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -37,6 +37,7 @@ #include "libavutil/emms.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" @@ -48,9 +49,9 @@ #include "internal.h" #include "jpegquanttables.h" #include "mathops.h" +#include "progressframe.h" #include "refstruct.h" #include "thread.h" -#include "threadframe.h" #include "videodsp.h" #include "vp3data.h" #include "vp4data.h" @@ -200,9 +201,9 @@ typedef struct Vp3DecodeContext { int version; int width, height; int chroma_x_shift, chroma_y_shift; - ThreadFrame golden_frame; - ThreadFrame last_frame; - ThreadFrame current_frame; + ProgressFrame golden_frame; + ProgressFrame last_frame; + ProgressFrame current_frame; int keyframe; uint8_t idct_permutation[64]; uint8_t idct_scantable[64]; @@ -352,12 +353,9 @@ static void vp3_decode_flush(AVCodecContext *avctx) { Vp3DecodeContext *s = avctx->priv_data; - if (s->golden_frame.f) - ff_thread_release_ext_buffer(&s->golden_frame); - if (s->last_frame.f) - ff_thread_release_ext_buffer(&s->last_frame); - if (s->current_frame.f) - ff_thread_release_ext_buffer(&s->current_frame); + ff_progress_frame_unref(&s->golden_frame); + ff_progress_frame_unref(&s->last_frame); + ff_progress_frame_unref(&s->current_frame); } static av_cold int vp3_decode_end(AVCodecContext *avctx) @@ -371,9 +369,6 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx) /* release all frames */ vp3_decode_flush(avctx); - av_frame_free(&s->current_frame.f); - av_frame_free(&s->last_frame.f); - av_frame_free(&s->golden_frame.f); ff_refstruct_unref(&s->coeff_vlc); @@ -1907,10 +1902,9 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int y) /* At the end of the frame, report INT_MAX instead of the height of * the frame. This makes the other threads' ff_thread_await_progress() * calls cheaper, because they don't have to clip their values. */ - ff_thread_report_progress(&s->current_frame, - y_flipped == s->height ? INT_MAX - : y_flipped - 1, - 0); + ff_progress_frame_report(&s->current_frame, + y_flipped == s->height ? INT_MAX + : y_flipped - 1); } if (!s->avctx->draw_horiz_band) @@ -1941,7 +1935,7 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int y) static void await_reference_row(Vp3DecodeContext *s, const Vp3Fragment *fragment, int motion_y, int y) { - const ThreadFrame *ref_frame; + const ProgressFrame *ref_frame; int ref_row; int border = motion_y & 1; @@ -1954,7 +1948,7 @@ static void await_reference_row(Vp3DecodeContext *s, const Vp3Fragment *fragment ref_row = y + (motion_y >> 1); ref_row = FFMAX(FFABS(ref_row), ref_row + 8 + border); - ff_thread_await_progress(ref_frame, ref_row, 0); + ff_progress_frame_await(ref_frame, ref_row); } #if CONFIG_VP4_DECODER @@ -2064,12 +2058,12 @@ static void render_slice(Vp3DecodeContext *s, int slice) int16_t *block = s->block; int motion_x = 0xdeadbeef, motion_y = 0xdeadbeef; /* When decoding keyframes, the earlier frames may not be available, - * so to avoid using undefined pointer arithmetic on them we just - * use the current frame instead. Nothing is ever read from these - * frames in case of a keyframe. */ - const AVFrame *last_frame = s->last_frame.f->data[0] ? + * so we just use the current frame in this case instead; + * it also avoid using undefined pointer arithmetic. Nothing is + * ever read from these frames in case of a keyframe. */ + const AVFrame *last_frame = s->last_frame.f ? s->last_frame.f : s->current_frame.f; - const AVFrame *golden_frame = s->golden_frame.f->data[0] ? + const AVFrame *golden_frame = s->golden_frame.f ? s->golden_frame.f : s->current_frame.f; int motion_halfpel_index; int first_pixel; @@ -2351,17 +2345,6 @@ static av_cold int allocate_tables(AVCodecContext *avctx) return 0; } -static av_cold int init_frames(Vp3DecodeContext *s) -{ - s->current_frame.f = av_frame_alloc(); - s->last_frame.f = av_frame_alloc(); - s->golden_frame.f = av_frame_alloc(); - - if (!s->current_frame.f || !s->last_frame.f || !s->golden_frame.f) - return AVERROR(ENOMEM); - - return 0; -} static av_cold void free_vlc_tables(FFRefStructOpaque unused, void *obj) { @@ -2380,10 +2363,6 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) int c_height; int y_fragment_count, c_fragment_count; - ret = init_frames(s); - if (ret < 0) - return ret; - if (avctx->codec_tag == MKTAG('V', 'P', '4', '0')) { s->version = 3; #if !CONFIG_VP4_DECODER @@ -2522,61 +2501,42 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) } /// Release and shuffle frames after decode finishes -static int update_frames(AVCodecContext *avctx) +static void update_frames(AVCodecContext *avctx) { Vp3DecodeContext *s = avctx->priv_data; - int ret = 0; - if (s->keyframe) { - ff_thread_release_ext_buffer(&s->golden_frame); - ret = ff_thread_ref_frame(&s->golden_frame, &s->current_frame); - } + if (s->keyframe) + ff_progress_frame_replace(&s->golden_frame, &s->current_frame); + /* shuffle frames */ - ff_thread_release_ext_buffer(&s->last_frame); - FFSWAP(ThreadFrame, s->last_frame, s->current_frame); - - return ret; + ff_progress_frame_unref(&s->last_frame); + FFSWAP(ProgressFrame, s->last_frame, s->current_frame); } #if HAVE_THREADS -static int ref_frame(ThreadFrame *dst, const ThreadFrame *src) +static void ref_frames(Vp3DecodeContext *dst, const Vp3DecodeContext *src) { - ff_thread_release_ext_buffer(dst); - if (src->f->data[0]) - return ff_thread_ref_frame(dst, src); - return 0; -} - -static int ref_frames(Vp3DecodeContext *dst, const Vp3DecodeContext *src) -{ - int ret; - if ((ret = ref_frame(&dst->current_frame, &src->current_frame)) < 0 || - (ret = ref_frame(&dst->golden_frame, &src->golden_frame)) < 0 || - (ret = ref_frame(&dst->last_frame, &src->last_frame)) < 0) - return ret; - return 0; + 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) { Vp3DecodeContext *s = dst->priv_data; const Vp3DecodeContext *s1 = src->priv_data; - int qps_changed = 0, err; + int qps_changed = 0; ff_refstruct_replace(&s->coeff_vlc, s1->coeff_vlc); - if (!s1->current_frame.f->data[0] || + // copy previous frame data + ref_frames(s, s1); + if (!s1->current_frame.f || s->width != s1->width || s->height != s1->height) { - if (s != s1) - ref_frames(s, s1); return -1; } if (s != s1) { - // copy previous frame data - if ((err = ref_frames(s, s1)) < 0) - return err; - s->keyframe = s1->keyframe; // copy qscale data if necessary @@ -2598,7 +2558,8 @@ static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext * } } - return update_frames(dst); + update_frames(dst); + return 0; } #endif @@ -2689,15 +2650,20 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, 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, + 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; + } s->current_frame.f->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; if (s->keyframe) s->current_frame.f->flags |= AV_FRAME_FLAG_KEY; else s->current_frame.f->flags &= ~AV_FRAME_FLAG_KEY; - if ((ret = ff_thread_get_ext_buffer(avctx, &s->current_frame, - AV_GET_BUFFER_FLAG_REF)) < 0) - goto error; if (!s->edge_emu_buffer) { s->edge_emu_buffer = av_malloc(9 * FFABS(s->current_frame.f->linesize[0])); @@ -2755,19 +2721,16 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, #endif } } else { - if (!s->golden_frame.f->data[0]) { + if (!s->golden_frame.f) { av_log(s->avctx, AV_LOG_WARNING, "vp3: first frame not a keyframe\n"); + if ((ret = ff_progress_frame_get_buffer(avctx, &s->golden_frame, + AV_GET_BUFFER_FLAG_REF)) < 0) + goto error; s->golden_frame.f->pict_type = AV_PICTURE_TYPE_I; - if ((ret = ff_thread_get_ext_buffer(avctx, &s->golden_frame, - AV_GET_BUFFER_FLAG_REF)) < 0) - goto error; - ff_thread_release_ext_buffer(&s->last_frame); - if ((ret = ff_thread_ref_frame(&s->last_frame, - &s->golden_frame)) < 0) - goto error; - ff_thread_report_progress(&s->last_frame, INT_MAX, 0); + ff_progress_frame_replace(&s->last_frame, &s->golden_frame); + ff_progress_frame_report(&s->golden_frame, INT_MAX); } } ff_thread_finish_setup(avctx); @@ -2845,16 +2808,13 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame, *got_frame = 1; - if (!HAVE_THREADS || !(s->avctx->active_thread_type & FF_THREAD_FRAME)) { - ret = update_frames(avctx); - if (ret < 0) - return ret; - } + if (!HAVE_THREADS || !(s->avctx->active_thread_type & FF_THREAD_FRAME)) + update_frames(avctx); return buf_size; error: - ff_thread_report_progress(&s->current_frame, INT_MAX, 0); + 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); @@ -3204,7 +3164,8 @@ const FFCodec ff_theora_decoder = { .flush = vp3_decode_flush, UPDATE_THREAD_CONTEXT(vp3_update_thread_context), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | - FF_CODEC_CAP_EXPORTS_CROPPING | FF_CODEC_CAP_ALLOCATE_PROGRESS, + FF_CODEC_CAP_EXPORTS_CROPPING | + FF_CODEC_CAP_USES_PROGRESSFRAMES, }; #endif @@ -3222,7 +3183,7 @@ const FFCodec ff_vp3_decoder = { .flush = vp3_decode_flush, UPDATE_THREAD_CONTEXT(vp3_update_thread_context), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | - FF_CODEC_CAP_ALLOCATE_PROGRESS, + FF_CODEC_CAP_USES_PROGRESSFRAMES, }; #if CONFIG_VP4_DECODER @@ -3240,6 +3201,6 @@ const FFCodec ff_vp4_decoder = { .flush = vp3_decode_flush, UPDATE_THREAD_CONTEXT(vp3_update_thread_context), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | - FF_CODEC_CAP_ALLOCATE_PROGRESS, + FF_CODEC_CAP_USES_PROGRESSFRAMES, }; #endif diff --git a/libavcodec/vp56.c b/libavcodec/vp56.c index f2ee3fafd..1da47ca43 100644 --- a/libavcodec/vp56.c +++ b/libavcodec/vp56.c @@ -23,6 +23,7 @@ * VP5 and VP6 compatible video decoder (common features) */ +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "decode.h" diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index faca7ecc1..d6df01865 100644 --- a/libavcodec/vp8.c +++ b/libavcodec/vp8.c @@ -26,6 +26,7 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" @@ -34,9 +35,9 @@ #include "hwaccel_internal.h" #include "hwconfig.h" #include "mathops.h" +#include "progressframe.h" #include "refstruct.h" #include "thread.h" -#include "threadframe.h" #include "vp8.h" #include "vp89_rac.h" #include "vp8data.h" @@ -102,9 +103,9 @@ static void free_buffers(VP8Context *s) static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref) { - int ret; - if ((ret = ff_thread_get_ext_buffer(s->avctx, &f->tf, - ref ? AV_GET_BUFFER_FLAG_REF : 0)) < 0) + int ret = ff_progress_frame_get_buffer(s->avctx, &f->tf, + ref ? AV_GET_BUFFER_FLAG_REF : 0); + if (ret < 0) return ret; f->seg_map = ff_refstruct_allocz(s->mb_width * s->mb_height); if (!f->seg_map) { @@ -119,7 +120,7 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref) fail: ff_refstruct_unref(&f->seg_map); - ff_thread_release_ext_buffer(&f->tf); + ff_progress_frame_unref(&f->tf); return ret; } @@ -127,27 +128,10 @@ static void vp8_release_frame(VP8Frame *f) { ff_refstruct_unref(&f->seg_map); ff_refstruct_unref(&f->hwaccel_picture_private); - ff_thread_release_ext_buffer(&f->tf); + ff_progress_frame_unref(&f->tf); } -#if CONFIG_VP8_DECODER -static int vp8_ref_frame(VP8Frame *dst, const VP8Frame *src) -{ - int ret; - - vp8_release_frame(dst); - - if ((ret = ff_thread_ref_frame(&dst->tf, &src->tf)) < 0) - return ret; - ff_refstruct_replace(&dst->seg_map, src->seg_map); - ff_refstruct_replace(&dst->hwaccel_picture_private, - src->hwaccel_picture_private); - - return 0; -} -#endif /* CONFIG_VP8_DECODER */ - -static void vp8_decode_flush_impl(AVCodecContext *avctx, int free_mem) +static av_cold void vp8_decode_flush_impl(AVCodecContext *avctx, int free_mem) { VP8Context *s = avctx->priv_data; int i; @@ -163,7 +147,7 @@ static void vp8_decode_flush_impl(AVCodecContext *avctx, int free_mem) FF_HW_SIMPLE_CALL(avctx, flush); } -static void vp8_decode_flush(AVCodecContext *avctx) +static av_cold void vp8_decode_flush(AVCodecContext *avctx) { vp8_decode_flush_impl(avctx, 0); } @@ -186,7 +170,7 @@ static VP8Frame *vp8_find_free_buffer(VP8Context *s) av_log(s->avctx, AV_LOG_FATAL, "Ran out of free frames!\n"); abort(); } - if (frame->tf.f->buf[0]) + if (frame->tf.f) vp8_release_frame(frame); return frame; @@ -1839,7 +1823,7 @@ static const uint8_t subpel_idx[3][8] = { */ static av_always_inline void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, uint8_t *dst, - const ThreadFrame *ref, const VP8mv *mv, + const ProgressFrame *ref, const VP8mv *mv, int x_off, int y_off, int block_w, int block_h, int width, int height, ptrdiff_t linesize, vp8_mc_func mc_func[3][3]) @@ -1856,7 +1840,7 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, uint8_t *dst, y_off += mv->y >> 2; // edge emulation - ff_thread_await_progress(ref, (3 + y_off + block_h + subpel_idx[2][my]) >> 4, 0); + ff_progress_frame_await(ref, (3 + y_off + block_h + subpel_idx[2][my]) >> 4); src += y_off * linesize + x_off; if (x_off < mx_idx || x_off >= width - block_w - subpel_idx[2][mx] || y_off < my_idx || y_off >= height - block_h - subpel_idx[2][my]) { @@ -1872,7 +1856,7 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, uint8_t *dst, } mc_func[my_idx][mx_idx](dst, linesize, src, src_linesize, block_h, mx, my); } else { - ff_thread_await_progress(ref, (3 + y_off + block_h) >> 4, 0); + ff_progress_frame_await(ref, (3 + y_off + block_h) >> 4); mc_func[0][0](dst, linesize, src + y_off * linesize + x_off, linesize, block_h, 0, 0); } @@ -1897,7 +1881,7 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, uint8_t *dst, */ static av_always_inline void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1, - uint8_t *dst2, const ThreadFrame *ref, const VP8mv *mv, + uint8_t *dst2, const ProgressFrame *ref, const VP8mv *mv, int x_off, int y_off, int block_w, int block_h, int width, int height, ptrdiff_t linesize, vp8_mc_func mc_func[3][3]) @@ -1914,7 +1898,7 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1, // edge emulation src1 += y_off * linesize + x_off; src2 += y_off * linesize + x_off; - ff_thread_await_progress(ref, (3 + y_off + block_h + subpel_idx[2][my]) >> 3, 0); + ff_progress_frame_await(ref, (3 + y_off + block_h + subpel_idx[2][my]) >> 3); if (x_off < mx_idx || x_off >= width - block_w - subpel_idx[2][mx] || y_off < my_idx || y_off >= height - block_h - subpel_idx[2][my]) { s->vdsp.emulated_edge_mc(td->edge_emu_buffer, @@ -1939,7 +1923,7 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1, mc_func[my_idx][mx_idx](dst2, linesize, src2, linesize, block_h, mx, my); } } else { - ff_thread_await_progress(ref, (3 + y_off + block_h) >> 3, 0); + ff_progress_frame_await(ref, (3 + y_off + block_h) >> 3); mc_func[0][0](dst1, linesize, src1 + y_off * linesize + x_off, linesize, block_h, 0, 0); mc_func[0][0](dst2, linesize, src2 + y_off * linesize + x_off, linesize, block_h, 0, 0); } @@ -1947,7 +1931,7 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1, static av_always_inline void vp8_mc_part(VP8Context *s, VP8ThreadData *td, uint8_t *const dst[3], - const ThreadFrame *ref_frame, int x_off, int y_off, + const ProgressFrame *ref_frame, int x_off, int y_off, int bx_off, int by_off, int block_w, int block_h, int width, int height, const VP8mv *mv) { @@ -2012,7 +1996,7 @@ void inter_predict(VP8Context *s, VP8ThreadData *td, uint8_t *const dst[3], { int x_off = mb_x << 4, y_off = mb_y << 4; int width = 16 * s->mb_width, height = 16 * s->mb_height; - const ThreadFrame *ref = &s->framep[mb->ref_frame]->tf; + const ProgressFrame *ref = &s->framep[mb->ref_frame]->tf; const VP8mv *bmv = mb->bmv; switch (mb->partitioning) { @@ -2432,7 +2416,7 @@ static av_always_inline int decode_mb_row_no_filter(AVCodecContext *avctx, void // if we re-use the same map. if (prev_frame && s->segmentation.enabled && !s->segmentation.update_map) - ff_thread_await_progress(&prev_frame->tf, mb_y, 0); + ff_progress_frame_await(&prev_frame->tf, mb_y); mb = s->macroblocks + (s->mb_height - mb_y - 1) * 2; memset(mb - 1, 0, sizeof(*mb)); // zero left macroblock AV_WN32A(s->intra4x4_pred_mode_left, DC_PRED * 0x01010101); @@ -2640,7 +2624,7 @@ int vp78_decode_mb_row_sliced(AVCodecContext *avctx, void *tdata, int jobnr, td->mv_bounds.mv_max.y -= 64 * num_jobs; if (avctx->active_thread_type == FF_THREAD_FRAME) - ff_thread_report_progress(&curframe->tf, mb_y, 0); + ff_progress_frame_report(&curframe->tf, mb_y); } return 0; @@ -2708,7 +2692,7 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, // release no longer referenced frames for (i = 0; i < 5; i++) - if (s->frames[i].tf.f->buf[0] && + if (s->frames[i].tf.f && &s->frames[i] != prev_frame && &s->frames[i] != s->framep[VP8_FRAME_PREVIOUS] && &s->frames[i] != s->framep[VP8_FRAME_GOLDEN] && @@ -2737,14 +2721,14 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, goto err; } + if ((ret = vp8_alloc_frame(s, curframe, referenced)) < 0) + goto err; if (s->keyframe) curframe->tf.f->flags |= AV_FRAME_FLAG_KEY; else curframe->tf.f->flags &= ~AV_FRAME_FLAG_KEY; curframe->tf.f->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; - if ((ret = vp8_alloc_frame(s, curframe, referenced)) < 0) - goto err; // check if golden and altref are swapped if (s->update_altref != VP8_FRAME_NONE) @@ -2801,7 +2785,7 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, // if we re-use the same map. if (prev_frame && s->segmentation.enabled && !s->segmentation.update_map) - ff_thread_await_progress(&prev_frame->tf, 1, 0); + ff_progress_frame_await(&prev_frame->tf, 1); if (is_vp7) ret = vp7_decode_mv_mb_modes(avctx, curframe, prev_frame); else @@ -2832,7 +2816,7 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, num_jobs); } - ff_thread_report_progress(&curframe->tf, INT_MAX, 0); + ff_progress_frame_report(&curframe->tf, INT_MAX); memcpy(&s->framep[0], &s->next_framep[0], sizeof(s->framep[0]) * 4); skip_decode: @@ -2869,32 +2853,15 @@ static int vp7_decode_frame(AVCodecContext *avctx, AVFrame *frame, av_cold int ff_vp8_decode_free(AVCodecContext *avctx) { - VP8Context *s = avctx->priv_data; - int i; - vp8_decode_flush_impl(avctx, 1); - for (i = 0; i < FF_ARRAY_ELEMS(s->frames); i++) - av_frame_free(&s->frames[i].tf.f); return 0; } -static av_cold int vp8_init_frames(VP8Context *s) -{ - int i; - for (i = 0; i < FF_ARRAY_ELEMS(s->frames); i++) { - s->frames[i].tf.f = av_frame_alloc(); - if (!s->frames[i].tf.f) - return AVERROR(ENOMEM); - } - return 0; -} - static av_always_inline int vp78_decode_init(AVCodecContext *avctx, int is_vp7) { VP8Context *s = avctx->priv_data; - int ret; s->avctx = avctx; s->pix_fmt = AV_PIX_FMT_NONE; @@ -2918,11 +2885,6 @@ int vp78_decode_init(AVCodecContext *avctx, int is_vp7) /* does not change for VP8 */ memcpy(s->prob[0].scan, ff_zigzag_scan, sizeof(s->prob[0].scan)); - if ((ret = vp8_init_frames(s)) < 0) { - ff_vp8_decode_free(avctx); - return ret; - } - return 0; } @@ -2940,13 +2902,20 @@ av_cold int ff_vp8_decode_init(AVCodecContext *avctx) #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, + src->hwaccel_picture_private); +} + #define REBASE(pic) ((pic) ? (pic) - &s_src->frames[0] + &s->frames[0] : NULL) static int vp8_decode_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { VP8Context *s = dst->priv_data, *s_src = src->priv_data; - int i; if (s->macroblocks_base && (s_src->mb_width != s->mb_width || s_src->mb_height != s->mb_height)) { @@ -2961,13 +2930,8 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst, s->lf_delta = s_src->lf_delta; memcpy(s->sign_bias, s_src->sign_bias, sizeof(s->sign_bias)); - for (i = 0; i < FF_ARRAY_ELEMS(s_src->frames); i++) { - if (s_src->frames[i].tf.f->buf[0]) { - int ret = vp8_ref_frame(&s->frames[i], &s_src->frames[i]); - if (ret < 0) - return ret; - } - } + for (int i = 0; i < FF_ARRAY_ELEMS(s_src->frames); i++) + vp8_replace_frame(&s->frames[i], &s_src->frames[i]); s->framep[0] = REBASE(s_src->next_framep[0]); s->framep[1] = REBASE(s_src->next_framep[1]); @@ -2991,6 +2955,7 @@ const FFCodec ff_vp7_decoder = { FF_CODEC_DECODE_CB(vp7_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1, .flush = vp8_decode_flush, + .caps_internal = FF_CODEC_CAP_USES_PROGRESSFRAMES, }; #endif /* CONFIG_VP7_DECODER */ @@ -3006,7 +2971,7 @@ const FFCodec ff_vp8_decoder = { FF_CODEC_DECODE_CB(ff_vp8_decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS, - .caps_internal = FF_CODEC_CAP_ALLOCATE_PROGRESS, + .caps_internal = FF_CODEC_CAP_USES_PROGRESSFRAMES, .flush = vp8_decode_flush, UPDATE_THREAD_CONTEXT(vp8_decode_update_thread_context), .hw_configs = (const AVCodecHWConfigInternal *const []) { diff --git a/libavcodec/vp8.h b/libavcodec/vp8.h index 798f67b3d..9bdef0aa8 100644 --- a/libavcodec/vp8.h +++ b/libavcodec/vp8.h @@ -31,8 +31,9 @@ #include "libavutil/mem_internal.h" #include "libavutil/thread.h" +#include "avcodec.h" #include "h264pred.h" -#include "threadframe.h" +#include "progressframe.h" #include "videodsp.h" #include "vp8dsp.h" #include "vpx_rac.h" @@ -150,7 +151,7 @@ typedef struct VP8ThreadData { } VP8ThreadData; typedef struct VP8Frame { - ThreadFrame tf; + ProgressFrame tf; uint8_t *seg_map; ///< RefStruct reference void *hwaccel_picture_private; ///< RefStruct reference diff --git a/libavcodec/vp8dsp.c b/libavcodec/vp8dsp.c index 72d4ea379..88bb67f78 100644 --- a/libavcodec/vp8dsp.c +++ b/libavcodec/vp8dsp.c @@ -681,6 +681,8 @@ av_cold void ff_vp78dsp_init(VP8DSPContext *dsp) ff_vp78dsp_init_arm(dsp); #elif ARCH_PPC ff_vp78dsp_init_ppc(dsp); +#elif ARCH_RISCV + ff_vp78dsp_init_riscv(dsp); #elif ARCH_X86 ff_vp78dsp_init_x86(dsp); #endif @@ -710,6 +712,10 @@ av_cold void ff_vp7dsp_init(VP8DSPContext *dsp) dsp->vp8_v_loop_filter_simple = vp7_v_loop_filter_simple_c; dsp->vp8_h_loop_filter_simple = vp7_h_loop_filter_simple_c; + +#if ARCH_RISCV + ff_vp7dsp_init_riscv(dsp); +#endif } #endif /* CONFIG_VP7_DECODER */ diff --git a/libavcodec/vp8dsp.h b/libavcodec/vp8dsp.h index 30dc2c6cc..e3de2e049 100644 --- a/libavcodec/vp8dsp.h +++ b/libavcodec/vp8dsp.h @@ -87,8 +87,11 @@ void ff_vp78dsp_init(VP8DSPContext *c); void ff_vp78dsp_init_aarch64(VP8DSPContext *c); void ff_vp78dsp_init_arm(VP8DSPContext *c); void ff_vp78dsp_init_ppc(VP8DSPContext *c); +void ff_vp78dsp_init_riscv(VP8DSPContext *c); void ff_vp78dsp_init_x86(VP8DSPContext *c); +void ff_vp7dsp_init_riscv(VP8DSPContext *c); + void ff_vp8dsp_init(VP8DSPContext *c); void ff_vp8dsp_init_aarch64(VP8DSPContext *c); void ff_vp8dsp_init_arm(VP8DSPContext *c); diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c index 4cc528130..8ede2e2eb 100644 --- a/libavcodec/vp9.c +++ b/libavcodec/vp9.c @@ -30,9 +30,9 @@ #include "hwaccel_internal.h" #include "hwconfig.h" #include "profiles.h" +#include "progressframe.h" #include "refstruct.h" #include "thread.h" -#include "threadframe.h" #include "pthread_internal.h" #include "videodsp.h" @@ -42,6 +42,7 @@ #include "vp9dec.h" #include "vpx_rac.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/video_enc_params.h" @@ -54,7 +55,6 @@ DEFINE_OFFSET_ARRAY(VP9Context, vp9_context, pthread_init_cnt, static int vp9_alloc_entries(AVCodecContext *avctx, int n) { VP9Context *s = avctx->priv_data; - int i; if (avctx->active_thread_type & FF_THREAD_SLICE) { if (s->entries) @@ -63,9 +63,6 @@ static int vp9_alloc_entries(AVCodecContext *avctx, int n) { s->entries = av_malloc_array(n, sizeof(atomic_int)); if (!s->entries) return AVERROR(ENOMEM); - - for (i = 0; i < n; i++) - atomic_init(&s->entries[i], 0); } return 0; } @@ -99,7 +96,7 @@ static void vp9_tile_data_free(VP9TileData *td) static void vp9_frame_unref(VP9Frame *f) { - ff_thread_release_ext_buffer(&f->tf); + ff_progress_frame_unref(&f->tf); ff_refstruct_unref(&f->extradata); ff_refstruct_unref(&f->hwaccel_picture_private); f->segmentation_map = NULL; @@ -110,7 +107,7 @@ static int vp9_frame_alloc(AVCodecContext *avctx, VP9Frame *f) VP9Context *s = avctx->priv_data; int ret, sz; - ret = ff_thread_get_ext_buffer(avctx, &f->tf, AV_GET_BUFFER_FLAG_REF); + ret = ff_progress_frame_get_buffer(avctx, &f->tf, AV_GET_BUFFER_FLAG_REF); if (ret < 0) return ret; @@ -146,15 +143,11 @@ fail: return ret; } -static int vp9_frame_ref(VP9Frame *dst, VP9Frame *src) +static void vp9_frame_replace(VP9Frame *dst, const VP9Frame *src) { - int ret; + ff_progress_frame_replace(&dst->tf, &src->tf); - ret = ff_thread_ref_frame(&dst->tf, &src->tf); - if (ret < 0) - return ret; - - dst->extradata = ff_refstruct_ref(src->extradata); + ff_refstruct_replace(&dst->extradata, src->extradata); dst->segmentation_map = src->segmentation_map; dst->mv = src->mv; @@ -162,8 +155,6 @@ static int vp9_frame_ref(VP9Frame *dst, VP9Frame *src) ff_refstruct_replace(&dst->hwaccel_picture_private, src->hwaccel_picture_private); - - return 0; } static int update_size(AVCodecContext *avctx, int w, int h) @@ -588,9 +579,9 @@ static int decode_frame_header(AVCodecContext *avctx, s->s.h.signbias[1] = get_bits1(&s->gb) && !s->s.h.errorres; s->s.h.refidx[2] = get_bits(&s->gb, 3); s->s.h.signbias[2] = get_bits1(&s->gb) && !s->s.h.errorres; - if (!s->s.refs[s->s.h.refidx[0]].f->buf[0] || - !s->s.refs[s->s.h.refidx[1]].f->buf[0] || - !s->s.refs[s->s.h.refidx[2]].f->buf[0]) { + if (!s->s.refs[s->s.h.refidx[0]].f || + !s->s.refs[s->s.h.refidx[1]].f || + !s->s.refs[s->s.h.refidx[2]].f) { av_log(avctx, AV_LOG_ERROR, "Not all references are available\n"); return AVERROR_INVALIDDATA; } @@ -610,7 +601,8 @@ static int decode_frame_header(AVCodecContext *avctx, // Note that in this code, "CUR_FRAME" is actually before we // have formally allocated a frame, and thus actually represents // the _last_ frame - s->s.h.use_last_frame_mvs &= s->s.frames[CUR_FRAME].tf.f->width == w && + s->s.h.use_last_frame_mvs &= s->s.frames[CUR_FRAME].tf.f && + s->s.frames[CUR_FRAME].tf.f->width == w && s->s.frames[CUR_FRAME].tf.f->height == h; if (get_bits1(&s->gb)) // display size skip_bits(&s->gb, 32); @@ -1245,16 +1237,12 @@ static av_cold int vp9_decode_free(AVCodecContext *avctx) VP9Context *s = avctx->priv_data; int i; - for (i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) vp9_frame_unref(&s->s.frames[i]); - av_frame_free(&s->s.frames[i].tf.f); - } ff_refstruct_pool_uninit(&s->frame_extradata_pool); for (i = 0; i < 8; i++) { - ff_thread_release_ext_buffer(&s->s.refs[i]); - av_frame_free(&s->s.refs[i].f); - ff_thread_release_ext_buffer(&s->next_refs[i]); - av_frame_free(&s->next_refs[i].f); + ff_progress_frame_unref(&s->s.refs[i]); + ff_progress_frame_unref(&s->next_refs[i]); } free_buffers(s); @@ -1389,7 +1377,7 @@ static int decode_tiles(AVCodecContext *avctx, // FIXME maybe we can make this more finegrained by running the // loopfilter per-block instead of after each sbrow // In fact that would also make intra pred left preparation easier? - ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, row >> 3, 0); + ff_progress_frame_report(&s->s.frames[CUR_FRAME].tf, row >> 3); } } return 0; @@ -1566,46 +1554,37 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, int ret, i, j, ref; 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; if ((ret = decode_frame_header(avctx, data, size, &ref)) < 0) { return ret; } else if (ret == 0) { - if (!s->s.refs[ref].f->buf[0]) { + if (!s->s.refs[ref].f) { av_log(avctx, AV_LOG_ERROR, "Requested reference %d not available\n", ref); 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); + if ((ret = av_frame_ref(frame, s->s.refs[ref].f)) < 0) return ret; frame->pts = pkt->pts; frame->pkt_dts = pkt->dts; - for (i = 0; i < 8; i++) { - if (s->next_refs[i].f->buf[0]) - ff_thread_release_ext_buffer(&s->next_refs[i]); - if (s->s.refs[i].f->buf[0] && - (ret = ff_thread_ref_frame(&s->next_refs[i], &s->s.refs[i])) < 0) - return ret; - } *got_frame = 1; return pkt->size; } data += ret; size -= ret; - if (!retain_segmap_ref || s->s.h.keyframe || s->s.h.intraonly) { - if (s->s.frames[REF_FRAME_SEGMAP].tf.f->buf[0]) - vp9_frame_unref(&s->s.frames[REF_FRAME_SEGMAP]); - if (!s->s.h.keyframe && !s->s.h.intraonly && !s->s.h.errorres && s->s.frames[CUR_FRAME].tf.f->buf[0] && - (ret = vp9_frame_ref(&s->s.frames[REF_FRAME_SEGMAP], &s->s.frames[CUR_FRAME])) < 0) - return ret; - } - if (s->s.frames[REF_FRAME_MVPAIR].tf.f->buf[0]) - vp9_frame_unref(&s->s.frames[REF_FRAME_MVPAIR]); - if (!s->s.h.intraonly && !s->s.h.keyframe && !s->s.h.errorres && s->s.frames[CUR_FRAME].tf.f->buf[0] && - (ret = vp9_frame_ref(&s->s.frames[REF_FRAME_MVPAIR], &s->s.frames[CUR_FRAME])) < 0) - return ret; - if (s->s.frames[CUR_FRAME].tf.f->buf[0]) - vp9_frame_unref(&s->s.frames[CUR_FRAME]); + src = !s->s.h.keyframe && !s->s.h.intraonly && !s->s.h.errorres ? + &s->s.frames[CUR_FRAME] : &s->s.frames[BLANK_FRAME]; + if (!retain_segmap_ref || s->s.h.keyframe || s->s.h.intraonly) + vp9_frame_replace(&s->s.frames[REF_FRAME_SEGMAP], src); + vp9_frame_replace(&s->s.frames[REF_FRAME_MVPAIR], src); + vp9_frame_unref(&s->s.frames[CUR_FRAME]); if ((ret = vp9_frame_alloc(avctx, &s->s.frames[CUR_FRAME])) < 0) return ret; f = s->s.frames[CUR_FRAME].tf.f; @@ -1615,7 +1594,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, f->flags &= ~AV_FRAME_FLAG_KEY; f->pict_type = (s->s.h.keyframe || s->s.h.intraonly) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; - if (s->s.frames[REF_FRAME_SEGMAP].tf.f->buf[0] && + // Non-existent frames have the implicit dimension 0x0 != CUR_FRAME + if (!s->s.frames[REF_FRAME_MVPAIR].tf.f || (s->s.frames[REF_FRAME_MVPAIR].tf.f->width != s->s.frames[CUR_FRAME].tf.f->width || s->s.frames[REF_FRAME_MVPAIR].tf.f->height != s->s.frames[CUR_FRAME].tf.f->height)) { vp9_frame_unref(&s->s.frames[REF_FRAME_SEGMAP]); @@ -1623,15 +1603,9 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, // ref frame setup for (i = 0; i < 8; i++) { - if (s->next_refs[i].f->buf[0]) - ff_thread_release_ext_buffer(&s->next_refs[i]); - if (s->s.h.refreshrefmask & (1 << i)) { - ret = ff_thread_ref_frame(&s->next_refs[i], &s->s.frames[CUR_FRAME].tf); - } else if (s->s.refs[i].f->buf[0]) { - ret = ff_thread_ref_frame(&s->next_refs[i], &s->s.refs[i]); - } - if (ret < 0) - return ret; + ff_progress_frame_replace(&s->next_refs[i], + s->s.h.refreshrefmask & (1 << i) ? + &s->s.frames[CUR_FRAME].tf : &s->s.refs[i]); } if (avctx->hwaccel) { @@ -1689,7 +1663,7 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, #if HAVE_THREADS if (avctx->active_thread_type & FF_THREAD_SLICE) { for (i = 0; i < s->sb_rows; i++) - atomic_store(&s->entries[i], 0); + atomic_init(&s->entries[i], 0); } #endif @@ -1740,10 +1714,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, #endif { ret = decode_tiles(avctx, data, size); - if (ret < 0) { - ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0); - return ret; - } + if (ret < 0) + goto fail; } // Sum all counts fields into td[0].counts for tile threading @@ -1757,28 +1729,24 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame, ff_thread_finish_setup(avctx); } } while (s->pass++ == 1); - ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0); if (s->td->error_info < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to decode tile data\n"); s->td->error_info = 0; - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } if (avctx->export_side_data & AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS) { ret = vp9_export_enc_params(s, &s->s.frames[CUR_FRAME]); if (ret < 0) - return ret; + goto fail; } finish: + ff_progress_frame_report(&s->s.frames[CUR_FRAME].tf, INT_MAX); // ref frame setup - for (i = 0; i < 8; i++) { - if (s->s.refs[i].f->buf[0]) - ff_thread_release_ext_buffer(&s->s.refs[i]); - if (s->next_refs[i].f->buf[0] && - (ret = ff_thread_ref_frame(&s->s.refs[i], &s->next_refs[i])) < 0) - return ret; - } + for (int i = 0; i < 8; i++) + ff_progress_frame_replace(&s->s.refs[i], &s->next_refs[i]); if (!s->s.h.invisible) { if ((ret = av_frame_ref(frame, s->s.frames[CUR_FRAME].tf.f)) < 0) @@ -1787,6 +1755,9 @@ finish: } return pkt->size; +fail: + ff_progress_frame_report(&s->s.frames[CUR_FRAME].tf, INT_MAX); + return ret; } static void vp9_decode_flush(AVCodecContext *avctx) @@ -1797,7 +1768,7 @@ static void vp9_decode_flush(AVCodecContext *avctx) for (i = 0; i < 3; i++) vp9_frame_unref(&s->s.frames[i]); for (i = 0; i < 8; i++) - ff_thread_release_ext_buffer(&s->s.refs[i]); + ff_progress_frame_unref(&s->s.refs[i]); if (FF_HW_HAS_CB(avctx, flush)) FF_HW_SIMPLE_CALL(avctx, flush); @@ -1819,42 +1790,18 @@ static av_cold int vp9_decode_init(AVCodecContext *avctx) } #endif - for (int i = 0; i < 3; i++) { - s->s.frames[i].tf.f = av_frame_alloc(); - if (!s->s.frames[i].tf.f) - return AVERROR(ENOMEM); - } - for (int i = 0; i < 8; i++) { - s->s.refs[i].f = av_frame_alloc(); - s->next_refs[i].f = av_frame_alloc(); - if (!s->s.refs[i].f || !s->next_refs[i].f) - return AVERROR(ENOMEM); - } return 0; } #if HAVE_THREADS static int vp9_decode_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { - int i, ret; VP9Context *s = dst->priv_data, *ssrc = src->priv_data; - for (i = 0; i < 3; i++) { - if (s->s.frames[i].tf.f->buf[0]) - vp9_frame_unref(&s->s.frames[i]); - if (ssrc->s.frames[i].tf.f->buf[0]) { - if ((ret = vp9_frame_ref(&s->s.frames[i], &ssrc->s.frames[i])) < 0) - return ret; - } - } - for (i = 0; i < 8; i++) { - if (s->s.refs[i].f->buf[0]) - ff_thread_release_ext_buffer(&s->s.refs[i]); - if (ssrc->next_refs[i].f->buf[0]) { - if ((ret = ff_thread_ref_frame(&s->s.refs[i], &ssrc->next_refs[i])) < 0) - return ret; - } - } + for (int i = 0; i < 3; i++) + 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); s->frame_extradata_pool_size = ssrc->frame_extradata_pool_size; @@ -1894,7 +1841,7 @@ const FFCodec ff_vp9_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_SLICE_THREAD_HAS_MF | - FF_CODEC_CAP_ALLOCATE_PROGRESS, + FF_CODEC_CAP_USES_PROGRESSFRAMES, .flush = vp9_decode_flush, UPDATE_THREAD_CONTEXT(vp9_decode_update_thread_context), .p.profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles), diff --git a/libavcodec/vp9_mc_template.c b/libavcodec/vp9_mc_template.c index e654c0e5e..81e4ed59c 100644 --- a/libavcodec/vp9_mc_template.c +++ b/libavcodec/vp9_mc_template.c @@ -36,7 +36,7 @@ static void FN(inter_pred)(VP9TileData *td) const VP9Context *s = td->s; VP9Block *b = td->b; int row = td->row, col = td->col; - const ThreadFrame *tref1 = &s->s.refs[s->s.h.refidx[b->ref[0]]], *tref2; + const ProgressFrame *tref1 = &s->s.refs[s->s.h.refidx[b->ref[0]]], *tref2; const AVFrame *ref1 = tref1->f, *ref2; int w1 = ref1->width, h1 = ref1->height, w2, h2; ptrdiff_t ls_y = td->y_stride, ls_uv = td->uv_stride; diff --git a/libavcodec/vp9block.c b/libavcodec/vp9block.c index 5743f048c..3a694763c 100644 --- a/libavcodec/vp9block.c +++ b/libavcodec/vp9block.c @@ -22,8 +22,9 @@ */ #include "libavutil/avassert.h" +#include "libavutil/frame.h" -#include "threadframe.h" +#include "progressframe.h" #include "vp89_rac.h" #include "vp9.h" #include "vp9data.h" @@ -113,7 +114,7 @@ static void decode_mode(VP9TileData *td) uint8_t *refsegmap = s->s.frames[REF_FRAME_SEGMAP].segmentation_map; if (!s->s.frames[REF_FRAME_SEGMAP].uses_2pass) - ff_thread_await_progress(&s->s.frames[REF_FRAME_SEGMAP].tf, row >> 3, 0); + ff_progress_frame_await(&s->s.frames[REF_FRAME_SEGMAP].tf, row >> 3); for (y = 0; y < h4; y++) { int idx_base = (y + row) * 8 * s->sb_cols + col; for (x = 0; x < w4; x++) diff --git a/libavcodec/vp9dec.h b/libavcodec/vp9dec.h index 013aac49e..81dc80105 100644 --- a/libavcodec/vp9dec.h +++ b/libavcodec/vp9dec.h @@ -29,8 +29,8 @@ #include #include "libavutil/mem_internal.h" +#include "libavutil/pixfmt.h" #include "libavutil/thread.h" -#include "libavutil/internal.h" #include "get_bits.h" #include "videodsp.h" @@ -120,7 +120,7 @@ typedef struct VP9Context { int w, h; enum AVPixelFormat pix_fmt, last_fmt, gf_fmt; unsigned sb_cols, sb_rows, rows, cols; - ThreadFrame next_refs[8]; + ProgressFrame next_refs[8]; struct { uint8_t lim_lut[64]; @@ -245,7 +245,7 @@ void ff_vp9_decode_block(VP9TileData *td, int row, int col, VP9Filter *lflvl, ptrdiff_t yoff, ptrdiff_t uvoff, enum BlockLevel bl, enum BlockPartition bp); -void ff_vp9_loopfilter_sb(AVCodecContext *avctx, VP9Filter *lflvl, +void ff_vp9_loopfilter_sb(struct AVCodecContext *avctx, VP9Filter *lflvl, int row, int col, ptrdiff_t yoff, ptrdiff_t uvoff); void ff_vp9_intra_recon_8bpp(VP9TileData *td, diff --git a/libavcodec/vp9dsp.c b/libavcodec/vp9dsp.c index d8ddf74d4..967e6e1e1 100644 --- a/libavcodec/vp9dsp.c +++ b/libavcodec/vp9dsp.c @@ -100,6 +100,8 @@ av_cold void ff_vp9dsp_init(VP9DSPContext *dsp, int bpp, int bitexact) ff_vp9dsp_init_aarch64(dsp, bpp); #elif ARCH_ARM ff_vp9dsp_init_arm(dsp, bpp); +#elif ARCH_RISCV + ff_vp9dsp_init_riscv(dsp, bpp, bitexact); #elif ARCH_X86 ff_vp9dsp_init_x86(dsp, bpp, bitexact); #elif ARCH_MIPS diff --git a/libavcodec/vp9dsp.h b/libavcodec/vp9dsp.h index be0ac0b18..772848e34 100644 --- a/libavcodec/vp9dsp.h +++ b/libavcodec/vp9dsp.h @@ -131,6 +131,7 @@ void ff_vp9dsp_init_12(VP9DSPContext *dsp); void ff_vp9dsp_init_aarch64(VP9DSPContext *dsp, int bpp); void ff_vp9dsp_init_arm(VP9DSPContext *dsp, int bpp); +void ff_vp9dsp_init_riscv(VP9DSPContext *dsp, int bpp, int bitexact); void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact); void ff_vp9dsp_init_mips(VP9DSPContext *dsp, int bpp); void ff_vp9dsp_init_loongarch(VP9DSPContext *dsp, int bpp); diff --git a/libavcodec/vp9dsp_template.c b/libavcodec/vp9dsp_template.c index 9b1166170..9e5b25142 100644 --- a/libavcodec/vp9dsp_template.c +++ b/libavcodec/vp9dsp_template.c @@ -30,7 +30,7 @@ // FIXME see whether we can merge parts of this (perhaps at least 4x4 and 8x8) // back with h264pred.[ch] -static void vert_4x4_c(uint8_t *_dst, ptrdiff_t stride, +static void vert_4x4_c(uint8_t *restrict _dst, ptrdiff_t stride, const uint8_t *left, const uint8_t *_top) { pixel *dst = (pixel *) _dst; @@ -44,49 +44,73 @@ static void vert_4x4_c(uint8_t *_dst, ptrdiff_t stride, AV_WN4PA(dst + stride * 3, p4); } -static void vert_8x8_c(uint8_t *_dst, ptrdiff_t stride, +static void vert_8x8_c(uint8_t *restrict _dst, ptrdiff_t stride, const uint8_t *left, const uint8_t *_top) { pixel *dst = (pixel *) _dst; const pixel *top = (const pixel *) _top; +#if BIT_DEPTH == 8 + uint64_t p8 = AV_RN64A(top); +#else pixel4 p4a = AV_RN4PA(top + 0); pixel4 p4b = AV_RN4PA(top + 4); +#endif int y; stride /= sizeof(pixel); for (y = 0; y < 8; y++) { +#if BIT_DEPTH == 8 + AV_WN64A(dst, p8); +#else AV_WN4PA(dst + 0, p4a); AV_WN4PA(dst + 4, p4b); +#endif dst += stride; } } -static void vert_16x16_c(uint8_t *_dst, ptrdiff_t stride, +static void vert_16x16_c(uint8_t *restrict _dst, ptrdiff_t stride, const uint8_t *left, const uint8_t *_top) { pixel *dst = (pixel *) _dst; const pixel *top = (const pixel *) _top; +#if BIT_DEPTH == 8 + uint64_t p8a = AV_RN64A(top); + uint64_t p8b = AV_RN64A(top + 8); +#else pixel4 p4a = AV_RN4PA(top + 0); pixel4 p4b = AV_RN4PA(top + 4); pixel4 p4c = AV_RN4PA(top + 8); pixel4 p4d = AV_RN4PA(top + 12); +#endif int y; stride /= sizeof(pixel); for (y = 0; y < 16; y++) { +#if BIT_DEPTH == 8 + AV_WN64A(dst + 0, p8a); + AV_WN64A(dst + 8, p8b); +#else AV_WN4PA(dst + 0, p4a); AV_WN4PA(dst + 4, p4b); AV_WN4PA(dst + 8, p4c); AV_WN4PA(dst + 12, p4d); +#endif dst += stride; } } -static void vert_32x32_c(uint8_t *_dst, ptrdiff_t stride, +static void vert_32x32_c(uint8_t *restrict _dst, ptrdiff_t stride, const uint8_t *left, const uint8_t *_top) { pixel *dst = (pixel *) _dst; const pixel *top = (const pixel *) _top; +#if BIT_DEPTH == 8 + uint64_t p8a = AV_RN64A(top); + uint64_t p8b = AV_RN64A(top + 8); + uint64_t p8c = AV_RN64A(top + 16); + uint64_t p8d = AV_RN64A(top + 24); +#else pixel4 p4a = AV_RN4PA(top + 0); pixel4 p4b = AV_RN4PA(top + 4); pixel4 p4c = AV_RN4PA(top + 8); @@ -95,10 +119,17 @@ static void vert_32x32_c(uint8_t *_dst, ptrdiff_t stride, pixel4 p4f = AV_RN4PA(top + 20); pixel4 p4g = AV_RN4PA(top + 24); pixel4 p4h = AV_RN4PA(top + 28); +#endif int y; stride /= sizeof(pixel); for (y = 0; y < 32; y++) { +#if BIT_DEPTH == 8 + AV_WN64A(dst + 0, p8a); + AV_WN64A(dst + 8, p8b); + AV_WN64A(dst + 16, p8c); + AV_WN64A(dst + 24, p8d); +#else AV_WN4PA(dst + 0, p4a); AV_WN4PA(dst + 4, p4b); AV_WN4PA(dst + 8, p4c); @@ -107,6 +138,7 @@ static void vert_32x32_c(uint8_t *_dst, ptrdiff_t stride, AV_WN4PA(dst + 20, p4f); AV_WN4PA(dst + 24, p4g); AV_WN4PA(dst + 28, p4h); +#endif dst += stride; } } @@ -1936,9 +1968,9 @@ static av_cold void vp9dsp_loopfilter_init(VP9DSPContext *dsp) #if BIT_DEPTH != 12 -static av_always_inline void copy_c(uint8_t *dst, ptrdiff_t dst_stride, - const uint8_t *src, ptrdiff_t src_stride, - int w, int h) +static av_always_inline void copy_c(uint8_t *restrict dst, ptrdiff_t dst_stride, + const uint8_t *restrict src, + ptrdiff_t src_stride, int w, int h) { do { memcpy(dst, src, w * sizeof(pixel)); @@ -1948,9 +1980,9 @@ static av_always_inline void copy_c(uint8_t *dst, ptrdiff_t dst_stride, } while (--h); } -static av_always_inline void avg_c(uint8_t *_dst, ptrdiff_t dst_stride, - const uint8_t *_src, ptrdiff_t src_stride, - int w, int h) +static av_always_inline void avg_c(uint8_t *restrict _dst, ptrdiff_t dst_stride, + const uint8_t *restrict _src, + ptrdiff_t src_stride, int w, int h) { pixel *dst = (pixel *) _dst; const pixel *src = (const pixel *) _src; diff --git a/libavcodec/vp9lpf.c b/libavcodec/vp9lpf.c index 414cede85..afeebebf5 100644 --- a/libavcodec/vp9lpf.c +++ b/libavcodec/vp9lpf.c @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "avcodec.h" #include "vp9dec.h" static av_always_inline void filter_plane_cols(VP9Context *s, int col, int ss_h, int ss_v, diff --git a/libavcodec/vp9mvs.c b/libavcodec/vp9mvs.c index b93d878d6..790cf629a 100644 --- a/libavcodec/vp9mvs.c +++ b/libavcodec/vp9mvs.c @@ -21,7 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "threadframe.h" +#include "progressframe.h" #include "vp89_rac.h" #include "vp9data.h" #include "vp9dec.h" @@ -175,7 +175,7 @@ static void find_ref_mvs(VP9TileData *td, VP9mvrefPair *mv = &s->s.frames[REF_FRAME_MVPAIR].mv[row * s->sb_cols * 8 + col]; if (!s->s.frames[REF_FRAME_MVPAIR].uses_2pass) - ff_thread_await_progress(&s->s.frames[REF_FRAME_MVPAIR].tf, row >> 3, 0); + ff_progress_frame_await(&s->s.frames[REF_FRAME_MVPAIR].tf, row >> 3); if (mv->ref[0] == ref) RETURN_MV(mv->mv[0]); else if (mv->ref[1] == ref) @@ -294,7 +294,8 @@ void ff_vp9_fill_mv(VP9TileData *td, VP9mv *mv, int mode, int sb) VP9Block *b = td->b; if (mode == ZEROMV) { - AV_ZERO64(mv); + AV_ZERO32(&mv[0]); + AV_ZERO32(&mv[1]); } else { int hp; diff --git a/libavcodec/vp9recon.c b/libavcodec/vp9recon.c index 073c04b47..ccc49d771 100644 --- a/libavcodec/vp9recon.c +++ b/libavcodec/vp9recon.c @@ -22,9 +22,10 @@ */ #include "libavutil/avassert.h" +#include "libavutil/frame.h" #include "libavutil/mem_internal.h" -#include "threadframe.h" +#include "progressframe.h" #include "videodsp.h" #include "vp9data.h" #include "vp9dec.h" @@ -298,7 +299,7 @@ void ff_vp9_intra_recon_16bpp(VP9TileData *td, ptrdiff_t y_off, ptrdiff_t uv_off static av_always_inline void mc_luma_unscaled(VP9TileData *td, const vp9_mc_func (*mc)[2], uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *ref, ptrdiff_t ref_stride, - const ThreadFrame *ref_frame, + const ProgressFrame *ref_frame, ptrdiff_t y, ptrdiff_t x, const VP9mv *mv, int bw, int bh, int w, int h, int bytesperpixel) { @@ -314,11 +315,15 @@ static av_always_inline void mc_luma_unscaled(VP9TileData *td, const vp9_mc_func // we use +7 because the last 7 pixels of each sbrow can be changed in // the longest loopfilter of the next sbrow th = (y + bh + 4 * !!my + 7) >> 6; - ff_thread_await_progress(ref_frame, FFMAX(th, 0), 0); + ff_progress_frame_await(ref_frame, FFMAX(th, 0)); // The arm/aarch64 _hv filters read one more row than what actually is // needed, so switch to emulated edge one pixel sooner vertically // (!!my * 5) than horizontally (!!mx * 4). + // The arm/aarch64 _h filters read one more pixel than what actually is + // needed, so switch to emulated edge if that would read beyond the bottom + // right block. if (x < !!mx * 3 || y < !!my * 3 || + ((ARCH_AARCH64 || ARCH_ARM) && (x + !!mx * 5 > w - bw) && (y + !!my * 5 + 1 > h - bh)) || x + !!mx * 4 > w - bw || y + !!my * 5 > h - bh) { s->vdsp.emulated_edge_mc(td->edge_emu_buffer, ref - !!my * 3 * ref_stride - !!mx * 3 * bytesperpixel, @@ -336,7 +341,7 @@ static av_always_inline void mc_chroma_unscaled(VP9TileData *td, const vp9_mc_fu ptrdiff_t dst_stride, const uint8_t *ref_u, ptrdiff_t src_stride_u, const uint8_t *ref_v, ptrdiff_t src_stride_v, - const ThreadFrame *ref_frame, + const ProgressFrame *ref_frame, ptrdiff_t y, ptrdiff_t x, const VP9mv *mv, int bw, int bh, int w, int h, int bytesperpixel) { @@ -353,11 +358,15 @@ static av_always_inline void mc_chroma_unscaled(VP9TileData *td, const vp9_mc_fu // we use +7 because the last 7 pixels of each sbrow can be changed in // the longest loopfilter of the next sbrow th = (y + bh + 4 * !!my + 7) >> (6 - s->ss_v); - ff_thread_await_progress(ref_frame, FFMAX(th, 0), 0); + ff_progress_frame_await(ref_frame, FFMAX(th, 0)); // The arm/aarch64 _hv filters read one more row than what actually is // needed, so switch to emulated edge one pixel sooner vertically // (!!my * 5) than horizontally (!!mx * 4). + // The arm/aarch64 _h filters read one more pixel than what actually is + // needed, so switch to emulated edge if that would read beyond the bottom + // right block. if (x < !!mx * 3 || y < !!my * 3 || + ((ARCH_AARCH64 || ARCH_ARM) && (x + !!mx * 5 > w - bw) && (y + !!my * 5 + 1 > h - bh)) || x + !!mx * 4 > w - bw || y + !!my * 5 > h - bh) { s->vdsp.emulated_edge_mc(td->edge_emu_buffer, ref_u - !!my * 3 * src_stride_u - !!mx * 3 * bytesperpixel, @@ -407,7 +416,7 @@ static av_always_inline void mc_luma_scaled(VP9TileData *td, vp9_scaled_mc_func const vp9_mc_func (*mc)[2], uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *ref, ptrdiff_t ref_stride, - const ThreadFrame *ref_frame, + const ProgressFrame *ref_frame, ptrdiff_t y, ptrdiff_t x, const VP9mv *in_mv, int px, int py, int pw, int ph, int bw, int bh, int w, int h, int bytesperpixel, @@ -444,7 +453,7 @@ static av_always_inline void mc_luma_scaled(VP9TileData *td, vp9_scaled_mc_func // we use +7 because the last 7 pixels of each sbrow can be changed in // the longest loopfilter of the next sbrow th = (y + refbh_m1 + 4 + 7) >> 6; - ff_thread_await_progress(ref_frame, FFMAX(th, 0), 0); + ff_progress_frame_await(ref_frame, FFMAX(th, 0)); // The arm/aarch64 _hv filters read one more row than what actually is // needed, so switch to emulated edge one pixel sooner vertically // (y + 5 >= h - refbh_m1) than horizontally (x + 4 >= w - refbw_m1). @@ -467,7 +476,7 @@ static av_always_inline void mc_chroma_scaled(VP9TileData *td, vp9_scaled_mc_fun ptrdiff_t dst_stride, const uint8_t *ref_u, ptrdiff_t src_stride_u, const uint8_t *ref_v, ptrdiff_t src_stride_v, - const ThreadFrame *ref_frame, + const ProgressFrame *ref_frame, ptrdiff_t y, ptrdiff_t x, const VP9mv *in_mv, int px, int py, int pw, int ph, int bw, int bh, int w, int h, int bytesperpixel, @@ -514,7 +523,7 @@ static av_always_inline void mc_chroma_scaled(VP9TileData *td, vp9_scaled_mc_fun // we use +7 because the last 7 pixels of each sbrow can be changed in // the longest loopfilter of the next sbrow th = (y + refbh_m1 + 4 + 7) >> (6 - s->ss_v); - ff_thread_await_progress(ref_frame, FFMAX(th, 0), 0); + ff_progress_frame_await(ref_frame, FFMAX(th, 0)); // The arm/aarch64 _hv filters read one more row than what actually is // needed, so switch to emulated edge one pixel sooner vertically // (y + 5 >= h - refbh_m1) than horizontally (x + 4 >= w - refbw_m1). diff --git a/libavcodec/vp9shared.h b/libavcodec/vp9shared.h index b445a2a74..8a450c26a 100644 --- a/libavcodec/vp9shared.h +++ b/libavcodec/vp9shared.h @@ -29,8 +29,8 @@ #include "libavutil/mem_internal.h" +#include "progressframe.h" #include "vp9.h" -#include "threadframe.h" enum BlockPartition { PARTITION_NONE, // [ ] <-. @@ -63,7 +63,7 @@ typedef struct VP9mvrefPair { } VP9mvrefPair; typedef struct VP9Frame { - ThreadFrame tf; + ProgressFrame tf; void *extradata; ///< RefStruct reference uint8_t *segmentation_map; VP9mvrefPair *mv; @@ -164,11 +164,12 @@ typedef struct VP9BitstreamHeader { typedef struct VP9SharedContext { VP9BitstreamHeader h; - ThreadFrame refs[8]; + ProgressFrame refs[8]; #define CUR_FRAME 0 #define REF_FRAME_MVPAIR 1 #define REF_FRAME_SEGMAP 2 - VP9Frame frames[3]; +#define BLANK_FRAME 3 + VP9Frame frames[4]; } VP9SharedContext; #endif /* AVCODEC_VP9SHARED_H */ diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c index 2977cf9a5..4fd1861d2 100644 --- a/libavcodec/vqavideo.c +++ b/libavcodec/vqavideo.c @@ -73,6 +73,7 @@ #include #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "bytestream.h" #include "codec_internal.h" diff --git a/libavcodec/vqcdec.c b/libavcodec/vqcdec.c index dbcaba7b2..bb6984432 100644 --- a/libavcodec/vqcdec.c +++ b/libavcodec/vqcdec.c @@ -23,6 +23,7 @@ #include "get_bits.h" #include "codec_internal.h" #include "decode.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" #define VECTOR_VLC_BITS 6 diff --git a/libavcodec/vulkan_av1.c b/libavcodec/vulkan_av1.c index e607c1fc5..a0befb9c4 100644 --- a/libavcodec/vulkan_av1.c +++ b/libavcodec/vulkan_av1.c @@ -79,6 +79,7 @@ static int vk_av1_fill_pict(AVCodecContext *avctx, const AV1Frame **ref_src, const uint8_t *saved_order_hints) { FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; AV1VulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vkpic = &hp->vp; @@ -119,7 +120,7 @@ static int vk_av1_fill_pict(AVCodecContext *avctx, const AV1Frame **ref_src, .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, - .baseArrayLayer = ((has_grain || dec->dedicated_dpb) && dec->layered_dpb) ? + .baseArrayLayer = ((has_grain || dec->dedicated_dpb) && ctx->common.layered_dpb) ? hp->frame_id : 0, .imageViewBinding = vkpic->img_view_ref, }; @@ -284,7 +285,7 @@ static int vk_av1_start_frame(AVCodecContext *avctx, AV1VulkanDecodePicture *hp = ref_frame->hwaccel_picture_private; int found = 0; - if (ref_frame->f->pict_type == AV_PICTURE_TYPE_NONE) + if (!ref_frame->f) continue; for (int j = 0; j < ref_count; j++) { @@ -326,7 +327,7 @@ static int vk_av1_start_frame(AVCodecContext *avctx, const AV1Frame *ref_frame = &s->ref[idx]; AV1VulkanDecodePicture *hp = ref_frame->hwaccel_picture_private; - if (ref_frame->f->pict_type == AV_PICTURE_TYPE_NONE) + if (!ref_frame->f) ap->av1_pic_info.referenceNameSlotIndices[i] = AV1_REF_FRAME_NONE; else ap->av1_pic_info.referenceNameSlotIndices[i] = hp->frame_id; diff --git a/libavcodec/vulkan_decode.c b/libavcodec/vulkan_decode.c index 5f6523920..a8b906a9d 100644 --- a/libavcodec/vulkan_decode.c +++ b/libavcodec/vulkan_decode.c @@ -21,6 +21,7 @@ #include "vulkan_decode.h" #include "config_components.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/vulkan_loader.h" #if CONFIG_H264_VULKAN_HWACCEL @@ -87,7 +88,7 @@ int ff_vk_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) const VkVideoProfileInfoKHR *profile = get_video_profile(ctx, dst->codec_id); if (!profile) { - av_log(dst, AV_LOG_ERROR, "Video profile missing from frames context!"); + av_log(dst, AV_LOG_ERROR, "Video profile missing from frames context!\n"); return AVERROR(EINVAL); } @@ -110,7 +111,6 @@ int ff_vk_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) } dst_ctx->dedicated_dpb = src_ctx->dedicated_dpb; - dst_ctx->layered_dpb = src_ctx->layered_dpb; dst_ctx->external_fg = src_ctx->external_fg; dst_ctx->frame_id_alloc_mask = src_ctx->frame_id_alloc_mask; @@ -124,51 +124,6 @@ int ff_vk_params_invalidate(AVCodecContext *avctx, int t, const uint8_t *b, uint return 0; } -static int vk_decode_create_view(FFVulkanDecodeContext *dec, VkImageView *dst_view, - VkImageAspectFlags *aspect, AVVkFrame *src, - VkFormat vkf, int is_current) -{ - VkResult ret; - FFVulkanDecodeShared *ctx = dec->shared_ctx; - FFVulkanFunctions *vk = &ctx->s.vkfn; - VkImageAspectFlags aspect_mask = ff_vk_aspect_bits_from_vkfmt(vkf); - - VkSamplerYcbcrConversionInfo yuv_sampler_info = { - .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, - .conversion = ctx->yuv_sampler, - }; - VkImageViewCreateInfo img_view_create_info = { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .pNext = &yuv_sampler_info, - .viewType = dec->layered_dpb && !is_current ? - VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, - .format = vkf, - .image = src->img[0], - .components = (VkComponentMapping) { - .r = VK_COMPONENT_SWIZZLE_IDENTITY, - .g = VK_COMPONENT_SWIZZLE_IDENTITY, - .b = VK_COMPONENT_SWIZZLE_IDENTITY, - .a = VK_COMPONENT_SWIZZLE_IDENTITY, - }, - .subresourceRange = (VkImageSubresourceRange) { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseArrayLayer = 0, - .layerCount = dec->layered_dpb && !is_current ? - VK_REMAINING_ARRAY_LAYERS : 1, - .levelCount = 1, - }, - }; - - ret = vk->CreateImageView(ctx->s.hwctx->act_dev, &img_view_create_info, - ctx->s.hwctx->alloc, dst_view); - if (ret != VK_SUCCESS) - return AVERROR_EXTERNAL; - - *aspect = aspect_mask; - - return 0; -} - static AVFrame *vk_get_dpb_pool(FFVulkanDecodeShared *ctx) { int err; @@ -176,7 +131,7 @@ static AVFrame *vk_get_dpb_pool(FFVulkanDecodeShared *ctx) if (!avf) return NULL; - err = av_hwframe_get_buffer(ctx->dpb_hwfc_ref, avf, 0x0); + err = av_hwframe_get_buffer(ctx->common.dpb_hwfc_ref, avf, 0x0); if (err < 0) av_frame_free(&avf); @@ -206,21 +161,21 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, vkpic->destroy_image_view = vk->DestroyImageView; vkpic->wait_semaphores = vk->WaitSemaphores; - if (dec->layered_dpb && alloc_dpb) { - vkpic->img_view_ref = ctx->layered_view; - vkpic->img_aspect_ref = ctx->layered_aspect; + if (ctx->common.layered_dpb && alloc_dpb) { + vkpic->img_view_ref = ctx->common.layered_view; + vkpic->img_aspect_ref = ctx->common.layered_aspect; } else if (alloc_dpb) { - AVHWFramesContext *dpb_frames = (AVHWFramesContext *)ctx->dpb_hwfc_ref->data; + AVHWFramesContext *dpb_frames = (AVHWFramesContext *)ctx->common.dpb_hwfc_ref->data; AVVulkanFramesContext *dpb_hwfc = dpb_frames->hwctx; vkpic->dpb_frame = vk_get_dpb_pool(ctx); if (!vkpic->dpb_frame) return AVERROR(ENOMEM); - err = vk_decode_create_view(dec, &vkpic->img_view_ref, - &vkpic->img_aspect_ref, - (AVVkFrame *)vkpic->dpb_frame->data[0], - dpb_hwfc->format[0], is_current); + err = ff_vk_create_view(&ctx->s, &ctx->common, + &vkpic->img_view_ref, &vkpic->img_aspect_ref, + (AVVkFrame *)vkpic->dpb_frame->data[0], + dpb_hwfc->format[0], !is_current); if (err < 0) return err; @@ -231,10 +186,10 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, AVFrame *pic, AVHWFramesContext *frames = (AVHWFramesContext *)pic->hw_frames_ctx->data; AVVulkanFramesContext *hwfc = frames->hwctx; - err = vk_decode_create_view(dec, &vkpic->img_view_out, - &vkpic->img_aspect, - (AVVkFrame *)pic->data[0], - hwfc->format[0], is_current); + err = ff_vk_create_view(&ctx->s, &ctx->common, + &vkpic->img_view_out, &vkpic->img_aspect, + (AVVkFrame *)pic->data[0], + hwfc->format[0], !is_current); if (err < 0) return err; @@ -259,7 +214,7 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, const int nb = *nb_slices; uint8_t *slices; uint32_t *slice_off; - FFVkVideoBuffer *vkbuf; + FFVkBuffer *vkbuf; size_t new_size = vp->slices_size + startcode_len + size + ctx->caps.minBitstreamBufferSizeAlignment; @@ -273,29 +228,38 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, FFVulkanDecodePicture *vp, *offsets = dec->slice_off = slice_off; slice_off[nb] = vp->slices_size; - vkbuf = vp->slices_buf ? (FFVkVideoBuffer *)vp->slices_buf->data : NULL; - if (!vkbuf || vkbuf->buf.size < new_size) { + vkbuf = vp->slices_buf ? (FFVkBuffer *)vp->slices_buf->data : NULL; + if (!vkbuf || vkbuf->size < new_size) { int err; AVBufferRef *new_ref; - FFVkVideoBuffer *new_buf; - err = ff_vk_video_get_buffer(&ctx->s, &ctx->common, &new_ref, - VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR, - ctx->s.hwfc->create_pnext, new_size); + FFVkBuffer *new_buf; + + /* No point in requesting anything smaller. */ + size_t buf_size = FFMAX(new_size, 1024*1024); + + /* Align buffer to nearest power of two. Makes fragmentation management + * easier, and gives us ample headroom. */ + buf_size = 2 << av_log2(buf_size); + + err = ff_vk_get_pooled_buffer(&ctx->s, &ctx->buf_pool, &new_ref, + VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR, + ctx->s.hwfc->create_pnext, buf_size, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); if (err < 0) return err; - new_buf = (FFVkVideoBuffer *)new_ref->data; + new_buf = (FFVkBuffer *)new_ref->data; /* Copy data from the old buffer */ if (vkbuf) { - memcpy(new_buf->mem, vkbuf->mem, vp->slices_size); + memcpy(new_buf->mapped_mem, vkbuf->mapped_mem, vp->slices_size); av_buffer_unref(&vp->slices_buf); } vp->slices_buf = new_ref; vkbuf = new_buf; } - slices = vkbuf->mem; + slices = vkbuf->mapped_mem; /* Startcode */ memcpy(slices + vp->slices_size, startcode_prefix, startcode_len); @@ -330,6 +294,7 @@ void ff_vk_decode_flush(AVCodecContext *avctx) VkCommandBuffer cmd_buf; FFVkExecContext *exec = ff_vk_exec_get(&dec->exec_pool); + int had_submission = exec->had_submission; ff_vk_exec_start(&ctx->s, exec); cmd_buf = exec->buf; @@ -337,6 +302,11 @@ void ff_vk_decode_flush(AVCodecContext *avctx) vk->CmdControlVideoCodingKHR(cmd_buf, &decode_ctrl); vk->CmdEndVideoCodingKHR(cmd_buf, &decode_end); ff_vk_exec_submit(&ctx->s, exec); + + /* 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; } int ff_vk_decode_frame(AVCodecContext *avctx, @@ -346,7 +316,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, int err; VkResult ret; VkCommandBuffer cmd_buf; - FFVkVideoBuffer *sd_buf; + FFVkBuffer *sd_buf; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; FFVulkanDecodeShared *ctx = dec->shared_ctx; @@ -356,7 +326,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, AVVkFrame *vkf = (AVVkFrame *)pic->buf[0]->data; /* Quirks */ - const int layered_dpb = dec->layered_dpb; + const int layered_dpb = ctx->common.layered_dpb; VkVideoSessionParametersKHR *par = (VkVideoSessionParametersKHR *)dec->session_params->data; VkVideoBeginCodingInfoKHR decode_start = { @@ -384,28 +354,29 @@ int ff_vk_decode_frame(AVCodecContext *avctx, cur_vk_ref[0].slotIndex = -1; decode_start.referenceSlotCount++; - if (dec->exec_pool.nb_queries) { - int64_t prev_sub_res = 0; - ff_vk_exec_wait(&ctx->s, exec); - ret = ff_vk_exec_get_query(&ctx->s, exec, NULL, &prev_sub_res); + 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; } - if (ret == VK_SUCCESS) - av_log(avctx, prev_sub_res < 0 ? AV_LOG_ERROR : AV_LOG_DEBUG, - "Result of previous frame decoding: %"PRId64"\n", prev_sub_res); + 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 = (FFVkVideoBuffer *)vp->slices_buf->data; + sd_buf = (FFVkBuffer *)vp->slices_buf->data; /* Flush if needed */ - if (!(sd_buf->buf.flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + if (!(sd_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { VkMappedMemoryRange flush_buf = { .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, - .memory = sd_buf->buf.mem, + .memory = sd_buf->mem, .offset = 0, .size = FFALIGN(vp->slices_size, ctx->s.props.properties.limits.nonCoherentAtomSize), @@ -419,7 +390,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, } } - vp->decode_info.srcBuffer = sd_buf->buf.buf; + vp->decode_info.srcBuffer = sd_buf->buf; vp->decode_info.srcBufferOffset = 0; vp->decode_info.srcBufferRange = data_size; @@ -460,7 +431,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, .srcAccessMask = VK_ACCESS_2_NONE, .dstAccessMask = VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR, .oldLayout = vkf->layout[0], - .newLayout = (dec->layered_dpb || vp->dpb_frame) ? + .newLayout = (layered_dpb || vp->dpb_frame) ? VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR : VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR, /* Spec, 07252 utter madness */ .srcQueueFamilyIndex = vkf->queue_family[0], @@ -535,7 +506,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx, } else if (vp->decode_info.referenceSlotCount || vp->img_view_out != vp->img_view_ref) { /* Single barrier for a single layered ref */ - err = ff_vk_exec_add_dep_frame(&ctx->s, exec, ctx->layered_frame, + err = ff_vk_exec_add_dep_frame(&ctx->s, exec, ctx->common.layered_frame, VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR, VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR); if (err < 0) @@ -606,13 +577,8 @@ static void free_common(FFRefStructOpaque unused, void *obj) FFVulkanContext *s = &ctx->s; FFVulkanFunctions *vk = &ctx->s.vkfn; - /* Destroy layered view */ - if (ctx->layered_view) - vk->DestroyImageView(s->hwctx->act_dev, ctx->layered_view, s->hwctx->alloc); - /* This also frees all references from this pool */ - av_frame_free(&ctx->layered_frame); - av_buffer_unref(&ctx->dpb_hwfc_ref); + av_frame_free(&ctx->common.layered_frame); /* Destroy parameters */ if (ctx->empty_session_params) @@ -620,11 +586,9 @@ static void free_common(FFRefStructOpaque unused, void *obj) ctx->empty_session_params, s->hwctx->alloc); - ff_vk_video_common_uninit(s, &ctx->common); + av_buffer_pool_uninit(&ctx->buf_pool); - if (ctx->yuv_sampler) - vk->DestroySamplerYcbcrConversion(s->hwctx->act_dev, ctx->yuv_sampler, - s->hwctx->alloc); + ff_vk_video_common_uninit(s, &ctx->common); ff_vk_uninit(s); } @@ -911,9 +875,9 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ return AVERROR_EXTERNAL; } - /* TODO: make dedicated_dpb tunable */ dec->dedicated_dpb = !(dec_caps->flags & VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR); - dec->layered_dpb = !(caps->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR); + ctx->common.layered_dpb = !dec->dedicated_dpb ? 0 : + !(caps->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR); if (dec->dedicated_dpb) { fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR; @@ -922,6 +886,10 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_ VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR | 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)) + fmt_info.imageUsage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR; } /* Get the format of the images necessary */ @@ -1011,6 +979,7 @@ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) AVVulkanFramesContext *hwfc = frames_ctx->hwctx; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; FFVulkanDecodeProfileData *prof; + FFVulkanDecodeShared *ctx; frames_ctx->sw_format = AV_PIX_FMT_NONE; @@ -1047,6 +1016,11 @@ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) 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 | + FF_VK_EXT_VIDEO_MAINTENANCE_1)) + hwfc->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR; + return err; } @@ -1106,7 +1080,7 @@ int ff_vk_decode_uninit(AVCodecContext *avctx) int ff_vk_decode_init(AVCodecContext *avctx) { - int err, qf, cxpos = 0, cypos = 0, nb_q = 0; + int err, nb_q = 0; VkResult ret; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; FFVulkanDecodeShared *ctx; @@ -1137,12 +1111,6 @@ int ff_vk_decode_init(AVCodecContext *avctx) VkVideoSessionCreateInfoKHR session_create = { .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR, }; - 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 */ - }; err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VULKAN); if (err < 0) @@ -1153,12 +1121,9 @@ int ff_vk_decode_init(AVCodecContext *avctx) s = &ctx->s; vk = &ctx->s.vkfn; - s->frames_ref = av_buffer_ref(avctx->hw_frames_ctx); - s->frames = (AVHWFramesContext *)s->frames_ref->data; - s->hwfc = s->frames->hwctx; - - s->device = (AVHWDeviceContext *)s->frames->device_ref->data; - s->hwctx = s->device->hwctx; + err = ff_vk_init(s, avctx, NULL, avctx->hw_frames_ctx); + if (err < 0) + return err; profile = get_video_profile(ctx, avctx->codec_id); if (!profile) { @@ -1166,27 +1131,23 @@ int ff_vk_decode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - err = ff_vk_load_props(s); - if (err < 0) - goto fail; - /* Create queue context */ - qf = ff_vk_qf_init(s, &ctx->qf, VK_QUEUE_VIDEO_DECODE_BIT_KHR); - vk_desc = get_codecdesc(avctx->codec_id); - /* Check for support */ - if (!(s->video_props[qf].videoCodecOperations & vk_desc->decode_op)) { - av_log(avctx, AV_LOG_ERROR, "Decoding %s not supported on the given " - "queue family %i!\n", avcodec_get_name(avctx->codec_id), qf); - return AVERROR(EINVAL); + err = ff_vk_video_qf_init(s, &ctx->qf, + VK_QUEUE_VIDEO_DECODE_BIT_KHR, + vk_desc->decode_op); + if (err < 0) { + 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[qf].queryResultStatusSupport) + if (s->query_props[ctx->qf.queue_family].queryResultStatusSupport) nb_q = 1; session_create.flags = 0x0; - session_create.queueFamilyIndex = s->hwctx->queue_family_decode_index; + session_create.queueFamilyIndex = ctx->qf.queue_family; session_create.maxCodedExtent = ctx->caps.maxCodedExtent; session_create.maxDpbSlots = ctx->caps.maxDpbSlots; session_create.maxActiveReferencePictures = ctx->caps.maxActiveReferencePictures; @@ -1208,30 +1169,18 @@ int ff_vk_decode_init(AVCodecContext *avctx) if (err < 0) goto fail; - /* Get sampler */ - av_chroma_location_enum_to_pos(&cxpos, &cypos, avctx->chroma_sample_location); - yuv_sampler_info.xChromaOffset = cxpos >> 7; - yuv_sampler_info.yChromaOffset = cypos >> 7; - yuv_sampler_info.format = s->hwfc->format[0]; - ret = vk->CreateSamplerYcbcrConversion(s->hwctx->act_dev, &yuv_sampler_info, - s->hwctx->alloc, &ctx->yuv_sampler); - if (ret != VK_SUCCESS) { - err = AVERROR_EXTERNAL; - goto fail; - } - /* If doing an out-of-place decoding, create a DPB pool */ if (dec->dedicated_dpb || avctx->codec_id == AV_CODEC_ID_AV1) { AVHWFramesContext *dpb_frames; AVVulkanFramesContext *dpb_hwfc; - ctx->dpb_hwfc_ref = av_hwframe_ctx_alloc(s->frames->device_ref); - if (!ctx->dpb_hwfc_ref) { + ctx->common.dpb_hwfc_ref = av_hwframe_ctx_alloc(s->frames->device_ref); + if (!ctx->common.dpb_hwfc_ref) { err = AVERROR(ENOMEM); goto fail; } - dpb_frames = (AVHWFramesContext *)ctx->dpb_hwfc_ref->data; + 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; @@ -1245,23 +1194,25 @@ int ff_vk_decode_init(AVCodecContext *avctx) dpb_hwfc->usage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR | VK_IMAGE_USAGE_SAMPLED_BIT; /* Shuts validator up. */ - if (dec->layered_dpb) + if (ctx->common.layered_dpb) dpb_hwfc->nb_layers = ctx->caps.maxDpbSlots; - err = av_hwframe_ctx_init(ctx->dpb_hwfc_ref); + err = av_hwframe_ctx_init(ctx->common.dpb_hwfc_ref); if (err < 0) goto fail; - if (dec->layered_dpb) { - ctx->layered_frame = vk_get_dpb_pool(ctx); - if (!ctx->layered_frame) { + if (ctx->common.layered_dpb) { + ctx->common.layered_frame = vk_get_dpb_pool(ctx); + if (!ctx->common.layered_frame) { err = AVERROR(ENOMEM); goto fail; } - err = vk_decode_create_view(dec, &ctx->layered_view, &ctx->layered_aspect, - (AVVkFrame *)ctx->layered_frame->data[0], - s->hwfc->format[0], 0); + err = ff_vk_create_view(&ctx->s, &ctx->common, + &ctx->common.layered_view, + &ctx->common.layered_aspect, + (AVVkFrame *)ctx->common.layered_frame->data[0], + s->hwfc->format[0], 1); if (err < 0) goto fail; } diff --git a/libavcodec/vulkan_decode.h b/libavcodec/vulkan_decode.h index 076af9349..76e60836b 100644 --- a/libavcodec/vulkan_decode.h +++ b/libavcodec/vulkan_decode.h @@ -48,18 +48,12 @@ typedef struct FFVulkanDecodeShared { FFVkVideoCommon common; FFVkQueueFamilyCtx qf; + AVBufferPool *buf_pool; + VkVideoCapabilitiesKHR caps; VkVideoDecodeCapabilitiesKHR dec_caps; - AVBufferRef *dpb_hwfc_ref; /* Only used for dedicated_dpb */ - - AVFrame *layered_frame; /* Only used for layered_dpb */ - VkImageView layered_view; - VkImageAspectFlags layered_aspect; - VkVideoSessionParametersKHR empty_session_params; - - VkSamplerYcbcrConversion yuv_sampler; } FFVulkanDecodeShared; typedef struct FFVulkanDecodeContext { @@ -68,7 +62,6 @@ typedef struct FFVulkanDecodeContext { FFVkExecPool exec_pool; int dedicated_dpb; /* Oddity #1 - separate DPB images */ - int layered_dpb; /* Madness #1 - layered DPB images */ int external_fg; /* Oddity #2 - hardware can't apply film grain */ uint32_t frame_id_alloc_mask; /* For AV1 only */ diff --git a/libavcodec/vulkan_encode.c b/libavcodec/vulkan_encode.c new file mode 100644 index 000000000..d187b7cdd --- /dev/null +++ b/libavcodec/vulkan_encode.c @@ -0,0 +1,1059 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/avassert.h" +#include "vulkan_encode.h" +#include "config.h" + +#include "libavutil/vulkan_loader.h" + +const AVCodecHWConfigInternal *const ff_vulkan_encode_hw_configs[] = { + HW_CONFIG_ENCODER_FRAMES(VULKAN, VULKAN), + NULL, +}; + +av_cold void ff_vulkan_encode_uninit(FFVulkanEncodeContext *ctx) +{ + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &s->vkfn; + + /* Wait on and free execution pool */ + ff_vk_exec_pool_free(s, &ctx->enc_pool); + + /* Destroy the session params */ + if (ctx->session_params) + vk->DestroyVideoSessionParametersKHR(s->hwctx->act_dev, + ctx->session_params, + s->hwctx->alloc); + + ff_hw_base_encode_close(&ctx->base); + + av_buffer_pool_uninit(&ctx->buf_pool); + + ff_vk_video_common_uninit(s, &ctx->common); + + ff_vk_uninit(s); +} + +static int vulkan_encode_init(AVCodecContext *avctx, FFHWBaseEncodePicture *pic) +{ + int err; + FFVulkanEncodeContext *ctx = avctx->priv_data; + FFVulkanEncodePicture *vp = pic->priv; + + AVFrame *f = pic->input_image; + AVHWFramesContext *hwfc = (AVHWFramesContext *)f->hw_frames_ctx->data; + AVVulkanFramesContext *vkfc = hwfc->hwctx; + AVVkFrame *vkf = (AVVkFrame *)f->data[0]; + + if (ctx->codec->picture_priv_data_size > 0) { + pic->codec_priv = av_mallocz(ctx->codec->picture_priv_data_size); + if (!pic->codec_priv) + return AVERROR(ENOMEM); + } + + /* Input image view */ + err = ff_vk_create_view(&ctx->s, &ctx->common, + &vp->in.view, &vp->in.aspect, + vkf, vkfc->format[0], 0); + if (err < 0) + return err; + + /* Reference view */ + if (!ctx->common.layered_dpb) { + AVFrame *rf = pic->recon_image; + 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); + if (err < 0) + return err; + } else { + vp->dpb.view = ctx->common.layered_view; + vp->dpb.aspect = ctx->common.layered_aspect; + } + + return 0; +} + +static int vulkan_encode_free(AVCodecContext *avctx, FFHWBaseEncodePicture *pic) +{ + FFVulkanEncodeContext *ctx = avctx->priv_data; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + FFVulkanEncodePicture *vp = pic->priv; + + if (vp->in.view) + vk->DestroyImageView(ctx->s.hwctx->act_dev, vp->in.view, + ctx->s.hwctx->alloc); + + if (!ctx->common.layered_dpb && vp->dpb.view) + vk->DestroyImageView(ctx->s.hwctx->act_dev, vp->dpb.view, + ctx->s.hwctx->alloc); + + ctx->slots[vp->dpb_slot.slotIndex] = NULL; + + return 0; +} + +static int init_pic_rc(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeRateControlInfoKHR *rc_info, + VkVideoEncodeRateControlLayerInfoKHR *rc_layer /* Goes in ^ */) +{ + FFVulkanEncodeContext *ctx = avctx->priv_data; + + *rc_info = (VkVideoEncodeRateControlInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR, + .rateControlMode = ctx->opts.rc_mode, + }; + + if (ctx->opts.rc_mode > VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { + *rc_layer = (VkVideoEncodeRateControlLayerInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_LAYER_INFO_KHR, + .averageBitrate = avctx->bit_rate, + .maxBitrate = avctx->rc_max_rate ? avctx->rc_max_rate : avctx->bit_rate, + .frameRateNumerator = avctx->framerate.num, + .frameRateDenominator = avctx->framerate.den, + }; + rc_info->layerCount++; + rc_info->pLayers = rc_layer; + } + + return ctx->codec->init_pic_rc(avctx, pic, rc_info, rc_layer); +} + +static int vulkan_encode_issue(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic) +{ + FFVulkanEncodeContext *ctx = avctx->priv_data; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + const size_t size_align = ctx->caps.minBitstreamBufferSizeAlignment; + + FFVulkanEncodePicture *vp = base_pic->priv; + AVFrame *src = (AVFrame *)base_pic->input_image; + AVVkFrame *vkf = (AVVkFrame *)src->data[0]; + + int err, max_pkt_size; + + FFVkBuffer *sd_buf; + + int slot_index = -1; + FFVkExecContext *exec; + VkCommandBuffer cmd_buf; + VkImageMemoryBarrier2 img_bar[37]; + int nb_img_bar = 0; + + /* Coding start/end */ + VkVideoBeginCodingInfoKHR encode_start; + VkVideoEndCodingInfoKHR encode_end = { + .sType = VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR, + }; + + VkVideoEncodeRateControlLayerInfoKHR rc_layer; + VkVideoEncodeRateControlInfoKHR rc_info; + VkVideoEncodeQualityLevelInfoKHR q_info; + VkVideoCodingControlInfoKHR encode_ctrl; + + VkVideoReferenceSlotInfoKHR ref_slot[37]; + VkVideoEncodeInfoKHR encode_info; + + /* Create packet data buffer */ + max_pkt_size = FFALIGN(3 * ctx->base.surface_width * ctx->base.surface_height + (1 << 16), + ctx->caps.minBitstreamBufferSizeAlignment); + + err = ff_vk_get_pooled_buffer(&ctx->s, &ctx->buf_pool, &vp->pkt_buf, + 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); + if (err < 0) + return err; + + sd_buf = (FFVkBuffer *)vp->pkt_buf->data; + + /* Setup rate control */ + err = init_pic_rc(avctx, base_pic, &rc_info, &rc_layer); + if (err < 0) + return err; + + q_info = (VkVideoEncodeQualityLevelInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR, + .pNext = &rc_info, + .qualityLevel = ctx->opts.quality, + }; + encode_ctrl = (VkVideoCodingControlInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR, + .pNext = &q_info, + .flags = VK_VIDEO_CODING_CONTROL_ENCODE_QUALITY_LEVEL_BIT_KHR | + VK_VIDEO_CODING_CONTROL_ENCODE_RATE_CONTROL_BIT_KHR | + VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR, + }; + + for (int i = 0; i < ctx->caps.maxDpbSlots; i++) { + if (ctx->slots[i] == NULL) { + slot_index = i; + ctx->slots[i] = base_pic; + break; + } + } + av_assert0(slot_index >= 0); + + /* Current picture's ref slot */ + vp->dpb_res = (VkVideoPictureResourceInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, + .pNext = NULL, + .codedOffset = { 0 }, + .codedExtent = (VkExtent2D){ ctx->base.surface_width, + ctx->base.surface_height }, + .baseArrayLayer = ctx->common.layered_dpb ? slot_index : 0, + .imageViewBinding = vp->dpb.view, + }; + + vp->dpb_slot = (VkVideoReferenceSlotInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR, + .pNext = NULL, // Set later + .slotIndex = slot_index, + .pPictureResource = &vp->dpb_res, + }; + + encode_info = (VkVideoEncodeInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR, + .pNext = NULL, // Set later + .flags = 0x0, + .srcPictureResource = (VkVideoPictureResourceInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, + .pNext = NULL, + .codedOffset = { 0, 0 }, + .codedExtent = (VkExtent2D){ base_pic->input_image->width, + base_pic->input_image->height }, + .baseArrayLayer = 0, + .imageViewBinding = vp->in.view, + }, + .pSetupReferenceSlot = &vp->dpb_slot, + .referenceSlotCount = 0, + .pReferenceSlots = ref_slot, + .dstBuffer = sd_buf->buf, + .dstBufferOffset = 0, + .dstBufferRange = sd_buf->size, + .precedingExternallyEncodedBytes = 0, + }; + + for (int i = 0; i < MAX_REFERENCE_LIST_NUM; i++) { + for (int j = 0; j < base_pic->nb_refs[i]; j++) { + FFHWBaseEncodePicture *ref = base_pic->refs[i][j]; + FFVulkanEncodePicture *rvp = ref->priv; + ref_slot[encode_info.referenceSlotCount++] = rvp->dpb_slot; + } + } + + /* Calling vkCmdBeginVideoCodingKHR requires to declare all references + * being enabled upfront, including the current frame's output ref. */ + ref_slot[encode_info.referenceSlotCount] = vp->dpb_slot; + ref_slot[encode_info.referenceSlotCount].slotIndex = -1; + + /* Setup picture parameters */ + err = ctx->codec->init_pic_params(avctx, base_pic, + &encode_info); + if (err < 0) + return err; + + encode_start = (VkVideoBeginCodingInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR, + .pNext = !base_pic->force_idr ? &rc_info : NULL, + .videoSession = ctx->common.session, + .videoSessionParameters = ctx->session_params, + .referenceSlotCount = encode_info.referenceSlotCount + 1, + .pReferenceSlots = ref_slot, + }; + + /* Write header */ + if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) { + uint8_t *hdr_dst = sd_buf->mapped_mem + encode_info.dstBufferOffset; + size_t data_size = encode_info.dstBufferRange; + err = ctx->codec->write_sequence_headers(avctx, base_pic, hdr_dst, &data_size); + if (err < 0) + goto fail; + encode_info.dstBufferOffset += data_size; + encode_info.dstBufferRange -= data_size; + } + + /* Write extra units */ + if (ctx->codec->write_extra_headers) { + uint8_t *hdr_dst = sd_buf->mapped_mem + encode_info.dstBufferOffset; + size_t data_size = encode_info.dstBufferRange; + err = ctx->codec->write_extra_headers(avctx, base_pic, hdr_dst, &data_size); + if (err < 0) + goto fail; + encode_info.dstBufferOffset += data_size; + encode_info.dstBufferRange -= data_size; + } + + /* Align buffer offset to the required value with filler units */ + if (ctx->codec->write_filler) { + uint8_t *hdr_dst = sd_buf->mapped_mem + encode_info.dstBufferOffset; + size_t data_size = encode_info.dstBufferRange; + + uint32_t offset = encode_info.dstBufferOffset; + size_t offset_align = ctx->caps.minBitstreamBufferOffsetAlignment; + + uint32_t filler_data = FFALIGN(offset, offset_align) - offset; + + if (filler_data) { + while (filler_data < ctx->codec->filler_header_size) + filler_data += offset_align; + + filler_data -= ctx->codec->filler_header_size; + + err = ctx->codec->write_filler(avctx, filler_data, + hdr_dst, &data_size); + if (err < 0) + goto fail; + + encode_info.dstBufferOffset += data_size; + encode_info.dstBufferRange -= data_size; + } + } + + vp->slices_offset = encode_info.dstBufferOffset; + + /* Align buffer size to the nearest lower alignment requirement. */ + encode_info.dstBufferRange -= size_align; + encode_info.dstBufferRange = FFALIGN(encode_info.dstBufferRange, + size_align); + + /* Start command buffer recording */ + exec = vp->exec = ff_vk_exec_get(&ctx->enc_pool); + ff_vk_exec_start(&ctx->s, exec); + cmd_buf = exec->buf; + + /* Output packet buffer */ + err = ff_vk_exec_add_dep_buf(&ctx->s, exec, &vp->pkt_buf, 1, 1); + if (err < 0) + goto fail; + + /* Source image */ + err = ff_vk_exec_add_dep_frame(&ctx->s, exec, src, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR); + if (err < 0) + goto fail; + + /* Source image layout conversion */ + img_bar[nb_img_bar] = (VkImageMemoryBarrier2) { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = NULL, + .srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .srcAccessMask = vkf->access[0], + .dstStageMask = VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR, + .dstAccessMask = VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR, + .oldLayout = vkf->layout[0], + .newLayout = VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR, + .srcQueueFamilyIndex = vkf->queue_family[0], + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = vkf->img[0], + .subresourceRange = (VkImageSubresourceRange) { + .aspectMask = vp->in.aspect, + .layerCount = 1, + .levelCount = 1, + }, + }; + ff_vk_exec_update_frame(&ctx->s, exec, src, + &img_bar[nb_img_bar], &nb_img_bar); + + if (!ctx->common.layered_dpb) { + /* Source image's ref slot. + * No need to do a layout conversion, since the frames which are allocated + * with a DPB usage are automatically converted. */ + err = ff_vk_exec_add_dep_frame(&ctx->s, exec, base_pic->recon_image, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR); + if (err < 0) + return err; + + /* All references */ + for (int i = 0; i < MAX_REFERENCE_LIST_NUM; i++) { + for (int j = 0; j < base_pic->nb_refs[i]; j++) { + FFHWBaseEncodePicture *ref = base_pic->refs[i][j]; + err = ff_vk_exec_add_dep_frame(&ctx->s, exec, ref->recon_image, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR); + if (err < 0) + return err; + } + } + } else { + err = ff_vk_exec_add_dep_frame(&ctx->s, exec, ctx->common.layered_frame, + VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR, + VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR); + if (err < 0) + return err; + } + + /* Change image layout */ + vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + + /* Start, use parameters */ + vk->CmdBeginVideoCodingKHR(cmd_buf, &encode_start); + + /* Send control data */ + if (!ctx->session_reset) { + vk->CmdControlVideoCodingKHR(cmd_buf, &encode_ctrl); + ctx->session_reset++; + } + + /* Encode */ + vk->CmdBeginQuery(cmd_buf, ctx->enc_pool.query_pool, exec->query_idx + 0, 0); + vk->CmdEncodeVideoKHR(cmd_buf, &encode_info); + vk->CmdEndQuery(cmd_buf, ctx->enc_pool.query_pool, exec->query_idx + 0); + + /* End encoding */ + vk->CmdEndVideoCodingKHR(cmd_buf, &encode_end); + + /* End recording and submit for execution */ + err = ff_vk_exec_submit(&ctx->s, vp->exec); + if (err < 0) + goto fail; + + /* We don't need to keep the input image any longer, its already ref'd */ + av_frame_free(&base_pic->input_image); + + return 0; + +fail: + return err; +} + +static void vulkan_encode_wait(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic) +{ + FFVulkanEncodeContext *ctx = avctx->priv_data; + FFVulkanEncodePicture *vp = base_pic->priv; + + av_assert0(base_pic->encode_issued); + + if (base_pic->encode_complete) + return; + + ff_vk_exec_wait(&ctx->s, vp->exec); + base_pic->encode_complete = 1; +} + +static int vulkan_encode_output(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, AVPacket *pkt) +{ + VkResult ret; + FFVulkanEncodePicture *vp = base_pic->priv; + FFVulkanEncodeContext *ctx = avctx->priv_data; + FFVkBuffer *sd_buf = (FFVkBuffer *)vp->pkt_buf->data; + uint32_t *query_data; + + vulkan_encode_wait(avctx, base_pic); + + ret = ff_vk_exec_get_query(&ctx->s, vp->exec, (void **)&query_data, 0); + if (ret == VK_NOT_READY) { + av_log(avctx, AV_LOG_ERROR, "Unable to perform query: %s!\n", + ff_vk_ret2str(ret)); + return AVERROR(EINVAL); + } + + 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; + } + + if (query_data[2] != VK_QUERY_RESULT_STATUS_COMPLETE_KHR) { + av_log(avctx, AV_LOG_ERROR, "Unable to encode: %u\n", query_data[2]); + return AVERROR_EXTERNAL; + } + + /* Invalidate buffer if needed */ + if (!(sd_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + FFVulkanFunctions *vk = &ctx->s.vkfn; + VkMappedMemoryRange invalidate_buf; + + int offs = vp->slices_offset; + /* If the non-coherent alignment is greater than the bitstream buffer + * offset's alignment, and the offs value is not aligned already, + * align it to the previous alignment point. */ + if (ctx->s.props.properties.limits.nonCoherentAtomSize > + ctx->caps.minBitstreamBufferOffsetAlignment && offs && + (FFALIGN(offs, ctx->s.props.properties.limits.nonCoherentAtomSize) != offs)) { + offs -= ctx->s.props.properties.limits.nonCoherentAtomSize; + offs = FFALIGN(FFMAX(offs, 0), ctx->s.props.properties.limits.nonCoherentAtomSize); + } + + invalidate_buf = (VkMappedMemoryRange) { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = sd_buf->mem, + .offset = offs, + .size = VK_WHOLE_SIZE, + }; + + 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 */; + + /* 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, + ctx->codec->flags & VK_ENC_FLAG_NO_DELAY); +} + +static const FFHWEncodePictureOperation vulkan_base_encode_ops = { + .priv_size = sizeof(FFVulkanEncodePicture), + .init = &vulkan_encode_init, + .issue = &vulkan_encode_issue, + .output = &vulkan_encode_output, + .free = &vulkan_encode_free, +}; + +int ff_vulkan_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt) +{ + FFVulkanEncodeContext *ctx = avctx->priv_data; + return ff_hw_base_encode_receive_packet(&ctx->base, avctx, pkt); +} + +static int vulkan_encode_create_dpb(AVCodecContext *avctx, FFVulkanEncodeContext *ctx) +{ + int err; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + AVVulkanFramesContext *hwfc; + + enum AVPixelFormat dpb_format; + err = ff_hw_base_get_recon_format(base_ctx, NULL, &dpb_format); + if (err < 0) + return err; + + base_ctx->recon_frames_ref = av_hwframe_ctx_alloc(base_ctx->device_ref); + if (!base_ctx->recon_frames_ref) + return AVERROR(ENOMEM); + + base_ctx->recon_frames = (AVHWFramesContext *)base_ctx->recon_frames_ref->data; + hwfc = (AVVulkanFramesContext *)base_ctx->recon_frames->hwctx; + + 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; + + 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; + + if (ctx->common.layered_dpb) + hwfc->nb_layers = ctx->caps.maxDpbSlots; + + err = av_hwframe_ctx_init(base_ctx->recon_frames_ref); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialise DPB frame context: %s\n", + av_err2str(err)); + return err; + } + + if (ctx->common.layered_dpb) { + ctx->common.layered_frame = av_frame_alloc(); + if (!ctx->common.layered_frame) + return AVERROR(ENOMEM); + + err = av_hwframe_get_buffer(base_ctx->recon_frames_ref, + ctx->common.layered_frame, 0); + if (err < 0) + return AVERROR(ENOMEM); + + err = ff_vk_create_view(&ctx->s, &ctx->common, + &ctx->common.layered_view, + &ctx->common.layered_aspect, + (AVVkFrame *)ctx->common.layered_frame->data[0], + hwfc->format[0], 1); + if (err < 0) + return err; + + av_buffer_unref(&base_ctx->recon_frames_ref); + } + + return 0; +} + +static av_cold int init_rc(AVCodecContext *avctx, FFVulkanEncodeContext *ctx) +{ + if (ctx->opts.qp) { + ctx->explicit_qp = ctx->opts.qp; + } else if (avctx->global_quality > 0) { + if (avctx->flags & AV_CODEC_FLAG_QSCALE) + ctx->explicit_qp = avctx->global_quality / FF_QP2LAMBDA; + else + ctx->explicit_qp = avctx->global_quality; + } + + if (ctx->opts.rc_mode == FF_VK_RC_MODE_AUTO) { + if (ctx->explicit_qp >= 0) { + ctx->opts.rc_mode = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR; + } else if (avctx->global_quality > 0) { + if (avctx->flags & AV_CODEC_FLAG_QSCALE) + ctx->explicit_qp = avctx->global_quality / FF_QP2LAMBDA; + else + ctx->explicit_qp = avctx->global_quality; + ctx->opts.rc_mode = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR; + } else if (avctx->bit_rate) { + if (ctx->enc_caps.rateControlModes & VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR) + ctx->opts.rc_mode = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR; + else if (ctx->enc_caps.rateControlModes & VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR) + ctx->opts.rc_mode = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR; + else + ctx->opts.rc_mode = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR; + } else { + ctx->explicit_qp = 18; + ctx->opts.rc_mode = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR; + av_log(avctx, AV_LOG_WARNING, "No rate control settings specified, using fixed QP = %i\n", + ctx->explicit_qp); + } + } else if (ctx->opts.rc_mode != VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR && + !avctx->bit_rate) { + av_log(avctx, AV_LOG_WARNING, "No bitrate specified!\n"); + return AVERROR(EINVAL); + } + + if (ctx->opts.rc_mode && !(ctx->enc_caps.rateControlModes & ctx->opts.rc_mode)) { + static const char *rc_modes[] = { + [VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR] = "default", + [VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR] = "cqp", + [VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR] = "cbr", + [VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR] = "vbr", + }; + av_log(avctx, AV_LOG_ERROR, "Unsupported rate control mode %s, supported are:\n", + rc_modes[FFMIN(FF_ARRAY_ELEMS(rc_modes), ctx->opts.rc_mode)]); + av_log(avctx, AV_LOG_ERROR, " %s\n", rc_modes[0]); + for (int i = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR; + i <= VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR; i <<= 1) { + if (!(ctx->enc_caps.rateControlModes & i)) + continue; + av_log(avctx, AV_LOG_ERROR, " %s\n", rc_modes[i]); + } + return AVERROR(ENOTSUP); + } + + return 0; +} + +av_cold int ff_vulkan_write_global_header(AVCodecContext *avctx, + FFVulkanEncodeContext *ctx) +{ + int err; + + /* Write extradata if needed */ + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { + uint8_t data[4096]; + size_t data_len = sizeof(data); + + err = ctx->codec->write_sequence_headers(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); + } + } + + return 0; +} + +av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext *ctx, + const FFVulkanEncodeDescriptor *vk_desc, + const FFVulkanCodec *codec, + void *codec_caps, void *quality_pnext) +{ + int i, err; + VkResult ret; + FFVulkanFunctions *vk = &ctx->s.vkfn; + FFVulkanContext *s = &ctx->s; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + + const AVPixFmtDescriptor *desc; + + VkVideoFormatPropertiesKHR *ret_info; + uint32_t nb_out_fmts = 0; + + VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR quality_info; + + VkQueryPoolVideoEncodeFeedbackCreateInfoKHR query_create; + + VkVideoSessionCreateInfoKHR session_create = { + .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR, + }; + VkPhysicalDeviceVideoFormatInfoKHR fmt_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR, + .pNext = &ctx->profile_list, + }; + + if (!avctx->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " + "required to associate the encoding device.\n"); + return AVERROR(EINVAL); + } + + ctx->base.op = &vulkan_base_encode_ops; + ctx->codec = codec; + + s->frames_ref = av_buffer_ref(avctx->hw_frames_ctx); + s->frames = (AVHWFramesContext *)s->frames_ref->data; + s->hwfc = s->frames->hwctx; + + s->device = (AVHWDeviceContext *)s->frames->device_ref->data; + s->hwctx = s->device->hwctx; + + desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + if (!desc) + return AVERROR(EINVAL); + + s->extensions = ff_vk_extensions_to_mask(s->hwctx->enabled_dev_extensions, + s->hwctx->nb_enabled_dev_extensions); + + if (!(s->extensions & FF_VK_EXT_VIDEO_ENCODE_QUEUE)) { + av_log(avctx, AV_LOG_ERROR, "Device does not support the %s extension!\n", + VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME); + return AVERROR(ENOSYS); + } else if (!(s->extensions & FF_VK_EXT_VIDEO_MAINTENANCE_1)) { + av_log(avctx, AV_LOG_ERROR, "Device does not support the %s extension!\n", + VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME); + return AVERROR(ENOSYS); + } else if (!(s->extensions & vk_desc->encode_extension)) { + av_log(avctx, AV_LOG_ERROR, "Device does not support encoding %s!\n", + avcodec_get_name(avctx->codec_id)); + return AVERROR(ENOSYS); + } + + /* Load functions */ + err = ff_vk_load_functions(s->device, vk, s->extensions, 1, 1); + if (err < 0) + 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) { + av_log(avctx, AV_LOG_ERROR, "Encoding of %s is not supported by this device\n", + avcodec_get_name(avctx->codec_id)); + return err; + } + + /* Load all properties */ + err = ff_vk_load_props(s); + if (err < 0) + return err; + + /* Set tuning */ + ctx->usage_info = (VkVideoEncodeUsageInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_USAGE_INFO_KHR, + .videoUsageHints = ctx->opts.usage, + .videoContentHints = ctx->opts.content, + .tuningMode = ctx->opts.tune, + }; + + /* Load up the profile now, needed for caps and to create a query pool */ + ctx->profile.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR; + ctx->profile.pNext = &ctx->usage_info; + ctx->profile.videoCodecOperation = vk_desc->encode_op; + ctx->profile.chromaSubsampling = ff_vk_subsampling_from_av_desc(desc); + ctx->profile.lumaBitDepth = ff_vk_depth_from_av_depth(desc->comp[0].depth); + ctx->profile.chromaBitDepth = ctx->profile.lumaBitDepth; + + /* Setup a profile */ + err = codec->init_profile(avctx, &ctx->profile, &ctx->usage_info); + if (err < 0) + return err; + + ctx->profile_list.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR; + ctx->profile_list.profileCount = 1; + ctx->profile_list.pProfiles = &ctx->profile; + + /* Get the capabilities of the encoder for the given profile */ + ctx->enc_caps.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR; + ctx->enc_caps.pNext = codec_caps; + ctx->caps.sType = VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR; + ctx->caps.pNext = &ctx->enc_caps; + + ret = vk->GetPhysicalDeviceVideoCapabilitiesKHR(s->hwctx->phys_dev, + &ctx->profile, + &ctx->caps); + if (ret == VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize encoding: " + "%s profile \"%s\" not supported!\n", + avcodec_get_name(avctx->codec_id), + avcodec_profile_name(avctx->codec_id, avctx->profile)); + return AVERROR(EINVAL); + } else if (ret == VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR) { + av_log(avctx, AV_LOG_ERROR, "Unable to initialize encoding: " + "format (%s) not supported!\n", + av_get_pix_fmt_name(avctx->sw_pix_fmt)); + return AVERROR(EINVAL); + } else if (ret == VK_ERROR_FEATURE_NOT_PRESENT || + ret == VK_ERROR_FORMAT_NOT_SUPPORTED) { + return AVERROR(EINVAL); + } else if (ret != VK_SUCCESS) { + return AVERROR_EXTERNAL; + } + + err = init_rc(avctx, ctx); + if (err < 0) + return err; + + /* Create command and query pool */ + 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), + }; + 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) + return err; + + if (ctx->opts.quality > ctx->enc_caps.maxQualityLevels) { + av_log(avctx, AV_LOG_ERROR, "Invalid quality level %i: allowed range is " + "0 to %i\n", + ctx->opts.quality, ctx->enc_caps.maxQualityLevels); + return AVERROR(EINVAL); + } + + /* Get quality properties for the profile and quality level */ + quality_info = (VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR) { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR, + .pVideoProfile = &ctx->profile, + .qualityLevel = ctx->opts.quality, + }; + ctx->quality_props = (VkVideoEncodeQualityLevelPropertiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_PROPERTIES_KHR, + .pNext = quality_pnext, + }; + ret = vk->GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR(s->hwctx->phys_dev, + &quality_info, + &ctx->quality_props); + if (ret != VK_SUCCESS) + return AVERROR_EXTERNAL; + + /* Printout informative properties */ + av_log(avctx, AV_LOG_VERBOSE, "Encoder capabilities for %s profile \"%s\":\n", + avcodec_get_name(avctx->codec_id), + avcodec_profile_name(avctx->codec_id, avctx->profile)); + av_log(avctx, AV_LOG_VERBOSE, " Width: from %i to %i\n", + ctx->caps.minCodedExtent.width, ctx->caps.maxCodedExtent.width); + av_log(avctx, AV_LOG_VERBOSE, " Height: from %i to %i\n", + ctx->caps.minCodedExtent.height, ctx->caps.maxCodedExtent.height); + av_log(avctx, AV_LOG_VERBOSE, " Width alignment: %i\n", + ctx->caps.pictureAccessGranularity.width); + av_log(avctx, AV_LOG_VERBOSE, " Height alignment: %i\n", + ctx->caps.pictureAccessGranularity.height); + av_log(avctx, AV_LOG_VERBOSE, " Bitstream offset alignment: %"PRIu64"\n", + ctx->caps.minBitstreamBufferOffsetAlignment); + av_log(avctx, AV_LOG_VERBOSE, " Bitstream size alignment: %"PRIu64"\n", + ctx->caps.minBitstreamBufferSizeAlignment); + av_log(avctx, AV_LOG_VERBOSE, " Maximum references: %u\n", + ctx->caps.maxDpbSlots); + av_log(avctx, AV_LOG_VERBOSE, " Maximum active references: %u\n", + ctx->caps.maxActiveReferencePictures); + av_log(avctx, AV_LOG_VERBOSE, " Codec header version: %i.%i.%i (driver), %i.%i.%i (compiled)\n", + CODEC_VER(ctx->caps.stdHeaderVersion.specVersion), + CODEC_VER(vk_desc->ext_props.specVersion)); + av_log(avctx, AV_LOG_VERBOSE, " Encoder max quality: %i\n", + ctx->enc_caps.maxQualityLevels); + av_log(avctx, AV_LOG_VERBOSE, " Encoder image width alignment: %i\n", + ctx->enc_caps.encodeInputPictureGranularity.width); + av_log(avctx, AV_LOG_VERBOSE, " Encoder image height alignment: %i\n", + ctx->enc_caps.encodeInputPictureGranularity.height); + av_log(avctx, AV_LOG_VERBOSE, " Capability flags:%s%s%s\n", + ctx->caps.flags ? "" : + " none", + ctx->caps.flags & VK_VIDEO_CAPABILITY_PROTECTED_CONTENT_BIT_KHR ? + " protected" : "", + ctx->caps.flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR ? + " separate_references" : ""); + + /* Setup width/height alignment */ + base_ctx->surface_width = avctx->coded_width = + FFALIGN(avctx->width, ctx->caps.pictureAccessGranularity.width); + base_ctx->surface_height = avctx->coded_height = + FFALIGN(avctx->height, ctx->caps.pictureAccessGranularity.height); + + /* Setup slice width/height */ + base_ctx->slice_block_width = ctx->enc_caps.encodeInputPictureGranularity.width; + base_ctx->slice_block_height = ctx->enc_caps.encodeInputPictureGranularity.height; + + /* Check if encoding is possible with the given parameters */ + if (avctx->coded_width < ctx->caps.minCodedExtent.width || + avctx->coded_height < ctx->caps.minCodedExtent.height || + avctx->coded_width > ctx->caps.maxCodedExtent.width || + avctx->coded_height > ctx->caps.maxCodedExtent.height) { + av_log(avctx, AV_LOG_ERROR, "Input of %ix%i too large for encoder limits: %ix%i max\n", + avctx->coded_width, avctx->coded_height, + ctx->caps.minCodedExtent.width, ctx->caps.minCodedExtent.height); + return AVERROR(EINVAL); + } + + fmt_info.imageUsage = VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR | + VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR; + + ctx->common.layered_dpb = !(ctx->caps.flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR); + + /* Get the supported image formats */ + ret = vk->GetPhysicalDeviceVideoFormatPropertiesKHR(s->hwctx->phys_dev, + &fmt_info, + &nb_out_fmts, NULL); + if (ret == VK_ERROR_FORMAT_NOT_SUPPORTED || + (!nb_out_fmts && ret == VK_SUCCESS)) { + return AVERROR(EINVAL); + } else if (ret != VK_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Unable to get Vulkan format properties: %s!\n", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } + + ret_info = av_mallocz(sizeof(*ret_info)*nb_out_fmts); + if (!ret_info) + return AVERROR(ENOMEM); + + for (int i = 0; i < nb_out_fmts; i++) + ret_info[i].sType = VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR; + + ret = vk->GetPhysicalDeviceVideoFormatPropertiesKHR(s->hwctx->phys_dev, + &fmt_info, + &nb_out_fmts, ret_info); + if (ret == VK_ERROR_FORMAT_NOT_SUPPORTED || + (!nb_out_fmts && ret == VK_SUCCESS)) { + av_free(ret_info); + return AVERROR(EINVAL); + } else if (ret != VK_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Unable to get Vulkan format properties: %s!\n", + ff_vk_ret2str(ret)); + av_free(ret_info); + return AVERROR_EXTERNAL; + } + + av_log(avctx, AV_LOG_VERBOSE, "Supported input formats:\n"); + for (i = 0; i < nb_out_fmts; i++) + av_log(avctx, AV_LOG_VERBOSE, " %i: %i\n", i, ret_info[i].format); + + for (i = 0; i < nb_out_fmts; i++) { + if (ff_vk_pix_fmt_from_vkfmt(ret_info[i].format) == s->frames->sw_format) { + ctx->pic_format = ret_info[i].format; + break; + } + } + + av_free(ret_info); + + if (i == nb_out_fmts) { + av_log(avctx, AV_LOG_ERROR, "Pixel format %s of input frames not supported!\n", + av_get_pix_fmt_name(s->frames->sw_format)); + return AVERROR(EINVAL); + } + + /* Create session */ + session_create.pVideoProfile = &ctx->profile; + session_create.flags = 0x0; + session_create.queueFamilyIndex = ctx->qf_enc.queue_family; + session_create.maxCodedExtent = ctx->caps.maxCodedExtent; + session_create.maxDpbSlots = ctx->caps.maxDpbSlots; + session_create.maxActiveReferencePictures = ctx->caps.maxActiveReferencePictures; + session_create.pictureFormat = ctx->pic_format; + session_create.referencePictureFormat = session_create.pictureFormat; + session_create.pStdHeaderVersion = &vk_desc->ext_props; + + err = ff_vk_video_common_init(avctx, s, &ctx->common, &session_create); + if (err < 0) + return err; + + err = ff_hw_base_encode_init(avctx, &ctx->base); + if (err < 0) + return err; + + err = vulkan_encode_create_dpb(avctx, ctx); + if (err < 0) + return err; + + base_ctx->async_encode = 1; + base_ctx->encode_fifo = av_fifo_alloc2(base_ctx->async_depth, + sizeof(FFVulkanEncodePicture *), 0); + if (!base_ctx->encode_fifo) + return AVERROR(ENOMEM); + + return 0; +} + +int ff_vulkan_encode_create_session_params(AVCodecContext *avctx, FFVulkanEncodeContext *ctx, + void *codec_params_pnext) +{ + VkResult ret; + FFVulkanFunctions *vk = &ctx->s.vkfn; + FFVulkanContext *s = &ctx->s; + + VkVideoEncodeQualityLevelInfoKHR q_info; + VkVideoSessionParametersCreateInfoKHR session_params_create; + + q_info = (VkVideoEncodeQualityLevelInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_QUALITY_LEVEL_INFO_KHR, + .pNext = codec_params_pnext, + .qualityLevel = ctx->opts.quality, + }; + session_params_create = (VkVideoSessionParametersCreateInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR, + .pNext = &q_info, + .videoSession = ctx->common.session, + .videoSessionParametersTemplate = VK_NULL_HANDLE, + }; + + /* Create session parameters */ + ret = vk->CreateVideoSessionParametersKHR(s->hwctx->act_dev, &session_params_create, + s->hwctx->alloc, &ctx->session_params); + if (ret != VK_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Unable to create Vulkan video session parameters: %s!\n", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } + + return 0; +} diff --git a/libavcodec/vulkan_encode.h b/libavcodec/vulkan_encode.h new file mode 100644 index 000000000..a7a02d5fd --- /dev/null +++ b/libavcodec/vulkan_encode.h @@ -0,0 +1,259 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_VULKAN_ENCODE_H +#define AVCODEC_VULKAN_ENCODE_H + +#include "codec_id.h" +#include "internal.h" + +#include "encode.h" +#include "hwconfig.h" + +#include "vulkan_video.h" +#include "hw_base_encode.h" + +typedef struct FFVulkanEncodeDescriptor { + enum AVCodecID codec_id; + FFVulkanExtensions encode_extension; + VkVideoCodecOperationFlagBitsKHR encode_op; + + VkExtensionProperties ext_props; +} FFVulkanEncodeDescriptor; + +typedef struct FFVulkanEncodePicture { + FFHWBaseEncodePicture base; + VkVideoPictureResourceInfoKHR dpb_res; + VkVideoReferenceSlotInfoKHR dpb_slot; + + struct { + VkImageView view; + VkImageAspectFlags aspect; + } in; + + struct { + VkImageView view; + VkImageAspectFlags aspect; + } dpb; + + void *codec_layer; + void *codec_rc_layer; + + FFVkExecContext *exec; + AVBufferRef *pkt_buf; + int slices_offset; +} FFVulkanEncodePicture; + +/** + * Callback for writing stream-level headers. + */ +typedef int (*vkenc_cb_write_stream_headers)(AVCodecContext *avctx, + uint8_t *data, size_t *data_len); + +/** + * Callback for initializing codec-specific picture headers. + */ +typedef int (*vkenc_cb_init_pic_headers)(AVCodecContext *avctx, + FFVulkanEncodePicture *pic); + +/** + * Callback for writing alignment data. + * Align is the value to align offset to. + */ +typedef int (*vkenc_cb_write_filler)(AVCodecContext *avctx, uint32_t filler, + uint8_t *data, size_t *data_len); + +/** + * Callback for writing any extra units requested. data_len must be set + * to the available size, and its value will be overwritten by the #bytes written + * to the output buffer. + */ +typedef int (*vkenc_cb_write_extra_headers)(AVCodecContext *avctx, + FFVulkanEncodePicture *pic, + uint8_t *data, size_t *data_len); + +typedef struct FFVulkanCodec { + /** + * Codec feature flags. + */ + int flags; +/* Codec output packet without timestamp delay, which means the + * output packet has same PTS and DTS. For AV1. */ +#define VK_ENC_FLAG_NO_DELAY 1 << 6 + + /** + * Size of the codec-specific picture struct. + */ + size_t picture_priv_data_size; + + /** + * Size of the filler header. + */ + size_t filler_header_size; + + /** + * Initialize codec-specific structs in a Vulkan profile. + */ + int (*init_profile)(AVCodecContext *avctx, VkVideoProfileInfoKHR *profile, + void *pnext); + + /** + * Initialize codec-specific rate control structures for a picture. + */ + int (*init_pic_rc)(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeRateControlInfoKHR *rc_info, + VkVideoEncodeRateControlLayerInfoKHR *rc_layer); + + /** + * Initialize codec-specific picture parameters. + */ + int (*init_pic_params)(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeInfoKHR *encode_info); + + /** + * Callback for writing stream headers. + */ + int (*write_sequence_headers)(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + uint8_t *data, size_t *data_len); + + /** + * Callback for writing alignment data. + */ + int (*write_filler)(AVCodecContext *avctx, uint32_t filler, + uint8_t *data, size_t *data_len); + + /** + * Callback for writing any extra units requested. data_len must be set + * to the available size, and its value will be overwritten by the #bytes written + * to the output buffer. + */ + int (*write_extra_headers)(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + uint8_t *data, size_t *data_len); +} FFVulkanCodec; + +typedef struct FFVkEncodeCommonOptions { + int qp; + int quality; + int profile; + int level; + int tier; + int async_depth; + VkVideoEncodeUsageFlagBitsKHR usage; + VkVideoEncodeContentFlagBitsKHR content; + VkVideoEncodeTuningModeKHR tune; + + VkVideoEncodeRateControlModeFlagBitsKHR rc_mode; +#define FF_VK_RC_MODE_AUTO 0xFFFFFFFF +} FFVkEncodeCommonOptions; + +typedef struct FFVulkanEncodeContext { + FFVulkanContext s; + FFVkVideoCommon common; + FFHWBaseEncodeContext base; + const FFVulkanCodec *codec; + + int explicit_qp; + int session_reset; + + /* Session parameters object, initialized by each codec independently + * and set here. */ + VkVideoSessionParametersKHR session_params; + + AVBufferPool *buf_pool; + + VkFormat pic_format; + + FFVkEncodeCommonOptions opts; + + VkVideoProfileInfoKHR profile; + VkVideoProfileListInfoKHR profile_list; + VkVideoCapabilitiesKHR caps; + VkVideoEncodeQualityLevelPropertiesKHR quality_props; + VkVideoEncodeCapabilitiesKHR enc_caps; + VkVideoEncodeUsageInfoKHR usage_info; + + FFVkQueueFamilyCtx qf_enc; + FFVkExecPool enc_pool; + + FFHWBaseEncodePicture *slots[32]; +} FFVulkanEncodeContext; + +#define VULKAN_ENCODE_COMMON_OPTIONS \ + { "qp", "Use an explicit constant quantizer for the whole stream", OFFSET(common.opts.qp), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, FLAGS }, \ + { "quality", "Set encode quality (trades off against speed, higher is faster)", OFFSET(common.opts.quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, \ + { "rc_mode", "Select rate control type", OFFSET(common.opts.rc_mode), AV_OPT_TYPE_INT, { .i64 = FF_VK_RC_MODE_AUTO }, 0, FF_VK_RC_MODE_AUTO, FLAGS, "rc_mode" }, \ + { "auto", "Choose mode automatically based on parameters", 0, AV_OPT_TYPE_CONST, { .i64 = FF_VK_RC_MODE_AUTO }, INT_MIN, INT_MAX, FLAGS, "rc_mode" }, \ + { "driver", "Driver-specific rate control", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR }, INT_MIN, INT_MAX, FLAGS, "rc_mode" }, \ + { "cqp", "Constant quantizer mode", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "rc_mode" }, \ + { "cbr", "Constant bitrate mode", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "rc_mode" }, \ + { "vbr", "Variable bitrate mode", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "rc_mode" }, \ + { "tune", "Select tuning type", OFFSET(common.opts.tune), AV_OPT_TYPE_INT, { .i64 = VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR }, 0, INT_MAX, FLAGS, "tune" }, \ + { "default", "Default tuning", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR }, INT_MIN, INT_MAX, FLAGS, "tune" }, \ + { "hq", "High quality tuning", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_TUNING_MODE_HIGH_QUALITY_KHR }, INT_MIN, INT_MAX, FLAGS, "tune" }, \ + { "ll", "Low-latency tuning", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_TUNING_MODE_LOW_LATENCY_KHR }, INT_MIN, INT_MAX, FLAGS, "tune" }, \ + { "ull", "Ultra low-latency tuning", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_TUNING_MODE_ULTRA_LOW_LATENCY_KHR }, INT_MIN, INT_MAX, FLAGS, "tune" }, \ + { "lossless", "Lossless mode tuning", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_TUNING_MODE_LOSSLESS_KHR }, INT_MIN, INT_MAX, FLAGS, "tune" }, \ + { "usage", "Select usage type", OFFSET(common.opts.usage), AV_OPT_TYPE_FLAGS, { .i64 = VK_VIDEO_ENCODE_USAGE_DEFAULT_KHR }, 0, INT_MAX, FLAGS, "usage" }, \ + { "default", "Default optimizations", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_USAGE_DEFAULT_KHR }, INT_MIN, INT_MAX, FLAGS, "usage" }, \ + { "transcode", "Optimize for transcoding", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_USAGE_TRANSCODING_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "usage" }, \ + { "stream", "Optimize for streaming", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_USAGE_STREAMING_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "usage" }, \ + { "record", "Optimize for offline recording", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_USAGE_RECORDING_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "usage" }, \ + { "conference", "Optimize for teleconferencing", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_USAGE_CONFERENCING_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "usage" }, \ + { "content", "Select content type", OFFSET(common.opts.content), AV_OPT_TYPE_FLAGS, { .i64 = VK_VIDEO_ENCODE_CONTENT_DEFAULT_KHR }, 0, INT_MAX, FLAGS, "content" }, \ + { "default", "Default content", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_CONTENT_DEFAULT_KHR }, INT_MIN, INT_MAX, FLAGS, "content" }, \ + { "camera", "Camera footage", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_CONTENT_CAMERA_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "content" }, \ + { "desktop", "Screen recording", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_CONTENT_DESKTOP_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "content" }, \ + { "rendered", "Game or 3D content", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_CONTENT_RENDERED_BIT_KHR }, INT_MIN, INT_MAX, FLAGS, "content" } + +/** + * Initialize encoder. + */ +av_cold int ff_vulkan_encode_init(AVCodecContext *avctx, FFVulkanEncodeContext *ctx, + const FFVulkanEncodeDescriptor *vk_desc, + const FFVulkanCodec *codec, + void *codec_caps, void *quality_pnext); + +/** + * Write out the extradata in case its needed. + */ +av_cold int ff_vulkan_write_global_header(AVCodecContext *avctx, + FFVulkanEncodeContext *ctx); + +/** + * Encode. + */ +int ff_vulkan_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt); + +/** + * Uninitialize encoder. + */ +void ff_vulkan_encode_uninit(FFVulkanEncodeContext *ctx); + +/** + * Create session parameters. + */ +int ff_vulkan_encode_create_session_params(AVCodecContext *avctx, FFVulkanEncodeContext *ctx, + void *codec_params_pnext); + +/** + * Paperwork. + */ +extern const AVCodecHWConfigInternal *const ff_vulkan_encode_hw_configs[]; + +#endif /* AVCODEC_VULKAN_ENCODE_H */ diff --git a/libavcodec/vulkan_encode_h264.c b/libavcodec/vulkan_encode_h264.c new file mode 100644 index 000000000..a0a00a3db --- /dev/null +++ b/libavcodec/vulkan_encode_h264.c @@ -0,0 +1,1666 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_h264.h" +#include "atsc_a53.h" + +#include "h264_levels.h" +#include "h2645data.h" +#include "codec_internal.h" +#include "version.h" +#include "hw_base_encode_h264.h" + +#include "vulkan_encode.h" + +enum UnitElems { + UNIT_AUD = 1 << 0, + UNIT_SEI_TIMING = 1 << 1, + UNIT_SEI_IDENTIFIER = 1 << 2, + UNIT_SEI_RECOVERY = 1 << 3, + UNIT_SEI_A53_CC = 1 << 4, +}; + +const FFVulkanEncodeDescriptor ff_vk_enc_h264_desc = { + .codec_id = AV_CODEC_ID_H264, + .encode_extension = FF_VK_EXT_VIDEO_ENCODE_H264, + .encode_op = VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR, + .ext_props = { + .extensionName = VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME, + .specVersion = VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION, + }, +}; + +/* Random (version 4) ISO 11578 UUID. */ +static const uint8_t vulkan_encode_h264_sei_identifier_uuid[16] = { + 0x03, 0xfd, 0xf2, 0x0a, 0x5d, 0x4c, 0x05, 0x48, + 0x20, 0x98, 0xca, 0x6b, 0x0c, 0x95, 0x30, 0x1c, +}; + +typedef struct VulkanEncodeH264Picture { + int frame_num; + int64_t last_idr_frame; + uint16_t idr_pic_id; + int primary_pic_type; + int slice_type; + int pic_order_cnt; + + enum UnitElems units_needed; + + VkVideoEncodeH264RateControlInfoKHR vkrc_info; + VkVideoEncodeH264RateControlLayerInfoKHR vkrc_layer_info; + VkVideoEncodeH264GopRemainingFrameInfoKHR vkrc_remaining; + + StdVideoEncodeH264WeightTable slice_wt; + StdVideoEncodeH264SliceHeader slice_hdr; + VkVideoEncodeH264NaluSliceInfoKHR vkslice; + + StdVideoEncodeH264PictureInfo h264pic_info; + VkVideoEncodeH264PictureInfoKHR vkh264pic_info; + + StdVideoEncodeH264ReferenceInfo h264dpb_info; + VkVideoEncodeH264DpbSlotInfoKHR vkh264dpb_info; + + StdVideoEncodeH264RefListModEntry mods[MAX_REFERENCE_LIST_NUM][H264_MAX_RPLM_COUNT]; + StdVideoEncodeH264RefPicMarkingEntry mmco[H264_MAX_RPLM_COUNT]; + StdVideoEncodeH264ReferenceListsInfo ref_list_info; +} VulkanEncodeH264Picture; + +typedef struct VulkanEncodeH264Context { + FFVulkanEncodeContext common; + + FFHWBaseEncodeH264 units; + FFHWBaseEncodeH264Opts unit_opts; + + enum UnitElems unit_elems; + + uint8_t fixed_qp_p; + uint8_t fixed_qp_b; + + VkVideoEncodeH264ProfileInfoKHR profile; + + VkVideoEncodeH264CapabilitiesKHR caps; + VkVideoEncodeH264QualityLevelPropertiesKHR quality_props; + + CodedBitstreamContext *cbs; + CodedBitstreamFragment current_access_unit; + + H264RawAUD raw_aud; + + SEIRawUserDataUnregistered sei_identifier; + H264RawSEIPicTiming sei_pic_timing; + H264RawSEIRecoveryPoint sei_recovery_point; + SEIRawUserDataRegistered sei_a53cc; + void *sei_a53cc_data; + char *sei_identifier_string; +} VulkanEncodeH264Context; + +static int init_pic_rc(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeRateControlInfoKHR *rc_info, + VkVideoEncodeRateControlLayerInfoKHR *rc_layer) +{ + VulkanEncodeH264Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + VulkanEncodeH264Picture *hp = pic->codec_priv; + + hp->vkrc_info = (VkVideoEncodeH264RateControlInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_KHR, + .flags = VK_VIDEO_ENCODE_H264_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR | + VK_VIDEO_ENCODE_H264_RATE_CONTROL_REGULAR_GOP_BIT_KHR, + .idrPeriod = ctx->base.gop_size, + .gopFrameCount = ctx->base.gop_size, + .consecutiveBFrameCount = FFMAX(ctx->base.b_per_p - 1, 0), + .temporalLayerCount = 0, + }; + rc_info->pNext = &hp->vkrc_info; + + if (rc_info->rateControlMode > VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { + rc_info->virtualBufferSizeInMs = (enc->unit_opts.hrd_buffer_size * 1000LL) / avctx->bit_rate; + rc_info->initialVirtualBufferSizeInMs = (enc->unit_opts.initial_buffer_fullness * 1000LL) / avctx->bit_rate; + + hp->vkrc_layer_info = (VkVideoEncodeH264RateControlLayerInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_KHR, + + .useMinQp = avctx->qmin > 0, + .minQp.qpI = avctx->qmin > 0 ? avctx->qmin : 0, + .minQp.qpP = avctx->qmin > 0 ? avctx->qmin : 0, + .minQp.qpB = avctx->qmin > 0 ? avctx->qmin : 0, + + .useMaxQp = avctx->qmax > 0, + .maxQp.qpI = avctx->qmax > 0 ? avctx->qmax : 0, + .maxQp.qpP = avctx->qmax > 0 ? avctx->qmax : 0, + .maxQp.qpB = avctx->qmax > 0 ? avctx->qmax : 0, + + .useMaxFrameSize = 0, + }; + rc_layer->pNext = &hp->vkrc_layer_info; + hp->vkrc_info.temporalLayerCount = 1; + } + + return 0; +} + +static int vk_enc_h264_update_pic_info(AVCodecContext *avctx, + FFHWBaseEncodePicture *pic) +{ + VulkanEncodeH264Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + VulkanEncodeH264Picture *hp = pic->codec_priv; + FFHWBaseEncodePicture *prev = pic->prev; + VulkanEncodeH264Picture *hprev = prev ? prev->codec_priv : NULL; + + if (pic->type == FF_HW_PICTURE_TYPE_IDR) { + av_assert0(pic->display_order == pic->encode_order); + + hp->frame_num = 0; + hp->last_idr_frame = pic->display_order; + hp->idr_pic_id = hprev ? hprev->idr_pic_id + 1 : 0; + + hp->primary_pic_type = 0; + hp->slice_type = STD_VIDEO_H264_SLICE_TYPE_I; + } else { + av_assert0(prev); + + hp->frame_num = hprev->frame_num + prev->is_reference; + + hp->last_idr_frame = hprev->last_idr_frame; + hp->idr_pic_id = hprev->idr_pic_id; + + if (pic->type == FF_HW_PICTURE_TYPE_I) { + hp->slice_type = STD_VIDEO_H264_SLICE_TYPE_I; + hp->primary_pic_type = 0; + } else if (pic->type == FF_HW_PICTURE_TYPE_P) { + hp->slice_type = STD_VIDEO_H264_SLICE_TYPE_P; + hp->primary_pic_type = 1; + } else { + hp->slice_type = STD_VIDEO_H264_SLICE_TYPE_B; + hp->primary_pic_type = 2; + } + } + + hp->pic_order_cnt = pic->display_order - hp->last_idr_frame; + if (enc->units.raw_sps.pic_order_cnt_type == 2) + hp->pic_order_cnt *= 2; + + hp->units_needed = 0; + + if (enc->unit_elems & UNIT_SEI_IDENTIFIER && pic->encode_order == 0) + hp->units_needed |= UNIT_SEI_IDENTIFIER; + + if (enc->unit_elems & UNIT_SEI_TIMING) { + enc->sei_pic_timing = (H264RawSEIPicTiming) { + .cpb_removal_delay = 2 * (pic->encode_order - hp->last_idr_frame), + .dpb_output_delay = 2 * (pic->display_order - pic->encode_order + ctx->base.max_b_depth), + }; + + hp->units_needed |= UNIT_SEI_TIMING; + } + + if (enc->unit_elems & UNIT_SEI_RECOVERY && pic->type == FF_HW_PICTURE_TYPE_I) { + enc->sei_recovery_point = (H264RawSEIRecoveryPoint) { + .recovery_frame_cnt = 0, + .exact_match_flag = 1, + .broken_link_flag = ctx->base.b_per_p > 0, + }; + + hp->units_needed |= UNIT_SEI_RECOVERY; + } + + if (enc->unit_elems & UNIT_SEI_A53_CC) { + int err; + size_t sei_a53cc_len; + av_freep(&enc->sei_a53cc_data); + err = ff_alloc_a53_sei(pic->input_image, 0, &enc->sei_a53cc_data, &sei_a53cc_len); + if (err < 0) + return err; + if (enc->sei_a53cc_data != NULL) { + enc->sei_a53cc.itu_t_t35_country_code = 181; + enc->sei_a53cc.data = (uint8_t *)enc->sei_a53cc_data + 1; + enc->sei_a53cc.data_length = sei_a53cc_len - 1; + + hp->units_needed |= UNIT_SEI_A53_CC; + } + } + + return 0; +} + +static void setup_slices(AVCodecContext *avctx, + FFHWBaseEncodePicture *pic) +{ + VulkanEncodeH264Context *enc = avctx->priv_data; + VulkanEncodeH264Picture *hp = pic->codec_priv; + + hp->slice_wt = (StdVideoEncodeH264WeightTable) { + .flags = (StdVideoEncodeH264WeightTableFlags) { + .luma_weight_l0_flag = 0, + .chroma_weight_l0_flag = 0, + .luma_weight_l1_flag = 0, + .chroma_weight_l1_flag = 0, + }, + .luma_log2_weight_denom = 0, + .chroma_log2_weight_denom = 0, + .luma_weight_l0 = { 0 }, + .luma_offset_l0 = { 0 }, + .chroma_weight_l0 = { { 0 } }, + .chroma_offset_l0 = { { 0 } }, + .luma_weight_l1 = { 0 }, + .luma_offset_l1 = { 0 }, + .chroma_weight_l1 = { { 0 } }, + .chroma_offset_l1 = { { 0 } }, + }; + + hp->slice_hdr = (StdVideoEncodeH264SliceHeader) { + .flags = (StdVideoEncodeH264SliceHeaderFlags) { + .direct_spatial_mv_pred_flag = 1, + /* The vk_samples code does this */ + .num_ref_idx_active_override_flag = + ((enc->units.raw_pps.num_ref_idx_l0_default_active_minus1) && + (pic->type == FF_HW_PICTURE_TYPE_B)) ? 1 : 0, + }, + .first_mb_in_slice = 1, + .slice_type = hp->slice_type, + .slice_alpha_c0_offset_div2 = 0, + .slice_beta_offset_div2 = 0, + .slice_qp_delta = 0, /* Filled in below */ + /* Reserved */ + .cabac_init_idc = 0, + .disable_deblocking_filter_idc = 0, + .pWeightTable = NULL, // &hp->slice_wt, + }; + + hp->vkslice = (VkVideoEncodeH264NaluSliceInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_INFO_KHR, + .pNext = NULL, + .constantQp = pic->type == FF_HW_PICTURE_TYPE_B ? enc->fixed_qp_b : + pic->type == FF_HW_PICTURE_TYPE_P ? enc->fixed_qp_p : + enc->unit_opts.fixed_qp_idr, + .pStdSliceHeader = &hp->slice_hdr, + }; + + if (enc->common.opts.rc_mode != VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) + hp->vkslice.constantQp = 0; + + hp->slice_hdr.slice_qp_delta = hp->vkslice.constantQp - + (enc->units.raw_pps.pic_init_qp_minus26 + 26); + + hp->vkh264pic_info.pNaluSliceEntries = &hp->vkslice; + hp->vkh264pic_info.naluSliceEntryCount = 1; +} + +static void vk_enc_h264_default_ref_pic_list(AVCodecContext *avctx, + FFHWBaseEncodePicture *pic, + FFHWBaseEncodePicture **rpl0, + FFHWBaseEncodePicture **rpl1, + int *rpl_size) +{ + FFHWBaseEncodePicture *prev; + VulkanEncodeH264Picture *hp, *hn, *hc; + int i, j, n = 0; + + prev = pic->prev; + av_assert0(prev); + hp = pic->codec_priv; + + for (i = 0; i < pic->prev->nb_dpb_pics; i++) { + hn = prev->dpb[i]->codec_priv; + av_assert0(hn->frame_num < hp->frame_num); + + if (pic->type == FF_HW_PICTURE_TYPE_P) { + for (j = n; j > 0; j--) { + hc = rpl0[j - 1]->codec_priv; + av_assert0(hc->frame_num != hn->frame_num); + if (hc->frame_num > hn->frame_num) + break; + rpl0[j] = rpl0[j - 1]; + } + rpl0[j] = prev->dpb[i]; + + } else if (pic->type == FF_HW_PICTURE_TYPE_B) { + for (j = n; j > 0; j--) { + hc = rpl0[j - 1]->codec_priv; + av_assert0(hc->pic_order_cnt != hp->pic_order_cnt); + if (hc->pic_order_cnt < hp->pic_order_cnt) { + if (hn->pic_order_cnt > hp->pic_order_cnt || + hn->pic_order_cnt < hc->pic_order_cnt) + break; + } else { + if (hn->pic_order_cnt > hc->pic_order_cnt) + break; + } + rpl0[j] = rpl0[j - 1]; + } + rpl0[j] = prev->dpb[i]; + + for (j = n; j > 0; j--) { + hc = rpl1[j - 1]->codec_priv; + av_assert0(hc->pic_order_cnt != hp->pic_order_cnt); + if (hc->pic_order_cnt > hp->pic_order_cnt) { + if (hn->pic_order_cnt < hp->pic_order_cnt || + hn->pic_order_cnt > hc->pic_order_cnt) + break; + } else { + if (hn->pic_order_cnt < hc->pic_order_cnt) + break; + } + rpl1[j] = rpl1[j - 1]; + } + rpl1[j] = prev->dpb[i]; + } + + ++n; + } + + if (pic->type == FF_HW_PICTURE_TYPE_B) { + for (i = 0; i < n; i++) { + if (rpl0[i] != rpl1[i]) + break; + } + if (i == n) + FFSWAP(FFHWBaseEncodePicture *, rpl1[0], rpl1[1]); + } + + if (pic->type == FF_HW_PICTURE_TYPE_P || + pic->type == FF_HW_PICTURE_TYPE_B) { + av_log(avctx, AV_LOG_DEBUG, "Default RefPicList0 for fn=%d/poc=%d:", + hp->frame_num, hp->pic_order_cnt); + for (i = 0; i < n; i++) { + hn = rpl0[i]->codec_priv; + av_log(avctx, AV_LOG_DEBUG, " fn=%d/poc=%d", + hn->frame_num, hn->pic_order_cnt); + } + av_log(avctx, AV_LOG_DEBUG, "\n"); + } + if (pic->type == FF_HW_PICTURE_TYPE_B) { + av_log(avctx, AV_LOG_DEBUG, "Default RefPicList1 for fn=%d/poc=%d:", + hp->frame_num, hp->pic_order_cnt); + for (i = 0; i < n; i++) { + hn = rpl1[i]->codec_priv; + av_log(avctx, AV_LOG_DEBUG, " fn=%d/poc=%d", + hn->frame_num, hn->pic_order_cnt); + } + av_log(avctx, AV_LOG_DEBUG, "\n"); + } + + *rpl_size = n; +} + +static void setup_refs(AVCodecContext *avctx, + FFHWBaseEncodePicture *pic, + VkVideoEncodeInfoKHR *encode_info) +{ + int n, i, j; + VulkanEncodeH264Context *enc = avctx->priv_data; + VulkanEncodeH264Picture *hp = pic->codec_priv; + FFHWBaseEncodePicture *prev = pic->prev; + FFHWBaseEncodePicture *def_l0[MAX_DPB_SIZE], *def_l1[MAX_DPB_SIZE]; + VulkanEncodeH264Picture *href; + + hp->ref_list_info = (StdVideoEncodeH264ReferenceListsInfo) { + .flags = (StdVideoEncodeH264ReferenceListsInfoFlags) { + .ref_pic_list_modification_flag_l0 = 0, + .ref_pic_list_modification_flag_l1 = 0, + /* Reserved */ + }, + /* May be overridden during setup_slices() */ + .num_ref_idx_l0_active_minus1 = pic->nb_refs[0] - 1, + .num_ref_idx_l1_active_minus1 = pic->nb_refs[1] - 1, + /* .RefPicList0 is set in vk_enc_h264_default_ref_pic_list() */ + /* .RefPicList1 is set in vk_enc_h264_default_ref_pic_list() */ + /* Reserved */ + .pRefList0ModOperations = NULL, /* All set below */ + .refList0ModOpCount = 0, + .pRefList1ModOperations = NULL, + .refList1ModOpCount = 0, + .pRefPicMarkingOperations = NULL, + .refPicMarkingOpCount = 0, + }; + + for (i = 0; i < STD_VIDEO_H264_MAX_NUM_LIST_REF; i++) + hp->ref_list_info.RefPicList0[i] = hp->ref_list_info.RefPicList1[i] = -1; + + /* Note: really not sure */ + for (int i = 0; i < pic->nb_refs[0]; i++) { + VkVideoReferenceSlotInfoKHR *slot_info; + slot_info = (VkVideoReferenceSlotInfoKHR *)&encode_info->pReferenceSlots[i]; + hp->ref_list_info.RefPicList0[i] = slot_info->slotIndex; + } + + /* Note: really not sure */ + for (int i = 0; i < pic->nb_refs[1]; i++) { + VkVideoReferenceSlotInfoKHR *slot_info; + slot_info = (VkVideoReferenceSlotInfoKHR *)&encode_info->pReferenceSlots[pic->nb_refs[0] + i]; + hp->ref_list_info.RefPicList1[i] = slot_info->slotIndex; + } + + hp->h264pic_info.pRefLists = &hp->ref_list_info; + + if (pic->is_reference && pic->type != FF_HW_PICTURE_TYPE_IDR) { + FFHWBaseEncodePicture *discard_list[MAX_DPB_SIZE]; + int discard = 0, keep = 0; + + // Discard everything which is in the DPB of the previous frame but + // not in the DPB of this one. + for (i = 0; i < prev->nb_dpb_pics; i++) { + for (j = 0; j < pic->nb_dpb_pics; j++) { + if (prev->dpb[i] == pic->dpb[j]) + break; + } + if (j == pic->nb_dpb_pics) { + discard_list[discard] = prev->dpb[i]; + ++discard; + } else { + ++keep; + } + } + av_assert0(keep <= enc->units.dpb_frames); + + if (discard == 0) { + hp->h264pic_info.flags.adaptive_ref_pic_marking_mode_flag = 0; + } else { + hp->h264pic_info.flags.adaptive_ref_pic_marking_mode_flag = 1; + for (i = 0; i < discard; i++) { + VulkanEncodeH264Picture *old = discard_list[i]->codec_priv; + av_assert0(old->frame_num < hp->frame_num); + hp->mmco[i] = (StdVideoEncodeH264RefPicMarkingEntry) { + .memory_management_control_operation = 1, + .difference_of_pic_nums_minus1 = hp->frame_num - old->frame_num - 1, + }; + } + hp->mmco[i] = (StdVideoEncodeH264RefPicMarkingEntry) { + .memory_management_control_operation = 0, + }; + hp->ref_list_info.pRefPicMarkingOperations = hp->mmco; + hp->ref_list_info.refPicMarkingOpCount = i + 1; + } + } + + if (pic->type == FF_HW_PICTURE_TYPE_I || pic->type == FF_HW_PICTURE_TYPE_IDR) + return; + + // If the intended references are not the first entries of RefPicListN + // by default, use ref-pic-list-modification to move them there. + vk_enc_h264_default_ref_pic_list(avctx, pic, + def_l0, def_l1, &n); + + if (pic->type == FF_HW_PICTURE_TYPE_P) { + int need_rplm = 0; + for (i = 0; i < pic->nb_refs[0]; i++) { + av_assert0(pic->refs[0][i]); + if (pic->refs[0][i] != (FFHWBaseEncodePicture *)def_l0[i]) + need_rplm = 1; + } + + hp->ref_list_info.flags.ref_pic_list_modification_flag_l0 = need_rplm; + if (need_rplm) { + int pic_num = hp->frame_num; + for (i = 0; i < pic->nb_refs[0]; i++) { + href = pic->refs[0][i]->codec_priv; + av_assert0(href->frame_num != pic_num); + if (href->frame_num < pic_num) { + hp->mods[0][i] = (StdVideoEncodeH264RefListModEntry) { + .modification_of_pic_nums_idc = 0, + .abs_diff_pic_num_minus1 = pic_num - href->frame_num - 1, + }; + } else { + hp->mods[0][i] = (StdVideoEncodeH264RefListModEntry) { + .modification_of_pic_nums_idc = 1, + .abs_diff_pic_num_minus1 = href->frame_num - pic_num - 1, + }; + } + pic_num = href->frame_num; + } + hp->ref_list_info.pRefList0ModOperations = hp->mods[0]; + hp->ref_list_info.refList0ModOpCount = i - 1; + } + } else { + int need_rplm_l0 = 0, need_rplm_l1 = 0; + int n0 = 0, n1 = 0; + for (i = 0; i < pic->nb_refs[0]; i++) { + av_assert0(pic->refs[0][i]); + href = pic->refs[0][i]->codec_priv; + av_assert0(href->pic_order_cnt < hp->pic_order_cnt); + if (pic->refs[0][i] != (FFHWBaseEncodePicture *)def_l0[n0]) + need_rplm_l0 = 1; + ++n0; + } + + for (int i = 0; i < pic->nb_refs[1]; i++) { + av_assert0(pic->refs[1][i]); + href = pic->refs[1][i]->codec_priv; + av_assert0(href->pic_order_cnt > hp->pic_order_cnt); + if (pic->refs[1][i] != (FFHWBaseEncodePicture *)def_l1[n1]) + need_rplm_l1 = 1; + ++n1; + } + + hp->ref_list_info.flags.ref_pic_list_modification_flag_l0 = need_rplm_l0; + if (need_rplm_l0) { + int pic_num = hp->frame_num; + for (i = j = 0; i < pic->nb_refs[0]; i++) { + href = pic->refs[0][i]->codec_priv; + av_assert0(href->frame_num != pic_num); + if (href->frame_num < pic_num) { + hp->mods[0][j] = (StdVideoEncodeH264RefListModEntry) { + .modification_of_pic_nums_idc = 0, + .abs_diff_pic_num_minus1 = pic_num - href->frame_num - 1, + }; + } else { + hp->mods[0][j] = (StdVideoEncodeH264RefListModEntry) { + .modification_of_pic_nums_idc = 1, + .abs_diff_pic_num_minus1 = href->frame_num - pic_num - 1, + }; + } + pic_num = href->frame_num; + ++j; + } + hp->ref_list_info.pRefList0ModOperations = hp->mods[0]; + hp->ref_list_info.refList0ModOpCount = j - 1; + } + + hp->ref_list_info.flags.ref_pic_list_modification_flag_l1 = need_rplm_l1; + if (need_rplm_l1) { + int pic_num = hp->frame_num; + for (i = j = 0; i < pic->nb_refs[1]; i++) { + href = pic->refs[1][i]->codec_priv; + av_assert0(href->frame_num != pic_num); + if (href->frame_num < pic_num) { + hp->mods[1][j] = (StdVideoEncodeH264RefListModEntry) { + .modification_of_pic_nums_idc = 0, + .abs_diff_pic_num_minus1 = pic_num - href->frame_num - 1, + }; + } else { + hp->mods[1][j] = (StdVideoEncodeH264RefListModEntry) { + .modification_of_pic_nums_idc = 1, + .abs_diff_pic_num_minus1 = href->frame_num - pic_num - 1, + }; + } + pic_num = href->frame_num; + ++j; + } + hp->ref_list_info.pRefList1ModOperations = hp->mods[1]; + hp->ref_list_info.refList1ModOpCount = j - 1; + } + } +} + +static int init_pic_params(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeInfoKHR *encode_info) +{ + int err; + FFVulkanEncodePicture *vp = pic->priv; + VulkanEncodeH264Picture *hp = pic->codec_priv; + VkVideoReferenceSlotInfoKHR *ref_slot; + + err = vk_enc_h264_update_pic_info(avctx, pic); + if (err < 0) + return err; + + hp->vkh264pic_info = (VkVideoEncodeH264PictureInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PICTURE_INFO_KHR, + .pNext = NULL, + .pNaluSliceEntries = NULL, // Filled in during setup_slices() + .naluSliceEntryCount = 0, // Filled in during setup_slices() + .pStdPictureInfo = &hp->h264pic_info, + }; + + hp->h264pic_info = (StdVideoEncodeH264PictureInfo) { + .flags = (StdVideoEncodeH264PictureInfoFlags) { + .IdrPicFlag = pic->type == FF_HW_PICTURE_TYPE_IDR, + .is_reference = pic->is_reference, + .no_output_of_prior_pics_flag = 0, + .long_term_reference_flag = 0, + .adaptive_ref_pic_marking_mode_flag = 0, // Filled in during setup_refs() + /* Reserved */ + }, + .seq_parameter_set_id = 0, + .pic_parameter_set_id = 0, + .idr_pic_id = hp->idr_pic_id, + .primary_pic_type = pic->type == FF_HW_PICTURE_TYPE_P ? STD_VIDEO_H264_PICTURE_TYPE_P : + pic->type == FF_HW_PICTURE_TYPE_B ? STD_VIDEO_H264_PICTURE_TYPE_B : + pic->type == FF_HW_PICTURE_TYPE_I ? STD_VIDEO_H264_PICTURE_TYPE_I : + STD_VIDEO_H264_PICTURE_TYPE_IDR, + .frame_num = hp->frame_num, + .PicOrderCnt = hp->pic_order_cnt, + .temporal_id = 0, /* ? */ + /* Reserved */ + .pRefLists = NULL, // Filled in during setup_refs + }; + encode_info->pNext = &hp->vkh264pic_info; + + hp->h264dpb_info = (StdVideoEncodeH264ReferenceInfo) { + .flags = (StdVideoEncodeH264ReferenceInfoFlags) { + .used_for_long_term_reference = 0, + /* Reserved */ + }, + .primary_pic_type = hp->h264pic_info.primary_pic_type, + .FrameNum = hp->h264pic_info.frame_num, + .PicOrderCnt = hp->h264pic_info.PicOrderCnt, + .long_term_pic_num = 0, + .long_term_frame_idx = 0, + .temporal_id = hp->h264pic_info.temporal_id, + }; + hp->vkh264dpb_info = (VkVideoEncodeH264DpbSlotInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_KHR, + .pStdReferenceInfo = &hp->h264dpb_info, + }; + + vp->dpb_slot.pNext = &hp->vkh264dpb_info; + + ref_slot = (VkVideoReferenceSlotInfoKHR *)encode_info->pSetupReferenceSlot; + ref_slot->pNext = &hp->vkh264dpb_info; + + setup_refs(avctx, pic, encode_info); + + setup_slices(avctx, pic); + + return 0; +} + +static int init_profile(AVCodecContext *avctx, + VkVideoProfileInfoKHR *profile, void *pnext) +{ + VkResult ret; + VulkanEncodeH264Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + VkVideoEncodeH264CapabilitiesKHR h264_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_KHR, + }; + VkVideoEncodeCapabilitiesKHR enc_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR, + .pNext = &h264_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_H264_CONSTRAINED_BASELINE, + AV_PROFILE_H264_MAIN, + AV_PROFILE_H264_HIGH, + AV_PROFILE_H264_HIGH_10, + }; + 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 (desc->comp[0].depth == 8) + nb_profiles = 3; + + enc->profile = (VkVideoEncodeH264ProfileInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_KHR, + .pNext = pnext, + .stdProfileIdc = ff_vk_h264_profile_to_vk(avctx->profile), + }; + profile->pNext = &enc->profile; + + /* Set level */ + if (avctx->level == AV_LEVEL_UNKNOWN) + avctx->level = enc->common.opts.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.stdProfileIdc = ff_vk_h264_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.stdProfileIdc = ff_vk_h264_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) +{ + VulkanEncodeH264Context *enc = avctx->priv_data; + FFHWBaseEncodeH264Opts *unit_opts = &enc->unit_opts; + + if (avctx->rc_buffer_size) + unit_opts->hrd_buffer_size = avctx->rc_buffer_size; + else if (avctx->rc_max_rate > 0) + unit_opts->hrd_buffer_size = avctx->rc_max_rate; + else + unit_opts->hrd_buffer_size = avctx->bit_rate; + + if (avctx->rc_initial_buffer_occupancy) { + if (avctx->rc_initial_buffer_occupancy > unit_opts->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, unit_opts->hrd_buffer_size); + return AVERROR(EINVAL); + } + unit_opts->initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; + } else { + unit_opts->initial_buffer_fullness = unit_opts->hrd_buffer_size * 3 / 4; + } + + if (enc->common.opts.rc_mode == VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) { + /* HRD info is required for timing */ + enc->unit_elems &= ~UNIT_SEI_TIMING; + + enc->fixed_qp_p = av_clip(enc->common.explicit_qp, + enc->caps.minQp, enc->caps.maxQp); + if (avctx->i_quant_factor > 0.0) + unit_opts->fixed_qp_idr = av_clip((avctx->i_quant_factor * enc->fixed_qp_p + + avctx->i_quant_offset) + 0.5, + enc->caps.minQp, enc->caps.maxQp); + else + unit_opts->fixed_qp_idr = enc->fixed_qp_p; + + if (avctx->b_quant_factor > 0.0) + enc->fixed_qp_b = av_clip((avctx->b_quant_factor * enc->fixed_qp_p + + avctx->b_quant_offset) + 0.5, + enc->caps.minQp, enc->caps.maxQp); + else + enc->fixed_qp_b = enc->fixed_qp_p; + + av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " + "%d / %d / %d for IDR- / P- / B-frames.\n", + unit_opts->fixed_qp_idr, enc->fixed_qp_p, enc->fixed_qp_b); + } else { + unit_opts->fixed_qp_idr = 26; + enc->fixed_qp_p = 26; + enc->fixed_qp_b = 26; + } + + return 0; +} + +static av_cold int init_sequence_headers(AVCodecContext *avctx) +{ + int err; + VulkanEncodeH264Context *enc = avctx->priv_data; + + FFHWBaseEncodeH264 *units = &enc->units; + FFHWBaseEncodeH264Opts *unit_opts = &enc->unit_opts; + + unit_opts->bit_rate = avctx->bit_rate; + unit_opts->mb_width = FFALIGN(avctx->width, 16) / 16; + unit_opts->mb_height = FFALIGN(avctx->height, 16) / 16; + unit_opts->flags = enc->unit_elems & UNIT_SEI_TIMING ? FF_HW_H264_SEI_TIMING : 0; + + /* cabac already set via an option */ + /* fixed_qp_idr initialized in init_enc_options() */ + /* hrd_buffer_size initialized in init_enc_options() */ + /* initial_buffer_fullness initialized in init_enc_options() */ + + err = ff_hw_base_encode_init_params_h264(&enc->common.base, avctx, + units, unit_opts); + if (err < 0) + return err; + + units->raw_sps.seq_scaling_matrix_present_flag = + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_KHR); + units->raw_pps.pic_scaling_matrix_present_flag = + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_KHR); + units->raw_pps.transform_8x8_mode_flag = + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_TRANSFORM_8X8_MODE_FLAG_SET_BIT_KHR); + + return 0; +} + +typedef struct VulkanH264Units { + StdVideoH264SequenceParameterSet vksps; + StdVideoH264ScalingLists vksps_scaling; + StdVideoH264HrdParameters vksps_vui_header; + StdVideoH264SequenceParameterSetVui vksps_vui; + + StdVideoH264PictureParameterSet vkpps; + StdVideoH264ScalingLists vkpps_scaling; +} VulkanH264Units; + +static av_cold int base_unit_to_vk(AVCodecContext *avctx, + VulkanH264Units *vk_units) +{ + VulkanEncodeH264Context *enc = avctx->priv_data; + + FFHWBaseEncodeH264 *units = &enc->units; + + H264RawSPS *sps = &units->raw_sps; + H264RawHRD *hrd = &sps->vui.nal_hrd_parameters; + StdVideoH264ScalingLists *vksps_scaling = &vk_units->vksps_scaling; + StdVideoH264HrdParameters *vksps_vui_header = &vk_units->vksps_vui_header; + StdVideoH264SequenceParameterSetVui *vksps_vui = &vk_units->vksps_vui; + StdVideoH264SequenceParameterSet *vksps = &vk_units->vksps; + + H264RawPPS *pps = &units->raw_pps; + StdVideoH264ScalingLists *vkpps_scaling = &vk_units->vkpps_scaling; + StdVideoH264PictureParameterSet *vkpps = &vk_units->vkpps; + + *vksps_scaling = (StdVideoH264ScalingLists) { + .scaling_list_present_mask = 0x0, // mask + .use_default_scaling_matrix_mask = 1, + }; + + *vksps_vui_header = (StdVideoH264HrdParameters) { + .cpb_cnt_minus1 = hrd->cpb_cnt_minus1, + .bit_rate_scale = hrd->bit_rate_scale, + .cpb_size_scale = hrd->cpb_size_scale, + /* Reserved */ + /* bit_rate/cpb_size/cbr_flag set below */ + .initial_cpb_removal_delay_length_minus1 = hrd->initial_cpb_removal_delay_length_minus1, + .cpb_removal_delay_length_minus1 = hrd->cpb_removal_delay_length_minus1, + .dpb_output_delay_length_minus1 = hrd->dpb_output_delay_length_minus1, + .time_offset_length = hrd->time_offset_length, + }; + + for (int i = 0; i < H264_MAX_CPB_CNT; i++) { + vksps_vui_header->bit_rate_value_minus1[i] = hrd->bit_rate_value_minus1[i]; + vksps_vui_header->cpb_size_value_minus1[i] = hrd->cpb_size_value_minus1[i]; + vksps_vui_header->cbr_flag[i] = hrd->cbr_flag[i]; + } + + *vksps_vui = (StdVideoH264SequenceParameterSetVui) { + .flags = (StdVideoH264SpsVuiFlags) { + .aspect_ratio_info_present_flag = sps->vui.aspect_ratio_info_present_flag, + .overscan_info_present_flag = sps->vui.overscan_info_present_flag, + .overscan_appropriate_flag = sps->vui.overscan_appropriate_flag, + .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_loc_info_present_flag, + .timing_info_present_flag = sps->vui.timing_info_present_flag, + .fixed_frame_rate_flag = sps->vui.fixed_frame_rate_flag, + .bitstream_restriction_flag = sps->vui.bitstream_restriction_flag, + .nal_hrd_parameters_present_flag = sps->vui.nal_hrd_parameters_present_flag, + .vcl_hrd_parameters_present_flag = sps->vui.vcl_hrd_parameters_present_flag, + }, + .aspect_ratio_idc = sps->vui.aspect_ratio_idc, + .sar_width = sps->vui.sar_width, + .sar_height = sps->vui.sar_height, + .video_format = sps->vui.video_format, + .colour_primaries = sps->vui.colour_primaries, + .transfer_characteristics = sps->vui.transfer_characteristics, + .matrix_coefficients = sps->vui.matrix_coefficients, + .num_units_in_tick = sps->vui.num_units_in_tick, + .time_scale = sps->vui.time_scale, + .max_num_reorder_frames = sps->vui.max_num_reorder_frames, + .max_dec_frame_buffering = sps->vui.max_dec_frame_buffering, + .chroma_sample_loc_type_top_field = sps->vui.chroma_sample_loc_type_top_field, + .chroma_sample_loc_type_bottom_field = sps->vui.chroma_sample_loc_type_bottom_field, + /* Reserved */ + .pHrdParameters = vksps_vui_header, + }; + + *vksps = (StdVideoH264SequenceParameterSet) { + .flags = (StdVideoH264SpsFlags) { + .constraint_set0_flag = sps->constraint_set0_flag, + .constraint_set1_flag = sps->constraint_set1_flag, + .constraint_set2_flag = sps->constraint_set2_flag, + .constraint_set3_flag = sps->constraint_set3_flag, + .constraint_set4_flag = sps->constraint_set4_flag, + .constraint_set5_flag = sps->constraint_set5_flag, + .direct_8x8_inference_flag = sps->direct_8x8_inference_flag, + .mb_adaptive_frame_field_flag = sps->mb_adaptive_frame_field_flag, + .frame_mbs_only_flag = sps->frame_mbs_only_flag, + .delta_pic_order_always_zero_flag = sps->delta_pic_order_always_zero_flag, + .separate_colour_plane_flag = sps->separate_colour_plane_flag, + .gaps_in_frame_num_value_allowed_flag = sps->gaps_in_frame_num_allowed_flag, + .qpprime_y_zero_transform_bypass_flag = sps->qpprime_y_zero_transform_bypass_flag, + .frame_cropping_flag = sps->frame_cropping_flag, + .seq_scaling_matrix_present_flag = sps->seq_scaling_matrix_present_flag, + .vui_parameters_present_flag = sps->vui_parameters_present_flag, + }, + .profile_idc = ff_vk_h264_profile_to_vk(sps->profile_idc), + .level_idc = ff_vk_h264_level_to_vk(sps->level_idc), + .chroma_format_idc = sps->chroma_format_idc, + .seq_parameter_set_id = sps->seq_parameter_set_id, + .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8, + .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8, + .log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4, + .pic_order_cnt_type = sps->pic_order_cnt_type, + .offset_for_non_ref_pic = sps->offset_for_non_ref_pic, + .offset_for_top_to_bottom_field = sps->offset_for_top_to_bottom_field, + .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4, + .num_ref_frames_in_pic_order_cnt_cycle = sps->num_ref_frames_in_pic_order_cnt_cycle, + .max_num_ref_frames = sps->max_num_ref_frames, + /* Reserved */ + .pic_width_in_mbs_minus1 = sps->pic_width_in_mbs_minus1, + .pic_height_in_map_units_minus1 = sps->pic_height_in_map_units_minus1, + .frame_crop_left_offset = sps->frame_crop_left_offset, + .frame_crop_right_offset = sps->frame_crop_right_offset, + .frame_crop_top_offset = sps->frame_crop_top_offset, + .frame_crop_bottom_offset = sps->frame_crop_bottom_offset, + /* Reserved */ + .pOffsetForRefFrame = sps->offset_for_ref_frame, + .pScalingLists = vksps_scaling, + .pSequenceParameterSetVui = vksps_vui, + }; + + *vkpps_scaling = (StdVideoH264ScalingLists) { + .scaling_list_present_mask = 0x0, // mask + .use_default_scaling_matrix_mask = 1, + }; + + *vkpps = (StdVideoH264PictureParameterSet) { + .flags = (StdVideoH264PpsFlags) { + .transform_8x8_mode_flag = pps->transform_8x8_mode_flag, + .redundant_pic_cnt_present_flag = pps->redundant_pic_cnt_present_flag, + .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, + .deblocking_filter_control_present_flag = pps->deblocking_filter_control_present_flag, + .weighted_pred_flag = pps->weighted_pred_flag, + .bottom_field_pic_order_in_frame_present_flag = pps->bottom_field_pic_order_in_frame_present_flag, + .entropy_coding_mode_flag = pps->entropy_coding_mode_flag, + .pic_scaling_matrix_present_flag = pps->pic_scaling_matrix_present_flag, + }, + .seq_parameter_set_id = pps->seq_parameter_set_id, + .pic_parameter_set_id = pps->pic_parameter_set_id, + .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1, + .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1, + .weighted_bipred_idc = pps->weighted_bipred_idc, + .pic_init_qp_minus26 = pps->pic_init_qp_minus26, + .pic_init_qs_minus26 = pps->pic_init_qs_minus26, + .chroma_qp_index_offset = pps->chroma_qp_index_offset, + .second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset, + .pScalingLists = vkpps_scaling, + }; + + return 0; +} + +static int create_session_params(AVCodecContext *avctx) +{ + int err; + VulkanEncodeH264Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + VulkanH264Units vk_units = { 0 }; + + VkVideoEncodeH264SessionParametersAddInfoKHR h264_params_info; + VkVideoEncodeH264SessionParametersCreateInfoKHR h264_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 SPS/PPS units 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); + + h264_params_info = (VkVideoEncodeH264SessionParametersAddInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR, + .pStdSPSs = &vk_units.vksps, + .stdSPSCount = 1, + .pStdPPSs = &vk_units.vkpps, + .stdPPSCount = 1, + }; + h264_params = (VkVideoEncodeH264SessionParametersCreateInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR, + .maxStdSPSCount = 1, + .maxStdPPSCount = 1, + .pParametersAddInfo = &h264_params_info, + }; + + return ff_vulkan_encode_create_session_params(avctx, ctx, &h264_params); +} + +static int parse_feedback_units(AVCodecContext *avctx, + const uint8_t *data, size_t size, + int sps_override, int pps_override) +{ + int err; + VulkanEncodeH264Context *enc = avctx->priv_data; + + CodedBitstreamContext *cbs; + CodedBitstreamFragment au = { 0 }; + + err = ff_cbs_init(&cbs, AV_CODEC_ID_H264, avctx); + if (err < 0) + return err; + + err = ff_cbs_read(cbs, &au, 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. */ + if (pps_override) { + for (int i = 0; i < au.nb_units; i++) { + if (au.units[i].type == H264_NAL_PPS) { + H264RawPPS *pps = au.units[i].content; + memcpy(&enc->units.raw_pps, pps, sizeof(*pps)); + break; + } + } + } + + ff_cbs_fragment_free(&au); + ff_cbs_close(&cbs); + + return 0; +} + +static int init_base_units(AVCodecContext *avctx) +{ + int err; + VkResult ret; + VulkanEncodeH264Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + VkVideoEncodeH264SessionParametersGetInfoKHR h264_params_info; + VkVideoEncodeSessionParametersGetInfoKHR params_info; + VkVideoEncodeH264SessionParametersFeedbackInfoKHR h264_params_feedback; + 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 SPS/PPS units: %s\n", + av_err2str(err)); + return err; + } + + /* Create session parameters from them */ + err = create_session_params(avctx); + if (err < 0) + return err; + + h264_params_info = (VkVideoEncodeH264SessionParametersGetInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_GET_INFO_KHR, + .writeStdSPS = 1, + .writeStdPPS = 1, + .stdSPSId = enc->units.raw_sps.seq_parameter_set_id, + .stdPPSId = enc->units.raw_pps.pic_parameter_set_id, + }; + params_info = (VkVideoEncodeSessionParametersGetInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_GET_INFO_KHR, + .pNext = &h264_params_info, + .videoSessionParameters = ctx->session_params, + }; + + h264_params_feedback = (VkVideoEncodeH264SessionParametersFeedbackInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_FEEDBACK_INFO_KHR, + }; + params_feedback = (VkVideoEncodeSessionParametersFeedbackInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_FEEDBACK_INFO_KHR, + .pNext = &h264_params_feedback, + }; + + 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 H.264 units = %lu\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 (SPS: %i PPS: %i)\n", + params_feedback.hasOverrides, + h264_params_feedback.hasStdSPSOverrides, + h264_params_feedback.hasStdPPSOverrides); + + params_feedback.hasOverrides = 1; + h264_params_feedback.hasStdPPSOverrides = 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, + h264_params_feedback.hasStdSPSOverrides, + h264_params_feedback.hasStdPPSOverrides); + 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_h264_add_nal(AVCodecContext *avctx, + CodedBitstreamFragment *au, + void *nal_unit) +{ + H264RawNALUnitHeader *header = nal_unit; + + int 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; +} + +static int write_access_unit(AVCodecContext *avctx, + uint8_t *data, size_t *data_len, + CodedBitstreamFragment *au) +{ + VulkanEncodeH264Context *enc = avctx->priv_data; + + int err = ff_cbs_write_fragment_data(enc->cbs, au); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; + } + + if (*data_len < au->data_size) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: %zu < %zu.\n", + *data_len, au->data_size); + return AVERROR(ENOSPC); + } + + memcpy(data, au->data, au->data_size); + *data_len = au->data_size; + + return 0; +} + +static int write_sequence_headers(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeH264Context *enc = avctx->priv_data; + VulkanEncodeH264Picture *hp = base_pic ? base_pic->codec_priv : NULL; + CodedBitstreamFragment *au = &enc->current_access_unit; + + if (hp && hp->units_needed & UNIT_AUD) { + err = vulkan_encode_h264_add_nal(avctx, au, &enc->raw_aud); + if (err < 0) + goto fail; + } + + err = vulkan_encode_h264_add_nal(avctx, au, &enc->units.raw_sps); + if (err < 0) + goto fail; + + err = vulkan_encode_h264_add_nal(avctx, au, &enc->units.raw_pps); + if (err < 0) + goto fail; + + err = write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_reset(au); + return err; +} + +static int write_extra_headers(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeH264Context *enc = avctx->priv_data; + VulkanEncodeH264Picture *hp = base_pic->codec_priv; + CodedBitstreamFragment *au = &enc->current_access_unit; + + if (hp->units_needed & UNIT_AUD) { + err = vulkan_encode_h264_add_nal(avctx, au, &enc->raw_aud); + if (err < 0) + goto fail; + } + + if (hp->units_needed & UNIT_SEI_IDENTIFIER) { + err = ff_cbs_sei_add_message(enc->cbs, au, 1, + SEI_TYPE_USER_DATA_UNREGISTERED, + &enc->sei_identifier, NULL); + if (err < 0) + goto fail; + } + + if (hp->units_needed & UNIT_SEI_TIMING) { + if (base_pic->type == FF_HW_PICTURE_TYPE_IDR) { + err = ff_cbs_sei_add_message(enc->cbs, au, 1, + SEI_TYPE_BUFFERING_PERIOD, + &enc->units.sei_buffering_period, NULL); + if (err < 0) + goto fail; + } + err = ff_cbs_sei_add_message(enc->cbs, au, 1, + SEI_TYPE_PIC_TIMING, + &enc->sei_pic_timing, NULL); + if (err < 0) + goto fail; + } + + if (hp->units_needed & UNIT_SEI_RECOVERY) { + err = ff_cbs_sei_add_message(enc->cbs, au, 1, + SEI_TYPE_RECOVERY_POINT, + &enc->sei_recovery_point, NULL); + if (err < 0) + goto fail; + } + + if (hp->units_needed & UNIT_SEI_A53_CC) { + err = ff_cbs_sei_add_message(enc->cbs, au, 1, + SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35, + &enc->sei_a53cc, NULL); + if (err < 0) + goto fail; + } + + if (hp->units_needed) { + err = write_access_unit(avctx, data, data_len, au); + if (err < 0) + goto fail; + } else { + *data_len = 0; + } + +fail: + ff_cbs_fragment_reset(au); + return err; +} + +static int write_filler(AVCodecContext *avctx, uint32_t filler, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeH264Context *enc = avctx->priv_data; + CodedBitstreamFragment *au = &enc->current_access_unit; + + H264RawFiller raw_filler = { + .nal_unit_header = { + .nal_unit_type = H264_NAL_FILLER_DATA, + }, + .filler_size = filler, + }; + + err = vulkan_encode_h264_add_nal(avctx, au, &raw_filler); + if (err < 0) + goto fail; + + err = write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_reset(au); + return err; +} + +static const FFVulkanCodec enc_cb = { + .flags = FF_HW_FLAG_B_PICTURES | + FF_HW_FLAG_B_PICTURE_REFERENCES | + FF_HW_FLAG_NON_IDR_KEY_PICTURES, + .picture_priv_data_size = sizeof(VulkanEncodeH264Picture), + .filler_header_size = 6, + .init_profile = init_profile, + .init_pic_rc = init_pic_rc, + .init_pic_params = init_pic_params, + .write_sequence_headers = write_sequence_headers, + .write_extra_headers = write_extra_headers, + .write_filler = write_filler, +}; + +static av_cold int vulkan_encode_h264_init(AVCodecContext *avctx) +{ + int err, ref_l0, ref_l1; + VulkanEncodeH264Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + int flags; + + if (avctx->profile == AV_PROFILE_UNKNOWN) + avctx->profile = enc->common.opts.profile; + + enc->caps = (VkVideoEncodeH264CapabilitiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_KHR, + }; + + enc->quality_props = (VkVideoEncodeH264QualityLevelPropertiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_QUALITY_LEVEL_PROPERTIES_KHR, + }; + + err = ff_vulkan_encode_init(avctx, &enc->common, + &ff_vk_enc_h264_desc, &enc_cb, + &enc->caps, &enc->quality_props); + if (err < 0) + return err; + + av_log(avctx, AV_LOG_VERBOSE, "H264 encoder capabilities:\n"); + av_log(avctx, AV_LOG_VERBOSE, " Standard capability flags:\n"); + av_log(avctx, AV_LOG_VERBOSE, " separate_color_plane: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " qprime_y_zero_transform_bypass: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " scaling_lists: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " chroma_qp_index_offset: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_CHROMA_QP_INDEX_OFFSET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " second_chroma_qp_index_offset: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_SECOND_CHROMA_QP_INDEX_OFFSET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " pic_init_qp: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_PIC_INIT_QP_MINUS26_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " weighted:%s%s%s\n", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_WEIGHTED_PRED_FLAG_SET_BIT_KHR ? + " pred" : "", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_EXPLICIT_BIT_KHR ? + " bipred_explicit" : "", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_WEIGHTED_BIPRED_IDC_IMPLICIT_BIT_KHR ? + " bipred_implicit" : ""); + av_log(avctx, AV_LOG_VERBOSE, " 8x8_transforms: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_TRANSFORM_8X8_MODE_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " disable_direct_spatial_mv_pred: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_DIRECT_SPATIAL_MV_PRED_FLAG_UNSET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " coder:%s%s\n", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_UNSET_BIT_KHR ? + " cabac" : "", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_ENTROPY_CODING_MODE_FLAG_SET_BIT_KHR ? + " cavlc" : ""); + av_log(avctx, AV_LOG_VERBOSE, " direct_8x8_inference: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_DIRECT_8X8_INFERENCE_FLAG_UNSET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " constrained_intra_pred: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " deblock:%s%s%s\n", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_DISABLED_BIT_KHR ? + " filter_disabling" : "", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_ENABLED_BIT_KHR ? + " filter_enabling" : "", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_DEBLOCKING_FILTER_PARTIAL_BIT_KHR ? + " filter_partial" : ""); + + av_log(avctx, AV_LOG_VERBOSE, " Capability flags:\n"); + av_log(avctx, AV_LOG_VERBOSE, " hdr_compliance: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_HRD_COMPLIANCE_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " pred_weight_table_generated: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " row_unaligned_slice: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " different_slice_type: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_DIFFERENT_SLICE_TYPE_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " b_frame_in_l0_list: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " b_frame_in_l1_list: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " per_pict_type_min_max_qp: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " per_slice_constant_qp: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_PER_SLICE_CONSTANT_QP_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " generate_prefix_nalu: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_GENERATE_PREFIX_NALU_BIT_KHR)); + + av_log(avctx, AV_LOG_VERBOSE, " Capabilities:\n"); + av_log(avctx, AV_LOG_VERBOSE, " maxLevelIdc: %i\n", + enc->caps.maxLevelIdc); + av_log(avctx, AV_LOG_VERBOSE, " maxSliceCount: %i\n", + enc->caps.maxSliceCount); + av_log(avctx, AV_LOG_VERBOSE, " max(P/B)PictureL0ReferenceCount: %i P's; %i B's\n", + enc->caps.maxPPictureL0ReferenceCount, + enc->caps.maxBPictureL0ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxL1ReferenceCount: %i\n", + enc->caps.maxL1ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxTemporalLayerCount: %i\n", + enc->caps.maxTemporalLayerCount); + av_log(avctx, AV_LOG_VERBOSE, " expectDyadicTemporalLayerPattern: %i\n", + enc->caps.expectDyadicTemporalLayerPattern); + av_log(avctx, AV_LOG_VERBOSE, " min/max Qp: [%i, %i]\n", + enc->caps.minQp, enc->caps.maxQp); + av_log(avctx, AV_LOG_VERBOSE, " prefersGopRemainingFrames: %i\n", + enc->caps.prefersGopRemainingFrames); + av_log(avctx, AV_LOG_VERBOSE, " requiresGopRemainingFrames: %i\n", + enc->caps.requiresGopRemainingFrames); + + err = init_enc_options(avctx); + if (err < 0) + return err; + + flags = ctx->codec->flags; + if (!enc->caps.maxPPictureL0ReferenceCount && + !enc->caps.maxBPictureL0ReferenceCount && + !enc->caps.maxL1ReferenceCount) { + /* Intra-only */ + flags |= FF_HW_FLAG_INTRA_ONLY; + ref_l0 = ref_l1 = 0; + } else if (!enc->caps.maxPPictureL0ReferenceCount) { + /* No P-frames? How. */ + base_ctx->p_to_gpb = 1; + ref_l0 = enc->caps.maxBPictureL0ReferenceCount; + ref_l1 = enc->caps.maxL1ReferenceCount; + } else if (!enc->caps.maxBPictureL0ReferenceCount && + !enc->caps.maxL1ReferenceCount) { + /* No B-frames */ + flags &= ~(FF_HW_FLAG_B_PICTURES | FF_HW_FLAG_B_PICTURE_REFERENCES); + ref_l0 = enc->caps.maxPPictureL0ReferenceCount; + ref_l1 = 0; + } else { + /* P and B frames */ + ref_l0 = FFMIN(enc->caps.maxPPictureL0ReferenceCount, + enc->caps.maxBPictureL0ReferenceCount); + ref_l1 = enc->caps.maxL1ReferenceCount; + } + + err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1, + 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; + + /* Prepare SEI */ + if (enc->unit_elems & UNIT_SEI_IDENTIFIER) { + int len; + + memcpy(enc->sei_identifier.uuid_iso_iec_11578, + vulkan_encode_h264_sei_identifier_uuid, + sizeof(enc->sei_identifier.uuid_iso_iec_11578)); + + len = snprintf(NULL, 0, + "%s / Vulkan video %i.%i.%i / %s %i.%i.%i / %s", + LIBAVCODEC_IDENT, + CODEC_VER(ff_vk_enc_h264_desc.ext_props.specVersion), + s->driver_props.driverName, + CODEC_VER(s->props.properties.driverVersion), + s->props.properties.deviceName); + + if (len >= 0) { + enc->sei_identifier_string = av_malloc(len + 1); + if (!enc->sei_identifier_string) + return AVERROR(ENOMEM); + + len = snprintf(enc->sei_identifier_string, len + 1, + "%s / Vulkan video %i.%i.%i / %s %i.%i.%i / %s", + LIBAVCODEC_IDENT, + CODEC_VER(ff_vk_enc_h264_desc.ext_props.specVersion), + s->driver_props.driverName, + CODEC_VER(s->props.properties.driverVersion), + s->props.properties.deviceName); + + enc->sei_identifier.data = enc->sei_identifier_string; + enc->sei_identifier.data_length = len + 1; + } + } + + /* Init CBS */ + err = ff_cbs_init(&enc->cbs, AV_CODEC_ID_H264, avctx); + if (err < 0) + return err; + + /* Create units and session parameters */ + err = init_base_units(avctx); + if (err < 0) + return err; + + /* Write out extradata */ + err = ff_vulkan_write_global_header(avctx, &enc->common); + if (err < 0) + return err; + + return 0; +} + +static av_cold int vulkan_encode_h264_close(AVCodecContext *avctx) +{ + VulkanEncodeH264Context *enc = avctx->priv_data; + ff_vulkan_encode_uninit(&enc->common); + return 0; +} + +#define OFFSET(x) offsetof(VulkanEncodeH264Context, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption vulkan_encode_h264_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, + VULKAN_ENCODE_COMMON_OPTIONS, + + { "profile", "Set profile (profile_idc and constraint_set*_flag)", + 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("constrained_baseline", AV_PROFILE_H264_CONSTRAINED_BASELINE) }, + { PROFILE("main", AV_PROFILE_H264_MAIN) }, + { PROFILE("high", AV_PROFILE_H264_HIGH) }, + { PROFILE("high444p", AV_PROFILE_H264_HIGH_10) }, +#undef PROFILE + + { "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("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 + + { "coder", "Entropy coder type", OFFSET(unit_opts.cabac), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS, "coder" }, + { "cabac", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, FLAGS, "coder" }, + { "vlc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS, "coder" }, + + { "units", "Set units to include", OFFSET(unit_elems), AV_OPT_TYPE_FLAGS, { .i64 = UNIT_AUD | UNIT_SEI_IDENTIFIER | UNIT_SEI_RECOVERY | UNIT_SEI_TIMING | UNIT_SEI_A53_CC }, 0, INT_MAX, FLAGS, "units" }, + { "aud", "Include AUD units", 0, AV_OPT_TYPE_CONST, { .i64 = UNIT_AUD }, INT_MIN, INT_MAX, FLAGS, "units" }, + { "identifier", "Include encoder version identifier", 0, AV_OPT_TYPE_CONST, { .i64 = UNIT_SEI_IDENTIFIER }, INT_MIN, INT_MAX, FLAGS, "units" }, + { "timing", "Include timing parameters (buffering_period and pic_timing)", 0, AV_OPT_TYPE_CONST, { .i64 = UNIT_SEI_TIMING }, INT_MIN, INT_MAX, FLAGS, "units" }, + { "recovery", "Include recovery points where appropriate", 0, AV_OPT_TYPE_CONST, { .i64 = UNIT_SEI_RECOVERY }, INT_MIN, INT_MAX, FLAGS, "units" }, + { "a53_cc", "Include A/53 caption data", 0, AV_OPT_TYPE_CONST, { .i64 = UNIT_SEI_A53_CC }, INT_MIN, INT_MAX, FLAGS, "units" }, + + { NULL }, +}; + +static const FFCodecDefault vulkan_encode_h264_defaults[] = { + { "b", "0" }, + { "bf", "2" }, + { "g", "300" }, + { "i_qfactor", "1" }, + { "i_qoffset", "0" }, + { "b_qfactor", "1" }, + { "b_qoffset", "0" }, + { "qmin", "-1" }, + { "qmax", "-1" }, + { NULL }, +}; + +static const AVClass vulkan_encode_h264_class = { + .class_name = "h264_vulkan", + .item_name = av_default_item_name, + .option = vulkan_encode_h264_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_h264_vulkan_encoder = { + .p.name = "h264_vulkan", + CODEC_LONG_NAME("H.264/AVC (Vulkan)"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_H264, + .priv_data_size = sizeof(VulkanEncodeH264Context), + .init = &vulkan_encode_h264_init, + FF_CODEC_RECEIVE_PACKET_CB(&ff_vulkan_encode_receive_packet), + .close = &vulkan_encode_h264_close, + .p.priv_class = &vulkan_encode_h264_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_h264_defaults, + .p.pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_VULKAN, + AV_PIX_FMT_NONE, + }, + .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 new file mode 100644 index 000000000..6aadbc93f --- /dev/null +++ b/libavcodec/vulkan_encode_h265.c @@ -0,0 +1,1793 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_h265.h" +#include "atsc_a53.h" +#include "libavutil/mastering_display_metadata.h" + +#include "codec_internal.h" +#include "version.h" +#include "hw_base_encode_h265.h" + +#include "vulkan_encode.h" + +enum UnitElems { + UNIT_AUD = 1 << 0, + UNIT_SEI_MASTERING_DISPLAY = 1 << 1, + UNIT_SEI_CONTENT_LIGHT_LEVEL = 1 << 2, + UNIT_SEI_A53_CC = 1 << 3, +}; + +const FFVulkanEncodeDescriptor ff_vk_enc_h265_desc = { + .codec_id = AV_CODEC_ID_H265, + .encode_extension = FF_VK_EXT_VIDEO_ENCODE_H265, + .encode_op = VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR, + .ext_props = { + .extensionName = VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME, + .specVersion = VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION, + }, +}; + +typedef struct VulkanEncodeH265Picture { + int frame_num; + int64_t last_idr_frame; + uint16_t idr_pic_id; + int primary_pic_type; + int slice_type; + int pic_order_cnt; + int pic_type; + + enum UnitElems units_needed; + + VkVideoEncodeH265RateControlInfoKHR vkrc_info; + VkVideoEncodeH265RateControlLayerInfoKHR vkrc_layer_info; + + StdVideoEncodeH265PictureInfo h265pic_info; + VkVideoEncodeH265PictureInfoKHR vkh265pic_info; + + StdVideoEncodeH265WeightTable slice_wt; + StdVideoEncodeH265SliceSegmentHeader slice_hdr; + VkVideoEncodeH265NaluSliceSegmentInfoKHR vkslice; + + StdVideoEncodeH265ReferenceInfo h265dpb_info; + VkVideoEncodeH265DpbSlotInfoKHR vkh265dpb_info; + + StdVideoEncodeH265ReferenceListsInfo ref_list_info; + StdVideoEncodeH265LongTermRefPics l_rps; + StdVideoH265ShortTermRefPicSet s_rps; +} VulkanEncodeH265Picture; + +typedef struct VulkanEncodeH265Context { + FFVulkanEncodeContext common; + + FFHWBaseEncodeH265 units; + FFHWBaseEncodeH265Opts unit_opts; + + enum UnitElems unit_elems; + + uint8_t fixed_qp_idr; + uint8_t fixed_qp_p; + uint8_t fixed_qp_b; + + uint64_t hrd_buffer_size; + uint64_t initial_buffer_fullness; + + VkVideoEncodeH265ProfileInfoKHR profile; + + VkVideoEncodeH265CapabilitiesKHR caps; + VkVideoEncodeH265QualityLevelPropertiesKHR quality_props; + + CodedBitstreamContext *cbs; + CodedBitstreamFragment current_access_unit; + + H265RawAUD raw_aud; + + SEIRawMasteringDisplayColourVolume sei_mastering_display; + SEIRawContentLightLevelInfo sei_content_light_level; + SEIRawUserDataRegistered sei_a53cc; + void *sei_a53cc_data; +} VulkanEncodeH265Context; + +static int init_pic_rc(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeRateControlInfoKHR *rc_info, + VkVideoEncodeRateControlLayerInfoKHR *rc_layer) +{ + VulkanEncodeH265Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + VulkanEncodeH265Picture *hp = pic->codec_priv; + + hp->vkrc_info = (VkVideoEncodeH265RateControlInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_KHR, + .flags = VK_VIDEO_ENCODE_H265_RATE_CONTROL_REFERENCE_PATTERN_FLAT_BIT_KHR | + VK_VIDEO_ENCODE_H265_RATE_CONTROL_REGULAR_GOP_BIT_KHR, + .idrPeriod = ctx->base.gop_size, + .gopFrameCount = ctx->base.gop_size, + .consecutiveBFrameCount = FFMAX(ctx->base.b_per_p - 1, 0), + .subLayerCount = 0, + }; + rc_info->pNext = &hp->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; + + hp->vkrc_layer_info = (VkVideoEncodeH265RateControlLayerInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_KHR, + + .useMinQp = avctx->qmin > 0, + .minQp.qpI = avctx->qmin > 0 ? avctx->qmin : 0, + .minQp.qpP = avctx->qmin > 0 ? avctx->qmin : 0, + .minQp.qpB = avctx->qmin > 0 ? avctx->qmin : 0, + + .useMaxQp = avctx->qmax > 0, + .maxQp.qpI = avctx->qmax > 0 ? avctx->qmax : 0, + .maxQp.qpP = avctx->qmax > 0 ? avctx->qmax : 0, + .maxQp.qpB = avctx->qmax > 0 ? avctx->qmax : 0, + + .useMaxFrameSize = 0, + }; + rc_layer->pNext = &hp->vkrc_layer_info; + hp->vkrc_info.subLayerCount = 1; + } + + return 0; +} + +static int vk_enc_h265_update_pic_info(AVCodecContext *avctx, + FFHWBaseEncodePicture *pic) +{ + VulkanEncodeH265Context *enc = avctx->priv_data; + VulkanEncodeH265Picture *hp = pic->codec_priv; + FFHWBaseEncodePicture *prev = pic->prev; + VulkanEncodeH265Picture *hprev = prev ? prev->codec_priv : NULL; + + if (pic->type == FF_HW_PICTURE_TYPE_IDR) { + av_assert0(pic->display_order == pic->encode_order); + + hp->last_idr_frame = pic->display_order; + + hp->slice_type = STD_VIDEO_H265_SLICE_TYPE_I; + hp->pic_type = STD_VIDEO_H265_PICTURE_TYPE_IDR; + } else { + av_assert0(prev); + hp->last_idr_frame = hprev->last_idr_frame; + + if (pic->type == FF_HW_PICTURE_TYPE_I) { + hp->slice_type = STD_VIDEO_H265_SLICE_TYPE_I; + hp->pic_type = STD_VIDEO_H265_PICTURE_TYPE_I; + } else if (pic->type == FF_HW_PICTURE_TYPE_P) { + av_assert0(pic->refs[0]); + hp->slice_type = STD_VIDEO_H265_SLICE_TYPE_P; + hp->pic_type = STD_VIDEO_H265_PICTURE_TYPE_P; + } else { + FFHWBaseEncodePicture *irap_ref; + av_assert0(pic->refs[0][0] && pic->refs[1][0]); + for (irap_ref = pic; irap_ref; irap_ref = irap_ref->refs[1][0]) { + if (irap_ref->type == FF_HW_PICTURE_TYPE_I) + break; + } + hp->slice_type = STD_VIDEO_H265_SLICE_TYPE_B; + hp->pic_type = STD_VIDEO_H265_PICTURE_TYPE_B; + } + } + hp->pic_order_cnt = pic->display_order - hp->last_idr_frame; + + hp->units_needed = 0; + + if (enc->unit_elems & UNIT_AUD) { + hp->units_needed |= UNIT_AUD; + enc->raw_aud = (H265RawAUD) { + .nal_unit_header = { + .nal_unit_type = HEVC_NAL_AUD, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }, + .pic_type = hp->pic_type, + }; + } + + // 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 + // 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)) { + AVFrameSideData *sd = + av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + + if (sd) { + AVMasteringDisplayMetadata *mdm = (AVMasteringDisplayMetadata *)sd->data; + + // SEI is needed when both the primaries and luminance are set + if (mdm->has_primaries && mdm->has_luminance) { + SEIRawMasteringDisplayColourVolume *mdcv = + &enc->sei_mastering_display; + const int mapping[3] = {1, 2, 0}; + const int chroma_den = 50000; + const int luma_den = 10000; + + for (int i = 0; i < 3; i++) { + const int j = mapping[i]; + mdcv->display_primaries_x[i] = + FFMIN(lrint(chroma_den * + av_q2d(mdm->display_primaries[j][0])), + chroma_den); + mdcv->display_primaries_y[i] = + FFMIN(lrint(chroma_den * + av_q2d(mdm->display_primaries[j][1])), + chroma_den); + } + + mdcv->white_point_x = + FFMIN(lrint(chroma_den * av_q2d(mdm->white_point[0])), + chroma_den); + mdcv->white_point_y = + FFMIN(lrint(chroma_den * av_q2d(mdm->white_point[1])), + chroma_den); + + mdcv->max_display_mastering_luminance = + lrint(luma_den * av_q2d(mdm->max_luminance)); + mdcv->min_display_mastering_luminance = + FFMIN(lrint(luma_den * av_q2d(mdm->min_luminance)), + mdcv->max_display_mastering_luminance); + + hp->units_needed |= UNIT_SEI_MASTERING_DISPLAY; + } + } + } + + if ((enc->unit_elems & UNIT_SEI_CONTENT_LIGHT_LEVEL) && + (pic->type == FF_HW_PICTURE_TYPE_I || pic->type == FF_HW_PICTURE_TYPE_IDR)) { + AVFrameSideData *sd = av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + + if (sd) { + AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data; + SEIRawContentLightLevelInfo *clli = &enc->sei_content_light_level; + + clli->max_content_light_level = FFMIN(clm->MaxCLL, 65535); + clli->max_pic_average_light_level = FFMIN(clm->MaxFALL, 65535); + + hp->units_needed |= UNIT_SEI_CONTENT_LIGHT_LEVEL; + } + } + + if (enc->unit_elems & UNIT_SEI_A53_CC) { + int err; + size_t sei_a53cc_len; + av_freep(&enc->sei_a53cc_data); + err = ff_alloc_a53_sei(pic->input_image, 0, &enc->sei_a53cc_data, &sei_a53cc_len); + if (err < 0) + return err; + if (enc->sei_a53cc_data != NULL) { + enc->sei_a53cc.itu_t_t35_country_code = 181; + enc->sei_a53cc.data = (uint8_t *)enc->sei_a53cc_data + 1; + enc->sei_a53cc.data_length = sei_a53cc_len - 1; + + hp->units_needed |= UNIT_SEI_A53_CC; + } + } + + return 0; +} + +static void setup_slices(AVCodecContext *avctx, + FFHWBaseEncodePicture *pic) +{ + VulkanEncodeH265Context *enc = avctx->priv_data; + VulkanEncodeH265Picture *hp = pic->codec_priv; + + hp->slice_wt = (StdVideoEncodeH265WeightTable) { + .flags = (StdVideoEncodeH265WeightTableFlags) { + .luma_weight_l0_flag = 0, + .chroma_weight_l0_flag = 0, + .luma_weight_l1_flag = 0, + .chroma_weight_l1_flag = 0, + }, + .luma_log2_weight_denom = 0, + .delta_chroma_log2_weight_denom = 0, + .delta_luma_weight_l0 = { 0 }, + .luma_offset_l0 = { 0 }, + .delta_chroma_weight_l0 = { { 0 } }, + .delta_chroma_offset_l0 = { { 0 } }, + .delta_luma_weight_l1 = { 0 }, + .luma_offset_l1 = { 0 }, + .delta_chroma_weight_l1 = { { 0 } }, + .delta_chroma_offset_l1 = { { 0 } }, + }; + + hp->slice_hdr = (StdVideoEncodeH265SliceSegmentHeader) { + .flags = (StdVideoEncodeH265SliceSegmentHeaderFlags) { + .first_slice_segment_in_pic_flag = 1, + .dependent_slice_segment_flag = 0, + .slice_sao_luma_flag = enc->units.raw_sps.sample_adaptive_offset_enabled_flag, + .slice_sao_chroma_flag = enc->units.raw_sps.sample_adaptive_offset_enabled_flag, + .num_ref_idx_active_override_flag = 0, + .mvd_l1_zero_flag = 0, + .cabac_init_flag = 0, + .cu_chroma_qp_offset_enabled_flag = 0, + .deblocking_filter_override_flag = 0, + .slice_deblocking_filter_disabled_flag = 0, + .collocated_from_l0_flag = 1, + .slice_loop_filter_across_slices_enabled_flag = 0, + /* Reserved */ + }, + .slice_type = hp->slice_type, + .slice_segment_address = 0, + .collocated_ref_idx = 0, + .MaxNumMergeCand = 5, + .slice_cb_qp_offset = 0, + .slice_cr_qp_offset = 0, + .slice_beta_offset_div2 = 0, + .slice_tc_offset_div2 = 0, + .slice_act_y_qp_offset = 0, + .slice_act_cb_qp_offset = 0, + .slice_act_cr_qp_offset = 0, + .slice_qp_delta = 0, /* Filled in below */ + /* Reserved */ + .pWeightTable = NULL, // &hp->slice_wt, + }; + + hp->vkslice = (VkVideoEncodeH265NaluSliceSegmentInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_INFO_KHR, + .pNext = NULL, + .constantQp = pic->type == FF_HW_PICTURE_TYPE_B ? enc->fixed_qp_b : + pic->type == FF_HW_PICTURE_TYPE_P ? enc->fixed_qp_p : + enc->fixed_qp_idr, + .pStdSliceSegmentHeader = &hp->slice_hdr, + }; + + if (enc->common.opts.rc_mode != VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR) + hp->vkslice.constantQp = 0; + + hp->slice_hdr.slice_qp_delta = hp->vkslice.constantQp - + (enc->units.raw_pps.init_qp_minus26 + 26); + + hp->vkh265pic_info.pNaluSliceSegmentEntries = &hp->vkslice; + hp->vkh265pic_info.naluSliceSegmentEntryCount = 1; +} + +static void setup_refs(AVCodecContext *avctx, + FFHWBaseEncodePicture *pic, + VkVideoEncodeInfoKHR *encode_info) +{ + int i, j; + VulkanEncodeH265Context *enc = avctx->priv_data; + VulkanEncodeH265Picture *hp = pic->codec_priv; + + hp->ref_list_info = (StdVideoEncodeH265ReferenceListsInfo) { + .flags = (StdVideoEncodeH265ReferenceListsInfoFlags) { + .ref_pic_list_modification_flag_l0 = 0, + .ref_pic_list_modification_flag_l1 = 0, + /* Reserved */ + }, + /* May be overridden during setup_slices() */ + .num_ref_idx_l0_active_minus1 = pic->nb_refs[0] - 1, + .num_ref_idx_l1_active_minus1 = pic->nb_refs[1] - 1, + /* Reserved */ + .list_entry_l0 = { 0 }, + .list_entry_l1 = { 0 }, + }; + + for (i = 0; i < STD_VIDEO_H265_MAX_NUM_LIST_REF; i++) + hp->ref_list_info.RefPicList0[i] = hp->ref_list_info.RefPicList1[i] = -1; + + /* Note: really not sure */ + for (i = 0; i < pic->nb_refs[0]; i++) { + VkVideoReferenceSlotInfoKHR *slot_info; + slot_info = (VkVideoReferenceSlotInfoKHR *)&encode_info->pReferenceSlots[i]; + hp->ref_list_info.RefPicList0[i] = slot_info->slotIndex; + } + + /* Note: really not sure */ + for (i = 0; i < pic->nb_refs[1]; i++) { + VkVideoReferenceSlotInfoKHR *slot_info; + slot_info = (VkVideoReferenceSlotInfoKHR *)&encode_info->pReferenceSlots[pic->nb_refs[0] + i]; + hp->ref_list_info.RefPicList1[i] = slot_info->slotIndex; + } + + hp->h265pic_info.pRefLists = &hp->ref_list_info; + + if (pic->type != FF_HW_PICTURE_TYPE_IDR) { + StdVideoH265ShortTermRefPicSet *rps; + VulkanEncodeH265Picture *strp; + int rps_poc[MAX_DPB_SIZE]; + int rps_used[MAX_DPB_SIZE]; + int poc, rps_pics; + + hp->h265pic_info.flags.short_term_ref_pic_set_sps_flag = 0; + + rps = &hp->s_rps; + memset(rps, 0, sizeof(*rps)); + + rps_pics = 0; + for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) { + for (j = 0; j < pic->nb_refs[i]; j++) { + strp = pic->refs[i][j]->codec_priv; + rps_poc[rps_pics] = strp->pic_order_cnt; + rps_used[rps_pics] = 1; + ++rps_pics; + } + } + + for (i = 0; i < pic->nb_dpb_pics; i++) { + if (pic->dpb[i] == pic) + continue; + + for (j = 0; j < pic->nb_refs[0]; j++) { + if (pic->dpb[i] == pic->refs[0][j]) + break; + } + if (j < pic->nb_refs[0]) + continue; + + for (j = 0; j < pic->nb_refs[1]; j++) { + if (pic->dpb[i] == pic->refs[1][j]) + break; + } + if (j < pic->nb_refs[1]) + continue; + + strp = pic->dpb[i]->codec_priv; + rps_poc[rps_pics] = strp->pic_order_cnt; + rps_used[rps_pics] = 0; + ++rps_pics; + } + + for (i = 1; i < rps_pics; i++) { + for (j = i; j > 0; j--) { + if (rps_poc[j] > rps_poc[j - 1]) + break; + av_assert0(rps_poc[j] != rps_poc[j - 1]); + FFSWAP(int, rps_poc[j], rps_poc[j - 1]); + FFSWAP(int, rps_used[j], rps_used[j - 1]); + } + } + + av_log(avctx, AV_LOG_DEBUG, "RPS for POC %d:", hp->pic_order_cnt); + for (i = 0; i < rps_pics; i++) + av_log(avctx, AV_LOG_DEBUG, " (%d,%d)", rps_poc[i], rps_used[i]); + + av_log(avctx, AV_LOG_DEBUG, "\n"); + + for (i = 0; i < rps_pics; i++) { + av_assert0(rps_poc[i] != hp->pic_order_cnt); + if (rps_poc[i] > hp->pic_order_cnt) + break; + } + + rps->num_negative_pics = i; + rps->used_by_curr_pic_s0_flag = 0x0; + poc = hp->pic_order_cnt; + for (j = i - 1; j >= 0; j--) { + rps->delta_poc_s0_minus1[i - 1 - j] = poc - rps_poc[j] - 1; + rps->used_by_curr_pic_s0_flag |= rps_used[j] << (i - 1 - j); + poc = rps_poc[j]; + } + + rps->num_positive_pics = rps_pics - i; + rps->used_by_curr_pic_s1_flag = 0x0; + poc = hp->pic_order_cnt; + for (j = i; j < rps_pics; j++) { + rps->delta_poc_s1_minus1[j - i] = rps_poc[j] - poc - 1; + rps->used_by_curr_pic_s1_flag |= rps_used[j] << (j - i); + poc = rps_poc[j]; + } + + hp->l_rps.num_long_term_sps = 0; + hp->l_rps.num_long_term_pics = 0; + + // when this flag is not present, it is inerred to 1. + hp->slice_hdr.flags.collocated_from_l0_flag = 1; + hp->h265pic_info.flags.slice_temporal_mvp_enabled_flag = + enc->units.raw_sps.sps_temporal_mvp_enabled_flag; + if (hp->h265pic_info.flags.slice_temporal_mvp_enabled_flag) { + if (hp->slice_hdr.slice_type == STD_VIDEO_H265_SLICE_TYPE_B) + hp->slice_hdr.flags.collocated_from_l0_flag = 1; + hp->slice_hdr.collocated_ref_idx = 0; + } + + hp->slice_hdr.flags.num_ref_idx_active_override_flag = 0; + hp->ref_list_info.num_ref_idx_l0_active_minus1 = enc->units.raw_pps.num_ref_idx_l0_default_active_minus1; + hp->ref_list_info.num_ref_idx_l1_active_minus1 = enc->units.raw_pps.num_ref_idx_l1_default_active_minus1; + } + + hp->h265pic_info.pShortTermRefPicSet = &hp->s_rps; + hp->h265pic_info.pLongTermRefPics = &hp->l_rps; +} + +static int init_pic_params(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, + VkVideoEncodeInfoKHR *encode_info) +{ + int err; + VulkanEncodeH265Context *enc = avctx->priv_data; + FFVulkanEncodePicture *vp = pic->priv; + VulkanEncodeH265Picture *hp = pic->codec_priv; + VkVideoReferenceSlotInfoKHR *ref_slot; + + err = vk_enc_h265_update_pic_info(avctx, pic); + if (err < 0) + return err; + + hp->vkh265pic_info = (VkVideoEncodeH265PictureInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PICTURE_INFO_KHR, + .pNext = NULL, + .pNaluSliceSegmentEntries = NULL, // Filled in during setup_slices() + .naluSliceSegmentEntryCount = 0, // Filled in during setup_slices() + .pStdPictureInfo = &hp->h265pic_info, + }; + + hp->h265pic_info = (StdVideoEncodeH265PictureInfo) { + .flags = (StdVideoEncodeH265PictureInfoFlags) { + .is_reference = pic->is_reference, + .IrapPicFlag = pic->type == FF_HW_PICTURE_TYPE_IDR, + .used_for_long_term_reference = 0, + .discardable_flag = 0, + .cross_layer_bla_flag = 0, + .pic_output_flag = 1, + .no_output_of_prior_pics_flag = 0, + .short_term_ref_pic_set_sps_flag = 0, + .slice_temporal_mvp_enabled_flag = enc->units.raw_sps.sps_temporal_mvp_enabled_flag, + /* Reserved */ + }, + .pic_type = hp->pic_type, + .sps_video_parameter_set_id = 0, + .pps_seq_parameter_set_id = 0, + .pps_pic_parameter_set_id = 0, + .short_term_ref_pic_set_idx = 0, + .PicOrderCntVal = hp->pic_order_cnt, + .TemporalId = 0, + /* Reserved */ + .pRefLists = NULL, // Filled in during setup_refs + .pShortTermRefPicSet = NULL, + .pLongTermRefPics = NULL, + }; + encode_info->pNext = &hp->vkh265pic_info; + + hp->h265dpb_info = (StdVideoEncodeH265ReferenceInfo) { + .flags = (StdVideoEncodeH265ReferenceInfoFlags) { + .used_for_long_term_reference = 0, + .unused_for_reference = 0, + /* Reserved */ + }, + .pic_type = hp->h265pic_info.pic_type, + .PicOrderCntVal = hp->h265pic_info.PicOrderCntVal, + .TemporalId = hp->h265pic_info.TemporalId, + }; + hp->vkh265dpb_info = (VkVideoEncodeH265DpbSlotInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_KHR, + .pStdReferenceInfo = &hp->h265dpb_info, + }; + + vp->dpb_slot.pNext = &hp->vkh265dpb_info; + + ref_slot = (VkVideoReferenceSlotInfoKHR *)encode_info->pSetupReferenceSlot; + ref_slot->pNext = &hp->vkh265dpb_info; + + setup_refs(avctx, pic, encode_info); + + setup_slices(avctx, pic); + + return 0; +} + +static int init_profile(AVCodecContext *avctx, + VkVideoProfileInfoKHR *profile, void *pnext) +{ + VkResult ret; + VulkanEncodeH265Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + VkVideoEncodeH265CapabilitiesKHR h265_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_KHR, + }; + VkVideoEncodeCapabilitiesKHR enc_caps = { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR, + .pNext = &h265_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_HEVC_MAIN, + AV_PROFILE_HEVC_MAIN_10, + AV_PROFILE_HEVC_REXT, + }; + 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) + nb_profiles = 1; + else if (s->frames->sw_format == AV_PIX_FMT_P010) + nb_profiles = 2; + + enc->profile = (VkVideoEncodeH265ProfileInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_KHR, + .pNext = pnext, + .stdProfileIdc = ff_vk_h265_profile_to_vk(avctx->profile), + }; + profile->pNext = &enc->profile; + + /* Set level */ + if (avctx->level == AV_LEVEL_UNKNOWN) + avctx->level = enc->common.opts.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.stdProfileIdc = ff_vk_h265_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.stdProfileIdc = ff_vk_h265_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) +{ + VulkanEncodeH265Context *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->fixed_qp_p = av_clip(enc->common.opts.qp, + enc->caps.minQp, enc->caps.maxQp); + + if (avctx->i_quant_factor > 0.0) + enc->fixed_qp_idr = av_clip((avctx->i_quant_factor * enc->fixed_qp_p + + avctx->i_quant_offset) + 0.5, + enc->caps.minQp, enc->caps.maxQp); + else + enc->fixed_qp_idr = enc->fixed_qp_p; + + if (avctx->b_quant_factor > 0.0) + enc->fixed_qp_b = av_clip((avctx->b_quant_factor * enc->fixed_qp_p + + avctx->b_quant_offset) + 0.5, + enc->caps.minQp, enc->caps.maxQp); + else + enc->fixed_qp_b = enc->fixed_qp_p; + + av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " + "%d / %d / %d for IDR- / P- / B-frames.\n", + enc->fixed_qp_idr, enc->fixed_qp_p, enc->fixed_qp_b); + } else { + enc->fixed_qp_idr = 26; + enc->fixed_qp_p = 26; + enc->fixed_qp_b = 26; + } + + return 0; +} + +static av_cold int init_sequence_headers(AVCodecContext *avctx) +{ + int err; + VulkanEncodeH265Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + + FFHWBaseEncodeH265 *units = &enc->units; + FFHWBaseEncodeH265Opts *unit_opts = &enc->unit_opts; + + int max_ctb_size; + unsigned min_tb_size; + unsigned max_tb_size; + unsigned max_transform_hierarchy; + + unit_opts->tier = enc->common.opts.tier; + unit_opts->fixed_qp_idr = enc->fixed_qp_idr; + unit_opts->cu_qp_delta_enabled_flag = enc->common.opts.rc_mode != VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DISABLED_BIT_KHR; + + unit_opts->nb_slices = 1; + + unit_opts->slice_block_rows = (avctx->height + base_ctx->slice_block_height - 1) / + base_ctx->slice_block_height; + unit_opts->slice_block_cols = (avctx->width + base_ctx->slice_block_width - 1) / + base_ctx->slice_block_width; + + /* cabac already set via an option */ + /* fixed_qp_idr initialized in init_enc_options() */ + /* hrd_buffer_size initialized in init_enc_options() */ + /* initial_buffer_fullness initialized in init_enc_options() */ + + err = ff_hw_base_encode_init_params_h265(&enc->common.base, avctx, + units, unit_opts); + if (err < 0) + return err; + + units->raw_sps.sample_adaptive_offset_enabled_flag = + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG_SET_BIT_KHR); + units->raw_pps.transform_skip_enabled_flag = + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_SET_BIT_KHR); + + max_ctb_size = 16; + + /* coding blocks from 8x8 to max CTB size. */ + if (enc->caps.ctbSizes & VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_KHR) + max_ctb_size = 64; + else if (enc->caps.ctbSizes & VK_VIDEO_ENCODE_H265_CTB_SIZE_32_BIT_KHR) + max_ctb_size = 32; + + min_tb_size = 0; + max_tb_size = 0; + if (enc->caps.transformBlockSizes & VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_4_BIT_KHR) + min_tb_size = 4; + else if (enc->caps.transformBlockSizes & VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_8_BIT_KHR) + min_tb_size = 8; + else if (enc->caps.transformBlockSizes & VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_16_BIT_KHR) + min_tb_size = 16; + else if (enc->caps.transformBlockSizes & VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_32_BIT_KHR) + min_tb_size = 32; + + if (enc->caps.transformBlockSizes & VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_32_BIT_KHR) + max_tb_size = 32; + else if (enc->caps.transformBlockSizes & VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_16_BIT_KHR) + max_tb_size = 16; + else if (enc->caps.transformBlockSizes & VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_8_BIT_KHR) + max_tb_size = 8; + else if (enc->caps.transformBlockSizes & VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_4_BIT_KHR) + max_tb_size = 4; + + units->raw_sps.log2_min_luma_coding_block_size_minus3 = 0; + units->raw_sps.log2_diff_max_min_luma_coding_block_size = av_log2(max_ctb_size) - 3; + units->raw_sps.log2_min_luma_transform_block_size_minus2 = av_log2(min_tb_size) - 2; + units->raw_sps.log2_diff_max_min_luma_transform_block_size = av_log2(max_tb_size) - av_log2(min_tb_size); + + max_transform_hierarchy = av_log2(max_ctb_size) - av_log2(min_tb_size); + units->raw_sps.max_transform_hierarchy_depth_intra = max_transform_hierarchy; + units->raw_sps.max_transform_hierarchy_depth_intra = max_transform_hierarchy; + + units->raw_sps.vui.bitstream_restriction_flag = 0; + units->raw_sps.vui.max_bytes_per_pic_denom = 2; + units->raw_sps.vui.max_bits_per_min_cu_denom = 1; + + units->raw_sps.sps_temporal_mvp_enabled_flag = 0; + + if (base_ctx->gop_size & base_ctx->gop_size - 1 == 0) + units->raw_sps.log2_max_pic_order_cnt_lsb_minus4 = FFMAX(av_log2(base_ctx->gop_size) - 4, 0); + else + units->raw_sps.log2_max_pic_order_cnt_lsb_minus4 = FFMAX(av_log2(base_ctx->gop_size) - 3, 0); + + return 0; +} + +typedef struct VulkanH265Units { + StdVideoH265SequenceParameterSet sps; + StdVideoH265ShortTermRefPicSet str[STD_VIDEO_H265_SUBLAYERS_LIST_SIZE]; + StdVideoH265LongTermRefPicsSps ltr; + StdVideoH265ProfileTierLevel ptl_sps; + StdVideoH265DecPicBufMgr dpbm_sps; + + StdVideoH265HrdParameters vui_header_sps; + StdVideoH265SequenceParameterSetVui vui_sps; + + StdVideoH265SubLayerHrdParameters slhdrnal[HEVC_MAX_SUB_LAYERS]; + StdVideoH265SubLayerHrdParameters slhdrvcl[HEVC_MAX_SUB_LAYERS]; + + StdVideoH265PictureParameterSet pps; + StdVideoH265ScalingLists pps_scaling; + + StdVideoH265VideoParameterSet vps; + StdVideoH265ProfileTierLevel ptl_vps; + StdVideoH265DecPicBufMgr dpbm_vps; + StdVideoH265HrdParameters vui_header_vps; +} VulkanH265Units; + +static av_cold int base_unit_to_vk(AVCodecContext *avctx, + VulkanH265Units *vk_units) +{ + VulkanEncodeH265Context *enc = avctx->priv_data; + + H265RawSPS *sps = &enc->units.raw_sps; + StdVideoH265SequenceParameterSet *vksps = &vk_units->sps; + StdVideoH265ShortTermRefPicSet *str = vk_units->str; + StdVideoH265LongTermRefPicsSps *ltr = &vk_units->ltr; + StdVideoH265ProfileTierLevel *ptl_sps = &vk_units->ptl_sps; + StdVideoH265DecPicBufMgr *dpbm_sps = &vk_units->dpbm_sps; + + StdVideoH265HrdParameters *vui_header_sps = &vk_units->vui_header_sps; + StdVideoH265SequenceParameterSetVui *vui_sps = &vk_units->vui_sps; + + StdVideoH265SubLayerHrdParameters *slhdrnal = vk_units->slhdrnal; + StdVideoH265SubLayerHrdParameters *slhdrvcl = vk_units->slhdrvcl; + + H265RawPPS *pps = &enc->units.raw_pps; + StdVideoH265PictureParameterSet *vkpps = &vk_units->pps; + + H265RawVPS *vps = &enc->units.raw_vps; + StdVideoH265VideoParameterSet *vkvps = &vk_units->vps; + StdVideoH265ProfileTierLevel *ptl_vps = &vk_units->ptl_vps; + StdVideoH265DecPicBufMgr *dpbm_vps = &vk_units->dpbm_vps; + StdVideoH265HrdParameters *vui_header_vps = &vk_units->vui_header_vps; + + /* SPS */ + for (int i = 0; i < HEVC_MAX_SUB_LAYERS; i++) { + memcpy(&slhdrnal[i], &sps->vui.hrd_parameters.nal_sub_layer_hrd_parameters[i], sizeof(*slhdrnal)); + memcpy(&slhdrvcl[i], &sps->vui.hrd_parameters.vcl_sub_layer_hrd_parameters[i], sizeof(*slhdrvcl)); + slhdrnal[i].cbr_flag = 0x0; + slhdrvcl[i].cbr_flag = 0x0; + for (int j = 0; j < HEVC_MAX_CPB_CNT; j++) { + slhdrnal[i].cbr_flag |= sps->vui.hrd_parameters.nal_sub_layer_hrd_parameters[i].cbr_flag[j] << i; + slhdrvcl[i].cbr_flag |= sps->vui.hrd_parameters.vcl_sub_layer_hrd_parameters[i].cbr_flag[j] << i; + } + } + + *vui_header_sps = (StdVideoH265HrdParameters) { + .flags = (StdVideoH265HrdFlags) { + .nal_hrd_parameters_present_flag = sps->vui.hrd_parameters.nal_hrd_parameters_present_flag, + .vcl_hrd_parameters_present_flag = sps->vui.hrd_parameters.vcl_hrd_parameters_present_flag, + .sub_pic_hrd_params_present_flag = sps->vui.hrd_parameters.sub_pic_hrd_params_present_flag, + .sub_pic_cpb_params_in_pic_timing_sei_flag = sps->vui.hrd_parameters.sub_pic_cpb_params_in_pic_timing_sei_flag, + .fixed_pic_rate_general_flag = 0x0, + .fixed_pic_rate_within_cvs_flag = 0x0, + .low_delay_hrd_flag = 0x0, + }, + .tick_divisor_minus2 = sps->vui.hrd_parameters.tick_divisor_minus2, + .du_cpb_removal_delay_increment_length_minus1 = sps->vui.hrd_parameters.du_cpb_removal_delay_increment_length_minus1, + .dpb_output_delay_du_length_minus1 = sps->vui.hrd_parameters.dpb_output_delay_du_length_minus1, + .bit_rate_scale = sps->vui.hrd_parameters.bit_rate_scale, + .cpb_size_scale = sps->vui.hrd_parameters.cpb_size_scale, + .cpb_size_du_scale = sps->vui.hrd_parameters.cpb_size_du_scale, + .initial_cpb_removal_delay_length_minus1 = sps->vui.hrd_parameters.initial_cpb_removal_delay_length_minus1, + .au_cpb_removal_delay_length_minus1 = sps->vui.hrd_parameters.au_cpb_removal_delay_length_minus1, + .dpb_output_delay_length_minus1 = sps->vui.hrd_parameters.dpb_output_delay_length_minus1, + /* Reserved - 3*16 bits */ + .pSubLayerHrdParametersNal = slhdrnal, + .pSubLayerHrdParametersVcl = slhdrvcl, + }; + + for (int i = 0; i < HEVC_MAX_SUB_LAYERS; i++) { + vui_header_sps->flags.fixed_pic_rate_general_flag |= sps->vui.hrd_parameters.fixed_pic_rate_general_flag[i] << i; + vui_header_sps->flags.fixed_pic_rate_within_cvs_flag |= sps->vui.hrd_parameters.fixed_pic_rate_within_cvs_flag[i] << i; + vui_header_sps->flags.low_delay_hrd_flag |= sps->vui.hrd_parameters.low_delay_hrd_flag[i] << i; + } + + for (int i = 0; i < STD_VIDEO_H265_SUBLAYERS_LIST_SIZE; i++) { + dpbm_sps->max_latency_increase_plus1[i] = sps->sps_max_latency_increase_plus1[i]; + dpbm_sps->max_dec_pic_buffering_minus1[i] = sps->sps_max_dec_pic_buffering_minus1[i]; + dpbm_sps->max_num_reorder_pics[i] = sps->sps_max_num_reorder_pics[i]; + } + + *ptl_sps = (StdVideoH265ProfileTierLevel) { + .flags = (StdVideoH265ProfileTierLevelFlags) { + .general_tier_flag = sps->profile_tier_level.general_tier_flag, + .general_progressive_source_flag = sps->profile_tier_level.general_progressive_source_flag, + .general_interlaced_source_flag = sps->profile_tier_level.general_interlaced_source_flag, + .general_non_packed_constraint_flag = sps->profile_tier_level.general_non_packed_constraint_flag, + .general_frame_only_constraint_flag = sps->profile_tier_level.general_frame_only_constraint_flag, + }, + .general_profile_idc = ff_vk_h265_profile_to_vk(sps->profile_tier_level.general_profile_idc), + .general_level_idc = ff_vk_h265_level_to_vk(sps->profile_tier_level.general_level_idc), + }; + + for (int i = 0; i < STD_VIDEO_H265_MAX_SHORT_TERM_REF_PIC_SETS; i++) { + const H265RawSTRefPicSet *st_rps = &sps->st_ref_pic_set[i]; + + str[i] = (StdVideoH265ShortTermRefPicSet) { + .flags = (StdVideoH265ShortTermRefPicSetFlags) { + .inter_ref_pic_set_prediction_flag = st_rps->inter_ref_pic_set_prediction_flag, + .delta_rps_sign = st_rps->delta_rps_sign, + }, + .delta_idx_minus1 = st_rps->delta_idx_minus1, + .use_delta_flag = 0x0, + .abs_delta_rps_minus1 = st_rps->abs_delta_rps_minus1, + .used_by_curr_pic_flag = 0x0, + .used_by_curr_pic_s0_flag = 0x0, + .used_by_curr_pic_s1_flag = 0x0, + /* Reserved */ + /* Reserved */ + /* Reserved */ + .num_negative_pics = st_rps->num_negative_pics, + .num_positive_pics = st_rps->num_positive_pics, + }; + + for (int j = 0; j < HEVC_MAX_REFS; j++) { + str[i].use_delta_flag |= st_rps->use_delta_flag[j] << i; + str[i].used_by_curr_pic_flag |= st_rps->used_by_curr_pic_flag[j] << i; + str[i].used_by_curr_pic_s0_flag |= st_rps->used_by_curr_pic_s0_flag[j] << i; + str[i].used_by_curr_pic_s1_flag |= st_rps->used_by_curr_pic_s1_flag[j] << i; + str[i].delta_poc_s0_minus1[j] = st_rps->delta_poc_s0_minus1[j]; + str[i].delta_poc_s1_minus1[j] = st_rps->delta_poc_s1_minus1[j]; + } + } + + ltr->used_by_curr_pic_lt_sps_flag = 0; + for (int i = 0; i < STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS; i++) { + ltr->used_by_curr_pic_lt_sps_flag |= sps->lt_ref_pic_poc_lsb_sps[i] << i; + ltr->lt_ref_pic_poc_lsb_sps[i] = sps->lt_ref_pic_poc_lsb_sps[i]; + } + + *vksps = (StdVideoH265SequenceParameterSet) { + .flags = (StdVideoH265SpsFlags) { + .sps_temporal_id_nesting_flag = sps->sps_temporal_id_nesting_flag, + .separate_colour_plane_flag = sps->separate_colour_plane_flag, + .conformance_window_flag = sps->conformance_window_flag, + .sps_sub_layer_ordering_info_present_flag = sps->sps_sub_layer_ordering_info_present_flag, + .scaling_list_enabled_flag = sps->scaling_list_enabled_flag, + .sps_scaling_list_data_present_flag = sps->sps_scaling_list_data_present_flag, + .amp_enabled_flag = sps->amp_enabled_flag, + .sample_adaptive_offset_enabled_flag = sps->sample_adaptive_offset_enabled_flag, + .pcm_enabled_flag = sps->pcm_enabled_flag, + .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag, + .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag, + .sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag, + .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled_flag, + .vui_parameters_present_flag = sps->vui_parameters_present_flag, + .sps_extension_present_flag = sps->sps_extension_present_flag, + .sps_range_extension_flag = sps->sps_range_extension_flag, + .transform_skip_rotation_enabled_flag = sps->transform_skip_rotation_enabled_flag, + .transform_skip_context_enabled_flag = sps->transform_skip_context_enabled_flag, + .implicit_rdpcm_enabled_flag = sps->implicit_rdpcm_enabled_flag, + .explicit_rdpcm_enabled_flag = sps->explicit_rdpcm_enabled_flag, + .extended_precision_processing_flag = sps->extended_precision_processing_flag, + .intra_smoothing_disabled_flag = sps->intra_smoothing_disabled_flag, + .high_precision_offsets_enabled_flag = sps->high_precision_offsets_enabled_flag, + .persistent_rice_adaptation_enabled_flag = sps->persistent_rice_adaptation_enabled_flag, + .cabac_bypass_alignment_enabled_flag = sps->cabac_bypass_alignment_enabled_flag, + .sps_scc_extension_flag = sps->sps_scc_extension_flag, + .sps_curr_pic_ref_enabled_flag = sps->sps_curr_pic_ref_enabled_flag, + .palette_mode_enabled_flag = sps->palette_mode_enabled_flag, + .sps_palette_predictor_initializers_present_flag = sps->sps_palette_predictor_initializer_present_flag, + .intra_boundary_filtering_disabled_flag = sps->intra_boundary_filtering_disable_flag, + }, + .chroma_format_idc = sps->chroma_format_idc, + .pic_width_in_luma_samples = sps->pic_width_in_luma_samples, + .pic_height_in_luma_samples = sps->pic_height_in_luma_samples, + .sps_video_parameter_set_id = sps->sps_video_parameter_set_id, + .sps_max_sub_layers_minus1 = sps->sps_max_sub_layers_minus1, + .sps_seq_parameter_set_id = sps->sps_seq_parameter_set_id, + .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8, + .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8, + .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4, + .log2_min_luma_coding_block_size_minus3 = sps->log2_min_luma_coding_block_size_minus3, + .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size, + .log2_min_luma_transform_block_size_minus2 = sps->log2_min_luma_transform_block_size_minus2, + .log2_diff_max_min_luma_transform_block_size = sps->log2_diff_max_min_luma_transform_block_size, + .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter, + .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra, + .num_short_term_ref_pic_sets = sps->num_short_term_ref_pic_sets, + .num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps, + .pcm_sample_bit_depth_luma_minus1 = sps->pcm_sample_bit_depth_luma_minus1, + .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_sample_bit_depth_chroma_minus1, + .log2_min_pcm_luma_coding_block_size_minus3 = sps->log2_min_pcm_luma_coding_block_size_minus3, + .log2_diff_max_min_pcm_luma_coding_block_size = sps->log2_diff_max_min_pcm_luma_coding_block_size, + /* Reserved */ + /* Reserved */ + .palette_max_size = sps->palette_max_size, + .delta_palette_max_predictor_size = sps->delta_palette_max_predictor_size, + .motion_vector_resolution_control_idc = sps->motion_vector_resolution_control_idc, + .sps_num_palette_predictor_initializers_minus1 = sps->sps_num_palette_predictor_initializer_minus1, + .conf_win_left_offset = sps->conf_win_left_offset, + .conf_win_right_offset = sps->conf_win_right_offset, + .conf_win_top_offset = sps->conf_win_top_offset, + .conf_win_bottom_offset = sps->conf_win_bottom_offset, + .pProfileTierLevel = ptl_sps, + .pDecPicBufMgr = dpbm_sps, + .pScalingLists = NULL, + .pShortTermRefPicSet = str, + .pLongTermRefPicsSps = ltr, + .pSequenceParameterSetVui = vui_sps, + .pPredictorPaletteEntries = NULL, + }; + + /* PPS */ + *vkpps = (StdVideoH265PictureParameterSet) { + .flags = (StdVideoH265PpsFlags) { + .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag, + .output_flag_present_flag = pps->output_flag_present_flag, + .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag, + .cabac_init_present_flag = pps->cabac_init_present_flag, + .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, + .transform_skip_enabled_flag = pps->transform_skip_enabled_flag, + .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag, + .pps_slice_chroma_qp_offsets_present_flag = pps->pps_slice_chroma_qp_offsets_present_flag, + .weighted_pred_flag = pps->weighted_pred_flag, + .weighted_bipred_flag = pps->weighted_bipred_flag, + .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag, + .tiles_enabled_flag = pps->tiles_enabled_flag, + .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag, + .uniform_spacing_flag = pps->uniform_spacing_flag, + .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag, + .pps_loop_filter_across_slices_enabled_flag = pps->pps_loop_filter_across_slices_enabled_flag, + .deblocking_filter_control_present_flag = pps->deblocking_filter_control_present_flag, + .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag, + .pps_deblocking_filter_disabled_flag = pps->pps_deblocking_filter_disabled_flag, + .pps_scaling_list_data_present_flag = pps->pps_scaling_list_data_present_flag, + .lists_modification_present_flag = pps->lists_modification_present_flag, + .slice_segment_header_extension_present_flag = pps->slice_segment_header_extension_present_flag, + .pps_extension_present_flag = pps->pps_extension_present_flag, + .cross_component_prediction_enabled_flag = pps->cross_component_prediction_enabled_flag, + .chroma_qp_offset_list_enabled_flag = pps->chroma_qp_offset_list_enabled_flag, + .pps_curr_pic_ref_enabled_flag = pps->pps_curr_pic_ref_enabled_flag, + .residual_adaptive_colour_transform_enabled_flag = pps->residual_adaptive_colour_transform_enabled_flag, + .pps_slice_act_qp_offsets_present_flag = pps->pps_slice_act_qp_offsets_present_flag, + .pps_palette_predictor_initializers_present_flag = pps->pps_palette_predictor_initializer_present_flag, + .monochrome_palette_flag = pps->monochrome_palette_flag, + .pps_range_extension_flag = pps->pps_range_extension_flag, + }, + .pps_pic_parameter_set_id = pps->pps_pic_parameter_set_id, + .pps_seq_parameter_set_id = pps->pps_seq_parameter_set_id, + .sps_video_parameter_set_id = sps->sps_video_parameter_set_id, + .num_extra_slice_header_bits = pps->num_extra_slice_header_bits, + .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active_minus1, + .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active_minus1, + .init_qp_minus26 = pps->init_qp_minus26, + .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth, + .pps_cb_qp_offset = pps->pps_cb_qp_offset, + .pps_cr_qp_offset = pps->pps_cr_qp_offset, + .pps_beta_offset_div2 = pps->pps_beta_offset_div2, + .pps_tc_offset_div2 = pps->pps_tc_offset_div2, + .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2, + .log2_max_transform_skip_block_size_minus2 = pps->log2_max_transform_skip_block_size_minus2, + .diff_cu_chroma_qp_offset_depth = pps->diff_cu_chroma_qp_offset_depth, + .chroma_qp_offset_list_len_minus1 = pps->chroma_qp_offset_list_len_minus1, + .log2_sao_offset_scale_luma = pps->log2_sao_offset_scale_luma, + .log2_sao_offset_scale_chroma = pps->log2_sao_offset_scale_chroma, + .pps_act_y_qp_offset_plus5 = pps->pps_act_y_qp_offset_plus5, + .pps_act_cb_qp_offset_plus5 = pps->pps_act_cb_qp_offset_plus5, + .pps_act_cr_qp_offset_plus3 = pps->pps_act_cr_qp_offset_plus3, + .pps_num_palette_predictor_initializers = pps->pps_num_palette_predictor_initializer, + .luma_bit_depth_entry_minus8 = pps->luma_bit_depth_entry_minus8, + .chroma_bit_depth_entry_minus8 = pps->chroma_bit_depth_entry_minus8, + .num_tile_columns_minus1 = pps->num_tile_columns_minus1, + .num_tile_rows_minus1 = pps->num_tile_rows_minus1, + .pScalingLists = NULL, + .pPredictorPaletteEntries = NULL, + }; + + for (int i = 0; i < pps->num_tile_columns_minus1; i++) + vkpps->column_width_minus1[i] = pps->column_width_minus1[i]; + + for (int i = 0; i < pps->num_tile_rows_minus1; i++) + vkpps->row_height_minus1[i] = pps->row_height_minus1[i]; + + for (int i = 0; i <= pps->chroma_qp_offset_list_len_minus1; i++) { + vkpps->cb_qp_offset_list[i] = pps->cb_qp_offset_list[i]; + vkpps->cr_qp_offset_list[i] = pps->cr_qp_offset_list[i]; + } + + /* VPS */ + for (int i = 0; i < STD_VIDEO_H265_SUBLAYERS_LIST_SIZE; i++) { + dpbm_vps->max_latency_increase_plus1[i] = vps->vps_max_latency_increase_plus1[i]; + dpbm_vps->max_dec_pic_buffering_minus1[i] = vps->vps_max_dec_pic_buffering_minus1[i]; + dpbm_vps->max_num_reorder_pics[i] = vps->vps_max_num_reorder_pics[i]; + } + + *ptl_vps = (StdVideoH265ProfileTierLevel) { + .flags = (StdVideoH265ProfileTierLevelFlags) { + .general_tier_flag = vps->profile_tier_level.general_tier_flag, + .general_progressive_source_flag = vps->profile_tier_level.general_progressive_source_flag, + .general_interlaced_source_flag = vps->profile_tier_level.general_interlaced_source_flag, + .general_non_packed_constraint_flag = vps->profile_tier_level.general_non_packed_constraint_flag, + .general_frame_only_constraint_flag = vps->profile_tier_level.general_frame_only_constraint_flag, + }, + .general_profile_idc = ff_vk_h265_profile_to_vk(vps->profile_tier_level.general_profile_idc), + .general_level_idc = ff_vk_h265_level_to_vk(vps->profile_tier_level.general_level_idc), + }; + + *vkvps = (StdVideoH265VideoParameterSet) { + .flags = (StdVideoH265VpsFlags) { + .vps_temporal_id_nesting_flag = vps->vps_temporal_id_nesting_flag, + .vps_sub_layer_ordering_info_present_flag = vps->vps_sub_layer_ordering_info_present_flag, + .vps_timing_info_present_flag = vps->vps_timing_info_present_flag, + .vps_poc_proportional_to_timing_flag = vps->vps_poc_proportional_to_timing_flag, + }, + .vps_video_parameter_set_id = vps->vps_video_parameter_set_id, + .vps_max_sub_layers_minus1 = vps->vps_max_sub_layers_minus1, + /* Reserved */ + /* Reserved */ + .vps_num_units_in_tick = vps->vps_num_units_in_tick, + .vps_time_scale = vps->vps_time_scale, + .vps_num_ticks_poc_diff_one_minus1 = vps->vps_num_ticks_poc_diff_one_minus1, + /* Reserved */ + .pDecPicBufMgr = dpbm_vps, + .pHrdParameters = vui_header_vps, + .pProfileTierLevel = ptl_vps, + }; + + return 0; +} + +static int create_session_params(AVCodecContext *avctx) +{ + int err; + VulkanEncodeH265Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + VulkanH265Units vk_units = { 0 }; + + VkVideoEncodeH265SessionParametersAddInfoKHR h265_params_info; + VkVideoEncodeH265SessionParametersCreateInfoKHR h265_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 SPS/PPS units 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); + + h265_params_info = (VkVideoEncodeH265SessionParametersAddInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR, + .pStdSPSs = &vk_units.sps, + .stdSPSCount = 1, + .pStdPPSs = &vk_units.pps, + .stdPPSCount = 1, + .pStdVPSs = &vk_units.vps, + .stdVPSCount = 1, + }; + h265_params = (VkVideoEncodeH265SessionParametersCreateInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR, + .maxStdSPSCount = 1, + .maxStdPPSCount = 1, + .maxStdVPSCount = 1, + .pParametersAddInfo = &h265_params_info, + }; + + return ff_vulkan_encode_create_session_params(avctx, ctx, &h265_params); +} + +static int parse_feedback_units(AVCodecContext *avctx, + const uint8_t *data, size_t size, + int sps_override, int pps_override) +{ + int err; + VulkanEncodeH265Context *enc = avctx->priv_data; + + CodedBitstreamContext *cbs; + CodedBitstreamFragment au = { 0 }; + + err = ff_cbs_init(&cbs, AV_CODEC_ID_HEVC, avctx); + if (err < 0) + return err; + + err = ff_cbs_read(cbs, &au, 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 (sps_override) { + for (int i = 0; i < au.nb_units; i++) { + if (au.units[i].type == HEVC_NAL_SPS) { + H265RawSPS *sps = au.units[i].content; + enc->units.raw_sps.pic_width_in_luma_samples = sps->pic_width_in_luma_samples; + enc->units.raw_sps.pic_height_in_luma_samples = sps->pic_height_in_luma_samples; + enc->units.raw_sps.log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size; + enc->units.raw_sps.max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter; + enc->units.raw_sps.max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra; + } + } + } + + /* If PPS has an override, just copy it entirely. */ + if (pps_override) { + for (int i = 0; i < au.nb_units; i++) { + if (au.units[i].type == HEVC_NAL_PPS) { + H265RawPPS *pps = au.units[i].content; + memcpy(&enc->units.raw_pps, pps, sizeof(*pps)); + enc->fixed_qp_idr = pps->init_qp_minus26 + 26; + break; + } + } + } + + ff_cbs_fragment_free(&au); + ff_cbs_close(&cbs); + + return 0; +} + +static int init_base_units(AVCodecContext *avctx) +{ + int err; + VkResult ret; + VulkanEncodeH265Context *enc = avctx->priv_data; + FFVulkanEncodeContext *ctx = &enc->common; + FFVulkanContext *s = &ctx->s; + FFVulkanFunctions *vk = &ctx->s.vkfn; + + VkVideoEncodeH265SessionParametersGetInfoKHR h265_params_info; + VkVideoEncodeSessionParametersGetInfoKHR params_info; + VkVideoEncodeH265SessionParametersFeedbackInfoKHR h265_params_feedback; + 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 SPS/PPS units: %s\n", + av_err2str(err)); + return err; + } + + /* Create session parameters from them */ + err = create_session_params(avctx); + if (err < 0) + return err; + + h265_params_info = (VkVideoEncodeH265SessionParametersGetInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_GET_INFO_KHR, + .writeStdSPS = 1, + .writeStdPPS = 1, + .writeStdVPS = 1, + .stdSPSId = enc->units.raw_sps.sps_seq_parameter_set_id, + .stdPPSId = enc->units.raw_pps.pps_pic_parameter_set_id, + .stdVPSId = enc->units.raw_vps.vps_video_parameter_set_id, + }; + params_info = (VkVideoEncodeSessionParametersGetInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_GET_INFO_KHR, + .pNext = &h265_params_info, + .videoSessionParameters = ctx->session_params, + }; + + h265_params_feedback = (VkVideoEncodeH265SessionParametersFeedbackInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_FEEDBACK_INFO_KHR, + }; + params_feedback = (VkVideoEncodeSessionParametersFeedbackInfoKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_SESSION_PARAMETERS_FEEDBACK_INFO_KHR, + .pNext = &h265_params_feedback, + }; + + 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 H.265 units = %lu\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 (SPS: %i PPS: %i VPS: %i)\n", + params_feedback.hasOverrides, + h265_params_feedback.hasStdSPSOverrides, + h265_params_feedback.hasStdPPSOverrides, + h265_params_feedback.hasStdVPSOverrides); + + params_feedback.hasOverrides = 1; + h265_params_feedback.hasStdSPSOverrides = 1; + h265_params_feedback.hasStdPPSOverrides = 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, + h265_params_feedback.hasStdSPSOverrides, + h265_params_feedback.hasStdPPSOverrides); + 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_h265_add_nal(AVCodecContext *avctx, + CodedBitstreamFragment *au, + void *nal_unit) +{ + H265RawNALUnitHeader *header = nal_unit; + + int 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; +} + +static int write_access_unit(AVCodecContext *avctx, + uint8_t *data, size_t *data_len, + CodedBitstreamFragment *au) +{ + VulkanEncodeH265Context *enc = avctx->priv_data; + + int err = ff_cbs_write_fragment_data(enc->cbs, au); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; + } + + if (*data_len < au->data_size) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: %zu < %zu.\n", + *data_len, au->data_size); + return AVERROR(ENOSPC); + } + + memcpy(data, au->data, au->data_size); + *data_len = au->data_size; + + return 0; +} + +static int write_sequence_headers(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeH265Context *enc = avctx->priv_data; + VulkanEncodeH265Picture *hp = base_pic ? base_pic->codec_priv : NULL; + CodedBitstreamFragment *au = &enc->current_access_unit; + + if (hp && hp->units_needed & UNIT_AUD) { + err = vulkan_encode_h265_add_nal(avctx, au, &enc->raw_aud); + if (err < 0) + goto fail; + hp->units_needed &= ~UNIT_AUD; + } + + err = vulkan_encode_h265_add_nal(avctx, au, &enc->units.raw_vps); + if (err < 0) + goto fail; + + err = vulkan_encode_h265_add_nal(avctx, au, &enc->units.raw_sps); + if (err < 0) + goto fail; + + err = vulkan_encode_h265_add_nal(avctx, au, &enc->units.raw_pps); + if (err < 0) + goto fail; + + err = write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_reset(au); + return err; +} + +static int write_extra_headers(AVCodecContext *avctx, + FFHWBaseEncodePicture *base_pic, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeH265Context *enc = avctx->priv_data; + VulkanEncodeH265Picture *hp = base_pic->codec_priv; + CodedBitstreamFragment *au = &enc->current_access_unit; + + if (hp->units_needed & UNIT_AUD) { + err = vulkan_encode_h265_add_nal(avctx, au, &enc->raw_aud); + if (err < 0) + goto fail; + } + + if (hp->units_needed & UNIT_SEI_MASTERING_DISPLAY) { + err = ff_cbs_sei_add_message(enc->cbs, au, 1, + SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME, + &enc->sei_mastering_display, NULL); + if (err < 0) + goto fail; + } + + if (hp->units_needed & UNIT_SEI_CONTENT_LIGHT_LEVEL) { + err = ff_cbs_sei_add_message(enc->cbs, au, 1, + SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO, + &enc->sei_content_light_level, NULL); + if (err < 0) + goto fail; + } + if (hp->units_needed & UNIT_SEI_A53_CC) { + err = ff_cbs_sei_add_message(enc->cbs, au, 1, + SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35, + &enc->sei_a53cc, NULL); + if (err < 0) + goto fail; + } + + if (hp->units_needed) { + err = write_access_unit(avctx, data, data_len, au); + if (err < 0) + goto fail; + } else { + *data_len = 0; + } + +fail: + ff_cbs_fragment_reset(au); + return err; +} + +static int write_filler(AVCodecContext *avctx, uint32_t filler, + uint8_t *data, size_t *data_len) +{ + int err; + VulkanEncodeH265Context *enc = avctx->priv_data; + CodedBitstreamFragment *au = &enc->current_access_unit; + + H265RawFiller raw_filler = { + .nal_unit_header = + { + .nal_unit_type = HEVC_NAL_FD_NUT, + .nuh_temporal_id_plus1 = 1, + }, + .filler_size = filler, + }; + + err = vulkan_encode_h265_add_nal(avctx, au, &raw_filler); + if (err < 0) + goto fail; + + err = write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_reset(au); + return err; +} + +static const FFVulkanCodec enc_cb = { + .flags = FF_HW_FLAG_B_PICTURES | + FF_HW_FLAG_B_PICTURE_REFERENCES | + FF_HW_FLAG_NON_IDR_KEY_PICTURES, + .picture_priv_data_size = sizeof(VulkanEncodeH265Picture), + .filler_header_size = 7, + .init_profile = init_profile, + .init_pic_rc = init_pic_rc, + .init_pic_params = init_pic_params, + .write_sequence_headers = write_sequence_headers, + .write_extra_headers = write_extra_headers, + .write_filler = write_filler, +}; + +static av_cold int vulkan_encode_h265_init(AVCodecContext *avctx) +{ + int err, ref_l0, ref_l1; + VulkanEncodeH265Context *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 = (VkVideoEncodeH265CapabilitiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_KHR, + }; + + enc->quality_props = (VkVideoEncodeH265QualityLevelPropertiesKHR) { + .sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_QUALITY_LEVEL_PROPERTIES_KHR, + }; + + err = ff_vulkan_encode_init(avctx, &enc->common, + &ff_vk_enc_h265_desc, &enc_cb, + &enc->caps, &enc->quality_props); + if (err < 0) + return err; + + av_log(avctx, AV_LOG_VERBOSE, "H265 encoder capabilities:\n"); + av_log(avctx, AV_LOG_VERBOSE, " Standard capability flags:\n"); + av_log(avctx, AV_LOG_VERBOSE, " separate_color_plane: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_SEPARATE_COLOR_PLANE_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " sample_adaptive_offset: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " scaling_lists: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_SCALING_LIST_DATA_PRESENT_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " pcm: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_PCM_ENABLED_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " temporal_mvp: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_SPS_TEMPORAL_MVP_ENABLED_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " init_qp: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_INIT_QP_MINUS26_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " weighted:%s%s\n", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_WEIGHTED_PRED_FLAG_SET_BIT_KHR ? + " pred" : "", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_WEIGHTED_BIPRED_FLAG_SET_BIT_KHR ? + " bipred" : ""); + av_log(avctx, AV_LOG_VERBOSE, " parallel_merge_level: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_LOG2_PARALLEL_MERGE_LEVEL_MINUS2_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " sign_data_hiding: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_SIGN_DATA_HIDING_ENABLED_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " transform_skip:%s%s\n", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_SET_BIT_KHR ? + " set" : "", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_TRANSFORM_SKIP_ENABLED_FLAG_UNSET_BIT_KHR ? + " unset" : ""); + av_log(avctx, AV_LOG_VERBOSE, " slice_chroma_qp_offsets: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " transquant_bypass: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_TRANSQUANT_BYPASS_ENABLED_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " constrained_intra_pred: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_CONSTRAINED_INTRA_PRED_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " entrypy_coding_sync: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_ENTROPY_CODING_SYNC_ENABLED_FLAG_SET_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " dependent_slice_segment:%s%s\n", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG_SET_BIT_KHR ? + " enabled" : "", + enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_DEPENDENT_SLICE_SEGMENT_FLAG_SET_BIT_KHR ? + " set" : ""); + av_log(avctx, AV_LOG_VERBOSE, " slice_qp_delta: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_SLICE_QP_DELTA_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " different_slice_qp_delta: %i\n", + !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H265_STD_DIFFERENT_SLICE_QP_DELTA_BIT_KHR)); + + av_log(avctx, AV_LOG_VERBOSE, " Capability flags:\n"); + av_log(avctx, AV_LOG_VERBOSE, " hdr_compliance: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_HRD_COMPLIANCE_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " pred_weight_table_generated: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " row_unaligned_slice: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " different_slice_type: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_DIFFERENT_SLICE_TYPE_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " b_frame_in_l0_list: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " b_frame_in_l1_list: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " per_pict_type_min_max_qp: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " per_slice_constant_qp: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_PER_SLICE_CONSTANT_QP_BIT_KHR)); + av_log(avctx, AV_LOG_VERBOSE, " generate_prefix_nalu: %i\n", + !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_GENERATE_PREFIX_NALU_BIT_KHR)); + + av_log(avctx, AV_LOG_VERBOSE, " Capabilities:\n"); + av_log(avctx, AV_LOG_VERBOSE, " maxLevelIdc: %i\n", + enc->caps.maxLevelIdc); + av_log(avctx, AV_LOG_VERBOSE, " maxSliceCount: %i\n", + enc->caps.maxSliceSegmentCount); + av_log(avctx, AV_LOG_VERBOSE, " maxTiles: %ix%i\n", + enc->caps.maxTiles.width, enc->caps.maxTiles.height); + av_log(avctx, AV_LOG_VERBOSE, " cbtSizes: 0x%x\n", + enc->caps.ctbSizes); + av_log(avctx, AV_LOG_VERBOSE, " transformBlockSizes: 0x%x\n", + enc->caps.transformBlockSizes); + av_log(avctx, AV_LOG_VERBOSE, " max(P/B)PictureL0ReferenceCount: %i P's; %i B's\n", + enc->caps.maxPPictureL0ReferenceCount, + enc->caps.maxBPictureL0ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxL1ReferenceCount: %i\n", + enc->caps.maxL1ReferenceCount); + av_log(avctx, AV_LOG_VERBOSE, " maxSubLayerCount: %i\n", + enc->caps.maxSubLayerCount); + av_log(avctx, AV_LOG_VERBOSE, " expectDyadicTemporalLayerPattern: %i\n", + enc->caps.expectDyadicTemporalSubLayerPattern); + av_log(avctx, AV_LOG_VERBOSE, " min/max Qp: [%i, %i]\n", + enc->caps.minQp, enc->caps.maxQp); + av_log(avctx, AV_LOG_VERBOSE, " prefersGopRemainingFrames: %i\n", + enc->caps.prefersGopRemainingFrames); + av_log(avctx, AV_LOG_VERBOSE, " requiresGopRemainingFrames: %i\n", + enc->caps.requiresGopRemainingFrames); + + err = init_enc_options(avctx); + if (err < 0) + return err; + + flags = ctx->codec->flags; + if (!enc->caps.maxPPictureL0ReferenceCount && + !enc->caps.maxBPictureL0ReferenceCount && + !enc->caps.maxL1ReferenceCount) { + /* Intra-only */ + flags |= FF_HW_FLAG_INTRA_ONLY; + ref_l0 = ref_l1 = 0; + } else if (!enc->caps.maxPPictureL0ReferenceCount) { + /* No P-frames? How. */ + base_ctx->p_to_gpb = 1; + ref_l0 = enc->caps.maxBPictureL0ReferenceCount; + ref_l1 = enc->caps.maxL1ReferenceCount; + } else if (!enc->caps.maxBPictureL0ReferenceCount && + !enc->caps.maxL1ReferenceCount) { + /* No B-frames */ + flags &= ~(FF_HW_FLAG_B_PICTURES | FF_HW_FLAG_B_PICTURE_REFERENCES); + ref_l0 = enc->caps.maxPPictureL0ReferenceCount; + ref_l1 = 0; + } else { + /* P and B frames */ + ref_l0 = FFMIN(enc->caps.maxPPictureL0ReferenceCount, + enc->caps.maxBPictureL0ReferenceCount); + ref_l1 = enc->caps.maxL1ReferenceCount; + } + + err = ff_hw_base_init_gop_structure(base_ctx, avctx, ref_l0, ref_l1, + 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; + + /* Init CBS */ + err = ff_cbs_init(&enc->cbs, AV_CODEC_ID_HEVC, avctx); + if (err < 0) + return err; + + /* Create units and session parameters */ + err = init_base_units(avctx); + if (err < 0) + return err; + + /* Write out extradata */ + err = ff_vulkan_write_global_header(avctx, &enc->common); + if (err < 0) + return err; + + return 0; +} + +static av_cold int vulkan_encode_h265_close(AVCodecContext *avctx) +{ + VulkanEncodeH265Context *enc = avctx->priv_data; + ff_vulkan_encode_uninit(&enc->common); + return 0; +} + +#define OFFSET(x) offsetof(VulkanEncodeH265Context, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption vulkan_encode_h265_options[] = { + HW_BASE_ENCODE_COMMON_OPTIONS, + VULKAN_ENCODE_COMMON_OPTIONS, + + { "profile", "Set profile (profile_idc and constraint_set*_flag)", + 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_HEVC_MAIN) }, + { PROFILE("main10", AV_PROFILE_HEVC_MAIN_10) }, + { PROFILE("rext", AV_PROFILE_HEVC_REXT) }, +#undef PROFILE + + { "tier", "Set tier (general_tier_flag)", 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 (general_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("1", 30) }, + { LEVEL("2", 60) }, + { LEVEL("2.1", 63) }, + { LEVEL("3", 90) }, + { LEVEL("3.1", 93) }, + { LEVEL("4", 120) }, + { LEVEL("4.1", 123) }, + { LEVEL("5", 150) }, + { LEVEL("5.1", 153) }, + { LEVEL("5.2", 156) }, + { LEVEL("6", 180) }, + { LEVEL("6.1", 183) }, + { LEVEL("6.2", 186) }, +#undef LEVEL + + { "units", "Set units to include", OFFSET(unit_elems), AV_OPT_TYPE_FLAGS, { .i64 = UNIT_SEI_MASTERING_DISPLAY | UNIT_SEI_CONTENT_LIGHT_LEVEL | UNIT_SEI_A53_CC }, 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_SEI_MASTERING_DISPLAY | UNIT_SEI_CONTENT_LIGHT_LEVEL }, INT_MIN, INT_MAX, FLAGS, "units" }, + { "a53_cc", "Include A/53 caption data", 0, AV_OPT_TYPE_CONST, { .i64 = UNIT_SEI_A53_CC }, INT_MIN, INT_MAX, FLAGS, "units" }, + + { NULL }, +}; + +static const FFCodecDefault vulkan_encode_h265_defaults[] = { + { "b", "0" }, + { "bf", "2" }, + { "g", "300" }, + { "i_qfactor", "1" }, + { "i_qoffset", "0" }, + { "b_qfactor", "6/5" }, + { "b_qoffset", "0" }, + { "qmin", "-1" }, + { "qmax", "-1" }, + { NULL }, +}; + +static const AVClass vulkan_encode_h265_class = { + .class_name = "hevc_vulkan", + .item_name = av_default_item_name, + .option = vulkan_encode_h265_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_hevc_vulkan_encoder = { + .p.name = "hevc_vulkan", + CODEC_LONG_NAME("H.265/HEVC (Vulkan)"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_HEVC, + .priv_data_size = sizeof(VulkanEncodeH265Context), + .init = &vulkan_encode_h265_init, + FF_CODEC_RECEIVE_PACKET_CB(&ff_vulkan_encode_receive_packet), + .close = &vulkan_encode_h265_close, + .p.priv_class = &vulkan_encode_h265_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_h265_defaults, + .p.pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_VULKAN, + AV_PIX_FMT_NONE, + }, + .hw_configs = ff_vulkan_encode_hw_configs, + .p.wrapper_name = "vulkan", +}; diff --git a/libavcodec/vulkan_h264.c b/libavcodec/vulkan_h264.c index 0b296b3cc..05ac88413 100644 --- a/libavcodec/vulkan_h264.c +++ b/libavcodec/vulkan_h264.c @@ -60,6 +60,7 @@ static int vk_h264_fill_pict(AVCodecContext *avctx, H264Picture **ref_src, int dpb_slot_index) { FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; H264VulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vkpic = &hp->vp; @@ -95,7 +96,7 @@ static int vk_h264_fill_pict(AVCodecContext *avctx, H264Picture **ref_src, .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, .codedOffset = (VkOffset2D){ 0, 0 }, .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, - .baseArrayLayer = dec->layered_dpb ? dpb_slot_index : 0, + .baseArrayLayer = ctx->common.layered_dpb ? dpb_slot_index : 0, .imageViewBinding = vkpic->img_view_ref, }; diff --git a/libavcodec/vulkan_hevc.c b/libavcodec/vulkan_hevc.c index 239bff75e..0b2000568 100644 --- a/libavcodec/vulkan_hevc.c +++ b/libavcodec/vulkan_hevc.c @@ -16,9 +16,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "hevcdec.h" -#include "hevc_data.h" -#include "hevc_ps.h" +#include "libavutil/mem.h" +#include "hevc/hevcdec.h" +#include "hevc/data.h" +#include "hevc/ps.h" #include "vulkan_decode.h" @@ -135,10 +136,11 @@ static int vk_hevc_fill_pict(AVCodecContext *avctx, HEVCFrame **ref_src, HEVCFrame *pic, int is_current, int pic_id) { FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; + FFVulkanDecodeShared *ctx = dec->shared_ctx; HEVCVulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vkpic = &hp->vp; - int err = ff_vk_decode_prepare_frame(dec, pic->frame, vkpic, is_current, + int err = ff_vk_decode_prepare_frame(dec, pic->f, vkpic, is_current, dec->dedicated_dpb); if (err < 0) return err; @@ -159,8 +161,8 @@ static int vk_hevc_fill_pict(AVCodecContext *avctx, HEVCFrame **ref_src, *ref = (VkVideoPictureResourceInfoKHR) { .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, .codedOffset = (VkOffset2D){ 0, 0 }, - .codedExtent = (VkExtent2D){ pic->frame->width, pic->frame->height }, - .baseArrayLayer = dec->layered_dpb ? pic_id : 0, + .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, + .baseArrayLayer = ctx->common.layered_dpb ? pic_id : 0, .imageViewBinding = vkpic->img_view_ref, }; @@ -177,25 +179,6 @@ static int vk_hevc_fill_pict(AVCodecContext *avctx, HEVCFrame **ref_src, return 0; } -static StdVideoH265LevelIdc convert_to_vk_level_idc(int level_idc) -{ - switch (level_idc) { - case 10: return STD_VIDEO_H265_LEVEL_IDC_1_0; - case 20: return STD_VIDEO_H265_LEVEL_IDC_2_0; - case 21: return STD_VIDEO_H265_LEVEL_IDC_2_1; - case 30: return STD_VIDEO_H265_LEVEL_IDC_3_0; - case 31: return STD_VIDEO_H265_LEVEL_IDC_3_1; - case 40: return STD_VIDEO_H265_LEVEL_IDC_4_0; - case 41: return STD_VIDEO_H265_LEVEL_IDC_4_1; - case 50: return STD_VIDEO_H265_LEVEL_IDC_5_0; - case 51: return STD_VIDEO_H265_LEVEL_IDC_5_1; - case 60: return STD_VIDEO_H265_LEVEL_IDC_6_0; - case 61: return STD_VIDEO_H265_LEVEL_IDC_6_1; - default: - case 62: return STD_VIDEO_H265_LEVEL_IDC_6_2; - } -} - static void copy_scaling_list(const ScalingList *sl, StdVideoH265ScalingLists *vksl) { for (int i = 0; i < STD_VIDEO_H265_SCALING_LIST_4X4_NUM_LISTS; i++) { @@ -336,7 +319,7 @@ static void set_sps(const HEVCSPS *sps, int sps_idx, .general_frame_only_constraint_flag = sps->ptl.general_ptl.frame_only_constraint_flag, }, .general_profile_idc = sps->ptl.general_ptl.profile_idc, - .general_level_idc = convert_to_vk_level_idc(sps->ptl.general_ptl.level_idc), + .general_level_idc = ff_vk_h265_level_to_vk(sps->ptl.general_ptl.level_idc), }; for (int i = 0; i < sps->max_sub_layers; i++) { @@ -350,13 +333,15 @@ static void set_sps(const HEVCSPS *sps, int sps_idx, pal->PredictorPaletteEntries[i][j] = sps->sps_palette_predictor_initializer[i][j]; for (int i = 0; i < sps->nb_st_rps; i++) { + const ShortTermRPS *st_rps = &sps->st_rps[i]; + str[i] = (StdVideoH265ShortTermRefPicSet) { .flags = (StdVideoH265ShortTermRefPicSetFlags) { .inter_ref_pic_set_prediction_flag = sps->st_rps[i].rps_predict, .delta_rps_sign = sps->st_rps[i].delta_rps_sign, }, .delta_idx_minus1 = sps->st_rps[i].delta_idx - 1, - .use_delta_flag = sps->st_rps[i].use_delta_flag, + .use_delta_flag = sps->st_rps[i].use_delta, .abs_delta_rps_minus1 = sps->st_rps[i].abs_delta_rps - 1, .used_by_curr_pic_flag = 0x0, .used_by_curr_pic_s0_flag = 0x0, @@ -370,61 +355,58 @@ static void set_sps(const HEVCSPS *sps, int sps_idx, /* NOTE: This is the predicted, and *reordered* version. * Probably incorrect, but the spec doesn't say which version to use. */ - for (int j = 0; j < sps->st_rps[i].num_delta_pocs; j++) - str[i].used_by_curr_pic_flag |= sps->st_rps[i].used[j] << j; + str[i].used_by_curr_pic_flag = st_rps->used; + str[i].used_by_curr_pic_s0_flag = av_zero_extend(st_rps->used, str[i].num_negative_pics); + str[i].used_by_curr_pic_s1_flag = st_rps->used >> str[i].num_negative_pics; - for (int j = 0; j < str[i].num_negative_pics; j++) { - str[i].delta_poc_s0_minus1[j] = sps->st_rps[i].delta_poc_s0[j] - 1; - str[i].used_by_curr_pic_s0_flag |= sps->st_rps[i].used[j] << j; - } + for (int j = 0; j < str[i].num_negative_pics; j++) + str[i].delta_poc_s0_minus1[j] = st_rps->delta_poc[j] - (j ? st_rps->delta_poc[j - 1] : 0) - 1; - for (int j = 0; j < str[i].num_positive_pics; j++) { - str[i].delta_poc_s1_minus1[j] = sps->st_rps[i].delta_poc_s1[j] - 1; - str[i].used_by_curr_pic_s0_flag |= sps->st_rps[i].used[str[i].num_negative_pics + j] << j; - } + for (int j = 0; j < str[i].num_positive_pics; j++) + str[i].delta_poc_s1_minus1[j] = st_rps->delta_poc[st_rps->num_negative_pics + j] - + (j ? st_rps->delta_poc[st_rps->num_negative_pics + j - 1] : 0) - 1; } *ltr = (StdVideoH265LongTermRefPicsSps) { - .used_by_curr_pic_lt_sps_flag = 0x0, + .used_by_curr_pic_lt_sps_flag = sps->used_by_curr_pic_lt, }; for (int i = 0; i < sps->num_long_term_ref_pics_sps; i++) { - ltr->used_by_curr_pic_lt_sps_flag |= sps->used_by_curr_pic_lt_sps_flag[i] << i; ltr->lt_ref_pic_poc_lsb_sps[i] = sps->lt_ref_pic_poc_lsb_sps[i]; } *vksps = (StdVideoH265SequenceParameterSet) { .flags = (StdVideoH265SpsFlags) { - .sps_temporal_id_nesting_flag = sps->temporal_id_nesting_flag, - .separate_colour_plane_flag = sps->separate_colour_plane_flag, - .conformance_window_flag = sps->conformance_window_flag, - .sps_sub_layer_ordering_info_present_flag = sps->sublayer_ordering_info_flag, - .scaling_list_enabled_flag = sps->scaling_list_enable_flag, - .sps_scaling_list_data_present_flag = sps->scaling_list_enable_flag, - .amp_enabled_flag = sps->amp_enabled_flag, + .sps_temporal_id_nesting_flag = sps->temporal_id_nesting, + .separate_colour_plane_flag = sps->separate_colour_plane, + .conformance_window_flag = sps->conformance_window, + .sps_sub_layer_ordering_info_present_flag = sps->sublayer_ordering_info, + .scaling_list_enabled_flag = sps->scaling_list_enabled, + .sps_scaling_list_data_present_flag = sps->scaling_list_enabled, + .amp_enabled_flag = sps->amp_enabled, .sample_adaptive_offset_enabled_flag = sps->sao_enabled, - .pcm_enabled_flag = sps->pcm_enabled_flag, - .pcm_loop_filter_disabled_flag = sps->pcm.loop_filter_disable_flag, - .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag, - .sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag, - .strong_intra_smoothing_enabled_flag = sps->sps_strong_intra_smoothing_enable_flag, + .pcm_enabled_flag = sps->pcm_enabled, + .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled, + .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present, + .sps_temporal_mvp_enabled_flag = sps->temporal_mvp_enabled, + .strong_intra_smoothing_enabled_flag = sps->strong_intra_smoothing_enabled, .vui_parameters_present_flag = sps->vui_present, - .sps_extension_present_flag = sps->sps_extension_present_flag, - .sps_range_extension_flag = sps->sps_range_extension_flag, - .transform_skip_rotation_enabled_flag = sps->transform_skip_rotation_enabled_flag, - .transform_skip_context_enabled_flag = sps->transform_skip_context_enabled_flag, - .implicit_rdpcm_enabled_flag = sps->implicit_rdpcm_enabled_flag, - .explicit_rdpcm_enabled_flag = sps->explicit_rdpcm_enabled_flag, - .extended_precision_processing_flag = sps->extended_precision_processing_flag, - .intra_smoothing_disabled_flag = sps->intra_smoothing_disabled_flag, - .high_precision_offsets_enabled_flag = sps->high_precision_offsets_enabled_flag, - .persistent_rice_adaptation_enabled_flag = sps->persistent_rice_adaptation_enabled_flag, - .cabac_bypass_alignment_enabled_flag = sps->cabac_bypass_alignment_enabled_flag, - .sps_scc_extension_flag = sps->sps_scc_extension_flag, - .sps_curr_pic_ref_enabled_flag = sps->sps_curr_pic_ref_enabled_flag, - .palette_mode_enabled_flag = sps->palette_mode_enabled_flag, - .sps_palette_predictor_initializers_present_flag = sps->sps_palette_predictor_initializers_present_flag, - .intra_boundary_filtering_disabled_flag = sps->intra_boundary_filtering_disabled_flag, + .sps_extension_present_flag = sps->extension_present, + .sps_range_extension_flag = sps->range_extension, + .transform_skip_rotation_enabled_flag = sps->transform_skip_rotation_enabled, + .transform_skip_context_enabled_flag = sps->transform_skip_context_enabled, + .implicit_rdpcm_enabled_flag = sps->implicit_rdpcm_enabled, + .explicit_rdpcm_enabled_flag = sps->explicit_rdpcm_enabled, + .extended_precision_processing_flag = sps->extended_precision_processing, + .intra_smoothing_disabled_flag = sps->intra_smoothing_disabled, + .high_precision_offsets_enabled_flag = sps->high_precision_offsets_enabled, + .persistent_rice_adaptation_enabled_flag = sps->persistent_rice_adaptation_enabled, + .cabac_bypass_alignment_enabled_flag = sps->cabac_bypass_alignment_enabled, + .sps_scc_extension_flag = sps->scc_extension, + .sps_curr_pic_ref_enabled_flag = sps->curr_pic_ref_enabled, + .palette_mode_enabled_flag = sps->palette_mode_enabled, + .sps_palette_predictor_initializers_present_flag = sps->palette_predictor_initializers_present, + .intra_boundary_filtering_disabled_flag = sps->intra_boundary_filtering_disabled, }, .chroma_format_idc = sps->chroma_format_idc, .pic_width_in_luma_samples = sps->width, @@ -606,8 +588,8 @@ static void set_vps(const HEVCVPS *vps, .general_non_packed_constraint_flag = vps->ptl.general_ptl.non_packed_constraint_flag, .general_frame_only_constraint_flag = vps->ptl.general_ptl.frame_only_constraint_flag, }, - .general_profile_idc = vps->ptl.general_ptl.profile_idc, - .general_level_idc = convert_to_vk_level_idc(vps->ptl.general_ptl.level_idc), + .general_profile_idc = ff_vk_h265_profile_to_vk(vps->ptl.general_ptl.profile_idc), + .general_level_idc = ff_vk_h265_level_to_vk(vps->ptl.general_ptl.level_idc), }; for (int i = 0; i < vps->vps_max_sub_layers; i++) { @@ -731,12 +713,13 @@ static int vk_hevc_start_frame(AVCodecContext *avctx, { int err; HEVCContext *h = avctx->priv_data; - HEVCFrame *pic = h->ref; + 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 HEVCSPS *sps = h->ps.sps; - const HEVCPPS *pps = h->ps.pps; + const HEVCPPS *pps = h->pps; + const HEVCSPS *sps = pps->sps; int nb_refs = 0; if (!dec->session_params) { @@ -762,8 +745,8 @@ static int vk_hevc_start_frame(AVCodecContext *avctx, }; /* Fill in references */ - for (int i = 0; i < FF_ARRAY_ELEMS(h->DPB); i++) { - const HEVCFrame *ref = &h->DPB[i]; + for (int i = 0; i < FF_ARRAY_ELEMS(l->DPB); i++) { + const HEVCFrame *ref = &l->DPB[i]; int idx = nb_refs; if (!(ref->flags & (HEVC_FRAME_FLAG_SHORT_REF | HEVC_FRAME_FLAG_LONG_REF))) @@ -790,8 +773,8 @@ static int vk_hevc_start_frame(AVCodecContext *avctx, memset(hp->h265pic.RefPicSetStCurrBefore, 0xff, 8); for (int i = 0; i < h->rps[ST_CURR_BEF].nb_refs; i++) { HEVCFrame *frame = h->rps[ST_CURR_BEF].ref[i]; - for (int j = 0; j < FF_ARRAY_ELEMS(h->DPB); j++) { - const HEVCFrame *ref = &h->DPB[j]; + for (int j = 0; j < FF_ARRAY_ELEMS(l->DPB); j++) { + const HEVCFrame *ref = &l->DPB[j]; if (ref == frame) { hp->h265pic.RefPicSetStCurrBefore[i] = j; break; @@ -801,8 +784,8 @@ static int vk_hevc_start_frame(AVCodecContext *avctx, memset(hp->h265pic.RefPicSetStCurrAfter, 0xff, 8); for (int i = 0; i < h->rps[ST_CURR_AFT].nb_refs; i++) { HEVCFrame *frame = h->rps[ST_CURR_AFT].ref[i]; - for (int j = 0; j < FF_ARRAY_ELEMS(h->DPB); j++) { - const HEVCFrame *ref = &h->DPB[j]; + for (int j = 0; j < FF_ARRAY_ELEMS(l->DPB); j++) { + const HEVCFrame *ref = &l->DPB[j]; if (ref == frame) { hp->h265pic.RefPicSetStCurrAfter[i] = j; break; @@ -812,8 +795,8 @@ static int vk_hevc_start_frame(AVCodecContext *avctx, memset(hp->h265pic.RefPicSetLtCurr, 0xff, 8); for (int i = 0; i < h->rps[LT_CURR].nb_refs; i++) { HEVCFrame *frame = h->rps[LT_CURR].ref[i]; - for (int j = 0; j < FF_ARRAY_ELEMS(h->DPB); j++) { - const HEVCFrame *ref = &h->DPB[j]; + for (int j = 0; j < FF_ARRAY_ELEMS(l->DPB); j++) { + const HEVCFrame *ref = &l->DPB[j]; if (ref == frame) { hp->h265pic.RefPicSetLtCurr[i] = j; break; @@ -837,7 +820,7 @@ static int vk_hevc_start_frame(AVCodecContext *avctx, .dstPictureResource = (VkVideoPictureResourceInfoKHR) { .sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR, .codedOffset = (VkOffset2D){ 0, 0 }, - .codedExtent = (VkExtent2D){ pic->frame->width, pic->frame->height }, + .codedExtent = (VkExtent2D){ pic->f->width, pic->f->height }, .baseArrayLayer = 0, .imageViewBinding = vp->img_view_out, }, @@ -851,7 +834,7 @@ static int vk_hevc_decode_slice(AVCodecContext *avctx, uint32_t size) { const HEVCContext *h = avctx->priv_data; - HEVCVulkanDecodePicture *hp = h->ref->hwaccel_picture_private; + HEVCVulkanDecodePicture *hp = h->cur_frame->hwaccel_picture_private; FFVulkanDecodePicture *vp = &hp->vp; int err = ff_vk_decode_add_slice(avctx, vp, data, size, 1, @@ -867,7 +850,7 @@ static int vk_hevc_end_frame(AVCodecContext *avctx) { const HEVCContext *h = avctx->priv_data; FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data; - HEVCFrame *pic = h->ref; + HEVCFrame *pic = h->cur_frame; HEVCVulkanDecodePicture *hp = pic->hwaccel_picture_private; FFVulkanDecodePicture *vp = &hp->vp; FFVulkanDecodePicture *rvp[HEVC_MAX_REFS] = { 0 }; @@ -878,8 +861,8 @@ static int vk_hevc_end_frame(AVCodecContext *avctx) return 0; if (!dec->session_params) { - const HEVCSPS *sps = h->ps.sps; - const HEVCPPS *pps = h->ps.pps; + const HEVCPPS *pps = h->pps; + const HEVCSPS *sps = pps->sps; if (!pps) { unsigned int pps_id = h->sh.pps_id; @@ -904,14 +887,14 @@ static int vk_hevc_end_frame(AVCodecContext *avctx) for (int i = 0; i < vp->decode_info.referenceSlotCount; i++) { HEVCVulkanDecodePicture *rfhp = hp->ref_src[i]->hwaccel_picture_private; - rav[i] = hp->ref_src[i]->frame; + rav[i] = hp->ref_src[i]->f; rvp[i] = &rfhp->vp; } av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %"SIZE_SPECIFIER" bytes, %i slices\n", vp->slices_size, hp->h265_pic_info.sliceSegmentCount); - return ff_vk_decode_frame(avctx, pic->frame, vp, rav, rvp); + return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp); } static void vk_hevc_free_frame_priv(FFRefStructOpaque _hwctx, void *data) diff --git a/libavcodec/vulkan_video.c b/libavcodec/vulkan_video.c index 4be13ecc5..3a04d60d6 100644 --- a/libavcodec/vulkan_video.c +++ b/libavcodec/vulkan_video.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "vulkan_video.h" #define ASPECT_2PLANE (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT) @@ -157,6 +158,32 @@ int ff_vk_h264_level_to_av(StdVideoH264LevelIdc level) } } +StdVideoH264LevelIdc ff_vk_h264_level_to_vk(int level_idc) +{ + switch (level_idc) { + case 10: return STD_VIDEO_H264_LEVEL_IDC_1_0; + case 11: return STD_VIDEO_H264_LEVEL_IDC_1_1; + case 12: return STD_VIDEO_H264_LEVEL_IDC_1_2; + case 13: return STD_VIDEO_H264_LEVEL_IDC_1_3; + case 20: return STD_VIDEO_H264_LEVEL_IDC_2_0; + case 21: return STD_VIDEO_H264_LEVEL_IDC_2_1; + case 22: return STD_VIDEO_H264_LEVEL_IDC_2_2; + case 30: return STD_VIDEO_H264_LEVEL_IDC_3_0; + case 31: return STD_VIDEO_H264_LEVEL_IDC_3_1; + case 32: return STD_VIDEO_H264_LEVEL_IDC_3_2; + case 40: return STD_VIDEO_H264_LEVEL_IDC_4_0; + case 41: return STD_VIDEO_H264_LEVEL_IDC_4_1; + case 42: return STD_VIDEO_H264_LEVEL_IDC_4_2; + case 50: return STD_VIDEO_H264_LEVEL_IDC_5_0; + case 51: return STD_VIDEO_H264_LEVEL_IDC_5_1; + case 52: return STD_VIDEO_H264_LEVEL_IDC_5_2; + case 60: return STD_VIDEO_H264_LEVEL_IDC_6_0; + case 61: return STD_VIDEO_H264_LEVEL_IDC_6_1; + default: + case 62: return STD_VIDEO_H264_LEVEL_IDC_6_2; + } +} + int ff_vk_h265_level_to_av(StdVideoH265LevelIdc level) { switch (level) { @@ -176,82 +203,121 @@ int ff_vk_h265_level_to_av(StdVideoH265LevelIdc level) } } -static void free_data_buf(void *opaque, uint8_t *data) +StdVideoH265LevelIdc ff_vk_h265_level_to_vk(int level_idc) { - FFVulkanContext *ctx = opaque; - FFVkVideoBuffer *buf = (FFVkVideoBuffer *)data; - ff_vk_unmap_buffer(ctx, &buf->buf, 0); - ff_vk_free_buf(ctx, &buf->buf); - av_free(data); + switch (level_idc) { + case 10: return STD_VIDEO_H265_LEVEL_IDC_1_0; + case 20: return STD_VIDEO_H265_LEVEL_IDC_2_0; + case 21: return STD_VIDEO_H265_LEVEL_IDC_2_1; + case 30: return STD_VIDEO_H265_LEVEL_IDC_3_0; + case 31: return STD_VIDEO_H265_LEVEL_IDC_3_1; + case 40: return STD_VIDEO_H265_LEVEL_IDC_4_0; + case 41: return STD_VIDEO_H265_LEVEL_IDC_4_1; + case 50: return STD_VIDEO_H265_LEVEL_IDC_5_0; + case 51: return STD_VIDEO_H265_LEVEL_IDC_5_1; + case 60: return STD_VIDEO_H265_LEVEL_IDC_6_0; + case 61: return STD_VIDEO_H265_LEVEL_IDC_6_1; + default: + case 62: return STD_VIDEO_H265_LEVEL_IDC_6_2; + } } -static AVBufferRef *alloc_data_buf(void *opaque, size_t size) +StdVideoH264ProfileIdc ff_vk_h264_profile_to_vk(int profile) { - AVBufferRef *ref; - uint8_t *buf = av_mallocz(size); - if (!buf) - return NULL; - - ref = av_buffer_create(buf, size, free_data_buf, opaque, 0); - if (!ref) - av_free(buf); - return ref; + switch (profile) { + case AV_PROFILE_H264_CONSTRAINED_BASELINE: return STD_VIDEO_H264_PROFILE_IDC_BASELINE; + case AV_PROFILE_H264_MAIN: return STD_VIDEO_H264_PROFILE_IDC_MAIN; + case AV_PROFILE_H264_HIGH: return STD_VIDEO_H264_PROFILE_IDC_HIGH; + case AV_PROFILE_H264_HIGH_444_PREDICTIVE: return STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE; + default: return STD_VIDEO_H264_PROFILE_IDC_INVALID; + } } -int ff_vk_video_get_buffer(FFVulkanContext *ctx, FFVkVideoCommon *s, - AVBufferRef **buf, VkBufferUsageFlags usage, - void *create_pNext, size_t size) +StdVideoH265ProfileIdc ff_vk_h265_profile_to_vk(int profile) { - int err; - AVBufferRef *ref; - FFVkVideoBuffer *data; - - if (!s->buf_pool) { - s->buf_pool = av_buffer_pool_init2(sizeof(FFVkVideoBuffer), ctx, - alloc_data_buf, NULL); - if (!s->buf_pool) - return AVERROR(ENOMEM); + switch (profile) { + case AV_PROFILE_HEVC_MAIN: return STD_VIDEO_H265_PROFILE_IDC_MAIN; + case AV_PROFILE_HEVC_MAIN_10: return STD_VIDEO_H265_PROFILE_IDC_MAIN_10; + case AV_PROFILE_HEVC_REXT: return STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS; + default: return STD_VIDEO_H265_PROFILE_IDC_INVALID; } +} - *buf = ref = av_buffer_pool_get(s->buf_pool); - if (!ref) - return AVERROR(ENOMEM); - - data = (FFVkVideoBuffer *)ref->data; - - if (data->buf.size >= size) - return 0; - - /* No point in requesting anything smaller. */ - size = FFMAX(size, 1024*1024); - - /* Align buffer to nearest power of two. Makes fragmentation management - * easier, and gives us ample headroom. */ - size--; - size |= size >> 1; - size |= size >> 2; - size |= size >> 4; - size |= size >> 8; - size |= size >> 16; - size++; - - ff_vk_free_buf(ctx, &data->buf); - memset(data, 0, sizeof(FFVkVideoBuffer)); - - err = ff_vk_create_buf(ctx, &data->buf, size, - create_pNext, NULL, usage, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - if (err < 0) { - av_buffer_unref(&ref); - return err; +int ff_vk_h264_profile_to_av(StdVideoH264ProfileIdc 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; } +} - /* Map the buffer */ - err = ff_vk_map_buffer(ctx, &data->buf, &data->mem, 0); - if (err < 0) { - av_buffer_unref(&ref); - return err; +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) +{ + VkResult ret; + FFVulkanFunctions *vk = &s->vkfn; + VkImageAspectFlags aspect_mask = ff_vk_aspect_bits_from_vkfmt(vkf); + + VkSamplerYcbcrConversionInfo yuv_sampler_info = { + .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, + .conversion = common->yuv_sampler, + }; + VkImageViewCreateInfo img_view_create_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = &yuv_sampler_info, + .viewType = common->layered_dpb && is_dpb ? + VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, + .format = vkf, + .image = src->img[0], + .components = (VkComponentMapping) { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = (VkImageSubresourceRange) { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseArrayLayer = 0, + .layerCount = common->layered_dpb && is_dpb ? + VK_REMAINING_ARRAY_LAYERS : 1, + .levelCount = 1, + }, + }; + + ret = vk->CreateImageView(s->hwctx->act_dev, &img_view_create_info, + s->hwctx->alloc, view); + if (ret != VK_SUCCESS) + return AVERROR_EXTERNAL; + + *aspect = aspect_mask; return 0; } @@ -273,10 +339,20 @@ av_cold void ff_vk_video_common_uninit(FFVulkanContext *s, av_freep(&common->mem); - av_buffer_pool_uninit(&common->buf_pool); + if (common->layered_view) + vk->DestroyImageView(s->hwctx->act_dev, common->layered_view, + s->hwctx->alloc); + + 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(void *log, FFVulkanContext *s, +av_cold int ff_vk_video_common_init(AVCodecContext *avctx, FFVulkanContext *s, FFVkVideoCommon *common, VkVideoSessionCreateInfoKHR *session_create) { @@ -286,6 +362,25 @@ av_cold int ff_vk_video_common_init(void *log, 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); @@ -351,7 +446,7 @@ av_cold int ff_vk_video_common_init(void *log, FFVulkanContext *s, .memorySize = mem[i].memoryRequirements.size, }; - av_log(log, AV_LOG_VERBOSE, "Allocating %"PRIu64" bytes in bind index %i for video session\n", + av_log(avctx, AV_LOG_VERBOSE, "Allocating %"PRIu64" bytes in bind index %i for video session\n", bind_mem[i].memorySize, bind_mem[i].memoryBindIndex); } diff --git a/libavcodec/vulkan_video.h b/libavcodec/vulkan_video.h index 01a1de7d9..c205f7b88 100644 --- a/libavcodec/vulkan_video.h +++ b/libavcodec/vulkan_video.h @@ -19,6 +19,7 @@ #ifndef AVCODEC_VULKAN_VIDEO_H #define AVCODEC_VULKAN_VIDEO_H +#include "avcodec.h" #include "vulkan.h" #include @@ -33,7 +34,13 @@ typedef struct FFVkVideoSession { VkDeviceMemory *mem; uint32_t nb_mem; - AVBufferPool *buf_pool; + VkSamplerYcbcrConversion yuv_sampler; + + AVBufferRef *dpb_hwfc_ref; + int layered_dpb; + AVFrame *layered_frame; + VkImageView layered_view; + VkImageAspectFlags layered_aspect; } FFVkVideoCommon; /** @@ -56,6 +63,11 @@ 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. @@ -63,23 +75,28 @@ VkVideoComponentBitDepthFlagBitsKHR ff_vk_depth_from_av_depth(int depth); int ff_vk_h264_level_to_av(StdVideoH264LevelIdc level); int ff_vk_h265_level_to_av(StdVideoH265LevelIdc level); -typedef struct FFVkVideoBuffer { - FFVkBuffer buf; - uint8_t *mem; -} FFVkVideoBuffer; +StdVideoH264LevelIdc ff_vk_h264_level_to_vk(int level_idc); +StdVideoH265LevelIdc ff_vk_h265_level_to_vk(int level_idc); /** - * Get a mapped FFVkPooledBuffer with a specific guaranteed minimum size - * from a pool. + * Convert profile from/to AV to Vulkan */ -int ff_vk_video_get_buffer(FFVulkanContext *ctx, FFVkVideoCommon *s, - AVBufferRef **buf, VkBufferUsageFlags usage, - void *create_pNext, size_t size); +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); + +/** + * 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); /** * Initialize video session, allocating and binding necessary memory. */ -int ff_vk_video_common_init(void *log, FFVulkanContext *s, +int ff_vk_video_common_init(AVCodecContext *avctx, FFVulkanContext *s, FFVkVideoCommon *common, VkVideoSessionCreateInfoKHR *session_create); diff --git a/libavcodec/vvc.h b/libavcodec/vvc.h index c4cec1eb8..92639779c 100644 --- a/libavcodec/vvc.h +++ b/libavcodec/vvc.h @@ -151,6 +151,9 @@ enum { // get near that, though, so set a lower limit here with the maximum // possible value for 8K video (at most 135 32x32 Ctb rows). VVC_MAX_ENTRY_POINTS = VVC_MAX_TILE_COLUMNS * 135, + + // {sps, ph}_num_{ver, hor}_virtual_boundaries should in [0, 3] + VVC_MAX_VBS = 3, }; #endif /* AVCODEC_VVC_H */ diff --git a/libavcodec/vvc/Makefile b/libavcodec/vvc/Makefile index 2a0055d49..6a28d32bc 100644 --- a/libavcodec/vvc/Makefile +++ b/libavcodec/vvc/Makefile @@ -1,17 +1,17 @@ clean:: $(RM) $(CLEANSUFFIXES:%=libavcodec/vvc/%) -OBJS-$(CONFIG_VVC_DECODER) += vvc/vvcdec.o \ - vvc/vvcdsp.o \ - vvc/vvc_cabac.o \ - vvc/vvc_ctu.o \ - vvc/vvc_data.o \ - vvc/vvc_filter.o \ - vvc/vvc_inter.o \ - vvc/vvc_intra.o \ - vvc/vvc_intra_utils.o \ - vvc/vvc_itx_1d.o \ - vvc/vvc_mvs.o \ - vvc/vvc_ps.o \ - vvc/vvc_refs.o \ - vvc/vvc_thread.o \ +OBJS-$(CONFIG_VVC_DECODER) += vvc/dec.o \ + vvc/dsp.o \ + vvc/cabac.o \ + vvc/ctu.o \ + vvc/data.o \ + vvc/filter.o \ + vvc/inter.o \ + vvc/intra.o \ + vvc/intra_utils.o \ + vvc/itx_1d.o \ + vvc/mvs.o \ + vvc/ps.o \ + vvc/refs.o \ + vvc/thread.o \ diff --git a/libavcodec/vvc/vvc_cabac.c b/libavcodec/vvc/cabac.c similarity index 99% rename from libavcodec/vvc/vvc_cabac.c rename to libavcodec/vvc/cabac.c index 5e24a1b67..0d45eec75 100644 --- a/libavcodec/vvc/vvc_cabac.c +++ b/libavcodec/vvc/cabac.c @@ -21,9 +21,9 @@ */ #include "libavcodec/cabac_functions.h" -#include "vvc_cabac.h" -#include "vvc_ctu.h" -#include "vvc_data.h" +#include "cabac.h" +#include "ctu.h" +#include "data.h" #define CABAC_MAX_BIN 31 @@ -954,8 +954,8 @@ void get_left_top(const VVCLocalContext *lc, uint8_t *left, uint8_t *top, const VVCFrameContext *fc = lc->fc; const VVCSPS *sps = fc->ps.sps; const int min_cb_width = fc->ps.pps->min_cb_width; - const int x0b = av_mod_uintp2(x0, sps->ctb_log2_size_y); - const int y0b = av_mod_uintp2(y0, sps->ctb_log2_size_y); + const int x0b = av_zero_extend(x0, sps->ctb_log2_size_y); + const int y0b = av_zero_extend(y0, sps->ctb_log2_size_y); const int x_cb = x0 >> sps->min_cb_log2_size_y; const int y_cb = y0 >> sps->min_cb_log2_size_y; @@ -1132,8 +1132,8 @@ static int mtt_split_cu_vertical_flag_decode(VVCLocalContext *lc, const int x0, const VVCFrameContext *fc = lc->fc; const VVCSPS *sps = fc->ps.sps; const int min_cb_width = fc->ps.pps->min_cb_width; - const int x0b = av_mod_uintp2(x0, sps->ctb_log2_size_y); - const int y0b = av_mod_uintp2(y0, sps->ctb_log2_size_y); + const int x0b = av_zero_extend(x0, sps->ctb_log2_size_y); + const int y0b = av_zero_extend(y0, sps->ctb_log2_size_y); const int x_cb = x0 >> sps->min_cb_log2_size_y; const int y_cb = y0 >> sps->min_cb_log2_size_y; const int available_a = lc->ctb_up_flag || y0b; diff --git a/libavcodec/vvc/vvc_cabac.h b/libavcodec/vvc/cabac.h similarity index 98% rename from libavcodec/vvc/vvc_cabac.h rename to libavcodec/vvc/cabac.h index 172ab272f..e9bc98e23 100644 --- a/libavcodec/vvc/vvc_cabac.h +++ b/libavcodec/vvc/cabac.h @@ -20,10 +20,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVC_CABAC_H -#define AVCODEC_VVC_VVC_CABAC_H +#ifndef AVCODEC_VVC_CABAC_H +#define AVCODEC_VVC_CABAC_H -#include "vvc_ctu.h" +#include "ctu.h" int ff_vvc_cabac_init(VVCLocalContext *lc, int ctu_idx, int rx, int ry); @@ -123,4 +123,4 @@ int ff_vvc_end_of_slice_flag_decode(VVCLocalContext *lc); int ff_vvc_end_of_tile_one_bit(VVCLocalContext *lc); int ff_vvc_end_of_subset_one_bit(VVCLocalContext *lc); -#endif //AVCODEC_VVC_VVC_CABAC_H +#endif //AVCODEC_VVC_CABAC_H diff --git a/libavcodec/vvc/vvc_ctu.c b/libavcodec/vvc/ctu.c similarity index 97% rename from libavcodec/vvc/vvc_ctu.c rename to libavcodec/vvc/ctu.c index ffd83e4ea..b33ad576c 100644 --- a/libavcodec/vvc/vvc_ctu.c +++ b/libavcodec/vvc/ctu.c @@ -22,10 +22,10 @@ #include "libavcodec/refstruct.h" -#include "vvc_cabac.h" -#include "vvc_ctu.h" -#include "vvc_inter.h" -#include "vvc_mvs.h" +#include "cabac.h" +#include "ctu.h" +#include "inter.h" +#include "mvs.h" #define PROF_TEMP_SIZE (PROF_BLOCK_SIZE) * sizeof(int16_t) @@ -87,10 +87,10 @@ static int get_qp_y_pred(const VVCLocalContext *lc) const int min_cb_width = fc->ps.pps->min_cb_width; const int x_cb = cu->x0 >> sps->min_cb_log2_size_y; const int y_cb = cu->y0 >> sps->min_cb_log2_size_y; - const int x_ctb = cu->x0 >> ctb_log2_size; - const int y_ctb = cu->y0 >> ctb_log2_size; - const int in_same_ctb_a = ((xQg - 1) >> ctb_log2_size) == x_ctb && (yQg >> ctb_log2_size) == y_ctb; - const int in_same_ctb_b = (xQg >> ctb_log2_size) == x_ctb && ((yQg - 1) >> ctb_log2_size) == y_ctb; + const int rx = cu->x0 >> ctb_log2_size; + const int ry = cu->y0 >> ctb_log2_size; + const int in_same_ctb_a = ((xQg - 1) >> ctb_log2_size) == rx && (yQg >> ctb_log2_size) == ry; + const int in_same_ctb_b = (xQg >> ctb_log2_size) == rx && ((yQg - 1) >> ctb_log2_size) == ry; int qPy_pred, qPy_a, qPy_b; if (lc->na.cand_up) { @@ -115,8 +115,8 @@ static int get_qp_y_pred(const VVCLocalContext *lc) else qPy_a = fc->tab.qp[LUMA][(x_cb - 1) + y_cb * min_cb_width]; - av_assert2(qPy_a >= -fc->ps.sps->qp_bd_offset && qPy_a < 63); - av_assert2(qPy_b >= -fc->ps.sps->qp_bd_offset && qPy_b < 63); + av_assert2(qPy_a >= -fc->ps.sps->qp_bd_offset && qPy_a <= 63); + av_assert2(qPy_b >= -fc->ps.sps->qp_bd_offset && qPy_b <= 63); return (qPy_a + qPy_b + 1) >> 1; } @@ -713,8 +713,8 @@ static enum IntraPredMode luma_intra_pred_mode(VVCLocalContext* lc, const int in const int x_b = (x0 + cu->cb_width - 1) >> sps->min_cb_log2_size_y; const int y_b = (y0 - 1) >> sps->min_cb_log2_size_y; int min_cb_width = fc->ps.pps->min_cb_width; - int x0b = av_mod_uintp2(x0, sps->ctb_log2_size_y); - int y0b = av_mod_uintp2(y0, sps->ctb_log2_size_y); + int x0b = av_zero_extend(x0, sps->ctb_log2_size_y); + int y0b = av_zero_extend(y0, sps->ctb_log2_size_y); const int available_l = lc->ctb_left_flag || x0b; const int available_u = lc->ctb_up_flag || y0b; @@ -1081,10 +1081,13 @@ static PredMode pred_mode_decode(VVCLocalContext *lc, if (pred_mode_ibc_flag) pred_mode = MODE_IBC; } else { - pred_mode_flag = is_4x4 || mode_type == MODE_TYPE_INTRA || - mode_type != MODE_TYPE_INTER || IS_I(rsh); - pred_mode = pred_mode_flag ? MODE_INTRA : MODE_INTER; + pred_mode = MODE_INTRA; } + + 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); + return pred_mode; } @@ -1176,7 +1179,7 @@ static CodingUnit* alloc_cu(VVCLocalContext *lc, const int x0, const int y0) const VVCPPS *pps = fc->ps.pps; const int rx = x0 >> sps->ctb_log2_size_y; const int ry = y0 >> sps->ctb_log2_size_y; - CTU *ctu = fc->tab.ctus + ry * pps->ctb_width + rx; + CodingUnit **cus = fc->tab.cus + ry * pps->ctb_width + rx; CodingUnit *cu = ff_refstruct_pool_get(fc->cu_pool); if (!cu) @@ -1186,7 +1189,7 @@ static CodingUnit* alloc_cu(VVCLocalContext *lc, const int x0, const int y0) if (lc->cu) lc->cu->next = cu; else - ctu->cus = cu; + *cus = cu; lc->cu = cu; return cu; @@ -1231,15 +1234,14 @@ static CodingUnit* add_cu(VVCLocalContext *lc, const int x0, const int y0, static void set_cu_tabs(const VVCLocalContext *lc, const CodingUnit *cu) { - const VVCFrameContext *fc = lc->fc; - const TransformUnit *tu = cu->tus.head; + const VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &cu->pu; + const TransformUnit *tu = cu->tus.head; - if (cu->tree_type != DUAL_TREE_CHROMA) { - set_cb_tab(lc, fc->tab.cpm[LUMA], cu->pred_mode); + 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) set_cb_tab(lc, fc->tab.skip, cu->skip_flag); - } - if (fc->ps.sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA) - set_cb_tab(lc, fc->tab.cpm[CHROMA], cu->pred_mode); while (tu) { for (int j = 0; j < tu->nb_tbs; j++) { @@ -1263,8 +1265,8 @@ static void derive_mmvd(const VVCLocalContext *lc, MvField *mvf, const Mv *mmvd_ const RefPicList *rpl = sc->rpl; const int poc = lc->fc->ps.ph.poc; const int diff[] = { - poc - rpl[0].list[mvf->ref_idx[0]], - poc - rpl[1].list[mvf->ref_idx[1]] + poc - rpl[L0].refs[mvf->ref_idx[L0]].poc, + poc - rpl[L1].refs[mvf->ref_idx[L1]].poc }; const int sign = FFSIGN(diff[0]) != FFSIGN(diff[1]); @@ -1275,7 +1277,7 @@ static void derive_mmvd(const VVCLocalContext *lc, MvField *mvf, const Mv *mmvd_ const int i = FFABS(diff[0]) < FFABS(diff[1]); const int o = !i; mmvd[i] = *mmvd_offset; - if (!rpl[0].isLongTerm[mvf->ref_idx[0]] && !rpl[1].isLongTerm[mvf->ref_idx[1]]) { + if (!rpl[L0].refs[mvf->ref_idx[L0]].is_lt && !rpl[L1].refs[mvf->ref_idx[L1]].is_lt) { ff_vvc_mv_scale(&mmvd[o], mmvd_offset, diff[i], diff[o]); } else { @@ -1326,7 +1328,6 @@ static void merge_data_subblock(VVCLocalContext *lc) PredictionUnit *pu = &cu->pu; int merge_subblock_idx = 0; - set_cb_tab(lc, fc->tab.msf, pu->merge_subblock_flag); if (ph->max_num_subblock_merge_cand > 1) { merge_subblock_idx = ff_vvc_merge_subblock_idx(lc, ph->max_num_subblock_merge_cand); } @@ -1444,20 +1445,25 @@ static void merge_data_block(VVCLocalContext *lc) } } -static void merge_data_ibc(VVCLocalContext *lc) +static int merge_data_ibc(VVCLocalContext *lc) { const VVCFrameContext* fc = lc->fc; const VVCSPS* sps = fc->ps.sps; MotionInfo *mi = &lc->cu->pu.mi; int merge_idx = 0; + int ret; mi->pred_flag = PF_IBC; if (sps->max_num_ibc_merge_cand > 1) merge_idx = ff_vvc_merge_idx(lc); - ff_vvc_luma_mv_merge_ibc(lc, merge_idx, &mi->mv[L0][0]); + ret = ff_vvc_luma_mv_merge_ibc(lc, merge_idx, &mi->mv[L0][0]); + if (ret) + return ret; ff_vvc_store_mv(lc, mi); + + return 0; } static int hls_merge_data(VVCLocalContext *lc) @@ -1466,11 +1472,14 @@ static int hls_merge_data(VVCLocalContext *lc) const VVCPH *ph = &fc->ps.ph; const CodingUnit *cu = lc->cu; PredictionUnit *pu = &lc->cu->pu; + int ret; pu->merge_gpm_flag = 0; pu->mi.num_sb_x = pu->mi.num_sb_y = 1; if (cu->pred_mode == MODE_IBC) { - merge_data_ibc(lc); + ret = merge_data_ibc(lc); + if (ret) + return ret; } else { if (ph->max_num_subblock_merge_cand > 0 && cu->cb_width >= 8 && cu->cb_height >= 8) pu->merge_subblock_flag = ff_vvc_merge_subblock_flag(lc); @@ -1596,6 +1605,7 @@ static int mvp_data_ibc(VVCLocalContext *lc) int mvp_l0_flag = 0; int amvr_shift = 4; Mv *mv = &mi->mv[L0][0]; + int ret; mi->pred_flag = PF_IBC; mi->num_sb_x = 1; @@ -1607,7 +1617,9 @@ static int mvp_data_ibc(VVCLocalContext *lc) if (sps->r->sps_amvr_enabled_flag && (mv->x || mv->y)) amvr_shift = ff_vvc_amvr_shift(lc, pu->inter_affine_flag, cu->pred_mode, 1); - ff_vvc_mvp_ibc(lc, mvp_l0_flag, amvr_shift, mv); + ret = ff_vvc_mvp_ibc(lc, mvp_l0_flag, amvr_shift, mv); + if (ret) + return ret; ff_vvc_store_mv(lc, mi); return 0; @@ -1689,25 +1701,25 @@ static void derive_dmvr_bdof_flag(const VVCLocalContext *lc, PredictionUnit *pu) const VVCPH *ph = &fc->ps.ph; const VVCSH *sh = &lc->sc->sh; const int poc = ph->poc; - const RefPicList *rpl0 = lc->sc->rpl + L0; - const RefPicList *rpl1 = lc->sc->rpl + L1; - const int8_t *ref_idx = pu->mi.ref_idx; const MotionInfo *mi = &pu->mi; + const int8_t *ref_idx = mi->ref_idx; + const VVCRefPic *rp0 = &lc->sc->rpl[L0].refs[ref_idx[L0]]; + const VVCRefPic *rp1 = &lc->sc->rpl[L1].refs[ref_idx[L1]]; const CodingUnit *cu = lc->cu; const PredWeightTable *w = pps->r->pps_wp_info_in_ph_flag ? &fc->ps.ph.pwt : &sh->pwt; pu->bdof_flag = 0; if (mi->pred_flag == PF_BI && - (poc - rpl0->list[ref_idx[L0]] == rpl1->list[ref_idx[L1]] - poc) && - !rpl0->isLongTerm[ref_idx[L0]] && !rpl1->isLongTerm[ref_idx[L1]] && + (poc - rp0->poc == rp1->poc - poc) && + !rp0->is_lt && !rp1->is_lt && !cu->ciip_flag && !mi->bcw_idx && - !w->weight_flag[L0][LUMA][mi->ref_idx[L0]] && !w->weight_flag[L1][LUMA][mi->ref_idx[L1]] && - !w->weight_flag[L0][CHROMA][mi->ref_idx[L0]] && !w->weight_flag[L1][CHROMA][mi->ref_idx[L1]] && + !w->weight_flag[L0][LUMA][ref_idx[L0]] && !w->weight_flag[L1][LUMA][ref_idx[L1]] && + !w->weight_flag[L0][CHROMA][ref_idx[L0]] && !w->weight_flag[L1][CHROMA][ref_idx[L1]] && cu->cb_width >= 8 && cu->cb_height >= 8 && - (cu->cb_width * cu->cb_height >= 128)) { - // fixme: for RprConstraintsActiveFlag + (cu->cb_width * cu->cb_height >= 128) && + !rp0->is_scaled && !rp1->is_scaled) { if (!ph->r->ph_bdof_disabled_flag && mi->motion_model_idc == MOTION_TRANSLATION && !pu->merge_subblock_flag && @@ -2420,7 +2432,9 @@ static void ctu_get_pred(VVCLocalContext *lc, const int rs) const VVCFrameContext *fc = lc->fc; const H266RawSliceHeader *rsh = lc->sc->sh.r; CTU *ctu = fc->tab.ctus + rs; - const CodingUnit *cu = ctu->cus; + const CodingUnit *cu = fc->tab.cus[rs]; + + ctu->has_dmvr = 0; if (IS_I(rsh)) return; @@ -2491,6 +2505,10 @@ void ff_vvc_decode_neighbour(VVCLocalContext *lc, const int x_ctb, const int y_c lc->boundary_flags |= BOUNDARY_UPPER_TILE; if (ry > 0 && fc->tab.slice_idx[rs] != fc->tab.slice_idx[rs - fc->ps.pps->ctb_width]) lc->boundary_flags |= BOUNDARY_UPPER_SLICE; + if (fc->ps.sps->r->sps_subpic_ctu_top_left_x[lc->sc->sh.r->curr_subpic_idx] == rx) + lc->boundary_flags |= BOUNDARY_LEFT_SUBPIC; + if (fc->ps.sps->r->sps_subpic_ctu_top_left_y[lc->sc->sh.r->curr_subpic_idx] == ry) + lc->boundary_flags |= BOUNDARY_UPPER_SUBPIC; lc->ctb_left_flag = rx > 0 && !(lc->boundary_flags & BOUNDARY_LEFT_TILE); lc->ctb_up_flag = ry > 0 && !(lc->boundary_flags & BOUNDARY_UPPER_TILE) && !(lc->boundary_flags & BOUNDARY_UPPER_SLICE); lc->ctb_up_right_flag = lc->ctb_up_flag && (fc->ps.pps->ctb_to_col_bd[rx] == fc->ps.pps->ctb_to_col_bd[rx + 1]) && @@ -2502,8 +2520,8 @@ void ff_vvc_set_neighbour_available(VVCLocalContext *lc, const int x0, const int y0, const int w, const int h) { const int log2_ctb_size = lc->fc->ps.sps->ctb_log2_size_y; - const int x0b = av_mod_uintp2(x0, log2_ctb_size); - const int y0b = av_mod_uintp2(y0, log2_ctb_size); + const int x0b = av_zero_extend(x0, log2_ctb_size); + const int y0b = av_zero_extend(y0, log2_ctb_size); lc->na.cand_up = (lc->ctb_up_flag || y0b); lc->na.cand_left = (lc->ctb_left_flag || x0b); @@ -2513,9 +2531,8 @@ void ff_vvc_set_neighbour_available(VVCLocalContext *lc, lc->na.cand_up_right = lc->na.cand_up_right_sap && (x0 + w) < lc->end_of_tiles_x; } -void ff_vvc_ctu_free_cus(CTU *ctu) +void ff_vvc_ctu_free_cus(CodingUnit **cus) { - CodingUnit **cus = &ctu->cus; while (*cus) { CodingUnit *cu = *cus; TransformUnit **head = &cu->tus.head; diff --git a/libavcodec/vvc/vvc_ctu.h b/libavcodec/vvc/ctu.h similarity index 93% rename from libavcodec/vvc/vvc_ctu.h rename to libavcodec/vvc/ctu.h index 8020e184c..eab461256 100644 --- a/libavcodec/vvc/vvc_ctu.h +++ b/libavcodec/vvc/ctu.h @@ -20,13 +20,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVC_CTU_H -#define AVCODEC_VVC_VVC_CTU_H +#ifndef AVCODEC_VVC_CTU_H +#define AVCODEC_VVC_CTU_H #include "libavcodec/cabac.h" #include "libavutil/mem_internal.h" -#include "vvcdec.h" +#include "dec.h" #define MAX_CTU_SIZE 128 @@ -46,7 +46,8 @@ #define MAX_QP 63 #define MAX_PB_SIZE 128 -#define EDGE_EMU_BUFFER_STRIDE (MAX_PB_SIZE + 32) +#define MAX_SCALING_RATIO 8 +#define EDGE_EMU_BUFFER_STRIDE ((MAX_PB_SIZE + 32) * MAX_SCALING_RATIO) #define CHROMA_EXTRA_BEFORE 1 #define CHROMA_EXTRA_AFTER 2 @@ -58,6 +59,8 @@ #define BILINEAR_EXTRA_AFTER 1 #define BILINEAR_EXTRA 1 +#define SCALED_INT(pos) ((pos) >> 10) + #define MAX_CONTROL_POINTS 3 #define AFFINE_MIN_BLOCK_SIZE 4 @@ -326,7 +329,6 @@ typedef struct CodingUnit { } CodingUnit; typedef struct CTU { - CodingUnit *cus; int max_y[2][VVC_MAX_REF_ENTRIES]; int max_y_idx[2]; int has_dmvr; @@ -373,15 +375,12 @@ typedef struct VVCLocalContext { int end_of_tiles_x; int end_of_tiles_y; - /* +7 is for subpixel interpolation, *2 for high bit depths */ - DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2]; - /* The extended size between the new edge emu buffer is abused by SAO */ - DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer2)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2]; + /* *2 for high bit depths */ + DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[EDGE_EMU_BUFFER_STRIDE * EDGE_EMU_BUFFER_STRIDE * 2]; DECLARE_ALIGNED(32, int16_t, tmp)[MAX_PB_SIZE * MAX_PB_SIZE]; DECLARE_ALIGNED(32, int16_t, tmp1)[MAX_PB_SIZE * MAX_PB_SIZE]; DECLARE_ALIGNED(32, int16_t, tmp2)[MAX_PB_SIZE * MAX_PB_SIZE]; - DECLARE_ALIGNED(32, uint8_t, ciip_tmp1)[MAX_PB_SIZE * MAX_PB_SIZE * 2]; - DECLARE_ALIGNED(32, uint8_t, ciip_tmp2)[MAX_PB_SIZE * MAX_PB_SIZE * 2]; + DECLARE_ALIGNED(32, uint8_t, ciip_tmp)[MAX_PB_SIZE * MAX_PB_SIZE * 2]; DECLARE_ALIGNED(32, uint8_t, sao_buffer)[(MAX_CTU_SIZE + 2 * SAO_PADDING_SIZE) * EDGE_EMU_BUFFER_STRIDE * 2]; DECLARE_ALIGNED(32, uint8_t, alf_buffer_luma)[(MAX_CTU_SIZE + 2 * ALF_PADDING_SIZE) * EDGE_EMU_BUFFER_STRIDE * 2]; DECLARE_ALIGNED(32, uint8_t, alf_buffer_chroma)[(MAX_CTU_SIZE + 2 * ALF_PADDING_SIZE) * EDGE_EMU_BUFFER_STRIDE * 2]; @@ -421,8 +420,10 @@ typedef struct VVCLocalContext { #define BOUNDARY_LEFT_SLICE (1 << 0) #define BOUNDARY_LEFT_TILE (1 << 1) -#define BOUNDARY_UPPER_SLICE (1 << 2) -#define BOUNDARY_UPPER_TILE (1 << 3) +#define BOUNDARY_LEFT_SUBPIC (1 << 2) +#define BOUNDARY_UPPER_SLICE (1 << 3) +#define BOUNDARY_UPPER_TILE (1 << 4) +#define BOUNDARY_UPPER_SUBPIC (1 << 5) /* properties of the boundary of the current CTB for the purposes * of the deblocking filter */ int boundary_flags; @@ -459,10 +460,15 @@ typedef struct ALFParams { uint8_t ctb_filt_set_idx_y; ///< AlfCtbFiltSetIdxY uint8_t alf_ctb_filter_alt_idx[2]; ///< alf_ctb_filter_alt_idx[] uint8_t ctb_cc_idc[2]; ///< alf_ctb_cc_cb_idc, alf_ctb_cc_cr_idc - - uint8_t applied[3]; } ALFParams; +typedef struct VVCRect { + int l; // left + int t; // top + int r; // right + int b; // bottom +} VVCRect; + /** * parse a CTU * @param lc local context for CTU @@ -477,8 +483,8 @@ int ff_vvc_coding_tree_unit(VVCLocalContext *lc, int ctu_idx, int rs, int rx, in //utils void ff_vvc_set_neighbour_available(VVCLocalContext *lc, int x0, int y0, int w, int h); void ff_vvc_decode_neighbour(VVCLocalContext *lc, int x_ctb, int y_ctb, int rx, int ry, int rs); -void ff_vvc_ctu_free_cus(CTU *ctu); +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); -#endif // AVCODEC_VVC_VVC_CTU_H +#endif // AVCODEC_VVC_CTU_H diff --git a/libavcodec/vvc/vvc_data.c b/libavcodec/vvc/data.c similarity index 99% rename from libavcodec/vvc/vvc_data.c rename to libavcodec/vvc/data.c index 0c9376d09..a91e20754 100644 --- a/libavcodec/vvc/vvc_data.c +++ b/libavcodec/vvc/data.c @@ -22,7 +22,7 @@ #include "libavutil/avassert.h" -#include "vvc_data.h" +#include "data.h" const uint8_t ff_vvc_diag_scan_x[5][5][16*16] = { { @@ -1732,7 +1732,7 @@ const uint8_t ff_vvc_alf_aps_class_to_filt_map[25] = { 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, }; -const int8_t ff_vvc_inter_luma_filters[VVC_INTER_FILTER_TYPES][VVC_INTER_LUMA_FACTS][VVC_INTER_LUMA_TAPS] = { +const int8_t ff_vvc_inter_luma_filters[VVC_INTER_LUMA_FILTER_TYPES][VVC_INTER_LUMA_FACTS][VVC_INTER_LUMA_TAPS] = { { //1x, hpelIfIdx == 0, Table 27 { 0, 0, 0, 64, 0, 0, 0, 0 }, @@ -1773,6 +1773,46 @@ const int8_t ff_vvc_inter_luma_filters[VVC_INTER_FILTER_TYPES][VVC_INTER_LUMA_FA { 0, 1, -2, 4, 63, -3, 1, 0 }, }, + { + //1.5x, Table 28 + { -1, -5, 17, 42, 17, -5, -1, 0 }, + { 0, -5, 15, 41, 19, -5, -1, 0 }, + { 0, -5, 13, 40, 21, -4, -1, 0 }, + { 0, -5, 11, 39, 24, -4, -2, 1 }, + { 0, -5, 9, 38, 26, -3, -2, 1 }, + { 0, -5, 7, 38, 28, -2, -3, 1 }, + { 1, -5, 5, 36, 30, -1, -3, 1 }, + { 1, -4, 3, 35, 32, 0, -4, 1 }, + { 1, -4, 2, 33, 33, 2, -4, 1 }, + { 1, -4, 0, 32, 35, 3, -4, 1 }, + { 1, -3, -1, 30, 36, 5, -5, 1 }, + { 1, -3, -2, 28, 38, 7, -5, 0 }, + { 1, -2, -3, 26, 38, 9, -5, 0 }, + { 1, -2, -4, 24, 39, 11, -5, 0 }, + { 0, -1, -4, 21, 40, 13, -5, 0 }, + { 0, -1, -5, 19, 41, 15, -5, 0 }, + }, + + { + //2x, Table 29 + { -4, 2, 20, 28, 20, 2, -4, 0 }, + { -4, 0, 19, 29, 21, 5, -4, -2 }, + { -4, -1, 18, 29, 22, 6, -4, -2 }, + { -4, -1, 16, 29, 23, 7, -4, -2 }, + { -4, -1, 16, 28, 24, 7, -4, -2 }, + { -4, -1, 14, 28, 25, 8, -4, -2 }, + { -3, -3, 14, 27, 26, 9, -3, -3 }, + { -3, -1, 12, 28, 25, 10, -4, -3 }, + { -3, -3, 11, 27, 27, 11, -3, -3 }, + { -3, -4, 10, 25, 28, 12, -1, -3 }, + { -3, -3, 9, 26, 27, 14, -3, -3 }, + { -2, -4, 8, 25, 28, 14, -1, -4 }, + { -2, -4, 7, 24, 28, 16, -1, -4 }, + { -2, -4, 7, 23, 29, 16, -1, -4 }, + { -2, -4, 6, 22, 29, 18, -1, -4 }, + { -2, -4, 5, 21, 29, 19, 0, -4 }, + }, + { //1x, affine, Table 30 { 0, 0, 0, 64, 0, 0, 0, 0 }, @@ -1793,9 +1833,48 @@ const int8_t ff_vvc_inter_luma_filters[VVC_INTER_FILTER_TYPES][VVC_INTER_LUMA_FA { 0, 1, -2, 4, 63, -3, 1, 0 }, }, + { + //1.5x, affine, Table 31 + { 0, -6, 17, 42, 17, -5, -1, 0 }, + { 0, -5, 15, 41, 19, -5, -1, 0 }, + { 0, -5, 13, 40, 21, -4, -1, 0 }, + { 0, -5, 11, 39, 24, -4, -1, 0 }, + { 0, -5, 9, 38, 26, -3, -1, 0 }, + { 0, -5, 7, 38, 28, -2, -2, 0 }, + { 0, -4, 5, 36, 30, -1, -2, 0 }, + { 0, -3, 3, 35, 32, 0, -3, 0 }, + { 0, -3, 2, 33, 33, 2, -3, 0 }, + { 0, -3, 0, 32, 35, 3, -3, 0 }, + { 0, -2, -1, 30, 36, 5, -4, 0 }, + { 0, -2, -2, 28, 38, 7, -5, 0 }, + { 0, -1, -3, 26, 38, 9, -5, 0 }, + { 0, -1, -4, 24, 39, 11, -5, 0 }, + { 0, -1, -4, 21, 40, 13, -5, 0 }, + { 0, -1, -5, 19, 41, 15, -5, 0 }, + }, + + { + //2x, affine, Table 32 + { 0, -2, 20, 28, 20, 2, -4, 0 }, + { 0, -4, 19, 29, 21, 5, -6, 0 }, + { 0, -5, 18, 29, 22, 6, -6, 0 }, + { 0, -5, 16, 29, 23, 7, -6, 0 }, + { 0, -5, 16, 28, 24, 7, -6, 0 }, + { 0, -5, 14, 28, 25, 8, -6, 0 }, + { 0, -6, 14, 27, 26, 9, -6, 0 }, + { 0, -4, 12, 28, 25, 10, -7, 0 }, + { 0, -6, 11, 27, 27, 11, -6, 0 }, + { 0, -7, 10, 25, 28, 12, -4, 0 }, + { 0, -6, 9, 26, 27, 14, -6, 0 }, + { 0, -6, 8, 25, 28, 14, -5, 0 }, + { 0, -6, 7, 24, 28, 16, -5, 0 }, + { 0, -6, 7, 23, 29, 16, -5, 0 }, + { 0, -6, 6, 22, 29, 18, -5, 0 }, + { 0, -6, 5, 21, 29, 19, -4, 0 }, + } }; -const int8_t ff_vvc_inter_chroma_filters[VVC_INTER_FILTER_TYPES][VVC_INTER_CHROMA_FACTS][VVC_INTER_CHROMA_TAPS] = { +const int8_t ff_vvc_inter_chroma_filters[VVC_INTER_CHROMA_FILTER_TYPES][VVC_INTER_CHROMA_FACTS][VVC_INTER_CHROMA_TAPS] = { { //1x, Table 33 { 0, 64, 0, 0 }, diff --git a/libavcodec/vvc/vvc_data.h b/libavcodec/vvc/data.h similarity index 87% rename from libavcodec/vvc/vvc_data.h rename to libavcodec/vvc/data.h index 1f9a463bc..a0512e626 100644 --- a/libavcodec/vvc/vvc_data.h +++ b/libavcodec/vvc/data.h @@ -18,8 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVC_DATA_H -#define AVCODEC_VVC_VVC_DATA_H +#ifndef AVCODEC_VVC_DATA_H +#define AVCODEC_VVC_DATA_H #include @@ -43,15 +43,19 @@ extern const int8_t ff_vvc_lfnst_8x8[4][2][16][48]; extern const uint8_t ff_vvc_lfnst_tr_set_index[95]; extern uint8_t ff_vvc_default_scale_m[64 * 64]; -#define VVC_INTER_FILTER_TYPES 3 +#define VVC_INTER_LUMA_FILTER_TYPE_AFFINE 4 + +#define VVC_INTER_LUMA_FILTER_TYPES 7 +#define VVC_INTER_CHROMA_FILTER_TYPES 3 + #define VVC_INTER_LUMA_FACTS 16 #define VVC_INTER_LUMA_TAPS 8 #define VVC_INTER_CHROMA_FACTS 32 #define VVC_INTER_CHROMA_TAPS 4 #define VVC_INTER_LUMA_DMVR_FACTS 16 #define VVC_INTER_LUMA_DMVR_TAPS 2 -extern const int8_t ff_vvc_inter_luma_filters[VVC_INTER_FILTER_TYPES][VVC_INTER_LUMA_FACTS][VVC_INTER_LUMA_TAPS]; -extern const int8_t ff_vvc_inter_chroma_filters[VVC_INTER_FILTER_TYPES][VVC_INTER_CHROMA_FACTS][VVC_INTER_CHROMA_TAPS]; +extern const int8_t ff_vvc_inter_luma_filters[VVC_INTER_LUMA_FILTER_TYPES][VVC_INTER_LUMA_FACTS][VVC_INTER_LUMA_TAPS]; +extern const int8_t ff_vvc_inter_chroma_filters[VVC_INTER_CHROMA_FILTER_TYPES][VVC_INTER_CHROMA_FACTS][VVC_INTER_CHROMA_TAPS]; extern const int8_t ff_vvc_inter_luma_dmvr_filters[VVC_INTER_LUMA_DMVR_FACTS][VVC_INTER_LUMA_DMVR_TAPS]; #define VVC_INTRA_LUMA_TYPES 2 @@ -77,4 +81,4 @@ 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); -#endif /* AVCODEC_VVC_VVC_DATA_H */ +#endif /* AVCODEC_VVC_DATA_H */ diff --git a/libavcodec/vvc/vvcdec.c b/libavcodec/vvc/dec.c similarity index 89% rename from libavcodec/vvc/vvcdec.c rename to libavcodec/vvc/dec.c index ccb1b5986..edf2607f5 100644 --- a/libavcodec/vvc/vvcdec.c +++ b/libavcodec/vvc/dec.c @@ -25,13 +25,14 @@ #include "libavcodec/profiles.h" #include "libavcodec/refstruct.h" #include "libavutil/cpu.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" -#include "vvcdec.h" -#include "vvc_ctu.h" -#include "vvc_data.h" -#include "vvc_refs.h" -#include "vvc_thread.h" +#include "dec.h" +#include "ctu.h" +#include "data.h" +#include "refs.h" +#include "thread.h" #define TAB_MAX 32 @@ -81,7 +82,13 @@ static int tl_create(TabList *l) if (!*t->tab) return AVERROR(ENOMEM); } - } else if (l->zero) { + } + return 0; +} + +static int tl_zero(TabList *l) +{ + if (l->zero) { for (int i = 0; i < l->nb_tabs; i++) { Tab *t = l->tabs + i; memset(*t->tab, 0, t->size); @@ -90,20 +97,6 @@ static int tl_create(TabList *l) return 0; } -static void ctu_tl_init(TabList *l, VVCFrameContext *fc) -{ - const VVCPPS *pps = fc->ps.pps; - const int ctu_count = pps ? pps->ctb_count : 0; - const int changed = fc->tab.sz.ctu_count != ctu_count; - - tl_init(l, 1, changed); - - TL_ADD(deblock, ctu_count); - TL_ADD(sao, ctu_count); - TL_ADD(alf, ctu_count); - TL_ADD(ctus, ctu_count); -} - static void ctu_nz_tl_init(TabList *l, VVCFrameContext *fc) { const VVCSPS *sps = fc->ps.sps; @@ -113,6 +106,12 @@ static void ctu_nz_tl_init(TabList *l, VVCFrameContext *fc) const int changed = fc->tab.sz.ctu_count != ctu_count || fc->tab.sz.ctu_size != ctu_size; tl_init(l, 0, changed); + + TL_ADD(cus, ctu_count); + TL_ADD(ctus, ctu_count); + TL_ADD(deblock, ctu_count); + TL_ADD(sao, ctu_count); + TL_ADD(alf, ctu_count); TL_ADD(slice_idx, ctu_count); TL_ADD(coeffs, ctu_count * ctu_size * VVC_MAX_SAMPLE_ARRAYS); } @@ -125,21 +124,35 @@ static void min_cb_tl_init(TabList *l, VVCFrameContext *fc) tl_init(l, 1, changed); - TL_ADD(skip, pic_size_in_min_cb); TL_ADD(imf, pic_size_in_min_cb); - TL_ADD(imtf, 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 +} + +static void min_cb_nz_tl_init(TabList *l, VVCFrameContext *fc) +{ + const VVCPPS *pps = fc->ps.pps; + const int pic_size_in_min_cb = pps ? pps->min_cb_width * pps->min_cb_height : 0; + const int changed = fc->tab.sz.pic_size_in_min_cb != pic_size_in_min_cb; + + 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++) { + TL_ADD(cqt_depth[i], pic_size_in_min_cb); TL_ADD(cb_pos_x[i], pic_size_in_min_cb); TL_ADD(cb_pos_y[i], pic_size_in_min_cb); - TL_ADD(cb_width[i], pic_size_in_min_cb); TL_ADD(cb_height[i], pic_size_in_min_cb); - TL_ADD(cqt_depth[i], pic_size_in_min_cb); - TL_ADD(cpm[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); + } + // 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); } static void min_pu_tl_init(TabList *l, VVCFrameContext *fc) @@ -150,8 +163,18 @@ static void min_pu_tl_init(TabList *l, VVCFrameContext *fc) tl_init(l, 1, changed); - TL_ADD(msf, pic_size_in_min_pu); TL_ADD(iaf, pic_size_in_min_pu); +} + +static void min_pu_nz_tl_init(TabList *l, VVCFrameContext *fc) +{ + const VVCPPS *pps = fc->ps.pps; + const int pic_size_in_min_pu = pps ? pps->min_pu_width * pps->min_pu_height : 0; + const int changed = fc->tab.sz.pic_size_in_min_pu != pic_size_in_min_pu; + + tl_init(l, 0, changed); + + TL_ADD(msf, pic_size_in_min_pu); TL_ADD(mmi, pic_size_in_min_pu); TL_ADD(mvf, pic_size_in_min_pu); } @@ -165,39 +188,41 @@ static void min_tu_tl_init(TabList *l, VVCFrameContext *fc) tl_init(l, 1, changed); 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); + + for (int vertical = 0; vertical < 2; vertical++) + TL_ADD(bs[vertical][i], pic_size_in_min_tu); + } +} + +static void min_tu_nz_tl_init(TabList *l, VVCFrameContext *fc) +{ + const VVCPPS *pps = fc->ps.pps; + const int pic_size_in_min_tu = pps ? pps->min_tu_width * pps->min_tu_height : 0; + const int changed = fc->tab.sz.pic_size_in_min_tu != pic_size_in_min_tu; + + 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); - 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); - TL_ADD(qp[i], pic_size_in_min_tu); + for (int vertical = 0; vertical < 2; vertical++) { + TL_ADD(max_len_p[vertical], pic_size_in_min_tu); + TL_ADD(max_len_q[vertical], pic_size_in_min_tu); } -} -static void bs_tl_init(TabList *l, VVCFrameContext *fc) -{ - const VVCPPS *pps = fc->ps.pps; - const int bs_width = pps ? (pps->width >> 2) + 1 : 0; - const int bs_height = pps ? (pps->height >> 2) + 1 : 0; - const int bs_count = bs_width * bs_height; - const int changed = fc->tab.sz.bs_width != bs_width || - fc->tab.sz.bs_height != bs_height; - - tl_init(l, 1, changed); - - for (int i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++) { - TL_ADD(horizontal_bs[i], bs_count); - TL_ADD(vertical_bs[i], bs_count); - } - TL_ADD(horizontal_q, bs_count); - TL_ADD(horizontal_p, bs_count); - TL_ADD(vertical_p, bs_count); - TL_ADD(vertical_q, bs_count); + // For chroma, considering the joint CbCr, the QP tab size is related to the TU. + for (int i = CB; i < VVC_MAX_SAMPLE_ARRAYS; i++) + TL_ADD(qp[i], pic_size_in_min_tu); } static void pixel_buffer_nz_tl_init(TabList *l, VVCFrameContext *fc) @@ -213,7 +238,8 @@ static void pixel_buffer_nz_tl_init(TabList *l, VVCFrameContext *fc) const int c_end = chroma_idc ? VVC_MAX_SAMPLE_ARRAYS : 1; const int changed = fc->tab.sz.chroma_format_idc != chroma_idc || fc->tab.sz.width != width || fc->tab.sz.height != height || - fc->tab.sz.ctu_width != ctu_width || fc->tab.sz.ctu_height != ctu_height; + fc->tab.sz.ctu_width != ctu_width || fc->tab.sz.ctu_height != ctu_height || + fc->tab.sz.pixel_shift != ps; tl_init(l, 0, changed); @@ -292,12 +318,13 @@ typedef void (*tl_init_fn)(TabList *l, VVCFrameContext *fc); static int frame_context_for_each_tl(VVCFrameContext *fc, int (*unary_fn)(TabList *l)) { const tl_init_fn init[] = { - ctu_tl_init, ctu_nz_tl_init, min_cb_tl_init, + min_cb_nz_tl_init, min_pu_tl_init, + min_pu_nz_tl_init, min_tu_tl_init, - bs_tl_init, + min_tu_nz_tl_init, pixel_buffer_nz_tl_init, msm_tl_init, ispmf_tl_init, @@ -318,9 +345,9 @@ static int frame_context_for_each_tl(VVCFrameContext *fc, int (*unary_fn)(TabLis static void free_cus(VVCFrameContext *fc) { - if (fc->tab.ctus) { + if (fc->tab.cus) { for (int i = 0; i < fc->tab.sz.ctu_count; i++) - ff_vvc_ctu_free_cus(fc->tab.ctus + i); + ff_vvc_ctu_free_cus(fc->tab.cus + i); } } @@ -348,6 +375,9 @@ static int pic_arrays_init(VVCContext *s, VVCFrameContext *fc) if (ret < 0) return ret; + // for error handling case, we may call free_cus before VVC_TASK_STAGE_INIT, so we need to set cus to 0 here + memset(fc->tab.cus, 0, sizeof(*fc->tab.cus) * ctu_count); + memset(fc->tab.slice_idx, -1, sizeof(*fc->tab.slice_idx) * ctu_count); if (fc->tab.sz.ctu_count != ctu_count) { @@ -376,12 +406,15 @@ static int pic_arrays_init(VVCContext *s, VVCFrameContext *fc) fc->tab.sz.ctu_height = pps->ctb_height; fc->tab.sz.chroma_format_idc = sps->r->sps_chroma_format_idc; fc->tab.sz.pixel_shift = sps->pixel_shift; - fc->tab.sz.bs_width = (fc->ps.pps->width >> 2) + 1; - fc->tab.sz.bs_height = (fc->ps.pps->height >> 2) + 1; return 0; } +int ff_vvc_per_frame_init(VVCFrameContext *fc) +{ + return frame_context_for_each_tl(fc, tl_zero); +} + static int min_positive(const int idx, const int diff, const int min_diff) { return diff > 0 && (idx < 0 || diff < min_diff); @@ -402,8 +435,8 @@ static int8_t smvd_find(const VVCFrameContext *fc, const SliceContext *sc, int l int8_t idx = -1; int old_diff = -1; for (int i = 0; i < rsh->num_ref_idx_active[lx]; i++) { - if (!rpl->isLongTerm[i]) { - int diff = poc - rpl->list[i]; + if (!rpl->refs[i].is_lt) { + int diff = poc - rpl->refs[i].poc; if (find(idx, diff, old_diff)) { idx = i; old_diff = diff; @@ -497,9 +530,11 @@ static int ep_init_cabac_decoder(SliceContext *sc, const int index, skipped++; } size = end - start; + size = av_clip(size, 0, get_bits_left(gb) / 8); } else { size = get_bits_left(gb) / 8; } + 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); if (ret < 0) return ret; @@ -566,6 +601,9 @@ 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); + ff_refstruct_replace(&dst->progress, src->progress); ff_refstruct_replace(&dst->tab_dmvr_mvf, src->tab_dmvr_mvf); @@ -576,6 +614,11 @@ static int ref_frame(VVCFrame *dst, const VVCFrame *src) dst->poc = src->poc; dst->ctb_count = src->ctb_count; + + dst->scaling_win = src->scaling_win; + dst->ref_width = src->ref_width; + dst->ref_height = src->ref_height; + dst->flags = src->flags; dst->sequence = src->sequence; @@ -738,6 +781,7 @@ static void export_frame_params(VVCContext *s, const VVCFrameContext *fc) 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]; } static int frame_setup(VVCFrameContext *fc, VVCContext *s) @@ -895,10 +939,16 @@ 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; + int ret = ff_vvc_frame_submit(s, fc); + + if (ret < 0) { + ff_vvc_report_frame_finished(fc->ref); + return ret; + } + s->nb_frames++; s->nb_delayed++; - ff_vvc_frame_submit(s, fc); + if (s->nb_delayed >= s->nb_fcs) { if ((ret = wait_delayed_frame(s, output, got_output)) < 0) return ret; @@ -973,6 +1023,8 @@ static av_cold void vvc_decode_flush(AVCodecContext *avctx) ff_vvc_flush_dpb(last); } + s->ps.sps_id_used = 0; + s->eos = 1; } @@ -1006,7 +1058,7 @@ static av_cold int vvc_decode_init(AVCodecContext *avctx) static AVOnce init_static_once = AV_ONCE_INIT; const int cpu_count = av_cpu_count(); const int delayed = FFMIN(cpu_count, VVC_MAX_DELAYED_FRAMES); - const int thread_count = avctx->thread_count ? avctx->thread_count : delayed; + int thread_count = avctx->thread_count ? avctx->thread_count : delayed; int ret; s->avctx = avctx; @@ -1033,6 +1085,8 @@ static av_cold int vvc_decode_init(AVCodecContext *avctx) return ret; } + if (thread_count == 1) + thread_count = 0; s->executor = ff_vvc_executor_alloc(s, thread_count); if (!s->executor) return AVERROR(ENOMEM); @@ -1054,8 +1108,7 @@ const FFCodec ff_vvc_decoder = { .close = vvc_decode_free, FF_CODEC_DECODE_CB(vvc_decode_frame), .flush = vvc_decode_flush, - .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | - AV_CODEC_CAP_EXPERIMENTAL, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, .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), diff --git a/libavcodec/vvc/vvcdec.h b/libavcodec/vvc/dec.h similarity index 80% rename from libavcodec/vvc/vvcdec.h rename to libavcodec/vvc/dec.h index aa3d71552..d27cf52ca 100644 --- a/libavcodec/vvc/vvcdec.h +++ b/libavcodec/vvc/dec.h @@ -21,14 +21,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVCDEC_H -#define AVCODEC_VVC_VVCDEC_H +#ifndef AVCODEC_VVC_DEC_H +#define AVCODEC_VVC_DEC_H #include "libavcodec/videodsp.h" #include "libavcodec/vvc.h" -#include "vvc_ps.h" -#include "vvcdsp.h" +#include "ps.h" +#include "dsp.h" #define LUMA 0 #define CHROMA 1 @@ -42,10 +42,18 @@ #define L0 0 #define L1 1 +typedef struct VVCRefPic { + struct VVCFrame *ref; + int poc; + int is_lt; // is long term reference + + // for RPR + int is_scaled; ///< RprConstraintsActiveFlag + int scale[2]; ///< RefPicScale[] +} VVCRefPic; + typedef struct RefPicList { - struct VVCFrame *ref[VVC_MAX_REF_ENTRIES]; - int list[VVC_MAX_REF_ENTRIES]; - int isLongTerm[VVC_MAX_REF_ENTRIES]; + VVCRefPic refs[VVC_MAX_REF_ENTRIES]; int nb_refs; } RefPicList; @@ -53,9 +61,18 @@ typedef struct RefPicListTab { RefPicList refPicList[2]; } RefPicListTab; +typedef struct VVCWindow { + int16_t left_offset; + int16_t right_offset; + int16_t top_offset; + int16_t bottom_offset; +} VVCWindow; + typedef struct VVCFrame { struct AVFrame *frame; + 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 @@ -65,6 +82,12 @@ typedef struct VVCFrame { int poc; + //for RPR + VVCWindow scaling_win; ///< pps_scaling_win_left_offset * SubWithC, pps_scaling_win_right_offset * SubWithC, + ///< pps_scaling_win_top_offset * SubHeigtC, pps_scaling_win_bottom_offset * SubHiehgtC + int ref_width; ///< CurrPicScalWinWidthL + int ref_height; ///< CurrPicScalWinHeightL + struct VVCFrame *collocated_ref; struct FrameProgress *progress; ///< RefStruct reference @@ -155,20 +178,18 @@ typedef struct VVCFrameContext { uint8_t *tb_height[2]; uint8_t *pcmf[2]; - uint8_t *horizontal_bs[VVC_MAX_SAMPLE_ARRAYS]; - uint8_t *vertical_bs[VVC_MAX_SAMPLE_ARRAYS]; - uint8_t *horizontal_p; ///< horizontal maxFilterLengthPs for luma - uint8_t *horizontal_q; ///< horizontal maxFilterLengthQs for luma - uint8_t *vertical_p; ///< vertical maxFilterLengthPs for luma - uint8_t *vertical_q; ///< vertical maxFilterLengthQs for luma + uint8_t *bs[2][VVC_MAX_SAMPLE_ARRAYS]; ///< horizontal, vertical boundary filtering strength + uint8_t *max_len_p[2]; ///< horizontal, vertical maxFilterLengthPs for luma + uint8_t *max_len_q[2]; ///< horizontal, vertical maxFilterLengthQs for luma uint8_t *sao_pixel_buffer_h[VVC_MAX_SAMPLE_ARRAYS]; uint8_t *sao_pixel_buffer_v[VVC_MAX_SAMPLE_ARRAYS]; uint8_t *alf_pixel_buffer_h[VVC_MAX_SAMPLE_ARRAYS][2]; uint8_t *alf_pixel_buffer_v[VVC_MAX_SAMPLE_ARRAYS][2]; - int *coeffs; - struct CTU *ctus; + int *coeffs; + struct CTU *ctus; + struct CodingUnit **cus; uint8_t *ibc_vir_buf[VVC_MAX_SAMPLE_ARRAYS]; ///< IbcVirBuf[] @@ -185,8 +206,6 @@ typedef struct VVCFrameContext { int height; int chroma_format_idc; int pixel_shift; - int bs_width; - int bs_height; int ibc_buffer_width; ///< IbcBufWidth } sz; } tab; @@ -226,4 +245,4 @@ typedef struct VVCContext { int nb_delayed; ///< delayed frames } VVCContext ; -#endif /* AVCODEC_VVC_VVCDEC_H */ +#endif /* AVCODEC_VVC_DEC_H */ diff --git a/libavcodec/vvc/vvcdsp.c b/libavcodec/vvc/dsp.c similarity index 75% rename from libavcodec/vvc/vvcdsp.c rename to libavcodec/vvc/dsp.c index d63b9bc9b..433353c32 100644 --- a/libavcodec/vvc/vvcdsp.c +++ b/libavcodec/vvc/dsp.c @@ -20,32 +20,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "vvcdsp.h" -#include "vvc_ctu.h" -#include "vvc_itx_1d.h" +#include "dsp.h" +#include "ctu.h" +#include "itx_1d.h" #define VVC_SIGN(v) (v < 0 ? -1 : !!v) -static void av_always_inline pad_int16(int16_t *_dst, const ptrdiff_t dst_stride, const int width, const int height) -{ - const int padded_width = width + 2; - int16_t *dst; - for (int y = 0; y < height; y++) { - dst = _dst + y * dst_stride; - for (int x = 0; x < width; x++) { - dst[-1] = dst[0]; - dst[width] = dst[width - 1]; - } - } - - _dst--; - //top - memcpy(_dst - dst_stride, _dst, padded_width * sizeof(int16_t)); - //bottom - _dst += dst_stride * height; - memcpy(_dst, _dst - dst_stride, padded_width * sizeof(int16_t)); -} - static int vvc_sad(const int16_t *src0, const int16_t *src1, int dx, int dy, const int block_w, const int block_h) { @@ -77,22 +57,21 @@ typedef struct IntraEdgeParams { #define PROF_BORDER_EXT 1 #define PROF_BLOCK_SIZE (AFFINE_MIN_BLOCK_SIZE + PROF_BORDER_EXT * 2) -#define BDOF_BORDER_EXT 1 -#define BDOF_PADDED_SIZE (16 + BDOF_BORDER_EXT * 2) -#define BDOF_BLOCK_SIZE 4 -#define BDOF_GRADIENT_SIZE (BDOF_BLOCK_SIZE + BDOF_BORDER_EXT * 2) +#define BDOF_BORDER_EXT 1 +#define BDOF_BLOCK_SIZE 16 +#define BDOF_MIN_BLOCK_SIZE 4 #define BIT_DEPTH 8 -#include "vvcdsp_template.c" +#include "dsp_template.c" #undef BIT_DEPTH #define BIT_DEPTH 10 -#include "vvcdsp_template.c" +#include "dsp_template.c" #undef BIT_DEPTH #define BIT_DEPTH 12 -#include "vvcdsp_template.c" +#include "dsp_template.c" #undef BIT_DEPTH void ff_vvc_dsp_init(VVCDSPContext *vvcdsp, int bit_depth) @@ -121,7 +100,9 @@ void ff_vvc_dsp_init(VVCDSPContext *vvcdsp, int bit_depth) break; } -#if ARCH_X86 +#if ARCH_AARCH64 + ff_vvc_dsp_init_aarch64(vvcdsp, bit_depth); +#elif ARCH_X86 ff_vvc_dsp_init_x86(vvcdsp, bit_depth); #endif } diff --git a/libavcodec/vvc/vvcdsp.h b/libavcodec/vvc/dsp.h similarity index 84% rename from libavcodec/vvc/vvcdsp.h rename to libavcodec/vvc/dsp.h index f4fb3cb7d..635ebcafe 100644 --- a/libavcodec/vvc/vvcdsp.h +++ b/libavcodec/vvc/dsp.h @@ -21,27 +21,27 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVCDSP_H -#define AVCODEC_VVC_VVCDSP_H +#ifndef AVCODEC_VVC_DSP_H +#define AVCODEC_VVC_DSP_H #include #include -enum TxType { - DCT2, - DST7, - DCT8, - N_TX_TYPE, +enum VVCTxType { + VVC_DCT2, + VVC_DST7, + VVC_DCT8, + VVC_N_TX_TYPE, }; -enum TxSize { - TX_SIZE_2, - TX_SIZE_4, - TX_SIZE_8, - TX_SIZE_16, - TX_SIZE_32, - TX_SIZE_64, - N_TX_SIZE, +enum VVCTxSize { + VVC_TX_SIZE_2, + VVC_TX_SIZE_4, + VVC_TX_SIZE_8, + VVC_TX_SIZE_16, + VVC_TX_SIZE_32, + VVC_TX_SIZE_64, + VVC_N_TX_SIZE, }; typedef struct VVCInterDSPContext { @@ -57,6 +57,19 @@ typedef struct VVCInterDSPContext { uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, int height, int denom, int wx, int ox, const int8_t *hf, const int8_t *vf, int width); + void (*put_scaled[2 /* luma, chroma */][7 /* log2(width) - 1 */])( + int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, int src_height, + int x, int y, int dx, int dy, int height, const int8_t *hf, const int8_t *vf, int width); + + void (*put_uni_scaled[2 /* luma, chroma */][7 /* log2(width) - 1 */])( + uint8_t *dst, const ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, int src_height, + int x, int y, int dx, int dy, int height, const int8_t *hf, const int8_t *vf, int width); + + void (*put_uni_w_scaled[2 /* luma, chroma */][7 /* log2(width) - 1 */])( + uint8_t *dst, const ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, int src_height, + int x, int y, int dx, int dy, int height, int denom, int wx, int ox, const int8_t *hf, const int8_t *vf, + int width); + void (*avg)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1, int width, int height); @@ -75,8 +88,6 @@ typedef struct VVCInterDSPContext { void (*bdof_fetch_samples)(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, int x_frac, int y_frac, int width, int height); - void (*prof_grad_filter)(int16_t *gradient_h, int16_t *gradient_v, const ptrdiff_t gradient_stride, - const int16_t *src, const ptrdiff_t src_stride, int width, int height, const int pad); void (*apply_prof)(int16_t *dst, const int16_t *src, const int16_t *diff_mv_x, const int16_t *diff_mv_y); void (*apply_prof_uni)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src, @@ -84,7 +95,7 @@ typedef struct VVCInterDSPContext { void (*apply_prof_uni_w)(uint8_t *dst, const ptrdiff_t dst_stride, const int16_t *src, const int16_t *diff_mv_x, const int16_t *diff_mv_y, int denom, int wx, int ox); - void (*apply_bdof)(uint8_t *dst, ptrdiff_t dst_stride, int16_t *src0, int16_t *src1, int block_w, int block_h); + void (*apply_bdof)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1, int block_w, int block_h); int (*sad)(const int16_t *src0, const int16_t *src1, int dx, int dy, int block_w, int block_h); void (*dmvr[2][2])(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, int height, @@ -114,7 +125,7 @@ typedef struct VVCItxDSPContext { 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 (*itx[N_TX_TYPE][N_TX_SIZE])(int *coeffs, ptrdiff_t step, size_t nz); + 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); } VVCItxDSPContext; @@ -167,6 +178,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_x86(VVCDSPContext *hpc, const int bit_depth); -#endif /* AVCODEC_VVC_VVCDSP_H */ +#endif /* AVCODEC_VVC_DSP_H */ diff --git a/libavcodec/vvc/vvcdsp_template.c b/libavcodec/vvc/dsp_template.c similarity index 94% rename from libavcodec/vvc/vvcdsp_template.c rename to libavcodec/vvc/dsp_template.c index 33815d676..1aa1e027b 100644 --- a/libavcodec/vvc/vvcdsp_template.c +++ b/libavcodec/vvc/dsp_template.c @@ -22,12 +22,12 @@ #include "libavutil/frame.h" #include "libavcodec/bit_depth_template.c" -#include "vvcdec.h" -#include "vvc_data.h" +#include "dec.h" +#include "data.h" -#include "vvc_inter_template.c" -#include "vvc_intra_template.c" -#include "vvc_filter_template.c" +#include "inter_template.c" +#include "intra_template.c" +#include "filter_template.c" static void FUNC(add_residual)(uint8_t *_dst, const int *res, const int w, const int h, const ptrdiff_t _stride) @@ -97,7 +97,7 @@ static void FUNC(transform_bdpcm)(int *coeffs, const int width, const int height static void FUNC(ff_vvc_itx_dsp_init)(VVCItxDSPContext *const itx) { #define VVC_ITX(TYPE, type, s) \ - itx->itx[TYPE][TX_SIZE_##s] = ff_vvc_inv_##type##_##s; \ + itx->itx[VVC_##TYPE][VVC_##TX_SIZE_##s] = ff_vvc_inv_##type##_##s; \ #define VVC_ITX_COMMON(TYPE, type) \ VVC_ITX(TYPE, type, 4); \ diff --git a/libavcodec/vvc/vvc_filter.c b/libavcodec/vvc/filter.c similarity index 50% rename from libavcodec/vvc/vvc_filter.c rename to libavcodec/vvc/filter.c index dded447bf..25bef45ee 100644 --- a/libavcodec/vvc/vvc_filter.c +++ b/libavcodec/vvc/filter.c @@ -20,11 +20,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libavutil/frame.h" +#include "libavutil/imgutils.h" -#include "vvc_ctu.h" -#include "vvc_data.h" -#include "vvc_filter.h" -#include "vvc_refs.h" +#include "ctu.h" +#include "data.h" +#include "filter.h" +#include "refs.h" #define LEFT 0 #define TOP 1 @@ -34,6 +35,10 @@ #define DEFAULT_INTRA_TC_OFFSET 2 +#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)] + //Table 43 Derivation of threshold variables beta' and tc' from input Q static const uint16_t tctable[66] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -51,6 +56,32 @@ static const uint8_t betatable[64] = { 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, }; +// One vertical and one horizontal virtual boundary in a CTU at most. The CTU will be divided into 4 subblocks. +#define MAX_VBBS 4 + +static int get_virtual_boundary(const VVCFrameContext *fc, const int ctu_pos, const int vertical) +{ + const VVCSPS *sps = fc->ps.sps; + const VVCPH *ph = &fc->ps.ph; + const uint16_t *vbs = vertical ? ph->vb_pos_x : ph->vb_pos_y; + const uint8_t nb_vbs = vertical ? ph->num_ver_vbs : ph->num_hor_vbs; + const int pos = ctu_pos << sps->ctb_log2_size_y; + + if (sps->r->sps_virtual_boundaries_enabled_flag) { + for (int i = 0; i < nb_vbs; i++) { + const int o = vbs[i] - pos; + if (o >= 0 && o < sps->ctb_size_y) + return vbs[i]; + } + } + return 0; +} + +static int is_virtual_boundary(const VVCFrameContext *fc, const int pos, const int vertical) +{ + return get_virtual_boundary(fc, pos >> fc->ps.sps->ctb_log2_size_y, vertical) == pos; +} + static int get_qPc(const VVCFrameContext *fc, const int x0, const int y0, const int chroma) { const int x = x0 >> MIN_TU_LOG2; @@ -99,7 +130,7 @@ static void copy_vert(uint8_t *dst, const uint8_t *src, const int pixel_shift, c static void copy_ctb_to_hv(VVCFrameContext *fc, const uint8_t *src, const ptrdiff_t src_stride, const int x, const int y, const int width, const int height, - const int c_idx, const int x_ctb, const int y_ctb, const int top) + const int c_idx, const int rx, const int ry, const int top) { const int ps = fc->ps.sps->pixel_shift; const int w = fc->ps.pps->width >> fc->ps.sps->hshift[c_idx]; @@ -107,16 +138,16 @@ static void copy_ctb_to_hv(VVCFrameContext *fc, const uint8_t *src, if (top) { /* top */ - memcpy(fc->tab.sao_pixel_buffer_h[c_idx] + (((2 * y_ctb) * w + x) << ps), + memcpy(fc->tab.sao_pixel_buffer_h[c_idx] + (((2 * ry) * w + x) << ps), src, width << ps); } else { /* bottom */ - memcpy(fc->tab.sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 1) * w + x) << ps), + memcpy(fc->tab.sao_pixel_buffer_h[c_idx] + (((2 * ry + 1) * w + x) << ps), src + src_stride * (height - 1), width << ps); /* copy vertical edges */ - copy_vert(fc->tab.sao_pixel_buffer_v[c_idx] + (((2 * x_ctb) * h + y) << ps), src, ps, height, 1 << ps, src_stride); - copy_vert(fc->tab.sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 1) * h + y) << ps), src + ((width - 1) << ps), ps, height, 1 << ps, src_stride); + copy_vert(fc->tab.sao_pixel_buffer_v[c_idx] + (((2 * rx) * h + y) << ps), src, ps, height, 1 << ps, src_stride); + copy_vert(fc->tab.sao_pixel_buffer_v[c_idx] + (((2 * rx + 1) * h + y) << ps), src + ((width - 1) << ps), ps, height, 1 << ps, src_stride); } } @@ -135,7 +166,7 @@ static void sao_copy_ctb_to_hv(VVCLocalContext *lc, const int rx, const int ry, const int ctb_size_v = ctb_size_y >> fc->ps.sps->vshift[c_idx]; const int width = FFMIN(ctb_size_h, (fc->ps.pps->width >> fc->ps.sps->hshift[c_idx]) - x); const int height = FFMIN(ctb_size_v, (fc->ps.pps->height >> fc->ps.sps->vshift[c_idx]) - y); - const uint8_t *src = &fc->frame->data[c_idx][y * src_stride + (x << fc->ps.sps->pixel_shift)]; + const uint8_t *src = POS(c_idx, x0, y0); copy_ctb_to_hv(fc, src, src_stride, x, y, width, height, c_idx, rx, ry, top); } } @@ -151,154 +182,198 @@ void ff_vvc_sao_copy_ctb_to_hv(VVCLocalContext *lc, const int rx, const int ry, sao_copy_ctb_to_hv(lc, rx, ry, 0); } -void ff_vvc_sao_filter(VVCLocalContext *lc, int x, int y) +static int sao_can_cross_slices(const VVCFrameContext *fc, const int rx, const int ry, const int dx, const int dy) { - VVCFrameContext *fc = lc->fc; - const int ctb_size_y = fc->ps.sps->ctb_size_y; - static const uint8_t sao_tab[16] = { 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8 }; - int c_idx; - int edges[4]; // 0 left 1 top 2 right 3 bottom - const int x_ctb = x >> fc->ps.sps->ctb_log2_size_y; - const int y_ctb = y >> fc->ps.sps->ctb_log2_size_y; - const SAOParams *sao = &CTB(fc->tab.sao, x_ctb, y_ctb); - // flags indicating unfilterable edges - uint8_t vert_edge[] = { 0, 0 }; - uint8_t horiz_edge[] = { 0, 0 }; - uint8_t diag_edge[] = { 0, 0, 0, 0 }; - const uint8_t lfase = fc->ps.pps->r->pps_loop_filter_across_slices_enabled_flag; - const uint8_t no_tile_filter = fc->ps.pps->r->num_tiles_in_pic > 1 && - !fc->ps.pps->r->pps_loop_filter_across_tiles_enabled_flag; - const uint8_t restore = no_tile_filter || !lfase; - uint8_t left_tile_edge = 0; - uint8_t right_tile_edge = 0; - uint8_t up_tile_edge = 0; - uint8_t bottom_tile_edge = 0; + const uint8_t lfase = fc->ps.pps->r->pps_loop_filter_across_slices_enabled_flag; - edges[LEFT] = x_ctb == 0; - edges[TOP] = y_ctb == 0; - edges[RIGHT] = x_ctb == fc->ps.pps->ctb_width - 1; - edges[BOTTOM] = y_ctb == fc->ps.pps->ctb_height - 1; + return lfase || CTB(fc->tab.slice_idx, rx, ry) == CTB(fc->tab.slice_idx, rx + dx, ry + dy); +} - if (restore) { - if (!edges[LEFT]) { - left_tile_edge = no_tile_filter && fc->ps.pps->ctb_to_col_bd[x_ctb] == x_ctb; - vert_edge[0] = (!lfase && CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb - 1, y_ctb)) || left_tile_edge; - } - if (!edges[RIGHT]) { - right_tile_edge = no_tile_filter && fc->ps.pps->ctb_to_col_bd[x_ctb] != fc->ps.pps->ctb_to_col_bd[x_ctb + 1]; - vert_edge[1] = (!lfase && CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb + 1, y_ctb)) || right_tile_edge; - } - if (!edges[TOP]) { - up_tile_edge = no_tile_filter && fc->ps.pps->ctb_to_row_bd[y_ctb] == y_ctb; - horiz_edge[0] = (!lfase && CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb, y_ctb - 1)) || up_tile_edge; - } - if (!edges[BOTTOM]) { - bottom_tile_edge = no_tile_filter && fc->ps.pps->ctb_to_row_bd[y_ctb] != fc->ps.pps->ctb_to_row_bd[y_ctb + 1]; - horiz_edge[1] = (!lfase && CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb, y_ctb + 1)) || bottom_tile_edge; - } - if (!edges[LEFT] && !edges[TOP]) { - diag_edge[0] = (!lfase && CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb - 1, y_ctb - 1)) || left_tile_edge || up_tile_edge; - } - if (!edges[TOP] && !edges[RIGHT]) { - diag_edge[1] = (!lfase && CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb + 1, y_ctb - 1)) || right_tile_edge || up_tile_edge; - } - if (!edges[RIGHT] && !edges[BOTTOM]) { - diag_edge[2] = (!lfase && CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb + 1, y_ctb + 1)) || right_tile_edge || bottom_tile_edge; - } - if (!edges[LEFT] && !edges[BOTTOM]) { - diag_edge[3] = (!lfase && CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb - 1, y_ctb + 1)) || left_tile_edge || bottom_tile_edge; - } +static void sao_get_edges(uint8_t vert_edge[2], uint8_t horiz_edge[2], uint8_t diag_edge[4], int *restore, + const VVCLocalContext *lc, const int edges[4], const int rx, const int ry) +{ + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const H266RawSPS *rsps = sps->r; + const VVCPPS *pps = fc->ps.pps; + const int subpic_idx = lc->sc->sh.r->curr_subpic_idx; + const uint8_t lfase = fc->ps.pps->r->pps_loop_filter_across_slices_enabled_flag; + const uint8_t no_tile_filter = pps->r->num_tiles_in_pic > 1 && !pps->r->pps_loop_filter_across_tiles_enabled_flag; + const uint8_t no_subpic_filter = rsps->sps_num_subpics_minus1 && !rsps->sps_loop_filter_across_subpic_enabled_flag[subpic_idx]; + uint8_t lf_edge[] = { 0, 0, 0, 0 }; + + *restore = no_subpic_filter || no_tile_filter || !lfase || rsps->sps_virtual_boundaries_enabled_flag; + + if (!*restore) + return; + + if (!edges[LEFT]) { + lf_edge[LEFT] = no_tile_filter && pps->ctb_to_col_bd[rx] == rx; + lf_edge[LEFT] |= no_subpic_filter && rsps->sps_subpic_ctu_top_left_x[subpic_idx] == rx; + lf_edge[LEFT] |= is_virtual_boundary(fc, rx << sps->ctb_log2_size_y, 1); + vert_edge[0] = !sao_can_cross_slices(fc, rx, ry, -1, 0) || lf_edge[LEFT]; + } + if (!edges[RIGHT]) { + lf_edge[RIGHT] = no_tile_filter && pps->ctb_to_col_bd[rx] != pps->ctb_to_col_bd[rx + 1]; + lf_edge[RIGHT] |= no_subpic_filter && rsps->sps_subpic_ctu_top_left_x[subpic_idx] + rsps->sps_subpic_width_minus1[subpic_idx] == rx; + lf_edge[RIGHT] |= is_virtual_boundary(fc, (rx + 1) << sps->ctb_log2_size_y, 1); + vert_edge[1] = !sao_can_cross_slices(fc, rx, ry, 1, 0) || lf_edge[RIGHT]; + } + if (!edges[TOP]) { + lf_edge[TOP] = no_tile_filter && pps->ctb_to_row_bd[ry] == ry; + lf_edge[TOP] |= no_subpic_filter && rsps->sps_subpic_ctu_top_left_y[subpic_idx] == ry; + lf_edge[TOP] |= is_virtual_boundary(fc, ry << sps->ctb_log2_size_y, 0); + horiz_edge[0] = !sao_can_cross_slices(fc, rx, ry, 0, -1) || lf_edge[TOP]; + } + if (!edges[BOTTOM]) { + lf_edge[BOTTOM] = no_tile_filter && pps->ctb_to_row_bd[ry] != pps->ctb_to_row_bd[ry + 1]; + lf_edge[BOTTOM] |= no_subpic_filter && rsps->sps_subpic_ctu_top_left_y[subpic_idx] + rsps->sps_subpic_height_minus1[subpic_idx] == ry; + lf_edge[BOTTOM] |= is_virtual_boundary(fc, (ry + 1) << sps->ctb_log2_size_y, 0); + horiz_edge[1] = !sao_can_cross_slices(fc, rx, ry, 0, 1) || lf_edge[BOTTOM]; } - for (c_idx = 0; c_idx < (fc->ps.sps->r->sps_chroma_format_idc ? 3 : 1); c_idx++) { - int x0 = x >> fc->ps.sps->hshift[c_idx]; - int y0 = y >> fc->ps.sps->vshift[c_idx]; - ptrdiff_t src_stride = fc->frame->linesize[c_idx]; - int ctb_size_h = ctb_size_y >> fc->ps.sps->hshift[c_idx]; - int ctb_size_v = ctb_size_y >> fc->ps.sps->vshift[c_idx]; - int width = FFMIN(ctb_size_h, (fc->ps.pps->width >> fc->ps.sps->hshift[c_idx]) - x0); - int height = FFMIN(ctb_size_v, (fc->ps.pps->height >> fc->ps.sps->vshift[c_idx]) - y0); - int tab = sao_tab[(FFALIGN(width, 8) >> 3) - 1]; - uint8_t *src = &fc->frame->data[c_idx][y0 * src_stride + (x0 << fc->ps.sps->pixel_shift)]; - ptrdiff_t dst_stride; - uint8_t *dst; + if (!edges[LEFT] && !edges[TOP]) + diag_edge[0] = !sao_can_cross_slices(fc, rx, ry, -1, -1) || lf_edge[LEFT] || lf_edge[TOP]; + + if (!edges[TOP] && !edges[RIGHT]) + diag_edge[1] = !sao_can_cross_slices(fc, rx, ry, 1, -1) || lf_edge[RIGHT] || lf_edge[TOP]; + + if (!edges[RIGHT] && !edges[BOTTOM]) + diag_edge[2] = !sao_can_cross_slices(fc, rx, ry, 1, 1) || lf_edge[RIGHT] || lf_edge[BOTTOM]; + + if (!edges[LEFT] && !edges[BOTTOM]) + diag_edge[3] = !sao_can_cross_slices(fc, rx, ry, -1, 1) || lf_edge[LEFT] || lf_edge[BOTTOM]; +} + +static void sao_copy_hor(uint8_t *dst, const ptrdiff_t dst_stride, + const uint8_t *src, const ptrdiff_t src_stride, const int width, const int edges[4], const int ps) +{ + const int left = 1 - edges[LEFT]; + const int right = 1 - edges[RIGHT]; + int pos = 0; + + src -= left << ps; + dst -= left << ps; + + if (left) { + copy_pixel(dst, src, ps); + pos += (1 << ps); + } + memcpy(dst + pos, src + pos, width << ps); + if (right) { + pos += width << ps; + copy_pixel(dst + pos, src + pos, ps); + } +} + +static void sao_extends_edges(uint8_t *dst, const ptrdiff_t dst_stride, + const uint8_t *src, const ptrdiff_t src_stride, const int width, const int height, + const VVCFrameContext *fc, const int x0, const int y0, const int rx, const int ry, const int edges[4], const int c_idx) +{ + const uint8_t *sao_h = fc->tab.sao_pixel_buffer_h[c_idx]; + const uint8_t *sao_v = fc->tab.sao_pixel_buffer_v[c_idx]; + const int x = x0 >> fc->ps.sps->hshift[c_idx]; + const int y = y0 >> fc->ps.sps->vshift[c_idx]; + const int w = fc->ps.pps->width >> fc->ps.sps->hshift[c_idx]; + const int h = fc->ps.pps->height >> fc->ps.sps->vshift[c_idx]; + const int ps = fc->ps.sps->pixel_shift; + + if (!edges[TOP]) + sao_copy_hor(dst - dst_stride, dst_stride, sao_h + (((2 * ry - 1) * w + x) << ps), src_stride, width, edges, ps); + + if (!edges[BOTTOM]) + sao_copy_hor(dst + height * dst_stride, dst_stride, sao_h + (((2 * ry + 2) * w + x) << ps), src_stride, width, edges, ps); + + if (!edges[LEFT]) + copy_vert(dst - (1 << ps), sao_v + (((2 * rx - 1) * h + y) << ps), ps, height, dst_stride, 1 << ps); + + if (!edges[RIGHT]) + copy_vert(dst + (width << ps), sao_v + (((2 * rx + 2) * h + y) << ps), ps, height, dst_stride, 1 << ps); + + copy_ctb(dst, src, width << ps, height, dst_stride, src_stride); +} + +static void sao_restore_vb(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, + const int width, const int height, const int vb_pos, const int ps, const int vertical) +{ + int w = 2; + int h = (vertical ? height : width); + int dx = vb_pos - 1; + int dy = 0; + + if (!vertical) { + FFSWAP(int, w, h); + FFSWAP(int, dx, dy); + } + dst += dy * dst_stride +(dx << ps); + src += dy * src_stride +(dx << ps); + + av_image_copy_plane(dst, dst_stride, src, src_stride, w << ps, h); +} + +void ff_vvc_sao_filter(VVCLocalContext *lc, int x0, int y0) +{ + VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const int rx = x0 >> sps->ctb_log2_size_y; + const int ry = y0 >> sps->ctb_log2_size_y; + const int edges[4] = { !rx, !ry, rx == fc->ps.pps->ctb_width - 1, ry == fc->ps.pps->ctb_height - 1 }; + const SAOParams *sao = &CTB(fc->tab.sao, rx, ry); + // flags indicating unfilterable edges + uint8_t vert_edge[] = { 0, 0 }; + uint8_t horiz_edge[] = { 0, 0 }; + uint8_t diag_edge[] = { 0, 0, 0, 0 }; + int restore, vb_x = 0, vb_y = 0;; + + if (sps->r->sps_virtual_boundaries_enabled_flag) { + vb_x = get_virtual_boundary(fc, rx, 1); + vb_y = get_virtual_boundary(fc, ry, 0); + } + + sao_get_edges(vert_edge, horiz_edge, diag_edge, &restore, lc, edges, rx, ry); + + for (int c_idx = 0; c_idx < (sps->r->sps_chroma_format_idc ? 3 : 1); c_idx++) { + static const uint8_t sao_tab[16] = { 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8 }; + const ptrdiff_t src_stride = fc->frame->linesize[c_idx]; + uint8_t *src = POS(c_idx, x0, y0); + const int hs = sps->hshift[c_idx]; + const int vs = sps->vshift[c_idx]; + const int ps = sps->pixel_shift; + const int width = FFMIN(sps->ctb_size_y, fc->ps.pps->width - x0) >> hs; + const int height = FFMIN(sps->ctb_size_y, fc->ps.pps->height - y0) >> vs; + const int tab = sao_tab[(FFALIGN(width, 8) >> 3) - 1]; + const int sao_eo_class = sao->eo_class[c_idx]; switch (sao->type_idx[c_idx]) { - case SAO_BAND: - fc->vvcdsp.sao.band_filter[tab](src, src, src_stride, src_stride, - sao->offset_val[c_idx], sao->band_position[c_idx], width, height); - break; - case SAO_EDGE: - { - const int w = fc->ps.pps->width >> fc->ps.sps->hshift[c_idx]; - const int h = fc->ps.pps->height >> fc->ps.sps->vshift[c_idx]; - const int sh = fc->ps.sps->pixel_shift; + case SAO_BAND: + fc->vvcdsp.sao.band_filter[tab](src, src, src_stride, src_stride, + sao->offset_val[c_idx], sao->band_position[c_idx], width, height); + break; + case SAO_EDGE: + { + const ptrdiff_t dst_stride = 2 * MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE; + uint8_t *dst = lc->sao_buffer + dst_stride + AV_INPUT_BUFFER_PADDING_SIZE; - dst_stride = 2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE; - dst = lc->sao_buffer + dst_stride + AV_INPUT_BUFFER_PADDING_SIZE; + sao_extends_edges(dst, dst_stride, src, src_stride, width, height, fc, x0, y0, rx, ry, edges, c_idx); - if (!edges[TOP]) { - const int left = 1 - edges[LEFT]; - const int right = 1 - edges[RIGHT]; - const uint8_t *src1; - uint8_t *dst1; - int pos = 0; + fc->vvcdsp.sao.edge_filter[tab](src, dst, src_stride, sao->offset_val[c_idx], + sao->eo_class[c_idx], width, height); + fc->vvcdsp.sao.edge_restore[restore](src, dst, src_stride, dst_stride, + sao, edges, width, height, c_idx, vert_edge, horiz_edge, diag_edge); - dst1 = dst - dst_stride - (left << sh); - src1 = fc->tab.sao_pixel_buffer_h[c_idx] + (((2 * y_ctb - 1) * w + x0 - left) << sh); - if (left) { - copy_pixel(dst1, src1, sh); - pos += (1 << sh); - } - memcpy(dst1 + pos, src1 + pos, width << sh); - if (right) { - pos += width << sh; - copy_pixel(dst1 + pos, src1 + pos, sh); - } + if (vb_x > x0 && sao_eo_class != SAO_EO_VERT) + sao_restore_vb(src, src_stride, dst, dst_stride, width, height, (vb_x - x0) >> hs, ps, 1); + if (vb_y > y0 && sao_eo_class != SAO_EO_HORIZ) + sao_restore_vb(src, src_stride, dst, dst_stride, width, height, (vb_y - y0) >> vs, ps, 0); + + break; } - if (!edges[BOTTOM]) { - const int left = 1 - edges[LEFT]; - const int right = 1 - edges[RIGHT]; - const uint8_t *src1; - uint8_t *dst1; - int pos = 0; - - dst1 = dst + height * dst_stride - (left << sh); - src1 = fc->tab.sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 2) * w + x0 - left) << sh); - if (left) { - copy_pixel(dst1, src1, sh); - pos += (1 << sh); - } - memcpy(dst1 + pos, src1 + pos, width << sh); - if (right) { - pos += width << sh; - copy_pixel(dst1 + pos, src1 + pos, sh); - } - } - if (!edges[LEFT]) { - copy_vert(dst - (1 << sh), - fc->tab.sao_pixel_buffer_v[c_idx] + (((2 * x_ctb - 1) * h + y0) << sh), - sh, height, dst_stride, 1 << sh); - } - if (!edges[RIGHT]) { - copy_vert(dst + (width << sh), - fc->tab.sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 2) * h + y0) << sh), - sh, height, dst_stride, 1 << sh); - } - - copy_ctb(dst, src, width << sh, height, dst_stride, src_stride); - fc->vvcdsp.sao.edge_filter[tab](src, dst, src_stride, sao->offset_val[c_idx], - sao->eo_class[c_idx], width, height); - fc->vvcdsp.sao.edge_restore[restore](src, dst, src_stride, dst_stride, - sao, edges, width, height, c_idx, vert_edge, horiz_edge, diag_edge); - break; - } } } } -#define TAB_BS(t, x, y) (t)[((y) >> 2) * (fc->tab.sz.bs_width) + ((x) >> 2)] -#define TAB_MAX_LEN(t, x, y) (t)[((y) >> 2) * (fc->tab.sz.bs_width) + ((x) >> 2)] +#define TAB_BS(t, x, y) (t)[((y) >> MIN_TU_LOG2) * (fc->ps.pps->min_tu_width) + ((x) >> MIN_TU_LOG2)] +#define TAB_MAX_LEN(t, x, y) (t)[((y) >> MIN_TU_LOG2) * (fc->ps.pps->min_tu_width) + ((x) >> MIN_TU_LOG2)] //8 samples a time #define DEBLOCK_STEP 8 @@ -315,9 +390,9 @@ static int boundary_strength(const VVCLocalContext *lc, const MvField *curr, con if (curr->pred_flag == PF_BI && neigh->pred_flag == PF_BI) { // same L0 and L1 - if (rpl[0].list[curr->ref_idx[0]] == neigh_rpl[0].list[neigh->ref_idx[0]] && - rpl[0].list[curr->ref_idx[0]] == rpl[1].list[curr->ref_idx[1]] && - neigh_rpl[0].list[neigh->ref_idx[0]] == neigh_rpl[1].list[neigh->ref_idx[1]]) { + if (rpl[L0].refs[curr->ref_idx[L0]].poc == neigh_rpl[L0].refs[neigh->ref_idx[L0]].poc && + rpl[L0].refs[curr->ref_idx[L0]].poc == rpl[L1].refs[curr->ref_idx[L1]].poc && + neigh_rpl[L0].refs[neigh->ref_idx[L0]].poc == neigh_rpl[L1].refs[neigh->ref_idx[L1]].poc) { if ((FFABS(neigh->mv[0].x - curr->mv[0].x) >= 8 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 8 || FFABS(neigh->mv[1].x - curr->mv[1].x) >= 8 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 8) && (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 8 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 8 || @@ -325,15 +400,15 @@ static int boundary_strength(const VVCLocalContext *lc, const MvField *curr, con return 1; else return 0; - } else if (neigh_rpl[0].list[neigh->ref_idx[0]] == rpl[0].list[curr->ref_idx[0]] && - neigh_rpl[1].list[neigh->ref_idx[1]] == rpl[1].list[curr->ref_idx[1]]) { + } else if (neigh_rpl[L0].refs[neigh->ref_idx[L0]].poc == rpl[L0].refs[curr->ref_idx[L0]].poc && + neigh_rpl[L1].refs[neigh->ref_idx[L1]].poc == rpl[L1].refs[curr->ref_idx[L1]].poc) { if (FFABS(neigh->mv[0].x - curr->mv[0].x) >= 8 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 8 || FFABS(neigh->mv[1].x - curr->mv[1].x) >= 8 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 8) return 1; else return 0; - } else if (neigh_rpl[1].list[neigh->ref_idx[1]] == rpl[0].list[curr->ref_idx[0]] && - neigh_rpl[0].list[neigh->ref_idx[0]] == rpl[1].list[curr->ref_idx[1]]) { + } else if (neigh_rpl[L1].refs[neigh->ref_idx[L1]].poc == rpl[L0].refs[curr->ref_idx[L0]].poc && + neigh_rpl[L0].refs[neigh->ref_idx[L0]].poc == rpl[L1].refs[curr->ref_idx[L1]].poc) { if (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 8 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 8 || FFABS(neigh->mv[0].x - curr->mv[1].x) >= 8 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 8) return 1; @@ -348,18 +423,18 @@ static int boundary_strength(const VVCLocalContext *lc, const MvField *curr, con if (curr->pred_flag & 1) { A = curr->mv[0]; - ref_A = rpl[0].list[curr->ref_idx[0]]; + ref_A = rpl[L0].refs[curr->ref_idx[L0]].poc; } else { A = curr->mv[1]; - ref_A = rpl[1].list[curr->ref_idx[1]]; + ref_A = rpl[L1].refs[curr->ref_idx[L1]].poc; } if (neigh->pred_flag & 1) { B = neigh->mv[0]; - ref_B = neigh_rpl[0].list[neigh->ref_idx[0]]; + ref_B = neigh_rpl[L0].refs[neigh->ref_idx[L0]].poc; } else { B = neigh->mv[1]; - ref_B = neigh_rpl[1].list[neigh->ref_idx[1]]; + ref_B = neigh_rpl[L1].refs[neigh->ref_idx[L1]].poc; } if (ref_A == ref_B) { @@ -400,30 +475,41 @@ static void derive_max_filter_length_luma(const VVCFrameContext *fc, const int q *max_len_p = FFMIN(5, *max_len_p); } -static void vvc_deblock_subblock_bs_vertical(const VVCLocalContext *lc, - const int cb_x, const int cb_y, const int x0, const int y0, const int width, const int height) +static void vvc_deblock_subblock_bs(const VVCLocalContext *lc, + const int cb, int x0, int y0, int width, int height, const int vertical) { const VVCFrameContext *fc = lc->fc; const MvField *tab_mvf = fc->tab.mvf; const RefPicList *rpl = lc->sc->rpl; - const int min_pu_width = fc->ps.pps->min_pu_width; + int stridea = fc->ps.pps->min_pu_width; + int strideb = 1; const int log2_min_pu_size = MIN_PU_LOG2; - // bs for TU internal vertical PU boundaries - for (int j = 0; j < height; j += 4) { - const int y_pu = (y0 + j) >> log2_min_pu_size; + if (!vertical) { + FFSWAP(int, x0, y0); + FFSWAP(int, width, height); + FFSWAP(int, stridea, strideb); + } - for (int i = 8 - ((x0 - cb_x) % 8); i < width; i += 8) { - const int xp_pu = (x0 + i - 1) >> log2_min_pu_size; - const int xq_pu = (x0 + i) >> log2_min_pu_size; - const MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu]; - const MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu]; - const int x = x0 + i; - const int y = y0 + j; - const int bs = boundary_strength(lc, curr, left, rpl); + // bs for TU internal vertical PU boundaries + for (int i = 8 - ((x0 - cb) % 8); i < width; i += 8) { + const int is_vb = is_virtual_boundary(fc, x0 + i, vertical); + const int xp_pu = (x0 + i - 1) >> log2_min_pu_size; + const int xq_pu = (x0 + i) >> log2_min_pu_size; + + for (int j = 0; j < height; j += 4) { + const int y_pu = (y0 + j) >> log2_min_pu_size; + const MvField *mvf_p = &tab_mvf[y_pu * stridea + xp_pu * strideb]; + const MvField *mvf_q = &tab_mvf[y_pu * stridea + xq_pu * strideb]; + const int bs = is_vb ? 0 : boundary_strength(lc, mvf_q, mvf_p, rpl); + int x = x0 + i; + int y = y0 + j; uint8_t max_len_p = 0, max_len_q = 0; - TAB_BS(fc->tab.vertical_bs[LUMA], x, y) = bs; + if (!vertical) + FFSWAP(int, x, y); + + TAB_BS(fc->tab.bs[vertical][LUMA], x, y) = bs; if (i == 4 || i == width - 4) max_len_p = max_len_q = 1; @@ -432,48 +518,8 @@ static void vvc_deblock_subblock_bs_vertical(const VVCLocalContext *lc, else max_len_p = max_len_q = 3; - TAB_MAX_LEN(fc->tab.vertical_p, x, y) = max_len_p; - TAB_MAX_LEN(fc->tab.vertical_q, x, y) = max_len_q; - } - } -} - -static void vvc_deblock_subblock_bs_horizontal(const VVCLocalContext *lc, - const int cb_x, const int cb_y, const int x0, const int y0, const int width, const int height) -{ - const VVCFrameContext *fc = lc->fc; - const MvField* tab_mvf = fc->tab.mvf; - const RefPicList* rpl = lc->sc->rpl; - const int min_pu_width = fc->ps.pps->min_pu_width; - const int log2_min_pu_size = MIN_PU_LOG2; - - // bs for TU internal horizontal PU boundaries - for (int j = 8 - ((y0 - cb_y) % 8); j < height; j += 8) { - int yp_pu = (y0 + j - 1) >> log2_min_pu_size; - int yq_pu = (y0 + j) >> log2_min_pu_size; - - for (int i = 0; i < width; i += 4) { - const int x_pu = (x0 + i) >> log2_min_pu_size; - const MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu]; - const MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu]; - const int x = x0 + i; - const int y = y0 + j; - const int bs = boundary_strength(lc, curr, top, rpl); - uint8_t max_len_p = 0, max_len_q = 0; - - TAB_BS(fc->tab.horizontal_bs[LUMA], x, y) = bs; - - //fixme: - //edgeTbFlags[ x − sbW ][ y ] is equal to 1 - //edgeTbFlags[ x + sbW ][ y ] is equal to 1 - if (j == 4 || j == height - 4) - max_len_p = max_len_q = 1; - else if (j == 8 || j == height - 8) - max_len_p = max_len_q = 2; - else - max_len_p = max_len_q = 3; - TAB_MAX_LEN(fc->tab.horizontal_p, x, y) = max_len_p; - TAB_MAX_LEN(fc->tab.horizontal_q, x, y) = 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; } } } @@ -528,200 +574,132 @@ static av_always_inline int deblock_bs(const VVCLocalContext *lc, return boundary_strength(lc, mvf_q, mvf_p, rpl_p); } -static void vvc_deblock_bs_luma_vertical(const VVCLocalContext *lc, - const int x0, const int y0, const int width, const int height) +static int deblock_is_boundary(const VVCLocalContext *lc, const int boundary, + const int pos, const int rs, const int vertical) +{ + const VVCFrameContext *fc = lc->fc; + const H266RawSPS *rsps = fc->ps.sps->r; + const H266RawPPS *rpps = fc->ps.pps->r; + int flag; + if (boundary && (pos % fc->ps.sps->ctb_size_y) == 0) { + flag = vertical ? BOUNDARY_LEFT_SLICE : BOUNDARY_UPPER_SLICE; + if (lc->boundary_flags & flag && + !rpps->pps_loop_filter_across_slices_enabled_flag) + return 0; + + flag = vertical ? BOUNDARY_LEFT_TILE : BOUNDARY_UPPER_TILE; + if (lc->boundary_flags & flag && + !rpps->pps_loop_filter_across_tiles_enabled_flag) + return 0; + + flag = vertical ? BOUNDARY_LEFT_SUBPIC : BOUNDARY_UPPER_SUBPIC; + if (lc->boundary_flags & flag) { + const int q_rs = rs - (vertical ? 1 : fc->ps.pps->ctb_width); + const SliceContext *q_slice = lc->fc->slices[lc->fc->tab.slice_idx[q_rs]]; + + if (!rsps->sps_loop_filter_across_subpic_enabled_flag[q_slice->sh.r->curr_subpic_idx] || + !rsps->sps_loop_filter_across_subpic_enabled_flag[lc->sc->sh.r->curr_subpic_idx]) + return 0; + } + } + return 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 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; - int boundary_left; - int has_vertical_sb = 0; + (x0 >> log2_min_pu_size)].pred_flag == PF_INTRA; - const int off_q = (y0 >> min_cb_log2) * min_cb_width + (x0 >> min_cb_log2); - const int cb_x = fc->tab.cb_pos_x[LUMA][off_q]; - const int cb_y = fc->tab.cb_pos_y[LUMA][off_q]; - const int cb_width = fc->tab.cb_width[LUMA][off_q]; - const int off_x = cb_x - x0; + 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 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; - if (!is_intra) { - if (fc->tab.msf[off_q] || fc->tab.iaf[off_q]) - has_vertical_sb = cb_width > 8; - } - - // bs for vertical TU boundaries - boundary_left = x0 > 0 && !(x0 & 3); - if (boundary_left && - ((!fc->ps.pps->r->pps_loop_filter_across_slices_enabled_flag && - lc->boundary_flags & BOUNDARY_LEFT_SLICE && - (x0 % (1 << fc->ps.sps->ctb_log2_size_y)) == 0) || - (!fc->ps.pps->r->pps_loop_filter_across_tiles_enabled_flag && - lc->boundary_flags & BOUNDARY_LEFT_TILE && - (x0 % (1 << fc->ps.sps->ctb_log2_size_y)) == 0))) - boundary_left = 0; - - if (boundary_left) { - const RefPicList *rpl_left = - (lc->boundary_flags & BOUNDARY_LEFT_SLICE) ? ff_vvc_get_ref_list(fc, fc->ref, x0 - 1, y0) : lc->sc->rpl; - for (int i = 0; i < height; i += 4) { + for (int i = 0; i < size; i += 4) { + const int x = x0 + i * !vertical; + const int y = y0 + i * vertical; uint8_t max_len_p, max_len_q; - const int bs = deblock_bs(lc, x0 - 1, y0 + i, x0, y0 + i, rpl_left, 0, off_x, has_vertical_sb); + const int bs = is_vb ? 0 : deblock_bs(lc, x - vertical, y - !vertical, x, y, rpl_p, LUMA, off, has_sb); - TAB_BS(fc->tab.vertical_bs[LUMA], x0, (y0 + i)) = bs; + TAB_BS(fc->tab.bs[vertical][LUMA], x, y) = bs; - derive_max_filter_length_luma(fc, x0, y0 + i, is_intra, has_vertical_sb, 1, &max_len_p, &max_len_q); - TAB_MAX_LEN(fc->tab.vertical_p, x0, y0 + i) = max_len_p; - TAB_MAX_LEN(fc->tab.vertical_q, x0, y0 + i) = max_len_q; + derive_max_filter_length_luma(fc, x, y, is_intra, 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_vertical(lc, cb_x, cb_y, x0, y0, width, height); + vvc_deblock_subblock_bs(lc, cb, x0, y0, width, height, vertical); } } -static void vvc_deblock_bs_luma_horizontal(const VVCLocalContext *lc, - const int x0, const int y0, const int width, const int height) -{ - const VVCFrameContext *fc = lc->fc; - const MvField *tab_mvf = fc->tab.mvf; - 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 is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width + - (x0 >> log2_min_pu_size)].pred_flag == PF_INTRA; - int boundary_upper; - int has_horizontal_sb = 0; - - const int off_q = (y0 >> min_cb_log2) * min_cb_width + (x0 >> min_cb_log2); - const int cb_x = fc->tab.cb_pos_x[LUMA][off_q]; - const int cb_y = fc->tab.cb_pos_y[LUMA][off_q]; - const int cb_height = fc->tab.cb_height[LUMA][off_q]; - const int off_y = y0 - cb_y; - - if (!is_intra) { - if (fc->tab.msf[off_q] || fc->tab.iaf[off_q]) - has_horizontal_sb = cb_height > 8; - } - - boundary_upper = y0 > 0 && !(y0 & 3); - if (boundary_upper && - ((!fc->ps.pps->r->pps_loop_filter_across_slices_enabled_flag && - lc->boundary_flags & BOUNDARY_UPPER_SLICE && - (y0 % (1 << fc->ps.sps->ctb_log2_size_y)) == 0) || - (!fc->ps.pps->r->pps_loop_filter_across_tiles_enabled_flag && - lc->boundary_flags & BOUNDARY_UPPER_TILE && - (y0 % (1 << fc->ps.sps->ctb_log2_size_y)) == 0))) - boundary_upper = 0; - - if (boundary_upper) { - const RefPicList *rpl_top = - (lc->boundary_flags & BOUNDARY_UPPER_SLICE) ? ff_vvc_get_ref_list(fc, fc->ref, x0, y0 - 1) : lc->sc->rpl; - - for (int i = 0; i < width; i += 4) { - uint8_t max_len_p, max_len_q; - const int bs = deblock_bs(lc, x0 + i, y0 - 1, x0 + i, y0, rpl_top, 0, off_y, has_horizontal_sb); - - TAB_BS(fc->tab.horizontal_bs[LUMA], x0 + i, y0) = bs; - - derive_max_filter_length_luma(fc, x0 + i, y0, is_intra, has_horizontal_sb, 0, &max_len_p, &max_len_q); - TAB_MAX_LEN(fc->tab.horizontal_p, x0 + i, y0) = max_len_p; - TAB_MAX_LEN(fc->tab.horizontal_q, x0 + i, y0) = max_len_q; - } - } - - if (!is_intra) { - if (fc->tab.msf[off_q] || fc->tab.iaf[off_q]) - vvc_deblock_subblock_bs_horizontal(lc, cb_x, cb_y, x0, y0, width, height); - } -} - -static void vvc_deblock_bs_chroma_vertical(const VVCLocalContext *lc, - const int x0, const int y0, const int width, const int height) +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 VVCFrameContext *fc = lc->fc; - int boundary_left; + const int shift = (vertical ? fc->ps.sps->hshift : fc->ps.sps->vshift)[CHROMA]; + const int mask = (CHROMA_GRID << shift) - 1; + const int pos = vertical ? x0 : y0; - // bs for vertical TU boundaries - boundary_left = x0 > 0 && !(x0 & ((CHROMA_GRID << fc->ps.sps->hshift[1]) - 1)); - if (boundary_left && - ((!fc->ps.pps->r->pps_loop_filter_across_slices_enabled_flag && - lc->boundary_flags & BOUNDARY_LEFT_SLICE && - (x0 % (1 << fc->ps.sps->ctb_log2_size_y)) == 0) || - (!fc->ps.pps->r->pps_loop_filter_across_tiles_enabled_flag && - lc->boundary_flags & BOUNDARY_LEFT_TILE && - (x0 % (1 << fc->ps.sps->ctb_log2_size_y)) == 0))) - boundary_left = 0; + 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; - if (boundary_left) { - for (int i = 0; i < height; i += 2) { - for (int c_idx = CB; c_idx <= CR; c_idx++) { - const int bs = deblock_bs(lc, x0 - 1, y0 + i, x0, y0 + i, NULL, c_idx, 0, 0); + for (int c_idx = CB; c_idx <= CR; c_idx++) { + 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); - TAB_BS(fc->tab.vertical_bs[c_idx], x0, (y0 + i)) = bs; - } - } - } -} - -static void vvc_deblock_bs_chroma_horizontal(const VVCLocalContext *lc, - const int x0, const int y0, const int width, const int height) -{ - const VVCFrameContext *fc = lc->fc; - int boundary_upper; - - boundary_upper = y0 > 0 && !(y0 & ((CHROMA_GRID << fc->ps.sps->vshift[1]) - 1)); - if (boundary_upper && - ((!fc->ps.pps->r->pps_loop_filter_across_slices_enabled_flag && - lc->boundary_flags & BOUNDARY_UPPER_SLICE && - (y0 % (1 << fc->ps.sps->ctb_log2_size_y)) == 0) || - (!fc->ps.pps->r->pps_loop_filter_across_tiles_enabled_flag && - lc->boundary_flags & BOUNDARY_UPPER_TILE && - (y0 % (1 << fc->ps.sps->ctb_log2_size_y)) == 0))) - boundary_upper = 0; - - if (boundary_upper) { - for (int i = 0; i < width; i += 2) { - for (int c_idx = CB; c_idx <= CR; c_idx++) { - const int bs = deblock_bs(lc, x0 + i, y0 - 1, x0 + i, y0, NULL, c_idx, 0, 0); - - TAB_BS(fc->tab.horizontal_bs[c_idx], x0 + i, y0) = bs; + TAB_BS(fc->tab.bs[vertical][c_idx], x, y) = bs; } } } } typedef void (*deblock_bs_fn)(const VVCLocalContext *lc, const int x0, const int y0, - const int width, const int height); + 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 vertical) +static void vvc_deblock_bs(const VVCLocalContext *lc, const int x0, const int y0, const int rs, const int vertical) { - 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; - deblock_bs_fn deblock_bs[2][2] = { - { vvc_deblock_bs_luma_horizontal, vvc_deblock_bs_chroma_horizontal }, - { vvc_deblock_bs_luma_vertical, vvc_deblock_bs_chroma_vertical } + 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 }; - for (int is_chroma = 0; is_chroma <= 1; is_chroma++) { + 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[vertical][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); + 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); } } } @@ -732,10 +710,8 @@ static void vvc_deblock_bs(const VVCLocalContext *lc, const int x0, const int y0 static void max_filter_length_luma(const VVCFrameContext *fc, const int qx, const int qy, const int vertical, uint8_t *max_len_p, uint8_t *max_len_q) { - const uint8_t *tab_len_p = vertical ? fc->tab.vertical_p : fc->tab.horizontal_p; - const uint8_t *tab_len_q = vertical ? fc->tab.vertical_q : fc->tab.horizontal_q; - *max_len_p = TAB_MAX_LEN(tab_len_p, qx, qy); - *max_len_q = TAB_MAX_LEN(tab_len_q, qx, qy); + *max_len_p = TAB_MAX_LEN(fc->tab.max_len_p[vertical], qx, qy); + *max_len_q = TAB_MAX_LEN(fc->tab.max_len_q[vertical], qx, qy); } //part of 8.8.3.3 Derivation process of transform block boundary @@ -805,148 +781,79 @@ static int get_qp(const VVCFrameContext *fc, const uint8_t *src, const int x, co return get_qp_c(fc, x, y, c_idx, vertical); } -void ff_vvc_deblock_vertical(const VVCLocalContext *lc, int x0, int y0) +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; - uint8_t *src; - int x, y, qp; + 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 } ; + const uint8_t no_p[4] = { 0 }; + const uint8_t no_q[4] = { 0 } ; - const int ctb_log2_size_y = fc->ps.sps->ctb_log2_size_y; - int x_end, y_end; - const int ctb_size = 1 << ctb_log2_size_y; - const int ctb = (x0 >> ctb_log2_size_y) + - (y0 >> ctb_log2_size_y) * fc->ps.pps->ctb_width; - const DBParams *params = fc->tab.deblock + ctb; + vvc_deblock_bs(lc, x0, y0, rs, vertical); - vvc_deblock_bs(lc, x0, y0, 1); - - x_end = x0 + ctb_size; - if (x_end > fc->ps.pps->width) - x_end = fc->ps.pps->width; - y_end = y0 + ctb_size; - if (y_end > fc->ps.pps->height) - y_end = fc->ps.pps->height; + if (!vertical) { + FFSWAP(int, x_end, y_end); + FFSWAP(int, x0, y0); + } for (int c_idx = 0; c_idx < c_end; c_idx++) { - const int hs = sps->hshift[c_idx]; - const int vs = sps->vshift[c_idx]; + const int hs = (vertical ? sps->hshift : sps->vshift)[c_idx]; + const int vs = (vertical ? sps->vshift : sps->hshift)[c_idx]; const int grid = c_idx ? (CHROMA_GRID << hs) : LUMA_GRID; const int tc_offset = params->tc_offset[c_idx]; const int beta_offset = params->beta_offset[c_idx]; + const int src_stride = fc->frame->linesize[c_idx]; - for (y = y0; y < y_end; y += (DEBLOCK_STEP << vs)) { - for (x = x0 ? x0 : grid; x < x_end; x += grid) { - int32_t bs[4], beta[4], tc[4], all_zero_bs = 1; + for (int y = y0; y < y_end; y += (DEBLOCK_STEP << vs)) { + for (int x = x0 ? x0 : grid; x < x_end; x += grid) { + 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]; for (int i = 0; i < DEBLOCK_STEP >> (2 - vs); i++) { - const int dy = i << 2; - bs[i] = (y + dy < y_end) ? TAB_BS(fc->tab.vertical_bs[c_idx], x, y + dy) : 0; + int tx = x; + int ty = y + (i << 2); + const int end = ty >= y_end; + + if (!vertical) + FFSWAP(int, tx, ty); + + bs[i] = end ? 0 : TAB_BS(fc->tab.bs[vertical][c_idx], tx, ty); if (bs[i]) { - src = &fc->frame->data[c_idx][((y + dy) >> vs) * fc->frame->linesize[c_idx] + ((x >> hs) << fc->ps.sps->pixel_shift)]; - qp = get_qp(fc, src, x, y + dy, c_idx, 1); - + const int qp = get_qp(fc, POS(c_idx, tx, ty), tx, ty, c_idx, vertical); beta[i] = betatable[av_clip(qp + beta_offset, 0, MAX_QP)]; - - max_filter_length(fc, x, y + dy, c_idx, 1, 0, bs[i], &max_len_p[i], &max_len_q[i]); + 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; } - tc[i] = bs[i] ? TC_CALC(qp, bs[i]) : 0; } if (!all_zero_bs) { - src = &fc->frame->data[c_idx][(y >> vs) * fc->frame->linesize[c_idx] + ((x >> hs) << fc->ps.sps->pixel_shift)]; - if (!c_idx) { - fc->vvcdsp.lf.filter_luma[1](src, fc->frame->linesize[c_idx], - beta, tc, no_p, no_q, max_len_p, max_len_q, 0); - } else { - fc->vvcdsp.lf.filter_chroma[1](src, fc->frame->linesize[c_idx], - beta, tc, no_p, no_q, max_len_p, max_len_q, vs); - } + uint8_t *src = vertical ? POS(c_idx, x, y) : POS(c_idx, y, x); + if (!c_idx) + fc->vvcdsp.lf.filter_luma[vertical](src, src_stride, beta, tc, no_p, no_q, max_len_p, max_len_q, horizontal_ctu_edge); + else + fc->vvcdsp.lf.filter_chroma[vertical](src, src_stride, beta, tc, no_p, no_q, max_len_p, max_len_q, vs); } } } } } -void ff_vvc_deblock_horizontal(const VVCLocalContext *lc, int x0, int y0) +void ff_vvc_deblock_vertical(const VVCLocalContext *lc, const int x0, const int y0, const int rs) { - VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const int c_end = fc->ps.sps->r->sps_chroma_format_idc ? VVC_MAX_SAMPLE_ARRAYS : 1; - uint8_t* src; - int x, y, qp; + vvc_deblock(lc, x0, y0, rs, 1); +} - //not use this yet, may needed by plt. - const uint8_t no_p[4] = { 0 }; - const uint8_t no_q[4] = { 0 } ; - - const int ctb_log2_size_y = fc->ps.sps->ctb_log2_size_y; - int x_end, y_end; - const int ctb_size = 1 << ctb_log2_size_y; - const int ctb = (x0 >> ctb_log2_size_y) + - (y0 >> ctb_log2_size_y) * fc->ps.pps->ctb_width; - const DBParams *params = fc->tab.deblock + ctb; - - vvc_deblock_bs(lc, x0, y0, 0); - - x_end = x0 + ctb_size; - if (x_end > fc->ps.pps->width) - x_end = fc->ps.pps->width; - y_end = y0 + ctb_size; - if (y_end > fc->ps.pps->height) - y_end = fc->ps.pps->height; - - for (int c_idx = 0; c_idx < c_end; c_idx++) { - const int hs = sps->hshift[c_idx]; - const int vs = sps->vshift[c_idx]; - const int grid = c_idx ? (CHROMA_GRID << vs) : LUMA_GRID; - const int beta_offset = params->beta_offset[c_idx]; - const int tc_offset = params->tc_offset[c_idx]; - - for (y = y0; y < y_end; y += grid) { - const uint8_t horizontal_ctu_edge = !(y % fc->ps.sps->ctb_size_y); - if (!y) - continue; - - for (x = x0 ? x0: 0; x < x_end; x += (DEBLOCK_STEP << hs)) { - int32_t bs[4], beta[4], tc[4], all_zero_bs = 1; - uint8_t max_len_p[4], max_len_q[4]; - - for (int i = 0; i < DEBLOCK_STEP >> (2 - hs); i++) { - const int dx = i << 2; - - bs[i] = (x + dx < x_end) ? TAB_BS(fc->tab.horizontal_bs[c_idx], x + dx, y) : 0; - if (bs[i]) { - src = &fc->frame->data[c_idx][(y >> vs) * fc->frame->linesize[c_idx] + (((x + dx)>> hs) << fc->ps.sps->pixel_shift)]; - qp = get_qp(fc, src, x + dx, y, c_idx, 0); - - beta[i] = betatable[av_clip(qp + beta_offset, 0, MAX_QP)]; - - max_filter_length(fc, x + dx, y, c_idx, 0, horizontal_ctu_edge, bs[i], &max_len_p[i], &max_len_q[i]); - all_zero_bs = 0; - } - tc[i] = bs[i] ? TC_CALC(qp, bs[i]) : 0; - } - if (!all_zero_bs) { - src = &fc->frame->data[c_idx][(y >> vs) * fc->frame->linesize[c_idx] + ((x >> hs) << fc->ps.sps->pixel_shift)]; - if (!c_idx) { - fc->vvcdsp.lf.filter_luma[0](src, fc->frame->linesize[c_idx], - beta, tc, no_p, no_q, max_len_p, max_len_q, horizontal_ctu_edge); - } else { - fc->vvcdsp.lf.filter_chroma[0](src, fc->frame->linesize[c_idx], - beta, tc, no_p, no_q, max_len_p, max_len_q, hs); - } - } - } - } - } +void ff_vvc_deblock_horizontal(const VVCLocalContext *lc, const int x0, const int y0, const int rs) +{ + vvc_deblock(lc, x0, y0, rs, 0); } static void alf_copy_border(uint8_t *dst, const uint8_t *src, @@ -994,7 +901,7 @@ static void alf_extend_horz(uint8_t *dst, const uint8_t *src, } static void alf_copy_ctb_to_hv(VVCFrameContext *fc, const uint8_t *src, const ptrdiff_t src_stride, - const int x, const int y, const int width, const int height, const int x_ctb, const int y_ctb, const int c_idx) + const int x, const int y, const int width, const int height, const int rx, const int ry, const int c_idx) { const int ps = fc->ps.sps->pixel_shift; const int w = fc->ps.pps->width >> fc->ps.sps->hshift[c_idx]; @@ -1005,12 +912,12 @@ static void alf_copy_ctb_to_hv(VVCFrameContext *fc, const uint8_t *src, const pt /* copy horizontal edges */ for (int i = 0; i < FF_ARRAY_ELEMS(offset_h); i++) { - alf_copy_border(fc->tab.alf_pixel_buffer_h[c_idx][i] + ((border_pixels * y_ctb * w + x)<< ps), + alf_copy_border(fc->tab.alf_pixel_buffer_h[c_idx][i] + ((border_pixels * ry * w + x)<< ps), src + offset_h[i] * src_stride, ps, width, border_pixels, w << ps, src_stride); } /* copy vertical edges */ for (int i = 0; i < FF_ARRAY_ELEMS(offset_v); i++) { - alf_copy_border(fc->tab.alf_pixel_buffer_v[c_idx][i] + ((h * x_ctb + y) * (border_pixels << ps)), + alf_copy_border(fc->tab.alf_pixel_buffer_v[c_idx][i] + ((h * rx + y) * (border_pixels << ps)), src + (offset_v[i] << ps), ps, border_pixels, height, border_pixels << ps, src_stride); } } @@ -1050,7 +957,7 @@ static void alf_fill_border_v(uint8_t *dst, const ptrdiff_t dst_stride, const ui } static void alf_prepare_buffer(VVCFrameContext *fc, uint8_t *_dst, const uint8_t *_src, const int x, const int y, - const int x_ctb, const int y_ctb, const int width, const int height, const ptrdiff_t dst_stride, const ptrdiff_t src_stride, + const int rx, const int ry, const int width, const int height, const ptrdiff_t dst_stride, const ptrdiff_t src_stride, const int c_idx, const int *edges) { const int ps = fc->ps.sps->pixel_shift; @@ -1062,23 +969,23 @@ static void alf_prepare_buffer(VVCFrameContext *fc, uint8_t *_dst, const uint8_t copy_ctb(_dst, _src, width << ps, height, dst_stride, src_stride); //top - src = fc->tab.alf_pixel_buffer_h[c_idx][1] + (((border_pixels * w) << ps) * (y_ctb - 1) + (x << ps)); + src = fc->tab.alf_pixel_buffer_h[c_idx][1] + (((border_pixels * w) << ps) * (ry - 1) + (x << ps)); dst = _dst - border_pixels * dst_stride; alf_fill_border_h(dst, dst_stride, src, w << ps, _dst, width, border_pixels, ps, edges[TOP]); //bottom - src = fc->tab.alf_pixel_buffer_h[c_idx][0] + (((border_pixels * w) << ps) * (y_ctb + 1) + (x << ps)); + src = fc->tab.alf_pixel_buffer_h[c_idx][0] + (((border_pixels * w) << ps) * (ry + 1) + (x << ps)); dst = _dst + height * dst_stride; alf_fill_border_h(dst, dst_stride, src, w << ps, _dst + (height - 1) * dst_stride, width, border_pixels, ps, edges[BOTTOM]); //left - src = fc->tab.alf_pixel_buffer_v[c_idx][1] + (h * (x_ctb - 1) + y - border_pixels) * (border_pixels << ps); + src = fc->tab.alf_pixel_buffer_v[c_idx][1] + (h * (rx - 1) + y - border_pixels) * (border_pixels << ps); dst = _dst - (border_pixels << ps) - border_pixels * dst_stride; alf_fill_border_v(dst, dst_stride, src, dst + (border_pixels << ps), border_pixels, height, ps, edges, edges[LEFT]); //right - src = fc->tab.alf_pixel_buffer_v[c_idx][0] + (h * (x_ctb + 1) + y - border_pixels) * (border_pixels << ps); + src = fc->tab.alf_pixel_buffer_v[c_idx][0] + (h * (rx + 1) + y - border_pixels) * (border_pixels << ps); dst = _dst + (width << ps) - border_pixels * dst_stride; alf_fill_border_v(dst, dst_stride, src, dst - (1 << ps), border_pixels, height, ps, edges, edges[RIGHT]); } @@ -1087,7 +994,7 @@ static void alf_prepare_buffer(VVCFrameContext *fc, uint8_t *_dst, const uint8_t #define ALF_MAX_FILTER_SIZE (ALF_MAX_BLOCKS_IN_CTU * ALF_NUM_COEFF_LUMA) static void alf_get_coeff_and_clip(VVCLocalContext *lc, int16_t *coeff, int16_t *clip, - const uint8_t *src, ptrdiff_t src_stride, int width, int height, int vb_pos, ALFParams *alf) + const uint8_t *src, ptrdiff_t src_stride, int width, int height, int vb_pos, const ALFParams *alf) { const VVCFrameContext *fc = lc->fc; const H266RawSliceHeader *rsh = lc->sc->sh.r; @@ -1118,7 +1025,7 @@ static void alf_get_coeff_and_clip(VVCLocalContext *lc, int16_t *coeff, int16_t static void alf_filter_luma(VVCLocalContext *lc, uint8_t *dst, const uint8_t *src, const ptrdiff_t dst_stride, const ptrdiff_t src_stride, const int x0, const int y0, - const int width, const int height, const int _vb_pos, ALFParams *alf) + const int width, const int height, const int _vb_pos, const ALFParams *alf) { const VVCFrameContext *fc = lc->fc; int vb_pos = _vb_pos - y0; @@ -1142,7 +1049,7 @@ static int alf_clip_from_idx(const VVCFrameContext *fc, const int idx) static void alf_filter_chroma(VVCLocalContext *lc, uint8_t *dst, const uint8_t *src, const ptrdiff_t dst_stride, const ptrdiff_t src_stride, const int c_idx, - const int width, const int height, const int vb_pos, ALFParams *alf) + const int width, const int height, const int vb_pos, const ALFParams *alf) { VVCFrameContext *fc = lc->fc; const H266RawSliceHeader *rsh = lc->sc->sh.r; @@ -1159,7 +1066,7 @@ static void alf_filter_chroma(VVCLocalContext *lc, uint8_t *dst, const uint8_t * static void alf_filter_cc(VVCLocalContext *lc, uint8_t *dst, const uint8_t *luma, const ptrdiff_t dst_stride, const ptrdiff_t luma_stride, const int c_idx, - const int width, const int height, const int hs, const int vs, const int vb_pos, ALFParams *alf) + const int width, const int height, const int hs, const int vs, const int vb_pos, const ALFParams *alf) { const VVCFrameContext *fc = lc->fc; const H266RawSliceHeader *rsh = lc->sc->sh.r; @@ -1177,10 +1084,9 @@ static void alf_filter_cc(VVCLocalContext *lc, uint8_t *dst, const uint8_t *luma void ff_vvc_alf_copy_ctu_to_hv(VVCLocalContext* lc, const int x0, const int y0) { VVCFrameContext *fc = lc->fc; - const int x_ctb = x0 >> fc->ps.sps->ctb_log2_size_y; - const int y_ctb = y0 >> fc->ps.sps->ctb_log2_size_y; + const int rx = x0 >> fc->ps.sps->ctb_log2_size_y; + const int ry = y0 >> fc->ps.sps->ctb_log2_size_y; const int ctb_size_y = fc->ps.sps->ctb_size_y; - const int ps = fc->ps.sps->pixel_shift; const int c_end = fc->ps.sps->r->sps_chroma_format_idc ? VVC_MAX_SAMPLE_ARRAYS : 1; for (int c_idx = 0; c_idx < c_end; c_idx++) { @@ -1192,76 +1098,144 @@ void ff_vvc_alf_copy_ctu_to_hv(VVCLocalContext* lc, const int x0, const int y0) const int height = FFMIN(fc->ps.pps->height - y0, ctb_size_y) >> vs; const int src_stride = fc->frame->linesize[c_idx]; - uint8_t* src = &fc->frame->data[c_idx][y * src_stride + (x << ps)]; + uint8_t *src = POS(c_idx, x0, y0); - alf_copy_ctb_to_hv(fc, src, src_stride, x, y, width, height, x_ctb, y_ctb, c_idx); + alf_copy_ctb_to_hv(fc, src, src_stride, x, y, width, height, rx, ry, c_idx); } } +static void alf_get_edges(const VVCLocalContext *lc, int edges[MAX_EDGES], const int rx, const int ry) +{ + VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const VVCPPS *pps = fc->ps.pps; + const int subpic_idx = lc->sc->sh.r->curr_subpic_idx; + + // we can't use |= instead of || in this function; |= is not a shortcut operator + + if (!pps->r->pps_loop_filter_across_tiles_enabled_flag) { + edges[LEFT] = edges[LEFT] || (lc->boundary_flags & BOUNDARY_LEFT_TILE); + edges[TOP] = edges[TOP] || (lc->boundary_flags & BOUNDARY_UPPER_TILE); + edges[RIGHT] = edges[RIGHT] || pps->ctb_to_col_bd[rx] != pps->ctb_to_col_bd[rx + 1]; + edges[BOTTOM] = edges[BOTTOM] || pps->ctb_to_row_bd[ry] != pps->ctb_to_row_bd[ry + 1]; + } + + if (!pps->r->pps_loop_filter_across_slices_enabled_flag) { + edges[LEFT] = edges[LEFT] || (lc->boundary_flags & BOUNDARY_LEFT_SLICE); + edges[TOP] = edges[TOP] || (lc->boundary_flags & BOUNDARY_UPPER_SLICE); + edges[RIGHT] = edges[RIGHT] || CTB(fc->tab.slice_idx, rx, ry) != CTB(fc->tab.slice_idx, rx + 1, ry); + edges[BOTTOM] = edges[BOTTOM] || CTB(fc->tab.slice_idx, rx, ry) != CTB(fc->tab.slice_idx, rx, ry + 1); + } + + if (!sps->r->sps_loop_filter_across_subpic_enabled_flag[subpic_idx]) { + edges[LEFT] = edges[LEFT] || (lc->boundary_flags & BOUNDARY_LEFT_SUBPIC); + edges[TOP] = edges[TOP] || (lc->boundary_flags & BOUNDARY_UPPER_SUBPIC); + edges[RIGHT] = edges[RIGHT] || fc->ps.sps->r->sps_subpic_ctu_top_left_x[subpic_idx] + fc->ps.sps->r->sps_subpic_width_minus1[subpic_idx] == rx; + edges[BOTTOM] = edges[BOTTOM] || fc->ps.sps->r->sps_subpic_ctu_top_left_y[subpic_idx] + fc->ps.sps->r->sps_subpic_height_minus1[subpic_idx] == ry; + } + + if (sps->r->sps_virtual_boundaries_enabled_flag) { + edges[LEFT] = edges[LEFT] || is_virtual_boundary(fc, rx << sps->ctb_log2_size_y, 1); + edges[TOP] = edges[TOP] || is_virtual_boundary(fc, ry << sps->ctb_log2_size_y, 0); + edges[RIGHT] = edges[RIGHT] || is_virtual_boundary(fc, (rx + 1) << sps->ctb_log2_size_y, 1); + edges[BOTTOM] = edges[BOTTOM] || is_virtual_boundary(fc, (ry + 1) << sps->ctb_log2_size_y, 0); + } +} + +static void alf_init_subblock(VVCRect *sb, int sb_edges[MAX_EDGES], const VVCRect *b, const int edges[MAX_EDGES]) +{ + *sb = *b; + memcpy(sb_edges, edges, sizeof(int) * MAX_EDGES); +} + +static void alf_get_subblock(VVCRect *sb, int edges[MAX_EDGES], const int bx, const int by, const int vb_pos[2], const int has_vb[2]) +{ + int *pos[] = { &sb->l, &sb->t, &sb->r, &sb->b }; + + for (int vertical = 0; vertical <= 1; vertical++) { + if (has_vb[vertical]) { + const int c = vertical ? (bx ? LEFT : RIGHT) : (by ? TOP : BOTTOM); + *pos[c] = vb_pos[vertical]; + edges[c] = 1; + } + } +} + +static void alf_get_subblocks(const VVCLocalContext *lc, VVCRect sbs[MAX_VBBS], int sb_edges[MAX_VBBS][MAX_EDGES], int *nb_sbs, + const int x0, const int y0, const int rx, const int ry) +{ + VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const VVCPPS *pps = fc->ps.pps; + const int ctu_size_y = sps->ctb_size_y; + const int vb_pos[] = { get_virtual_boundary(fc, ry, 0), get_virtual_boundary(fc, rx, 1) }; + const int has_vb[] = { vb_pos[0] > y0, vb_pos[1] > x0 }; + const VVCRect b = { x0, y0, FFMIN(x0 + ctu_size_y, pps->width), FFMIN(y0 + ctu_size_y, pps->height) }; + int edges[MAX_EDGES] = { !rx, !ry, rx == pps->ctb_width - 1, ry == pps->ctb_height - 1 }; + int i = 0; + + alf_get_edges(lc, edges, rx, ry); + + for (int by = 0; by <= has_vb[0]; by++) { + for (int bx = 0; bx <= has_vb[1]; bx++, i++) { + alf_init_subblock(sbs + i, sb_edges[i], &b, edges); + alf_get_subblock(sbs + i, sb_edges[i], bx, by, vb_pos, has_vb); + } + } + *nb_sbs = i; +} + void ff_vvc_alf_filter(VVCLocalContext *lc, const int x0, const int y0) { VVCFrameContext *fc = lc->fc; - const VVCPPS *pps = fc->ps.pps; - const int x_ctb = x0 >> fc->ps.sps->ctb_log2_size_y; - const int y_ctb = y0 >> fc->ps.sps->ctb_log2_size_y; - const int ctb_size_y = fc->ps.sps->ctb_size_y; - const int ps = fc->ps.sps->pixel_shift; + const VVCSPS *sps = fc->ps.sps; + const int rx = x0 >> sps->ctb_log2_size_y; + const int ry = y0 >> sps->ctb_log2_size_y; + const int ps = sps->pixel_shift; const int padded_stride = EDGE_EMU_BUFFER_STRIDE << ps; const int padded_offset = padded_stride * ALF_PADDING_SIZE + (ALF_PADDING_SIZE << ps); - const int c_end = fc->ps.sps->r->sps_chroma_format_idc ? VVC_MAX_SAMPLE_ARRAYS : 1; - ALFParams *alf = &CTB(fc->tab.alf, x_ctb, y_ctb); - int edges[MAX_EDGES] = { x_ctb == 0, y_ctb == 0, x_ctb == pps->ctb_width - 1, y_ctb == pps->ctb_height - 1 }; + const int c_end = sps->r->sps_chroma_format_idc ? VVC_MAX_SAMPLE_ARRAYS : 1; + const int has_chroma = !!sps->r->sps_chroma_format_idc; + const int ctu_end = y0 + sps->ctb_size_y; + const ALFParams *alf = &CTB(fc->tab.alf, rx, ry); + int sb_edges[MAX_VBBS][MAX_EDGES], nb_sbs; + VVCRect sbs[MAX_VBBS]; - if (!pps->r->pps_loop_filter_across_tiles_enabled_flag) { - edges[LEFT] = edges[LEFT] || (lc->boundary_flags & BOUNDARY_LEFT_TILE); - edges[TOP] = edges[TOP] || (lc->boundary_flags & BOUNDARY_UPPER_TILE); - edges[RIGHT] = edges[RIGHT] || pps->ctb_to_col_bd[x_ctb] != pps->ctb_to_col_bd[x_ctb + 1]; - edges[BOTTOM] = edges[BOTTOM] || pps->ctb_to_row_bd[y_ctb] != pps->ctb_to_row_bd[y_ctb + 1]; - } + alf_get_subblocks(lc, sbs, sb_edges, &nb_sbs, x0, y0, rx, ry); - if (!pps->r->pps_loop_filter_across_slices_enabled_flag) { - edges[LEFT] = edges[LEFT] || (lc->boundary_flags & BOUNDARY_LEFT_SLICE); - edges[TOP] = edges[TOP] || (lc->boundary_flags & BOUNDARY_UPPER_SLICE); - edges[RIGHT] = edges[RIGHT] || CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb + 1, y_ctb); - edges[BOTTOM] = edges[BOTTOM] || CTB(fc->tab.slice_idx, x_ctb, y_ctb) != CTB(fc->tab.slice_idx, x_ctb, y_ctb + 1); - } + for (int i = 0; i < nb_sbs; i++) { + const VVCRect *sb = sbs + i; + for (int c_idx = 0; c_idx < c_end; c_idx++) { + const int hs = fc->ps.sps->hshift[c_idx]; + const int vs = fc->ps.sps->vshift[c_idx]; + const int x = sb->l >> hs; + const int y = sb->t >> vs; + const int width = (sb->r - sb->l) >> hs; + const int height = (sb->b - sb->t) >> vs; + const int src_stride = fc->frame->linesize[c_idx]; + uint8_t *src = POS(c_idx, sb->l, sb->t); + uint8_t *padded; - for (int c_idx = 0; c_idx < c_end; c_idx++) { - const int hs = fc->ps.sps->hshift[c_idx]; - const int vs = fc->ps.sps->vshift[c_idx]; - const int ctb_size_h = ctb_size_y >> hs; - const int ctb_size_v = ctb_size_y >> vs; - const int x = x0 >> hs; - const int y = y0 >> vs; - const int pic_width = fc->ps.pps->width >> hs; - const int pic_height = fc->ps.pps->height >> vs; - const int width = FFMIN(pic_width - x, ctb_size_h); - const int height = FFMIN(pic_height - y, ctb_size_v); - const int src_stride = fc->frame->linesize[c_idx]; - uint8_t *src = &fc->frame->data[c_idx][y * src_stride + (x << ps)]; - uint8_t *padded; - - if (alf->ctb_flag[c_idx] || (!c_idx && (alf->ctb_cc_idc[0] || alf->ctb_cc_idc[1]))) { - padded = (c_idx ? lc->alf_buffer_chroma : lc->alf_buffer_luma) + padded_offset; - alf_prepare_buffer(fc, padded, src, x, y, x_ctb, y_ctb, width, height, - padded_stride, src_stride, c_idx, edges); - } - if (alf->ctb_flag[c_idx]) { - if (!c_idx) { - alf_filter_luma(lc, src, padded, src_stride, padded_stride, x, y, - width, height, y + ctb_size_v - ALF_VB_POS_ABOVE_LUMA, alf); - } else { - alf_filter_chroma(lc, src, padded, src_stride, padded_stride, c_idx, - width, height, ctb_size_v - ALF_VB_POS_ABOVE_CHROMA, alf); + if (alf->ctb_flag[c_idx] || (!c_idx && has_chroma && (alf->ctb_cc_idc[0] || alf->ctb_cc_idc[1]))) { + padded = (c_idx ? lc->alf_buffer_chroma : lc->alf_buffer_luma) + padded_offset; + alf_prepare_buffer(fc, padded, src, x, y, rx, ry, width, height, + padded_stride, src_stride, c_idx, sb_edges[i]); + } + if (alf->ctb_flag[c_idx]) { + if (!c_idx) { + alf_filter_luma(lc, src, padded, src_stride, padded_stride, x, y, + width, height, ctu_end - ALF_VB_POS_ABOVE_LUMA, alf); + } else { + alf_filter_chroma(lc, src, padded, src_stride, padded_stride, c_idx, + width, height, ((ctu_end - sb->t) >> vs) - ALF_VB_POS_ABOVE_CHROMA, alf); + } + } + if (c_idx && alf->ctb_cc_idc[c_idx - 1]) { + padded = lc->alf_buffer_luma + padded_offset; + alf_filter_cc(lc, src, padded, src_stride, padded_stride, c_idx, + width, height, hs, vs, ctu_end - sb->t - ALF_VB_POS_ABOVE_LUMA, alf); } } - if (c_idx && alf->ctb_cc_idc[c_idx - 1]) { - padded = lc->alf_buffer_luma + padded_offset; - alf_filter_cc(lc, src, padded, src_stride, padded_stride, c_idx, - width, height, hs, vs, (ctb_size_v << vs) - ALF_VB_POS_ABOVE_LUMA, alf); - } - - alf->applied[c_idx] = 1; } } @@ -1273,7 +1247,7 @@ void ff_vvc_lmcs_filter(const VVCLocalContext *lc, const int x, const int y) const int ctb_size = fc->ps.sps->ctb_size_y; const int width = FFMIN(fc->ps.pps->width - x, ctb_size); const int height = FFMIN(fc->ps.pps->height - y, ctb_size); - uint8_t *data = fc->frame->data[LUMA] + y * fc->frame->linesize[LUMA] + (x << fc->ps.sps->pixel_shift); + uint8_t *data = POS(LUMA, x, y); if (sc->sh.r->sh_lmcs_used_flag) fc->vvcdsp.lmcs.filter(data, fc->frame->linesize[LUMA], width, height, &fc->ps.lmcs.inv_lut); } diff --git a/libavcodec/vvc/vvc_filter.h b/libavcodec/vvc/filter.h similarity index 90% rename from libavcodec/vvc/vvc_filter.h rename to libavcodec/vvc/filter.h index 2ae4c33e2..03cc74e07 100644 --- a/libavcodec/vvc/vvc_filter.h +++ b/libavcodec/vvc/filter.h @@ -20,10 +20,10 @@ * 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_VVC_FILTER_H -#define AVCODEC_VVC_VVC_FILTER_H +#ifndef AVCODEC_VVC_FILTER_H +#define AVCODEC_VVC_FILTER_H -#include "vvcdec.h" +#include "dec.h" /** * lmcs filter for the CTU @@ -38,16 +38,18 @@ void ff_vvc_lmcs_filter(const VVCLocalContext *lc, const int x0, const int y0); * @param lc local context for CTU * @param x0 x position for the CTU * @param y0 y position for the CTU + * @param rs raster position for the CTU */ -void ff_vvc_deblock_vertical(const VVCLocalContext *lc, int x0, int y0); +void ff_vvc_deblock_vertical(const VVCLocalContext *lc, int x0, int y0, int rs); /** * horizontal deblock filter for the CTU * @param lc local context for CTU * @param x0 x position for the CTU * @param y0 y position for the CTU + * @param rs raster position for the CTU */ -void ff_vvc_deblock_horizontal(const VVCLocalContext *lc, int x0, int y0); +void ff_vvc_deblock_horizontal(const VVCLocalContext *lc, int x0, int y0, int rs); /** * sao filter for the CTU @@ -68,4 +70,4 @@ void ff_vvc_alf_copy_ctu_to_hv(VVCLocalContext* lc, int x0, int y0); */ void ff_vvc_alf_filter(VVCLocalContext *lc, const int x0, const int y0); -#endif // AVCODEC_VVC_VVC_CTU_H +#endif // AVCODEC_VVC_CTU_H diff --git a/libavcodec/vvc/vvc_filter_template.c b/libavcodec/vvc/filter_template.c similarity index 98% rename from libavcodec/vvc/vvc_filter_template.c rename to libavcodec/vvc/filter_template.c index 9b3a0e46f..6dd731008 100644 --- a/libavcodec/vvc/vvc_filter_template.c +++ b/libavcodec/vvc/filter_template.c @@ -77,7 +77,7 @@ static void FUNC(alf_filter_luma)(uint8_t *_dst, ptrdiff_t dst_stride, const uin const int is_near_vb_below = (y + i >= vb_pos) && (y + i <= vb_pos); const int is_near_vb = is_near_vb_above || is_near_vb_below; - if ((y + i < vb_pos) && ((y + i) >= vb_above)) { + if ((y + i < vb_pos) && ((y + i) > vb_above)) { p1 = (y + i == vb_pos - 1) ? p0 : p1; p3 = (y + i >= vb_pos - 2) ? p1 : p3; p5 = (y + i >= vb_pos - 3) ? p3 : p5; @@ -85,7 +85,7 @@ static void FUNC(alf_filter_luma)(uint8_t *_dst, ptrdiff_t dst_stride, const uin p2 = (y + i == vb_pos - 1) ? p0 : p2; p4 = (y + i >= vb_pos - 2) ? p2 : p4; p6 = (y + i >= vb_pos - 3) ? p4 : p6; - } else if ((y + i >= vb_pos) && ((y + i) <= vb_below)) { + } else if ((y + i >= vb_pos) && ((y + i) < vb_below)) { p2 = (y + i == vb_pos ) ? p0 : p2; p4 = (y + i <= vb_pos + 1) ? p2 : p4; p6 = (y + i <= vb_pos + 2) ? p4 : p6; @@ -153,8 +153,6 @@ static void FUNC(alf_filter_chroma)(uint8_t* _dst, ptrdiff_t dst_stride, const u const pixel *s2 = s0 - src_stride; const pixel *s3 = s1 + src_stride; const pixel *s4 = s2 - src_stride; - const pixel *s5 = s3 + src_stride; - const pixel *s6 = s4 - src_stride; for (int i = 0; i < ALF_BLOCK_SIZE; i++) { pixel *dst = (pixel *)_dst + (y + i) * dst_stride + x; @@ -164,8 +162,6 @@ static void FUNC(alf_filter_chroma)(uint8_t* _dst, ptrdiff_t dst_stride, const u const pixel *p2 = s2 + i * src_stride; const pixel *p3 = s3 + i * src_stride; const pixel *p4 = s4 + i * src_stride; - const pixel *p5 = s5 + i * src_stride; - const pixel *p6 = s6 + i * src_stride; const int is_near_vb_above = (y + i < vb_pos) && (y + i >= vb_pos - 1); const int is_near_vb_below = (y + i >= vb_pos) && (y + i <= vb_pos); @@ -174,19 +170,15 @@ static void FUNC(alf_filter_chroma)(uint8_t* _dst, ptrdiff_t dst_stride, const u if ((y + i < vb_pos) && ((y + i) >= vb_above)) { p1 = (y + i == vb_pos - 1) ? p0 : p1; p3 = (y + i >= vb_pos - 2) ? p1 : p3; - p5 = (y + i >= vb_pos - 3) ? p3 : p5; p2 = (y + i == vb_pos - 1) ? p0 : p2; p4 = (y + i >= vb_pos - 2) ? p2 : p4; - p6 = (y + i >= vb_pos - 3) ? p4 : p6; } else if ((y + i >= vb_pos) && ((y + i) <= vb_below)) { p2 = (y + i == vb_pos ) ? p0 : p2; p4 = (y + i <= vb_pos + 1) ? p2 : p4; - p6 = (y + i <= vb_pos + 2) ? p4 : p6; p1 = (y + i == vb_pos ) ? p0 : p1; p3 = (y + i <= vb_pos + 1) ? p1 : p3; - p5 = (y + i <= vb_pos + 2) ? p3 : p5; } for (int j = 0; j < ALF_BLOCK_SIZE; j++) { @@ -212,8 +204,6 @@ static void FUNC(alf_filter_chroma)(uint8_t* _dst, ptrdiff_t dst_stride, const u p2++; p3++; p4++; - p5++; - p6++; } } } diff --git a/libavcodec/vvc/inter.c b/libavcodec/vvc/inter.c new file mode 100644 index 000000000..64a9dd1e4 --- /dev/null +++ b/libavcodec/vvc/inter.c @@ -0,0 +1,1026 @@ +/* + * VVC inter prediction + * + * Copyright (C) 2022 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 "libavutil/frame.h" + +#include "data.h" +#include "inter.h" +#include "mvs.h" +#include "refs.h" + +// +1 is enough, + 32 for asm alignment +#define PROF_TEMP_OFFSET (MAX_PB_SIZE + 32) +static const int bcw_w_lut[] = {4, 5, 3, 10, -2}; + +static void subpic_get_rect(VVCRect *r, const VVCFrame *src_frame, const int subpic_idx, const int is_chroma) +{ + const VVCSPS *sps = src_frame->sps; + const VVCPPS *pps = src_frame->pps; + const int hs = sps->hshift[is_chroma]; + const int vs = sps->vshift[is_chroma]; + + r->l = pps->subpic_x[subpic_idx] >> hs; + r->t = pps->subpic_y[subpic_idx] >> vs; + r->r = r->l + (pps->subpic_width[subpic_idx] >> hs); + r->b = r->t + (pps->subpic_height[subpic_idx] >> vs); +} + +// clip to subblock and subpicture process in 8.5.6.3.2 Luma sample interpolation filtering process +static void clip_to_subpic(int *x_off, int *y_off, int *pic_width, int *pic_height, const VVCRect *subpic, const VVCRect *sb, const int dmvr_clip) +{ + const int l = dmvr_clip ? FFMIN(FFMAX(subpic->l, sb->l), subpic->r - 1) : subpic->l; + const int t = dmvr_clip ? FFMIN(FFMAX(subpic->t, sb->t), subpic->b - 1) : subpic->t; + const int r = dmvr_clip ? FFMAX(FFMIN(subpic->r, sb->r), subpic->l + 1) : subpic->r; + const int b = dmvr_clip ? FFMAX(FFMIN(subpic->b, sb->b), subpic->t + 1) : subpic->b; + + *x_off -= l; + *y_off -= t; + *pic_width = r - l; + *pic_height = b - t; +} + +static void emulated_edge_no_wrap(const VVCLocalContext *lc, uint8_t *dst, + const uint8_t **src, ptrdiff_t *src_stride, + int x_off, int y_off, const int block_w, const int block_h, + const int extra_before, const int extra_after, + const VVCRect *subpic, const VVCRect *sb, const int dmvr_clip) +{ + const VVCFrameContext *fc = lc->fc; + const int extra = extra_before + extra_after; + int pic_width, pic_height; + + *src += y_off * *src_stride + (x_off * (1 << fc->ps.sps->pixel_shift)); + + clip_to_subpic(&x_off, &y_off, &pic_width, &pic_height, subpic, sb, dmvr_clip); + + if (dmvr_clip || x_off < extra_before || y_off < extra_before || + x_off >= pic_width - block_w - extra_after || + y_off >= pic_height - block_h - extra_after) { + const int ps = fc->ps.sps->pixel_shift; + const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << ps; + const int offset = extra_before * *src_stride + (extra_before << ps); + const int buf_offset = extra_before * edge_emu_stride + (extra_before << ps); + + fc->vdsp.emulated_edge_mc(dst, *src - offset, edge_emu_stride, *src_stride, + block_w + extra, block_h + extra, x_off - extra_before, y_off - extra_before, + pic_width, pic_height); + + *src = dst + buf_offset; + *src_stride = edge_emu_stride; + } +} + +static void emulated_half(const VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, + const uint8_t *src, const ptrdiff_t src_stride, const int ps, + int x_off, int y_off, const int block_w, const int block_h, + const VVCRect *subpic,const VVCRect *half_sb, const int dmvr_clip) +{ + const VVCFrameContext *fc = lc->fc; + int pic_width, pic_height; + + src += y_off * src_stride + x_off * (1 << ps); + + clip_to_subpic(&x_off, &y_off, &pic_width, &pic_height, subpic, half_sb, dmvr_clip); + + fc->vdsp.emulated_edge_mc(dst, src, dst_stride, src_stride, + block_w, block_h, x_off, y_off, pic_width, pic_height); +} + +static void sb_set_lr(VVCRect *sb, const int l, const int r) +{ + sb->l = l; + sb->r = r; +} + +static void sb_wrap(VVCRect *sb, const int wrap) +{ + sb_set_lr(sb, sb->l + wrap, sb->r + wrap); +} + +static void emulated_edge(const VVCLocalContext *lc, uint8_t *dst, + const uint8_t **src, ptrdiff_t *src_stride, const VVCFrame *src_frame, + int x_sb, int y_sb, int x_off, int y_off, int block_w, int block_h, const int wrap_enabled, + const int is_chroma, const int extra_before, const int extra_after) +{ + const VVCSPS *sps = src_frame->sps; + const VVCPPS *pps = src_frame->pps; + const int ps = sps->pixel_shift; + const int subpic_idx = lc->sc->sh.r->curr_subpic_idx; + const int extra = extra_before + extra_after; + const int dmvr_clip = x_sb != x_off || y_sb != y_off; + const int dmvr_left = FFMAX(x_off, x_sb) - extra_before; + const int dmvr_right = FFMIN(x_off, x_sb) + block_w + extra_after; + const int left = x_off - extra_before; + const int top = y_off - extra_before; + const int pic_width = pps->width >> sps->hshift[is_chroma]; + const int wrap = pps->ref_wraparound_offset << (sps->min_cb_log2_size_y - sps->hshift[is_chroma]); + const ptrdiff_t dst_stride = EDGE_EMU_BUFFER_STRIDE << ps; + VVCRect sb = { x_sb - extra_before, y_sb - extra_before, x_sb + block_w + extra_after, y_sb + block_h + extra_after }; + VVCRect subpic; + + subpic_get_rect(&subpic, src_frame, subpic_idx, is_chroma); + + if (!wrap_enabled || (dmvr_left >= 0 && dmvr_right <= pic_width)) { + emulated_edge_no_wrap(lc, dst, src, src_stride, + x_off, y_off, block_w, block_h, extra_before, extra_after, &subpic, &sb, dmvr_clip); + return; + } + if (dmvr_right <= 0) { + sb_wrap(&sb, wrap); + emulated_edge_no_wrap(lc, dst, src, src_stride, + x_off + wrap, y_off, block_w, block_h, extra_before, extra_after, &subpic, &sb, dmvr_clip); + return; + } + if (dmvr_left >= pic_width) { + sb_wrap(&sb, -wrap); + emulated_edge_no_wrap(lc, dst, src, src_stride, + x_off - wrap, y_off, block_w, block_h, extra_before, extra_after, &subpic, &sb, dmvr_clip); + return; + } + + block_w += extra; + block_h += extra; + + // half block are wrapped + if (dmvr_left < 0 ) { + const int w = -left; + VVCRect half_sb = { sb.l + wrap, sb.t, 0 + wrap, sb.b }; + emulated_half(lc, dst, dst_stride, *src, *src_stride, ps, + left + wrap, top, w, block_h, &subpic, &half_sb, dmvr_clip); + + sb_set_lr(&half_sb, 0, sb.r); + emulated_half(lc, dst + (w << ps), dst_stride, *src, *src_stride, ps, + 0, top, block_w - w, block_h, &subpic, &half_sb, dmvr_clip); + } else { + const int w = pic_width - left; + VVCRect half_sb = { sb.l, sb.t, pic_width, sb.b }; + emulated_half(lc, dst, dst_stride, *src, *src_stride, ps, + left, top, w, block_h, &subpic, &half_sb, dmvr_clip); + + sb_set_lr(&half_sb, pic_width - wrap, sb.r - wrap); + emulated_half(lc, dst + (w << ps), dst_stride, *src, *src_stride, ps, + pic_width - wrap , top, block_w - w, block_h, &subpic, &half_sb, dmvr_clip); + } + + *src = dst + extra_before * dst_stride + (extra_before << ps); + *src_stride = dst_stride; +} + +#define MC_EMULATED_EDGE(dst, src, src_stride, x_off, y_off) \ + emulated_edge(lc, dst, src, src_stride, ref, x_off, y_off, x_off, y_off, block_w, block_h, wrap_enabled, is_chroma, \ + is_chroma ? CHROMA_EXTRA_BEFORE : LUMA_EXTRA_BEFORE, is_chroma ? CHROMA_EXTRA_AFTER : LUMA_EXTRA_AFTER) + +#define MC_EMULATED_EDGE_DMVR(dst, src, src_stride, x_sb, y_sb, x_off, y_off) \ + emulated_edge(lc, dst, src, src_stride, ref, x_sb, y_sb, x_off, y_off, block_w, block_h, wrap_enabled, is_chroma, \ + is_chroma ? CHROMA_EXTRA_BEFORE : LUMA_EXTRA_BEFORE, is_chroma ? CHROMA_EXTRA_AFTER : LUMA_EXTRA_AFTER) + +#define MC_EMULATED_EDGE_BILINEAR(dst, src, src_stride, x_off, y_off) \ + emulated_edge(lc, dst, src, src_stride, ref, x_off, y_off, x_off, y_off, pred_w, pred_h, wrap_enabled, 0, \ + BILINEAR_EXTRA_BEFORE, BILINEAR_EXTRA_AFTER) + +// part of 8.5.6.6 Weighted sample prediction process +static int derive_weight_uni(int *denom, int *wx, int *ox, + const VVCLocalContext *lc, const MvField *mvf, const int c_idx) +{ + const VVCFrameContext *fc = lc->fc; + const VVCPPS *pps = fc->ps.pps; + const VVCSH *sh = &lc->sc->sh; + const int weight_flag = (IS_P(sh->r) && pps->r->pps_weighted_pred_flag) || + (IS_B(sh->r) && pps->r->pps_weighted_bipred_flag); + if (weight_flag) { + const int lx = mvf->pred_flag - PF_L0; + const PredWeightTable *w = pps->r->pps_wp_info_in_ph_flag ? &fc->ps.ph.pwt : &sh->pwt; + + *denom = w->log2_denom[c_idx > 0]; + *wx = w->weight[lx][c_idx][mvf->ref_idx[lx]]; + *ox = w->offset[lx][c_idx][mvf->ref_idx[lx]]; + } + return weight_flag; +} + +// 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) +{ + 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; + + if (bcw_idx) { + *denom = 2; + *w1 = bcw_w_lut[bcw_idx]; + *w0 = 8 - *w1; + *o0 = *o1 = 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]]; + } + return 1; +} + +#define INTER_FILTER(t, frac) (is_chroma ? ff_vvc_inter_chroma_filters[t][frac] : ff_vvc_inter_luma_filters[t][frac]) + +static void mc(VVCLocalContext *lc, int16_t *dst, const VVCFrame *ref, const Mv *mv, + int x_off, int y_off, const int block_w, const int block_h, const int c_idx) +{ + const VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &lc->cu->pu; + const uint8_t *src = ref->frame->data[c_idx]; + ptrdiff_t src_stride = ref->frame->linesize[c_idx]; + const int is_chroma = !!c_idx; + const int hs = fc->ps.sps->hshift[c_idx]; + const int vs = fc->ps.sps->vshift[c_idx]; + const int idx = av_log2(block_w) - 1; + const intptr_t mx = av_zero_extend(mv->x, 4 + hs) << (is_chroma - hs); + const intptr_t my = av_zero_extend(mv->y, 4 + vs) << (is_chroma - vs); + const int hpel_if_idx = (is_chroma || pu->merge_gpm_flag) ? 0 : pu->mi.hpel_if_idx; + const int8_t *hf = INTER_FILTER(hpel_if_idx, mx); + const int8_t *vf = INTER_FILTER(hpel_if_idx, my); + const int wrap_enabled = fc->ps.pps->r->pps_ref_wraparound_enabled_flag; + + x_off += mv->x >> (4 + hs); + y_off += mv->y >> (4 + vs); + + MC_EMULATED_EDGE(lc->edge_emu_buffer, &src, &src_stride, x_off, y_off); + fc->vvcdsp.inter.put[is_chroma][idx][!!my][!!mx](dst, src, src_stride, block_h, hf, vf, block_w); +} + +static void mc_uni(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, + const VVCFrame *ref, const MvField *mvf, int x_off, int y_off, const int block_w, const int block_h, + const int c_idx) +{ + const VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &lc->cu->pu; + const uint8_t *src = ref->frame->data[c_idx]; + ptrdiff_t src_stride = ref->frame->linesize[c_idx]; + const int lx = mvf->pred_flag - PF_L0; + const int hs = fc->ps.sps->hshift[c_idx]; + const int vs = fc->ps.sps->vshift[c_idx]; + const int idx = av_log2(block_w) - 1; + const Mv *mv = &mvf->mv[lx]; + const int is_chroma = !!c_idx; + const intptr_t mx = av_zero_extend(mv->x, 4 + hs) << (is_chroma - hs); + const intptr_t my = av_zero_extend(mv->y, 4 + vs) << (is_chroma - vs); + const int hpel_if_idx = is_chroma ? 0 : pu->mi.hpel_if_idx; + const int8_t *hf = INTER_FILTER(hpel_if_idx, mx); + const int8_t *vf = INTER_FILTER(hpel_if_idx, my); + const int wrap_enabled = fc->ps.pps->r->pps_ref_wraparound_enabled_flag; + int denom, wx, ox; + + x_off += mv->x >> (4 + hs); + y_off += mv->y >> (4 + vs); + + MC_EMULATED_EDGE(lc->edge_emu_buffer, &src, &src_stride, x_off, y_off); + if (derive_weight_uni(&denom, &wx, &ox, lc, mvf, c_idx)) { + fc->vvcdsp.inter.put_uni_w[is_chroma][idx][!!my][!!mx](dst, dst_stride, src, src_stride, + block_h, denom, wx, ox, hf, vf, block_w); + } else { + fc->vvcdsp.inter.put_uni[is_chroma][idx][!!my][!!mx](dst, dst_stride, src, src_stride, + block_h, hf, vf, block_w); + } +} + +static void mc_bi(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, + const VVCFrame *ref0, const VVCFrame *ref1, const MvField *mvf, const MvField *orig_mv, + const int x_off, const int y_off, const int block_w, const int block_h, const int c_idx, + const int sb_bdof_flag) +{ + const VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &lc->cu->pu; + const int hs = fc->ps.sps->hshift[c_idx]; + const int vs = fc->ps.sps->vshift[c_idx]; + 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; + + for (int i = L0; i <= L1; i++) { + const Mv *mv = mvf->mv + i; + const int mx = av_zero_extend(mv->x, 4 + hs) << (is_chroma - hs); + const int my = av_zero_extend(mv->y, 4 + vs) << (is_chroma - vs); + const int ox = x_off + (mv->x >> (4 + hs)); + const int oy = y_off + (mv->y >> (4 + vs)); + const VVCFrame *ref = refs[i]; + ptrdiff_t src_stride = ref->frame->linesize[c_idx]; + const uint8_t *src = ref->frame->data[c_idx]; + const int8_t *hf = INTER_FILTER(hpel_if_idx, mx); + const int8_t *vf = INTER_FILTER(hpel_if_idx, my); + const int wrap_enabled = fc->ps.pps->r->pps_ref_wraparound_enabled_flag; + + if (pu->dmvr_flag) { + const int x_sb = x_off + (orig_mv->mv[i].x >> (4 + hs)); + const int y_sb = y_off + (orig_mv->mv[i].y >> (4 + vs)); + + MC_EMULATED_EDGE_DMVR(lc->edge_emu_buffer, &src, &src_stride, x_sb, y_sb, ox, oy); + } else { + MC_EMULATED_EDGE(lc->edge_emu_buffer, &src, &src_stride, ox, oy); + } + fc->vvcdsp.inter.put[is_chroma][idx][!!my][!!mx](tmp[i], src, src_stride, block_h, hf, vf, block_w); + if (sb_bdof_flag) + fc->vvcdsp.inter.bdof_fetch_samples(tmp[i], src, src_stride, mx, my, block_w, block_h); + } + 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); +} + +static const int8_t* inter_filter_scaled(const int scale, const int is_chroma, const int is_affine) +{ +#define SCALE_THRESHOLD_1 20480 +#define SCALE_THRESHOLD_2 28672 + + const int i = (scale > SCALE_THRESHOLD_2) + (scale > SCALE_THRESHOLD_1); + + if (!is_chroma) { + if (!is_affine) + return &ff_vvc_inter_luma_filters[i + !!i][0][0]; //hpel 1 is not needed for scaled + return &ff_vvc_inter_luma_filters[VVC_INTER_LUMA_FILTER_TYPE_AFFINE + i][0][0]; + } + + return &ff_vvc_inter_chroma_filters[i][0][0]; +} +#define INTER_FILTER_SCALED(scale) inter_filter_scaled(scale, is_chroma, is_affine) + +#define SCALED_CHROMA_ADDIN(scale, collocated_flag) (is_chroma ? (collocated_flag ? 0 : 8 * (scale - (1 << 14))) : 0) +#define SCALED_REF_SB(off, scaling_off, ref_mv, scale, add, shift) ((((off - (scaling_off << shift)) << (4 + shift)) + ref_mv) * scale + add) +#define SCALED_REF(ref_sb, offset, shift) (FFSIGN(ref_sb) * ((FFABS(ref_sb) + (128 << is_chroma)) >> (8 + is_chroma)) + (offset << (10 - shift)) + (32 >> is_chroma)) +#define SCALED_STEP(scale) ((scale + 8) >> 4) + +static void scaled_ref_pos_and_step(const VVCLocalContext *lc, const VVCRefPic *refp, const Mv *mv, const int x_off, const int y_off, const int c_idx, + int *x, int *y, int *dx, int *dy) +{ + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const int is_chroma = !!c_idx; + const int hs = sps->hshift[c_idx]; + const int vs = sps->vshift[c_idx]; + const int left_offset = fc->ref->scaling_win.left_offset; + const int top_offset = fc->ref->scaling_win.top_offset; + const int addx = SCALED_CHROMA_ADDIN(refp->scale[0], sps->r->sps_chroma_horizontal_collocated_flag); + const int addy = SCALED_CHROMA_ADDIN(refp->scale[1], sps->r->sps_chroma_vertical_collocated_flag); + const int refx_sb = SCALED_REF_SB(x_off, left_offset, mv->x, refp->scale[0], addx, hs); + const int refy_sb = SCALED_REF_SB(y_off, top_offset, mv->y, refp->scale[1], addy, vs); + + *x = SCALED_REF(refx_sb, left_offset, hs); + *y = SCALED_REF(refy_sb, top_offset, vs); + *dx = SCALED_STEP(refp->scale[0]); + *dy = SCALED_STEP(refp->scale[1]); +} + +static void emulated_edge_scaled(VVCLocalContext *lc, const uint8_t **src, ptrdiff_t *src_stride, int *src_height, + const VVCFrame *ref, const int x, const int y, const int dx, const int dy, const int w, const int h, const int is_chroma) +{ + const int x_off = SCALED_INT(x); + const int y_off = SCALED_INT(y); + const int x_end = SCALED_INT(x + w * dx); + const int y_end = SCALED_INT(y + h * dy); + const int x_last = SCALED_INT(x + (w - 1) * dx); + const int y_last = SCALED_INT(y + (h - 1) * dy); + const int block_w = x_end - x_off + (x_end == x_last); + const int block_h = *src_height = y_end - y_off + (y_end == y_last); + const int wrap_enabled = 0; + + MC_EMULATED_EDGE(lc->edge_emu_buffer, src, src_stride, x_off, y_off); +} + +static void mc_scaled(VVCLocalContext *lc, int16_t *dst, const VVCRefPic *refp, const Mv *mv, + int x_off, int y_off, const int block_w, const int block_h, const int c_idx) +{ + const VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &lc->cu->pu; + const uint8_t *src = refp->ref->frame->data[c_idx]; + ptrdiff_t src_stride = refp->ref->frame->linesize[c_idx]; + const int is_affine = pu->inter_affine_flag; + const int is_chroma = !!c_idx; + const int idx = av_log2(block_w) - 1; + const int8_t *hf = INTER_FILTER_SCALED(refp->scale[0]); + const int8_t *vf = INTER_FILTER_SCALED(refp->scale[1]); + int x, y, dx, dy, src_height; + + scaled_ref_pos_and_step(lc, refp, mv, x_off, y_off, c_idx, &x, &y, &dx, &dy); + emulated_edge_scaled(lc, &src, &src_stride, &src_height, refp->ref, x, y, dx, dy, block_w, block_h, is_chroma); + fc->vvcdsp.inter.put_scaled[is_chroma][idx](dst, src, src_stride, src_height, x, y, dx, dy, block_h, hf, vf, block_w); +} + +static void mc_uni_scaled(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, const VVCRefPic *refp, + const MvField *mvf, const int x_off, const int y_off, const int block_w, const int block_h, const int c_idx) +{ + const VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &lc->cu->pu; + const uint8_t *src = refp->ref->frame->data[c_idx]; + ptrdiff_t src_stride = refp->ref->frame->linesize[c_idx]; + const int lx = mvf->pred_flag - PF_L0; + const Mv *mv = &mvf->mv[lx]; + const int is_affine = pu->inter_affine_flag; + const int is_chroma = !!c_idx; + const int idx = av_log2(block_w) - 1; + const int8_t *hf = INTER_FILTER_SCALED(refp->scale[0]); + const int8_t *vf = INTER_FILTER_SCALED(refp->scale[1]); + int denom, wx, ox, x, y, dx, dy, src_height; + + scaled_ref_pos_and_step(lc, refp, mv, x_off, y_off, c_idx, &x, &y, &dx, &dy); + emulated_edge_scaled(lc, &src, &src_stride, &src_height, refp->ref, x, y, dx, dy, block_w, block_h, is_chroma); + + if (derive_weight_uni(&denom, &wx, &ox, lc, mvf, c_idx)) { + fc->vvcdsp.inter.put_uni_w_scaled[is_chroma][idx](dst, dst_stride, src, src_stride, src_height, + x, y, dx, dy, block_h, denom, wx, ox, hf, vf, block_w); + } else { + fc->vvcdsp.inter.put_uni_scaled[is_chroma][idx](dst, dst_stride, src, src_stride, src_height, + x, y, dx, dy, block_h, hf, vf, block_w); + } +} + +static void mc_bi_scaled(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, + 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 }; + + for (int i = L0; i <= L1; i++) { + const Mv *mv = mvf->mv + i; + const VVCRefPic *refp = refps[i]; + + if (refp->is_scaled) + mc_scaled(lc, tmp[i], refp, mv, x_off, y_off, block_w, block_h, c_idx); + 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); +} + +static void luma_prof_uni(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, + const VVCFrame *ref, const MvField *mvf, int x_off, int y_off, const int block_w, const int block_h, + const int cb_prof_flag, const int16_t *diff_mv_x, const int16_t *diff_mv_y) +{ + const VVCFrameContext *fc = lc->fc; + const uint8_t *src = ref->frame->data[LUMA]; + ptrdiff_t src_stride = ref->frame->linesize[LUMA]; + uint16_t *prof_tmp = lc->tmp + PROF_TEMP_OFFSET; + const int idx = av_log2(block_w) - 1; + const int lx = mvf->pred_flag - PF_L0; + const Mv *mv = mvf->mv + lx; + const int mx = mv->x & 0xf; + const int my = mv->y & 0xf; + const int8_t *hf = ff_vvc_inter_luma_filters[VVC_INTER_LUMA_FILTER_TYPE_AFFINE][mx]; + const int8_t *vf = ff_vvc_inter_luma_filters[VVC_INTER_LUMA_FILTER_TYPE_AFFINE][my]; + int denom, wx, ox; + const int weight_flag = derive_weight_uni(&denom, &wx, &ox, lc, mvf, LUMA); + const int wrap_enabled = fc->ps.pps->r->pps_ref_wraparound_enabled_flag; + const int is_chroma = 0; + + x_off += mv->x >> 4; + y_off += mv->y >> 4; + + MC_EMULATED_EDGE(lc->edge_emu_buffer, &src, &src_stride, x_off, y_off); + if (cb_prof_flag) { + fc->vvcdsp.inter.put[LUMA][idx][!!my][!!mx](prof_tmp, src, src_stride, AFFINE_MIN_BLOCK_SIZE, hf, vf, AFFINE_MIN_BLOCK_SIZE); + fc->vvcdsp.inter.fetch_samples(prof_tmp, src, src_stride, mx, my); + if (!weight_flag) + fc->vvcdsp.inter.apply_prof_uni(dst, dst_stride, prof_tmp, diff_mv_x, diff_mv_y); + else + fc->vvcdsp.inter.apply_prof_uni_w(dst, dst_stride, prof_tmp, diff_mv_x, diff_mv_y, denom, wx, ox); + } else { + if (!weight_flag) + fc->vvcdsp.inter.put_uni[LUMA][idx][!!my][!!mx](dst, dst_stride, src, src_stride, block_h, hf, vf, block_w); + else + fc->vvcdsp.inter.put_uni_w[LUMA][idx][!!my][!!mx](dst, dst_stride, src, src_stride, block_h, denom, wx, ox, hf, vf, block_w); + } +} + +static void luma_prof(VVCLocalContext *lc, int16_t *dst, const VVCFrame *ref, + const Mv *mv , const int x_off, const int y_off, const int block_w, const int block_h, const int lx) +{ + const VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &lc->cu->pu; + const int mx = mv->x & 0xf; + const int my = mv->y & 0xf; + const int ox = x_off + (mv->x >> 4); + const int oy = y_off + (mv->y >> 4); + const int idx = av_log2(block_w) - 1; + const int is_chroma = 0; + uint16_t *prof_tmp = lc->tmp2 + PROF_TEMP_OFFSET; + ptrdiff_t src_stride = ref->frame->linesize[LUMA]; + const uint8_t *src = ref->frame->data[LUMA]; + const int8_t *hf = ff_vvc_inter_luma_filters[VVC_INTER_LUMA_FILTER_TYPE_AFFINE][mx]; + const int8_t *vf = ff_vvc_inter_luma_filters[VVC_INTER_LUMA_FILTER_TYPE_AFFINE][my]; + const int wrap_enabled = fc->ps.pps->r->pps_ref_wraparound_enabled_flag; + + MC_EMULATED_EDGE(lc->edge_emu_buffer, &src, &src_stride, ox, oy); + if (!pu->cb_prof_flag[lx]) { + fc->vvcdsp.inter.put[LUMA][idx][!!my][!!mx](dst, src, src_stride, block_h, hf, vf, block_w); + } else { + fc->vvcdsp.inter.put[LUMA][idx][!!my][!!mx](prof_tmp, src, src_stride, AFFINE_MIN_BLOCK_SIZE, hf, vf, AFFINE_MIN_BLOCK_SIZE); + fc->vvcdsp.inter.fetch_samples(prof_tmp, src, src_stride, mx, my); + fc->vvcdsp.inter.apply_prof(dst, prof_tmp, pu->diff_mv_x[lx], pu->diff_mv_y[lx]); + } +} + +static void luma_prof_bi(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, + 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]; + const Mv *mv = mvf->mv + i; + + if (refp->is_scaled) + mc_scaled(lc, tmp[i], refp, mv, x_off, y_off, block_w, block_h, LUMA); + else + 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); +} + +static int pred_get_refs(const VVCLocalContext *lc, VVCRefPic *refp[2], const MvField *mv) +{ + RefPicList *rpl = lc->sc->rpl; + + for (int mask = PF_L0; mask <= PF_L1; mask++) { + if (mv->pred_flag & mask) { + const int lx = mask - PF_L0; + refp[lx] = rpl[lx].refs + mv->ref_idx[lx]; + if (!refp[lx]->ref) + return AVERROR_INVALIDDATA; + } + } + 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)] + +static void pred_gpm_blk(VVCLocalContext *lc) +{ + const VVCFrameContext *fc = lc->fc; + const CodingUnit *cu = lc->cu; + const PredictionUnit *pu = &cu->pu; + + const uint8_t angle_idx = ff_vvc_gpm_angle_idx[pu->gpm_partition_idx]; + const uint8_t weights_idx = ff_vvc_gpm_angle_to_weights_idx[angle_idx]; + const int w = av_log2(cu->cb_width) - 3; + const int h = av_log2(cu->cb_height) - 3; + const uint8_t off_x = ff_vvc_gpm_weights_offset_x[pu->gpm_partition_idx][h][w]; + const uint8_t off_y = ff_vvc_gpm_weights_offset_y[pu->gpm_partition_idx][h][w]; + const uint8_t mirror_type = ff_vvc_gpm_angle_to_mirror[angle_idx]; + const uint8_t *weights; + + const int c_end = fc->ps.sps->r->sps_chroma_format_idc ? 3 : 1; + + int16_t *tmp[2] = {lc->tmp, lc->tmp1}; + + for (int c_idx = 0; c_idx < c_end; c_idx++) { + const int hs = fc->ps.sps->hshift[c_idx]; + const int vs = fc->ps.sps->vshift[c_idx]; + const int x = lc->cu->x0 >> hs; + const int y = lc->cu->y0 >> vs; + const int width = cu->cb_width >> hs; + const int height = cu->cb_height >> vs; + uint8_t *dst = POS(c_idx, lc->cu->x0, lc->cu->y0); + ptrdiff_t dst_stride = fc->frame->linesize[c_idx]; + + int step_x = 1 << hs; + int step_y = VVC_GPM_WEIGHT_SIZE << vs; + if (!mirror_type) { + weights = &ff_vvc_gpm_weights[weights_idx][off_y * VVC_GPM_WEIGHT_SIZE + off_x]; + } else if (mirror_type == 1) { + step_x = -step_x; + weights = &ff_vvc_gpm_weights[weights_idx][off_y * VVC_GPM_WEIGHT_SIZE + VVC_GPM_WEIGHT_SIZE - 1- off_x]; + } else { + step_y = -step_y; + weights = &ff_vvc_gpm_weights[weights_idx][(VVC_GPM_WEIGHT_SIZE - 1 - off_y) * VVC_GPM_WEIGHT_SIZE + off_x]; + } + + for (int i = 0; i < 2; i++) { + const MvField *mv = pu->gpm_mv + i; + const int lx = mv->pred_flag - PF_L0; + VVCRefPic *refp = lc->sc->rpl[lx].refs + mv->ref_idx[lx]; + + if (!refp->ref) + return; + if (refp->is_scaled) + mc_scaled(lc, tmp[i], refp, mv->mv + lx, x, y, width, height, c_idx); + else + mc(lc, tmp[i], refp->ref, mv->mv + lx, x, y, width, height, c_idx); + } + fc->vvcdsp.inter.put_gpm(dst, dst_stride, width, height, tmp[0], tmp[1], weights, step_x, step_y); + } + return; +} + +static int ciip_derive_intra_weight(const VVCLocalContext *lc, const int x0, const int y0, + const int width, const int height) +{ + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const int x0b = av_zero_extend(x0, sps->ctb_log2_size_y); + const int y0b = av_zero_extend(y0, sps->ctb_log2_size_y); + const int available_l = lc->ctb_left_flag || x0b; + const int available_u = lc->ctb_up_flag || y0b; + const int min_pu_width = fc->ps.pps->min_pu_width; + int w = 1; + + if (available_u &&fc->tab.mvf[((y0 - 1) >> MIN_PU_LOG2) * min_pu_width + ((x0 - 1 + width)>> MIN_PU_LOG2)].pred_flag == PF_INTRA) + w++; + + if (available_l && fc->tab.mvf[((y0 - 1 + height)>> MIN_PU_LOG2) * min_pu_width + ((x0 - 1) >> MIN_PU_LOG2)].pred_flag == PF_INTRA) + w++; + + return w; +} + +static void pred_regular(VVCLocalContext *lc, const MvField *mvf, const MvField *orig_mvf, + const int x0, const int y0, const int sbw, const int sbh, const int sb_bdof_flag, const int c_start) +{ + const VVCFrameContext *fc = lc->fc; + const int c_end = fc->ps.sps->r->sps_chroma_format_idc ? CR : LUMA; + VVCRefPic *refp[2]; + + if (pred_get_refs(lc, refp, mvf) < 0) + return; + + for (int c_idx = c_start; c_idx <= c_end; c_idx++) { + uint8_t *dst = POS(c_idx, x0, y0); + const ptrdiff_t dst_stride = fc->frame->linesize[c_idx]; + const int hs = fc->ps.sps->hshift[c_idx]; + const int vs = fc->ps.sps->vshift[c_idx]; + const int x = x0 >> hs; + const int y = y0 >> vs; + const int w = sbw >> hs; + const int h = sbh >> vs; + const int is_luma = !c_idx; + const int do_ciip = lc->cu->ciip_flag && (is_luma || (w > 2)); + uint8_t *inter = do_ciip ? (uint8_t *)lc->ciip_tmp : dst; + const ptrdiff_t inter_stride = do_ciip ? (MAX_PB_SIZE * sizeof(uint16_t)) : dst_stride; + const int do_bdof = is_luma && sb_bdof_flag; + + if (mvf->pred_flag != PF_BI) { + const int lx = mvf->pred_flag - PF_L0; + + if (refp[lx]->is_scaled) { + mc_uni_scaled(lc, inter, inter_stride, refp[lx], mvf, + x, y, w, h, c_idx); + } else { + mc_uni(lc, inter, inter_stride, refp[lx]->ref, mvf, + x, y, w, h, c_idx); + } + } else { + if (refp[L0]->is_scaled || refp[L1]->is_scaled) { + mc_bi_scaled(lc, inter, inter_stride, refp[L0], refp[L1], mvf, + x, y, w, h, c_idx); + } else { + mc_bi(lc, inter, inter_stride, refp[L0]->ref, refp[L1]->ref, mvf, orig_mvf, + x, y, w, h, c_idx, do_bdof); + } + } + if (do_ciip) { + const int intra_weight = ciip_derive_intra_weight(lc, x0, y0, sbw, sbh); + fc->vvcdsp.intra.intra_pred(lc, x0, y0, sbw, sbh, c_idx); + if (!c_idx && lc->sc->sh.r->sh_lmcs_used_flag) + fc->vvcdsp.lmcs.filter(inter, inter_stride, w, h, &fc->ps.lmcs.fwd_lut); + fc->vvcdsp.inter.put_ciip(dst, dst_stride, w, h, inter, inter_stride, intra_weight); + } + } +} + +// 8.5.3.5 Parametric motion vector refinement process +static int parametric_mv_refine(const int *sad, const int stride) +{ + const int sad_minus = sad[-stride]; + const int sad_center = sad[0]; + const int sad_plus = sad[stride]; + int dmvc; + int denom = (( sad_minus + sad_plus) - (sad_center << 1 ) ) << 3; + if (!denom) + dmvc = 0; + else { + if (sad_minus == sad_center) + dmvc = -8; + else if (sad_plus == sad_center) + dmvc = 8; + else { + int num = ( sad_minus - sad_plus ) * (1 << 4); + int sign_num = 0; + int quotient = 0; + int counter = 3; + if (num < 0 ) { + num = - num; + sign_num = 1; + } + while (counter > 0) { + counter = counter - 1; + quotient = quotient << 1; + if ( num >= denom ) { + num = num - denom; + quotient = quotient + 1; + } + denom = (denom >> 1); + } + if (sign_num == 1 ) + dmvc = -quotient; + else + dmvc = quotient; + } + } + return dmvc; +} + +#define SAD_ARRAY_SIZE 5 +//8.5.3 Decoder-side motion vector refinement process +static void dmvr_mv_refine(VVCLocalContext *lc, MvField *mvf, MvField *orig_mv, int *sb_bdof_flag, + const VVCFrame *ref0, const VVCFrame *ref1, const int x_off, const int y_off, const int block_w, const int block_h) +{ + const VVCFrameContext *fc = lc->fc; + const int sr_range = 2; + const VVCFrame *refs[] = { ref0, ref1 }; + int16_t *tmp[] = { lc->tmp, lc->tmp1 }; + int sad[SAD_ARRAY_SIZE][SAD_ARRAY_SIZE]; + int min_dx, min_dy, min_sad, dx, dy; + + *orig_mv = *mvf; + min_dx = min_dy = dx = dy = 2; + + for (int i = L0; i <= L1; i++) { + const int pred_w = block_w + 2 * sr_range; + const int pred_h = block_h + 2 * sr_range; + const Mv *mv = mvf->mv + i; + const int mx = mv->x & 0xf; + const int my = mv->y & 0xf; + const int ox = x_off + (mv->x >> 4) - sr_range; + const int oy = y_off + (mv->y >> 4) - sr_range; + const VVCFrame *ref = refs[i]; + ptrdiff_t src_stride = ref->frame->linesize[LUMA]; + const uint8_t *src = ref->frame->data[LUMA]; + const int wrap_enabled = fc->ps.pps->r->pps_ref_wraparound_enabled_flag; + + MC_EMULATED_EDGE_BILINEAR(lc->edge_emu_buffer, &src, &src_stride, ox, oy); + fc->vvcdsp.inter.dmvr[!!my][!!mx](tmp[i], src, src_stride, pred_h, mx, my, pred_w); + } + + min_sad = fc->vvcdsp.inter.sad(tmp[L0], tmp[L1], dx, dy, block_w, block_h); + min_sad -= min_sad >> 2; + sad[dy][dx] = min_sad; + + if (min_sad >= block_w * block_h) { + int dmv[2]; + // 8.5.3.4 Array entry selection process + for (dy = 0; dy < SAD_ARRAY_SIZE; dy++) { + for (dx = 0; dx < SAD_ARRAY_SIZE; dx++) { + if (dx != sr_range || dy != sr_range) { + sad[dy][dx] = fc->vvcdsp.inter.sad(lc->tmp, lc->tmp1, dx, dy, block_w, block_h); + if (sad[dy][dx] < min_sad) { + min_sad = sad[dy][dx]; + min_dx = dx; + min_dy = dy; + } + } + } + } + dmv[0] = (min_dx - sr_range) * (1 << 4); + dmv[1] = (min_dy - sr_range) * (1 << 4); + if (min_dx != 0 && min_dx != 4 && min_dy != 0 && min_dy != 4) { + dmv[0] += parametric_mv_refine(&sad[min_dy][min_dx], 1); + dmv[1] += parametric_mv_refine(&sad[min_dy][min_dx], SAD_ARRAY_SIZE); + } + + for (int i = L0; i <= L1; i++) { + Mv *mv = mvf->mv + i; + mv->x += (1 - 2 * i) * dmv[0]; + mv->y += (1 - 2 * i) * dmv[1]; + ff_vvc_clip_mv(mv); + } + } + if (min_sad < 2 * block_w * block_h) { + *sb_bdof_flag = 0; + } +} + +static void set_dmvr_info(VVCFrameContext *fc, const int x0, const int y0, + const int width, const int height, const MvField *mvf) + +{ + const VVCPPS *pps = fc->ps.pps; + + for (int y = y0; y < y0 + height; y += MIN_PU_SIZE) { + for (int x = x0; x < x0 + width; x += MIN_PU_SIZE) { + const int idx = pps->min_pu_width * (y >> MIN_PU_LOG2) + (x >> MIN_PU_LOG2); + fc->ref->tab_dmvr_mvf[idx] = *mvf; + } + } +} + +static void derive_sb_mv(VVCLocalContext *lc, MvField *mv, MvField *orig_mv, int *sb_bdof_flag, + const int x0, const int y0, const int sbw, const int sbh) +{ + VVCFrameContext *fc = lc->fc; + const PredictionUnit *pu = &lc->cu->pu; + + *orig_mv = *mv = *ff_vvc_get_mvf(fc, x0, y0); + if (pu->bdof_flag) + *sb_bdof_flag = 1; + if (pu->dmvr_flag) { + VVCRefPic *refp[2]; + if (pred_get_refs(lc, refp, mv) < 0) + return; + dmvr_mv_refine(lc, mv, orig_mv, sb_bdof_flag, refp[L0]->ref, refp[L1]->ref, x0, y0, sbw, sbh); + set_dmvr_info(fc, x0, y0, sbw, sbh, mv); + } +} + +static void pred_regular_blk(VVCLocalContext *lc, const int skip_ciip) +{ + const CodingUnit *cu = lc->cu; + PredictionUnit *pu = &lc->cu->pu; + const MotionInfo *mi = &pu->mi; + MvField mv, orig_mv; + int sbw, sbh, sb_bdof_flag = 0; + + if (cu->ciip_flag && skip_ciip) + return; + + sbw = cu->cb_width / mi->num_sb_x; + sbh = cu->cb_height / mi->num_sb_y; + + for (int sby = 0; sby < mi->num_sb_y; sby++) { + for (int sbx = 0; sbx < mi->num_sb_x; sbx++) { + const int x0 = cu->x0 + sbx * sbw; + const int y0 = cu->y0 + sby * sbh; + + if (cu->ciip_flag) + ff_vvc_set_neighbour_available(lc, x0, y0, sbw, sbh); + + derive_sb_mv(lc, &mv, &orig_mv, &sb_bdof_flag, x0, y0, sbw, sbh); + pred_regular(lc, &mv, &orig_mv, x0, y0, sbw, sbh, sb_bdof_flag, LUMA); + } + } +} + +static void derive_affine_mvc(MvField *mvc, const VVCFrameContext *fc, const MvField *mv, + const int x0, const int y0, const int sbw, const int sbh) +{ + const int hs = fc->ps.sps->hshift[1]; + const int vs = fc->ps.sps->vshift[1]; + const MvField* mv2 = ff_vvc_get_mvf(fc, x0 + hs * sbw, y0 + vs * sbh); + *mvc = *mv; + + // Due to different pred_flag, one of the motion vectors may have an invalid value. + // Cast them to an unsigned type to avoid undefined behavior. + mvc->mv[0].x += (unsigned int)mv2->mv[0].x; + mvc->mv[0].y += (unsigned int)mv2->mv[0].y; + mvc->mv[1].x += (unsigned int)mv2->mv[1].x; + mvc->mv[1].y += (unsigned int)mv2->mv[1].y; + ff_vvc_round_mv(mvc->mv + 0, 0, 1); + ff_vvc_round_mv(mvc->mv + 1, 0, 1); +} + +static void pred_affine_blk(VVCLocalContext *lc) +{ + const VVCFrameContext *fc = lc->fc; + const CodingUnit *cu = lc->cu; + const PredictionUnit *pu = &cu->pu; + const MotionInfo *mi = &pu->mi; + const int x0 = cu->x0; + const int y0 = cu->y0; + const int sbw = cu->cb_width / mi->num_sb_x; + const int sbh = cu->cb_height / mi->num_sb_y; + const int hs = fc->ps.sps->hshift[1]; + const int vs = fc->ps.sps->vshift[1]; + const int dst_stride = fc->frame->linesize[LUMA]; + + for (int sby = 0; sby < mi->num_sb_y; sby++) { + for (int sbx = 0; sbx < mi->num_sb_x; sbx++) { + const int x = x0 + sbx * sbw; + const int y = y0 + sby * sbh; + + uint8_t *dst0 = POS(0, x, y); + const MvField *mv = ff_vvc_get_mvf(fc, x, y); + VVCRefPic *refp[2]; + + if (pred_get_refs(lc, refp, mv) < 0) + return; + + if (mi->pred_flag != PF_BI) { + const int lx = mi->pred_flag - PF_L0; + if (refp[lx]->is_scaled) { + mc_uni_scaled(lc, dst0, dst_stride, refp[lx], mv, x, y, sbw, sbh, LUMA); + } else { + luma_prof_uni(lc, dst0, dst_stride, refp[lx]->ref, + mv, x, y, sbw, sbh, pu->cb_prof_flag[lx], + pu->diff_mv_x[lx], pu->diff_mv_y[lx]); + } + } else { + luma_prof_bi(lc, dst0, dst_stride, refp[L0], refp[L1], mv, x, y, sbw, sbh); + } + if (fc->ps.sps->r->sps_chroma_format_idc) { + if (!av_zero_extend(sby, vs) && !av_zero_extend(sbx, hs)) { + MvField mvc; + + derive_affine_mvc(&mvc, fc, mv, x, y, sbw, sbh); + pred_regular(lc, &mvc, NULL, x, y, sbw << hs, sbh << vs, 0, CB); + } + } + + } + } +} + +static void predict_inter(VVCLocalContext *lc) +{ + const VVCFrameContext *fc = lc->fc; + const CodingUnit *cu = lc->cu; + const PredictionUnit *pu = &cu->pu; + + if (pu->merge_gpm_flag) + pred_gpm_blk(lc); + else if (pu->inter_affine_flag) + pred_affine_blk(lc); + else + pred_regular_blk(lc, 1); //intra block is not ready yet, skip ciip + + if (lc->sc->sh.r->sh_lmcs_used_flag && !cu->ciip_flag) { + uint8_t* dst0 = POS(0, cu->x0, cu->y0); + fc->vvcdsp.lmcs.filter(dst0, fc->frame->linesize[LUMA], cu->cb_width, cu->cb_height, &fc->ps.lmcs.fwd_lut); + } +} + +static int has_inter_luma(const CodingUnit *cu) +{ + return (cu->pred_mode == MODE_INTER || cu->pred_mode == MODE_SKIP) && cu->tree_type != DUAL_TREE_CHROMA; +} + +int ff_vvc_predict_inter(VVCLocalContext *lc, const int rs) +{ + const VVCFrameContext *fc = lc->fc; + CodingUnit *cu = fc->tab.cus[rs]; + + while (cu) { + lc->cu = cu; + if (has_inter_luma(cu)) + predict_inter(lc); + cu = cu->next; + } + + return 0; +} + +void ff_vvc_predict_ciip(VVCLocalContext *lc) +{ + av_assert0(lc->cu->ciip_flag); + + //todo: refact out ciip from pred_regular_blk + pred_regular_blk(lc, 0); +} + +#undef POS diff --git a/libavcodec/vvc/vvc_inter.h b/libavcodec/vvc/inter.h similarity index 90% rename from libavcodec/vvc/vvc_inter.h rename to libavcodec/vvc/inter.h index 61fc44b3a..50f2dbb66 100644 --- a/libavcodec/vvc/vvc_inter.h +++ b/libavcodec/vvc/inter.h @@ -20,10 +20,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVC_INTER_H -#define AVCODEC_VVC_VVC_INTER_H +#ifndef AVCODEC_VVC_INTER_H +#define AVCODEC_VVC_INTER_H -#include "vvc_ctu.h" +#include "ctu.h" /** * Loop entire CTU to predict all inter coding blocks @@ -39,4 +39,4 @@ int ff_vvc_predict_inter(VVCLocalContext *lc, int rs); */ void ff_vvc_predict_ciip(VVCLocalContext *lc); -#endif // AVCODEC_VVC_VVC_INTER_H +#endif // AVCODEC_VVC_INTER_H diff --git a/libavcodec/vvc/vvc_inter_template.c b/libavcodec/vvc/inter_template.c similarity index 62% rename from libavcodec/vvc/vvc_inter_template.c rename to libavcodec/vvc/inter_template.c index e5cff079f..c073a73e7 100644 --- a/libavcodec/vvc/vvc_inter_template.c +++ b/libavcodec/vvc/inter_template.c @@ -21,6 +21,166 @@ */ #include "libavcodec/h26x/h2656_inter_template.c" +#include "libavutil/imgutils.h" + +#define TMP_STRIDE EDGE_EMU_BUFFER_STRIDE +static void av_always_inline FUNC(put_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride, + const uint8_t *const _src, ptrdiff_t _src_stride, const int src_height, + const int _x, const int _y, const int dx, const int dy, + const int height, const int8_t *hf, const int8_t *vf, const int width, const int is_uni, const int is_chroma) +{ + int16_t tmp_array[TMP_STRIDE * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + pixel *dst = (pixel*)_dst; + int16_t *dst16 = (int16_t*)_dst; + const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel); + const ptrdiff_t src_stride = _src_stride / sizeof(pixel); + const int shift = FFMAX(2, 14 - BIT_DEPTH); + const int offset = 1 << (shift - 1); + const int taps = is_chroma ? VVC_INTER_CHROMA_TAPS : VVC_INTER_LUMA_TAPS; + const int extra = is_chroma ? CHROMA_EXTRA : LUMA_EXTRA; + const int extra_before = is_chroma ? CHROMA_EXTRA_BEFORE : LUMA_EXTRA_BEFORE; + const int shift1 = 6 - is_chroma; + const int shift2 = 4 + is_chroma; + const int x0 = SCALED_INT(_x); + const int y0 = SCALED_INT(_y); + + for (int i = 0; i < width; i++) { + const int tx = _x + dx * i; + const int x = SCALED_INT(tx) - x0; + const int mx = av_zero_extend(tx >> shift1, shift2); + const int8_t *filter = hf + mx * taps; + const pixel *src = (pixel*)_src - extra_before * src_stride; + + for (int j = 0; j < src_height + extra; j++) { + tmp[j] = (is_chroma ? CHROMA_FILTER(src, 1) : LUMA_FILTER(src, 1)) >> (BIT_DEPTH - 8); + src += src_stride; + } + tmp += TMP_STRIDE; + } + + for (int i = 0; i < height; i++) { + const int ty = _y + dy * i; + const int x = SCALED_INT(ty) - y0; + const int mx = av_zero_extend(ty >> shift1, shift2); + const int8_t *filter = vf + mx * taps; + + tmp = tmp_array + extra_before; + for (int j = 0; j < width; j++) { + const int val = (is_chroma ? CHROMA_FILTER(tmp, 1) : LUMA_FILTER(tmp, 1)) >> 6; + if (is_uni) + dst[j] = av_clip_pixel((val + offset) >> shift); + else + dst16[j] = val; + tmp += TMP_STRIDE; + } + if (is_uni) + dst += dst_stride; + else + dst16 += dst_stride; + } +} + +static void FUNC(put_luma_scaled)(int16_t *_dst, + const uint8_t *_src, ptrdiff_t _src_stride, const int src_height, + const int x, const int y, const int dx, const int dy, + const int height, const int8_t *hf, const int8_t *vf, const int width) +{ + FUNC(put_scaled)((uint8_t *)_dst, MAX_PB_SIZE * sizeof(pixel), _src, _src_stride, src_height, x, y, dx, dy, height, hf, vf, width, 0, 0); +} + +static void FUNC(put_chroma_scaled)(int16_t *_dst, + const uint8_t *_src, ptrdiff_t _src_stride, const int src_height, + const int x, const int y, const int dx, const int dy, + const int height, const int8_t *hf, const int8_t *vf, const int width) +{ + FUNC(put_scaled)((uint8_t *)_dst, MAX_PB_SIZE * sizeof(pixel), _src, _src_stride, src_height, x, y, dx, dy, height, hf, vf, width, 0, 1); +} + +static void FUNC(put_uni_luma_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride, + const uint8_t *_src, ptrdiff_t _src_stride, const int src_height, + const int x, const int y, const int dx, const int dy, + const int height, const int8_t *hf, const int8_t *vf, const int width) +{ + FUNC(put_scaled)(_dst, _dst_stride, _src, _src_stride, src_height, x, y, dx, dy, height, hf, vf, width, 1, 0); +} + +static void FUNC(put_uni_chroma_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride, + const uint8_t *_src, ptrdiff_t _src_stride, const int src_height, + const int x, const int y, const int dx, const int dy, + const int height, const int8_t *hf, const int8_t *vf, const int width) +{ + FUNC(put_scaled)(_dst, _dst_stride, _src, _src_stride, src_height, x, y, dx, dy, height, hf, vf, width, 1, 1); +} + +static void av_always_inline FUNC(put_uni_w_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride, + const uint8_t *const _src, ptrdiff_t _src_stride, const int src_height, + const int _x, const int _y, const int dx, const int dy, const int denom, const int wx, const int _ox, + const int height, const int8_t *hf, const int8_t *vf, const int width, const int is_chroma) +{ + int16_t tmp_array[TMP_STRIDE * MAX_PB_SIZE]; + int16_t *tmp = tmp_array; + pixel *dst = (pixel*)_dst; + const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel); + const ptrdiff_t src_stride = _src_stride / sizeof(pixel); + const int shift = FFMAX(2, 14 - BIT_DEPTH); + const int offset = 1 << (shift - 1); + const int ox = _ox * (1 << (BIT_DEPTH - 8)); + const int taps = is_chroma ? VVC_INTER_CHROMA_TAPS : VVC_INTER_LUMA_TAPS; + const int extra = is_chroma ? CHROMA_EXTRA : LUMA_EXTRA; + const int extra_before = is_chroma ? CHROMA_EXTRA_BEFORE : LUMA_EXTRA_BEFORE; + const int shift1 = 6 - is_chroma; + const int shift2 = 4 + is_chroma; + const int x0 = SCALED_INT(_x); + const int y0 = SCALED_INT(_y); + + for (int i = 0; i < width; i++) { + const int tx = _x + dx * i; + const int x = SCALED_INT(tx) - x0; + const int mx = av_zero_extend(tx >> shift1, shift2); + const int8_t *filter = hf + mx * taps; + const pixel *src = (pixel*)_src - extra_before * src_stride; + + for (int j = 0; j < src_height + extra; j++) { + tmp[j] = (is_chroma ? CHROMA_FILTER(src, 1) : LUMA_FILTER(src, 1)) >> (BIT_DEPTH - 8); + src += src_stride; + } + tmp += TMP_STRIDE; + } + + for (int i = 0; i < height; i++) { + const int ty = _y + dy * i; + const int x = SCALED_INT(ty) - y0; + const int mx = av_zero_extend(ty >> shift1, shift2); + const int8_t *filter = vf + mx * taps; + + tmp = tmp_array + extra_before; + for (int j = 0; j < width; j++) { + const int val = (is_chroma ? CHROMA_FILTER(tmp, 1) : LUMA_FILTER(tmp, 1)) >> 6; + dst[j] = av_clip_pixel(((wx * val + offset) >> shift) + ox); + tmp += TMP_STRIDE; + } + dst += dst_stride; + } +} + +static void FUNC(put_uni_luma_w_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride, + const uint8_t *_src, ptrdiff_t _src_stride, const int src_height, + const int x, const int y, const int dx, const int dy, const int denom, const int wx, const int ox, + const int height, const int8_t *hf, const int8_t *vf, const int width) +{ + FUNC(put_uni_w_scaled)(_dst, _dst_stride, _src, _src_stride, src_height, x, y, dx, dy, denom, wx, ox, height, hf, vf, width, 0); +} + +static void FUNC(put_uni_chroma_w_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride, + const uint8_t *_src, ptrdiff_t _src_stride, const int src_height, + const int x, const int y, const int dx, const int dy, const int denom, const int wx, const int ox, + const int height, const int8_t *hf, const int8_t *vf, const int width) +{ + FUNC(put_uni_w_scaled)(_dst, _dst_stride, _src, _src_stride, src_height, x, y, dx, dy, denom, wx, ox, height, hf, vf, width, 1); +} + +#undef TMP_STRIDE static void FUNC(avg)(uint8_t *_dst, const ptrdiff_t _dst_stride, const int16_t *src0, const int16_t *src1, const int width, const int height) @@ -46,7 +206,7 @@ static void FUNC(w_avg)(uint8_t *_dst, const ptrdiff_t _dst_stride, 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) << (BIT_DEPTH - 8)) + 1) << (shift - 1); + const int offset = ((o0 + o1) * (1 << (BIT_DEPTH - 8)) + 1) * (1 << (shift - 1)); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) @@ -132,13 +292,11 @@ static void FUNC(fetch_samples)(int16_t *_dst, const uint8_t *_src, const ptrdif FUNC(bdof_fetch_samples)(_dst, _src, _src_stride, x_frac, y_frac, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE); } -static void FUNC(prof_grad_filter)(int16_t *_gradient_h, int16_t *_gradient_v, const ptrdiff_t gradient_stride, - const int16_t *_src, const ptrdiff_t src_stride, const int width, const int height, const int pad) +static void FUNC(prof_grad_filter)(int16_t *gradient_h, int16_t *gradient_v, const ptrdiff_t gradient_stride, + const int16_t *_src, const ptrdiff_t src_stride, const int width, const int height) { const int shift = 6; const int16_t *src = _src; - int16_t *gradient_h = _gradient_h + pad * (1 + gradient_stride); - int16_t *gradient_v = _gradient_v + pad * (1 + gradient_stride); for (int y = 0; y < height; y++) { const int16_t *p = src; @@ -151,10 +309,6 @@ static void FUNC(prof_grad_filter)(int16_t *_gradient_h, int16_t *_gradient_v, c gradient_v += gradient_stride; src += src_stride; } - if (pad) { - pad_int16(_gradient_h + 1 + gradient_stride, gradient_stride, width, height); - pad_int16(_gradient_v + 1 + gradient_stride, gradient_stride, width, height); - } } static void FUNC(apply_prof)(int16_t *dst, const int16_t *src, const int16_t *diff_mv_x, const int16_t *diff_mv_y) @@ -163,7 +317,7 @@ static void FUNC(apply_prof)(int16_t *dst, const int16_t *src, const int16_t *di int16_t gradient_h[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE]; int16_t gradient_v[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE]; - FUNC(prof_grad_filter)(gradient_h, gradient_v, AFFINE_MIN_BLOCK_SIZE, src, MAX_PB_SIZE, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE, 0); + FUNC(prof_grad_filter)(gradient_h, gradient_v, AFFINE_MIN_BLOCK_SIZE, src, MAX_PB_SIZE, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE); for (int y = 0; y < AFFINE_MIN_BLOCK_SIZE; y++) { for (int x = 0; x < AFFINE_MIN_BLOCK_SIZE; x++) { @@ -192,7 +346,7 @@ static void FUNC(apply_prof_uni)(uint8_t *_dst, const ptrdiff_t _dst_stride, con int16_t gradient_h[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE]; int16_t gradient_v[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE]; - FUNC(prof_grad_filter)(gradient_h, gradient_v, AFFINE_MIN_BLOCK_SIZE, src, MAX_PB_SIZE, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE, 0); + FUNC(prof_grad_filter)(gradient_h, gradient_v, AFFINE_MIN_BLOCK_SIZE, src, MAX_PB_SIZE, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE); for (int y = 0; y < AFFINE_MIN_BLOCK_SIZE; y++) { for (int x = 0; x < AFFINE_MIN_BLOCK_SIZE; x++) { @@ -220,7 +374,7 @@ static void FUNC(apply_prof_uni_w)(uint8_t *_dst, const ptrdiff_t _dst_stride, int16_t gradient_h[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE]; int16_t gradient_v[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE]; - FUNC(prof_grad_filter)(gradient_h, gradient_v, AFFINE_MIN_BLOCK_SIZE, src, MAX_PB_SIZE, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE, 0); + FUNC(prof_grad_filter)(gradient_h, gradient_v, AFFINE_MIN_BLOCK_SIZE, src, MAX_PB_SIZE, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE); for (int y = 0; y < AFFINE_MIN_BLOCK_SIZE; y++) { for (int x = 0; x < AFFINE_MIN_BLOCK_SIZE; x++) { @@ -235,47 +389,47 @@ static void FUNC(apply_prof_uni_w)(uint8_t *_dst, const ptrdiff_t _dst_stride, } static void FUNC(derive_bdof_vx_vy)(const int16_t *_src0, const int16_t *_src1, - const int16_t **gradient_h, const int16_t **gradient_v, ptrdiff_t gradient_stride, + const int pad_left, const int pad_top, const int pad_right, const int pad_bottom, + const int16_t **gradient_h, const int16_t **gradient_v, int* vx, int* vy) { const int shift2 = 4; const int shift3 = 1; const int thres = 1 << 4; int sgx2 = 0, sgy2 = 0, sgxgy = 0, sgxdi = 0, sgydi = 0; - const int16_t *src0 = _src0 - 1 - MAX_PB_SIZE; - const int16_t *src1 = _src1 - 1 - MAX_PB_SIZE; - for (int y = 0; y < BDOF_GRADIENT_SIZE; y++) { - for (int x = 0; x < BDOF_GRADIENT_SIZE; x++) { - const int diff = (src0[x] >> shift2) - (src1[x] >> shift2); - const int idx = gradient_stride * y + x; + for (int y = -1; y < BDOF_MIN_BLOCK_SIZE + 1; y++) { + const int dy = y + (pad_top && y < 0) - (pad_bottom && y == BDOF_MIN_BLOCK_SIZE); // we pad for the first and last row + const int16_t *src0 = _src0 + dy * MAX_PB_SIZE; + const int16_t *src1 = _src1 + dy * MAX_PB_SIZE; + + for (int x = -1; x < BDOF_MIN_BLOCK_SIZE + 1; x++) { + const int dx = x + (pad_left && x < 0) - (pad_right && x == BDOF_MIN_BLOCK_SIZE); // we pad for the first and last col + const int diff = (src0[dx] >> shift2) - (src1[dx] >> shift2); + const int idx = BDOF_BLOCK_SIZE * dy + dx; const int temph = (gradient_h[0][idx] + gradient_h[1][idx]) >> shift3; const int tempv = (gradient_v[0][idx] + gradient_v[1][idx]) >> shift3; + sgx2 += FFABS(temph); sgy2 += FFABS(tempv); sgxgy += VVC_SIGN(tempv) * temph; sgxdi += -VVC_SIGN(temph) * diff; sgydi += -VVC_SIGN(tempv) * diff; } - src0 += MAX_PB_SIZE; - src1 += MAX_PB_SIZE; } *vx = sgx2 > 0 ? av_clip((sgxdi * (1 << 2)) >> av_log2(sgx2) , -thres + 1, thres - 1) : 0; *vy = sgy2 > 0 ? av_clip(((sgydi * (1 << 2)) - ((*vx * sgxgy) >> 1)) >> av_log2(sgy2), -thres + 1, thres - 1) : 0; } static void FUNC(apply_bdof_min_block)(pixel* dst, const ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1, - const int16_t **gradient_h, const int16_t **gradient_v, const int vx, const int vy) + const int16_t **gh, const int16_t **gv, const int vx, const int vy) { const int shift4 = 15 - BIT_DEPTH; const int offset4 = 1 << (shift4 - 1); - const int16_t* gh[] = { gradient_h[0] + 1 + BDOF_PADDED_SIZE, gradient_h[1] + 1 + BDOF_PADDED_SIZE }; - const int16_t* gv[] = { gradient_v[0] + 1 + BDOF_PADDED_SIZE, gradient_v[1] + 1 + BDOF_PADDED_SIZE }; - - for (int y = 0; y < BDOF_BLOCK_SIZE; y++) { - for (int x = 0; x < BDOF_BLOCK_SIZE; x++) { - const int idx = y * BDOF_PADDED_SIZE + x; + for (int y = 0; y < BDOF_MIN_BLOCK_SIZE; y++) { + for (int x = 0; x < BDOF_MIN_BLOCK_SIZE; x++) { + const int idx = y * BDOF_BLOCK_SIZE + x; const int bdof_offset = vx * (gh[0][idx] - gh[1][idx]) + vy * (gv[0][idx] - gv[1][idx]); dst[x] = av_clip_pixel((src0[x] + offset4 + src1[x] + bdof_offset) >> shift4); } @@ -285,34 +439,32 @@ static void FUNC(apply_bdof_min_block)(pixel* dst, const ptrdiff_t dst_stride, c } } -static void FUNC(apply_bdof)(uint8_t *_dst, const ptrdiff_t _dst_stride, int16_t *_src0, int16_t *_src1, +static void FUNC(apply_bdof)(uint8_t *_dst, const ptrdiff_t _dst_stride, const int16_t *_src0, const int16_t *_src1, const int block_w, const int block_h) { - int16_t gradient_h[2][BDOF_PADDED_SIZE * BDOF_PADDED_SIZE]; - int16_t gradient_v[2][BDOF_PADDED_SIZE * BDOF_PADDED_SIZE]; + int16_t gradient_h[2][BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE]; + int16_t gradient_v[2][BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE]; int vx, vy; const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel); pixel* dst = (pixel*)_dst; - FUNC(prof_grad_filter)(gradient_h[0], gradient_v[0], BDOF_PADDED_SIZE, - _src0, MAX_PB_SIZE, block_w, block_h, 1); - pad_int16(_src0, MAX_PB_SIZE, block_w, block_h); - FUNC(prof_grad_filter)(gradient_h[1], gradient_v[1], BDOF_PADDED_SIZE, - _src1, MAX_PB_SIZE, block_w, block_h, 1); - pad_int16(_src1, MAX_PB_SIZE, block_w, block_h); + FUNC(prof_grad_filter)(gradient_h[0], gradient_v[0], BDOF_BLOCK_SIZE, + _src0, MAX_PB_SIZE, block_w, block_h); + FUNC(prof_grad_filter)(gradient_h[1], gradient_v[1], BDOF_BLOCK_SIZE, + _src1, MAX_PB_SIZE, block_w, block_h); - for (int y = 0; y < block_h; y += BDOF_BLOCK_SIZE) { - for (int x = 0; x < block_w; x += BDOF_BLOCK_SIZE) { + for (int y = 0; y < block_h; y += BDOF_MIN_BLOCK_SIZE) { + for (int x = 0; x < block_w; x += BDOF_MIN_BLOCK_SIZE) { const int16_t* src0 = _src0 + y * MAX_PB_SIZE + x; const int16_t* src1 = _src1 + y * MAX_PB_SIZE + x; pixel *d = dst + x; - const int idx = BDOF_PADDED_SIZE * y + x; + const int idx = BDOF_BLOCK_SIZE * y + x; const int16_t* gh[] = { gradient_h[0] + idx, gradient_h[1] + idx }; const int16_t* gv[] = { gradient_v[0] + idx, gradient_v[1] + idx }; - FUNC(derive_bdof_vx_vy)(src0, src1, gh, gv, BDOF_PADDED_SIZE, &vx, &vy); + FUNC(derive_bdof_vx_vy)(src0, src1, !x, !y, x + BDOF_MIN_BLOCK_SIZE == block_w, y + BDOF_MIN_BLOCK_SIZE == block_h, gh, gv, &vx, &vy); FUNC(apply_bdof_min_block)(d, dst_stride, src0, src1, gh, gv, vx, vy); } - dst += BDOF_BLOCK_SIZE * dst_stride; + dst += BDOF_MIN_BLOCK_SIZE * dst_stride; } } @@ -324,6 +476,7 @@ static void FUNC(apply_bdof)(uint8_t *_dst, const ptrdiff_t _dst_stride, int16_t 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) { +#if BIT_DEPTH != 10 const pixel *src = (const pixel *)_src; const ptrdiff_t src_stride = _src_stride / sizeof(pixel); #if BIT_DEPTH > 10 @@ -332,7 +485,7 @@ static void FUNC(dmvr)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_s #define DMVR_SHIFT(s) (((s) + offset4) >> shift4) #else #define DMVR_SHIFT(s) ((s) << (10 - BIT_DEPTH)) -#endif +#endif // BIT_DEPTH > 10 for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) @@ -341,6 +494,10 @@ static void FUNC(dmvr)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_s dst += MAX_PB_SIZE; } #undef DMVR_SHIFT +#else + av_image_copy_plane((uint8_t*)dst, sizeof(int16_t) * MAX_PB_SIZE, _src, _src_stride, + width * sizeof(pixel), height); +#endif // BIT_DEPTH != 10 } //8.5.3.2.2 Luma sample bilinear interpolation process @@ -440,6 +597,15 @@ static void FUNC(ff_vvc_inter_dsp_init)(VVCInterDSPContext *const inter) FUNCS(LUMA, luma); FUNCS(CHROMA, chroma); + for (int i = 0; i < FF_ARRAY_ELEMS(inter->put_scaled[LUMA]); i++) { + inter->put_scaled[LUMA][i] = FUNC(put_luma_scaled); + inter->put_scaled[CHROMA][i] = FUNC(put_chroma_scaled); + inter->put_uni_scaled[LUMA][i] = FUNC(put_uni_luma_scaled); + inter->put_uni_scaled[CHROMA][i] = FUNC(put_uni_chroma_scaled); + inter->put_uni_w_scaled[LUMA][i] = FUNC(put_uni_luma_w_scaled); + inter->put_uni_w_scaled[CHROMA][i] = FUNC(put_uni_chroma_w_scaled); + } + inter->avg = FUNC(avg); inter->w_avg = FUNC(w_avg); @@ -457,7 +623,6 @@ static void FUNC(ff_vvc_inter_dsp_init)(VVCInterDSPContext *const inter) inter->apply_prof_uni = FUNC(apply_prof_uni); inter->apply_prof_uni_w = FUNC(apply_prof_uni_w); inter->apply_bdof = FUNC(apply_bdof); - inter->prof_grad_filter = FUNC(prof_grad_filter); inter->sad = vvc_sad; } diff --git a/libavcodec/vvc/vvc_intra.c b/libavcodec/vvc/intra.c similarity index 92% rename from libavcodec/vvc/vvc_intra.c rename to libavcodec/vvc/intra.c index 6d976320f..41ed89c94 100644 --- a/libavcodec/vvc/vvc_intra.c +++ b/libavcodec/vvc/intra.c @@ -22,10 +22,10 @@ #include "libavutil/frame.h" #include "libavutil/imgutils.h" -#include "vvc_data.h" -#include "vvc_inter.h" -#include "vvc_intra.h" -#include "vvc_itx_1d.h" +#include "data.h" +#include "inter.h" +#include "intra.h" +#include "itx_1d.h" static int is_cclm(enum IntraPredMode mode) { @@ -128,15 +128,15 @@ static void ilfnst_transform(const VVCLocalContext *lc, TransformBlock *tb) } //part of 8.7.4 Transformation process for scaled transform coefficients -static void derive_transform_type(const VVCFrameContext *fc, const VVCLocalContext *lc, const TransformBlock *tb, enum TxType *trh, enum TxType *trv) +static void derive_transform_type(const VVCFrameContext *fc, const VVCLocalContext *lc, const TransformBlock *tb, enum VVCTxType *trh, enum VVCTxType *trv) { const CodingUnit *cu = lc->cu; - static const enum TxType mts_to_trh[] = {DCT2, DST7, DCT8, DST7, DCT8}; - static const enum TxType mts_to_trv[] = {DCT2, DST7, DST7, DCT8, DCT8}; + static const enum VVCTxType mts_to_trh[] = { VVC_DCT2, VVC_DST7, VVC_DCT8, VVC_DST7, VVC_DCT8 }; + static const enum VVCTxType mts_to_trv[] = { VVC_DCT2, VVC_DST7, VVC_DST7, VVC_DCT8, VVC_DCT8 }; const VVCSPS *sps = fc->ps.sps; int implicit_mts_enabled = 0; if (tb->c_idx || (cu->isp_split_type != ISP_NO_SPLIT && cu->lfnst_idx)) { - *trh = *trv = DCT2; + *trh = *trv = VVC_DCT2; return; } @@ -152,11 +152,11 @@ static void derive_transform_type(const VVCFrameContext *fc, const VVCLocalConte const int w = tb->tb_width; const int h = tb->tb_height; if (cu->sbt_flag) { - *trh = (cu->sbt_horizontal_flag || cu->sbt_pos_flag) ? DST7 : DCT8; - *trv = (!cu->sbt_horizontal_flag || cu->sbt_pos_flag) ? DST7 : DCT8; + *trh = (cu->sbt_horizontal_flag || cu->sbt_pos_flag) ? VVC_DST7 : VVC_DCT8; + *trv = (!cu->sbt_horizontal_flag || cu->sbt_pos_flag) ? VVC_DST7 : VVC_DCT8; } else { - *trh = (w >= 4 && w <= 16) ? DST7 : DCT2; - *trv = (h >= 4 && h <= 16) ? DST7 : DCT2; + *trh = (w >= 4 && w <= 16) ? VVC_DST7 : VVC_DCT2; + *trv = (h >= 4 && h <= 16) ? VVC_DST7 : VVC_DCT2; } return; } @@ -339,18 +339,20 @@ static void derive_qp(const VVCLocalContext *lc, const TransformUnit *tu, Transf //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 + 2 * 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 + 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 + 2 * 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 + 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] = { @@ -416,7 +418,7 @@ static const uint8_t* derive_scale_m(const VVCLocalContext *lc, const TransformB static av_always_inline int scale_coeff(const TransformBlock *tb, int coeff, const int scale, const int scale_m, const int log2_transform_range) { - coeff = (coeff * scale * scale_m + tb->bd_offset) >> tb->bd_shift; + coeff = ((int64_t) coeff * scale * scale_m + tb->bd_offset) >> tb->bd_shift; coeff = av_clip_intp2(coeff, log2_transform_range); return coeff; } @@ -445,7 +447,7 @@ static void dequant(const VVCLocalContext *lc, const TransformUnit *tu, Transfor //transmatrix[0][0] #define DCT_A 64 -static void itx_2d(const VVCFrameContext *fc, TransformBlock *tb, const enum TxType trh, const enum TxType trv) +static void itx_2d(const VVCFrameContext *fc, TransformBlock *tb, const enum VVCTxType trh, const enum VVCTxType trv) { const VVCSPS *sps = fc->ps.sps; const int w = tb->tb_width; @@ -454,7 +456,7 @@ static void itx_2d(const VVCFrameContext *fc, TransformBlock *tb, const enum TxT const size_t nzh = tb->max_scan_y + 1; const int shift[] = { 7, 5 + sps->log2_transform_range - sps->bit_depth }; - if (w == h && nzw == 1 && nzh == 1 && trh == DCT2 && trv == DCT2) { + if (w == h && nzw == 1 && nzh == 1 && trh == VVC_DCT2 && trv == VVC_DCT2) { const int add[] = { 1 << (shift[0] - 1), 1 << (shift[1] - 1) }; const int t = (tb->coeffs[0] * DCT_A + add[0]) >> shift[0]; const int dc = (t * DCT_A + add[1]) >> shift[1]; @@ -474,7 +476,7 @@ static void itx_2d(const VVCFrameContext *fc, TransformBlock *tb, const enum TxT scale(tb->coeffs, tb->coeffs, w, h, shift[1]); } -static void itx_1d(const VVCFrameContext *fc, TransformBlock *tb, const enum TxType trh, const enum TxType trv) +static void itx_1d(const VVCFrameContext *fc, TransformBlock *tb, const enum VVCTxType trh, const enum VVCTxType trv) { const VVCSPS *sps = fc->ps.sps; const int w = tb->tb_width; @@ -482,7 +484,7 @@ static void itx_1d(const VVCFrameContext *fc, TransformBlock *tb, const enum TxT const size_t nzw = tb->max_scan_x + 1; const size_t nzh = tb->max_scan_y + 1; - if ((w > 1 && nzw == 1 && trh == DCT2) || (h > 1 && nzh == 1 && trv == DCT2)) { + if ((w > 1 && nzw == 1 && trh == VVC_DCT2) || (h > 1 && nzh == 1 && trv == VVC_DCT2)) { const int shift = 6 + sps->log2_transform_range - sps->bit_depth; const int add = 1 << (shift - 1); const int dc = (tb->coeffs[0] * DCT_A + add) >> shift; @@ -540,7 +542,7 @@ static void itransform(VVCLocalContext *lc, TransformUnit *tu, const int tu_idx, transform_bdpcm(tb, lc, cu); dequant(lc, tu, tb); if (!tb->ts) { - enum TxType trh, trv; + enum VVCTxType trh, trv; if (cu->apply_lfnst_flag[c_idx]) ilfnst_transform(lc, tb); @@ -662,8 +664,7 @@ int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const in const VVCSPS *sps = fc->ps.sps; const int x_ctb = rx << sps->ctb_log2_size_y; const int y_ctb = ry << sps->ctb_log2_size_y; - CTU *ctu = fc->tab.ctus + rs; - CodingUnit *cu = ctu->cus; + CodingUnit *cu = fc->tab.cus[rs]; int ret = 0; lc->num_ras[0] = lc->num_ras[1] = 0; @@ -689,7 +690,7 @@ int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const in ibc_fill_vir_buf(lc, cu); cu = cu->next; } - ff_vvc_ctu_free_cus(ctu); + ff_vvc_ctu_free_cus(fc->tab.cus + rs); return ret; } diff --git a/libavcodec/vvc/vvc_intra.h b/libavcodec/vvc/intra.h similarity index 93% rename from libavcodec/vvc/vvc_intra.h rename to libavcodec/vvc/intra.h index 6b674008f..8a0269913 100644 --- a/libavcodec/vvc/vvc_intra.h +++ b/libavcodec/vvc/intra.h @@ -19,10 +19,10 @@ * 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_VVC_INTRA_H -#define AVCODEC_VVC_VVC_INTRA_H +#ifndef AVCODEC_VVC_INTRA_H +#define AVCODEC_VVC_INTRA_H -#include "vvc_ctu.h" +#include "ctu.h" /** * reconstruct a CTU @@ -46,4 +46,4 @@ 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); -#endif // AVCODEC_VVC_VVC_INTRA_H +#endif // AVCODEC_VVC_INTRA_H diff --git a/libavcodec/vvc/vvc_intra_template.c b/libavcodec/vvc/intra_template.c similarity index 99% rename from libavcodec/vvc/vvc_intra_template.c rename to libavcodec/vvc/intra_template.c index a07888526..62342c814 100644 --- a/libavcodec/vvc/vvc_intra_template.c +++ b/libavcodec/vvc/intra_template.c @@ -22,7 +22,7 @@ #include "libavcodec/bit_depth_template.c" -#include "vvc_intra.h" +#include "intra.h" #define POS(x, y) src[(x) + stride * (y)] @@ -99,7 +99,7 @@ static av_always_inline void FUNC(cclm_select_luma)(const VVCFrameContext *fc, { const VVCSPS *sps = fc->ps.sps; - const int b_ctu_boundary = !av_mod_uintp2(y0, sps->ctb_log2_size_y); + const int b_ctu_boundary = !av_zero_extend(y0, sps->ctb_log2_size_y); const int hs = sps->hshift[1]; const int vs = sps->vshift[1]; const ptrdiff_t stride = fc->frame->linesize[0] / sizeof(pixel); diff --git a/libavcodec/vvc/vvc_intra_utils.c b/libavcodec/vvc/intra_utils.c similarity index 96% rename from libavcodec/vvc/vvc_intra_utils.c rename to libavcodec/vvc/intra_utils.c index 7d34cff02..8c40eb1b1 100644 --- a/libavcodec/vvc/vvc_intra_utils.c +++ b/libavcodec/vvc/intra_utils.c @@ -25,10 +25,10 @@ #include "libavutil/avassert.h" #include "libavutil/macros.h" #include "libavutil/common.h" -#include "vvc_ctu.h" -#include "vvc_intra.h" -#include "vvc_ps.h" -#include "vvcdec.h" +#include "ctu.h" +#include "intra.h" +#include "ps.h" +#include "dec.h" int ff_vvc_get_mip_size_id(const int w, const int h) { @@ -100,7 +100,7 @@ int ff_vvc_get_top_available(const VVCLocalContext *lc, const int x, const int y const int vs = sps->vshift[c_idx]; const int log2_ctb_size_v = sps->ctb_log2_size_y - vs; const int end_of_ctb_x = ((lc->cu->x0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y; - const int y0b = av_mod_uintp2(y, log2_ctb_size_v); + const int y0b = av_zero_extend(y, log2_ctb_size_v); const int max_x = FFMIN(fc->ps.pps->width, end_of_ctb_x) >> hs; const ReconstructedArea *a; int px = x; @@ -130,7 +130,7 @@ int ff_vvc_get_left_available(const VVCLocalContext *lc, const int x, const int const int hs = sps->hshift[c_idx]; const int vs = sps->vshift[c_idx]; const int log2_ctb_size_h = sps->ctb_log2_size_y - hs; - const int x0b = av_mod_uintp2(x, log2_ctb_size_h); + const int x0b = av_zero_extend(x, log2_ctb_size_h); const int end_of_ctb_y = ((lc->cu->y0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y; const int max_y = FFMIN(fc->ps.pps->height, end_of_ctb_y) >> vs; const ReconstructedArea *a; diff --git a/libavcodec/vvc/vvc_itx_1d.c b/libavcodec/vvc/itx_1d.c similarity index 99% rename from libavcodec/vvc/vvc_itx_1d.c rename to libavcodec/vvc/itx_1d.c index cb076f680..c84e39440 100644 --- a/libavcodec/vvc/vvc_itx_1d.c +++ b/libavcodec/vvc/itx_1d.c @@ -57,8 +57,8 @@ Compact inverse discrete cosine transform circuit for MPEG video decoding. */ -#include "vvc_data.h" -#include "vvc_itx_1d.h" +#include "data.h" +#include "itx_1d.h" #include "libavutil/avutil.h" #define G2(m) ((nz > 2) ? (m) : 0) diff --git a/libavcodec/vvc/vvc_itx_1d.h b/libavcodec/vvc/itx_1d.h similarity index 94% rename from libavcodec/vvc/vvc_itx_1d.h rename to libavcodec/vvc/itx_1d.h index d9094f524..59495827b 100644 --- a/libavcodec/vvc/vvc_itx_1d.h +++ b/libavcodec/vvc/itx_1d.h @@ -20,8 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVC_ITX_1D_H -#define AVCODEC_VVC_VVC_ITX_1D_H +#ifndef AVCODEC_VVC_ITX_1D_H +#define AVCODEC_VVC_ITX_1D_H #include #include @@ -49,4 +49,4 @@ vvc_itx_1d_fn(ff_vvc_inv_dct8_32); void ff_vvc_inv_lfnst_1d(int *v, const int *u, int no_zero_size, int n_tr_s, int pred_mode_intra, int lfnst_idx, int log2_transform_range); -#endif // AVCODEC_VVC_VVC_ITX_1D_H +#endif // AVCODEC_VVC_ITX_1D_H diff --git a/libavcodec/vvc/vvc_mvs.c b/libavcodec/vvc/mvs.c similarity index 93% rename from libavcodec/vvc/vvc_mvs.c rename to libavcodec/vvc/mvs.c index 51d5e3b6b..86ad31003 100644 --- a/libavcodec/vvc/vvc_mvs.c +++ b/libavcodec/vvc/mvs.c @@ -20,10 +20,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "vvc_ctu.h" -#include "vvc_data.h" -#include "vvc_refs.h" -#include "vvc_mvs.h" +#include "ctu.h" +#include "data.h" +#include "refs.h" +#include "mvs.h" #define IS_SAME_MV(a, b) (AV_RN64A(a) == AV_RN64A(b)) @@ -88,8 +88,8 @@ static int check_mvset(Mv *mvLXCol, Mv *mvCol, const RefPicList *refPicList, int X, int refIdxLx, const RefPicList *refPicList_col, int listCol, int refidxCol) { - int cur_lt = refPicList[X].isLongTerm[refIdxLx]; - int col_lt = refPicList_col[listCol].isLongTerm[refidxCol]; + int cur_lt = refPicList[X].refs[refIdxLx].is_lt; + int col_lt = refPicList_col[listCol].refs[refidxCol].is_lt; int col_poc_diff, cur_poc_diff; if (cur_lt != col_lt) { @@ -98,8 +98,8 @@ static int check_mvset(Mv *mvLXCol, Mv *mvCol, return 0; } - col_poc_diff = colPic - refPicList_col[listCol].list[refidxCol]; - cur_poc_diff = poc - refPicList[X].list[refIdxLx]; + col_poc_diff = colPic - refPicList_col[listCol].refs[refidxCol].poc; + cur_poc_diff = poc - refPicList[X].refs[refIdxLx].poc; mv_compression(mvCol); if (cur_lt || col_poc_diff == cur_poc_diff) { @@ -125,8 +125,8 @@ int ff_vvc_no_backward_pred_flag(const VVCLocalContext *lc) const RefPicList *rpl = lc->sc->rpl; for (j = 0; j < 2; j++) { - for (i = 0; i < rpl[j].nb_refs; i++) { - if (rpl[j].list[i] > lc->fc->ps.ph.poc) { + for (i = 0; i < lc->sc->sh.r->num_ref_idx_active[j]; i++) { + if (rpl[j].refs[i].poc > lc->fc->ps.ph.poc) { check_diffpicount++; break; } @@ -200,10 +200,12 @@ static int derive_temporal_colocated_mvs(const VVCLocalContext *lc, MvField temp static int temporal_luma_motion_vector(const VVCLocalContext *lc, const int refIdxLx, Mv *mvLXCol, const int X, int check_center, int sb_flag) { - const VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const CodingUnit *cu = lc->cu; - int x, y, colPic, availableFlagLXCol = 0; + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const VVCPPS *pps = fc->ps.pps; + const CodingUnit *cu = lc->cu; + const int subpic_idx = lc->sc->sh.r->curr_subpic_idx; + int x, y, x_end, y_end, colPic, availableFlagLXCol = 0; int min_pu_width = fc->ps.pps->min_pu_width; VVCFrame *ref = fc->ref->collocated_ref; MvField *tab_mvf; @@ -224,10 +226,12 @@ static int temporal_luma_motion_vector(const VVCLocalContext *lc, x = cu->x0 + cu->cb_width; y = cu->y0 + cu->cb_height; + x_end = pps->subpic_x[subpic_idx] + pps->subpic_width[subpic_idx]; + y_end = pps->subpic_y[subpic_idx] + pps->subpic_height[subpic_idx]; + if (tab_mvf && (cu->y0 >> sps->ctb_log2_size_y) == (y >> sps->ctb_log2_size_y) && - y < fc->ps.pps->height && - x < fc->ps.pps->width) { + x < x_end && y < y_end) { x &= ~7; y &= ~7; temp_col = TAB_MVF(x, y); @@ -293,7 +297,8 @@ static int derive_cb_prof_flag_lx(const VVCLocalContext *lc, const PredictionUni if (IS_SAME_MV(cp_mv, cp_mv + 1) && IS_SAME_MV(cp_mv, cp_mv + 2)) return 0; } - //fixme: RprConstraintsActiveFlag + if (lc->sc->rpl[lx].refs[mi->ref_idx[lx]].is_scaled) + return 0; return 1; } @@ -394,7 +399,6 @@ static void store_cp_mv(const VVCLocalContext *lc, const MotionInfo *mi, const i const int offset = (y_cb * min_cb_width + x_cb) * MAX_CONTROL_POINTS; memcpy(&fc->tab.cp_mv[lx][offset], mi->mv[lx], sizeof(Mv) * num_cp_mv); - SAMPLE_CTB(fc->tab.mmi, x_cb, y_cb) = mi->motion_model_idc; } } } @@ -540,25 +544,31 @@ typedef struct NeighbourContext { const VVCLocalContext *lc; } NeighbourContext; +static int is_available(const VVCFrameContext *fc, const int x0, const int y0) +{ + const VVCSPS *sps = fc->ps.sps; + const int x = x0 >> sps->min_cb_log2_size_y; + const int y = y0 >> sps->min_cb_log2_size_y; + const int min_cb_width = fc->ps.pps->min_cb_width; + + return SAMPLE_CTB(fc->tab.cb_width[0], x, y) != 0; +} + static int is_a0_available(const VVCLocalContext *lc, const CodingUnit *cu) { const VVCFrameContext *fc = lc->fc; const VVCSPS *sps = fc->ps.sps; - const int x0b = av_mod_uintp2(cu->x0, sps->ctb_log2_size_y); + const int x0b = av_zero_extend(cu->x0, sps->ctb_log2_size_y); int cand_bottom_left; if (!x0b && !lc->ctb_left_flag) { cand_bottom_left = 0; } else { - const int log2_min_cb_size = sps->min_cb_log2_size_y; - const int min_cb_width = fc->ps.pps->min_cb_width; - const int x = (cu->x0 - 1) >> log2_min_cb_size; - const int y = (cu->y0 + cu->cb_height) >> log2_min_cb_size; - const int max_y = FFMIN(fc->ps.pps->height, ((cu->y0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y); + const int max_y = FFMIN(fc->ps.pps->height, ((cu->y0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y); if (cu->y0 + cu->cb_height >= max_y) cand_bottom_left = 0; else - cand_bottom_left = SAMPLE_CTB(fc->tab.cb_width[0], x, y) != 0; + cand_bottom_left = is_available(fc, cu->x0 - 1, cu->y0 + cu->cb_height); } return cand_bottom_left; } @@ -603,9 +613,9 @@ static int check_available(Neighbour *n, const VVCLocalContext *lc, const int ch if (!n->checked) { n->checked = 1; n->available = !sps->r->sps_entropy_coding_sync_enabled_flag || ((n->x >> sps->ctb_log2_size_y) <= (cu->x0 >> sps->ctb_log2_size_y)); - n->available &= cu->pred_mode == pred_flag_to_mode(TAB_MVF(n->x, n->y).pred_flag); + n->available = n->available && is_available(fc, n->x, n->y) && cu->pred_mode == pred_flag_to_mode(TAB_MVF(n->x, n->y).pred_flag); if (check_mer) - n->available &= !is_same_mer(fc, n->x, n->y, cu->x0, cu->y0); + n->available = n->available && !is_same_mer(fc, n->x, n->y, cu->x0, cu->y0); } return n->available; } @@ -989,13 +999,18 @@ static av_always_inline int compare_pf_ref_idx(const MvField *A, const struct Mv return 1; } -static av_always_inline void sb_clip_location(const VVCFrameContext *fc, +static av_always_inline void sb_clip_location(const VVCLocalContext *lc, const int x_ctb, const int y_ctb, const Mv* temp_mv, int *x, int *y) { - const VVCPPS *pps = fc->ps.pps; - const int ctb_log2_size = fc->ps.sps->ctb_log2_size_y; - *y = av_clip(*y + temp_mv->y, y_ctb, FFMIN(pps->height - 1, y_ctb + (1 << ctb_log2_size) - 1)) & ~7; - *x = av_clip(*x + temp_mv->x, x_ctb, FFMIN(pps->width - 1, x_ctb + (1 << ctb_log2_size) + 3)) & ~7; + const VVCFrameContext *fc = lc->fc; + const VVCPPS *pps = fc->ps.pps; + const int ctb_log2_size = fc->ps.sps->ctb_log2_size_y; + const int subpic_idx = lc->sc->sh.r->curr_subpic_idx; + const int x_end = pps->subpic_x[subpic_idx] + pps->subpic_width[subpic_idx]; + const int y_end = pps->subpic_y[subpic_idx] + pps->subpic_height[subpic_idx]; + + *x = av_clip(*x + temp_mv->x, x_ctb, FFMIN(x_end - 1, x_ctb + (1 << ctb_log2_size) + 3)) & ~7; + *y = av_clip(*y + temp_mv->y, y_ctb, FFMIN(y_end - 1, y_ctb + (1 << ctb_log2_size) - 1)) & ~7; } static void sb_temproal_luma_motion(const VVCLocalContext *lc, @@ -1013,7 +1028,7 @@ static void sb_temproal_luma_motion(const VVCLocalContext *lc, int colPic = ref->poc; int X = 0; - sb_clip_location(fc, x_ctb, y_ctb, temp_mv, &x, &y); + sb_clip_location(lc, x_ctb, y_ctb, temp_mv, &x, &y); temp_col = TAB_MVF(x, y); mvLXCol = mv + 0; @@ -1048,9 +1063,9 @@ static int sb_temporal_luma_motion_data(const VVCLocalContext *lc, const MvField colPic = ref->poc; if (a1) { - if ((a1->pred_flag & PF_L0) && colPic == rpl[0].list[a1->ref_idx[0]]) + if ((a1->pred_flag & PF_L0) && colPic == rpl[L0].refs[a1->ref_idx[L0]].poc) *temp_mv = a1->mv[0]; - else if ((a1->pred_flag & PF_L1) && colPic == rpl[1].list[a1->ref_idx[1]]) + else if ((a1->pred_flag & PF_L1) && colPic == rpl[L1].refs[a1->ref_idx[L1]].poc) *temp_mv = a1->mv[1]; ff_vvc_round_mv(temp_mv, 0, 4); } @@ -1407,16 +1422,16 @@ static int mvp_candidate(const VVCLocalContext *lc, const int x_cand, const int const MvField* tab_mvf = fc->tab.mvf; const MvField *mvf = &TAB_MVF(x_cand, y_cand); const PredFlag maskx = lx + 1; - const int poc = rpl[lx].list[ref_idx[lx]]; + const int poc = rpl[lx].refs[ref_idx[lx]].poc; int available = 0; - if ((mvf->pred_flag & maskx) && rpl[lx].list[mvf->ref_idx[lx]] == poc) { + if ((mvf->pred_flag & maskx) && rpl[lx].refs[mvf->ref_idx[lx]].poc == poc) { available = 1; *mv = mvf->mv[lx]; } else { const int ly = !lx; const PredFlag masky = ly + 1; - if ((mvf->pred_flag & masky) && rpl[ly].list[mvf->ref_idx[ly]] == poc) { + if ((mvf->pred_flag & masky) && rpl[ly].refs[mvf->ref_idx[ly]].poc == poc) { available = 1; *mv = mvf->mv[ly]; } @@ -1439,15 +1454,15 @@ static int affine_mvp_candidate(const VVCLocalContext *lc, const MvField *mvf = &TAB_MVF(x_nb, y_nb); RefPicList* rpl = lc->sc->rpl; const PredFlag maskx = lx + 1; - const int poc = rpl[lx].list[ref_idx[lx]]; + const int poc = rpl[lx].refs[ref_idx[lx]].poc; - if ((mvf->pred_flag & maskx) && rpl[lx].list[mvf->ref_idx[lx]] == poc) { + if ((mvf->pred_flag & maskx) && rpl[lx].refs[mvf->ref_idx[lx]].poc == poc) { available = 1; affine_cps_from_nb(lc, x_nb, y_nb, nbw, nbh, lx, cps, num_cp); } else { const int ly = !lx; const PredFlag masky = ly + 1; - if ((mvf->pred_flag & masky) && rpl[ly].list[mvf->ref_idx[ly]] == poc) { + if ((mvf->pred_flag & masky) && rpl[ly].refs[mvf->ref_idx[ly]].poc == poc) { available = 1; affine_cps_from_nb(lc, x_nb, y_nb, nbw, nbh, ly, cps, num_cp); } @@ -1539,7 +1554,7 @@ static int mvp_history_candidates(const VVCLocalContext *lc, { const EntryPoint* ep = lc->ep; const RefPicList* rpl = lc->sc->rpl; - const int poc = rpl[lx].list[ref_idx]; + const int poc = rpl[lx].refs[ref_idx].poc; if (ep->num_hmvp == 0) return 0; @@ -1548,7 +1563,7 @@ static int mvp_history_candidates(const VVCLocalContext *lc, for (int j = 0; j < 2; j++) { const int ly = (j ? !lx : lx); PredFlag mask = PF_L0 + ly; - if ((h->pred_flag & mask) && poc == rpl[ly].list[h->ref_idx[ly]]) { + if ((h->pred_flag & mask) && poc == rpl[ly].refs[h->ref_idx[ly]].poc) { if (mvp_lx_flag == num_cands) { *mv = h->mv[ly]; ff_vvc_round_mv(mv, amvr_shift, amvr_shift); @@ -1685,17 +1700,34 @@ static void ibc_merge_candidates(VVCLocalContext *lc, const int merge_idx, Mv *m memset(mv, 0, sizeof(*mv)); } -void ff_vvc_mvp_ibc(VVCLocalContext *lc, const int mvp_l0_flag, const int amvr_shift, Mv *mv) +static int ibc_check_mv(VVCLocalContext *lc, Mv *mv) +{ + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = lc->fc->ps.sps; + const CodingUnit *cu = lc->cu; + const Mv *bv = &cu->pu.mi.mv[L0][0]; + + if (sps->ctb_size_y < ((cu->y0 + (bv->y >> 4)) & (sps->ctb_size_y - 1)) + cu->cb_height) { + av_log(fc->log_ctx, AV_LOG_ERROR, "IBC region spans multiple CTBs.\n"); + return AVERROR_INVALIDDATA; + } + + return 0; +} + +int ff_vvc_mvp_ibc(VVCLocalContext *lc, const int mvp_l0_flag, const int amvr_shift, Mv *mv) { LOCAL_ALIGNED_8(Mv, mvp, [1]); ibc_merge_candidates(lc, mvp_l0_flag, mvp); ibc_add_mvp(mv, mvp, amvr_shift); + return ibc_check_mv(lc, mv); } -void ff_vvc_luma_mv_merge_ibc(VVCLocalContext *lc, const int merge_idx, Mv *mv) +int ff_vvc_luma_mv_merge_ibc(VVCLocalContext *lc, const int merge_idx, Mv *mv) { ibc_merge_candidates(lc, merge_idx, mv); + return ibc_check_mv(lc, mv); } static int affine_mvp_constructed_cp(NeighbourContext *ctx, @@ -1714,14 +1746,14 @@ static int affine_mvp_constructed_cp(NeighbourContext *ctx, if (check_available(n, ctx->lc, 0)) { const PredFlag maskx = lx + 1; const MvField* mvf = &TAB_MVF(n->x, n->y); - const int poc = rpl[lx].list[ref_idx]; - if ((mvf->pred_flag & maskx) && rpl[lx].list[mvf->ref_idx[lx]] == poc) { + const int poc = rpl[lx].refs[ref_idx].poc; + if ((mvf->pred_flag & maskx) && rpl[lx].refs[mvf->ref_idx[lx]].poc == poc) { available = 1; *cp = mvf->mv[lx]; } else { const int ly = !lx; const PredFlag masky = ly + 1; - if ((mvf->pred_flag & masky) && rpl[ly].list[mvf->ref_idx[ly]] == poc) { + if ((mvf->pred_flag & masky) && rpl[ly].refs[mvf->ref_idx[ly]].poc == poc) { available = 1; *cp = mvf->mv[ly]; } diff --git a/libavcodec/vvc/vvc_mvs.h b/libavcodec/vvc/mvs.h similarity index 88% rename from libavcodec/vvc/vvc_mvs.h rename to libavcodec/vvc/mvs.h index 78ad17c30..b2242b2a4 100644 --- a/libavcodec/vvc/vvc_mvs.h +++ b/libavcodec/vvc/mvs.h @@ -20,19 +20,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVC_MVS_H -#define AVCODEC_VVC_VVC_MVS_H +#ifndef AVCODEC_VVC_MVS_H +#define AVCODEC_VVC_MVS_H -#include "vvc_ctu.h" +#include "ctu.h" void ff_vvc_round_mv(Mv *mv, int lshift, int rshift); void ff_vvc_clip_mv(Mv *mv); void ff_vvc_mv_scale(Mv *dst, const Mv *src, int td, int tb); void ff_vvc_luma_mv_merge_mode(VVCLocalContext *lc, int merge_idx, int ciip_flag, MvField *mv); void ff_vvc_luma_mv_merge_gpm(VVCLocalContext *lc, const int merge_gpm_idx[2], MvField *mv); -void ff_vvc_luma_mv_merge_ibc(VVCLocalContext *lc, int merge_idx, Mv *mv); +int ff_vvc_luma_mv_merge_ibc(VVCLocalContext *lc, int merge_idx, Mv *mv); void ff_vvc_mvp(VVCLocalContext *lc, const int *mvp_lx_flag, const int amvr_shift, MotionInfo *mi); -void ff_vvc_mvp_ibc(VVCLocalContext *lc, int mvp_l0_flag, int amvr_shift, Mv *mv); +int ff_vvc_mvp_ibc(VVCLocalContext *lc, int mvp_l0_flag, int amvr_shift, Mv *mv); void ff_vvc_sb_mv_merge_mode(VVCLocalContext *lc, int merge_subblock_idx, PredictionUnit *pu); void ff_vvc_affine_mvp(VVCLocalContext *lc, const int *mvp_lx_flag, const int amvr_shift, MotionInfo* mi); void ff_vvc_store_sb_mvs(const VVCLocalContext *lc, PredictionUnit *pu); @@ -45,4 +45,4 @@ 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); -#endif //AVCODEC_VVC_VVC_MVS_H +#endif //AVCODEC_VVC_MVS_H diff --git a/libavcodec/vvc/vvc_ps.c b/libavcodec/vvc/ps.c similarity index 83% rename from libavcodec/vvc/vvc_ps.c rename to libavcodec/vvc/ps.c index 7972803da..ff9a6c7a1 100644 --- a/libavcodec/vvc/vvc_ps.c +++ b/libavcodec/vvc/ps.c @@ -20,12 +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 "libavcodec/cbs_h266.h" -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" #include "libavcodec/refstruct.h" -#include "vvc_data.h" -#include "vvc_ps.h" -#include "vvcdec.h" +#include "data.h" +#include "ps.h" +#include "dec.h" static int sps_map_pixel_format(VVCSPS *sps, void *log_ctx) { @@ -99,9 +101,14 @@ static int sps_chroma_qp_table(VVCSPS *sps) qp_out[0] = qp_in[0] = r->sps_qp_table_start_minus26[i] + 26; for (int j = 0; j < num_points_in_qp_table; j++ ) { + const uint8_t delta_qp_out = (r->sps_delta_qp_in_val_minus1[i][j] ^ r->sps_delta_qp_diff_val[i][j]); delta_qp_in[j] = r->sps_delta_qp_in_val_minus1[i][j] + 1; + // Note: we cannot check qp_{in,out}[j+1] here as qp_*[j] + delta_qp_* + // may not fit in an 8-bit signed integer. + if (qp_in[j] + delta_qp_in[j] > 63 || qp_out[j] + delta_qp_out > 63) + return AVERROR(EINVAL); qp_in[j+1] = qp_in[j] + delta_qp_in[j]; - qp_out[j+1] = qp_out[j] + (r->sps_delta_qp_in_val_minus1[i][j] ^ r->sps_delta_qp_diff_val[i][j]); + qp_out[j+1] = qp_out[j] + delta_qp_out; } sps->chroma_qp_table[i][qp_in[0] + off] = qp_out[0]; for (int k = qp_in[0] - 1 + off; k >= 0; k--) @@ -184,8 +191,11 @@ static int sps_derive(VVCSPS *sps, void *log_ctx) sps_inter(sps); sps_partition_constraints(sps); sps_ladf(sps); - if (r->sps_chroma_format_idc != 0) - sps_chroma_qp_table(sps); + if (r->sps_chroma_format_idc != 0) { + ret = sps_chroma_qp_table(sps); + if (ret < 0) + return ret; + } return 0; } @@ -217,14 +227,22 @@ fail: return NULL; } -static int decode_sps(VVCParamSets *ps, const H266RawSPS *rsps, void *log_ctx) +static int decode_sps(VVCParamSets *ps, const H266RawSPS *rsps, void *log_ctx, int is_clvss) { const int sps_id = rsps->sps_seq_parameter_set_id; const VVCSPS *old_sps = ps->sps_list[sps_id]; const VVCSPS *sps; - if (old_sps && old_sps->r == rsps) - return 0; + if (is_clvss) { + ps->sps_id_used = 0; + } + + if (old_sps) { + if (old_sps->r == rsps || !memcmp(old_sps->r, rsps, sizeof(*old_sps->r))) + return 0; + else if (ps->sps_id_used & (1 << sps_id)) + return AVERROR_INVALIDDATA; + } sps = sps_alloc(rsps, log_ctx); if (!sps) @@ -232,6 +250,7 @@ static int decode_sps(VVCParamSets *ps, const H266RawSPS *rsps, void *log_ctx) ff_refstruct_unref(&ps->sps_list[sps_id]); ps->sps_list[sps_id] = sps; + ps->sps_id_used |= (1 << sps_id); return 0; } @@ -290,6 +309,7 @@ static int pps_bd(VVCPPS *pps) for (int k = pps->col_bd[i]; k < j; k++) pps->ctb_to_col_bd[k] = pps->col_bd[i]; } + pps->col_bd[r->num_tile_columns] = pps->ctb_to_col_bd[pps->ctb_width] = pps->ctb_width; for (int i = 0, j = 0; i < r->num_tile_rows; i++) { pps->row_bd[i] = j; @@ -297,6 +317,8 @@ static int pps_bd(VVCPPS *pps) for (int k = pps->row_bd[i]; k < j; k++) pps->ctb_to_row_bd[k] = pps->row_bd[i]; } + pps->row_bd[r->num_tile_rows] = pps->ctb_to_row_bd[pps->ctb_height] = pps->ctb_height; + return 0; } @@ -319,43 +341,120 @@ static void tile_xy(int *tile_x, int *tile_y, const int tile_idx, const VVCPPS * *tile_y = tile_idx / pps->r->num_tile_columns; } -static void ctu_xy(int *ctu_x, int *ctu_y, const int tile_x, const int tile_y, const VVCPPS *pps) +static void ctu_xy(int *rx, int *ry, const int tile_x, const int tile_y, const VVCPPS *pps) { - *ctu_x = pps->col_bd[tile_x]; - *ctu_y = pps->row_bd[tile_y]; + *rx = pps->col_bd[tile_x]; + *ry = pps->row_bd[tile_y]; } -static int ctu_rs(const int ctu_x, const int ctu_y, const VVCPPS *pps) +static int ctu_rs(const int rx, const int ry, const VVCPPS *pps) { - return pps->ctb_width * ctu_y + ctu_x; + return pps->ctb_width * ry + rx; } -static int pps_add_ctus(VVCPPS *pps, int *off, const int ctu_x, const int ctu_y, +static int pps_add_ctus(VVCPPS *pps, int *off, const int rx, const int ry, const int w, const int h) { int start = *off; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { - pps->ctb_addr_in_slice[*off] = ctu_rs(ctu_x + x, ctu_y + y, pps); + pps->ctb_addr_in_slice[*off] = ctu_rs(rx + x, ry + y, pps); (*off)++; } } return *off - start; } +static void pps_single_slice_picture(VVCPPS *pps, int *off) +{ + 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, + pps->col_bd[i], pps->row_bd[j], + pps->r->col_width_val[i], pps->r->row_height_val[j]); + } + } +} + +static void subpic_tiles(int *tile_x, int *tile_y, int *tile_x_end, int *tile_y_end, + const VVCSPS *sps, const VVCPPS *pps, const int i) +{ + const int rx = sps->r->sps_subpic_ctu_top_left_x[i]; + const int ry = sps->r->sps_subpic_ctu_top_left_y[i]; + + *tile_x = *tile_y = 0; + + while (pps->col_bd[*tile_x] < rx) + (*tile_x)++; + + while (pps->row_bd[*tile_y] < ry) + (*tile_y)++; + + *tile_x_end = (*tile_x); + *tile_y_end = (*tile_y); + + while (pps->col_bd[*tile_x_end] < rx + sps->r->sps_subpic_width_minus1[i] + 1) + (*tile_x_end)++; + + while (pps->row_bd[*tile_y_end] < ry + sps->r->sps_subpic_height_minus1[i] + 1) + (*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) +{ + 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); +} + +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) +{ + 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, + pps->col_bd[tx], pps->row_bd[ty], + pps->r->col_width_val[tx], pps->r->row_height_val[ty]); + } + } +} + +static void pps_subpic_slice(VVCPPS *pps, const VVCSPS *sps, const int i, int *off) +{ + int tx, ty, x_end, y_end; + + pps->slice_start_offset[i] = *off; + pps->num_ctus_in_slice[i] = 0; + + 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); + else + 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) +{ + if (!sps->r->sps_subpic_info_present_flag) { + pps_single_slice_picture(pps, off); + } else { + for (int i = 0; i < pps->r->pps_num_slices_in_pic_minus1 + 1; i++) + pps_subpic_slice(pps, sps, i, off); + } +} + static int pps_one_tile_slices(VVCPPS *pps, const int tile_idx, int i, int *off) { const H266RawPPS *r = pps->r; - int ctu_x, ctu_y, ctu_y_end, tile_x, tile_y; + int rx, ry, ctu_y_end, tile_x, tile_y; tile_xy(&tile_x, &tile_y, tile_idx, pps); - ctu_xy(&ctu_x, &ctu_y, tile_x, tile_y, pps); - ctu_y_end = ctu_y + r->row_height_val[tile_y]; - while (ctu_y < ctu_y_end) { + ctu_xy(&rx, &ry, tile_x, tile_y, pps); + ctu_y_end = ry + r->row_height_val[tile_y]; + while (ry < ctu_y_end) { pps->slice_start_offset[i] = *off; - pps->num_ctus_in_slice[i] = pps_add_ctus(pps, off, ctu_x, ctu_y, + pps->num_ctus_in_slice[i] = pps_add_ctus(pps, off, rx, ry, r->col_width_val[tile_x], r->slice_height_in_ctus[i]); - ctu_y += r->slice_height_in_ctus[i++]; + ry += r->slice_height_in_ctus[i++]; } i--; return i; @@ -364,32 +463,36 @@ static int pps_one_tile_slices(VVCPPS *pps, const int tile_idx, int i, int *off) static void pps_multi_tiles_slice(VVCPPS *pps, const int tile_idx, const int i, int *off) { const H266RawPPS *r = pps->r; - int ctu_x, ctu_y,tile_x, tile_y; + int rx, ry, tile_x, tile_y; tile_xy(&tile_x, &tile_y, tile_idx, pps); pps->slice_start_offset[i] = *off; 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++) { - ctu_xy(&ctu_x, &ctu_y, tx, ty, pps); - pps->num_ctus_in_slice[i] += pps_add_ctus(pps, off, ctu_x, ctu_y, + ctu_xy(&rx, &ry, tx, ty, pps); + pps->num_ctus_in_slice[i] += pps_add_ctus(pps, off, rx, ry, r->col_width_val[tx], r->row_height_val[ty]); } } } -static void pps_rect_slice(VVCPPS* pps) +static void pps_rect_slice(VVCPPS *pps, const VVCSPS *sps) { - const H266RawPPS* r = pps->r; + const H266RawPPS *r = pps->r; int tile_idx = 0, off = 0; + if (r->pps_single_slice_per_subpic_flag) { + pps_single_slice_per_subpic(pps, sps, &off); + return; + } + 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); } else { pps_multi_tiles_slice(pps, tile_idx, i, &off); - } tile_idx = next_tile_idx(tile_idx, i, r); } @@ -398,24 +501,24 @@ static void pps_rect_slice(VVCPPS* pps) static void pps_no_rect_slice(VVCPPS* pps) { const H266RawPPS* r = pps->r; - int ctu_x, ctu_y, off = 0; + 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++) { - ctu_xy(&ctu_x, &ctu_y, tile_x, tile_y, pps); - pps_add_ctus(pps, &off, ctu_x, ctu_y, r->col_width_val[tile_x], r->row_height_val[tile_y]); + 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]); } } } -static int pps_slice_map(VVCPPS *pps) +static int pps_slice_map(VVCPPS *pps, const VVCSPS *sps) { 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); + pps_rect_slice(pps, sps); else pps_no_rect_slice(pps); @@ -430,6 +533,24 @@ static void pps_ref_wraparound_offset(VVCPPS *pps, const VVCSPS *sps) pps->ref_wraparound_offset = (pps->width / sps->min_cb_size_y) - r->pps_pic_width_minus_wraparound_offset; } +static void pps_subpic(VVCPPS *pps, const VVCSPS *sps) +{ + const H266RawSPS *rsps = sps->r; + for (int i = 0; i < rsps->sps_num_subpics_minus1 + 1; i++) { + if (rsps->sps_subpic_treated_as_pic_flag[i]) { + pps->subpic_x[i] = rsps->sps_subpic_ctu_top_left_x[i] << sps->ctb_log2_size_y; + pps->subpic_y[i] = rsps->sps_subpic_ctu_top_left_y[i] << sps->ctb_log2_size_y; + pps->subpic_width[i] = FFMIN(pps->width - pps->subpic_x[i], (rsps->sps_subpic_width_minus1[i] + 1) << sps->ctb_log2_size_y); + pps->subpic_height[i] = FFMIN(pps->height - pps->subpic_y[i], (rsps->sps_subpic_height_minus1[i] + 1) << sps->ctb_log2_size_y); + } else { + pps->subpic_x[i] = 0; + pps->subpic_y[i] = 0; + pps->subpic_width[i] = pps->width; + pps->subpic_height[i] = pps->height; + } + } +} + static int pps_derive(VVCPPS *pps, const VVCSPS *sps) { int ret; @@ -441,11 +562,12 @@ static int pps_derive(VVCPPS *pps, const VVCSPS *sps) if (ret < 0) return ret; - ret = pps_slice_map(pps); + ret = pps_slice_map(pps, sps); if (ret < 0) return ret; pps_ref_wraparound_offset(pps, sps); + pps_subpic(pps, sps); return 0; } @@ -505,7 +627,7 @@ static int decode_pps(VVCParamSets *ps, const H266RawPPS *rpps) return ret; } -static int decode_ps(VVCParamSets *ps, const CodedBitstreamH266Context *h266, void *log_ctx) +static int decode_ps(VVCParamSets *ps, const CodedBitstreamH266Context *h266, void *log_ctx, int is_clvss) { const H266RawPictureHeader *ph = h266->ph; const H266RawPPS *rpps; @@ -523,7 +645,7 @@ static int decode_ps(VVCParamSets *ps, const CodedBitstreamH266Context *h266, vo if (!rsps) return AVERROR_INVALIDDATA; - ret = decode_sps(ps, rsps, log_ctx); + ret = decode_sps(ps, rsps, log_ctx, is_clvss); if (ret < 0) return ret; @@ -674,8 +796,49 @@ static int ph_max_num_subblock_merge_cand(const H266RawSPS *sps, const H266RawPi return sps->sps_sbtmvp_enabled_flag && ph->ph_temporal_mvp_enabled_flag; } +static int ph_vb_pos(uint16_t *vbs, uint8_t *num_vbs, const uint16_t *pos_minus_1, const uint8_t num_pos, uint16_t max, const int ctb_size_y) +{ + max = FF_CEIL_RSHIFT(max, 3) - 2; + for (int i = 0; i < num_pos; i++) { + if (pos_minus_1[i] > max) + return AVERROR_INVALIDDATA; + + vbs[i] = (pos_minus_1[i] + 1) << 3; + + // The distance between any two vertical virtual boundaries shall be greater than or equal to CtbSizeY luma samples + if (i && vbs[i] < vbs[i - 1] + ctb_size_y) + return AVERROR_INVALIDDATA; + } + *num_vbs = num_pos; + + return 0; +} + +#define VBF(f) (sps->sps_virtual_boundaries_present_flag ? sps->sps_##f : ph->r->ph_##f) +#define VBFS(c, d) VBF(virtual_boundary_pos_##c##_minus1), VBF(num_##d##_virtual_boundaries) + +static int ph_vb(VVCPH *ph, const H266RawSPS *sps, const H266RawPPS *pps) +{ + const int ctb_size_y = 1 << (sps->sps_log2_ctu_size_minus5 + 5); + int ret; + + if (!sps->sps_virtual_boundaries_enabled_flag) + return 0; + + ret = ph_vb_pos(ph->vb_pos_x, &ph->num_ver_vbs, VBFS(x, ver), pps->pps_pic_width_in_luma_samples, ctb_size_y); + if (ret < 0) + return ret; + + ret = ph_vb_pos(ph->vb_pos_y, &ph->num_hor_vbs, VBFS(y, hor), pps->pps_pic_height_in_luma_samples, ctb_size_y); + if (ret < 0) + return ret; + + return 0; +} + static int ph_derive(VVCPH *ph, const H266RawSPS *sps, const H266RawPPS *pps, const int poc_tid0, const int is_clvss) { + int ret; ph->max_num_subblock_merge_cand = ph_max_num_subblock_merge_cand(sps, ph->r); ph->poc = ph_compute_poc(ph->r, sps, poc_tid0, is_clvss); @@ -683,6 +846,10 @@ static int ph_derive(VVCPH *ph, const H266RawSPS *sps, const H266RawPPS *pps, co if (pps->pps_wp_info_in_ph_flag) pred_weight_table(&ph->pwt, &ph->r->ph_pred_weight_table); + ret = ph_vb(ph, sps, pps); + if (ret < 0) + return ret; + return 0; } @@ -762,13 +929,16 @@ int ff_vvc_decode_frame_ps(VVCFrameParamSets *fps, struct VVCContext *s) int ret = 0; VVCParamSets *ps = &s->ps; const CodedBitstreamH266Context *h266 = s->cbc->priv_data; + int is_clvss; - ret = decode_ps(ps, h266, s->avctx); + decode_recovery_flag(s); + is_clvss = IS_CLVSS(s); + + ret = decode_ps(ps, h266, s->avctx, is_clvss); if (ret < 0) return ret; - decode_recovery_flag(s); - ret = decode_frame_ps(fps, ps, h266, s->poc_tid0, IS_CLVSS(s)); + ret = decode_frame_ps(fps, ps, h266, s->poc_tid0, is_clvss); decode_recovery_poc(s, &fps->ph); return ret; } @@ -1079,12 +1249,12 @@ static void sh_deblock_offsets(VVCSH *sh) const H266RawSliceHeader *r = sh->r; if (!r->sh_deblocking_filter_disabled_flag) { - sh->deblock.beta_offset[LUMA] = r->sh_luma_beta_offset_div2 << 1; - sh->deblock.tc_offset[LUMA] = r->sh_luma_tc_offset_div2 << 1; - sh->deblock.beta_offset[CB] = r->sh_cb_beta_offset_div2 << 1; - sh->deblock.tc_offset[CB] = r->sh_cb_tc_offset_div2 << 1; - sh->deblock.beta_offset[CR] = r->sh_cr_beta_offset_div2 << 1; - sh->deblock.tc_offset[CR] = r->sh_cr_tc_offset_div2 << 1; + sh->deblock.beta_offset[LUMA] = r->sh_luma_beta_offset_div2 * 2; + sh->deblock.tc_offset[LUMA] = r->sh_luma_tc_offset_div2 * 2; + sh->deblock.beta_offset[CB] = r->sh_cb_beta_offset_div2 * 2; + sh->deblock.tc_offset[CB] = r->sh_cb_tc_offset_div2 * 2; + sh->deblock.beta_offset[CR] = r->sh_cr_beta_offset_div2 * 2; + sh->deblock.tc_offset[CR] = r->sh_cr_tc_offset_div2 * 2; } } diff --git a/libavcodec/vvc/vvc_ps.h b/libavcodec/vvc/ps.h similarity index 91% rename from libavcodec/vvc/vvc_ps.h rename to libavcodec/vvc/ps.h index 1164d0eab..9203e2c57 100644 --- a/libavcodec/vvc/vvc_ps.h +++ b/libavcodec/vvc/ps.h @@ -20,8 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVC_PS_H -#define AVCODEC_VVC_VVC_PS_H +#ifndef AVCODEC_VVC_PS_H +#define AVCODEC_VVC_PS_H #include "libavcodec/cbs_h266.h" #include "libavcodec/vvc.h" @@ -69,7 +69,7 @@ typedef struct VVCSPS { uint8_t bit_depth; ///< BitDepth uint8_t qp_bd_offset; ///< QpBdOffset uint8_t ctb_log2_size_y; ///< CtbLog2SizeY - uint8_t ctb_size_y; ///< CtbSizeY + uint16_t ctb_size_y; ///< CtbSizeY uint8_t min_cb_log2_size_y; ///< MinCbLog2SizeY uint8_t min_cb_size_y; ///< MinCbSizeY uint8_t max_tb_size_y; ///< MaxTbSizeY @@ -115,10 +115,10 @@ typedef struct VVCPPS { uint16_t min_tu_height; uint32_t *ctb_addr_in_slice; ///< CtbAddrInCurrSlice for entire picture - uint16_t *col_bd; - uint16_t *row_bd; - uint16_t *ctb_to_col_bd; - uint16_t *ctb_to_row_bd; + uint16_t *col_bd; ///< TileColBdVal + uint16_t *row_bd; ///< TileRowBdVal + uint16_t *ctb_to_col_bd; ///< CtbToTileColBd + uint16_t *ctb_to_row_bd; ///< CtbToTileRowBd uint16_t width32; ///< width in 32 pixels uint16_t height32; ///< height in 32 pixels @@ -127,6 +127,10 @@ typedef struct VVCPPS { uint16_t ref_wraparound_offset; ///< PpsRefWraparoundOffset + uint16_t subpic_x[VVC_MAX_SLICES]; ///< SubpicLeftBoundaryPos + uint16_t subpic_y[VVC_MAX_SLICES]; ///< SubpicTopBoundaryPos + uint16_t subpic_width[VVC_MAX_SLICES]; + uint16_t subpic_height[VVC_MAX_SLICES]; } VVCPPS; #define MAX_WEIGHTS 15 @@ -147,6 +151,12 @@ typedef struct VVCPH { //derived values uint32_t max_num_subblock_merge_cand; ///< MaxNumSubblockMergeCand int32_t poc; ///< PicOrderCntVal + + uint8_t num_ver_vbs; ///< NumVerVirtualBoundaries + uint16_t vb_pos_x[VVC_MAX_VBS]; ///< VirtualBoundaryPosX + uint8_t num_hor_vbs; ///< NumHorVirtualBoundaries + uint16_t vb_pos_y[VVC_MAX_VBS]; ///< VirtualBoundaryPosY + PredWeightTable pwt; } VVCPH; @@ -210,6 +220,9 @@ typedef struct VVCParamSets { const VVCALF *alf_list[VVC_MAX_ALF_COUNT]; ///< RefStruct reference const H266RawAPS *lmcs_list[VVC_MAX_LMCS_COUNT]; ///< RefStruct reference const VVCScalingList *scaling_list[VVC_MAX_SL_COUNT]; ///< RefStruct reference + + // Bit field of SPS IDs used in the current CVS + uint16_t sps_id_used; } VVCParamSets; typedef struct VVCFrameParamSets { @@ -259,4 +272,4 @@ int ff_vvc_decode_sh(VVCSH *sh, const VVCFrameParamSets *ps, const CodedBitstrea void ff_vvc_frame_ps_free(VVCFrameParamSets *fps); void ff_vvc_ps_uninit(VVCParamSets *ps); -#endif /* AVCODEC_VVC_VVC_PS_H */ +#endif /* AVCODEC_VVC_PS_H */ diff --git a/libavcodec/vvc/vvc_refs.c b/libavcodec/vvc/refs.c similarity index 82% rename from libavcodec/vvc/vvc_refs.c rename to libavcodec/vvc/refs.c index 893048454..bf093bea9 100644 --- a/libavcodec/vvc/vvc_refs.c +++ b/libavcodec/vvc/refs.c @@ -22,11 +22,12 @@ #include +#include "libavutil/mem.h" #include "libavutil/thread.h" #include "libavcodec/refstruct.h" #include "libavcodec/thread.h" -#include "vvc_refs.h" +#include "refs.h" #define VVC_FRAME_FLAG_OUTPUT (1 << 0) #define VVC_FRAME_FLAG_SHORT_REF (1 << 1) @@ -51,6 +52,8 @@ void ff_vvc_unref_frame(VVCFrameContext *fc, VVCFrame *frame, int flags) frame->flags &= ~flags; 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); @@ -111,13 +114,18 @@ static FrameProgress *alloc_progress(void) static VVCFrame *alloc_frame(VVCContext *s, VVCFrameContext *fc) { + const VVCSPS *sps = fc->ps.sps; const VVCPPS *pps = fc->ps.pps; for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) { int ret; VVCFrame *frame = &fc->DPB[i]; + VVCWindow *win = &frame->scaling_win; if (frame->frame->buf[0]) continue; + frame->sps = ff_refstruct_ref_c(fc->ps.sps); + frame->pps = ff_refstruct_ref_c(fc->ps.pps); + ret = ff_thread_get_buffer(s->avctx, frame->frame, AV_GET_BUFFER_FLAG_REF); if (ret < 0) return NULL; @@ -138,6 +146,13 @@ static VVCFrame *alloc_frame(VVCContext *s, VVCFrameContext *fc) for (int j = 0; j < frame->ctb_count; j++) frame->rpl_tab[j] = frame->rpl; + win->left_offset = pps->r->pps_scaling_win_left_offset * (1 << sps->hshift[CHROMA]); + win->right_offset = pps->r->pps_scaling_win_right_offset * (1 << sps->hshift[CHROMA]); + win->top_offset = pps->r->pps_scaling_win_top_offset * (1 << sps->vshift[CHROMA]); + win->bottom_offset = pps->r->pps_scaling_win_bottom_offset * (1 << sps->vshift[CHROMA]); + 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; + frame->progress = alloc_progress(); if (!frame->progress) goto fail; @@ -176,9 +191,9 @@ int ff_vvc_set_new_ref(VVCContext *s, VVCFrameContext *fc, AVFrame **frame) fc->ref = ref; if (s->no_output_before_recovery_flag && (IS_RASL(s) || !GDR_IS_RECOVERED(s))) - ref->flags = 0; + ref->flags = VVC_FRAME_FLAG_SHORT_REF; else if (ph->r->ph_pic_output_flag) - ref->flags = VVC_FRAME_FLAG_OUTPUT; + ref->flags = VVC_FRAME_FLAG_OUTPUT | VVC_FRAME_FLAG_SHORT_REF; if (!ph->r->ph_non_ref_pic_flag) ref->flags |= VVC_FRAME_FLAG_SHORT_REF; @@ -225,7 +240,7 @@ int ff_vvc_output_frame(VVCContext *s, VVCFrameContext *fc, AVFrame *out, const /* wait for more frames before output */ if (!flush && s->seq_output == s->seq_decode && sps && - nb_output <= sps->r->sps_dpb_params.dpb_max_dec_pic_buffering_minus1[sps->r->sps_max_sublayers_minus1] + 1) + nb_output <= sps->r->sps_dpb_params.dpb_max_num_reorder_pics[sps->r->sps_max_sublayers_minus1]) return 0; if (nb_output) { @@ -347,11 +362,30 @@ static VVCFrame *generate_missing_ref(VVCContext *s, VVCFrameContext *fc, int po return frame; } +#define CHECK_MAX(d) (frame->ref_##d * frame->sps->r->sps_pic_##d##_max_in_luma_samples >= ref->ref_##d * (frame->pps->r->pps_pic_##d##_in_luma_samples - max)) +#define CHECK_SAMPLES(d) (frame->pps->r->pps_pic_##d##_in_luma_samples == ref->pps->r->pps_pic_##d##_in_luma_samples) +static int check_candidate_ref(const VVCFrame *frame, const VVCRefPic *refp) +{ + const VVCFrame *ref = refp->ref; + + if (refp->is_scaled) { + const int max = FFMAX(8, frame->sps->min_cb_size_y); + return frame->ref_width * 2 >= ref->ref_width && + frame->ref_height * 2 >= ref->ref_height && + frame->ref_width <= ref->ref_width * 8 && + frame->ref_height <= ref->ref_height * 8 && + CHECK_MAX(width) && CHECK_MAX(height); + } + return CHECK_SAMPLES(width) && CHECK_SAMPLES(height); +} + +#define RPR_SCALE(f) (((ref->f << 14) + (fc->ref->f >> 1)) / fc->ref->f) /* add a reference with the given poc to the list and mark it as used in DPB */ static int add_candidate_ref(VVCContext *s, VVCFrameContext *fc, RefPicList *list, int poc, int ref_flag, uint8_t use_msb) { - VVCFrame *ref = find_ref_idx(s, fc, poc, use_msb); + VVCFrame *ref = find_ref_idx(s, fc, poc, use_msb); + VVCRefPic *refp = &list->refs[list->nb_refs]; if (ref == fc->ref || list->nb_refs >= VVC_MAX_REF_ENTRIES) return AVERROR_INVALIDDATA; @@ -362,9 +396,21 @@ static int add_candidate_ref(VVCContext *s, VVCFrameContext *fc, RefPicList *lis return AVERROR(ENOMEM); } - list->list[list->nb_refs] = poc; - list->ref[list->nb_refs] = ref; - list->isLongTerm[list->nb_refs] = ref_flag & VVC_FRAME_FLAG_LONG_REF; + refp->poc = poc; + refp->ref = ref; + refp->is_lt = ref_flag & VVC_FRAME_FLAG_LONG_REF; + refp->is_scaled = ref->sps->r->sps_num_subpics_minus1 != fc->ref->sps->r->sps_num_subpics_minus1|| + memcmp(&ref->scaling_win, &fc->ref->scaling_win, sizeof(ref->scaling_win)) || + ref->pps->r->pps_pic_width_in_luma_samples != fc->ref->pps->r->pps_pic_width_in_luma_samples || + ref->pps->r->pps_pic_height_in_luma_samples != fc->ref->pps->r->pps_pic_height_in_luma_samples; + + if (!check_candidate_ref(fc->ref, refp)) + return AVERROR_INVALIDDATA; + + if (refp->is_scaled) { + refp->scale[0] = RPR_SCALE(ref_width); + refp->scale[1] = RPR_SCALE(ref_height); + } list->nb_refs++; mark_ref(ref, ref_flag); @@ -460,9 +506,14 @@ int ff_vvc_slice_rpl(VVCContext *s, VVCFrameContext *fc, SliceContext *sc) return ret; } } - if ((!rsh->sh_collocated_from_l0_flag) == lx && - rsh->sh_collocated_ref_idx < rpl->nb_refs) - fc->ref->collocated_ref = rpl->ref[rsh->sh_collocated_ref_idx]; + if (ph->r->ph_temporal_mvp_enabled_flag && + (!rsh->sh_collocated_from_l0_flag) == lx && + rsh->sh_collocated_ref_idx < rpl->nb_refs) { + const VVCRefPic *refp = rpl->refs + rsh->sh_collocated_ref_idx; + if (refp->is_scaled || refp->ref->sps->ctb_log2_size_y != sps->ctb_log2_size_y) + return AVERROR_INVALIDDATA; + fc->ref->collocated_ref = refp->ref; + } } return 0; } @@ -537,12 +588,13 @@ void ff_vvc_report_progress(VVCFrame *frame, const VVCProgress vp, const int y) VVCProgressListener *l = NULL; ff_mutex_lock(&p->lock); - - av_assert0(p->progress[vp] < y || p->progress[vp] == INT_MAX); - p->progress[vp] = y; - l = get_done_listener(p, vp); - ff_cond_signal(&p->cond); - + if (p->progress[vp] < y) { + // Due to the nature of thread scheduling, later progress may reach this point before earlier progress. + // Therefore, we only update the progress when p->progress[vp] < y. + p->progress[vp] = y; + l = get_done_listener(p, vp); + ff_cond_signal(&p->cond); + } ff_mutex_unlock(&p->lock); while (l) { diff --git a/libavcodec/vvc/vvc_refs.h b/libavcodec/vvc/refs.h similarity index 94% rename from libavcodec/vvc/vvc_refs.h rename to libavcodec/vvc/refs.h index eba4422fb..8ae33d4a9 100644 --- a/libavcodec/vvc/vvc_refs.h +++ b/libavcodec/vvc/refs.h @@ -20,10 +20,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVC_REFS_H -#define AVCODEC_VVC_VVC_REFS_H +#ifndef AVCODEC_VVC_REFS_H +#define AVCODEC_VVC_REFS_H -#include "vvcdec.h" +#include "dec.h" 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); @@ -55,4 +55,4 @@ void ff_vvc_report_frame_finished(VVCFrame *frame); void ff_vvc_report_progress(VVCFrame *frame, VVCProgress vp, int y); void ff_vvc_add_progress_listener(VVCFrame *frame, VVCProgressListener *l); -#endif // AVCODEC_VVC_VVC_REFS_H +#endif // AVCODEC_VVC_REFS_H diff --git a/libavcodec/vvc/vvc_thread.c b/libavcodec/vvc/thread.c similarity index 87% rename from libavcodec/vvc/vvc_thread.c rename to libavcodec/vvc/thread.c index 31c931f05..86a7753c6 100644 --- a/libavcodec/vvc/vvc_thread.c +++ b/libavcodec/vvc/thread.c @@ -23,14 +23,15 @@ #include #include "libavutil/executor.h" +#include "libavutil/mem.h" #include "libavutil/thread.h" -#include "vvc_thread.h" -#include "vvc_ctu.h" -#include "vvc_filter.h" -#include "vvc_inter.h" -#include "vvc_intra.h" -#include "vvc_refs.h" +#include "thread.h" +#include "ctu.h" +#include "filter.h" +#include "inter.h" +#include "intra.h" +#include "refs.h" typedef struct ProgressListener { VVCProgressListener l; @@ -39,6 +40,7 @@ typedef struct ProgressListener { } ProgressListener; typedef enum VVCTaskStage { + VVC_TASK_STAGE_INIT, // for CTU(0, 0) only VVC_TASK_STAGE_PARSE, VVC_TASK_STAGE_INTER, VVC_TASK_STAGE_RECON, @@ -123,11 +125,17 @@ static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const atomic_store(&t->target_inter_score, 0); } -static void task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx) +static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx) { + if (t->sc) { + // the task already inited, error bitstream + return AVERROR_INVALIDDATA; + } t->sc = sc; t->ep = ep; t->ctu_idx = ctu_idx; + + return 0; } static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage) @@ -168,10 +176,14 @@ static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uin uint8_t target = 0; VVCFrameContext *fc = t->fc; + if (stage == VVC_TASK_STAGE_INIT) + return 1; + if (stage == VVC_TASK_STAGE_PARSE) { - const H266RawSPS *rsps = fc->ps.sps->r; - const int wpp = rsps->sps_entropy_coding_sync_enabled_flag && !is_first_row(fc, t->rx, t->ry); - target = 2 + wpp - 1; //left parse + colocation + wpp - no previous stage + const H266RawSPS *rsps = fc->ps.sps->r; + const int wpp = rsps->sps_entropy_coding_sync_enabled_flag && !is_first_row(fc, t->rx, t->ry); + const int no_prev_stage = t->rs > 0; + target = 2 + wpp - no_prev_stage; //left parse + colocation + wpp - no_prev_stage } else if (stage == VVC_TASK_STAGE_INTER) { target = atomic_load(&t->target_inter_score); } else { @@ -286,10 +298,14 @@ static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContex CTU *ctu = fc->tab.ctus + rs; for (int lx = 0; lx < 2; lx++) { for (int i = 0; i < sh->r->num_ref_idx_active[lx]; i++) { - const int y = ctu->max_y[lx][i]; - VVCFrame *ref = sc->rpl[lx].ref[i]; - if (ref && y >= 0) + int y = ctu->max_y[lx][i]; + VVCRefPic *refp = sc->rpl[lx].refs + i; + VVCFrame *ref = refp->ref; + if (ref && y >= 0) { + if (refp->is_scaled) + y = y * refp->scale[1] >> 14; add_progress_listener(ref, &t->listener[lx][i], t, s, VVC_PROGRESS_PIXEL, y + LUMA_EXTRA_AFTER); + } } } } @@ -374,19 +390,69 @@ static int task_priority_higher(const AVTask *_a, const AVTask *_b) const VVCTask *a = (const VVCTask*)_a; const VVCTask *b = (const VVCTask*)_b; - CHECK(a->fc->decode_order, b->fc->decode_order); //decode order - if (a->stage == VVC_TASK_STAGE_PARSE || b->stage == VVC_TASK_STAGE_PARSE) { + 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; + + if (fc->ps.ph.r->ph_temporal_mvp_enabled_flag || fc->ps.sps->r->sps_sbtmvp_enabled_flag) { + VVCFrame *col = fc->ref->collocated_ref; + const int first_col = t->rx == fc->ps.pps->ctb_to_col_bd[t->rx]; + if (col && first_col) { + //we depend on bottom and right boundary, do not - 1 for y + const int y = (t->ry << fc->ps.sps->ctb_log2_size_y); + add_progress_listener(col, &t->col_listener, t, s, VVC_PROGRESS_MV, y); + return; + } + } + frame_thread_add_score(s, fc->ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE); +} + +static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep) +{ + const int rs = sc->sh.ctb_addr_in_curr_slice[ep->ctu_start]; + VVCTask *t = ft->tasks + rs; + + frame_thread_add_score(s, ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE); +} + +static int run_init(VVCContext *s, VVCLocalContext *lc, VVCTask *t) +{ + VVCFrameContext *fc = lc->fc; + VVCFrameThread *ft = fc->ft; + const int ret = ff_vvc_per_frame_init(fc); + + if (ret < 0) + return ret; + + for (int i = 0; i < fc->nb_slices; i++) { + SliceContext *sc = fc->slices[i]; + for (int j = 0; j < sc->nb_eps; j++) { + EntryPoint *ep = sc->eps + j; + for (int k = ep->ctu_start; k < ep->ctu_end; k++) { + const int rs = sc->sh.ctb_addr_in_curr_slice[k]; + VVCTask *t = ft->tasks + rs; + check_colocation(s, t); + } + submit_entry_point(s, ft, sc, ep); + } + } + return 0; +} + static void report_frame_progress(VVCFrameContext *fc, const int ry, const VVCProgress idx) { @@ -400,12 +466,16 @@ static void report_frame_progress(VVCFrameContext *fc, y = old = ft->row_progress[idx]; while (y < ft->ctu_height && atomic_load(&ft->rows[y].col_progress[idx]) == ft->ctu_width) y++; + if (old != y) + ft->row_progress[idx] = y; + // ff_vvc_report_progress will acquire other frames' locks, which could lead to a deadlock + // We need to unlock ft->lock first + ff_mutex_unlock(&ft->lock); + if (old != y) { const int progress = y == ft->ctu_height ? INT_MAX : y * ctu_size; - ft->row_progress[idx] = y; ff_vvc_report_progress(fc->ref, idx, progress); } - ff_mutex_unlock(&ft->lock); } } @@ -416,7 +486,6 @@ static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t) const int rs = t->rs; const CTU *ctu = fc->tab.ctus + rs; - lc->sc = t->sc; lc->ep = t->ep; ret = ff_vvc_coding_tree_unit(lc, t->ctu_idx, rs, t->rx, t->ry); @@ -432,15 +501,12 @@ static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t) static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t) { VVCFrameContext *fc = lc->fc; - VVCFrameThread *ft = fc->ft; - const int rs = t->ry * ft->ctu_width + t->rx; - const CTU *ctu = fc->tab.ctus + rs; - const int slice_idx = fc->tab.slice_idx[rs]; + const CTU *ctu = fc->tab.ctus + t->rs; + int ret; - if (slice_idx != -1) { - lc->sc = fc->slices[slice_idx]; - ff_vvc_predict_inter(lc, rs); - } + ret = ff_vvc_predict_inter(lc, t->rs); + if (ret < 0) + return ret; if (ctu->has_dmvr) report_frame_progress(fc, t->ry, VVC_PROGRESS_MV); @@ -450,16 +516,7 @@ static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t) static int run_recon(VVCContext *s, VVCLocalContext *lc, VVCTask *t) { - VVCFrameContext *fc = lc->fc; - const int rs = t->rs; - const int slice_idx = fc->tab.slice_idx[rs]; - - if (slice_idx != -1) { - lc->sc = fc->slices[slice_idx]; - ff_vvc_reconstruct(lc, rs, t->rx, t->ry); - } - - return 0; + return ff_vvc_reconstruct(lc, t->rs, t->rx, t->ry); } static int run_lmcs(VVCContext *s, VVCLocalContext *lc, VVCTask *t) @@ -469,13 +526,8 @@ static int run_lmcs(VVCContext *s, VVCLocalContext *lc, VVCTask *t) const int ctu_size = ft->ctu_size; const int x0 = t->rx * ctu_size; const int y0 = t->ry * ctu_size; - const int rs = t->ry * ft->ctu_width + t->rx; - const int slice_idx = fc->tab.slice_idx[rs]; - if (slice_idx != -1) { - lc->sc = fc->slices[slice_idx]; - ff_vvc_lmcs_filter(lc, x0, y0); - } + ff_vvc_lmcs_filter(lc, x0, y0); return 0; } @@ -484,18 +536,13 @@ static int run_deblock_v(VVCContext *s, VVCLocalContext *lc, VVCTask *t) { VVCFrameContext *fc = lc->fc; VVCFrameThread *ft = fc->ft; - const int rs = t->ry * ft->ctu_width + t->rx; const int ctb_size = ft->ctu_size; const int x0 = t->rx * ctb_size; const int y0 = t->ry * ctb_size; - const int slice_idx = fc->tab.slice_idx[rs]; - if (slice_idx != -1) { - lc->sc = fc->slices[slice_idx]; - if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) { - ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, rs); - ff_vvc_deblock_vertical(lc, x0, y0); - } + if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) { + ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs); + ff_vvc_deblock_vertical(lc, x0, y0, t->rs); } return 0; @@ -506,20 +553,15 @@ static int run_deblock_h(VVCContext *s, VVCLocalContext *lc, VVCTask *t) VVCFrameContext *fc = lc->fc; VVCFrameThread *ft = fc->ft; const int ctb_size = ft->ctu_size; - const int rs = t->ry * ft->ctu_width + t->rx; const int x0 = t->rx * ctb_size; const int y0 = t->ry * ctb_size; - const int slice_idx = fc->tab.slice_idx[rs]; - if (slice_idx != -1) { - lc->sc = fc->slices[slice_idx]; - if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) { - ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, rs); - ff_vvc_deblock_horizontal(lc, x0, y0); - } - if (fc->ps.sps->r->sps_sao_enabled_flag) - ff_vvc_sao_copy_ctb_to_hv(lc, t->rx, t->ry, t->ry == ft->ctu_height - 1); + if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) { + ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs); + ff_vvc_deblock_horizontal(lc, x0, y0, t->rs); } + if (fc->ps.sps->r->sps_sao_enabled_flag) + ff_vvc_sao_copy_ctb_to_hv(lc, t->rx, t->ry, t->ry == ft->ctu_height - 1); return 0; } @@ -528,13 +570,12 @@ static int run_sao(VVCContext *s, VVCLocalContext *lc, VVCTask *t) { VVCFrameContext *fc = lc->fc; VVCFrameThread *ft = fc->ft; - const int rs = t->ry * fc->ps.pps->ctb_width + t->rx; const int ctb_size = ft->ctu_size; const int x0 = t->rx * ctb_size; const int y0 = t->ry * ctb_size; if (fc->ps.sps->r->sps_sao_enabled_flag) { - ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, rs); + ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs); ff_vvc_sao_filter(lc, x0, y0); } @@ -553,12 +594,8 @@ static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t) const int y0 = t->ry * ctu_size; if (fc->ps.sps->r->sps_alf_enabled_flag) { - const int slice_idx = CTB(fc->tab.slice_idx, t->rx, t->ry); - if (slice_idx != -1) { - lc->sc = fc->slices[slice_idx]; - ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs); - ff_vvc_alf_filter(lc, x0, y0); - } + ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs); + ff_vvc_alf_filter(lc, x0, y0); } report_frame_progress(fc, t->ry, VVC_PROGRESS_PIXEL); @@ -568,6 +605,7 @@ static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t) #define VVC_THREAD_DEBUG #ifdef VVC_THREAD_DEBUG const static char* task_name[] = { + "INIT", "P", "I", "R", @@ -587,7 +625,8 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) VVCFrameContext *fc = t->fc; VVCFrameThread *ft = fc->ft; const VVCTaskStage stage = t->stage; - run_func run[] = { + static const run_func run[] = { + run_init, run_parse, run_inter, run_recon, @@ -602,6 +641,8 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) 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 + lc->sc = t->sc; + if (!atomic_load(&ft->ret)) { if ((ret = run[stage](s, lc, t)) < 0) { #ifdef COMPAT_ATOMICS_WIN32_STDATOMIC_H @@ -745,7 +786,7 @@ int ff_vvc_frame_thread_init(VVCFrameContext *fc) for (int rs = 0; rs < ft->ctu_count; rs++) { VVCTask *t = ft->tasks + rs; - task_init(t, VVC_TASK_STAGE_PARSE, fc, rs % ft->ctu_width, rs / ft->ctu_width); + task_init(t, rs ? VVC_TASK_STAGE_PARSE : VVC_TASK_STAGE_INIT, fc, rs % ft->ctu_width, rs / ft->ctu_width); } memset(&ft->row_progress[0], 0, sizeof(ft->row_progress)); @@ -764,32 +805,7 @@ fail: return AVERROR(ENOMEM); } -static void check_colocation(VVCContext *s, VVCTask *t) -{ - const VVCFrameContext *fc = t->fc; - - if (fc->ps.ph.r->ph_temporal_mvp_enabled_flag || fc->ps.sps->r->sps_sbtmvp_enabled_flag) { - VVCFrame *col = fc->ref->collocated_ref; - const int first_col = t->rx == fc->ps.pps->ctb_to_col_bd[t->rx]; - if (col && first_col) { - //we depend on bottom and right boundary, do not - 1 for y - const int y = (t->ry << fc->ps.sps->ctb_log2_size_y); - add_progress_listener(col, &t->col_listener, t, s, VVC_PROGRESS_MV, y); - return; - } - } - frame_thread_add_score(s, fc->ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE); -} - -static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep) -{ - const int rs = sc->sh.ctb_addr_in_curr_slice[ep->ctu_start]; - VVCTask *t = ft->tasks + rs; - - frame_thread_add_score(s, ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE); -} - -void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) +int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) { VVCFrameThread *ft = fc->ft; @@ -800,13 +816,15 @@ void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc) for (int k = ep->ctu_start; k < ep->ctu_end; k++) { const int rs = sc->sh.ctb_addr_in_curr_slice[k]; VVCTask *t = ft->tasks + rs; - - task_init_parse(t, sc, ep, k); - check_colocation(s, t); + const int ret = task_init_parse(t, sc, ep, k); + if (ret < 0) + return ret; } - submit_entry_point(s, ft, sc, ep); } } + frame_thread_add_score(s, ft, 0, 0, VVC_TASK_STAGE_INIT); + + return 0; } int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc) diff --git a/libavcodec/vvc/vvc_thread.h b/libavcodec/vvc/thread.h similarity index 83% rename from libavcodec/vvc/vvc_thread.h rename to libavcodec/vvc/thread.h index 6c726744f..7b15dbee5 100644 --- a/libavcodec/vvc/vvc_thread.h +++ b/libavcodec/vvc/thread.h @@ -20,17 +20,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VVC_VVC_THREAD_H -#define AVCODEC_VVC_VVC_THREAD_H +#ifndef AVCODEC_VVC_THREAD_H +#define AVCODEC_VVC_THREAD_H -#include "vvcdec.h" +#include "dec.h" struct AVExecutor* ff_vvc_executor_alloc(VVCContext *s, int thread_count); void ff_vvc_executor_free(struct AVExecutor **e); int ff_vvc_frame_thread_init(VVCFrameContext *fc); void ff_vvc_frame_thread_free(VVCFrameContext *fc); -void ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc); +int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc); int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc); +int ff_vvc_per_frame_init(VVCFrameContext *fc); -#endif // AVCODEC_VVC_VVC_THREAD_H +#endif // AVCODEC_VVC_THREAD_H diff --git a/libavcodec/vvc/vvc_inter.c b/libavcodec/vvc/vvc_inter.c deleted file mode 100644 index c5629f7f6..000000000 --- a/libavcodec/vvc/vvc_inter.c +++ /dev/null @@ -1,926 +0,0 @@ -/* - * VVC inter prediction - * - * Copyright (C) 2022 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 "libavutil/frame.h" - -#include "vvc_data.h" -#include "vvc_inter.h" -#include "vvc_mvs.h" -#include "vvc_refs.h" - -// +1 is enough, + 32 for asm alignment -#define PROF_TEMP_OFFSET (MAX_PB_SIZE + 32) -static const int bcw_w_lut[] = {4, 5, 3, 10, -2}; - -static int emulated_edge(const VVCFrameContext *fc, uint8_t *dst, const uint8_t **src, ptrdiff_t *src_stride, - const int x_off, const int y_off, const int block_w, const int block_h, const int is_luma) -{ - const int extra_before = is_luma ? LUMA_EXTRA_BEFORE : CHROMA_EXTRA_BEFORE; - const int extra_after = is_luma ? LUMA_EXTRA_AFTER : CHROMA_EXTRA_AFTER; - const int extra = is_luma ? LUMA_EXTRA : CHROMA_EXTRA; - const int pic_width = is_luma ? fc->ps.pps->width : (fc->ps.pps->width >> fc->ps.sps->hshift[1]); - const int pic_height = is_luma ? fc->ps.pps->height : (fc->ps.pps->height >> fc->ps.sps->vshift[1]); - - if (x_off < extra_before || y_off < extra_before || - x_off >= pic_width - block_w - extra_after || - y_off >= pic_height - block_h - extra_after) { - const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << fc->ps.sps->pixel_shift; - int offset = extra_before * *src_stride + (extra_before << fc->ps.sps->pixel_shift); - int buf_offset = extra_before * edge_emu_stride + (extra_before << fc->ps.sps->pixel_shift); - - fc->vdsp.emulated_edge_mc(dst, *src - offset, edge_emu_stride, *src_stride, - block_w + extra, block_h + extra, x_off - extra_before, y_off - extra_before, - pic_width, pic_height); - - *src = dst + buf_offset; - *src_stride = edge_emu_stride; - return 1; - } - return 0; -} - -static void emulated_edge_dmvr(const VVCFrameContext *fc, uint8_t *dst, const uint8_t **src, ptrdiff_t *src_stride, - const int x_sb, const int y_sb, const int x_off, const int y_off, const int block_w, const int block_h, const int is_luma) -{ - const int extra_before = is_luma ? LUMA_EXTRA_BEFORE : CHROMA_EXTRA_BEFORE; - const int extra_after = is_luma ? LUMA_EXTRA_AFTER : CHROMA_EXTRA_AFTER; - const int extra = is_luma ? LUMA_EXTRA : CHROMA_EXTRA; - const int pic_width = is_luma ? fc->ps.pps->width : (fc->ps.pps->width >> fc->ps.sps->hshift[1]); - const int pic_height = is_luma ? fc->ps.pps->height : (fc->ps.pps->height >> fc->ps.sps->vshift[1]); - - if (x_off < extra_before || y_off < extra_before || - x_off >= pic_width - block_w - extra_after || - y_off >= pic_height - block_h - extra_after|| - (x_off != x_sb || y_off != y_sb)) { - const int ps = fc->ps.sps->pixel_shift; - const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << ps; - const int offset = extra_before * *src_stride + (extra_before << ps); - const int buf_offset = extra_before * edge_emu_stride + (extra_before << ps); - - const int start_x = FFMIN(FFMAX(x_sb - extra_before, 0), pic_width - 1); - const int start_y = FFMIN(FFMAX(y_sb - extra_before, 0), pic_height - 1); - const int width = FFMAX(FFMIN(pic_width, x_sb + block_w + extra_after) - start_x, 1); - const int height = FFMAX(FFMIN(pic_height, y_sb + block_h + extra_after) - start_y, 1); - - fc->vdsp.emulated_edge_mc(dst, *src - offset, edge_emu_stride, *src_stride, block_w + extra, block_h + extra, - x_off - start_x - extra_before, y_off - start_y - extra_before, width, height); - - *src = dst + buf_offset; - *src_stride = edge_emu_stride; - } -} - -static void emulated_edge_bilinear(const VVCFrameContext *fc, uint8_t *dst, const uint8_t **src, ptrdiff_t *src_stride, - const int x_off, const int y_off, const int block_w, const int block_h) -{ - int pic_width = fc->ps.pps->width; - int pic_height = fc->ps.pps->height; - - if (x_off < BILINEAR_EXTRA_BEFORE || y_off < BILINEAR_EXTRA_BEFORE || - x_off >= pic_width - block_w - BILINEAR_EXTRA_AFTER || - y_off >= pic_height - block_h - BILINEAR_EXTRA_AFTER) { - const ptrdiff_t edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << fc->ps.sps->pixel_shift; - const int offset = BILINEAR_EXTRA_BEFORE * *src_stride + (BILINEAR_EXTRA_BEFORE << fc->ps.sps->pixel_shift); - const int buf_offset = BILINEAR_EXTRA_BEFORE * edge_emu_stride + (BILINEAR_EXTRA_BEFORE << fc->ps.sps->pixel_shift); - - fc->vdsp.emulated_edge_mc(dst, *src - offset, edge_emu_stride, *src_stride, block_w + BILINEAR_EXTRA, block_h + BILINEAR_EXTRA, - x_off - BILINEAR_EXTRA_BEFORE, y_off - BILINEAR_EXTRA_BEFORE, pic_width, pic_height); - - *src = dst + buf_offset; - *src_stride = edge_emu_stride; - } -} - - -#define EMULATED_EDGE_LUMA(dst, src, src_stride, x_off, y_off) \ - emulated_edge(fc, dst, src, src_stride, x_off, y_off, block_w, block_h, 1) - -#define EMULATED_EDGE_CHROMA(dst, src, src_stride, x_off, y_off) \ - emulated_edge(fc, dst, src, src_stride, x_off, y_off, block_w, block_h, 0) - -#define EMULATED_EDGE_DMVR_LUMA(dst, src, src_stride, x_sb, y_sb, x_off, y_off) \ - emulated_edge_dmvr(fc, dst, src, src_stride, x_sb, y_sb, x_off, y_off, block_w, block_h, 1) - -#define EMULATED_EDGE_DMVR_CHROMA(dst, src, src_stride, x_sb, y_sb, x_off, y_off) \ - emulated_edge_dmvr(fc, dst, src, src_stride, x_sb, y_sb, x_off, y_off, block_w, block_h, 0) - -#define EMULATED_EDGE_BILINEAR(dst, src, src_stride, x_off, y_off) \ - emulated_edge_bilinear(fc, dst, src, src_stride, x_off, y_off, pred_w, pred_h) - -// part of 8.5.6.6 Weighted sample prediction process -static int derive_weight_uni(int *denom, int *wx, int *ox, - const VVCLocalContext *lc, const MvField *mvf, const int c_idx) -{ - const VVCFrameContext *fc = lc->fc; - const VVCPPS *pps = fc->ps.pps; - const VVCSH *sh = &lc->sc->sh; - const int weight_flag = (IS_P(sh->r) && pps->r->pps_weighted_pred_flag) || - (IS_B(sh->r) && pps->r->pps_weighted_bipred_flag); - if (weight_flag) { - const int lx = mvf->pred_flag - PF_L0; - const PredWeightTable *w = pps->r->pps_wp_info_in_ph_flag ? &fc->ps.ph.pwt : &sh->pwt; - - *denom = w->log2_denom[c_idx > 0]; - *wx = w->weight[lx][c_idx][mvf->ref_idx[lx]]; - *ox = w->offset[lx][c_idx][mvf->ref_idx[lx]]; - } - return weight_flag; -} - -// 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) -{ - 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; - - if (bcw_idx) { - *denom = 2; - *w1 = bcw_w_lut[bcw_idx]; - *w0 = 8 - *w1; - *o0 = *o1 = 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]]; - } - return 1; -} - -static void luma_mc(VVCLocalContext *lc, int16_t *dst, const AVFrame *ref, const Mv *mv, - int x_off, int y_off, const int block_w, const int block_h) -{ - const VVCFrameContext *fc = lc->fc; - const uint8_t *src = ref->data[0]; - ptrdiff_t src_stride = ref->linesize[0]; - const int idx = av_log2(block_w) - 1; - const int mx = mv->x & 0xf; - const int my = mv->y & 0xf; - const int8_t *hf = ff_vvc_inter_luma_filters[0][mx]; - const int8_t *vf = ff_vvc_inter_luma_filters[0][my]; - - x_off += mv->x >> 4; - y_off += mv->y >> 4; - src += y_off * src_stride + (x_off * (1 << fc->ps.sps->pixel_shift)); - - EMULATED_EDGE_LUMA(lc->edge_emu_buffer, &src, &src_stride, x_off, y_off); - - fc->vvcdsp.inter.put[LUMA][idx][!!my][!!mx](dst, src, src_stride, block_h, hf, vf, block_w); -} - -static void chroma_mc(VVCLocalContext *lc, int16_t *dst, const AVFrame *ref, const Mv *mv, - int x_off, int y_off, const int block_w, const int block_h, const int c_idx) -{ - const VVCFrameContext *fc = lc->fc; - const uint8_t *src = ref->data[c_idx]; - ptrdiff_t src_stride = ref->linesize[c_idx]; - int hs = fc->ps.sps->hshift[c_idx]; - int vs = fc->ps.sps->vshift[c_idx]; - const int idx = av_log2(block_w) - 1; - const intptr_t mx = av_mod_uintp2(mv->x, 4 + hs) << (1 - hs); - const intptr_t my = av_mod_uintp2(mv->y, 4 + vs) << (1 - vs); - const int8_t *hf = ff_vvc_inter_chroma_filters[0][mx]; - const int8_t *vf = ff_vvc_inter_chroma_filters[0][my]; - - x_off += mv->x >> (4 + hs); - y_off += mv->y >> (4 + vs); - src += y_off * src_stride + (x_off * (1 << fc->ps.sps->pixel_shift)); - - EMULATED_EDGE_CHROMA(lc->edge_emu_buffer, &src, &src_stride, x_off, y_off); - fc->vvcdsp.inter.put[CHROMA][idx][!!my][!!mx](dst, src, src_stride, block_h, hf, vf, block_w); -} - -static void luma_mc_uni(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, - const AVFrame *ref, const MvField *mvf, int x_off, int y_off, const int block_w, const int block_h, - const int hf_idx, const int vf_idx) -{ - const VVCFrameContext *fc = lc->fc; - const int lx = mvf->pred_flag - PF_L0; - const Mv *mv = mvf->mv + lx; - const uint8_t *src = ref->data[0]; - ptrdiff_t src_stride = ref->linesize[0]; - const int idx = av_log2(block_w) - 1; - const int mx = mv->x & 0xf; - const int my = mv->y & 0xf; - const int8_t *hf = ff_vvc_inter_luma_filters[hf_idx][mx]; - const int8_t *vf = ff_vvc_inter_luma_filters[vf_idx][my]; - int denom, wx, ox; - - x_off += mv->x >> 4; - y_off += mv->y >> 4; - src += y_off * src_stride + (x_off * (1 << fc->ps.sps->pixel_shift)); - - EMULATED_EDGE_LUMA(lc->edge_emu_buffer, &src, &src_stride, x_off, y_off); - - if (derive_weight_uni(&denom, &wx, &ox, lc, mvf, LUMA)) { - fc->vvcdsp.inter.put_uni_w[LUMA][idx][!!my][!!mx](dst, dst_stride, src, src_stride, - block_h, denom, wx, ox, hf, vf, block_w); - } else { - fc->vvcdsp.inter.put_uni[LUMA][idx][!!my][!!mx](dst, dst_stride, src, src_stride, - block_h, hf, vf, block_w); - } -} - -static void luma_mc_bi(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, - const AVFrame *ref0, const Mv *mv0, const int x_off, const int y_off, const int block_w, const int block_h, - const AVFrame *ref1, const Mv *mv1, const MvField *mvf, const int hf_idx, const int vf_idx, - const MvField *orig_mv, const int sb_bdof_flag) -{ - const VVCFrameContext *fc = lc->fc; - const PredictionUnit *pu = &lc->cu->pu; - const int idx = av_log2(block_w) - 1; - const AVFrame *ref[] = { 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, LUMA, pu->dmvr_flag); - - for (int i = L0; i <= L1; i++) { - const Mv *mv = mvf->mv + i; - const int mx = mv->x & 0xf; - const int my = mv->y & 0xf; - const int ox = x_off + (mv->x >> 4); - const int oy = y_off + (mv->y >> 4); - ptrdiff_t src_stride = ref[i]->linesize[0]; - const uint8_t *src = ref[i]->data[0] + oy * src_stride + (ox * (1 << fc->ps.sps->pixel_shift)); - const int8_t *hf = ff_vvc_inter_luma_filters[hf_idx][mx]; - const int8_t *vf = ff_vvc_inter_luma_filters[vf_idx][my]; - - if (pu->dmvr_flag) { - const int x_sb = x_off + (orig_mv->mv[i].x >> 4); - const int y_sb = y_off + (orig_mv->mv[i].y >> 4); - - EMULATED_EDGE_DMVR_LUMA(lc->edge_emu_buffer, &src, &src_stride, x_sb, y_sb, ox, oy); - } else { - EMULATED_EDGE_LUMA(lc->edge_emu_buffer, &src, &src_stride, ox, oy); - } - fc->vvcdsp.inter.put[LUMA][idx][!!my][!!mx](tmp[i], src, src_stride, block_h, hf, vf, block_w); - if (sb_bdof_flag) - fc->vvcdsp.inter.bdof_fetch_samples(tmp[i], src, src_stride, mx, my, block_w, block_h); - } - - 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); -} - -static void chroma_mc_uni(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, - const uint8_t *src, ptrdiff_t src_stride, int x_off, int y_off, - const int block_w, const int block_h, const MvField *mvf, const int c_idx, - const int hf_idx, const int vf_idx) -{ - const VVCFrameContext *fc = lc->fc; - const int lx = mvf->pred_flag - PF_L0; - const int hs = fc->ps.sps->hshift[1]; - const int vs = fc->ps.sps->vshift[1]; - const int idx = av_log2(block_w) - 1; - const Mv *mv = &mvf->mv[lx]; - const intptr_t mx = av_mod_uintp2(mv->x, 4 + hs) << (1 - hs); - const intptr_t my = av_mod_uintp2(mv->y, 4 + vs) << (1 - vs); - const int8_t *hf = ff_vvc_inter_chroma_filters[hf_idx][mx]; - const int8_t *vf = ff_vvc_inter_chroma_filters[vf_idx][my]; - int denom, wx, ox; - - x_off += mv->x >> (4 + hs); - y_off += mv->y >> (4 + vs); - src += y_off * src_stride + (x_off * (1 << fc->ps.sps->pixel_shift)); - - - EMULATED_EDGE_CHROMA(lc->edge_emu_buffer, &src, &src_stride, x_off, y_off); - if (derive_weight_uni(&denom, &wx, &ox, lc, mvf, c_idx)) { - fc->vvcdsp.inter.put_uni_w[CHROMA][idx][!!my][!!mx](dst, dst_stride, src, src_stride, - block_h, denom, wx, ox, hf, vf, block_w); - } else { - fc->vvcdsp.inter.put_uni[CHROMA][idx][!!my][!!mx](dst, dst_stride, src, src_stride, - block_h, hf, vf, block_w); - } -} - -static void chroma_mc_bi(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, - const AVFrame *ref0, const AVFrame *ref1, const int x_off, const int y_off, - const int block_w, const int block_h, const MvField *mvf, const int c_idx, - const int hf_idx, const int vf_idx, const MvField *orig_mv, const int dmvr_flag, const int ciip_flag) -{ - const VVCFrameContext *fc = lc->fc; - const int hs = fc->ps.sps->hshift[1]; - const int vs = fc->ps.sps->vshift[1]; - const int idx = av_log2(block_w) - 1; - const AVFrame *ref[] = { 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, c_idx, dmvr_flag); - - for (int i = L0; i <= L1; i++) { - const Mv *mv = mvf->mv + i; - const int mx = av_mod_uintp2(mv->x, 4 + hs) << (1 - hs); - const int my = av_mod_uintp2(mv->y, 4 + vs) << (1 - vs); - const int ox = x_off + (mv->x >> (4 + hs)); - const int oy = y_off + (mv->y >> (4 + vs)); - ptrdiff_t src_stride = ref[i]->linesize[c_idx]; - const uint8_t *src = ref[i]->data[c_idx] + oy * src_stride + (ox * (1 << fc->ps.sps->pixel_shift)); - const int8_t *hf = ff_vvc_inter_chroma_filters[hf_idx][mx]; - const int8_t *vf = ff_vvc_inter_chroma_filters[vf_idx][my]; - if (dmvr_flag) { - const int x_sb = x_off + (orig_mv->mv[i].x >> (4 + hs)); - const int y_sb = y_off + (orig_mv->mv[i].y >> (4 + vs)); - EMULATED_EDGE_DMVR_CHROMA(lc->edge_emu_buffer, &src, &src_stride, x_sb, y_sb, ox, oy); - } else { - EMULATED_EDGE_CHROMA(lc->edge_emu_buffer, &src, &src_stride, ox, oy); - } - fc->vvcdsp.inter.put[CHROMA][idx][!!my][!!mx](tmp[i], src, src_stride, block_h, hf, vf, block_w); - } - 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); -} - -static void luma_prof_uni(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, - const AVFrame *ref, const MvField *mvf, int x_off, int y_off, const int block_w, const int block_h, - const int cb_prof_flag, const int16_t *diff_mv_x, const int16_t *diff_mv_y) -{ - const VVCFrameContext *fc = lc->fc; - const uint8_t *src = ref->data[0]; - ptrdiff_t src_stride = ref->linesize[0]; - uint16_t *prof_tmp = lc->tmp + PROF_TEMP_OFFSET; - const int idx = av_log2(block_w) - 1; - const int lx = mvf->pred_flag - PF_L0; - const Mv *mv = mvf->mv + lx; - const int mx = mv->x & 0xf; - const int my = mv->y & 0xf; - const int8_t *hf = ff_vvc_inter_luma_filters[2][mx]; - const int8_t *vf = ff_vvc_inter_luma_filters[2][my]; - int denom, wx, ox; - const int weight_flag = derive_weight_uni(&denom, &wx, &ox, lc, mvf, LUMA); - - x_off += mv->x >> 4; - y_off += mv->y >> 4; - src += y_off * src_stride + (x_off * (1 << fc->ps.sps->pixel_shift)); - - EMULATED_EDGE_LUMA(lc->edge_emu_buffer, &src, &src_stride, x_off, y_off); - if (cb_prof_flag) { - fc->vvcdsp.inter.put[LUMA][idx][!!my][!!mx](prof_tmp, src, src_stride, AFFINE_MIN_BLOCK_SIZE, hf, vf, AFFINE_MIN_BLOCK_SIZE); - fc->vvcdsp.inter.fetch_samples(prof_tmp, src, src_stride, mx, my); - if (!weight_flag) - fc->vvcdsp.inter.apply_prof_uni(dst, dst_stride, prof_tmp, diff_mv_x, diff_mv_y); - else - fc->vvcdsp.inter.apply_prof_uni_w(dst, dst_stride, prof_tmp, diff_mv_x, diff_mv_y, denom, wx, ox); - } else { - if (!weight_flag) - fc->vvcdsp.inter.put_uni[LUMA][idx][!!my][!!mx](dst, dst_stride, src, src_stride, block_h, hf, vf, block_w); - else - fc->vvcdsp.inter.put_uni_w[LUMA][idx][!!my][!!mx](dst, dst_stride, src, src_stride, block_h, denom, wx, ox, hf, vf, block_w); - } -} - -static void luma_prof_bi(VVCLocalContext *lc, uint8_t *dst, const ptrdiff_t dst_stride, - const AVFrame *ref0, const AVFrame *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 PredictionUnit *pu = &lc->cu->pu; - const AVFrame *ref[] = { ref0, ref1 }; - int16_t *tmp[] = { lc->tmp, lc->tmp1 }; - uint16_t *prof_tmp = lc->tmp2 + PROF_TEMP_OFFSET; - const int idx = av_log2(block_w) - 1; - 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 Mv *mv = mvf->mv + i; - const int mx = mv->x & 0xf; - const int my = mv->y & 0xf; - const int ox = x_off + (mv->x >> 4); - const int oy = y_off + (mv->y >> 4); - ptrdiff_t src_stride = ref[i]->linesize[0]; - const uint8_t *src = ref[i]->data[0] + oy * src_stride + (ox * (1 << fc->ps.sps->pixel_shift)); - const int8_t *hf = ff_vvc_inter_luma_filters[2][mx]; - const int8_t *vf = ff_vvc_inter_luma_filters[2][my]; - - EMULATED_EDGE_LUMA(lc->edge_emu_buffer, &src, &src_stride, ox, oy); - if (!pu->cb_prof_flag[i]) { - fc->vvcdsp.inter.put[LUMA][idx][!!my][!!mx](tmp[i], src, src_stride, block_h, hf, vf, block_w); - } else { - fc->vvcdsp.inter.put[LUMA][idx][!!my][!!mx](prof_tmp, src, src_stride, AFFINE_MIN_BLOCK_SIZE, hf, vf, AFFINE_MIN_BLOCK_SIZE); - fc->vvcdsp.inter.fetch_samples(prof_tmp, src, src_stride, mx, my); - fc->vvcdsp.inter.apply_prof(tmp[i], prof_tmp, pu->diff_mv_x[i], pu->diff_mv_y[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); -} - -static int pred_get_refs(const VVCLocalContext *lc, VVCFrame *ref[2], const MvField *mv) -{ - const RefPicList *rpl = lc->sc->rpl; - - for (int mask = PF_L0; mask <= PF_L1; mask++) { - if (mv->pred_flag & mask) { - const int lx = mask - PF_L0; - ref[lx] = rpl[lx].ref[mv->ref_idx[lx]]; - if (!ref[lx]) - return AVERROR_INVALIDDATA; - } - } - 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)] - -static void pred_gpm_blk(VVCLocalContext *lc) -{ - const VVCFrameContext *fc = lc->fc; - const CodingUnit *cu = lc->cu; - const PredictionUnit *pu = &cu->pu; - - const uint8_t angle_idx = ff_vvc_gpm_angle_idx[pu->gpm_partition_idx]; - const uint8_t weights_idx = ff_vvc_gpm_angle_to_weights_idx[angle_idx]; - const int w = av_log2(cu->cb_width) - 3; - const int h = av_log2(cu->cb_height) - 3; - const uint8_t off_x = ff_vvc_gpm_weights_offset_x[pu->gpm_partition_idx][h][w]; - const uint8_t off_y = ff_vvc_gpm_weights_offset_y[pu->gpm_partition_idx][h][w]; - const uint8_t mirror_type = ff_vvc_gpm_angle_to_mirror[angle_idx]; - const uint8_t *weights; - - const int c_end = fc->ps.sps->r->sps_chroma_format_idc ? 3 : 1; - - int16_t *tmp[2] = {lc->tmp, lc->tmp1}; - - for (int c_idx = 0; c_idx < c_end; c_idx++) { - const int hs = fc->ps.sps->hshift[c_idx]; - const int vs = fc->ps.sps->vshift[c_idx]; - const int x = lc->cu->x0 >> hs; - const int y = lc->cu->y0 >> vs; - const int width = cu->cb_width >> hs; - const int height = cu->cb_height >> vs; - uint8_t *dst = POS(c_idx, lc->cu->x0, lc->cu->y0); - ptrdiff_t dst_stride = fc->frame->linesize[c_idx]; - - int step_x = 1 << hs; - int step_y = VVC_GPM_WEIGHT_SIZE << vs; - if (!mirror_type) { - weights = &ff_vvc_gpm_weights[weights_idx][off_y * VVC_GPM_WEIGHT_SIZE + off_x]; - } else if (mirror_type == 1) { - step_x = -step_x; - weights = &ff_vvc_gpm_weights[weights_idx][off_y * VVC_GPM_WEIGHT_SIZE + VVC_GPM_WEIGHT_SIZE - 1- off_x]; - } else { - step_y = -step_y; - weights = &ff_vvc_gpm_weights[weights_idx][(VVC_GPM_WEIGHT_SIZE - 1 - off_y) * VVC_GPM_WEIGHT_SIZE + off_x]; - } - - for (int i = 0; i < 2; i++) { - const MvField *mv = pu->gpm_mv + i; - const int lx = mv->pred_flag - PF_L0; - VVCFrame *ref = lc->sc->rpl[lx].ref[mv->ref_idx[lx]]; - if (!ref) - return; - if (c_idx) - chroma_mc(lc, tmp[i], ref->frame, mv->mv + lx, x, y, width, height, c_idx); - else - luma_mc(lc, tmp[i], ref->frame, mv->mv + lx, x, y, width, height); - } - fc->vvcdsp.inter.put_gpm(dst, dst_stride, width, height, tmp[0], tmp[1], weights, step_x, step_y); - } - return; -} - -static int ciip_derive_intra_weight(const VVCLocalContext *lc, const int x0, const int y0, - const int width, const int height) -{ - const VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const int x0b = av_mod_uintp2(x0, sps->ctb_log2_size_y); - const int y0b = av_mod_uintp2(y0, sps->ctb_log2_size_y); - const int available_l = lc->ctb_left_flag || x0b; - const int available_u = lc->ctb_up_flag || y0b; - const int min_pu_width = fc->ps.pps->min_pu_width; - - int w = 1; - - if (available_u &&fc->tab.mvf[((y0 - 1) >> MIN_PU_LOG2) * min_pu_width + ((x0 - 1 + width)>> MIN_PU_LOG2)].pred_flag == PF_INTRA) - w++; - - if (available_l && fc->tab.mvf[((y0 - 1 + height)>> MIN_PU_LOG2) * min_pu_width + ((x0 - 1) >> MIN_PU_LOG2)].pred_flag == PF_INTRA) - w++; - - return w; -} - -static void pred_regular_luma(VVCLocalContext *lc, const int hf_idx, const int vf_idx, const MvField *mv, - const int x0, const int y0, const int sbw, const int sbh, const MvField *orig_mv, const int sb_bdof_flag) -{ - const SliceContext *sc = lc->sc; - const VVCFrameContext *fc = lc->fc; - const int ciip_flag = lc->cu->ciip_flag; - uint8_t *dst = POS(0, x0, y0); - const ptrdiff_t dst_stride = fc->frame->linesize[0]; - uint8_t *inter = ciip_flag ? (uint8_t *)lc->ciip_tmp1 : dst; - const ptrdiff_t inter_stride = ciip_flag ? (MAX_PB_SIZE * sizeof(uint16_t)) : dst_stride; - VVCFrame *ref[2]; - - if (pred_get_refs(lc, ref, mv) < 0) - return; - - if (mv->pred_flag != PF_BI) { - const int lx = mv->pred_flag - PF_L0; - luma_mc_uni(lc, inter, inter_stride, ref[lx]->frame, - mv, x0, y0, sbw, sbh, hf_idx, vf_idx); - } else { - luma_mc_bi(lc, inter, inter_stride, ref[0]->frame, - &mv->mv[0], x0, y0, sbw, sbh, ref[1]->frame, &mv->mv[1], mv, - hf_idx, vf_idx, orig_mv, sb_bdof_flag); - } - - if (ciip_flag) { - const int intra_weight = ciip_derive_intra_weight(lc, x0, y0, sbw, sbh); - fc->vvcdsp.intra.intra_pred(lc, x0, y0, sbw, sbh, 0); - if (sc->sh.r->sh_lmcs_used_flag) - fc->vvcdsp.lmcs.filter(inter, inter_stride, sbw, sbh, &fc->ps.lmcs.fwd_lut); - fc->vvcdsp.inter.put_ciip(dst, dst_stride, sbw, sbh, inter, inter_stride, intra_weight); - - } -} - -static void pred_regular_chroma(VVCLocalContext *lc, const MvField *mv, - const int x0, const int y0, const int sbw, const int sbh, const MvField *orig_mv, const int dmvr_flag) -{ - const VVCFrameContext *fc = lc->fc; - const int hs = fc->ps.sps->hshift[1]; - const int vs = fc->ps.sps->vshift[1]; - const int x0_c = x0 >> hs; - const int y0_c = y0 >> vs; - const int w_c = sbw >> hs; - const int h_c = sbh >> vs; - const int do_ciip = lc->cu->ciip_flag && (w_c > 2); - - uint8_t* dst1 = POS(1, x0, y0); - uint8_t* dst2 = POS(2, x0, y0); - const ptrdiff_t dst1_stride = fc->frame->linesize[1]; - const ptrdiff_t dst2_stride = fc->frame->linesize[2]; - - uint8_t *inter1 = do_ciip ? (uint8_t *)lc->ciip_tmp1 : dst1; - const ptrdiff_t inter1_stride = do_ciip ? (MAX_PB_SIZE * sizeof(uint16_t)) : dst1_stride; - - uint8_t *inter2 = do_ciip ? (uint8_t *)lc->ciip_tmp2 : dst2; - const ptrdiff_t inter2_stride = do_ciip ? (MAX_PB_SIZE * sizeof(uint16_t)) : dst2_stride; - - //fix me - const int hf_idx = 0; - const int vf_idx = 0; - VVCFrame *ref[2]; - - if (pred_get_refs(lc, ref, mv) < 0) - return; - - if (mv->pred_flag != PF_BI) { - const int lx = mv->pred_flag - PF_L0; - if (!ref[lx]) - return; - - chroma_mc_uni(lc, inter1, inter1_stride, ref[lx]->frame->data[1], ref[lx]->frame->linesize[1], - x0_c, y0_c, w_c, h_c, mv, CB, hf_idx, vf_idx); - chroma_mc_uni(lc, inter2, inter2_stride, ref[lx]->frame->data[2], ref[lx]->frame->linesize[2], - x0_c, y0_c, w_c, h_c, mv, CR, hf_idx, vf_idx); - } else { - if (!ref[0] || !ref[1]) - return; - - chroma_mc_bi(lc, inter1, inter1_stride, ref[0]->frame, ref[1]->frame, - x0_c, y0_c, w_c, h_c, mv, CB, hf_idx, vf_idx, orig_mv, dmvr_flag, lc->cu->ciip_flag); - - chroma_mc_bi(lc, inter2, inter2_stride, ref[0]->frame, ref[1]->frame, - x0_c, y0_c, w_c, h_c, mv, CR, hf_idx, vf_idx, orig_mv, dmvr_flag, lc->cu->ciip_flag); - - } - if (do_ciip) { - const int intra_weight = ciip_derive_intra_weight(lc, x0, y0, sbw, sbh); - fc->vvcdsp.intra.intra_pred(lc, x0, y0, sbw, sbh, 1); - fc->vvcdsp.intra.intra_pred(lc, x0, y0, sbw, sbh, 2); - fc->vvcdsp.inter.put_ciip(dst1, dst1_stride, w_c, h_c, inter1, inter1_stride, intra_weight); - fc->vvcdsp.inter.put_ciip(dst2, dst2_stride, w_c, h_c, inter2, inter2_stride, intra_weight); - - } -} - -// 8.5.3.5 Parametric motion vector refinement process -static int parametric_mv_refine(const int *sad, const int stride) -{ - const int sad_minus = sad[-stride]; - const int sad_center = sad[0]; - const int sad_plus = sad[stride]; - int dmvc; - int denom = (( sad_minus + sad_plus) - (sad_center << 1 ) ) << 3; - if (!denom) - dmvc = 0; - else { - if (sad_minus == sad_center) - dmvc = -8; - else if (sad_plus == sad_center) - dmvc = 8; - else { - int num = ( sad_minus - sad_plus ) * (1 << 4); - int sign_num = 0; - int quotient = 0; - int counter = 3; - if (num < 0 ) { - num = - num; - sign_num = 1; - } - while (counter > 0) { - counter = counter - 1; - quotient = quotient << 1; - if ( num >= denom ) { - num = num - denom; - quotient = quotient + 1; - } - denom = (denom >> 1); - } - if (sign_num == 1 ) - dmvc = -quotient; - else - dmvc = quotient; - } - } - return dmvc; -} - -#define SAD_ARRAY_SIZE 5 -//8.5.3 Decoder-side motion vector refinement process -static void dmvr_mv_refine(VVCLocalContext *lc, MvField *mvf, MvField *orig_mv, int *sb_bdof_flag, - const AVFrame *ref0, const AVFrame *ref1, const int x_off, const int y_off, const int block_w, const int block_h) -{ - const VVCFrameContext *fc = lc->fc; - const int sr_range = 2; - const AVFrame *ref[] = { ref0, ref1 }; - int16_t *tmp[] = { lc->tmp, lc->tmp1 }; - int sad[SAD_ARRAY_SIZE][SAD_ARRAY_SIZE]; - int min_dx, min_dy, min_sad, dx, dy; - - *orig_mv = *mvf; - min_dx = min_dy = dx = dy = 2; - - for (int i = L0; i <= L1; i++) { - const int pred_w = block_w + 2 * sr_range; - const int pred_h = block_h + 2 * sr_range; - const Mv *mv = mvf->mv + i; - const int mx = mv->x & 0xf; - const int my = mv->y & 0xf; - const int ox = x_off + (mv->x >> 4) - sr_range; - const int oy = y_off + (mv->y >> 4) - sr_range; - ptrdiff_t src_stride = ref[i]->linesize[LUMA]; - const uint8_t *src = ref[i]->data[LUMA] + oy * src_stride + (ox * (1 << fc->ps.sps->pixel_shift)); - EMULATED_EDGE_BILINEAR(lc->edge_emu_buffer, &src, &src_stride, ox, oy); - fc->vvcdsp.inter.dmvr[!!my][!!mx](tmp[i], src, src_stride, pred_h, mx, my, pred_w); - } - - min_sad = fc->vvcdsp.inter.sad(tmp[L0], tmp[L1], dx, dy, block_w, block_h); - min_sad -= min_sad >> 2; - sad[dy][dx] = min_sad; - - if (min_sad >= block_w * block_h) { - int dmv[2]; - // 8.5.3.4 Array entry selection process - for (dy = 0; dy < SAD_ARRAY_SIZE; dy++) { - for (dx = 0; dx < SAD_ARRAY_SIZE; dx++) { - if (dx != sr_range || dy != sr_range) { - sad[dy][dx] = fc->vvcdsp.inter.sad(lc->tmp, lc->tmp1, dx, dy, block_w, block_h); - if (sad[dy][dx] < min_sad) { - min_sad = sad[dy][dx]; - min_dx = dx; - min_dy = dy; - } - } - } - } - dmv[0] = (min_dx - sr_range) * (1 << 4); - dmv[1] = (min_dy - sr_range) * (1 << 4); - if (min_dx != 0 && min_dx != 4 && min_dy != 0 && min_dy != 4) { - dmv[0] += parametric_mv_refine(&sad[min_dy][min_dx], 1); - dmv[1] += parametric_mv_refine(&sad[min_dy][min_dx], SAD_ARRAY_SIZE); - } - - for (int i = L0; i <= L1; i++) { - Mv *mv = mvf->mv + i; - mv->x += (1 - 2 * i) * dmv[0]; - mv->y += (1 - 2 * i) * dmv[1]; - ff_vvc_clip_mv(mv); - } - } - if (min_sad < 2 * block_w * block_h) { - *sb_bdof_flag = 0; - } -} - -static void set_dmvr_info(VVCFrameContext *fc, const int x0, const int y0, - const int width, const int height, const MvField *mvf) - -{ - const VVCPPS *pps = fc->ps.pps; - - for (int y = y0; y < y0 + height; y += MIN_PU_SIZE) { - for (int x = x0; x < x0 + width; x += MIN_PU_SIZE) { - const int idx = pps->min_pu_width * (y >> MIN_PU_LOG2) + (x >> MIN_PU_LOG2); - fc->ref->tab_dmvr_mvf[idx] = *mvf; - } - } -} - -static void derive_sb_mv(VVCLocalContext *lc, MvField *mv, MvField *orig_mv, int *sb_bdof_flag, - const int x0, const int y0, const int sbw, const int sbh) -{ - VVCFrameContext *fc = lc->fc; - const PredictionUnit *pu = &lc->cu->pu; - - *orig_mv = *mv = *ff_vvc_get_mvf(fc, x0, y0); - if (pu->bdof_flag) - *sb_bdof_flag = 1; - if (pu->dmvr_flag) { - VVCFrame* ref[2]; - if (pred_get_refs(lc, ref, mv) < 0) - return; - dmvr_mv_refine(lc, mv, orig_mv, sb_bdof_flag, ref[0]->frame, ref[1]->frame, x0, y0, sbw, sbh); - set_dmvr_info(fc, x0, y0, sbw, sbh, mv); - } -} - -static void pred_regular_blk(VVCLocalContext *lc, const int skip_ciip) -{ - const VVCFrameContext *fc = lc->fc; - const CodingUnit *cu = lc->cu; - PredictionUnit *pu = &lc->cu->pu; - const MotionInfo *mi = &pu->mi; - MvField mv, orig_mv; - int sbw, sbh, sb_bdof_flag = 0; - - if (cu->ciip_flag && skip_ciip) - return; - - sbw = cu->cb_width / mi->num_sb_x; - sbh = cu->cb_height / mi->num_sb_y; - - for (int sby = 0; sby < mi->num_sb_y; sby++) { - for (int sbx = 0; sbx < mi->num_sb_x; sbx++) { - const int x0 = cu->x0 + sbx * sbw; - const int y0 = cu->y0 + sby * sbh; - - if (cu->ciip_flag) - ff_vvc_set_neighbour_available(lc, x0, y0, sbw, sbh); - - derive_sb_mv(lc, &mv, &orig_mv, &sb_bdof_flag, x0, y0, sbw, sbh); - pred_regular_luma(lc, mi->hpel_if_idx, mi->hpel_if_idx, &mv, x0, y0, sbw, sbh, &orig_mv, sb_bdof_flag); - if (fc->ps.sps->r->sps_chroma_format_idc) - pred_regular_chroma(lc, &mv, x0, y0, sbw, sbh, &orig_mv, pu->dmvr_flag); - } - } -} - -static void derive_affine_mvc(MvField *mvc, const VVCFrameContext *fc, const MvField *mv, - const int x0, const int y0, const int sbw, const int sbh) -{ - const int hs = fc->ps.sps->hshift[1]; - const int vs = fc->ps.sps->vshift[1]; - const MvField* mv2 = ff_vvc_get_mvf(fc, x0 + hs * sbw, y0 + vs * sbh); - *mvc = *mv; - - // Due to different pred_flag, one of the motion vectors may have an invalid value. - // Cast them to an unsigned type to avoid undefined behavior. - mvc->mv[0].x += (unsigned int)mv2->mv[0].x; - mvc->mv[0].y += (unsigned int)mv2->mv[0].y; - mvc->mv[1].x += (unsigned int)mv2->mv[1].x; - mvc->mv[1].y += (unsigned int)mv2->mv[1].y; - ff_vvc_round_mv(mvc->mv + 0, 0, 1); - ff_vvc_round_mv(mvc->mv + 1, 0, 1); -} - -static void pred_affine_blk(VVCLocalContext *lc) -{ - const VVCFrameContext *fc = lc->fc; - const CodingUnit *cu = lc->cu; - const PredictionUnit *pu = &cu->pu; - const MotionInfo *mi = &pu->mi; - const int x0 = cu->x0; - const int y0 = cu->y0; - const int sbw = cu->cb_width / mi->num_sb_x; - const int sbh = cu->cb_height / mi->num_sb_y; - const int hs = fc->ps.sps->hshift[1]; - const int vs = fc->ps.sps->vshift[1]; - - for (int sby = 0; sby < mi->num_sb_y; sby++) { - for (int sbx = 0; sbx < mi->num_sb_x; sbx++) { - const int x = x0 + sbx * sbw; - const int y = y0 + sby * sbh; - - uint8_t *dst0 = POS(0, x, y); - const MvField *mv = ff_vvc_get_mvf(fc, x, y); - VVCFrame *ref[2]; - - if (pred_get_refs(lc, ref, mv) < 0) - return; - - if (mi->pred_flag != PF_BI) { - const int lx = mi->pred_flag - PF_L0; - luma_prof_uni(lc, dst0, fc->frame->linesize[0], ref[lx]->frame, - mv, x, y, sbw, sbh, pu->cb_prof_flag[lx], - pu->diff_mv_x[lx], pu->diff_mv_y[lx]); - } else { - luma_prof_bi(lc, dst0, fc->frame->linesize[0], ref[0]->frame, ref[1]->frame, - mv, x, y, sbw, sbh); - } - if (fc->ps.sps->r->sps_chroma_format_idc) { - if (!av_mod_uintp2(sby, vs) && !av_mod_uintp2(sbx, hs)) { - MvField mvc; - derive_affine_mvc(&mvc, fc, mv, x, y, sbw, sbh); - pred_regular_chroma(lc, &mvc, x, y, sbw<fc; - const CodingUnit *cu = lc->cu; - const PredictionUnit *pu = &cu->pu; - - if (pu->merge_gpm_flag) - pred_gpm_blk(lc); - else if (pu->inter_affine_flag) - pred_affine_blk(lc); - else - pred_regular_blk(lc, 1); //intra block is not ready yet, skip ciip - - if (lc->sc->sh.r->sh_lmcs_used_flag && !cu->ciip_flag) { - uint8_t* dst0 = POS(0, cu->x0, cu->y0); - fc->vvcdsp.lmcs.filter(dst0, fc->frame->linesize[LUMA], cu->cb_width, cu->cb_height, &fc->ps.lmcs.fwd_lut); - } -} - -static int has_inter_luma(const CodingUnit *cu) -{ - return (cu->pred_mode == MODE_INTER || cu->pred_mode == MODE_SKIP) && cu->tree_type != DUAL_TREE_CHROMA; -} - -int ff_vvc_predict_inter(VVCLocalContext *lc, const int rs) -{ - const VVCFrameContext *fc = lc->fc; - const CTU *ctu = fc->tab.ctus + rs; - CodingUnit *cu = ctu->cus; - - while (cu) { - lc->cu = cu; - if (has_inter_luma(cu)) - predict_inter(lc); - cu = cu->next; - } - - return 0; -} - -void ff_vvc_predict_ciip(VVCLocalContext *lc) -{ - av_assert0(lc->cu->ciip_flag); - - //todo: refact out ciip from pred_regular_blk - pred_regular_blk(lc, 0); -} - -#undef POS diff --git a/libavcodec/vvc_parser.c b/libavcodec/vvc_parser.c index 245cb214c..8d32d6657 100644 --- a/libavcodec/vvc_parser.c +++ b/libavcodec/vvc_parser.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "cbs.h" #include "cbs_h266.h" #include "parser.h" @@ -184,14 +185,10 @@ static void set_parser_ctx(AVCodecParserContext *s, AVCodecContext *avctx, avctx->color_range = sps->vui.vui_full_range_flag ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; - avctx->has_b_frames = (sps->sps_max_sublayers_minus1 + 1) > 2 ? 2 : - sps->sps_max_sublayers_minus1; - avctx->max_b_frames = sps->sps_max_sublayers_minus1; - if (sps->sps_ptl_dpb_hrd_params_present_flag && sps->sps_timing_hrd_params_present_flag) { - int num = sps->sps_general_timing_hrd_parameters.num_units_in_tick; - int den = sps->sps_general_timing_hrd_parameters.time_scale; + uint32_t num = sps->sps_general_timing_hrd_parameters.num_units_in_tick; + uint32_t den = sps->sps_general_timing_hrd_parameters.time_scale; if (num != 0 && den != 0) av_reduce(&avctx->framerate.den, &avctx->framerate.num, diff --git a/libavcodec/wavarc.c b/libavcodec/wavarc.c index 536c74e47..93b76c43e 100644 --- a/libavcodec/wavarc.c +++ b/libavcodec/wavarc.c @@ -19,13 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" #include "get_bits.h" -#include "bytestream.h" #include "mathops.h" #include "unary.h" diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c index 505bd3c96..bf9aa0cdc 100644 --- a/libavcodec/wavpack.c +++ b/libavcodec/wavpack.c @@ -20,8 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/buffer.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #define BITSTREAM_READER_LE #include "avcodec.h" @@ -30,7 +30,7 @@ #include "get_bits.h" #include "refstruct.h" #include "thread.h" -#include "threadframe.h" +#include "threadprogress.h" #include "unary.h" #include "wavpack.h" #include "dsd.h" @@ -103,15 +103,14 @@ typedef struct WavpackContext { WavpackFrameContext **fdec; int fdec_num; - int block; int samples; int ch_offset; - AVFrame *frame; - ThreadFrame curr_frame, prev_frame; Modulation modulation; DSDContext *dsdctx; ///< RefStruct reference + ThreadProgress *curr_progress, *prev_progress; ///< RefStruct references + FFRefStructPool *progress_pool; ///< RefStruct reference int dsd_channels; } WavpackContext; @@ -994,11 +993,14 @@ static int wv_dsd_reset(WavpackContext *s, int channels) s->dsd_channels = 0; ff_refstruct_unref(&s->dsdctx); + ff_refstruct_unref(&s->curr_progress); + ff_refstruct_unref(&s->prev_progress); if (!channels) return 0; - if (channels > INT_MAX / sizeof(*s->dsdctx)) + if (WV_MAX_CHANNELS > SIZE_MAX / sizeof(*s->dsdctx) && + channels > SIZE_MAX / sizeof(*s->dsdctx)) return AVERROR(EINVAL); s->dsdctx = ff_refstruct_allocz(channels * sizeof(*s->dsdctx)); @@ -1009,6 +1011,8 @@ static int wv_dsd_reset(WavpackContext *s, int channels) for (i = 0; i < channels; i++) memset(s->dsdctx[i].buf, 0x69, sizeof(s->dsdctx[i].buf)); + ff_init_dsd_data(); + return 0; } @@ -1017,22 +1021,31 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { WavpackContext *fsrc = src->priv_data; WavpackContext *fdst = dst->priv_data; - int ret; - - if (dst == src) - return 0; - - ff_thread_release_ext_buffer(&fdst->curr_frame); - if (fsrc->curr_frame.f->data[0]) { - if ((ret = ff_thread_ref_frame(&fdst->curr_frame, &fsrc->curr_frame)) < 0) - return ret; - } + ff_refstruct_replace(&fdst->curr_progress, fsrc->curr_progress); ff_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) +{ + ThreadProgress *progress = obj; + return ff_thread_progress_init(progress, 1); +} + +static void progress_pool_reset_cb(FFRefStructOpaque opaque, void *obj) +{ + ThreadProgress *progress = obj; + ff_thread_progress_reset(progress); +} + +static av_cold void progress_pool_free_entry_cb(FFRefStructOpaque opaque, void *obj) +{ + ThreadProgress *progress = obj; + ff_thread_progress_destroy(progress); +} #endif static av_cold int wavpack_decode_init(AVCodecContext *avctx) @@ -1043,13 +1056,17 @@ static av_cold int wavpack_decode_init(AVCodecContext *avctx) s->fdec_num = 0; - s->curr_frame.f = av_frame_alloc(); - s->prev_frame.f = av_frame_alloc(); - - if (!s->curr_frame.f || !s->prev_frame.f) - return AVERROR(ENOMEM); - - ff_init_dsd_data(); +#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, + progress_pool_init_cb, + progress_pool_reset_cb, + progress_pool_free_entry_cb, NULL); + if (!s->progress_pool) + return AVERROR(ENOMEM); + } +#endif return 0; } @@ -1063,19 +1080,14 @@ static av_cold int wavpack_decode_end(AVCodecContext *avctx) av_freep(&s->fdec); s->fdec_num = 0; - ff_thread_release_ext_buffer(&s->curr_frame); - av_frame_free(&s->curr_frame.f); - - ff_thread_release_ext_buffer(&s->prev_frame); - av_frame_free(&s->prev_frame.f); - - ff_refstruct_unref(&s->dsdctx); + ff_refstruct_pool_uninit(&s->progress_pool); + wv_dsd_reset(s, 0); return 0; } -static int wavpack_decode_block(AVCodecContext *avctx, int block_no, - const uint8_t *buf, int buf_size) +static int wavpack_decode_block(AVCodecContext *avctx, AVFrame *frame, int block_no, + const uint8_t *buf, int buf_size, int *new_progress) { WavpackContext *wc = avctx->priv_data; WavpackFrameContext *s; @@ -1406,13 +1418,13 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, chmask = bytestream2_get_le32(&gb); break; case 4: - size = bytestream2_get_byte(&gb); + bytestream2_get_byte(&gb); chan |= (bytestream2_get_byte(&gb) & 0xF) << 8; chan += 1; chmask = bytestream2_get_le24(&gb); break; case 5: - size = bytestream2_get_byte(&gb); + bytestream2_get_byte(&gb); chan |= (bytestream2_get_byte(&gb) & 0xF) << 8; chan += 1; chmask = bytestream2_get_le32(&gb); @@ -1421,6 +1433,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, av_log(avctx, AV_LOG_ERROR, "Invalid channel info size %d\n", size); } + av_assert1(chan <= WV_MAX_CHANNELS); break; case WP_ID_SAMPLE_RATE: if (size != 3) { @@ -1512,36 +1525,43 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, } else { av_channel_layout_default(&new_ch_layout, s->stereo + 1); } + av_assert1(new_ch_layout.nb_channels <= WV_MAX_CHANNELS); /* clear DSD state if stream properties change */ - if (new_ch_layout.nb_channels != wc->dsd_channels || - av_channel_layout_compare(&new_ch_layout, &avctx->ch_layout) || - new_samplerate != avctx->sample_rate || - !!got_dsd != !!wc->dsdctx) { + if ((wc->dsdctx && !got_dsd) || + got_dsd && (new_ch_layout.nb_channels != wc->dsd_channels || + av_channel_layout_compare(&new_ch_layout, &avctx->ch_layout) || + new_samplerate != avctx->sample_rate)) { ret = wv_dsd_reset(wc, got_dsd ? new_ch_layout.nb_channels : 0); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error reinitializing the DSD context\n"); return ret; } - ff_thread_release_ext_buffer(&wc->curr_frame); } av_channel_layout_copy(&avctx->ch_layout, &new_ch_layout); avctx->sample_rate = new_samplerate; avctx->sample_fmt = sample_fmt; avctx->bits_per_raw_sample = orig_bpp; - ff_thread_release_ext_buffer(&wc->prev_frame); - FFSWAP(ThreadFrame, wc->curr_frame, wc->prev_frame); - /* get output buffer */ - wc->curr_frame.f->nb_samples = s->samples; - ret = ff_thread_get_ext_buffer(avctx, &wc->curr_frame, - AV_GET_BUFFER_FLAG_REF); + frame->nb_samples = s->samples; + ret = ff_thread_get_buffer(avctx, frame, 0); if (ret < 0) return ret; - wc->frame = wc->curr_frame.f; - ff_thread_finish_setup(avctx); + 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); + if (!wc->prev_progress) + return AVERROR(ENOMEM); + FFSWAP(ThreadProgress*, wc->prev_progress, wc->curr_progress); + *new_progress = 1; + } + av_assert1(!!wc->dsdctx == !!wc->curr_progress); + ff_thread_finish_setup(avctx); + } } if (wc->ch_offset + s->stereo >= avctx->ch_layout.nb_channels) { @@ -1549,9 +1569,9 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, return ((avctx->err_recognition & AV_EF_EXPLODE) || !wc->ch_offset) ? AVERROR_INVALIDDATA : 0; } - samples_l = wc->frame->extended_data[wc->ch_offset]; + samples_l = frame->extended_data[wc->ch_offset]; if (s->stereo) - samples_r = wc->frame->extended_data[wc->ch_offset + 1]; + samples_r = frame->extended_data[wc->ch_offset + 1]; wc->ch_offset += 1 + s->stereo; @@ -1603,26 +1623,27 @@ static int dsd_channel(AVCodecContext *avctx, void *frmptr, int jobnr, int threa const WavpackContext *s = avctx->priv_data; AVFrame *frame = frmptr; - ff_dsd2pcm_translate (&s->dsdctx [jobnr], s->samples, 0, + ff_dsd2pcm_translate(&s->dsdctx[jobnr], s->samples, 0, (uint8_t *)frame->extended_data[jobnr], 4, (float *)frame->extended_data[jobnr], 1); return 0; } -static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *rframe, +static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt) { WavpackContext *s = avctx->priv_data; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; int frame_size, ret, frame_flags; + int block = 0, new_progress = 0; + + av_assert1(!s->curr_progress || s->dsdctx); if (avpkt->size <= WV_HEADER_SIZE) return AVERROR_INVALIDDATA; - s->frame = NULL; - s->block = 0; s->ch_offset = 0; /* determine number of samples */ @@ -1643,13 +1664,15 @@ static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *rframe, if (frame_size <= 0 || frame_size > buf_size) { av_log(avctx, AV_LOG_ERROR, "Block %d has invalid size (size %d vs. %d bytes left)\n", - s->block, frame_size, buf_size); + block, frame_size, buf_size); ret = AVERROR_INVALIDDATA; goto error; } - if ((ret = wavpack_decode_block(avctx, s->block, buf, frame_size)) < 0) + ret = wavpack_decode_block(avctx, frame, block, buf, + frame_size, &new_progress); + if (ret < 0) goto error; - s->block++; + block++; buf += frame_size; buf_size -= frame_size; } @@ -1660,26 +1683,23 @@ static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *rframe, goto error; } - ff_thread_await_progress(&s->prev_frame, INT_MAX, 0); - ff_thread_release_ext_buffer(&s->prev_frame); - - if (s->modulation == MODULATION_DSD) - avctx->execute2(avctx, dsd_channel, s->frame, NULL, avctx->ch_layout.nb_channels); - - ff_thread_report_progress(&s->curr_frame, INT_MAX, 0); - - if ((ret = av_frame_ref(rframe, s->frame)) < 0) - return ret; + if (s->dsdctx) { + if (s->prev_progress) + ff_thread_progress_await(s->prev_progress, INT_MAX); + avctx->execute2(avctx, dsd_channel, frame, NULL, avctx->ch_layout.nb_channels); + if (s->curr_progress) + ff_thread_progress_report(s->curr_progress, INT_MAX); + } *got_frame_ptr = 1; return avpkt->size; error: - if (s->frame) { - ff_thread_await_progress(&s->prev_frame, INT_MAX, 0); - ff_thread_release_ext_buffer(&s->prev_frame); - ff_thread_report_progress(&s->curr_frame, INT_MAX, 0); + if (new_progress) { + if (s->prev_progress) + ff_thread_progress_await(s->prev_progress, INT_MAX); + ff_thread_progress_report(s->curr_progress, INT_MAX); } return ret; @@ -1698,6 +1718,5 @@ const FFCodec ff_wavpack_decoder = { UPDATE_THREAD_CONTEXT(update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_CHANNEL_CONF, - .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | - FF_CODEC_CAP_ALLOCATE_PROGRESS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/wavpack.h b/libavcodec/wavpack.h index 9f62f8406..2efbb1fd0 100644 --- a/libavcodec/wavpack.h +++ b/libavcodec/wavpack.h @@ -57,6 +57,7 @@ #define WV_FLT_ZERO_SENT 0x08 #define WV_FLT_ZERO_SIGN 0x10 +#define WV_MAX_CHANNELS (1 << 12) #define WV_MAX_SAMPLES 150000 enum WP_ID_Flags { diff --git a/libavcodec/wavpackenc.c b/libavcodec/wavpackenc.c index 923eae55f..e99ab951d 100644 --- a/libavcodec/wavpackenc.c +++ b/libavcodec/wavpackenc.c @@ -22,6 +22,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/wbmpdec.c b/libavcodec/wbmpdec.c index 3b5753abc..50c729047 100644 --- a/libavcodec/wbmpdec.c +++ b/libavcodec/wbmpdec.c @@ -74,9 +74,6 @@ static int wbmp_decode_frame(AVCodecContext *avctx, AVFrame *p, else readbits(p->data[0], width, height, p->linesize[0], gb.buffer, gb.buffer_end - gb.buffer); - p->flags |= AV_FRAME_FLAG_KEY; - p->pict_type = AV_PICTURE_TYPE_I; - *got_frame = 1; return buf_size; diff --git a/libavcodec/webp.c b/libavcodec/webp.c index 9308ea2b6..b624458d6 100644 --- a/libavcodec/webp.c +++ b/libavcodec/webp.c @@ -41,6 +41,7 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #define BITSTREAM_READER_LE #include "avcodec.h" @@ -703,6 +704,9 @@ static int decode_entropy_coded_image(WebPContext *s, enum ImageRole role, ref_x = FFMAX(0, ref_x); ref_y = FFMAX(0, ref_y); + if (ref_y == y && ref_x >= x) + return AVERROR_INVALIDDATA; + /* copy pixels * source and dest regions can overlap and wrap lines, so just * copy per-pixel */ @@ -1570,5 +1574,6 @@ const FFCodec ff_webp_decoder = { FF_CODEC_DECODE_CB(webp_decode_frame), .close = webp_decode_close, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, - .caps_internal = FF_CODEC_CAP_ICC_PROFILES, + .caps_internal = FF_CODEC_CAP_ICC_PROFILES | + FF_CODEC_CAP_USES_PROGRESSFRAMES, }; diff --git a/libavcodec/webvttdec.c b/libavcodec/webvttdec.c index 690f00dc4..35bdbe805 100644 --- a/libavcodec/webvttdec.c +++ b/libavcodec/webvttdec.c @@ -37,9 +37,9 @@ static const struct { {"", "{\\i1}"}, {"", "{\\i0}"}, {"", "{\\b1}"}, {"", "{\\b0}"}, {"", "{\\u1}"}, {"", "{\\u0}"}, - {"{", "\\{"}, {"}", "\\}"}, // escape to avoid ASS markup conflicts + {"{", "\\{{}"}, {"\\", "\\\xe2\x81\xa0"}, // escape to avoid ASS markup conflicts {">", ">"}, {"<", "<"}, - {"‎", ""}, {"‏", ""}, // FIXME: properly honor bidi marks + {"‎", "\xe2\x80\x8e"}, {"‏", "\xe2\x80\x8f"}, {"&", "&"}, {" ", "\\h"}, }; diff --git a/libavcodec/wma.c b/libavcodec/wma.c index 5eacf230f..da9c914b5 100644 --- a/libavcodec/wma.c +++ b/libavcodec/wma.c @@ -20,6 +20,7 @@ */ #include "libavutil/attributes.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "sinewin.h" diff --git a/libavcodec/wmaenc.c b/libavcodec/wmaenc.c index 80ff696be..6949f08fb 100644 --- a/libavcodec/wmaenc.c +++ b/libavcodec/wmaenc.c @@ -23,6 +23,7 @@ #include "libavutil/attributes.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" diff --git a/libavcodec/wmalosslessdec.c b/libavcodec/wmalosslessdec.c index 5d1c7ac66..9559fe1fa 100644 --- a/libavcodec/wmalosslessdec.c +++ b/libavcodec/wmalosslessdec.c @@ -26,6 +26,7 @@ #include "libavutil/attributes.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "avcodec.h" diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c index 65b269add..a6c4a7563 100644 --- a/libavcodec/wmaprodec.c +++ b/libavcodec/wmaprodec.c @@ -89,6 +89,7 @@ #include #include "libavutil/audio_fifo.h" +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "libavutil/ffmath.h" #include "libavutil/float_dsp.h" @@ -2023,7 +2024,7 @@ static av_cold int xma_decode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); } - return ret; + return 0; } static av_cold int xma_decode_end(AVCodecContext *avctx) diff --git a/libavcodec/wmavoice.c b/libavcodec/wmavoice.c index 4e93aadab..39868e02b 100644 --- a/libavcodec/wmavoice.c +++ b/libavcodec/wmavoice.c @@ -29,6 +29,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/thread.h" #include "libavutil/tx.h" @@ -654,7 +655,7 @@ static void calc_input_response(WMAVoiceContext *s, float *lpcs_src, lpcs[n] = angle_mul * pwr; /* 70.57 =~ 1/log10(1.0331663) */ - idx = av_clipf((pwr * gain_mul - 0.0295) * 70.570526123, 0, INT_MAX / 2); + idx = av_clipd((pwr * gain_mul - 0.0295) * 70.570526123, 0, INT_MAX / 2); if (idx > 127) { // fall back if index falls outside table range coeffs[n] = wmavoice_energy_table[127] * @@ -1505,6 +1506,8 @@ static int synth_frame(AVCodecContext *ctx, GetBitContext *gb, int frame_idx, /* Parse frame type ("frame header"), see frame_descs */ int bd_idx = s->vbm_tree[get_vlc2(gb, frame_type_vlc, 6, 3)], block_nsamples; + pitch[0] = INT_MAX; + if (bd_idx < 0) { av_log(ctx, AV_LOG_ERROR, "Invalid frame type VLC code, skipping\n"); @@ -1622,6 +1625,9 @@ static int synth_frame(AVCodecContext *ctx, GetBitContext *gb, int frame_idx, double i_lsps[MAX_LSPS]; float lpcs[MAX_LSPS]; + if(frame_descs[bd_idx].fcb_type >= FCB_TYPE_AW_PULSES && pitch[0] == INT_MAX) + return AVERROR_INVALIDDATA; + for (n = 0; n < s->lsps; n++) // LSF -> LSP i_lsps[n] = cos(0.5 * (prev_lsps[n] + lsps[n])); ff_acelp_lspd2lpc(i_lsps, lpcs, s->lsps >> 1); diff --git a/libavcodec/wmv2.c b/libavcodec/wmv2.c index e3d3288d3..c2bcb988c 100644 --- a/libavcodec/wmv2.c +++ b/libavcodec/wmv2.c @@ -49,7 +49,8 @@ av_cold 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, op_pixels_func (*pix_op)[4], + 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; diff --git a/libavcodec/wmv2.h b/libavcodec/wmv2.h index e49b81cdf..6fc9704c3 100644 --- a/libavcodec/wmv2.h +++ b/libavcodec/wmv2.h @@ -39,7 +39,8 @@ 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, op_pixels_func (*pix_op)[4], + uint8_t *const *ref_picture, + const op_pixels_func (*pix_op)[4], int motion_x, int motion_y, int h); diff --git a/libavcodec/wmv2dec.c b/libavcodec/wmv2dec.c index ff27d1b4d..677467ccc 100644 --- a/libavcodec/wmv2dec.c +++ b/libavcodec/wmv2dec.c @@ -27,6 +27,7 @@ #include "mathops.h" #include "mpegutils.h" #include "mpegvideo.h" +#include "mpegvideodec.h" #include "msmpeg4.h" #include "msmpeg4_vc1_data.h" #include "msmpeg4dec.h" @@ -103,7 +104,7 @@ static int parse_mb_skip(WMV2DecContext *w) int mb_x, mb_y; int coded_mb_count = 0; MpegEncContext *const s = &w->s; - uint32_t *const mb_type = s->current_picture_ptr->mb_type; + uint32_t *const mb_type = s->cur_pic.mb_type; w->skip_type = get_bits(&s->gb, 2); switch (w->skip_type) { @@ -111,7 +112,7 @@ static int parse_mb_skip(WMV2DecContext *w) 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] = - MB_TYPE_16x16 | MB_TYPE_L0; + MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; break; case SKIP_TYPE_MPEG: if (get_bits_left(&s->gb) < s->mb_height * s->mb_width) @@ -119,7 +120,7 @@ static int parse_mb_skip(WMV2DecContext *w) 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_L0; + (get_bits1(&s->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++) { @@ -128,11 +129,11 @@ static int parse_mb_skip(WMV2DecContext *w) 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] = - MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0; + 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_L0; + (get_bits1(&s->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } } break; @@ -143,11 +144,11 @@ static int parse_mb_skip(WMV2DecContext *w) 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] = - MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0; + 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_L0; + (get_bits1(&s->gb) ? MB_TYPE_SKIP : 0) | MB_TYPE_16x16 | MB_TYPE_FORWARD_MV; } } break; @@ -238,9 +239,8 @@ int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) if (s->pict_type == AV_PICTURE_TYPE_I) { /* Is filling with zeroes really the right thing to do? */ - memset(s->current_picture_ptr->mb_type, 0, - sizeof(*s->current_picture_ptr->mb_type) * - s->mb_height * s->mb_stride); + memset(s->cur_pic.mb_type, 0, + sizeof(*s->cur_pic.mb_type) * s->mb_height * s->mb_stride); if (w->j_type_bit) w->j_type = get_bits1(&s->gb); else @@ -331,7 +331,7 @@ int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) s->esc3_run_length = 0; if (w->j_type) { - ff_intrax8_decode_picture(&w->x8, &s->current_picture, + 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); @@ -366,11 +366,11 @@ static int16_t *wmv2_pred_motion(WMV2DecContext *w, int *px, int *py) wrap = s->b8_stride; xy = s->block_index[0]; - mot_val = s->current_picture.motion_val[0][xy]; + mot_val = s->cur_pic.motion_val[0][xy]; - A = s->current_picture.motion_val[0][xy - 1]; - B = s->current_picture.motion_val[0][xy - wrap]; - C = s->current_picture.motion_val[0][xy + 2 - wrap]; + 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]; if (s->mb_x && !s->first_slice_line && !s->mspel && w->top_left_mv_flag) diff = FFMAX(FFABS(A[0] - B[0]), FFABS(A[1] - B[1])); @@ -452,7 +452,7 @@ static int wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) return 0; if (s->pict_type == AV_PICTURE_TYPE_P) { - if (IS_SKIP(s->current_picture.mb_type[s->mb_y * s->mb_stride + s->mb_x])) { + if (IS_SKIP(s->cur_pic.mb_type[s->mb_y * s->mb_stride + s->mb_x])) { /* skip mb */ s->mb_intra = 0; for (i = 0; i < 6; i++) @@ -585,7 +585,7 @@ static av_cold int wmv2_decode_end(AVCodecContext *avctx) WMV2DecContext *const w = avctx->priv_data; ff_intrax8_common_end(&w->x8); - return ff_h263_decode_end(avctx); + return ff_mpv_decode_close(avctx); } const FFCodec ff_wmv2_decoder = { diff --git a/libavcodec/wmv2enc.c b/libavcodec/wmv2enc.c index 8eb56444a..fded6f0e7 100644 --- a/libavcodec/wmv2enc.c +++ b/libavcodec/wmv2enc.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "h263.h" @@ -248,6 +249,7 @@ const FFCodec ff_wmv2_encoder = { 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 }, }; diff --git a/libavcodec/wnv1.c b/libavcodec/wnv1.c index 0e8dae598..3d0d90fe3 100644 --- a/libavcodec/wnv1.c +++ b/libavcodec/wnv1.c @@ -69,7 +69,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->flags |= AV_FRAME_FLAG_KEY; if ((ret = init_get_bits8(&gb, buf + 8, buf_size - 8)) < 0) return ret; diff --git a/libavcodec/wrapped_avframe.c b/libavcodec/wrapped_avframe.c index 0278ea42b..a513bb3d3 100644 --- a/libavcodec/wrapped_avframe.c +++ b/libavcodec/wrapped_avframe.c @@ -28,10 +28,9 @@ #include "codec_internal.h" #include "decode.h" -#include "libavutil/internal.h" #include "libavutil/frame.h" #include "libavutil/buffer.h" -#include "libavutil/pixdesc.h" +#include "libavutil/mem.h" static void wrapped_avframe_release_buffer(void *unused, uint8_t *data) { diff --git a/libavcodec/x86/Makefile b/libavcodec/x86/Makefile index 21c5e9b0d..331183f45 100644 --- a/libavcodec/x86/Makefile +++ b/libavcodec/x86/Makefile @@ -61,7 +61,6 @@ 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_PRORES_LGPL_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 @@ -176,7 +175,6 @@ 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_LGPL_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 diff --git a/libavcodec/x86/aacencdsp.asm b/libavcodec/x86/aacencdsp.asm index 0d3ba4b89..8e435b7d2 100644 --- a/libavcodec/x86/aacencdsp.asm +++ b/libavcodec/x86/aacencdsp.asm @@ -53,21 +53,39 @@ cglobal abs_pow34, 3, 3, 3, out, in, size ; int size, int is_signed, int maxval, const float Q34, ; const float rounding) ;******************************************************************* -INIT_XMM sse2 +%macro AAC_QUANTIZE_BANDS 0 cglobal aac_quantize_bands, 5, 5, 6, out, in, scaled, size, is_signed, maxval, Q34, rounding %if UNIX64 == 0 +%if mmsize == 32 + vbroadcastss m0, Q34m + vbroadcastss m1, roundingm +%else movss m0, Q34m movss m1, roundingm - cvtsi2ss m3, dword maxvalm -%else - cvtsi2ss m3, maxvald -%endif shufps m0, m0, 0 shufps m1, m1, 0 - shufps m3, m3, 0 +%endif + cvtsi2ss xm3, dword maxvalm + shufps xm3, xm3, xm3, 0 +%else ; UNIX64 + shufps xm0, xm0, 0 + shufps xm1, xm1, 0 + cvtsi2ss xm3, maxvald + shufps xm3, xm3, xm3, 0 +%if mmsize == 32 + vinsertf128 m0, m0, xm0, 1 + vinsertf128 m1, m1, xm1, 1 +%endif +%endif +%if mmsize == 32 + vinsertf128 m3, m3, xm3, 1 +%endif shl is_signedd, 31 - movd m4, is_signedd - shufps m4, m4, 0 + movd xm4, is_signedd + shufps xm4, xm4, xm4, 0 +%if mmsize == 32 + vinsertf128 m4, m4, xm4, 1 +%endif shl sized, 2 add inq, sizeq add outq, sizeq @@ -78,9 +96,15 @@ cglobal aac_quantize_bands, 5, 5, 6, out, in, scaled, size, is_signed, maxval, Q addps m2, m1 minps m2, m3 andps m5, m4, [inq+sizeq] - orps m2, m5 + xorps m2, m5 cvttps2dq m2, m2 mova [outq+sizeq], m2 add sizeq, mmsize jl .loop RET +%endmacro + +INIT_XMM sse2 +AAC_QUANTIZE_BANDS +INIT_YMM avx +AAC_QUANTIZE_BANDS diff --git a/libavcodec/x86/aacencdsp_init.c b/libavcodec/x86/aacencdsp_init.c index e0d8dec4f..cf17dbf91 100644 --- a/libavcodec/x86/aacencdsp_init.c +++ b/libavcodec/x86/aacencdsp_init.c @@ -30,6 +30,9 @@ void ff_abs_pow34_sse(float *out, const float *in, const int size); void ff_aac_quantize_bands_sse2(int *out, const float *in, const float *scaled, int size, int is_signed, int maxval, const float Q34, const float rounding); +void ff_aac_quantize_bands_avx(int *out, const float *in, const float *scaled, + int size, int is_signed, int maxval, const float Q34, + const float rounding); av_cold void ff_aacenc_dsp_init_x86(AACEncDSPContext *s) { @@ -40,4 +43,7 @@ av_cold void ff_aacenc_dsp_init_x86(AACEncDSPContext *s) if (EXTERNAL_SSE2(cpu_flags)) s->quant_bands = ff_aac_quantize_bands_sse2; + + if (EXTERNAL_AVX_FAST(cpu_flags)) + s->quant_bands = ff_aac_quantize_bands_avx; } diff --git a/libavcodec/x86/ac3dsp.asm b/libavcodec/x86/ac3dsp.asm index 0ba980aa7..21f59708b 100644 --- a/libavcodec/x86/ac3dsp.asm +++ b/libavcodec/x86/ac3dsp.asm @@ -43,7 +43,7 @@ SECTION .text %macro AC3_EXPONENT_MIN 0 cglobal ac3_exponent_min, 3, 4, 2, exp, reuse_blks, expn, offset - shl reuse_blksq, 8 + shl reuse_blksd, 8 jz .end LOOP_ALIGN .nextexp: @@ -57,7 +57,7 @@ cglobal ac3_exponent_min, 3, 4, 2, exp, reuse_blks, expn, offset jae .nextblk mova [expq], m0 add expq, mmsize - sub expnq, mmsize + sub expnd, mmsize jg .nextexp .end: RET @@ -71,7 +71,7 @@ AC3_EXPONENT_MIN %undef LOOP_ALIGN ;----------------------------------------------------------------------------- -; void ff_float_to_fixed24(int32_t *dst, const float *src, unsigned int len) +; void ff_float_to_fixed24(int32_t *dst, const float *src, size_t len) ;----------------------------------------------------------------------------- INIT_XMM sse2 @@ -217,6 +217,7 @@ cglobal ac3_compute_mantissa_size, 1, 2, 4, mant_cnt, sum %macro AC3_EXTRACT_EXPONENTS 0 cglobal ac3_extract_exponents, 3, 3, 4, exp, coef, len + movsxdifnidn lenq, lend add expq, lenq lea coefq, [coefq+4*lenq] neg lenq diff --git a/libavcodec/x86/blockdsp.asm b/libavcodec/x86/blockdsp.asm index e380308d4..cccc9a801 100644 --- a/libavcodec/x86/blockdsp.asm +++ b/libavcodec/x86/blockdsp.asm @@ -80,3 +80,36 @@ INIT_XMM sse CLEAR_BLOCKS 1 INIT_YMM avx CLEAR_BLOCKS 1 + +;----------------------------------------- +; void ff_fill_block_tab_%1(uint8_t *block, uint8_t value, +; ptrdiff_t line_size, int h); +;----------------------------------------- +%macro FILL_BLOCK_TAB 2 +cglobal fill_block_tab_%1, 4, 5, 1, block, value, stride, h, stride3 + lea stride3q, [strideq + strideq * 2] +%if cpuflag(avx2) + movd m0, valued + vpbroadcastb m0, m0 +%else + SPLATB_REG m0, value, x +%endif +.loop: + mov%2 [blockq], m0 + mov%2 [blockq + strideq], m0 + mov%2 [blockq + strideq * 2], m0 + mov%2 [blockq + stride3q], m0 + lea blockq, [blockq + strideq * 4] + sub hd, 4 + jg .loop + RET +%endmacro + +INIT_XMM sse2 +FILL_BLOCK_TAB 8, q +FILL_BLOCK_TAB 16, a +%if HAVE_AVX2_EXTERNAL +INIT_XMM avx2 +FILL_BLOCK_TAB 8, q +FILL_BLOCK_TAB 16, a +%endif diff --git a/libavcodec/x86/blockdsp_init.c b/libavcodec/x86/blockdsp_init.c index 996124114..37f3bb6a8 100644 --- a/libavcodec/x86/blockdsp_init.c +++ b/libavcodec/x86/blockdsp_init.c @@ -29,6 +29,11 @@ void ff_clear_block_avx(int16_t *block); void ff_clear_blocks_sse(int16_t *blocks); void ff_clear_blocks_avx(int16_t *blocks); +void ff_fill_block_tab_16_sse2(uint8_t *block, uint8_t value, ptrdiff_t line_size, int h); +void ff_fill_block_tab_8_sse2(uint8_t *block, uint8_t value, ptrdiff_t line_size, int h); +void ff_fill_block_tab_16_avx2(uint8_t *block, uint8_t value, ptrdiff_t line_size, int h); +void ff_fill_block_tab_8_avx2(uint8_t *block, uint8_t value, ptrdiff_t line_size, int h); + av_cold void ff_blockdsp_init_x86(BlockDSPContext *c) { #if HAVE_X86ASM @@ -38,9 +43,17 @@ av_cold void ff_blockdsp_init_x86(BlockDSPContext *c) c->clear_block = ff_clear_block_sse; c->clear_blocks = ff_clear_blocks_sse; } + if (EXTERNAL_SSE2(cpu_flags)) { + c->fill_block_tab[0] = ff_fill_block_tab_16_sse2; + c->fill_block_tab[1] = ff_fill_block_tab_8_sse2; + } if (EXTERNAL_AVX_FAST(cpu_flags)) { c->clear_block = ff_clear_block_avx; c->clear_blocks = ff_clear_blocks_avx; } + if (EXTERNAL_AVX2(cpu_flags)) { + 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/celt_pvq_init.c b/libavcodec/x86/celt_pvq_init.c index 5a0669e6f..817d00003 100644 --- a/libavcodec/x86/celt_pvq_init.c +++ b/libavcodec/x86/celt_pvq_init.c @@ -23,7 +23,7 @@ #include "libavutil/attributes.h" #include "libavutil/x86/cpu.h" -#include "libavcodec/opus_pvq.h" +#include "libavcodec/opus/pvq.h" extern float ff_pvq_search_approx_sse2(float *X, int *y, int K, int N); extern float ff_pvq_search_approx_sse4(float *X, int *y, int K, int N); diff --git a/libavcodec/x86/celt_pvq_search.asm b/libavcodec/x86/celt_pvq_search.asm index e9bff0265..3c6974d37 100644 --- a/libavcodec/x86/celt_pvq_search.asm +++ b/libavcodec/x86/celt_pvq_search.asm @@ -20,7 +20,6 @@ ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ;****************************************************************************** -%include "config.asm" %include "libavutil/x86/x86util.asm" %ifdef __NASM_VER__ diff --git a/libavcodec/x86/flacdsp.asm b/libavcodec/x86/flacdsp.asm index 4b2fd6543..9fc82ee9a 100644 --- a/libavcodec/x86/flacdsp.asm +++ b/libavcodec/x86/flacdsp.asm @@ -29,7 +29,7 @@ vector: db 0,1,4,5,8,9,12,13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0, SECTION .text -%macro PMACSDQL 5 +%macro PMACSDQL 3 %if cpuflag(xop) pmacsdql %1, %2, %3, %1 %else @@ -38,9 +38,9 @@ SECTION .text %endif %endmacro -%macro LPC_32 1 +%macro LPC_32 3 INIT_XMM %1 -cglobal flac_lpc_32, 5,6,5, decoded, coeffs, pred_order, qlevel, len, j +cglobal flac_lpc_%2, 5,6,5, decoded, coeffs, pred_order, qlevel, len, j sub lend, pred_orderd jle .ret movsxdifnidn pred_orderq, pred_orderd @@ -59,22 +59,22 @@ ALIGN 16 test jq, jq jz .end_order .loop_order: - PMACSDQL m2, m0, m1, m2, m0 + PMACSDQL m2, m0, m1 movd m0, [decodedq+jq*4] - PMACSDQL m3, m1, m0, m3, m1 + PMACSDQL m3, m1, m0 movd m1, [coeffsq+jq*4] inc jq jl .loop_order .end_order: - PMACSDQL m2, m0, m1, m2, m0 - psrlq m2, m4 + PMACSDQL m2, m0, m1 + %3 m2, m4 movd m0, [decodedq] paddd m0, m2 movd [decodedq], m0 sub lend, 2 jl .ret - PMACSDQL m3, m1, m0, m3, m1 - psrlq m3, m4 + PMACSDQL m3, m1, m0 + %3 m3, m4 movd m1, [decodedq+4] paddd m1, m3 movd [decodedq+4], m1 @@ -83,10 +83,60 @@ ALIGN 16 RET %endmacro +LPC_32 sse4, 16, psrad +LPC_32 sse4, 32, psrlq %if HAVE_XOP_EXTERNAL -LPC_32 xop +LPC_32 xop, 32, psrlq %endif -LPC_32 sse4 + +INIT_XMM sse2 +cglobal flac_wasted_32, 3,3,5, decoded, wasted, len + shl lend, 2 + add decodedq, lenq + neg lenq + movd m4, wastedd +ALIGN 16 +.loop: + mova m0, [decodedq+lenq+mmsize*0] + mova m1, [decodedq+lenq+mmsize*1] + mova m2, [decodedq+lenq+mmsize*2] + mova m3, [decodedq+lenq+mmsize*3] + pslld m0, m4 + pslld m1, m4 + pslld m2, m4 + pslld m3, m4 + mova [decodedq+lenq+mmsize*0], m0 + mova [decodedq+lenq+mmsize*1], m1 + mova [decodedq+lenq+mmsize*2], m2 + mova [decodedq+lenq+mmsize*3], m3 + add lenq, mmsize * 4 + jl .loop + RET + +INIT_XMM sse4 +cglobal flac_wasted_33, 4,4,5, decoded, residuals, wasted, len + shl lend, 2 + lea decodedq, [decodedq+lenq*2] + add residualsq, lenq + neg lenq + movd m4, wastedd +ALIGN 16 +.loop: + pmovsxdq m0, [residualsq+lenq+mmsize*0] + pmovsxdq m1, [residualsq+lenq+mmsize/2] + pmovsxdq m2, [residualsq+lenq+mmsize*1] + pmovsxdq m3, [residualsq+lenq+mmsize*1+mmsize/2] + psllq m0, m4 + psllq m1, m4 + psllq m2, m4 + psllq m3, m4 + mova [decodedq+lenq*2+mmsize*0], m0 + mova [decodedq+lenq*2+mmsize*1], m1 + mova [decodedq+lenq*2+mmsize*2], m2 + mova [decodedq+lenq*2+mmsize*3], m3 + add lenq, mmsize * 2 + jl .loop + RET ;---------------------------------------------------------------------------------- ;void ff_flac_decorrelate_[lrm]s_16_sse2(uint8_t **out, int32_t **in, int channels, diff --git a/libavcodec/x86/flacdsp_init.c b/libavcodec/x86/flacdsp_init.c index 87daed700..fa993d346 100644 --- a/libavcodec/x86/flacdsp_init.c +++ b/libavcodec/x86/flacdsp_init.c @@ -23,11 +23,16 @@ #include "libavutil/x86/cpu.h" #include "config.h" +void ff_flac_lpc_16_sse4(int32_t *samples, const int coeffs[32], int order, + int qlevel, int len); void ff_flac_lpc_32_sse4(int32_t *samples, const int coeffs[32], int order, int qlevel, int len); void ff_flac_lpc_32_xop(int32_t *samples, const int coeffs[32], int order, int qlevel, int len); +void ff_flac_wasted_32_sse2(int32_t *decoded, int wasted, int len); +void ff_flac_wasted_33_sse4(int64_t *decoded, const int32_t *residual, int wasted, int len); + #define DECORRELATE_FUNCS(fmt, opt) \ void ff_flac_decorrelate_ls_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \ int len, int shift); \ @@ -61,6 +66,7 @@ av_cold void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE2(cpu_flags)) { + c->wasted32 = ff_flac_wasted_32_sse2; if (fmt == AV_SAMPLE_FMT_S16) { c->decorrelate[1] = ff_flac_decorrelate_ls_16_sse2; c->decorrelate[2] = ff_flac_decorrelate_rs_16_sse2; @@ -93,7 +99,9 @@ av_cold void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int } } if (EXTERNAL_SSE4(cpu_flags)) { + c->lpc16 = ff_flac_lpc_16_sse4; c->lpc32 = ff_flac_lpc_32_sse4; + c->wasted33 = ff_flac_wasted_33_sse4; } if (EXTERNAL_AVX(cpu_flags)) { if (fmt == AV_SAMPLE_FMT_S16) { diff --git a/libavcodec/x86/h264_weight.asm b/libavcodec/x86/h264_weight.asm index 66353d1a9..5524f3e28 100644 --- a/libavcodec/x86/h264_weight.asm +++ b/libavcodec/x86/h264_weight.asm @@ -206,7 +206,7 @@ BIWEIGHT_FUNC_MM 16, 8 cglobal h264_biweight_%1, 7, 8, %2 BIWEIGHT_SETUP movifnidn r3d, r3m - sar r3, 1 + sar r3d, 1 lea r4, [r2*2] .nextrow: BIWEIGHT_STEPA 0, 1, 0 @@ -264,7 +264,7 @@ INIT_XMM ssse3 cglobal h264_biweight_8, 7, 8, 8 BIWEIGHT_SETUP movifnidn r3d, r3m - sar r3, 1 + sar r3d, 1 lea r4, [r2*2] .nextrow: diff --git a/libavcodec/x86/hevcdsp_init.c b/libavcodec/x86/hevcdsp_init.c index f5bc342cd..2c0fca303 100644 --- a/libavcodec/x86/hevcdsp_init.c +++ b/libavcodec/x86/hevcdsp_init.c @@ -26,7 +26,7 @@ #include "libavutil/mem_internal.h" #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #include "libavcodec/x86/hevcdsp.h" #include "libavcodec/x86/h26x/h2656dsp.h" diff --git a/libavcodec/x86/me_cmp_init.c b/libavcodec/x86/me_cmp_init.c index bc1051c27..98b71b189 100644 --- a/libavcodec/x86/me_cmp_init.c +++ b/libavcodec/x86/me_cmp_init.c @@ -94,7 +94,7 @@ static int nsse16_mmx(MpegEncContext *c, const uint8_t *pix1, const uint8_t *pix int score1, score2; if (c) - score1 = c->mecc.sse[0](c, pix1, pix2, stride, h); + 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) diff --git a/libavcodec/x86/mpegvideo.c b/libavcodec/x86/mpegvideo.c index 73967cafd..9878607a8 100644 --- a/libavcodec/x86/mpegvideo.c +++ b/libavcodec/x86/mpegvideo.c @@ -312,8 +312,7 @@ static void dct_unquantize_mpeg2_intra_mmx(MpegEncContext *s, if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; else qscale <<= 1; - if(s->alternate_scan) nCoeffs= 63; //FIXME - 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; @@ -380,8 +379,7 @@ static void dct_unquantize_mpeg2_inter_mmx(MpegEncContext *s, if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; else qscale <<= 1; - if(s->alternate_scan) nCoeffs= 63; //FIXME - else nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; + nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; quant_matrix = s->inter_matrix; __asm__ volatile( diff --git a/libavcodec/x86/mpegvideoenc_template.c b/libavcodec/x86/mpegvideoenc_template.c index 5f013be7f..4096d6391 100644 --- a/libavcodec/x86/mpegvideoenc_template.c +++ b/libavcodec/x86/mpegvideoenc_template.c @@ -99,8 +99,6 @@ static int RENAME(dct_quantize)(MpegEncContext *s, const uint16_t *qmat, *bias; LOCAL_ALIGNED_16(int16_t, temp_block, [64]); - av_assert2((7&(uintptr_t)(&temp_block[0])) == 0); //did gcc align it correctly? - //s->fdct (block); RENAME_FDCT(ff_fdct)(block); // cannot be anything else ... diff --git a/libavcodec/x86/mpegvideoencdsp.asm b/libavcodec/x86/mpegvideoencdsp.asm index 3cbe7b4d4..c73b359c4 100644 --- a/libavcodec/x86/mpegvideoencdsp.asm +++ b/libavcodec/x86/mpegvideoencdsp.asm @@ -24,12 +24,11 @@ %include "libavutil/x86/x86util.asm" SECTION .text -; int ff_pix_sum16(const uint8_t *pix, int line_size) +; int ff_pix_sum16(const uint8_t *pix, ptrdiff_t line_size) ; %1 = number of loops ; %2 = number of GPRs used %macro PIX_SUM16 3 cglobal pix_sum16, 2, %2, 6 - movsxdifnidn r1, r1d mov r2, %1 lea r3, [r1*3] %if notcpuflag(xop) @@ -72,12 +71,11 @@ INIT_XMM xop PIX_SUM16 4, 4, 4 %endif -; int ff_pix_norm1(const uint8_t *pix, int line_size) +; int ff_pix_norm1(const uint8_t *pix, ptrdiff_t line_size) ; %1 = number of xmm registers used ; %2 = number of loops %macro PIX_NORM1 2 cglobal pix_norm1, 2, 3, %1 - movsxdifnidn r1, r1d mov r2, %2 pxor m0, m0 pxor m5, m5 diff --git a/libavcodec/x86/mpegvideoencdsp_init.c b/libavcodec/x86/mpegvideoencdsp_init.c index ec174b15a..d39091a5c 100644 --- a/libavcodec/x86/mpegvideoencdsp_init.c +++ b/libavcodec/x86/mpegvideoencdsp_init.c @@ -23,9 +23,9 @@ #include "libavcodec/avcodec.h" #include "libavcodec/mpegvideoencdsp.h" -int ff_pix_sum16_sse2(const uint8_t *pix, int line_size); -int ff_pix_sum16_xop(const uint8_t *pix, int line_size); -int ff_pix_norm1_sse2(const uint8_t *pix, int line_size); +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 @@ -95,15 +95,13 @@ int ff_pix_norm1_sse2(const uint8_t *pix, int line_size); #undef PHADDD #endif /* HAVE_SSSE3_INLINE */ -/* Draw the edges of width 'w' of an image of size width, height - * this MMX version can only handle w == 8 || w == 16. */ -static void draw_edges_mmx(uint8_t *buf, int wrap, int width, int height, +/* 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) { uint8_t *ptr, *last_line; int i; - last_line = buf + (height - 1) * wrap; /* left and right */ ptr = buf; if (w == 8) { @@ -121,7 +119,7 @@ static void draw_edges_mmx(uint8_t *buf, int wrap, int width, int height, "movq %%mm1, (%0, %2) \n\t" "add %1, %0 \n\t" "cmp %3, %0 \n\t" - "jb 1b \n\t" + "jnz 1b \n\t" : "+r" (ptr) : "r" ((x86_reg) wrap), "r" ((x86_reg) width), "r" (ptr + wrap * height)); @@ -142,7 +140,7 @@ static void draw_edges_mmx(uint8_t *buf, int wrap, int width, int height, "movq %%mm1, 8(%0, %2) \n\t" "add %1, %0 \n\t" "cmp %3, %0 \n\t" - "jb 1b \n\t" + "jnz 1b \n\t" : "+r"(ptr) : "r"((x86_reg)wrap), "r"((x86_reg)width), "r"(ptr + wrap * height) ); @@ -161,52 +159,23 @@ static void draw_edges_mmx(uint8_t *buf, int wrap, int width, int height, "movd %%mm1, (%0, %2) \n\t" "add %1, %0 \n\t" "cmp %3, %0 \n\t" - "jb 1b \n\t" + "jnz 1b \n\t" : "+r" (ptr) : "r" ((x86_reg) wrap), "r" ((x86_reg) width), "r" (ptr + wrap * height)); } - /* top and bottom (and hopefully also the corners) */ - if (sides & EDGE_TOP) { - for (i = 0; i < h; i += 4) { - ptr = buf - (i + 1) * wrap - w; - __asm__ volatile ( - "1: \n\t" - "movq (%1, %0), %%mm0 \n\t" - "movq %%mm0, (%0) \n\t" - "movq %%mm0, (%0, %2) \n\t" - "movq %%mm0, (%0, %2, 2) \n\t" - "movq %%mm0, (%0, %3) \n\t" - "add $8, %0 \n\t" - "cmp %4, %0 \n\t" - "jb 1b \n\t" - : "+r" (ptr) - : "r" ((x86_reg) buf - (x86_reg) ptr - w), - "r" ((x86_reg) - wrap), "r" ((x86_reg) - wrap * 3), - "r" (ptr + width + 2 * w)); - } - } - - if (sides & EDGE_BOTTOM) { - for (i = 0; i < h; i += 4) { - ptr = last_line + (i + 1) * wrap - w; - __asm__ volatile ( - "1: \n\t" - "movq (%1, %0), %%mm0 \n\t" - "movq %%mm0, (%0) \n\t" - "movq %%mm0, (%0, %2) \n\t" - "movq %%mm0, (%0, %2, 2) \n\t" - "movq %%mm0, (%0, %3) \n\t" - "add $8, %0 \n\t" - "cmp %4, %0 \n\t" - "jb 1b \n\t" - : "+r" (ptr) - : "r" ((x86_reg) last_line - (x86_reg) ptr - w), - "r" ((x86_reg) wrap), "r" ((x86_reg) wrap * 3), - "r" (ptr + width + 2 * w)); - } - } + /* top and bottom + corners */ + buf -= w; + last_line = buf + (height - 1) * wrap; + if (sides & EDGE_TOP) + for (i = 0; i < h; i++) + // top + memcpy(buf - (i + 1) * wrap, buf, width + w + w); + if (sides & EDGE_BOTTOM) + for (i = 0; i < h; i++) + // bottom + memcpy(last_line + (i + 1) * wrap, last_line, width + w + w); } #endif /* HAVE_INLINE_ASM */ diff --git a/libavcodec/x86/opusdsp.asm b/libavcodec/x86/opusdsp.asm index 418cc1633..635f59f83 100644 --- a/libavcodec/x86/opusdsp.asm +++ b/libavcodec/x86/opusdsp.asm @@ -22,16 +22,13 @@ SECTION_RODATA - ; 0.85..^1 0.85..^2 0.85..^3 0.85..^4 -tab_st: dd 0x3f599a00, 0x3f38f671, 0x3f1d382a, 0x3f05a32f - SECTION .text INIT_XMM fma3 %if UNIX64 -cglobal opus_deemphasis, 3, 3, 8, out, in, len +cglobal opus_deemphasis, 4, 4, 8, out, in, weights, len %else -cglobal opus_deemphasis, 4, 4, 8, out, in, coeff, len +cglobal opus_deemphasis, 5, 5, 8, out, in, coeff, weights, len %endif %if ARCH_X86_32 VBROADCASTSS m0, coeffm @@ -41,7 +38,7 @@ cglobal opus_deemphasis, 4, 4, 8, out, in, coeff, len shufps m0, m0, 0 %endif - movaps m4, [tab_st] + movaps m4, [weightsq] VBROADCASTSS m5, m4 shufps m6, m4, m4, q1111 shufps m7, m4, m4, q2222 diff --git a/libavcodec/x86/opusdsp_init.c b/libavcodec/x86/opusdsp_init.c index 582fbb4f0..83f7616a2 100644 --- a/libavcodec/x86/opusdsp_init.c +++ b/libavcodec/x86/opusdsp_init.c @@ -20,10 +20,10 @@ #include "libavutil/attributes.h" #include "libavutil/x86/cpu.h" -#include "libavcodec/opusdsp.h" +#include "libavcodec/opus/dsp.h" void ff_opus_postfilter_fma3(float *data, int period, float *gains, int len); -float ff_opus_deemphasis_fma3(float *out, float *in, float coeff, int len); +float ff_opus_deemphasis_fma3(float *out, float *in, float coeff, const float *weights, int len); av_cold void ff_opus_dsp_init_x86(OpusDSP *ctx) { diff --git a/libavcodec/x86/vvc/Makefile b/libavcodec/x86/vvc/Makefile index d1623bd46..aa59aa59c 100644 --- a/libavcodec/x86/vvc/Makefile +++ b/libavcodec/x86/vvc/Makefile @@ -3,5 +3,9 @@ clean:: OBJS-$(CONFIG_VVC_DECODER) += x86/vvc/vvcdsp_init.o \ x86/h26x/h2656dsp.o -X86ASM-OBJS-$(CONFIG_VVC_DECODER) += x86/vvc/vvc_mc.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 \ x86/h26x/h2656_inter.o diff --git a/libavcodec/x86/vvc/vvc_alf.asm b/libavcodec/x86/vvc/vvc_alf.asm new file mode 100644 index 000000000..f69a69f05 --- /dev/null +++ b/libavcodec/x86/vvc/vvc_alf.asm @@ -0,0 +1,876 @@ +;****************************************************************************** +;* VVC Adaptive Loop Filter SIMD optimizations +;* +;* Copyright (c) 2023-2024 Nuo Mi +;* Copyright (c) 2023-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 "libavutil/x86/x86util.asm" + +SECTION_RODATA + +%macro PARAM_SHUFFE 1 +%assign i (%1 * 2) +%assign j ((i + 1) << 8) + (i) +param_shuffe_ %+ %1: +%rep 2 + times 4 dw j + times 4 dw (j + 0x0808) +%endrep +%endmacro + +PARAM_SHUFFE 0 +PARAM_SHUFFE 1 +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 + +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 + +SECTION .text + + +%define ALF_NUM_COEFF_LUMA 12 +%define ALF_NUM_COEFF_CHROMA 6 +%define ALF_NUM_COEFF_CC 7 + +;%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] +%endmacro + +%macro LOAD_LUMA_PARAMS_W16 6 + LOAD_LUMA_PARAMS_W16 %1, %2, %3, %4 + ;m%1 = 03 02 01 00 + ;m%2 = 07 06 05 04 + ;m%3 = 11 10 09 08 + + shufpd m%5, m%1, m%2, 0011b ;06 02 05 01 + shufpd m%6, m%3, m%5, 1001b ;06 10 01 09 + + shufpd m%1, m%1, m%6, 1100b ;06 03 09 00 + shufpd m%2, m%2, m%6, 0110b ;10 07 01 04 + shufpd m%3, m%3, m%5, 0110b ;02 11 05 08 + + vpermpd m%1, m%1, 01111000b ;09 06 03 00 + shufpd m%2, m%2, m%2, 1001b ;10 07 04 01 + vpermpd m%3, m%3, 10000111b ;11 08 05 02 +%endmacro + +; %1-%3 out +; %4 clip or filter +; %5-%6 tmp +%macro LOAD_LUMA_PARAMS 6 + LOAD_LUMA_PARAMS_W16 %1, %2, %3, %4, %5, %6 +%endmacro + +%macro LOAD_CHROMA_PARAMS 4 + ; LOAD_CHROMA_PARAMS_W %+ WIDTH %1, %2, %3, %4 + movq xm%1, [%3q] + movd xm%2, [%3q + 8] + vpbroadcastq m%1, xm%1 + vpbroadcastq m%2, xm%2 +%endmacro + +%macro LOAD_PARAMS 0 +%if LUMA + LOAD_LUMA_PARAMS 3, 4, 5, filter, 6, 7 + LOAD_LUMA_PARAMS 6, 7, 8, clip, 9, 10 +%else + LOAD_CHROMA_PARAMS 3, 4, filter, 5 + LOAD_CHROMA_PARAMS 6, 7, clip, 8 +%endif +%endmacro + +; FILTER(param_idx) +; input: m2, m9, m10 +; output: m0, m1 +; tmp: m11-m13 +%macro FILTER 1 + %assign i (%1 % 4) + %assign j (%1 / 4 + 3) + %assign k (%1 / 4 + 6) + %define filters m %+ j + %define clips m %+ k + + pshufb m12, clips, [param_shuffe_ %+ i] ;clip + pxor m11, m11 + psubw m11, m12 ;-clip + + psubw m9, m2 + CLIPW m9, m11, m12 + + psubw m10, m2 + CLIPW m10, m11, m12 + + punpckhwd m13, m9, m10 + punpcklwd m9, m9, m10 + + pshufb m12, filters, [param_shuffe_ %+ i] ;filter + punpcklwd m10, m12, m12 + punpckhwd m12, m12, m12 + + pmaddwd m9, m10 + pmaddwd m12, m13 + + paddd m0, m9 + paddd m1, m12 +%endmacro + +; FILTER(param_idx, bottom, top, byte_offset) +; input: param_idx, bottom, top, byte_offset +; output: m0, m1 +; temp: m9, m10 +%macro FILTER 4 + LOAD_PIXELS m10, [%2 + %4] + LOAD_PIXELS m9, [%3 - %4] + FILTER %1 +%endmacro + +; GET_SRCS(line) +; brief: get source lines +; input: src, src_stride, vb_pos +; output: s1...s6 +%macro GET_SRCS 1 + lea s1q, [srcq + src_strideq] + lea s3q, [s1q + src_strideq] +%if LUMA + lea s5q, [s3q + src_strideq] +%endif + neg src_strideq + lea s2q, [srcq + src_strideq] + lea s4q, [s2q + src_strideq] +%if LUMA + lea s6q, [s4q + src_strideq] +%endif + neg src_strideq + +%if LUMA + cmp vb_posq, 0 + je %%vb_bottom + cmp vb_posq, 4 + jne %%vb_end +%else + cmp vb_posq, 2 + jne %%vb_end + cmp %1, 2 + jge %%vb_bottom +%endif + +%%vb_above: + ; above + ; 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 + cmove s1q, srcq + cmove s2q, srcq + + dec vb_posq + cmp vb_posq, %1 + cmovbe s3q, s1q + cmovbe s4q, s2q + + dec vb_posq +%if LUMA + cmp vb_posq, %1 + cmovbe s5q, s3q + cmovbe s6q, s4q +%endif + add vb_posq, 3 + jmp %%vb_end + +%%vb_bottom: + ; bottom + ; 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 + cmove s1q, srcq + cmove s2q, srcq + + inc vb_posq + cmp vb_posq, %1 + cmovae s3q, s1q + cmovae s4q, s2q + + inc vb_posq +%if LUMA + cmp vb_posq, %1 + cmovae s5q, s3q + cmovae s6q, s4q +%endif + sub vb_posq, 2 +%%vb_end: +%endmacro + +; SHIFT_VB(line) +; brief: shift filter result +; input: m0, m1, vb_pos +; output: m0 +; temp: m9 +%macro SHIFT_VB 1 +%define SHIFT 7 +%if LUMA + cmp %1, 3 + je %%near_above + cmp %1, 0 + je %%near_below + jmp %%no_vb + %%near_above: + cmp vb_posq, 4 + je %%near_vb + jmp %%no_vb + %%near_below: + cmp vb_posq, 0 + je %%near_vb +%else + cmp %1, 0 + je %%no_vb + cmp %1, 3 + je %%no_vb + cmp vb_posq, 2 + je %%near_vb +%endif +%%no_vb: + psrad m0, SHIFT + psrad m1, SHIFT + jmp %%shift_end +%%near_vb: + vpbroadcastd m9, [dd448] + paddd m0, m9 + paddd m1, m9 + psrad m0, SHIFT + 3 + psrad m1, SHIFT + 3 +%%shift_end: + packssdw m0, m0, m1 +%endmacro + +; FILTER_VB(line) +; brief: filter pixels for luma and chroma +; input: line +; output: m0, m1 +; temp: s0q...s1q +%macro FILTER_VB 1 + vpbroadcastd m0, [dw64] + vpbroadcastd m1, [dw64] + + GET_SRCS %1 +%if LUMA + FILTER 0, s5q, s6q, 0 * ps + FILTER 1, s3q, s4q, 1 * ps + FILTER 2, s3q, s4q, 0 * ps + FILTER 3, s3q, s4q, -1 * ps + FILTER 4, s1q, s2q, 2 * ps + FILTER 5, s1q, s2q, 1 * ps + FILTER 6, s1q, s2q, 0 * ps + FILTER 7, s1q, s2q, -1 * ps + FILTER 8, s1q, s2q, -2 * ps + FILTER 9, srcq, srcq, 3 * ps + FILTER 10, srcq, srcq, 2 * ps + FILTER 11, srcq, srcq, 1 * ps +%else + FILTER 0, s3q, s4q, 0 * ps + FILTER 1, s1q, s2q, 1 * ps + FILTER 2, s1q, s2q, 0 * ps + FILTER 3, s1q, s2q, -1 * ps + FILTER 4, srcq, srcq, 2 * ps + FILTER 5, srcq, srcq, 1 * ps +%endif + SHIFT_VB %1 +%endmacro + +; LOAD_PIXELS(dest, src) +%macro LOAD_PIXELS 2 +%if ps == 2 + movu %1, %2 +%else + pmovzxbw %1, %2 +%endif +%endmacro + +; STORE_PIXELS_W16(dst, src) +%macro STORE_PIXELS_W16 2 + %if ps == 2 + movu [%1], m%2 + %else + movu [%1], xm%2 + %endif +%endmacro + +%macro STORE_PIXELS_W8 2 + %if ps == 2 + movu [%1], xm%2 + %else + movq [%1], xm%2 + %endif +%endmacro + +; STORE_PIXELS_W4(dst, src, offset) +%macro STORE_PIXELS_W4 3 + %if ps == 2 + movq [%1 + %3 * ps], xm%2 + %else + movd [%1 + %3], xm%2 + %endif +%endmacro + +%macro STORE_PIXELS_W8LE 3 + 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 + STORE_PIXELS_W4 %1, %2, 8 + jmp .end +.w4: + STORE_PIXELS_W4 %1, %2, 0 +.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 + + %ifidn %3, 16 + STORE_PIXELS_W16 %1, %2 + %else + %if LUMA + STORE_PIXELS_W8 %1, %2 + %else + STORE_PIXELS_W8LE %1, %2, %3 + %endif + %endif +%endmacro + +%macro FILTER_16x4 1 +%if LUMA + push clipq + push strideq + %define s1q clipq + %define s2q strideq +%else + %define s1q s5q + %define s2q s6q +%endif + + %define s3q pixel_maxq + %define s4q offsetq + push xq + + xor xq, xq +%%filter_16x4_loop: + LOAD_PIXELS m2, [srcq] ;p0 + + FILTER_VB xq + + ; sum += curr + paddsw m0, m2 + + ; clip to pixel + CLIPW m0, m14, m15 + + STORE_PIXELS dstq, 0, %1 + + lea srcq, [srcq + src_strideq] + lea dstq, [dstq + dst_strideq] + inc xq + cmp xq, 4 + jl %%filter_16x4_loop + + mov xq, src_strideq + neg xq + lea srcq, [srcq + xq * 4] + mov xq, dst_strideq + neg xq + lea dstq, [dstq + xq * 4] + + pop xq + +%if LUMA + pop strideq + pop clipq +%endif +%endmacro + +; FILTER(bpc, luma/chroma) +%macro ALF_FILTER 2 +%xdefine BPC %1 +%ifidn %2, luma + %xdefine LUMA 1 +%else + %xdefine LUMA 0 +%endif + +; ****************************** +; 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); +; ****************************** +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 + pxor m14, m14 + +.loop: + push srcq + push dstq + push widthq + xor xq, xq + + .loop_w: + cmp widthq, 16 + jl .loop_w_end + + LOAD_PARAMS + FILTER_16x4 16 + + add srcq, 16 * ps + add dstq, 16 * ps + add xq, 16 + sub widthq, 16 + jmp .loop_w + +.loop_w_end: + cmp widthq, 0 + je .w_end + + LOAD_PARAMS + FILTER_16x4 widthq + +.w_end: + + pop widthq + pop dstq + pop srcq + 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 + jg .loop + RET +%endmacro + +; FILTER(bpc) +%macro ALF_FILTER 1 + ALF_FILTER %1, luma + ALF_FILTER %1, chroma +%endmacro + +%define ALF_GRADIENT_BORDER 2 +%define ALF_BORDER_LUMA 3 + +; ****************************** +; void ff_vvc_alf_classify_grad(int *gradient_sum, const uint8_t *src, +; ptrdiff_t src_stride, intptr_t width, intptr_t height, intptr_t vb_pos); +; ****************************** +%macro ALF_CLASSIFY_GRAD 1 +cglobal vvc_alf_classify_grad_%1bpc, 6, 14, 16, gradient_sum, src, src_stride, width, height, vb_pos, \ + x, y, s0, s1, s2, s3, vb_pos_below, src_stride3 + + lea src_stride3q, [src_strideq * 2 + src_strideq] + + lea vb_pos_belowd, [vb_posd + ALF_GRADIENT_BORDER] + + ; src = src - ALF_BORDER_LUMA * src_stride - ALF_BORDER_LUMA + sub srcq, src_stride3q + sub srcq, ALF_BORDER_LUMA * ps + + add widthd, ALF_GRADIENT_BORDER * 2 + add heightd, ALF_GRADIENT_BORDER * 2 + + xor yd, yd + +.loop_h: + xor xd, xd + pxor m15, m15 ; prev + .loop_w: + lea s0q, [srcq + xq * ps] + lea s1q, [s0q + src_strideq] + lea s2q, [s0q + 2 * src_strideq] + lea s3q, [s0q + src_stride3q] + + cmp yd, vb_pos_belowd + cmove s0q, s1q + + cmp yd, vb_posd + cmove s3q, s2q + + LOAD_PIXELS m0, [s0q] + LOAD_PIXELS m1, [s1q] + LOAD_PIXELS m2, [s2q] + LOAD_PIXELS m3, [s3q] + + LOAD_PIXELS m4, [s0q + 2 * ps] + LOAD_PIXELS m5, [s1q + 2 * ps] + LOAD_PIXELS m6, [s2q + 2 * ps] + LOAD_PIXELS m7, [s3q + 2 * ps] + + pblendw m8, m0, m1, 0xaa ; nw + pblendw m9, m0, m5, 0x55 ; n + pblendw m10, m4, m5, 0xaa ; ne + pblendw m11, m1, m2, 0xaa ; w + pblendw m12, m5, m6, 0xaa ; e + pblendw m13, m2, m3, 0xaa ; sw + pblendw m14, m2, m7, 0x55 ; s + + pblendw m0, m1, m6, 0x55 + paddw m0, m0 ; c + + movu m1, [CLASSIFY_SHUFFE] + pshufb m1, m0, m1 ; d + + paddw m9, m14 ; n + s + psubw m9, m0 ; (n + s) - c + pabsw m9, m9 ; ver + + paddw m11, m12 ; w + e + psubw m11, m1 ; (w + e) - d + pabsw m11, m11 ; hor + + pblendw m14, m6, m7, 0xaa ; se + paddw m8, m14 ; nw + se + psubw m8, m1 ; (nw + se) - d + pabsw m8, m8 ; di0 + + paddw m10, m13 ; ne + sw + psubw m10, m1 ; (nw + se) - d + pabsw m10, m10 ; di1 + + phaddw m9, m11 ; vh, each word represent 2x2 pixels + phaddw m8, m10 ; di, each word represent 2x2 pixels + phaddw m0, m9, m8 ; all = each word represent 4x2 pixels, order is v_h_d0_d1 x 4 + + vinserti128 m15, m15, xm0, 1 + pblendw m1, m0, m15, 0xaa ; t + + phaddw m1, m0 ; each word represent 8x2 pixels, adjacent word share 4x2 pixels + + vextracti128 xm15, m0, 1 ; prev + + movu [gradient_sumq], m1 + + add gradient_sumq, 32 + add xd, 16 + cmp xd, widthd + jl .loop_w + + lea srcq, [srcq + 2 * src_strideq] + add yd, 2 + cmp yd, heightd + jl .loop_h + RET +%endmacro + +; SAVE_CLASSIFY_PARAM_W16(dest, src) +%macro SAVE_CLASSIFY_PARAM_W16 2 + lea tempq, [%1q + xq] + movu [tempq], xm%2 + vperm2i128 m%2, m%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 +%endmacro + +; SAVE_CLASSIFY_PARAM_W4 +%macro SAVE_CLASSIFY_PARAM_W4 2 + movd [%1], xm%2 + vperm2i128 m%2, m%2, m%2, 1 + movd [%1 + widthq], xm%2 +%endmacro + +; SAVE_CLASSIFY_PARAM_W(dest, src) +%macro SAVE_CLASSIFY_PARAM_W 2 + lea tempq, [%1q + xq] + 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 +%%w4: + SAVE_CLASSIFY_PARAM_W4 tempq, %2 +%%end: +%endmacro + +%macro ALF_CLASSIFY_H8 0 + ; first line, sum of 16x4 pixels (includes borders) + lea gradq, [gradient_sumq + 2 * xq] + movu m0, [gradq] + 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 + + vpbroadcastd m14, [dw3] + pblendvb m14, m14, [dd2], m13 ; ac + + pblendvb m3, m15, [gradq + sum_stride3q], m13 + + ; extent to dword to avoid overflow + punpcklwd m4, m0, m15 + punpckhwd m5, m0, m15 + punpcklwd m6, m1, m15 + punpckhwd m7, m1, m15 + punpcklwd m8, m2, m15 + punpckhwd m9, m2, m15 + punpcklwd m10, m3, m15 + punpckhwd m11, m3, m15 + + paddd m0, m4, m6 + paddd m1, m5, m7 + paddd m2, m8, m10 + paddd m3, m9, m11 + + ; sum of the first row + paddd m0, m2 ; low + paddd m1, m3 ; high + + lea gradq, [gradq + 2 * sum_strideq] + + pblendvb m10, m15, [gradq], m13 + + movu m11, [gradq + sum_strideq] + movu m12, [gradq + 2 * sum_strideq] + movu m13, [gradq + sum_stride3q] + + punpcklwd m4, m10, m15 + punpckhwd m5, m10, m15 + punpcklwd m6, m11, m15 + punpckhwd m7, m11, m15 + punpcklwd m8, m12, m15 + punpckhwd m9, m12, m15 + punpcklwd m10, m13, m15 + punpckhwd m11, m13, m15 + + paddd m2, m4, m6 + paddd m3, m5, m7 + paddd m4, m8, m10 + paddd m5, m9, m11 + + ; sum of the second row + paddd m2, m4 ; low + paddd m3, m5 ; high + + punpckldq m4, m0, m2 + punpckhdq m5, m0, m2 + punpckldq m6, m1, m3 + punpckhdq m7, m1, m3 + + ; each dword represent 4x2 alf blocks + ; the order is 01452367 + punpckldq m0, m4, m6 ; sum_v + punpckhdq m1, m4, m6 ; sum_h + punpckldq m2, m5, m7 ; sum_d0 + punpckhdq m3, m5, m7 ; sum_d1 + + pcmpgtd m4, m0, m1 ; dir_hv - 1 + pmaxsd m5, m0, m1 ; hv1 + pminsd m6, m0, m1 ; hv0 + + paddd m0, m1; ; sum_hv + + pcmpgtd m7, m2, m3 ; dir_d - 1 + pmaxsd m8, m2, m3 ; d1 + pminsd m9, m2, m3 ; d0 + + ; *transpose_idx = dir_d * 2 + dir_hv; + vpbroadcastd m10, [dw3] + paddd m11, m7, m7 + paddd m11, m4 + paddd m10, m11 + vpermq m10, m10, 11011000b + SAVE_CLASSIFY_PARAM transpose_idx, 10 + + psrlq m10, m8, 32 + psrlq m11, m6, 32 + pmuldq m12, m10, m11 ; d1 * hv0 high + psrlq m1, m9, 32 + psrlq m2, m5, 32 + pmuldq m3, m1, m2 ; d0 * hv1 high + pcmpgtq m10, m12, m3 ; dir1 - 1 high + + pmuldq m1, m8, m6 ; d1 * hv0 low + pmuldq m2, m9, m5 ; d0 * hv1 low + pcmpgtq m1, m2 ; dir1 - 1 low + + vpblendd m1, m1, m10, 0xaa ; dir1 - 1 + + pblendvb m2, m5, m8, m1 ; hvd1 + pblendvb m3, m6, m9, m1 ; hvd0 + + movd xm5, bit_depthd + vpbroadcastd m5, xm5 + + ;*class_idx = arg_var[av_clip_uintp2(sum_hv * ac >> (BIT_DEPTH - 1), 4)]; + pmulld m0, m14 ; sum_hv * ac + vpsrlvd m0, m0, m5 + pminsd m0, [dd15] + movu m6, [ARG_VAR_SHUFFE] + pshufb m6, m0 ; class_idx + + vpbroadcastd m10, [dw5] + + ; if (hvd1 * 2 > 9 * hvd0) + ; *class_idx += ((dir1 << 1) + 2) * 5; + ; else if (hvd1 > 2 * hvd0) + ; *class_idx += ((dir1 << 1) + 1) * 5; + paddd m7, m3, m3 + pcmpgtd m7, m2, m7 ; hvd1 > 2 * hvd0 + pand m7, m10 + paddd m6, m7 ; class_idx + + paddd m8, m2, m2 + pslld m9, m3, 3 + paddd m9, m3 + pcmpgtd m8, m9 ; hvd1 * 2 > 9 * hvd0 + pand m8, m10 + paddd m6, m8 ; class_idx + + pandn m1, m7 + paddd m1, m1 ; dir1 << 1 + paddd m6, m1 ; class_idx + vpermq m6, m6, 11011000b + + SAVE_CLASSIFY_PARAM class_idx, 6 +%endmacro + +%macro ALF_CLASSIFY_16x8 0 +%define SAVE_CLASSIFY_PARAM SAVE_CLASSIFY_PARAM_W16 + ALF_CLASSIFY_H8 +%undef SAVE_CLASSIFY_PARAM +%endmacro + +%macro ALF_CLASSIFY_Wx8 0 +%define SAVE_CLASSIFY_PARAM SAVE_CLASSIFY_PARAM_W + ALF_CLASSIFY_H8 +%undef SAVE_CLASSIFY_PARAM +%endmacro + +; ****************************** +;void ff_vvc_alf_classify(int *class_idx, int *transpose_idx, const int *gradient_sum, +; intptr_t width, intptr_t height, intptr_t vb_pos, int *gradient_tmp, intptr_t bit_depth); +; ****************************** +%macro ALF_CLASSIFY 1 +%define ps (%1 / 8) +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 + + ; now we can use gradient to get class idx and transpose idx + lea sum_strideq, [widthd + ALF_GRADIENT_BORDER * 2] + add sum_strideq, 15 + and sum_strideq, ~15 ; align to 16 + add sum_strideq, sum_strideq ; two rows a time + + add gradient_sumq, 8 ; first 4 words are garbage + + lea sum_stride3q, [3 * sum_strideq] + + xor yd, yd + and vb_posd, ~7 ; floor align to 8 + pxor m15, m15 + +.loop_sum_h: + xor xd, xd + .loop_sum_w16: + lea wd, [widthd] + sub wd, xd + cmp wd, 16 + jl .loop_sum_w16_end + + ALF_CLASSIFY_16x8 + + add xd, 16 + jmp .loop_sum_w16 + .loop_sum_w16_end: + + cmp wd, 0 + je .loop_sum_w_end + + ALF_CLASSIFY_Wx8 + +.loop_sum_w_end: + lea gradient_sumq, [gradient_sumq + 4 * sum_strideq] + lea transpose_idxq, [transpose_idxq + 2 * widthq] + lea class_idxq, [class_idxq + 2 * widthq] + + add yd, 8 + cmp yd, heightd + jl .loop_sum_h + + RET +%endmacro + +%if ARCH_X86_64 +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +ALF_FILTER 16 +ALF_FILTER 8 +ALF_CLASSIFY 16 +ALF_CLASSIFY 8 +%endif +%endif diff --git a/libavcodec/x86/vvc/vvc_dmvr.asm b/libavcodec/x86/vvc/vvc_dmvr.asm new file mode 100644 index 000000000..4c971f970 --- /dev/null +++ b/libavcodec/x86/vvc/vvc_dmvr.asm @@ -0,0 +1,373 @@ +; /* +; * Provide AVX2 luma dmvr functions for VVC decoding +; * 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 "libavutil/x86/x86util.asm" + +%define MAX_PB_SIZE 128 + +SECTION_RODATA 32 + +shift_12 times 2 dw 1 << (15 - (12 - 10)) +shift3_8 times 2 dw 1 << (15 - (8 - 6)) +shift3_10 times 2 dw 1 << (15 - (10 - 6)) +shift3_12 times 2 dw 1 << (15 - (12 - 6)) +pw_16 times 2 dw 16 + +%if ARCH_X86_64 + +%if HAVE_AVX2_EXTERNAL + +SECTION .text + +%define pstride (bd / 10 + 1) + +; LOAD(dst, src) +%macro LOAD_W16 2 +%if bd == 8 + pmovzxbw %1, %2 +%else + movu %1, %2 +%endif +%endmacro + +%macro SHIFT_W16 2 +%if bd == 8 + psllw %1, (10 - bd) +%elif bd == 10 + ; nothing +%else + pmulhrsw %1, %2 +%endif +%endmacro + +%macro SAVE_W16 2 + movu %1, %2 +%endmacro + +; NEXT_4_LINES(is_h) +%macro NEXT_4_LINES 1 + lea dstq, [dstq + dsq*4] + lea srcq, [srcq + ssq*4] +%if %1 + lea src1q, [srcq + pstride] +%endif +%endmacro + + +; DMVR_4xW16(dst, dst_stride, dst_stride3, src, src_stride, src_stride3) +%macro DMVR_4xW16 6 + LOAD_W16 m0, [%4] + LOAD_W16 m1, [%4 + %5] + LOAD_W16 m2, [%4 + 2 * %5] + LOAD_W16 m3, [%4 + %6] + + SHIFT_W16 m0, m4 + SHIFT_W16 m1, m4 + SHIFT_W16 m2, m4 + SHIFT_W16 m3, m4 + + SAVE_W16 [%1] , m0 + SAVE_W16 [%1 + %2] , m1 + SAVE_W16 [%1 + 2 * %2], m2 + SAVE_W16 [%1 + %3] , m3 +%endmacro + +; buf += -stride * h + off +; OFFSET_TO_W4(buf, stride, off) +%macro OFFSET_TO_W4 3 + mov id, hd + imul iq, %2 + sub %1, iq + lea %1, [%1 + %3] +%endmacro + +%macro OFFSET_TO_W4 0 + OFFSET_TO_W4 srcq, ssq, 16 * (bd / 10 + 1) + OFFSET_TO_W4 dstq, dsq, 16 * 2 +%endmacro + +; void ff_vvc_dmvr_%1_avx2(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, +; int height, intptr_t mx, intptr_t my, int width); +%macro DMVR_AVX2 1 +cglobal vvc_dmvr_%1, 4, 9, 5, dst, src, ss, h, ds, ds3, w, ss3, i +%define bd %1 + + LOAD_STRIDES + +%if %1 > 10 + vpbroadcastd m4, [shift_%1] +%endif + + mov wd, wm + mov id, hd +.w16: + sub id, 4 + jl .w16_end + DMVR_4xW16 dstq, dsq, ds3q, srcq, ssq, ss3q + NEXT_4_LINES 0 + jmp .w16 +.w16_end: + + sub wd, 16 + jl .w4_end + + OFFSET_TO_W4 +.w4: + sub hd, 4 + jl .w4_end + DMVR_4xW16 dstq, dsq, ds3q, srcq, ssq, ss3q + NEXT_4_LINES 0 + jmp .w4 +.w4_end: + + RET +%endmacro + +; LOAD_COEFFS(coeffs0, coeffs1, src) +%macro LOAD_COEFFS 3 + movd xm%2, %3 + vpbroadcastw m%2, xm%2 + vpbroadcastd m%1, [pw_16] + psubw m%1, m%2 +%endmacro + +; LOAD_SHIFT(shift, src) +%macro LOAD_SHIFT 2 + vpbroadcastd %1, [%2] +%if bd == 12 + psllw %1, 1 ; avoid signed mul for pmulhrsw +%endif +%endmacro + +; LOAD_STRIDES(shift, src) +%macro LOAD_STRIDES 0 + mov dsq, MAX_PB_SIZE * 2 + lea ss3q, [ssq*3] + lea ds3q, [dsq*3] +%endmacro + +; BILINEAR(dst/src0, src1, coeff0, coeff1, round, tmp) +%macro BILINEAR 6 + pmullw %1, %3 + pmullw %6, %2, %4 + paddw %1, %6 +%if bd == 12 + psrlw %1, 1 ; avoid signed mul for pmulhrsw +%endif + pmulhrsw %1, %5 +%endmacro + +; DMVR_H_1xW16(dst, src0, src1, offset, tmp) +%macro DMVR_H_1xW16 5 + LOAD_W16 %1, [%2 + %4] + LOAD_W16 %5, [%3 + %4] + BILINEAR %1, %5, m10, m11, m12, %5 +%endmacro + +; DMVR_H_4xW16(dst, dst_stride, dst_stride3, src, src_stride, src_stride3, src1) +%macro DMVR_H_4xW16 7 + DMVR_H_1xW16 m0, %4, %7, 0, m4 + DMVR_H_1xW16 m1, %4, %7, %5, m5 + DMVR_H_1xW16 m2, %4, %7, 2 * %5, m6 + DMVR_H_1xW16 m3, %4, %7, %6, m7 + + SAVE_W16 [%1] , m0 + SAVE_W16 [%1 + %2] , m1 + SAVE_W16 [%1 + 2 * %2], m2 + SAVE_W16 [%1 + %3] , m3 +%endmacro + +; void ff_vvc_dmvr_h_%1_avx2(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, +; int height, intptr_t mx, intptr_t my, int width); +%macro DMVR_H_AVX2 1 +cglobal vvc_dmvr_h_%1, 4, 10, 13, dst, src, ss, h, ds, ds3, w, ss3, src1, i +%define bd %1 + + LOAD_COEFFS 10, 11, dsm + LOAD_SHIFT m12, shift3_%1 + + LOAD_STRIDES + lea src1q, [srcq + pstride] + + mov wd, wm + mov id, hd +.w16: + sub id, 4 + jl .w16_end + DMVR_H_4xW16 dstq, dsq, ds3q, srcq, ssq, ss3q, src1q + NEXT_4_LINES 1 + jmp .w16 +.w16_end: + + sub wd, 16 + jl .w4_end + + OFFSET_TO_W4 + lea src1q, [srcq + pstride] +.w4: + sub hd, 4 + jl .w4_end + DMVR_H_4xW16 dstq, dsq, ds3q, srcq, ssq, ss3q, src1q + NEXT_4_LINES 1 + jmp .w4 +.w4_end: + + RET +%endmacro + +; DMVR_V_4xW16(dst, dst_stride, dst_stride3, src, src_stride, src_stride3) +%macro DMVR_V_4xW16 6 + LOAD_W16 m1, [%4 + %5] + LOAD_W16 m2, [%4 + 2 * %5] + LOAD_W16 m3, [%4 + %6] + LOAD_W16 m4, [%4 + 4 * %5] + + BILINEAR m0, m1, m8, m9, m10, m11 + BILINEAR m1, m2, m8, m9, m10, m12 + BILINEAR m2, m3, m8, m9, m10, m13 + BILINEAR m3, m4, m8, m9, m10, m14 + + SAVE_W16 [%1] , m0 + SAVE_W16 [%1 + %2] , m1 + SAVE_W16 [%1 + 2 * %2], m2 + SAVE_W16 [%1 + %3] , m3 + + ; why can't we use SWAP m0, m4 here? + movaps m0, m4 +%endmacro + +; void ff_vvc_dmvr_v_%1_avx2(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, +; int height, intptr_t mx, intptr_t my, int width); +%macro DMVR_V_AVX2 1 +cglobal vvc_dmvr_v_%1, 4, 9, 15, dst, src, ss, h, ds, ds3, w, ss3, i +%define bd %1 + + LOAD_COEFFS 8, 9, ds3m + LOAD_SHIFT m10, shift3_%1 + + LOAD_STRIDES + + mov wd, wm + mov id, hd + LOAD_W16 m0, [srcq] +.w16: + sub id, 4 + jl .w16_end + DMVR_V_4xW16 dstq, dsq, ds3q, srcq, ssq, ss3q + NEXT_4_LINES 0 + jmp .w16 +.w16_end: + + sub wd, 16 + jl .w4_end + + OFFSET_TO_W4 + LOAD_W16 m0, [srcq] +.w4: + sub hd, 4 + jl .w4_end + DMVR_V_4xW16 dstq, dsq, ds3q, srcq, ssq, ss3q + NEXT_4_LINES 0 + jmp .w4 +.w4_end: + + RET +%endmacro + +; DMVR_HV_4xW16(dst, dst_stride, dst_stride3, src, src_stride, src_stride3, src1) +%macro DMVR_HV_4xW16 7 + DMVR_H_1xW16 m1, %4, %7, %5, m6 + DMVR_H_1xW16 m2, %4, %7, 2 * %5, m7 + DMVR_H_1xW16 m3, %4, %7, %6, m8 + DMVR_H_1xW16 m4, %4, %7, 4 * %5, m9 + + BILINEAR m0, m1, m13, m14, m15, m6 + BILINEAR m1, m2, m13, m14, m15, m7 + BILINEAR m2, m3, m13, m14, m15, m8 + BILINEAR m3, m4, m13, m14, m15, m9 + + SAVE_W16 [%1] , m0 + SAVE_W16 [%1 + %2] , m1 + SAVE_W16 [%1 + 2 * %2], m2 + SAVE_W16 [%1 + %3] , m3 + + ; why can't we use SWAP m0, m4 here? + movaps m0, m4 +%endmacro + +; void ff_vvc_dmvr_hv_%1_avx2(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, +; int height, intptr_t mx, intptr_t my, int width); +%macro DMVR_HV_AVX2 1 +cglobal vvc_dmvr_hv_%1, 7, 10, 16, dst, src, ss, h, ds, ds3, w, ss3, src1, i +%define bd %1 + + LOAD_COEFFS 10, 11, dsm + LOAD_SHIFT m12, shift3_%1 + + LOAD_COEFFS 13, 14, ds3m + LOAD_SHIFT m15, shift3_10 + + LOAD_STRIDES + lea src1q, [srcq + pstride] + + mov id, hd + DMVR_H_1xW16 m0, srcq, src1q, 0, m5 +.w16: + sub id, 4 + jl .w16_end + DMVR_HV_4xW16 dstq, dsq, ds3q, srcq, ssq, ss3q, src1q + NEXT_4_LINES 1 + jmp .w16 +.w16_end: + + sub wd, 16 + jl .w4_end + + OFFSET_TO_W4 + lea src1q, [srcq + pstride] + + DMVR_H_1xW16 m0, srcq, src1q, 0, m5 +.w4: + sub hd, 4 + jl .w4_end + DMVR_HV_4xW16 dstq, dsq, ds3q, srcq, ssq, ss3q, src1q + NEXT_4_LINES 1 + jmp .w4 +.w4_end: + + RET +%endmacro + +%macro VVC_DMVR_AVX2 1 + DMVR_AVX2 %1 + DMVR_H_AVX2 %1 + DMVR_V_AVX2 %1 + DMVR_HV_AVX2 %1 +%endmacro + +INIT_YMM avx2 + +VVC_DMVR_AVX2 8 +VVC_DMVR_AVX2 10 +VVC_DMVR_AVX2 12 + +%endif ; HAVE_AVX2_EXTERNAL + +%endif ; ARCH_X86_64 diff --git a/libavcodec/x86/vvc/vvc_of.asm b/libavcodec/x86/vvc/vvc_of.asm new file mode 100644 index 000000000..5893bfb23 --- /dev/null +++ b/libavcodec/x86/vvc/vvc_of.asm @@ -0,0 +1,385 @@ +; /* +; * Provide AVX2 luma optical flow functions for VVC decoding +; * 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 "libavutil/x86/x86util.asm" + +%define MAX_PB_SIZE 128 +%define SRC_STRIDE (MAX_PB_SIZE * 2) +%define SRC_PS 2 ; source pixel size, sizeof(int16_t) +%define BDOF_STACK_SIZE 10 ; (4 + 1) * 2, 4 lines + the first line, *2 for h and v +%define bdof_stack_offset(line) ((line) * 2 % BDOF_STACK_SIZE * mmsize) +%define SHIFT 6 +%define SHIFT2 4 + +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 +%if ARCH_X86_64 + +%if HAVE_AVX2_EXTERNAL + +SECTION .text + +INIT_YMM avx2 + +; dst = (src0 >> shift) - (src1 >> shift) +%macro DIFF 5 ; dst, src0, src1, shift, tmp + psraw %1, %2, %4 + psraw %5, %3, %4 + psubw %1, %5 +%endmacro + +%macro LOAD_GRAD_H 4 ; dst, src, off, tmp + movu %1, [%2 + %3 + 2 * SRC_PS] + movu %4, [%2 + %3] + + DIFF %1, %1, %4, SHIFT, %4 +%endmacro + +%macro SUM_GRAD 2 ;(dst/grad0, grad1) + paddw %1, %2 + psraw %1, 1 ; shift3 +%endmacro + +%macro APPLY_BDOF_MIN_BLOCK_LINE 5 ; dst, vx, vy, tmp, line_num +%define off bdof_stack_offset(%5) + pmullw %1, %2, [rsp + off + 0 * mmsize] ; vx * (gradient_h[0] - gradient_h[1]) + pmullw %4, %3, [rsp + off + 1 * mmsize] ; vy * (gradient_v[0] - gradient_v[1]) + paddw %1, [src0q + (%5 + 1) * SRC_STRIDE + SRC_PS] + 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 + cmp pixel_maxd, (1 << 8) - 1 + jne %%save_16bpc + SAVE_8BPC %1, %2 + jmp %%end +%%save_16bpc: + SAVE_16BPC %1, %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 + pxor m9, m9 + + movd xm10, pixel_maxd + vpbroadcastw m10, xm10 + + lea tmp0d, [pixel_maxd + 1] + movd xm11, tmp0d + VPBROADCASTW m11, xm11 ;shift_4 for pmulhrsw + + APPLY_BDOF_MIN_BLOCK_LINE m6, %2, %3, m7, (%1) * 4 + 0 + SAVE [dstq + 0 * dsq], 6 + + APPLY_BDOF_MIN_BLOCK_LINE m6, %2, %3, m7, (%1) * 4 + 1 + SAVE [dstq + 1 * dsq], 6 + + APPLY_BDOF_MIN_BLOCK_LINE m6, %2, %3, m7, (%1) * 4 + 2 + SAVE [dstq + 2 * dsq], 6 + + APPLY_BDOF_MIN_BLOCK_LINE m6, %2, %3, m7, (%1) * 4 + 3 + SAVE [dstq + ds3q], 6 +%endmacro + +%macro SUM_MIN_BLOCK_W16 4 ; src/dst, shuffle, perm, tmp + pshufb %4, %1, %2 + vpermd %4, %3, %4 + paddw %1, %4 +%endmacro + +%macro SUM_MIN_BLOCK_W8 3 ; src/dst, shuffle, tmp + pshufb %3, %1, %2 + paddw %1, %3 +%endmacro + +%macro BDOF_PROF_GRAD 2 ; line_no, last_line +%assign i0 (%1 + 0) % 3 +%assign j0 (%1 + 1) % 3 +%assign k0 (%1 + 2) % 3 +%assign i1 3 + (%1 + 0) % 3 +%assign j1 3 + (%1 + 1) % 3 +%assign k1 3 + (%1 + 2) % 3 + +; we cached src0 in m0 to m2 +%define t0 m %+ i0 +%define c0 m %+ j0 +%define b0 m %+ k0 + +; we cached src1 in m3 to m5 +%define t1 m %+ i1 +%define c1 m %+ j1 +%define b1 m %+ k1 +%define ndiff t1 +%define off bdof_stack_offset(%1) + + movu b0, [src0q + (%1 + 2) * SRC_STRIDE + SRC_PS] + movu b1, [src1q + (%1 + 2) * SRC_STRIDE + SRC_PS] + + ; gradient_v[0], gradient_v[1] + DIFF m6, b0, t0, SHIFT, t0 + DIFF m7, b1, t1, SHIFT, t1 + + ; save gradient_v[0] - gradient_v[1] + psubw m10, m6, m7 + mova [rsp + off + mmsize], m10 + + ; gradient_h[0], gradient_h[1] + LOAD_GRAD_H m8, src0q, (%1 + 1) * SRC_STRIDE, t0 + LOAD_GRAD_H m9, src1q, (%1 + 1) * SRC_STRIDE, t1 + + ; save gradient_h[0] - gradient_h[1] + psubw m11, m8, m9 + mova [rsp + off], m11 + + SUM_GRAD m8, m9 ; temph + SUM_GRAD m6, m7 ; tempv + + DIFF ndiff, c1, c0, SHIFT2, t0 ; -diff + + psignw m7, ndiff, m8 ; sgxdi + psignw m9, ndiff, m6 ; sgydi + psignw m10, m8, m6 ; sgxgy + + 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 + SUM_MIN_BLOCK_W8 m9, t0, m11 + SUM_MIN_BLOCK_W8 m10, t0, m11 + 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 + SUM_MIN_BLOCK_W16 m8, t0, t1, m11 + SUM_MIN_BLOCK_W16 m9, t0, t1, m11 + SUM_MIN_BLOCK_W16 m10, t0, t1, m11 + +%%wend: + vpblendd m11, m8, m7, 10101010b + vpblendd m7, m8, m7, 01010101b + pshufd m7, m7, q2301 + paddw m8, m7, m11 ;4 x (2sgx2, 2sgxdi) + + vpblendd m11, m6, m9, 10101010b + vpblendd m9, m6, m9, 01010101b + pshufd m9, m9, q2301 + paddw m6, m9, m11 ;4 x (2sgy2, 2sgydi) + + vpblendw m11, m8, m6, 10101010b + vpblendw m6, m8, m6, 01010101b + pshuflw m6, m6, q2301 + pshufhw m6, m6, q2301 + paddw m8, m6, m11 ; 4 x (4sgx2, 4sgy2, 4sgxdi, 4sgydi) + +%if (%1) == 0 || (%2) + ; pad for top and bottom + paddw m8, m8 + paddw m10, m10 +%endif + + paddw m12, m8 + paddw m13, m10 +%endmacro + + +%macro LOG2 5 ; log_sum, src, cmp, shift, tmp + pcmpgtw %5, %2, %3 + pandd %5, %4 + paddw %1, %5 + + psrlw %2, %5 + psrlw %4, 1 + psrlw %3, %4 +%endmacro + +%macro LOG2 2 ; dst/src, offset + pextrw tmp0d, xm%1, %2 + bsr tmp0d, tmp0d + pinsrw xm%1, tmp0d, %2 +%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 +%endmacro + +; %1: 4 (sgx2, sgy2, sgxdi, gydi) +; %2: 4 (4sgxgy) +%macro BDOF_VX_VY 2 ; + pshufd m6, m%1, q0032 + punpckldq m%1, m6 + vextracti128 xm7, m%1, 1 + + 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)) + + ; Promote to dword since vpsrlvw is AVX-512 only + pmovsxwd m8, xm8 + pmovsxwd m9, xm9 + pmovsxwd m10, xm10 + + pslld m9, 2 ; 4 (log2(sgx2) << 2, log2(sgy2) << 2) + + psignd m11, m9, m8 + vpsravd m11, m11, m10 + CLIPD m11, [pd_m15], [pd_15] ; 4 (vx, junk) + + pshuflw m%1, m11, q0000 + pshufhw m%1, m%1, q0000 ; 4 (2junk, 2vx) + + psllq m6, m%2, 32 + paddw m%2, m6 + + pmaddwd m%2, m%1 ; 4 (junk, vx * sgxgy) + psrad m%2, 1 + psubd m9, m%2 ; 4 (junk, (sgydi << 2) - (vx * sgxgy >> 1)) + + psignd m9, m8 + vpsravd m%2, m9, m10 + CLIPD m%2, [pd_m15], [pd_15] ; 4 (junk, vy) + + pshuflw m%2, m%2, q2222 + pshufhw m%2, m%2, q2222 ; 4 (4vy) +%endmacro + + +%macro BDOF_MINI_BLOCKS 2 ; (block_num, last_block) + +%if (%1) == 0 + movu m0, [src0q + 0 * SRC_STRIDE + SRC_PS] + movu m1, [src0q + 1 * SRC_STRIDE + SRC_PS] + 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 + + 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 + 4, 0 +%endif + paddw m14, m12 + paddw m15, m13 + + BDOF_VX_VY 14, 15 + APPLY_BDOF_MIN_BLOCK %1, m14, m15, bd + lea dstq, [dstq + 4 * dsq] +%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 + + lea ds3q, [dsq * 3] + sub src0q, SRC_STRIDE + SRC_PS + sub src1q, SRC_STRIDE + SRC_PS + + BDOF_MINI_BLOCKS 0, 0 + + cmp hd, 16 + je .h16 + BDOF_MINI_BLOCKS 1, 1 + jmp .end + +.h16: + BDOF_MINI_BLOCKS 1, 0 + BDOF_MINI_BLOCKS 2, 0 + BDOF_MINI_BLOCKS 3, 1 + +.end: + RET +%endmacro + +%macro VVC_OF_AVX2 0 + BDOF_AVX2 +%endmacro + +VVC_OF_AVX2 + +%endif ; HAVE_AVX2_EXTERNAL + +%endif ; ARCH_X86_64 diff --git a/libavcodec/x86/vvc/vvc_sad.asm b/libavcodec/x86/vvc/vvc_sad.asm new file mode 100644 index 000000000..982951a37 --- /dev/null +++ b/libavcodec/x86/vvc/vvc_sad.asm @@ -0,0 +1,134 @@ +; /* +; * Provide SIMD DMVR SAD functions for VVC decoding +; * +; * Copyright (c) 2024 Stone Chen +; * +; * This file is part of FFmpeg. +; * +; * FFmpeg is free software; you can redistribute it and/or +; * modify it under the terms of the GNU Lesser General Public +; * License as published by the Free Software Foundation; either +; * version 2.1 of the License, or (at your option) any later version. +; * +; * FFmpeg is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; * Lesser General Public License for more details. +; * +; * You should have received a copy of the GNU Lesser General 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" +%define MAX_PB_SIZE 128 +%define ROWS 2 + +SECTION_RODATA + +pw_1: times 2 dw 1 + +; DMVR SAD is only calculated on even rows to reduce complexity +; Additionally the only valid sizes are 8x16, 16x8, and 16x16 +SECTION .text + +%macro MIN_MAX_SAD 3 + pminuw %3, %2, %1 + pmaxuw %1, %2, %1 + psubusw %1, %1, %3 +%endmacro + +%macro HORIZ_ADD 3 ; xm0, xm1, m1 + vextracti128 %1, %3, q0001 ; 3 2 1 0 + paddd %1, %2 ; xm0 (7 + 3) (6 + 2) (5 + 1) (4 + 0) + pshufd %2, %1, q0032 ; xm1 - - (7 + 3) (6 + 2) + paddd %1, %1, %2 ; xm0 _ _ (5 1 7 3) (4 0 6 2) + pshufd %2, %1, q0001 ; xm1 _ _ (5 1 7 3) (5 1 7 3) + paddd %1, %1, %2 ; (01234567) +%endmacro + +%if ARCH_X86_64 +%if HAVE_AVX2_EXTERNAL + +INIT_YMM avx2 + +cglobal vvc_sad, 6, 9, 5, src1, src2, dx, dy, block_w, block_h, off1, off2, row_idx + movsxdifnidn dxq, dxd + movsxdifnidn dyq, dyd + + sub dxq, 2 + sub dyq, 2 + + mov off1q, 2 + mov off2q, 2 + + add off1q, dyq + sub off2q, dyq + + shl off1q, 7 + shl off2q, 7 + + add off1q, dxq + sub off2q, dxq + + lea src1q, [src1q + off1q * 2 + 2 * 2] + lea src2q, [src2q + off2q * 2 + 2 * 2] + + pxor m3, m3 + vpbroadcastd m4, [pw_1] + + cmp block_wd, 16 + je vvc_sad_16 + + vvc_sad_8: + .loop_height: + movu xm0, [src1q] + vinserti128 m0, m0, [src1q + MAX_PB_SIZE * ROWS * 2], 1 + movu xm1, [src2q] + vinserti128 m1, m1, [src2q + MAX_PB_SIZE * ROWS * 2], 1 + + MIN_MAX_SAD m1, m0, m2 + pmaddwd m1, m4 + paddd m3, m1 + + add src1q, 2 * MAX_PB_SIZE * ROWS * 2 + add src2q, 2 * MAX_PB_SIZE * ROWS * 2 + + sub block_hd, 4 + jg .loop_height + + HORIZ_ADD xm0, xm3, m3 + movd eax, xm0 + RET + + vvc_sad_16: + sar block_wd, 4 + .loop_height: + mov off1q, src1q + mov off2q, src2q + mov row_idxd, block_wd + + .loop_width: + movu m0, [src1q] + movu m1, [src2q] + MIN_MAX_SAD m1, m0, m2 + pmaddwd m1, m4 + paddd m3, m1 + + add src1q, 32 + add src2q, 32 + dec row_idxd + jg .loop_width + + lea src1q, [off1q + ROWS * MAX_PB_SIZE * 2] + lea src2q, [off2q + ROWS * MAX_PB_SIZE * 2] + + sub block_hd, 2 + jg .loop_height + + HORIZ_ADD xm0, xm3, m3 + movd eax, xm0 + RET + +%endif +%endif diff --git a/libavcodec/x86/vvc/vvcdsp_init.c b/libavcodec/x86/vvc/vvcdsp_init.c index 0d2c683f0..3a128b21e 100644 --- a/libavcodec/x86/vvc/vvcdsp_init.c +++ b/libavcodec/x86/vvc/vvcdsp_init.c @@ -24,16 +24,139 @@ #include "config.h" #include "libavutil/cpu.h" -#include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" -#include "libavcodec/vvc/vvcdec.h" -#include "libavcodec/vvc/vvc_ctu.h" -#include "libavcodec/vvc/vvcdsp.h" +#include "libavcodec/vvc/dec.h" +#include "libavcodec/vvc/ctu.h" +#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) + +#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); \ +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, 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 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) \ -static void ff_vvc_put_ ## name ## _ ## depth ## _##opt(int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, \ +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) \ { \ ff_h2656_put_## name ## _ ## depth ## _##opt(dst, 2 * MAX_PB_SIZE, src, srcstride, height, hf, vf, width); \ @@ -69,7 +192,9 @@ static void ff_vvc_put_ ## name ## _ ## depth ## _##opt(int16_t *dst, const uint FW_PUT_SSE4( 8) FW_PUT_SSE4(10) FW_PUT_SSE4(12) +#endif +#if HAVE_AVX2_EXTERNAL #define FW_PUT_TAP_AVX2(n, bitd) \ FW_PUT(n ## tap_h32, bitd, avx2) \ FW_PUT(n ## tap_h64, bitd, avx2) \ @@ -105,6 +230,51 @@ 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, \ + 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); \ + BF(ff_vvc_alf_classify, bpc, opt)(class_idx, transpose_idx, gradient_tmp, width, height, vb_pos, bd); \ +} \ + +ALF_FUNCS(8, 8, avx2) +ALF_FUNCS(16, 10, avx2) +ALF_FUNCS(16, 12, avx2) + +#endif + #define PEL_LINK(dst, C, W, idx1, idx2, name, D, opt) \ dst[C][W][idx1][idx2] = ff_vvc_put_## name ## _ ## D ## _##opt; \ dst ## _uni[C][W][idx1][idx2] = ff_h2656_put_uni_ ## name ## _ ## D ## _##opt; \ @@ -170,41 +340,30 @@ FW_PUT_16BPC_AVX2(12) MC_TAP_LINKS_16BPC_AVX2(LUMA, 8, bd); \ MC_TAP_LINKS_16BPC_AVX2(CHROMA, 4, bd); -#define bf(fn, bd, opt) fn##_##bd##_##opt -#define BF(fn, bpc, opt) fn##_##bpc##bpc_##opt - -#define AVG_BPC_FUNC(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_FUNCS(bpc, bd, opt) \ -static void bf(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); \ -} \ -static void bf(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_BPC_FUNC(8, avx2) -AVG_BPC_FUNC(16, avx2) - -AVG_FUNCS(8, 8, avx2) -AVG_FUNCS(16, 10, avx2) -AVG_FUNCS(16, 12, avx2) - -#define AVG_INIT(bd, opt) do { \ - c->inter.avg = bf(avg, bd, opt); \ - c->inter.w_avg = bf(w_avg, bd, opt); \ +#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 #endif void ff_vvc_dsp_init_x86(VVCDSPContext *const c, const int bd) @@ -212,45 +371,50 @@ void ff_vvc_dsp_init_x86(VVCDSPContext *const c, const int bd) #if ARCH_X86_64 const int cpu_flags = av_get_cpu_flags(); - if (bd == 8) { + switch (bd) { + case 8: if (EXTERNAL_SSE4(cpu_flags)) { MC_LINK_SSE4(8); } if (EXTERNAL_AVX2_FAST(cpu_flags)) { + ALF_INIT(8); + AVG_INIT(8, avx2); MC_LINKS_AVX2(8); + OF_INIT(8); + DMVR_INIT(8); + SAD_INIT(); } - } else if (bd == 10) { + break; + case 10: if (EXTERNAL_SSE4(cpu_flags)) { MC_LINK_SSE4(10); } if (EXTERNAL_AVX2_FAST(cpu_flags)) { + ALF_INIT(10); + AVG_INIT(10, avx2); MC_LINKS_AVX2(10); MC_LINKS_16BPC_AVX2(10); + OF_INIT(10); + DMVR_INIT(10); + SAD_INIT(); } - } else if (bd == 12) { + break; + case 12: if (EXTERNAL_SSE4(cpu_flags)) { MC_LINK_SSE4(12); } if (EXTERNAL_AVX2_FAST(cpu_flags)) { + ALF_INIT(12); + AVG_INIT(12, avx2); MC_LINKS_AVX2(12); MC_LINKS_16BPC_AVX2(12); + OF_INIT(12); + DMVR_INIT(12); + SAD_INIT(); } - } - - if (EXTERNAL_AVX2(cpu_flags)) { - switch (bd) { - case 8: - AVG_INIT(8, avx2); - break; - case 10: - AVG_INIT(10, avx2); - break; - case 12: - AVG_INIT(12, avx2); - break; - default: - break; - } + break; + default: + break; } #endif } diff --git a/libavcodec/xan.c b/libavcodec/xan.c index cc0ecea5e..56675dbbb 100644 --- a/libavcodec/xan.c +++ b/libavcodec/xan.c @@ -607,6 +607,9 @@ static int xan_decode_frame(AVCodecContext *avctx, AVFrame *frame, return AVERROR_INVALIDDATA; } + if (buf_size < 9) + return AVERROR_INVALIDDATA; + if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) return ret; diff --git a/libavcodec/xbmdec.c b/libavcodec/xbmdec.c index 2d84327e0..09096b9df 100644 --- a/libavcodec/xbmdec.c +++ b/libavcodec/xbmdec.c @@ -135,9 +135,6 @@ static int xbm_decode_frame(AVCodecContext *avctx, AVFrame *p, } } - p->flags |= AV_FRAME_FLAG_KEY; - p->pict_type = AV_PICTURE_TYPE_I; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/xl.c b/libavcodec/xl.c index f008d56e8..6d60611ad 100644 --- a/libavcodec/xl.c +++ b/libavcodec/xl.c @@ -59,8 +59,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; Y = p->data[0]; U = p->data[1]; diff --git a/libavcodec/xpmdec.c b/libavcodec/xpmdec.c index b915abe0b..2eb5daf54 100644 --- a/libavcodec/xpmdec.c +++ b/libavcodec/xpmdec.c @@ -22,6 +22,7 @@ */ #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" @@ -428,9 +429,6 @@ static int xpm_decode_frame(AVCodecContext *avctx, AVFrame *p, ptr += mod_strcspn(ptr, ",") + 1; } - p->flags |= AV_FRAME_FLAG_KEY; - p->pict_type = AV_PICTURE_TYPE_I; - *got_frame = 1; return avpkt->size; diff --git a/libavcodec/xsubdec.c b/libavcodec/xsubdec.c index b804a9029..6be4c18b0 100644 --- a/libavcodec/xsubdec.c +++ b/libavcodec/xsubdec.c @@ -21,6 +21,7 @@ #include "libavutil/mathematics.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "get_bits.h" #include "bytestream.h" diff --git a/libavcodec/xwddec.c b/libavcodec/xwddec.c index f691587be..fac8c21af 100644 --- a/libavcodec/xwddec.c +++ b/libavcodec/xwddec.c @@ -216,9 +216,6 @@ static int xwd_decode_frame(AVCodecContext *avctx, AVFrame *p, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - p->flags |= AV_FRAME_FLAG_KEY; - p->pict_type = AV_PICTURE_TYPE_I; - if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { uint32_t *dst = (uint32_t *)p->data[1]; uint8_t red, green, blue; diff --git a/libavcodec/xwdenc.c b/libavcodec/xwdenc.c index 08554d863..40bee2010 100644 --- a/libavcodec/xwdenc.c +++ b/libavcodec/xwdenc.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/imgutils_internal.h" #include "libavutil/pixdesc.h" #include "avcodec.h" #include "bytestream.h" diff --git a/libavcodec/y41pdec.c b/libavcodec/y41pdec.c index 14e36dc99..270b23c14 100644 --- a/libavcodec/y41pdec.c +++ b/libavcodec/y41pdec.c @@ -51,9 +51,6 @@ static int y41p_decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - for (i = avctx->height - 1; i >= 0 ; i--) { y = &pic->data[0][i * pic->linesize[0]]; u = &pic->data[1][i * pic->linesize[1]]; diff --git a/libavcodec/ylc.c b/libavcodec/ylc.c index b03df3155..44cbfa712 100644 --- a/libavcodec/ylc.c +++ b/libavcodec/ylc.c @@ -426,8 +426,6 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p, dst += p->linesize[0]; } - p->pict_type = AV_PICTURE_TYPE_I; - p->flags |= AV_FRAME_FLAG_KEY; *got_frame = 1; return avpkt->size; diff --git a/libavcodec/yop.c b/libavcodec/yop.c index 1294c5cc0..77b8d6e05 100644 --- a/libavcodec/yop.c +++ b/libavcodec/yop.c @@ -274,6 +274,7 @@ const FFCodec ff_yop_decoder = { CODEC_LONG_NAME("Psygnosis YOP Video"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_YOP, + .p.capabilities = AV_CODEC_CAP_DR1, .priv_data_size = sizeof(YopDecContext), .init = yop_decode_init, .close = yop_decode_close, diff --git a/libavcodec/yuv4dec.c b/libavcodec/yuv4dec.c index ad83a2125..3b406057f 100644 --- a/libavcodec/yuv4dec.c +++ b/libavcodec/yuv4dec.c @@ -46,9 +46,6 @@ static int yuv4_decode_frame(AVCodecContext *avctx, AVFrame *pic, if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; - pic->flags |= AV_FRAME_FLAG_KEY; - pic->pict_type = AV_PICTURE_TYPE_I; - y = pic->data[0]; u = pic->data[1]; v = pic->data[2]; diff --git a/libavcodec/zmbv.c b/libavcodec/zmbv.c index d309a8612..2c09ccbd7 100644 --- a/libavcodec/zmbv.c +++ b/libavcodec/zmbv.c @@ -29,6 +29,7 @@ #include "libavutil/common.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "decode.h" diff --git a/libavcodec/zmbvenc.c b/libavcodec/zmbvenc.c index d20330568..04889b97d 100644 --- a/libavcodec/zmbvenc.c +++ b/libavcodec/zmbvenc.c @@ -24,11 +24,10 @@ * Zip Motion Blocks Video encoder */ -#include -#include +#include -#include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" diff --git a/libavdevice/alsa.c b/libavdevice/alsa.c index b055f6c1a..d62ccc09c 100644 --- a/libavdevice/alsa.c +++ b/libavdevice/alsa.c @@ -34,6 +34,7 @@ #include "avdevice.h" #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "alsa.h" diff --git a/libavdevice/android_camera.c b/libavdevice/android_camera.c index 3aa8597c6..5de44e6d8 100644 --- a/libavdevice/android_camera.c +++ b/libavdevice/android_camera.c @@ -39,6 +39,7 @@ #include "libavutil/display.h" #include "libavutil/imgutils.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/pixfmt.h" diff --git a/libavdevice/audiotoolbox.m b/libavdevice/audiotoolbox.m index 3bd707f23..7d95c3459 100644 --- a/libavdevice/audiotoolbox.m +++ b/libavdevice/audiotoolbox.m @@ -28,6 +28,7 @@ #import #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavformat/internal.h" #include "libavformat/mux.h" diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c index cd7b03ef4..5712fa47c 100644 --- a/libavdevice/avdevice.c +++ b/libavdevice/avdevice.c @@ -17,6 +17,7 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "avdevice.h" #include "internal.h" #include "libavformat/demux.h" diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 3fe3df2cb..c5a09c656 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -29,6 +29,7 @@ #include #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "libavutil/avstring.h" diff --git a/libavdevice/bktr.c b/libavdevice/bktr.c index ac5b53486..eed75a9a9 100644 --- a/libavdevice/bktr.c +++ b/libavdevice/bktr.c @@ -29,6 +29,7 @@ #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" diff --git a/libavdevice/caca.c b/libavdevice/caca.c index c3b232975..42cceccf3 100644 --- a/libavdevice/caca.c +++ b/libavdevice/caca.c @@ -19,6 +19,7 @@ */ #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavformat/mux.h" diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h index 34ab1b967..6b32dc2d0 100644 --- a/libavdevice/decklink_common.h +++ b/libavdevice/decklink_common.h @@ -30,6 +30,7 @@ #endif extern "C" { +#include "libavutil/mem.h" #include "libavcodec/packet_internal.h" #include "libavfilter/ccfifo.h" } @@ -146,6 +147,7 @@ struct decklink_ctx { DecklinkPtsSource video_pts_source; int draw_bars; BMDPixelFormat raw_format; + DecklinkSignalLossAction signal_loss_action; int frames_preroll; int frames_buffer; diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h index 9c55d8914..53d2c583e 100644 --- a/libavdevice/decklink_common_c.h +++ b/libavdevice/decklink_common_c.h @@ -37,6 +37,12 @@ typedef enum DecklinkPtsSource { PTS_SRC_NB } DecklinkPtsSource; +typedef enum DecklinkSignalLossAction { + SIGNAL_LOSS_NONE = 1, + SIGNAL_LOSS_REPEAT = 2, + SIGNAL_LOSS_BARS = 3 +} DecklinkSignalLossAction; + struct decklink_cctx { const AVClass *cclass; @@ -68,6 +74,7 @@ struct decklink_cctx { int64_t timestamp_align; int timing_offset; int wait_for_tc; + DecklinkSignalLossAction signal_loss_action; }; #endif /* AVDEVICE_DECKLINK_COMMON_C_H */ diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index 671573853..418701e4e 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -593,6 +593,7 @@ private: int no_video; int64_t initial_video_pts; int64_t initial_audio_pts; + IDeckLinkVideoInputFrame* last_video_frame; }; decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _refs(1) @@ -602,10 +603,13 @@ decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _ref ctx = (struct decklink_ctx *)cctx->ctx; no_video = 0; initial_audio_pts = initial_video_pts = AV_NOPTS_VALUE; + last_video_frame = nullptr; } decklink_input_callback::~decklink_input_callback() { + if (last_video_frame) + last_video_frame->Release(); } ULONG decklink_input_callback::AddRef(void) @@ -729,6 +733,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( BMDTimeValue frameTime; BMDTimeValue frameDuration; int64_t wallclock = 0, abs_wallclock = 0; + int64_t video_pkt_pts, audio_pkt_pts; struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; if (ctx->autodetect) { @@ -755,6 +760,8 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( wallclock = av_gettime_relative(); if (ctx->audio_pts_source == PTS_SRC_ABS_WALLCLOCK || ctx->video_pts_source == PTS_SRC_ABS_WALLCLOCK) abs_wallclock = av_gettime(); + video_pkt_pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts, cctx->copyts); + audio_pkt_pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts, cctx->copyts); // Handle Video Frame if (videoFrame) { @@ -773,7 +780,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( ctx->video_st->time_base.den); if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) { - if (ctx->draw_bars && videoFrame->GetPixelFormat() == bmdFormat8BitYUV) { + if (ctx->signal_loss_action == SIGNAL_LOSS_BARS && videoFrame->GetPixelFormat() == bmdFormat8BitYUV) { unsigned bars[8] = { 0xEA80EA80, 0xD292D210, 0xA910A9A5, 0x90229035, 0x6ADD6ACA, 0x51EF515A, 0x286D28EF, 0x10801080 }; @@ -785,6 +792,9 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( for (int x = 0; x < width; x += 2) *p++ = bars[(x * 8) / width]; } + } else if (ctx->signal_loss_action == SIGNAL_LOSS_REPEAT && last_video_frame) { + videoFrame = last_video_frame; + videoFrame->GetBytes(&frameBytes); } if (!no_video) { @@ -793,6 +803,12 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( } no_video = 1; } else { + if (ctx->signal_loss_action == SIGNAL_LOSS_REPEAT) { + if (last_video_frame) + last_video_frame->Release(); + last_video_frame = videoFrame; + last_video_frame->AddRef(); + } if (no_video) { av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - Input returned " "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped); @@ -846,7 +862,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( return S_OK; } - pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts, cctx->copyts); + pkt.pts = video_pkt_pts; pkt.dts = pkt.pts; pkt.duration = frameDuration; @@ -949,7 +965,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codecpar->ch_layout.nb_channels * (ctx->audio_depth / 8); audioFrame->GetBytes(&audioFrameBytes); audioFrame->GetPacketTime(&audio_pts, ctx->audio_st->time_base.den); - pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts, cctx->copyts); + pkt.pts = audio_pkt_pts; pkt.dts = pkt.pts; //fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts); @@ -1036,6 +1052,7 @@ av_cold int ff_decklink_read_close(AVFormatContext *avctx) ctx->dli->StopStreams(); ctx->dli->DisableVideoInput(); ctx->dli->DisableAudioInput(); + ctx->dli->SetCallback(nullptr); } ff_decklink_cleanup(avctx); @@ -1074,6 +1091,16 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) ctx->audio_pts_source = cctx->audio_pts_source; ctx->video_pts_source = cctx->video_pts_source; ctx->draw_bars = cctx->draw_bars; + ctx->signal_loss_action = cctx->signal_loss_action; + if (!ctx->draw_bars && ctx->signal_loss_action == SIGNAL_LOSS_BARS) { + ctx->signal_loss_action = SIGNAL_LOSS_NONE; + av_log(avctx, AV_LOG_WARNING, "Setting signal_loss_action to none because draw_bars is false\n"); + } + if (!ctx->draw_bars && ctx->signal_loss_action != SIGNAL_LOSS_NONE) { + av_log(avctx, AV_LOG_ERROR, "options draw_bars and signal_loss_action are mutually exclusive\n"); + av_freep(&ctx); + return AVERROR(EINVAL); + } ctx->audio_depth = cctx->audio_depth; if (cctx->raw_format > 0 && (unsigned int)cctx->raw_format < FF_ARRAY_ELEMS(decklink_raw_format_map)) ctx->raw_format = decklink_raw_format_map[cctx->raw_format]; @@ -1087,7 +1114,8 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) break; default: av_log(avctx, AV_LOG_ERROR, "Value of channels option must be one of 2, 8 or 16\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto error; } /* Check audio bit depth option for valid values: 16 or 32 */ @@ -1097,18 +1125,20 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) break; default: av_log(avctx, AV_LOG_ERROR, "Value for audio bit depth option must be either 16 or 32\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto error; } /* List available devices. */ if (ctx->list_devices) { ff_decklink_list_devices_legacy(avctx, 1, 0); - return AVERROR_EXIT; + ret = AVERROR_EXIT; + goto error; } ret = ff_decklink_init_device(avctx, avctx->url); if (ret < 0) - return ret; + goto error; /* Get input device. */ if (ctx->dl->QueryInterface(IID_IDeckLinkInput, (void **) &ctx->dli) != S_OK) { @@ -1309,6 +1339,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) error: ff_decklink_cleanup(avctx); + av_freep(&cctx->ctx); return ret; } diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c index e211c9d3f..b8cdb7bd8 100644 --- a/libavdevice/decklink_dec_c.c +++ b/libavdevice/decklink_dec_c.c @@ -95,12 +95,16 @@ static const AVOption options[] = { { "reference", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_REFERENCE}, 0, 0, DEC, .unit = "pts_source"}, { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_WALLCLOCK}, 0, 0, DEC, .unit = "pts_source"}, { "abs_wallclock", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_ABS_WALLCLOCK}, 0, 0, DEC, .unit = "pts_source"}, - { "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, DEC }, + { "draw_bars", "use option signal_loss_action instead" , OFFSET(draw_bars), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, DEC | AV_OPT_FLAG_DEPRECATED }, { "queue_size", "input queue buffer size", OFFSET(queue_size), AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC }, { "audio_depth", "audio bitdepth (16 or 32)", OFFSET(audio_depth), AV_OPT_TYPE_INT, { .i64 = 16}, 16, 32, DEC }, { "decklink_copyts", "copy timestamps, do not remove the initial offset", OFFSET(copyts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC }, { "timestamp_align", "capture start time alignment (in seconds)", OFFSET(timestamp_align), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, DEC }, { "wait_for_tc", "drop frames till a frame with timecode is received. TC format must be set", OFFSET(wait_for_tc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC }, + { "signal_loss_action", "action on signal loss", OFFSET(signal_loss_action), AV_OPT_TYPE_INT, { .i64 = SIGNAL_LOSS_BARS }, SIGNAL_LOSS_NONE, SIGNAL_LOSS_BARS, DEC, .unit = "signal_loss_action" }, + { "none", "do not do anything (usually leads to black frames)", 0, AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_NONE }, 0, 0, DEC, .unit = "signal_loss_action"}, + { "bars", "draw color bars (only supported for 8-bit signals)", 0, AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_BARS }, 0, 0, DEC, .unit = "signal_loss_action"}, + { "repeat", "repeat the last video frame", 0, AV_OPT_TYPE_CONST, { .i64 = SIGNAL_LOSS_REPEAT }, 0, 0, DEC, .unit = "signal_loss_action"}, { NULL }, }; diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c index 57d8e1c0a..84db15157 100644 --- a/libavdevice/dshow.c +++ b/libavdevice/dshow.c @@ -898,8 +898,8 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, if (devtype == VideoDevice) { VIDEO_STREAM_CONFIG_CAPS *vcaps = caps; - BITMAPINFOHEADER *bih; - int64_t *fr; + BITMAPINFOHEADER *bih = NULL; + int64_t *fr = NULL; #if DSHOWDEBUG ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps); #endif diff --git a/libavdevice/dshow_enummediatypes.c b/libavdevice/dshow_enummediatypes.c index 4cb7057e1..64a236cc1 100644 --- a/libavdevice/dshow_enummediatypes.c +++ b/libavdevice/dshow_enummediatypes.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "dshow_capture.h" DECLARE_QUERYINTERFACE(enummediatypes, DShowEnumMediaTypes, diff --git a/libavdevice/dshow_pin.c b/libavdevice/dshow_pin.c index f846b6891..baa001b5d 100644 --- a/libavdevice/dshow_pin.c +++ b/libavdevice/dshow_pin.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "dshow_capture.h" #include diff --git a/libavdevice/fbdev_common.c b/libavdevice/fbdev_common.c index 2c70abb1f..d8b99614d 100644 --- a/libavdevice/fbdev_common.c +++ b/libavdevice/fbdev_common.c @@ -27,6 +27,7 @@ #include "fbdev_common.h" #include "libavutil/common.h" #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "avdevice.h" struct rgb_pixfmt_map_entry { diff --git a/libavdevice/gdigrab.c b/libavdevice/gdigrab.c index 58e876ea9..08a41c304 100644 --- a/libavdevice/gdigrab.c +++ b/libavdevice/gdigrab.c @@ -31,6 +31,7 @@ #include "config.h" #include "libavformat/demux.h" #include "libavformat/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time.h" #include "libavutil/wchar_filename.h" @@ -280,7 +281,7 @@ gdigrab_read_header(AVFormatContext *s1) hwnd = (HWND) strtoull(name, &p, 0); - if (p == NULL || p == name || p[0] == '\0') + if (p == NULL || p == name || p[0] != '\0') { av_log(s1, AV_LOG_ERROR, "Invalid window handle '%s', must be a valid integer.\n", name); diff --git a/libavdevice/iec61883.c b/libavdevice/iec61883.c index 689bcc81d..670e29aa3 100644 --- a/libavdevice/iec61883.c +++ b/libavdevice/iec61883.c @@ -33,6 +33,7 @@ #include "libavformat/demux.h" #include "libavformat/dv.h" #include "libavformat/mpegts.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avdevice.h" diff --git a/libavdevice/jack.c b/libavdevice/jack.c index 40f2af5cc..bb06971fe 100644 --- a/libavdevice/jack.c +++ b/libavdevice/jack.c @@ -27,6 +27,7 @@ #include "libavutil/internal.h" #include "libavutil/log.h" #include "libavutil/fifo.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time.h" #include "libavformat/avformat.h" @@ -290,11 +291,9 @@ static int audio_read_packet(AVFormatContext *context, AVPacket *pkt) av_log(context, AV_LOG_ERROR, "Input error: timed out when waiting for JACK process callback output\n"); } else { - char errbuf[128]; int ret = AVERROR(errno); - av_strerror(ret, errbuf, sizeof(errbuf)); av_log(context, AV_LOG_ERROR, "Error while waiting for audio packet: %s\n", - errbuf); + av_err2str(ret)); } if (!self->client) av_log(context, AV_LOG_ERROR, "Input error: JACK server is gone\n"); diff --git a/libavdevice/kmsgrab.c b/libavdevice/kmsgrab.c index bf6341e9f..3d15754f3 100644 --- a/libavdevice/kmsgrab.c +++ b/libavdevice/kmsgrab.c @@ -36,6 +36,7 @@ #include "libavutil/hwcontext_drm.h" #include "libavutil/internal.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixfmt.h" #include "libavutil/pixdesc.h" diff --git a/libavdevice/opengl_enc.c b/libavdevice/opengl_enc.c index 69de6fad0..93d395988 100644 --- a/libavdevice/opengl_enc.c +++ b/libavdevice/opengl_enc.c @@ -50,6 +50,7 @@ #include "libavutil/common.h" #include "libavutil/frame.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/log.h" #include "libavutil/opt.h" @@ -1066,7 +1067,7 @@ static av_cold int opengl_write_header(AVFormatContext *h) 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 -\n" + "Example: ffmpeg -i INPUT -f nut -c:v rawvideo - | ffplay -loglevel warning -vf setpts=0 -\n" ); opengl->warned = 1; } diff --git a/libavdevice/riscv/Makefile b/libavdevice/riscv/Makefile new file mode 100644 index 000000000..52857aacb --- /dev/null +++ b/libavdevice/riscv/Makefile @@ -0,0 +1 @@ +SHLIBOBJS += riscv/cpu_common.o diff --git a/libavdevice/riscv/cpu_common.c b/libavdevice/riscv/cpu_common.c new file mode 100644 index 000000000..17c9b392c --- /dev/null +++ b/libavdevice/riscv/cpu_common.c @@ -0,0 +1 @@ +#include "libavutil/riscv/cpu_common.c" diff --git a/libavdevice/sdl2.c b/libavdevice/sdl2.c index ec3c3d19b..491c8dafe 100644 --- a/libavdevice/sdl2.c +++ b/libavdevice/sdl2.c @@ -26,13 +26,10 @@ #include #include -#include "libavutil/avstring.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" -#include "libavutil/time.h" -#include "avdevice.h" #include "libavformat/mux.h" typedef struct { @@ -170,7 +167,7 @@ static int sdl2_write_header(AVFormatContext *s) 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 -\n" + "Example: ffmpeg -i INPUT -f nut -c:v rawvideo - | ffplay -loglevel warning -vf setpts=0 -\n" ); sdl->warned = 1; } diff --git a/libavdevice/sndio.c b/libavdevice/sndio.c index 46f287588..1a4f20344 100644 --- a/libavdevice/sndio.c +++ b/libavdevice/sndio.c @@ -22,7 +22,7 @@ #include #include -#include "avdevice.h" +#include "libavutil/mem.h" #include "libavdevice/sndio.h" diff --git a/libavdevice/utils.c b/libavdevice/utils.c index c72a839df..74574715e 100644 --- a/libavdevice/utils.c +++ b/libavdevice/utils.c @@ -17,6 +17,7 @@ */ #include "internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavformat/avformat.h" #include "libavformat/demux.h" diff --git a/libavdevice/v4l2-common.c b/libavdevice/v4l2-common.c index b5b4448a3..ebfd2b6d8 100644 --- a/libavdevice/v4l2-common.c +++ b/libavdevice/v4l2-common.c @@ -50,6 +50,12 @@ const struct fmt_map ff_fmt_conversion_table[] = { { AV_PIX_FMT_GRAY16LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_Z16 }, #endif { AV_PIX_FMT_NV12, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12 }, +#ifdef V4L2_PIX_FMT_NV16 + { AV_PIX_FMT_NV16, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV16 }, +#endif +#ifdef V4L2_PIX_FMT_NV24 + { AV_PIX_FMT_NV24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV24 }, +#endif { AV_PIX_FMT_NONE, AV_CODEC_ID_MJPEG, V4L2_PIX_FMT_MJPEG }, { AV_PIX_FMT_NONE, AV_CODEC_ID_MJPEG, V4L2_PIX_FMT_JPEG }, #ifdef V4L2_PIX_FMT_H264 diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c index 50ac47ec5..0ae687233 100644 --- a/libavdevice/v4l2.c +++ b/libavdevice/v4l2.c @@ -35,6 +35,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavutil/time.h" @@ -91,6 +92,9 @@ struct video_data { TimeFilter *timefilter; int64_t last_time_m; + int multiplanar; + enum v4l2_buf_type buf_type; + int buffers; atomic_int buffers_queued; void **buf_start; @@ -107,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 defined(__sun) || defined(__BIONIC__) || defined(__musl__) /* POSIX-like */ +#if HAVE_POSIX_IOCTL int (*ioctl_f)(int fd, int request, ...); #else int (*ioctl_f)(int fd, unsigned long int request, ...); @@ -181,7 +185,13 @@ static int device_open(AVFormatContext *ctx, const char* device_path) av_log(ctx, AV_LOG_VERBOSE, "fd:%d capabilities:%x\n", fd, cap.capabilities); - if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { + s->multiplanar = 0; + s->buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) { + s->multiplanar = 1; + s->buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + } else { av_log(ctx, AV_LOG_ERROR, "Not a video capture device.\n"); err = AVERROR(ENODEV); goto fail; @@ -205,7 +215,7 @@ static int device_init(AVFormatContext *ctx, int *width, int *height, uint32_t pixelformat) { struct video_data *s = ctx->priv_data; - struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; + struct v4l2_format fmt = { .type = s->buf_type }; int res = 0; fmt.fmt.pix.width = *width; @@ -287,7 +297,7 @@ static void list_framesizes(AVFormatContext *ctx, uint32_t pixelformat) static void list_formats(AVFormatContext *ctx, int type) { const struct video_data *s = ctx->priv_data; - struct v4l2_fmtdesc vfd = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; + struct v4l2_fmtdesc vfd = { .type = s->buf_type }; while(!v4l2_ioctl(s->fd, VIDIOC_ENUM_FMT, &vfd)) { enum AVCodecID codec_id = ff_fmt_v4l2codec(vfd.pixelformat); @@ -351,7 +361,7 @@ static int mmap_init(AVFormatContext *ctx) int i, res; struct video_data *s = ctx->priv_data; struct v4l2_requestbuffers req = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .type = s->buf_type, .count = desired_video_buffers, .memory = V4L2_MEMORY_MMAP }; @@ -380,10 +390,14 @@ static int mmap_init(AVFormatContext *ctx) } for (i = 0; i < req.count; i++) { + unsigned int buf_length, buf_offset; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; struct v4l2_buffer buf = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .type = s->buf_type, .index = i, - .memory = V4L2_MEMORY_MMAP + .memory = V4L2_MEMORY_MMAP, + .m.planes = s->multiplanar ? planes : NULL, + .length = s->multiplanar ? VIDEO_MAX_PLANES : 0, }; if (v4l2_ioctl(s->fd, VIDIOC_QUERYBUF, &buf) < 0) { res = AVERROR(errno); @@ -391,16 +405,28 @@ static int mmap_init(AVFormatContext *ctx) return res; } - s->buf_len[i] = buf.length; + if (s->multiplanar) { + if (buf.length != 1) { + av_log(ctx, AV_LOG_ERROR, "multiplanar only supported when buf.length == 1\n"); + return AVERROR_PATCHWELCOME; + } + buf_length = buf.m.planes[0].length; + buf_offset = buf.m.planes[0].m.mem_offset; + } else { + buf_length = buf.length; + buf_offset = buf.m.offset; + } + + s->buf_len[i] = buf_length; if (s->frame_size > 0 && s->buf_len[i] < s->frame_size) { av_log(ctx, AV_LOG_ERROR, "buf_len[%d] = %d < expected frame size %d\n", i, s->buf_len[i], s->frame_size); return AVERROR(ENOMEM); } - s->buf_start[i] = v4l2_mmap(NULL, buf.length, + s->buf_start[i] = v4l2_mmap(NULL, buf_length, PROT_READ | PROT_WRITE, MAP_SHARED, - s->fd, buf.m.offset); + s->fd, buf_offset); if (s->buf_start[i] == MAP_FAILED) { res = AVERROR(errno); @@ -428,13 +454,16 @@ static int enqueue_buffer(struct video_data *s, struct v4l2_buffer *buf) static void mmap_release_buffer(void *opaque, uint8_t *data) { + struct v4l2_plane planes[VIDEO_MAX_PLANES]; struct v4l2_buffer buf = { 0 }; struct buff_data *buf_descriptor = opaque; struct video_data *s = buf_descriptor->s; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.type = s->buf_type; buf.memory = V4L2_MEMORY_MMAP; buf.index = buf_descriptor->index; + buf.m.planes = s->multiplanar ? planes : NULL; + buf.length = s->multiplanar ? VIDEO_MAX_PLANES : 0; av_free(buf_descriptor); enqueue_buffer(s, &buf); @@ -504,11 +533,15 @@ static int convert_timestamp(AVFormatContext *ctx, int64_t *ts) static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) { struct video_data *s = ctx->priv_data; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; struct v4l2_buffer buf = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .memory = V4L2_MEMORY_MMAP + .type = s->buf_type, + .memory = V4L2_MEMORY_MMAP, + .m.planes = s->multiplanar ? planes : NULL, + .length = s->multiplanar ? VIDEO_MAX_PLANES : 0, }; struct timeval buf_ts; + unsigned int bytesused; int res; pkt->size = 0; @@ -535,38 +568,40 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) // always keep at least one buffer queued av_assert0(atomic_load(&s->buffers_queued) >= 1); + bytesused = s->multiplanar ? buf.m.planes[0].bytesused : buf.bytesused; + #ifdef V4L2_BUF_FLAG_ERROR if (buf.flags & V4L2_BUF_FLAG_ERROR) { av_log(ctx, AV_LOG_WARNING, "Dequeued v4l2 buffer contains corrupted data (%d bytes).\n", - buf.bytesused); - buf.bytesused = 0; + bytesused); + bytesused = 0; } else #endif { /* CPIA is a compressed format and we don't know the exact number of bytes * used by a frame, so set it here as the driver announces it. */ if (ctx->video_codec_id == AV_CODEC_ID_CPIA) - s->frame_size = buf.bytesused; + s->frame_size = bytesused; - if (s->frame_size > 0 && buf.bytesused != s->frame_size) { + if (s->frame_size > 0 && bytesused != s->frame_size) { av_log(ctx, AV_LOG_WARNING, "Dequeued v4l2 buffer contains %d bytes, but %d were expected. Flags: 0x%08X.\n", - buf.bytesused, s->frame_size, buf.flags); - buf.bytesused = 0; + bytesused, s->frame_size, buf.flags); + bytesused = 0; } } /* Image is at s->buff_start[buf.index] */ if (atomic_load(&s->buffers_queued) == FFMAX(s->buffers / 8, 1)) { /* when we start getting low on queued buffers, fall back on copying data */ - res = av_new_packet(pkt, buf.bytesused); + res = av_new_packet(pkt, bytesused); if (res < 0) { av_log(ctx, AV_LOG_ERROR, "Error allocating a packet.\n"); enqueue_buffer(s, &buf); return res; } - memcpy(pkt->data, s->buf_start[buf.index], buf.bytesused); + memcpy(pkt->data, s->buf_start[buf.index], bytesused); res = enqueue_buffer(s, &buf); if (res) { @@ -577,7 +612,7 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) struct buff_data *buf_descriptor; pkt->data = s->buf_start[buf.index]; - pkt->size = buf.bytesused; + pkt->size = bytesused; buf_descriptor = av_malloc(sizeof(struct buff_data)); if (!buf_descriptor) { @@ -614,10 +649,13 @@ static int mmap_start(AVFormatContext *ctx) int i, res; for (i = 0; i < s->buffers; i++) { + struct v4l2_plane planes[VIDEO_MAX_PLANES]; struct v4l2_buffer buf = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .type = s->buf_type, .index = i, - .memory = V4L2_MEMORY_MMAP + .memory = V4L2_MEMORY_MMAP, + .m.planes = s->multiplanar ? planes : NULL, + .length = s->multiplanar ? VIDEO_MAX_PLANES : 0, }; if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) { @@ -629,7 +667,7 @@ static int mmap_start(AVFormatContext *ctx) } atomic_store(&s->buffers_queued, s->buffers); - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + type = s->buf_type; if (v4l2_ioctl(s->fd, VIDIOC_STREAMON, &type) < 0) { res = AVERROR(errno); av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n", @@ -645,7 +683,7 @@ static void mmap_close(struct video_data *s) enum v4l2_buf_type type; int i; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + type = s->buf_type; /* We do not check for the result, because we could * not do anything about it anyway... */ @@ -732,7 +770,7 @@ static int v4l2_set_parameters(AVFormatContext *ctx) tpf = &streamparm.parm.capture.timeperframe; } - streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + streamparm.type = s->buf_type; if (v4l2_ioctl(s->fd, VIDIOC_G_PARM, &streamparm) < 0) { ret = AVERROR(errno); av_log(ctx, AV_LOG_WARNING, "ioctl(VIDIOC_G_PARM): %s\n", av_err2str(ret)); @@ -920,7 +958,7 @@ static int v4l2_read_header(AVFormatContext *ctx) } if (!s->width && !s->height) { - struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; + struct v4l2_format fmt = { .type = s->buf_type }; av_log(ctx, AV_LOG_VERBOSE, "Querying the device for the current frame size\n"); diff --git a/libavdevice/version.c b/libavdevice/version.c index 92d7f2d15..a058efe46 100644 --- a/libavdevice/version.c +++ b/libavdevice/version.c @@ -18,9 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "config.h" -#include "libavutil/avassert.h" #include "avdevice.h" #include "version.h" @@ -29,7 +30,7 @@ const char av_device_ffversion[] = "FFmpeg version " FFMPEG_VERSION; unsigned avdevice_version(void) { - av_assert0(LIBAVDEVICE_VERSION_MICRO >= 100); + static_assert(LIBAVDEVICE_VERSION_MICRO >= 100, "micro version starts at 100"); return LIBAVDEVICE_VERSION_INT; } diff --git a/libavdevice/version.h b/libavdevice/version.h index ec6c33787..7608a8602 100644 --- a/libavdevice/version.h +++ b/libavdevice/version.h @@ -29,7 +29,7 @@ #include "version_major.h" -#define LIBAVDEVICE_VERSION_MINOR 1 +#define LIBAVDEVICE_VERSION_MINOR 3 #define LIBAVDEVICE_VERSION_MICRO 100 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ diff --git a/libavdevice/vfwcap.c b/libavdevice/vfwcap.c index dd077dd08..1fda90efa 100644 --- a/libavdevice/vfwcap.c +++ b/libavdevice/vfwcap.c @@ -21,6 +21,7 @@ #include "libavutil/internal.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" diff --git a/libavdevice/xcbgrab.c b/libavdevice/xcbgrab.c index 329e79bf3..c736ec0cb 100644 --- a/libavdevice/xcbgrab.c +++ b/libavdevice/xcbgrab.c @@ -40,6 +40,7 @@ #include "libavutil/internal.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/time.h" diff --git a/libavdevice/xv.c b/libavdevice/xv.c index cba933ef1..d1bc4e8d6 100644 --- a/libavdevice/xv.c +++ b/libavdevice/xv.c @@ -33,6 +33,7 @@ #include #include "libavutil/frame.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 994d9773b..91487afb2 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -167,6 +167,7 @@ OBJS-$(CONFIG_STEREOTOOLS_FILTER) += af_stereotools.o OBJS-$(CONFIG_STEREOWIDEN_FILTER) += af_stereowiden.o OBJS-$(CONFIG_SUPEREQUALIZER_FILTER) += af_superequalizer.o OBJS-$(CONFIG_SURROUND_FILTER) += af_surround.o +OBJS-$(CONFIG_TILTSHELF_FILTER) += af_biquads.o OBJS-$(CONFIG_TREBLE_FILTER) += af_biquads.o OBJS-$(CONFIG_TREMOLO_FILTER) += af_tremolo.o OBJS-$(CONFIG_VIBRATO_FILTER) += af_vibrato.o generate_wave_table.o @@ -239,7 +240,7 @@ OBJS-$(CONFIG_COLORKEY_OPENCL_FILTER) += vf_colorkey_opencl.o opencl.o \ opencl/colorkey.o OBJS-$(CONFIG_COLORHOLD_FILTER) += vf_colorkey.o OBJS-$(CONFIG_COLORLEVELS_FILTER) += vf_colorlevels.o -OBJS-$(CONFIG_COLORMAP_FILTER) += vf_colormap.o +OBJS-$(CONFIG_COLORMAP_FILTER) += vf_colormap.o framesync.o OBJS-$(CONFIG_COLORMATRIX_FILTER) += vf_colormatrix.o OBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o colorspacedsp.o OBJS-$(CONFIG_COLORSPACE_CUDA_FILTER) += vf_colorspace_cuda.o \ @@ -330,7 +331,7 @@ OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o OBJS-$(CONFIG_GRAPHMONITOR_FILTER) += f_graphmonitor.o OBJS-$(CONFIG_GRAYWORLD_FILTER) += vf_grayworld.o OBJS-$(CONFIG_GREYEDGE_FILTER) += vf_colorconstancy.o -OBJS-$(CONFIG_GUIDED_FILTER) += vf_guided.o +OBJS-$(CONFIG_GUIDED_FILTER) += vf_guided.o framesync.o OBJS-$(CONFIG_HALDCLUT_FILTER) += vf_lut3d.o framesync.o OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o OBJS-$(CONFIG_HFLIP_VULKAN_FILTER) += vf_flip_vulkan.o vulkan.o @@ -350,7 +351,7 @@ OBJS-$(CONFIG_HWUPLOAD_FILTER) += vf_hwupload.o 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 +OBJS-$(CONFIG_IDENTITY_FILTER) += vf_identity.o framesync.o OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o OBJS-$(CONFIG_IL_FILTER) += vf_il.o OBJS-$(CONFIG_INFLATE_FILTER) += vf_neighbor.o @@ -359,6 +360,7 @@ OBJS-$(CONFIG_INTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_KERNDEINT_FILTER) += vf_kerndeint.o OBJS-$(CONFIG_KIRSCH_FILTER) += vf_convolution.o OBJS-$(CONFIG_LAGFUN_FILTER) += vf_lagfun.o +OBJS-$(CONFIG_LCEVC_FILTER) += vf_lcevc.o OBJS-$(CONFIG_LATENCY_FILTER) += f_latency.o OBJS-$(CONFIG_LENSCORRECTION_FILTER) += vf_lenscorrection.o OBJS-$(CONFIG_LENSFUN_FILTER) += vf_lensfun.o @@ -390,9 +392,9 @@ OBJS-$(CONFIG_MIDEQUALIZER_FILTER) += vf_midequalizer.o framesync.o OBJS-$(CONFIG_MINTERPOLATE_FILTER) += vf_minterpolate.o motion_estimation.o OBJS-$(CONFIG_MIX_FILTER) += vf_mix.o framesync.o OBJS-$(CONFIG_MONOCHROME_FILTER) += vf_monochrome.o -OBJS-$(CONFIG_MORPHO_FILTER) += vf_morpho.o +OBJS-$(CONFIG_MORPHO_FILTER) += vf_morpho.o framesync.o OBJS-$(CONFIG_MPDECIMATE_FILTER) += vf_mpdecimate.o -OBJS-$(CONFIG_MULTIPLY_FILTER) += vf_multiply.o +OBJS-$(CONFIG_MULTIPLY_FILTER) += vf_multiply.o framesync.o OBJS-$(CONFIG_NEGATE_FILTER) += vf_negate.o OBJS-$(CONFIG_NLMEANS_FILTER) += vf_nlmeans.o OBJS-$(CONFIG_NLMEANS_OPENCL_FILTER) += vf_nlmeans_opencl.o opencl.o opencl/nlmeans.o @@ -455,7 +457,7 @@ OBJS-$(CONFIG_ROBERTS_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o opencl/convolution.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 +OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o scale_eval.o framesync.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 @@ -463,7 +465,7 @@ OBJS-$(CONFIG_SCALE_QSV_FILTER) += vf_vpp_qsv.o OBJS-$(CONFIG_SCALE_VAAPI_FILTER) += vf_scale_vaapi.o scale_eval.o vaapi_vpp.o OBJS-$(CONFIG_SCALE_VT_FILTER) += vf_scale_vt.o scale_eval.o OBJS-$(CONFIG_SCALE_VULKAN_FILTER) += vf_scale_vulkan.o vulkan.o vulkan_filter.o -OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o scale_eval.o +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_SCHARR_FILTER) += vf_convolution.o @@ -563,6 +565,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_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 \ @@ -581,6 +584,8 @@ OBJS-$(CONFIG_XSTACK_VAAPI_FILTER) += vf_stack_vaapi.o framesync.o vaa OBJS-$(CONFIG_HSTACK_QSV_FILTER) += vf_stack_qsv.o framesync.o OBJS-$(CONFIG_VSTACK_QSV_FILTER) += vf_stack_qsv.o framesync.o OBJS-$(CONFIG_XSTACK_QSV_FILTER) += vf_stack_qsv.o framesync.o +OBJS-$(CONFIG_PAD_VAAPI_FILTER) += vf_pad_vaapi.o vaapi_vpp.o +OBJS-$(CONFIG_DRAWBOX_VAAPI_FILTER) += vf_drawbox_vaapi.o vaapi_vpp.o OBJS-$(CONFIG_ALLRGB_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_ALLYUV_FILTER) += vsrc_testsrc.o @@ -600,6 +605,7 @@ OBJS-$(CONFIG_NULLSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_OPENCLSRC_FILTER) += vf_program_opencl.o opencl.o OBJS-$(CONFIG_PAL75BARS_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_PAL100BARS_FILTER) += vsrc_testsrc.o +OBJS-$(CONFIG_PERLIN_FILTER) += vsrc_perlin.o perlin.o OBJS-$(CONFIG_QRENCODE_FILTER) += qrencode.o textutils.o OBJS-$(CONFIG_QRENCODESRC_FILTER) += qrencode.o textutils.o OBJS-$(CONFIG_RGBTESTSRC_FILTER) += vsrc_testsrc.o diff --git a/libavfilter/aap_template.c b/libavfilter/aap_template.c index ea9c815a8..0e0580fb3 100644 --- a/libavfilter/aap_template.c +++ b/libavfilter/aap_template.c @@ -36,18 +36,6 @@ #define fn2(a,b) fn3(a,b) #define fn(a) fn2(a, SAMPLE_FORMAT) -#if DEPTH == 64 -static double scalarproduct_double(const double *v1, const double *v2, int len) -{ - double p = 0.0; - - for (int i = 0; i < len; i++) - p += v1[i] * v2[i]; - - return p; -} -#endif - static ftype fn(fir_sample)(AudioAPContext *s, ftype sample, ftype *delay, ftype *coeffs, ftype *tmp, int *offset) { @@ -60,7 +48,7 @@ static ftype fn(fir_sample)(AudioAPContext *s, ftype sample, ftype *delay, #if DEPTH == 32 output = s->fdsp->scalarproduct_float(delay, tmp, s->kernel_size); #else - output = scalarproduct_double(delay, tmp, s->kernel_size); + output = s->fdsp->scalarproduct_double(delay, tmp, s->kernel_size); #endif if (--(*offset) < 0) diff --git a/libavfilter/aeval.c b/libavfilter/aeval.c index b26d75f12..0e7ba8df8 100644 --- a/libavfilter/aeval.c +++ b/libavfilter/aeval.c @@ -28,13 +28,12 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "avfilter.h" #include "audio.h" #include "filters.h" #include "formats.h" -#include "internal.h" static const char * const var_names[] = { "ch", ///< the value of the current channel @@ -243,23 +242,25 @@ static int config_props(AVFilterLink *outlink) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - EvalContext *eval = ctx->priv; + const EvalContext *eval = ctx->priv; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }; AVChannelLayout chlayouts[] = { eval->chlayout.nb_channels ? eval->chlayout : FF_COUNT2LAYOUT(eval->nb_channels), { 0 } }; int sample_rates[] = { eval->sample_rate, -1 }; int ret; - ret = ff_set_common_formats_from_list(ctx, sample_fmts); + ret = ff_set_common_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 activate(AVFilterContext *ctx) @@ -328,7 +329,7 @@ const AVFilter ff_asrc_aevalsrc = { .priv_size = sizeof(EvalContext), .inputs = NULL, FILTER_OUTPUTS(aevalsrc_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .priv_class = &aevalsrc_class, }; @@ -346,12 +347,12 @@ static const AVOption aeval_options[]= { AVFILTER_DEFINE_CLASS(aeval); -static int aeval_query_formats(AVFilterContext *ctx) +static int aeval_query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { AVFilterChannelLayouts *layouts; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; - EvalContext *eval = ctx->priv; + const EvalContext *eval = ctx->priv; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }; @@ -359,25 +360,22 @@ static int aeval_query_formats(AVFilterContext *ctx) // inlink supports any channel layout layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &cfg_in[0]->channel_layouts)) < 0) return ret; - if (eval->same_chlayout) { - if ((ret = ff_set_common_all_channel_counts(ctx)) < 0) - return ret; - } else { + if (!eval->same_chlayout) { // outlink supports only requested output channel layout layouts = NULL; if ((ret = ff_add_channel_layout(&layouts, &FF_COUNT2LAYOUT(eval->nb_channels))) < 0) return ret; - if ((ret = ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts)) < 0) return ret; } - if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts)) < 0) + if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts)) < 0) return ret; - return ff_set_common_all_samplerates(ctx); + return 0; } static int aeval_config_output(AVFilterLink *outlink) @@ -472,7 +470,7 @@ const AVFilter ff_af_aeval = { .priv_size = sizeof(EvalContext), FILTER_INPUTS(aeval_inputs), FILTER_OUTPUTS(aeval_outputs), - FILTER_QUERY_FUNC(aeval_query_formats), + FILTER_QUERY_FUNC2(aeval_query_formats), .priv_class = &aeval_class, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_aap.c b/libavfilter/af_aap.c index 85d905c1a..05608d7fb 100644 --- a/libavfilter/af_aap.c +++ b/libavfilter/af_aap.c @@ -21,13 +21,13 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "formats.h" #include "filters.h" -#include "internal.h" enum OutModes { IN_MODE, @@ -95,9 +95,11 @@ static const AVOption aap_options[] = { AVFILTER_DEFINE_CLASS(aap); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioAPContext *s = ctx->priv; + const AudioAPContext *s = ctx->priv; static const enum AVSampleFormat sample_fmts[3][3] = { { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }, { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, @@ -105,13 +107,11 @@ static int query_formats(AVFilterContext *ctx) }; int ret; - if ((ret = ff_set_common_all_channel_counts(ctx)) < 0) + if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + sample_fmts[s->precision])) < 0) return ret; - if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts[s->precision])) < 0) - return ret; - - return ff_set_common_all_samplerates(ctx); + return 0; } static int activate(AVFilterContext *ctx) @@ -325,7 +325,7 @@ const AVFilter ff_af_aap = { .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), - FILTER_QUERY_FUNC(query_formats), + 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 1fcbad878..e520b1b66 100644 --- a/libavfilter/af_acontrast.c +++ b/libavfilter/af_acontrast.c @@ -23,6 +23,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" typedef struct AudioContrastContext { const AVClass *class; diff --git a/libavfilter/af_acopy.c b/libavfilter/af_acopy.c index f65f04d46..9d06e2d4b 100644 --- a/libavfilter/af_acopy.c +++ b/libavfilter/af_acopy.c @@ -18,7 +18,7 @@ #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" static int filter_frame(AVFilterLink *inlink, AVFrame *in) { diff --git a/libavfilter/af_acrossover.c b/libavfilter/af_acrossover.c index 0e7781c77..3fd5c1d24 100644 --- a/libavfilter/af_acrossover.c +++ b/libavfilter/af_acrossover.c @@ -26,16 +26,15 @@ #include "libavutil/attributes.h" #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" -#include "libavutil/eval.h" #include "libavutil/float_dsp.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #define MAX_SPLITS 16 #define MAX_BANDS MAX_SPLITS + 1 @@ -109,9 +108,11 @@ static const AVOption acrossover_options[] = { AVFILTER_DEFINE_CLASS(acrossover); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioCrossoverContext *s = ctx->priv; + const AudioCrossoverContext *s = ctx->priv; static const enum AVSampleFormat auto_sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, @@ -122,9 +123,7 @@ static int query_formats(AVFilterContext *ctx) AV_SAMPLE_FMT_NONE }; const enum AVSampleFormat *sample_fmts_list = sample_fmts; - int ret = ff_set_common_all_channel_counts(ctx); - if (ret < 0) - return ret; + int ret; switch (s->precision) { case 0: @@ -139,11 +138,11 @@ static int query_formats(AVFilterContext *ctx) default: break; } - ret = ff_set_common_formats_from_list(ctx, sample_fmts_list); + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts_list); if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + return 0; } static int parse_gains(AVFilterContext *ctx) @@ -628,7 +627,7 @@ const AVFilter ff_af_acrossover = { .uninit = uninit, FILTER_INPUTS(inputs), .outputs = NULL, - FILTER_QUERY_FUNC(query_formats), + 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 5fc942224..f064f5b04 100644 --- a/libavfilter/af_acrusher.c +++ b/libavfilter/af_acrusher.c @@ -18,9 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "audio.h" typedef struct LFOContext { diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c index 378922573..819ad2ab5 100644 --- a/libavfilter/af_adeclick.c +++ b/libavfilter/af_adeclick.c @@ -19,12 +19,12 @@ */ #include "libavutil/audio_fifo.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "avfilter.h" #include "audio.h" #include "filters.h" -#include "internal.h" typedef struct DeclickChannel { double *auxiliary; diff --git a/libavfilter/af_adecorrelate.c b/libavfilter/af_adecorrelate.c index 87355e72e..5cde9e7e1 100644 --- a/libavfilter/af_adecorrelate.c +++ b/libavfilter/af_adecorrelate.c @@ -22,10 +22,12 @@ #include "libavutil/channel_layout.h" #include "libavutil/ffmath.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/random_seed.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #define MAX_STAGES 16 #define FILTER_FC 1100.0 diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c index 87a86170a..ab2d66044 100644 --- a/libavfilter/af_adelay.c +++ b/libavfilter/af_adelay.c @@ -19,13 +19,12 @@ */ #include "libavutil/avstring.h" -#include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "avfilter.h" #include "audio.h" #include "filters.h" -#include "internal.h" typedef struct ChanDelay { int64_t delay; diff --git a/libavfilter/af_adenorm.c b/libavfilter/af_adenorm.c index f5f903917..7dc3c0f73 100644 --- a/libavfilter/af_adenorm.c +++ b/libavfilter/af_adenorm.c @@ -21,7 +21,7 @@ #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" enum FilterType { DC_TYPE, diff --git a/libavfilter/af_aderivative.c b/libavfilter/af_aderivative.c index 4883972dc..1254aa945 100644 --- a/libavfilter/af_aderivative.c +++ b/libavfilter/af_aderivative.c @@ -19,7 +19,7 @@ #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct ADerivativeContext { const AVClass *class; diff --git a/libavfilter/af_adrc.c b/libavfilter/af_adrc.c index 34e5433a6..7410b99ed 100644 --- a/libavfilter/af_adrc.c +++ b/libavfilter/af_adrc.c @@ -22,12 +22,12 @@ #include "libavutil/eval.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" static const char * const var_names[] = { "ch", ///< the value of the current channel @@ -362,6 +362,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); AudioDRCContext *s = ctx->priv; AVFrame *out; int ret; @@ -372,7 +373,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) goto fail; } - s->var_values[VAR_SN] = outlink->sample_count_in; + s->var_values[VAR_SN] = outl->sample_count_in; s->var_values[VAR_T] = s->var_values[VAR_SN] * (double)1/outlink->sample_rate; s->in = in; diff --git a/libavfilter/af_adynamicequalizer.c b/libavfilter/af_adynamicequalizer.c index aa1dc5f45..ba03faff6 100644 --- a/libavfilter/af_adynamicequalizer.c +++ b/libavfilter/af_adynamicequalizer.c @@ -19,9 +19,11 @@ #include #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "formats.h" enum DetectionModes { @@ -108,9 +110,11 @@ typedef struct AudioDynamicEqualizerContext { ChannelContext *cc; } AudioDynamicEqualizerContext; -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioDynamicEqualizerContext *s = ctx->priv; + const AudioDynamicEqualizerContext *s = ctx->priv; static const enum AVSampleFormat sample_fmts[3][3] = { { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }, { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, @@ -118,13 +122,11 @@ static int query_formats(AVFilterContext *ctx) }; int ret; - if ((ret = ff_set_common_all_channel_counts(ctx)) < 0) + if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + sample_fmts[s->precision])) < 0) return ret; - if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts[s->precision])) < 0) - return ret; - - return ff_set_common_all_samplerates(ctx); + return 0; } static double get_coef(double x, double sr) @@ -279,7 +281,7 @@ const AVFilter ff_af_adynamicequalizer = { .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + 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 8afe59222..a0276616c 100644 --- a/libavfilter/af_adynamicsmooth.c +++ b/libavfilter/af_adynamicsmooth.c @@ -20,6 +20,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" typedef struct AudioDynamicSmoothContext { const AVClass *class; diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c index 0b57c0e58..b1c656e03 100644 --- a/libavfilter/af_aecho.c +++ b/libavfilter/af_aecho.c @@ -20,12 +20,12 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "avfilter.h" #include "audio.h" #include "filters.h" -#include "internal.h" typedef struct AudioEchoContext { const AVClass *class; diff --git a/libavfilter/af_aemphasis.c b/libavfilter/af_aemphasis.c index d808eec1c..4bde91671 100644 --- a/libavfilter/af_aemphasis.c +++ b/libavfilter/af_aemphasis.c @@ -20,7 +20,7 @@ #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "audio.h" typedef struct BiquadCoeffs { diff --git a/libavfilter/af_aexciter.c b/libavfilter/af_aexciter.c index 400d6707b..3fe7ce799 100644 --- a/libavfilter/af_aexciter.c +++ b/libavfilter/af_aexciter.c @@ -18,9 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "audio.h" typedef struct ChannelParams { diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c index 3a4587346..7cc5182d1 100644 --- a/libavfilter/af_afade.c +++ b/libavfilter/af_afade.c @@ -29,7 +29,6 @@ #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" typedef struct AudioFadeContext { const AVClass *class; @@ -452,8 +451,8 @@ const AVFilter ff_af_afade = { #if CONFIG_ACROSSFADE_FILTER static const AVOption acrossfade_options[] = { - { "nb_samples", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX/10, FLAGS }, - { "ns", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX/10, 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 }, { "d", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0 }, 0, 60000000, FLAGS }, { "overlap", "overlap 1st stream end with 2nd stream start", OFFSET(overlap), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, FLAGS }, diff --git a/libavfilter/af_afftdn.c b/libavfilter/af_afftdn.c index 5c8712daf..fd6b2b268 100644 --- a/libavfilter/af_afftdn.c +++ b/libavfilter/af_afftdn.c @@ -23,6 +23,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "avfilter.h" @@ -354,8 +355,9 @@ static void process_frame(AVFilterContext *ctx, double *prior, double *prior_band_excit, int track_noise) { AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); const double *abs_var = dnch->abs_var; - const double ratio = outlink->frame_count_out ? s->ratio : 1.0; + const double ratio = outl->frame_count_out ? s->ratio : 1.0; const double rratio = 1. - ratio; const int *bin2band = s->bin2band; double *noisy_data = dnch->noisy_data; diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c index 2b2a70b0b..98b09e666 100644 --- a/libavfilter/af_afftfilt.c +++ b/libavfilter/af_afftfilt.c @@ -19,7 +19,7 @@ */ #include "libavutil/avstring.h" -#include "libavfilter/internal.h" +#include "libavutil/mem.h" #include "libavutil/common.h" #include "libavutil/cpu.h" #include "libavutil/opt.h" diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c index 9df9c28c7..c641893d4 100644 --- a/libavfilter/af_afir.c +++ b/libavfilter/af_afir.c @@ -27,13 +27,12 @@ #include "libavutil/avassert.h" #include "libavutil/cpu.h" +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" -#include "libavutil/common.h" #include "libavutil/float_dsp.h" #include "libavutil/frame.h" -#include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/opt.h" #include "libavutil/rational.h" @@ -42,10 +41,86 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" -#include "af_afir.h" #include "af_afirdsp.h" -#include "video.h" + +#define MAX_IR_STREAMS 32 + +typedef struct AudioFIRSegment { + int nb_partitions; + int part_size; + int block_size; + int fft_length; + int coeff_size; + int input_size; + int input_offset; + + int *output_offset; + int *part_index; + + AVFrame *sumin; + AVFrame *sumout; + AVFrame *blockout; + AVFrame *tempin; + AVFrame *tempout; + AVFrame *buffer; + AVFrame *coeff; + AVFrame *input; + AVFrame *output; + + AVTXContext **ctx, **tx, **itx; + av_tx_fn ctx_fn, tx_fn, itx_fn; +} AudioFIRSegment; + +typedef struct AudioFIRContext { + const AVClass *class; + + float wet_gain; + float dry_gain; + float length; + int gtype; + float ir_norm; + float ir_link; + float ir_gain; + int ir_format; + int ir_load; + float max_ir_len; + int response; + int w, h; + AVRational frame_rate; + int ir_channel; + int minp; + int maxp; + int nb_irs; + int prev_selir; + int selir; + int precision; + int format; + + int eof_coeffs[MAX_IR_STREAMS]; + int have_coeffs[MAX_IR_STREAMS]; + int nb_taps[MAX_IR_STREAMS]; + int nb_segments[MAX_IR_STREAMS]; + int max_offset[MAX_IR_STREAMS]; + int nb_channels; + int one2many; + int prev_is_disabled; + int *loading; + double *ch_gain; + + AudioFIRSegment seg[MAX_IR_STREAMS][1024]; + + AVFrame *in; + AVFrame *xfade[2]; + AVFrame *fadein[2]; + AVFrame *ir[MAX_IR_STREAMS]; + AVFrame *norm_ir[MAX_IR_STREAMS]; + int min_part_size; + int max_part_size; + int64_t pts; + + AudioFIRDSPContext afirdsp; + AVFloatDSPContext *fdsp; +} AudioFIRContext; #define DEPTH 32 #include "afir_template.c" @@ -464,9 +539,11 @@ static int activate(AVFilterContext *ctx) return FFERROR_NOT_READY; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioFIRContext *s = ctx->priv; + const AudioFIRContext *s = ctx->priv; static const enum AVSampleFormat sample_fmts[3][3] = { { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }, { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, @@ -474,32 +551,29 @@ static int query_formats(AVFilterContext *ctx) }; int ret; - if (s->ir_format) { - ret = ff_set_common_all_channel_counts(ctx); - if (ret < 0) - return ret; - } else { + if (!s->ir_format) { AVFilterChannelLayouts *mono = NULL; AVFilterChannelLayouts *layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[0]->outcfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &cfg_in[0]->channel_layouts)) < 0) return ret; - if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts)) < 0) return ret; ret = ff_add_channel_layout(&mono, &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO); if (ret) return ret; for (int i = 1; i < ctx->nb_inputs; i++) { - if ((ret = ff_channel_layouts_ref(mono, &ctx->inputs[i]->outcfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(mono, &cfg_in[i]->channel_layouts)) < 0) return ret; } } - if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts[s->precision])) < 0) + if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + sample_fmts[s->precision])) < 0) return ret; - return ff_set_common_all_samplerates(ctx); + return 0; } static int config_output(AVFilterLink *outlink) @@ -708,7 +782,7 @@ const AVFilter ff_af_afir = { .description = NULL_IF_CONFIG_SMALL("Apply Finite Impulse Response filter with supplied coefficients in additional stream(s)."), .priv_size = sizeof(AudioFIRContext), .priv_class = &afir_class, - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), FILTER_OUTPUTS(outputs), .init = init, .activate = activate, diff --git a/libavfilter/af_afir.h b/libavfilter/af_afir.h deleted file mode 100644 index 8e4afd79c..000000000 --- a/libavfilter/af_afir.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2017 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 - */ - -#ifndef AVFILTER_AFIR_H -#define AVFILTER_AFIR_H - -#include "libavutil/float_dsp.h" -#include "libavutil/frame.h" -#include "libavutil/rational.h" -#include "libavutil/tx.h" -#include "avfilter.h" -#include "af_afirdsp.h" - -#define MAX_IR_STREAMS 32 - -typedef struct AudioFIRSegment { - int nb_partitions; - int part_size; - int block_size; - int fft_length; - int coeff_size; - int input_size; - int input_offset; - - int *output_offset; - int *part_index; - - AVFrame *sumin; - AVFrame *sumout; - AVFrame *blockout; - AVFrame *tempin; - AVFrame *tempout; - AVFrame *buffer; - AVFrame *coeff; - AVFrame *input; - AVFrame *output; - - AVTXContext **ctx, **tx, **itx; - av_tx_fn ctx_fn, tx_fn, itx_fn; -} AudioFIRSegment; - -typedef struct AudioFIRContext { - const AVClass *class; - - float wet_gain; - float dry_gain; - float length; - int gtype; - float ir_norm; - float ir_link; - float ir_gain; - int ir_format; - int ir_load; - float max_ir_len; - int response; - int w, h; - AVRational frame_rate; - int ir_channel; - int minp; - int maxp; - int nb_irs; - int prev_selir; - int selir; - int precision; - int format; - - int eof_coeffs[MAX_IR_STREAMS]; - int have_coeffs[MAX_IR_STREAMS]; - int nb_taps[MAX_IR_STREAMS]; - int nb_segments[MAX_IR_STREAMS]; - int max_offset[MAX_IR_STREAMS]; - int nb_channels; - int one2many; - int prev_is_disabled; - int *loading; - double *ch_gain; - - AudioFIRSegment seg[MAX_IR_STREAMS][1024]; - - AVFrame *in; - AVFrame *xfade[2]; - AVFrame *fadein[2]; - AVFrame *ir[MAX_IR_STREAMS]; - AVFrame *norm_ir[MAX_IR_STREAMS]; - int min_part_size; - int max_part_size; - int64_t pts; - - AudioFIRDSPContext afirdsp; - AVFloatDSPContext *fdsp; -} AudioFIRContext; - -#endif /* AVFILTER_AFIR_H */ diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c index 8a3bdee7f..a7d05a9ce 100644 --- a/libavfilter/af_aformat.c +++ b/libavfilter/af_aformat.c @@ -26,152 +26,120 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" typedef struct AFormatContext { const AVClass *class; - AVFilterFormats *formats; - AVFilterFormats *sample_rates; - AVFilterChannelLayouts *channel_layouts; + enum AVSampleFormat *formats; + unsigned nb_formats; - char *formats_str; - char *sample_rates_str; - char *channel_layouts_str; + int *sample_rates; + unsigned nb_sample_rates; + + AVChannelLayout *channel_layouts; + unsigned nb_channel_layouts; } AFormatContext; +static const AVOptionArrayDef array_def = { .sep = '|' }; + #define OFFSET(x) offsetof(AFormatContext, x) #define A AV_OPT_FLAG_AUDIO_PARAM #define F AV_OPT_FLAG_FILTERING_PARAM static const AVOption aformat_options[] = { - { "sample_fmts", "A '|'-separated list of sample formats.", OFFSET(formats_str), AV_OPT_TYPE_STRING, .flags = A|F }, - { "f", "A '|'-separated list of sample formats.", OFFSET(formats_str), AV_OPT_TYPE_STRING, .flags = A|F }, - { "sample_rates", "A '|'-separated list of sample rates.", OFFSET(sample_rates_str), AV_OPT_TYPE_STRING, .flags = A|F }, - { "r", "A '|'-separated list of sample rates.", OFFSET(sample_rates_str), AV_OPT_TYPE_STRING, .flags = A|F }, - { "channel_layouts", "A '|'-separated list of channel layouts.", OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = A|F }, - { "cl", "A '|'-separated list of channel layouts.", OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = A|F }, + { "sample_fmts", "A '|'-separated list of sample formats.", OFFSET(formats), + AV_OPT_TYPE_SAMPLE_FMT | AV_OPT_TYPE_FLAG_ARRAY, .default_val.arr = &array_def, .flags = A|F }, + { "f", "A '|'-separated list of sample formats.", OFFSET(formats), + AV_OPT_TYPE_SAMPLE_FMT | AV_OPT_TYPE_FLAG_ARRAY, .default_val.arr = &array_def, .flags = A|F }, + { "sample_rates", "A '|'-separated list of sample rates.", OFFSET(sample_rates), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .default_val.arr = &array_def, .min = 1, .max = INT_MAX, .flags = A|F }, + { "r", "A '|'-separated list of sample rates.", OFFSET(sample_rates), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .default_val.arr = &array_def, .min = 1, .max = INT_MAX, .flags = A|F }, + { "channel_layouts", "A '|'-separated list of channel layouts.", OFFSET(channel_layouts), + AV_OPT_TYPE_CHLAYOUT | AV_OPT_TYPE_FLAG_ARRAY, .default_val.arr = &array_def, .flags = A|F }, + { "cl", "A '|'-separated list of channel layouts.", OFFSET(channel_layouts), + AV_OPT_TYPE_CHLAYOUT | AV_OPT_TYPE_FLAG_ARRAY, .default_val.arr = &array_def, .flags = A|F }, { NULL } }; AVFILTER_DEFINE_CLASS(aformat); -#define PARSE_FORMATS(str, type, list, add_to_list, get_fmt, none, desc) \ -do { \ - char *next, *cur = str; \ - int ret; \ - \ - while (cur) { \ - type fmt; \ - next = strchr(cur, '|'); \ - if (next) \ - *next++ = 0; \ - \ - if ((fmt = get_fmt(cur)) == none) { \ - av_log(ctx, AV_LOG_ERROR, "Error parsing " desc ": %s.\n", cur);\ - return AVERROR(EINVAL); \ - } \ - if ((ret = add_to_list(&list, fmt)) < 0) { \ - return ret; \ - } \ - \ - cur = next; \ - } \ -} while (0) - -static int get_sample_rate(const char *samplerate) -{ - int ret = strtol(samplerate, NULL, 0); - return FFMAX(ret, 0); -} - -static int parse_channel_layouts(AVFilterContext *ctx) +static av_cold int init(AVFilterContext *ctx) { AFormatContext *s = ctx->priv; - char *next, *cur = s->channel_layouts_str; - AVChannelLayout fmt = { 0 }; - int ret; - while (cur) { - next = strchr(cur, '|'); - if (next) - *next++ = 0; + // terminate format lists for ff_set*_from_list() + if (s->nb_formats) { + void *tmp = av_realloc_array(s->formats, s->nb_formats + 1, + sizeof(*s->formats)); + if (!tmp) + return AVERROR(ENOMEM); + s->formats = tmp; + s->formats[s->nb_formats] = AV_SAMPLE_FMT_NONE; - ret = av_channel_layout_from_string(&fmt, cur); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", cur); - return AVERROR(EINVAL); - } - ret = ff_add_channel_layout(&s->channel_layouts, &fmt); - av_channel_layout_uninit(&fmt); - if (ret < 0) - return ret; - - cur = next; + } + if (s->nb_sample_rates) { + void *tmp = av_realloc_array(s->sample_rates, s->nb_sample_rates + 1, + sizeof(*s->sample_rates)); + if (!tmp) + return AVERROR(ENOMEM); + s->sample_rates = tmp; + s->sample_rates[s->nb_sample_rates] = -1; + } + if (s->nb_channel_layouts) { + void *tmp = av_realloc_array(s->channel_layouts, s->nb_channel_layouts + 1, + sizeof(*s->channel_layouts)); + if (!tmp) + return AVERROR(ENOMEM); + s->channel_layouts = tmp; + s->channel_layouts[s->nb_channel_layouts] = (AVChannelLayout){ .nb_channels = 0 }; } return 0; } -static av_cold int init(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AFormatContext *s = ctx->priv; + const AFormatContext *s = ctx->priv; int ret; - PARSE_FORMATS(s->formats_str, enum AVSampleFormat, s->formats, - ff_add_format, av_get_sample_fmt, AV_SAMPLE_FMT_NONE, "sample format"); - PARSE_FORMATS(s->sample_rates_str, int, s->sample_rates, ff_add_format, - get_sample_rate, 0, "sample rate"); - ret = parse_channel_layouts(ctx); - if (ret < 0) - return ret; + if (s->nb_formats) { + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, s->formats); + if (ret < 0) + return ret; + } + + if (s->nb_sample_rates) { + ret = ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, s->sample_rates); + if (ret < 0) + return ret; + } + + if (s->nb_channel_layouts) { + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, s->channel_layouts); + if (ret < 0) + return ret; + } return 0; } -static av_cold void uninit(AVFilterContext *ctx) -{ - AFormatContext *s = ctx->priv; - - ff_formats_unref(&s->formats); - ff_formats_unref(&s->sample_rates); - ff_channel_layouts_unref(&s->channel_layouts); -} - -static int query_formats(AVFilterContext *ctx) -{ - AFormatContext *s = ctx->priv; - int ret; - - ret = ff_set_common_formats(ctx, s->formats ? s->formats : - ff_all_formats(AVMEDIA_TYPE_AUDIO)); - s->formats = NULL; - if (ret < 0) - return ret; - ret = ff_set_common_samplerates(ctx, s->sample_rates ? s->sample_rates : - ff_all_samplerates()); - s->sample_rates = NULL; - if (ret < 0) - return ret; - ret = ff_set_common_channel_layouts(ctx, s->channel_layouts ? s->channel_layouts : - ff_all_channel_counts()); - s->channel_layouts = NULL; - return ret; -} - const AVFilter ff_af_aformat = { .name = "aformat", .description = NULL_IF_CONFIG_SMALL("Convert the input audio to one of the specified formats."), .init = init, - .uninit = uninit, .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_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_afreqshift.c b/libavfilter/af_afreqshift.c index 9a6cfd2fc..fa93eed99 100644 --- a/libavfilter/af_afreqshift.c +++ b/libavfilter/af_afreqshift.c @@ -24,6 +24,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #define MAX_NB_COEFFS 16 diff --git a/libavfilter/af_afwtdn.c b/libavfilter/af_afwtdn.c index 8d69259e7..fb172f26c 100644 --- a/libavfilter/af_afwtdn.c +++ b/libavfilter/af_afwtdn.c @@ -21,6 +21,7 @@ #include #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c index d72548595..09655b7f8 100644 --- a/libavfilter/af_agate.c +++ b/libavfilter/af_agate.c @@ -310,26 +310,28 @@ static int activate(AVFilterContext *ctx) return 0; } -static int scquery_formats(AVFilterContext *ctx) +static int scquery_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE }; - int ret = ff_channel_layouts_ref(ff_all_channel_counts(), - &ctx->inputs[1]->outcfg.channel_layouts); + int ret; + + /* Generic code will link the channel properties of the main input and the + * output; it won't touch the second input as its channel_layouts is already + * set. */ + ret = ff_channel_layouts_ref(ff_all_channel_counts(), + &cfg_in[1]->channel_layouts); if (ret < 0) return ret; - /* This will link the channel properties of the main input and the output; - * it won't touch the second input as its channel_layouts is already set. */ - if ((ret = ff_set_common_all_channel_counts(ctx)) < 0) + if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts)) < 0) return ret; - if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts)) < 0) - return ret; - - return ff_set_common_all_samplerates(ctx); + return 0; } static int scconfig_output(AVFilterLink *outlink) @@ -385,7 +387,7 @@ const AVFilter ff_af_sidechaingate = { .uninit = uninit, FILTER_INPUTS(sidechaingate_inputs), FILTER_OUTPUTS(sidechaingate_outputs), - FILTER_QUERY_FUNC(scquery_formats), + FILTER_QUERY_FUNC2(scquery_formats), .process_command = ff_filter_process_command, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c index ff35f6b92..dfeeb34c9 100644 --- a/libavfilter/af_aiir.c +++ b/libavfilter/af_aiir.c @@ -22,12 +22,13 @@ #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/xga_font_data.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct ThreadData { @@ -77,9 +78,11 @@ typedef struct AudioIIRContext { int (*iir_channel)(AVFilterContext *ctx, void *arg, int ch, int nb_jobs); } AudioIIRContext; -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioIIRContext *s = ctx->priv; + const AudioIIRContext *s = ctx->priv; AVFilterFormats *formats; enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBLP, @@ -92,23 +95,17 @@ static int query_formats(AVFilterContext *ctx) int ret; if (s->response) { - AVFilterLink *videolink = ctx->outputs[1]; - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &videolink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(formats, &cfg_out[1]->formats)) < 0) return ret; } - ret = ff_set_common_all_channel_counts(ctx); - if (ret < 0) - return ret; - sample_fmts[0] = s->sample_format; - ret = ff_set_common_formats_from_list(ctx, sample_fmts); + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + return 0; } #define IIR_CH(name, type, min, max, need_clipping) \ @@ -819,7 +816,6 @@ static void solve(double *matrix, double *vector, int n, double *y, double *x, d static int convert_serial2parallel(AVFilterContext *ctx, int channels) { AudioIIRContext *s = ctx->priv; - int ret = 0; for (int ch = 0; ch < channels; ch++) { IIRChannel *iir = &s->iir[ch]; @@ -828,17 +824,17 @@ static int convert_serial2parallel(AVFilterContext *ctx, int channels) double *impulse = av_calloc(length, sizeof(*impulse)); double *y = av_calloc(length, sizeof(*y)); double *resp = av_calloc(length, sizeof(*resp)); - double *M = av_calloc((length - 1) * 2 * nb_biquads, sizeof(*M)); - double *W = av_calloc((length - 1) * 2 * nb_biquads, sizeof(*W)); + double *M = av_calloc((length - 1) * nb_biquads, 2 * 2 * sizeof(*M)); + double *W; if (!impulse || !y || !resp || !M) { av_free(impulse); av_free(y); av_free(resp); av_free(M); - av_free(W); return AVERROR(ENOMEM); } + W = M + (length - 1) * 2 * nb_biquads; impulse[0] = 1.; @@ -877,10 +873,6 @@ static int convert_serial2parallel(AVFilterContext *ctx, int channels) av_free(y); av_free(resp); av_free(M); - av_free(W); - - if (ret < 0) - return ret; } return 0; @@ -1438,14 +1430,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) static int config_video(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AudioIIRContext *s = ctx->priv; outlink->sample_aspect_ratio = (AVRational){1,1}; outlink->w = s->w; outlink->h = s->h; - outlink->frame_rate = s->rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->rate; + outlink->time_base = av_inv_q(l->frame_rate); return 0; } @@ -1575,7 +1568,7 @@ const AVFilter ff_af_aiir = { .init = init, .uninit = uninit, FILTER_INPUTS(inputs), - FILTER_QUERY_FUNC(query_formats), + 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 9a8670476..a08616f69 100644 --- a/libavfilter/af_alimiter.c +++ b/libavfilter/af_alimiter.c @@ -27,11 +27,12 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/fifo.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct MetaItem { int64_t pts; diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c index 26040e5ed..16507299b 100644 --- a/libavfilter/af_amerge.c +++ b/libavfilter/af_amerge.c @@ -26,12 +26,12 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "filters.h" #include "audio.h" #include "formats.h" -#include "internal.h" #define SWR_CH_MAX 64 diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index f55c5724d..bc9720092 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -37,13 +37,13 @@ #include "libavutil/eval.h" #include "libavutil/float_dsp.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #define INPUT_ON 1 /**< input is active */ #define INPUT_EOF 2 /**< input has reached EOF (may still be active) */ diff --git a/libavfilter/af_amultiply.c b/libavfilter/af_amultiply.c index 4ae355c79..5090098c1 100644 --- a/libavfilter/af_amultiply.c +++ b/libavfilter/af_amultiply.c @@ -21,11 +21,11 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" typedef struct AudioMultiplyContext { const AVClass *class; diff --git a/libavfilter/af_anequalizer.c b/libavfilter/af_anequalizer.c index 37ebcb5db..26e9c3cdd 100644 --- a/libavfilter/af_anequalizer.c +++ b/libavfilter/af_anequalizer.c @@ -22,11 +22,12 @@ #include "libavutil/intreadwrite.h" #include "libavutil/avstring.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "audio.h" #include "video.h" @@ -216,13 +217,11 @@ 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 *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; - AudioNEqualizerContext *s = ctx->priv; - AVFilterFormats *formats; - AVFilterChannelLayouts *layouts; + const AudioNEqualizerContext *s = ctx->priv; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBLP, @@ -231,25 +230,13 @@ static int query_formats(AVFilterContext *ctx) int ret; if (s->draw_curves) { - AVFilterLink *videolink = ctx->outputs[1]; - formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &videolink->incfg.formats)) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, pix_fmts); + if (ret < 0) return 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) - return ret; - - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0 || - (ret = ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts)) < 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_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); + if (ret < 0) return ret; return 0; @@ -774,7 +761,7 @@ const AVFilter ff_af_anequalizer = { .uninit = uninit, FILTER_INPUTS(inputs), .outputs = NULL, - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .process_command = process_command, .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | diff --git a/libavfilter/af_anlmdndsp.h b/libavfilter/af_anlmdndsp.h index d8f5136cd..4b4c3d8b6 100644 --- a/libavfilter/af_anlmdndsp.h +++ b/libavfilter/af_anlmdndsp.h @@ -26,7 +26,6 @@ #include "audio.h" #include "avfilter.h" #include "formats.h" -#include "internal.h" typedef struct AudioNLMDNDSPContext { float (*compute_distance_ssd)(const float *f1, const float *f2, ptrdiff_t K); diff --git a/libavfilter/af_anlms.c b/libavfilter/af_anlms.c index 9b0d11cd6..4e83a0501 100644 --- a/libavfilter/af_anlms.c +++ b/libavfilter/af_anlms.c @@ -21,13 +21,13 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" enum OutModes { IN_MODE, @@ -87,9 +87,11 @@ static const AVOption anlms_options[] = { AVFILTER_DEFINE_CLASS_EXT(anlms, "anlm(f|s)", anlms_options); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioNLMSContext *s = ctx->priv; + const AudioNLMSContext *s = ctx->priv; static const enum AVSampleFormat sample_fmts[3][3] = { { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }, { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, @@ -97,13 +99,11 @@ static int query_formats(AVFilterContext *ctx) }; int ret; - if ((ret = ff_set_common_all_channel_counts(ctx)) < 0) + if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + sample_fmts[s->precision])) < 0) return ret; - if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts[s->precision])) < 0) - return ret; - - return ff_set_common_all_samplerates(ctx); + return 0; } static int activate(AVFilterContext *ctx) @@ -277,7 +277,7 @@ const AVFilter ff_af_anlmf = { .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), - FILTER_QUERY_FUNC(query_formats), + 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 257dba1a4..d7645fd0e 100644 --- a/libavfilter/af_anull.c +++ b/libavfilter/af_anull.c @@ -24,7 +24,7 @@ #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "libavutil/internal.h" const AVFilter ff_af_anull = { diff --git a/libavfilter/af_apad.c b/libavfilter/af_apad.c index 1e0ecd201..6cdfd1597 100644 --- a/libavfilter/af_apad.c +++ b/libavfilter/af_apad.c @@ -33,7 +33,6 @@ #include "avfilter.h" #include "audio.h" #include "filters.h" -#include "internal.h" typedef struct APadContext { const AVClass *class; diff --git a/libavfilter/af_aphaser.c b/libavfilter/af_aphaser.c index 4690276a6..b070f4d2a 100644 --- a/libavfilter/af_aphaser.c +++ b/libavfilter/af_aphaser.c @@ -24,10 +24,11 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "generate_wave_table.h" typedef struct AudioPhaserContext { diff --git a/libavfilter/af_apsyclip.c b/libavfilter/af_apsyclip.c index 6a0c23d6e..5afc3930c 100644 --- a/libavfilter/af_apsyclip.c +++ b/libavfilter/af_apsyclip.c @@ -19,12 +19,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" typedef struct AudioPsyClipContext { const AVClass *class; diff --git a/libavfilter/af_apulsator.c b/libavfilter/af_apulsator.c index e471936d1..4272e5f3a 100644 --- a/libavfilter/af_apulsator.c +++ b/libavfilter/af_apulsator.c @@ -22,8 +22,8 @@ #include "libavutil/channel_layout.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "audio.h" enum PulsatorModes { SINE, TRIANGLE, SQUARE, SAWUP, SAWDOWN, NB_MODES }; @@ -185,19 +185,30 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ff_filter_frame(outlink, out); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AVFilterChannelLayouts *layout = NULL; - AVFilterFormats *formats = NULL; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_DBL, + AV_SAMPLE_FMT_NONE, + }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; + int ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_DBL )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_set_common_channel_layouts (ctx , layout )) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) + return ret; + + return 0; } static int config_input(AVFilterLink *inlink) @@ -245,5 +256,5 @@ const AVFilter ff_af_apulsator = { .priv_class = &apulsator_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c index 8ff2fe597..d6de07404 100644 --- a/libavfilter/af_aresample.c +++ b/libavfilter/af_aresample.c @@ -34,7 +34,6 @@ #include "audio.h" #include "filters.h" #include "formats.h" -#include "internal.h" typedef struct AResampleContext { const AVClass *class; @@ -64,16 +63,15 @@ static av_cold void uninit(AVFilterContext *ctx) swr_free(&aresample->swr); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AResampleContext *aresample = ctx->priv; + const AResampleContext *aresample = ctx->priv; enum AVSampleFormat out_format; AVChannelLayout out_layout = { 0 }; int64_t out_rate; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; - AVFilterFormats *in_formats, *out_formats; AVFilterFormats *in_samplerates, *out_samplerates; AVFilterChannelLayouts *in_layouts, *out_layouts; @@ -85,15 +83,15 @@ static int query_formats(AVFilterContext *ctx) av_opt_get_int(aresample->swr, "osr", 0, &out_rate); in_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO); - if ((ret = ff_formats_ref(in_formats, &inlink->outcfg.formats)) < 0) + if ((ret = ff_formats_ref(in_formats, &cfg_in[0]->formats)) < 0) return ret; in_samplerates = ff_all_samplerates(); - if ((ret = ff_formats_ref(in_samplerates, &inlink->outcfg.samplerates)) < 0) + if ((ret = ff_formats_ref(in_samplerates, &cfg_in[0]->samplerates)) < 0) return ret; in_layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(in_layouts, &inlink->outcfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(in_layouts, &cfg_in[0]->channel_layouts)) < 0) return ret; if(out_rate > 0) { @@ -103,7 +101,7 @@ static int query_formats(AVFilterContext *ctx) out_samplerates = ff_all_samplerates(); } - if ((ret = ff_formats_ref(out_samplerates, &outlink->incfg.samplerates)) < 0) + if ((ret = ff_formats_ref(out_samplerates, &cfg_out[0]->samplerates)) < 0) return ret; if(out_format != AV_SAMPLE_FMT_NONE) { @@ -111,7 +109,7 @@ static int query_formats(AVFilterContext *ctx) out_formats = ff_make_format_list(formatlist); } else out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO); - if ((ret = ff_formats_ref(out_formats, &outlink->incfg.formats)) < 0) + if ((ret = ff_formats_ref(out_formats, &cfg_out[0]->formats)) < 0) return ret; av_opt_get_chlayout(aresample->swr, "ochl", 0, &out_layout); @@ -122,7 +120,7 @@ static int query_formats(AVFilterContext *ctx) out_layouts = ff_all_channel_counts(); av_channel_layout_uninit(&out_layout); - return ff_channel_layouts_ref(out_layouts, &outlink->incfg.channel_layouts); + return ff_channel_layouts_ref(out_layouts, &cfg_out[0]->channel_layouts); } @@ -373,5 +371,5 @@ const AVFilter ff_af_aresample = { .priv_class = &aresample_class, FILTER_INPUTS(ff_audio_default_filterpad), FILTER_OUTPUTS(aresample_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_arls.c b/libavfilter/af_arls.c index bbe8e3cb2..3f182454e 100644 --- a/libavfilter/af_arls.c +++ b/libavfilter/af_arls.c @@ -20,13 +20,13 @@ #include "libavutil/common.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "formats.h" #include "filters.h" -#include "internal.h" enum OutModes { IN_MODE, @@ -84,9 +84,11 @@ static const AVOption arls_options[] = { AVFILTER_DEFINE_CLASS(arls); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioRLSContext *s = ctx->priv; + const AudioRLSContext *s = ctx->priv; static const enum AVSampleFormat sample_fmts[3][3] = { { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }, { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, @@ -94,13 +96,11 @@ static int query_formats(AVFilterContext *ctx) }; int ret; - if ((ret = ff_set_common_all_channel_counts(ctx)) < 0) + if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, + sample_fmts[s->precision])) < 0) return ret; - if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts[s->precision])) < 0) - return ret; - - return ff_set_common_all_samplerates(ctx); + return 0; } static int activate(AVFilterContext *ctx) @@ -291,7 +291,7 @@ const AVFilter ff_af_arls = { .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), - FILTER_QUERY_FUNC(query_formats), + 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 ee005eb34..3c2ae6370 100644 --- a/libavfilter/af_arnndn.c +++ b/libavfilter/af_arnndn.c @@ -34,6 +34,7 @@ #include "libavutil/avassert.h" #include "libavutil/file_open.h" #include "libavutil/float_dsp.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/tx.h" @@ -326,7 +327,9 @@ static int rnnoise_model_from_file(FILE *f, RNNModel **rnn) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, @@ -334,15 +337,11 @@ static int query_formats(AVFilterContext *ctx) }; int ret, sample_rates[] = { 48000, -1 }; - ret = ff_set_common_formats_from_list(ctx, sample_fmts); + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_all_channel_counts(ctx); - 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_input(AVFilterLink *inlink) @@ -1607,7 +1606,7 @@ const AVFilter ff_af_arnndn = { .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + 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 bb5c30fab..7765690fd 100644 --- a/libavfilter/af_asdr.c +++ b/libavfilter/af_asdr.c @@ -22,10 +22,10 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" typedef struct ChanStats { double u; diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c index a12e6cadf..3d2d99dae 100644 --- a/libavfilter/af_asetnsamples.c +++ b/libavfilter/af_asetnsamples.c @@ -29,7 +29,6 @@ #include "avfilter.h" #include "audio.h" #include "filters.h" -#include "internal.h" typedef struct ASNSContext { const AVClass *class; diff --git a/libavfilter/af_asetrate.c b/libavfilter/af_asetrate.c index 50ccfc91b..061edebdf 100644 --- a/libavfilter/af_asetrate.c +++ b/libavfilter/af_asetrate.c @@ -20,8 +20,8 @@ #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" typedef struct ASetRateContext { const AVClass *class; @@ -47,23 +47,19 @@ static const AVOption asetrate_options[] = { AVFILTER_DEFINE_CLASS(asetrate); -static av_cold int query_formats(AVFilterContext *ctx) +static av_cold int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - ASetRateContext *sr = ctx->priv; + const ASetRateContext *sr = ctx->priv; int ret, sample_rates[] = { sr->sample_rate, -1 }; - if ((ret = ff_set_common_formats(ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO))) < 0) - return ret; - - if ((ret = ff_set_common_all_channel_counts(ctx)) < 0) - return ret; - if ((ret = ff_formats_ref(ff_all_samplerates(), - &ctx->inputs[0]->outcfg.samplerates)) < 0) + &cfg_in[0]->samplerates)) < 0) return ret; return ff_formats_ref(ff_make_format_list(sample_rates), - &ctx->outputs[0]->incfg.samplerates); + &cfg_out[0]->samplerates); } static av_cold int config_props(AVFilterLink *outlink) @@ -122,7 +118,7 @@ const AVFilter ff_af_asetrate = { .priv_size = sizeof(ASetRateContext), FILTER_INPUTS(asetrate_inputs), FILTER_OUTPUTS(asetrate_outputs), - FILTER_QUERY_FUNC(query_formats), + 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 b1b462d68..b83847b86 100644 --- a/libavfilter/af_ashowinfo.c +++ b/libavfilter/af_ashowinfo.c @@ -24,14 +24,11 @@ */ #include -#include #include "libavutil/adler32.h" #include "libavutil/attributes.h" #include "libavutil/channel_layout.h" -#include "libavutil/common.h" #include "libavutil/downmix_info.h" -#include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/replaygain.h" #include "libavutil/timestamp.h" @@ -41,7 +38,7 @@ #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct AShowInfoContext { /** @@ -176,6 +173,7 @@ static void dump_unknown(AVFilterContext *ctx, AVFrameSideData *sd) static int filter_frame(AVFilterLink *inlink, AVFrame *buf) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AShowInfoContext *s = ctx->priv; char chlayout_str[128]; @@ -206,7 +204,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) "n:%"PRId64" pts:%s pts_time:%s " "fmt:%s channels:%d chlayout:%s rate:%d nb_samples:%d " "checksum:%08"PRIX32" ", - inlink->frame_count_out, + inl->frame_count_out, av_ts2str(buf->pts), av_ts2timestr(buf->pts, &inlink->time_base), av_get_sample_fmt_name(buf->format), buf->ch_layout.nb_channels, chlayout_str, buf->sample_rate, buf->nb_samples, diff --git a/libavfilter/af_asoftclip.c b/libavfilter/af_asoftclip.c index e6483c439..232ed05c0 100644 --- a/libavfilter/af_asoftclip.c +++ b/libavfilter/af_asoftclip.c @@ -23,6 +23,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #define MAX_OVERSAMPLE 64 diff --git a/libavfilter/af_aspectralstats.c b/libavfilter/af_aspectralstats.c index 49c9d97e8..ca7939551 100644 --- a/libavfilter/af_aspectralstats.c +++ b/libavfilter/af_aspectralstats.c @@ -21,12 +21,12 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "window_func.h" #define MEASURE_ALL UINT_MAX diff --git a/libavfilter/af_asr.c b/libavfilter/af_asr.c index 884e17afb..8e8eeb19a 100644 --- a/libavfilter/af_asr.c +++ b/libavfilter/af_asr.c @@ -22,11 +22,12 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" typedef struct ASRContext { const AVClass *class; @@ -121,20 +122,33 @@ static av_cold int asr_init(AVFilterContext *ctx) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - ASRContext *s = ctx->priv; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_NONE, + }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_MONO, + { .nb_channels = 0 }, + }; + + const ASRContext *s = ctx->priv; int sample_rates[] = { s->rate, -1 }; int ret; - AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layout = NULL; + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) + return ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_S16 )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO )) < 0 || - (ret = ff_set_common_channel_layouts (ctx , layout )) < 0 || - (ret = ff_set_common_samplerates_from_list(ctx, sample_rates )) < 0) + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + 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; @@ -169,5 +183,5 @@ const AVFilter ff_af_asr = { .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(asr_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_astats.c b/libavfilter/af_astats.c index 9e8c96358..62ebc3f83 100644 --- a/libavfilter/af_astats.c +++ b/libavfilter/af_astats.c @@ -22,10 +22,11 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #define HISTOGRAM_SIZE 8192 #define HISTOGRAM_MAX (HISTOGRAM_SIZE-1) diff --git a/libavfilter/af_asubboost.c b/libavfilter/af_asubboost.c index 31db4b81a..5698f5028 100644 --- a/libavfilter/af_asubboost.c +++ b/libavfilter/af_asubboost.c @@ -18,9 +18,11 @@ #include "libavutil/channel_layout.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" typedef struct ASubBoostContext { const AVClass *class; diff --git a/libavfilter/af_asupercut.c b/libavfilter/af_asupercut.c index 848388c52..76e9d4b96 100644 --- a/libavfilter/af_asupercut.c +++ b/libavfilter/af_asupercut.c @@ -24,6 +24,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" typedef struct BiquadCoeffs { double a1, a2; diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c index 654b080e8..3b03caa4d 100644 --- a/libavfilter/af_atempo.c +++ b/libavfilter/af_atempo.c @@ -40,15 +40,14 @@ #include #include "libavutil/avassert.h" -#include "libavutil/avstring.h" #include "libavutil/channel_layout.h" -#include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "libavutil/tx.h" #include "avfilter.h" #include "audio.h" -#include "internal.h" +#include "filters.h" /** * A fragment of audio waveform @@ -245,18 +244,6 @@ static void yae_release_buffers(ATempoContext *atempo) av_tx_uninit(&atempo->complex_to_real); } -/* av_realloc is not aligned enough; fortunately, the data does not need to - * be preserved */ -#define RE_MALLOC_OR_FAIL(field, field_size, element_size) \ - do { \ - av_freep(&field); \ - field = av_calloc(field_size, element_size); \ - if (!field) { \ - yae_release_buffers(atempo); \ - return AVERROR(ENOMEM); \ - } \ - } while (0) - /** * Prepare filter for processing audio data of given format, * sample rate and number of channels. @@ -270,6 +257,7 @@ static int yae_reset(ATempoContext *atempo, uint32_t nlevels = 0; float scale = 1.f, iscale = 1.f; uint32_t pot; + int ret; int i; atempo->format = format; @@ -289,38 +277,51 @@ static int yae_reset(ATempoContext *atempo, nlevels++; } + /* av_realloc is not aligned enough, so simply discard all the old buffers + * (fortunately, their data does not need to be preserved) */ + yae_release_buffers(atempo); + // initialize audio fragment buffers: - RE_MALLOC_OR_FAIL(atempo->frag[0].data, atempo->window, atempo->stride); - RE_MALLOC_OR_FAIL(atempo->frag[1].data, atempo->window, atempo->stride); - RE_MALLOC_OR_FAIL(atempo->frag[0].xdat_in, (atempo->window + 1), sizeof(AVComplexFloat)); - RE_MALLOC_OR_FAIL(atempo->frag[1].xdat_in, (atempo->window + 1), sizeof(AVComplexFloat)); - RE_MALLOC_OR_FAIL(atempo->frag[0].xdat, (atempo->window + 1), sizeof(AVComplexFloat)); - RE_MALLOC_OR_FAIL(atempo->frag[1].xdat, (atempo->window + 1), sizeof(AVComplexFloat)); + if (!(atempo->frag[0].data = av_calloc(atempo->window, atempo->stride)) || + !(atempo->frag[1].data = av_calloc(atempo->window, atempo->stride)) || + !(atempo->frag[0].xdat_in = av_calloc(atempo->window + 1, sizeof(AVComplexFloat))) || + !(atempo->frag[1].xdat_in = av_calloc(atempo->window + 1, sizeof(AVComplexFloat))) || + !(atempo->frag[0].xdat = av_calloc(atempo->window + 1, sizeof(AVComplexFloat))) || + !(atempo->frag[1].xdat = av_calloc(atempo->window + 1, sizeof(AVComplexFloat)))) { + ret = AVERROR(ENOMEM); + goto fail; + } // initialize rDFT contexts: - av_tx_uninit(&atempo->real_to_complex); - av_tx_uninit(&atempo->complex_to_real); + ret = av_tx_init(&atempo->real_to_complex, &atempo->r2c_fn, + AV_TX_FLOAT_RDFT, 0, 1 << (nlevels + 1), &scale, 0); + if (ret < 0) + goto fail; - av_tx_init(&atempo->real_to_complex, &atempo->r2c_fn, AV_TX_FLOAT_RDFT, 0, 1 << (nlevels + 1), &scale, 0); - if (!atempo->real_to_complex) { - yae_release_buffers(atempo); - return AVERROR(ENOMEM); + ret = av_tx_init(&atempo->complex_to_real, &atempo->c2r_fn, + AV_TX_FLOAT_RDFT, 1, 1 << (nlevels + 1), &iscale, 0); + if (ret < 0) + goto fail; + + if (!(atempo->correlation_in = av_calloc(atempo->window + 1, sizeof(AVComplexFloat))) || + !(atempo->correlation = av_calloc(atempo->window, sizeof(AVComplexFloat)))) { + ret = AVERROR(ENOMEM); + goto fail; } - av_tx_init(&atempo->complex_to_real, &atempo->c2r_fn, AV_TX_FLOAT_RDFT, 1, 1 << (nlevels + 1), &iscale, 0); - if (!atempo->complex_to_real) { - yae_release_buffers(atempo); - return AVERROR(ENOMEM); - } - - RE_MALLOC_OR_FAIL(atempo->correlation_in, (atempo->window + 1), sizeof(AVComplexFloat)); - RE_MALLOC_OR_FAIL(atempo->correlation, atempo->window, sizeof(AVComplexFloat)); - atempo->ring = atempo->window * 3; - RE_MALLOC_OR_FAIL(atempo->buffer, atempo->ring, atempo->stride); + atempo->buffer = av_calloc(atempo->ring, atempo->stride); + if (!atempo->buffer) { + ret = AVERROR(ENOMEM); + goto fail; + } // initialize the Hann window function: - RE_MALLOC_OR_FAIL(atempo->hann, atempo->window, sizeof(float)); + atempo->hann = av_malloc_array(atempo->window, sizeof(float)); + if (!atempo->hann) { + ret = AVERROR(ENOMEM); + goto fail; + } for (i = 0; i < atempo->window; i++) { double t = (double)i / (double)(atempo->window - 1); @@ -328,8 +329,10 @@ static int yae_reset(ATempoContext *atempo, atempo->hann[i] = (float)h; } - yae_clear(atempo); return 0; +fail: + yae_release_buffers(atempo); + return ret; } static int yae_update(AVFilterContext *ctx) @@ -995,20 +998,20 @@ static av_cold void uninit(AVFilterContext *ctx) yae_release_buffers(atempo); } - // WSOLA necessitates an internal sliding window ring buffer - // for incoming audio stream. - // - // Planar sample formats are too cumbersome to store in a ring buffer, - // therefore planar sample formats are not supported. - // - static const enum AVSampleFormat sample_fmts[] = { - AV_SAMPLE_FMT_U8, - AV_SAMPLE_FMT_S16, - AV_SAMPLE_FMT_S32, - AV_SAMPLE_FMT_FLT, - AV_SAMPLE_FMT_DBL, - AV_SAMPLE_FMT_NONE - }; +// WSOLA necessitates an internal sliding window ring buffer +// for incoming audio stream. +// +// Planar sample formats are too cumbersome to store in a ring buffer, +// therefore planar sample formats are not supported. +// +static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_U8, + AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_S32, + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_DBL, + AV_SAMPLE_FMT_NONE +}; static int config_props(AVFilterLink *inlink) { diff --git a/libavfilter/af_atilt.c b/libavfilter/af_atilt.c index 172e3259d..c8f4ba1e9 100644 --- a/libavfilter/af_atilt.c +++ b/libavfilter/af_atilt.c @@ -21,6 +21,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #define MAX_ORDER 30 diff --git a/libavfilter/af_axcorrelate.c b/libavfilter/af_axcorrelate.c index 82a36f257..b887c07bf 100644 --- a/libavfilter/af_axcorrelate.c +++ b/libavfilter/af_axcorrelate.c @@ -26,7 +26,6 @@ #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" typedef struct AudioXCorrelateContext { const AVClass *class; diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c index ddca9d874..dc7f19d7e 100644 --- a/libavfilter/af_biquads.c +++ b/libavfilter/af_biquads.c @@ -67,12 +67,12 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" enum FilterType { biquad, @@ -154,9 +154,11 @@ typedef struct BiquadsContext { void *cache, int *clip, int disabled); } BiquadsContext; -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - BiquadsContext *s = ctx->priv; + const BiquadsContext *s = ctx->priv; static const enum AVSampleFormat auto_sample_fmts[] = { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, @@ -169,9 +171,7 @@ static int query_formats(AVFilterContext *ctx) AV_SAMPLE_FMT_NONE }; const enum AVSampleFormat *sample_fmts_list = sample_fmts; - int ret = ff_set_common_all_channel_counts(ctx); - if (ret < 0) - return ret; + int ret; switch (s->precision) { case 0: @@ -190,11 +190,11 @@ static int query_formats(AVFilterContext *ctx) sample_fmts_list = auto_sample_fmts; break; } - ret = ff_set_common_formats_from_list(ctx, sample_fmts_list); + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts_list); if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + return 0; } #define BIQUAD_FILTER(name, type, ftype, min, max, need_clipping) \ @@ -1463,7 +1463,7 @@ const AVFilter ff_af_##name_ = { \ .uninit = uninit, \ FILTER_INPUTS(ff_audio_default_filterpad), \ FILTER_OUTPUTS(outputs), \ - FILTER_QUERY_FUNC(query_formats), \ + FILTER_QUERY_FUNC2(query_formats), \ .process_command = process_command, \ .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, \ } diff --git a/libavfilter/af_bs2b.c b/libavfilter/af_bs2b.c index ebd50d4d7..006c8564f 100644 --- a/libavfilter/af_bs2b.c +++ b/libavfilter/af_bs2b.c @@ -29,8 +29,8 @@ #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" typedef void (*filter_func)(t_bs2bdp bs2bdp, uint8_t *sample, int n); @@ -90,9 +90,14 @@ static av_cold void uninit(AVFilterContext *ctx) bs2b_close(bs2b->bs2bp); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AVFilterChannelLayouts *layouts = NULL; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_U8, @@ -104,17 +109,15 @@ static int query_formats(AVFilterContext *ctx) }; int ret; - if (ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO) != 0) - return AVERROR(ENOMEM); - ret = ff_set_common_channel_layouts(ctx, layouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); if (ret < 0) return ret; - ret = ff_set_common_formats_from_list(ctx, sample_fmts); + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + return 0; } static int filter_frame(AVFilterLink *inlink, AVFrame *frame) @@ -211,5 +214,5 @@ const AVFilter ff_af_bs2b = { .uninit = uninit, FILTER_INPUTS(bs2b_inputs), FILTER_OUTPUTS(bs2b_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c index 64efacb57..7a99ac778 100644 --- a/libavfilter/af_channelmap.c +++ b/libavfilter/af_channelmap.c @@ -29,13 +29,14 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" struct ChannelMap { int in_channel; @@ -54,14 +55,15 @@ enum MappingMode { MAP_PAIR_STR_STR }; -#define MAX_CH 64 typedef struct ChannelMapContext { const AVClass *class; char *mapping_str; AVChannelLayout output_layout; - struct ChannelMap map[MAX_CH]; + struct ChannelMap *map; int nch; enum MappingMode mode; + + uint8_t **source_planes; } ChannelMapContext; #define OFFSET(x) offsetof(ChannelMapContext, x) @@ -77,6 +79,13 @@ static const AVOption channelmap_options[] = { AVFILTER_DEFINE_CLASS(channelmap); +static void channelmap_uninit(AVFilterContext *ctx) +{ + ChannelMapContext *s = ctx->priv; + av_freep(&s->map); + av_freep(&s->source_planes); +} + static char* split(char *message, char delim) { char *next = strchr(message, delim); if (next) @@ -84,7 +93,7 @@ static char* split(char *message, char delim) { return next; } -static int get_channel_idx(char **map, int *ch, char delim, int max_nb_channels) +static int get_channel_idx(char **map, int *ch, char delim) { char *next; int len; @@ -98,7 +107,7 @@ static int get_channel_idx(char **map, int *ch, char delim, int max_nb_channels) sscanf(*map, "%d%n", ch, &n); if (n != len) return AVERROR(EINVAL); - if (*ch < 0 || *ch >= max_nb_channels) + if (*ch < 0) return AVERROR(EINVAL); *map = next; return 0; @@ -147,7 +156,8 @@ static av_cold int channelmap_init(AVFilterContext *ctx) int map_entries = 0; enum MappingMode mode; int64_t out_ch_mask = 0; - uint64_t presence_mask; + uint8_t *presence_map = NULL; + int ret = 0; int i; mapping = s->mapping_str; @@ -181,27 +191,25 @@ static av_cold int channelmap_init(AVFilterContext *ctx) if (*++sep) // Allow trailing comma map_entries++; } - } - if (map_entries > MAX_CH) { - av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries); - return AVERROR(EINVAL); - } - - for (i = 0; i < MAX_CH; i++) { - s->map[i].in_channel_idx = -1; - s->map[i].out_channel_idx = -1; - s->map[i].in_channel = -1; - s->map[i].out_channel = -1; + s->map = av_malloc_array(map_entries, sizeof(*s->map)); + if (!s->map) + return AVERROR(ENOMEM); } for (i = 0; i < map_entries; i++) { int in_ch_idx = -1, out_ch_idx = -1; int in_ch = -1, out_ch = -1; static const char err[] = "Failed to parse channel map\n"; + + s->map[i].in_channel_idx = -1; + s->map[i].out_channel_idx = -1; + s->map[i].in_channel = -1; + s->map[i].out_channel = -1; + switch (mode) { case MAP_ONE_INT: - if (get_channel_idx(&mapping, &in_ch_idx, separator, MAX_CH) < 0) { + if (get_channel_idx(&mapping, &in_ch_idx, separator) < 0) { av_log(ctx, AV_LOG_ERROR, err); return AVERROR(EINVAL); } @@ -217,8 +225,8 @@ static av_cold int channelmap_init(AVFilterContext *ctx) s->map[i].out_channel_idx = i; break; case MAP_PAIR_INT_INT: - if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 || - get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) { + if (get_channel_idx(&mapping, &in_ch_idx, '-') < 0 || + get_channel_idx(&mapping, &out_ch_idx, separator) < 0) { av_log(ctx, AV_LOG_ERROR, err); return AVERROR(EINVAL); } @@ -226,7 +234,7 @@ static av_cold int channelmap_init(AVFilterContext *ctx) s->map[i].out_channel_idx = out_ch_idx; break; case MAP_PAIR_INT_STR: - if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 || + if (get_channel_idx(&mapping, &in_ch_idx, '-') < 0 || get_channel(&mapping, &out_ch, separator) < 0) { av_log(ctx, AV_LOG_ERROR, err); return AVERROR(EINVAL); @@ -240,7 +248,7 @@ static av_cold int channelmap_init(AVFilterContext *ctx) break; case MAP_PAIR_STR_INT: if (get_channel(&mapping, &in_ch, '-') < 0 || - get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) { + get_channel_idx(&mapping, &out_ch_idx, separator) < 0) { av_log(ctx, AV_LOG_ERROR, err); return AVERROR(EINVAL); } @@ -274,6 +282,11 @@ static av_cold int channelmap_init(AVFilterContext *ctx) if (mode == MAP_NONE) { int i; s->nch = s->output_layout.nb_channels; + + s->map = av_malloc_array(s->nch, sizeof(*s->map)); + if (!s->map) + return AVERROR(ENOMEM); + for (i = 0; i < s->nch; i++) { s->map[i].in_channel_idx = i; s->map[i].out_channel_idx = i; @@ -300,41 +313,51 @@ static av_cold int channelmap_init(AVFilterContext *ctx) } } - presence_mask = 0; + presence_map = av_calloc(s->nch, sizeof(*presence_map)); for (i = 0; i < s->nch; i++) { - uint64_t idx_mask; - int ret = check_idx_and_id(ctx, s->map[i].out_channel_idx, s->map[i].out_channel, &s->output_layout, "out"); + const int out_idx = s->map[i].out_channel_idx; + ret = check_idx_and_id(ctx, out_idx, s->map[i].out_channel, &s->output_layout, "out"); if (ret < 0) - return ret; - idx_mask = (1ULL << s->map[i].out_channel_idx); - if (presence_mask & idx_mask) { + break; + if (presence_map[out_idx]) { char layout_name[256]; av_channel_layout_describe(&s->output_layout, layout_name, sizeof(layout_name)); av_log(ctx, AV_LOG_ERROR, "Mapping %d assigns channel #%d twice in output layout '%s'.\n", i + 1, s->map[i].out_channel_idx, layout_name); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + break; } - presence_mask |= idx_mask; + presence_map[out_idx] = 1; } + av_freep(&presence_map); + if (ret < 0) + return ret; return 0; } -static int channelmap_query_formats(AVFilterContext *ctx) +static int channelmap_query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - ChannelMapContext *s = ctx->priv; + const ChannelMapContext *s = ctx->priv; AVFilterChannelLayouts *channel_layouts = NULL; + int ret; - if ((ret = ff_set_common_formats (ctx, ff_planar_sample_fmts())) < 0 || - (ret = ff_set_common_all_samplerates(ctx )) < 0 || - (ret = ff_add_channel_layout(&channel_layouts, &s->output_layout)) < 0 || - (ret = ff_channel_layouts_ref(channel_layouts, - &ctx->outputs[0]->incfg.channel_layouts)) < 0) + ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, ff_planar_sample_fmts()); + if (ret < 0) return ret; - return ff_channel_layouts_ref(ff_all_channel_counts(), - &ctx->inputs[0]->outcfg.channel_layouts); + ret = ff_add_channel_layout(&channel_layouts, &s->output_layout); + if (ret < 0) + return ret; + + ret = ff_channel_layouts_ref(channel_layouts, &cfg_out[0]->channel_layouts); + if (ret < 0) + return ret; + + return 0; } static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf) @@ -345,10 +368,9 @@ static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf) const int nch_in = inlink->ch_layout.nb_channels; const int nch_out = s->nch; int ch, ret; - uint8_t *source_planes[MAX_CH]; - memcpy(source_planes, buf->extended_data, - nch_in * sizeof(source_planes[0])); + memcpy(s->source_planes, buf->extended_data, + nch_in * sizeof(s->source_planes[0])); if (nch_out > nch_in) { if (nch_out > FF_ARRAY_ELEMS(buf->data)) { @@ -372,7 +394,7 @@ static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf) for (ch = 0; ch < nch_out; ch++) { buf->extended_data[s->map[ch].out_channel_idx] = - source_planes[s->map[ch].in_channel_idx]; + s->source_planes[s->map[ch].in_channel_idx]; } if (buf->data != buf->extended_data) @@ -403,6 +425,12 @@ static int channelmap_config_input(AVFilterLink *inlink) err = AVERROR(EINVAL); } + av_freep(&s->source_planes); + s->source_planes = av_calloc(inlink->ch_layout.nb_channels, + sizeof(*s->source_planes)); + if (!s->source_planes) + return AVERROR(ENOMEM); + return err; } @@ -420,9 +448,10 @@ const AVFilter ff_af_channelmap = { .name = "channelmap", .description = NULL_IF_CONFIG_SMALL("Remap audio channels."), .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_FUNC(channelmap_query_formats), + FILTER_QUERY_FUNC2(channelmap_query_formats), }; diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c index 92e605e1b..64b6c7a1e 100644 --- a/libavfilter/af_channelsplit.c +++ b/libavfilter/af_channelsplit.c @@ -26,15 +26,13 @@ #include "libavutil/attributes.h" #include "libavutil/channel_layout.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" - -#define MAX_CH 64 typedef struct ChannelSplitContext { const AVClass *class; @@ -42,7 +40,7 @@ typedef struct ChannelSplitContext { AVChannelLayout channel_layout; char *channels_str; - int map[64]; + int *map; } ChannelSplitContext; #define OFFSET(x) offsetof(ChannelSplitContext, x) @@ -71,10 +69,9 @@ static av_cold int init(AVFilterContext *ctx) goto fail; } - if (channel_layout.nb_channels > MAX_CH) { - av_log(ctx, AV_LOG_ERROR, "Too many channels\n"); - goto fail; - } + s->map = av_calloc(channel_layout.nb_channels, sizeof(*s->map)); + if (!s->map) + return AVERROR(ENOMEM); for (i = 0; i < channel_layout.nb_channels; i++) { enum AVChannel channel = av_channel_layout_channel_from_index(&channel_layout, i); @@ -118,20 +115,23 @@ static av_cold void uninit(AVFilterContext *ctx) ChannelSplitContext *s = ctx->priv; av_channel_layout_uninit(&s->channel_layout); + av_freep(&s->map); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { ChannelSplitContext *s = ctx->priv; AVFilterChannelLayouts *in_layouts = NULL; int i, ret; - if ((ret = ff_set_common_formats(ctx, ff_planar_sample_fmts())) < 0 || - (ret = ff_set_common_all_samplerates(ctx)) < 0) + ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, ff_planar_sample_fmts()); + if (ret < 0) return ret; if ((ret = ff_add_channel_layout(&in_layouts, &s->channel_layout)) < 0 || - (ret = ff_channel_layouts_ref(in_layouts, &ctx->inputs[0]->outcfg.channel_layouts)) < 0) + (ret = ff_channel_layouts_ref(in_layouts, &cfg_in[0]->channel_layouts)) < 0) return ret; for (i = 0; i < ctx->nb_outputs; i++) { @@ -139,9 +139,27 @@ static int query_formats(AVFilterContext *ctx) AVFilterChannelLayouts *out_layouts = NULL; enum AVChannel channel = av_channel_layout_channel_from_index(&s->channel_layout, s->map[i]); - if ((ret = av_channel_layout_from_mask(&channel_layout, 1ULL << channel)) < 0 || - (ret = ff_add_channel_layout(&out_layouts, &channel_layout)) < 0 || - (ret = ff_channel_layouts_ref(out_layouts, &ctx->outputs[i]->incfg.channel_layouts)) < 0) + channel_layout.u.map = av_mallocz(sizeof(*channel_layout.u.map)); + if (!channel_layout.u.map) + return AVERROR(ENOMEM); + + channel_layout.u.map[0].id = channel; + channel_layout.nb_channels = 1; + channel_layout.order = AV_CHANNEL_ORDER_CUSTOM; + + ret = av_channel_layout_retype(&channel_layout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL); + if (ret < 0) { + av_channel_layout_uninit(&channel_layout); + return ret; + } + + ret = ff_add_channel_layout(&out_layouts, &channel_layout); + av_channel_layout_uninit(&channel_layout); + if (ret < 0) + return ret; + + ret = ff_channel_layouts_ref(out_layouts, &cfg_out[i]->channel_layouts); + if (ret < 0) return ret; } @@ -150,22 +168,24 @@ static int query_formats(AVFilterContext *ctx) static int filter_frame(AVFilterLink *outlink, AVFrame *buf) { + AVFrame *buf_out; AVFilterContext *ctx = outlink->src; ChannelSplitContext *s = ctx->priv; const int i = FF_OUTLINK_IDX(outlink); - enum AVChannel channel = av_channel_layout_channel_from_index(&buf->ch_layout, s->map[i]); int ret; - av_assert1(channel >= 0); - - AVFrame *buf_out = av_frame_clone(buf); + buf_out = av_frame_clone(buf); if (!buf_out) return AVERROR(ENOMEM); buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[s->map[i]]; - ret = av_channel_layout_from_mask(&buf_out->ch_layout, 1ULL << channel); - if (ret < 0) + + av_channel_layout_uninit(&buf_out->ch_layout); + ret = av_channel_layout_copy(&buf_out->ch_layout, &outlink->ch_layout); + if (ret < 0) { + av_frame_free(&buf_out); return ret; + } return ff_filter_frame(ctx->outputs[i], buf_out); } @@ -231,6 +251,6 @@ const AVFilter ff_af_channelsplit = { .uninit = uninit, FILTER_INPUTS(ff_audio_default_filterpad), .outputs = NULL, - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, }; diff --git a/libavfilter/af_chorus.c b/libavfilter/af_chorus.c index 19826cfb1..7b3f5be9a 100644 --- a/libavfilter/af_chorus.c +++ b/libavfilter/af_chorus.c @@ -30,10 +30,11 @@ */ #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "generate_wave_table.h" typedef struct ChorusContext { diff --git a/libavfilter/af_compand.c b/libavfilter/af_compand.c index 3e799c3b1..1aedc0f6b 100644 --- a/libavfilter/af_compand.c +++ b/libavfilter/af_compand.c @@ -30,11 +30,12 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct ChanParam { double attack; diff --git a/libavfilter/af_compensationdelay.c b/libavfilter/af_compensationdelay.c index 924ccefe9..9d307fd1f 100644 --- a/libavfilter/af_compensationdelay.c +++ b/libavfilter/af_compensationdelay.c @@ -23,7 +23,7 @@ #include "libavutil/samplefmt.h" #include "avfilter.h" #include "audio.h" -#include "internal.h" +#include "filters.h" typedef struct CompensationDelayContext { const AVClass *class; diff --git a/libavfilter/af_crossfeed.c b/libavfilter/af_crossfeed.c index ee6540a9f..1d70e4064 100644 --- a/libavfilter/af_crossfeed.c +++ b/libavfilter/af_crossfeed.c @@ -18,6 +18,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" @@ -47,17 +48,27 @@ typedef struct CrossfeedContext { double *side[3]; } CrossfeedContext; -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; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_DBL, + AV_SAMPLE_FMT_NONE, + }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; + int ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_DBL )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_set_common_channel_layouts (ctx , layout )) < 0 || - (ret = ff_set_common_all_samplerates (ctx )) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) + return ret; + + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) return ret; return 0; @@ -371,7 +382,7 @@ const AVFilter ff_af_crossfeed = { .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + 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 01cdf8bd6..f7f4b063b 100644 --- a/libavfilter/af_crystalizer.c +++ b/libavfilter/af_crystalizer.c @@ -22,6 +22,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" typedef struct CrystalizerContext { const AVClass *class; diff --git a/libavfilter/af_dcshift.c b/libavfilter/af_dcshift.c index 3e9ba7e52..bea15e51d 100644 --- a/libavfilter/af_dcshift.c +++ b/libavfilter/af_dcshift.c @@ -23,7 +23,7 @@ #include "libavutil/samplefmt.h" #include "avfilter.h" #include "audio.h" -#include "internal.h" +#include "filters.h" typedef struct DCShiftContext { const AVClass *class; diff --git a/libavfilter/af_deesser.c b/libavfilter/af_deesser.c index 16c10d21b..b5fad9789 100644 --- a/libavfilter/af_deesser.c +++ b/libavfilter/af_deesser.c @@ -21,9 +21,11 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" typedef struct DeesserChannel { double s1, s2, s3; diff --git a/libavfilter/af_dialoguenhance.c b/libavfilter/af_dialoguenhance.c index 03bfccb07..cae837554 100644 --- a/libavfilter/af_dialoguenhance.c +++ b/libavfilter/af_dialoguenhance.c @@ -19,13 +19,13 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "audio.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include @@ -69,22 +69,30 @@ static const AVOption dialoguenhance_options[] = { AVFILTER_DEFINE_CLASS(dialoguenhance); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AVFilterFormats *formats = NULL; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE, + }; + AVFilterChannelLayouts *in_layout = NULL, *out_layout = NULL; int ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_FLTP )) < 0 || - (ret = ff_add_format (&formats, AV_SAMPLE_FMT_DBLP )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&in_layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_channel_layouts_ref(in_layout, &ctx->inputs[0]->outcfg.channel_layouts)) < 0 || - (ret = ff_add_channel_layout (&out_layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_SURROUND)) < 0 || - (ret = ff_channel_layouts_ref(out_layout, &ctx->outputs[0]->incfg.channel_layouts)) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + if ((ret = ff_add_channel_layout (&in_layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || + (ret = ff_channel_layouts_ref(in_layout, &cfg_in[0]->channel_layouts)) < 0 || + (ret = ff_add_channel_layout (&out_layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_SURROUND)) < 0 || + (ret = ff_channel_layouts_ref(out_layout, &cfg_out[0]->channel_layouts)) < 0) + return ret; + + return 0; } #define DEPTH 32 @@ -217,7 +225,7 @@ const AVFilter ff_af_dialoguenhance = { .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + 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 5eea86557..e5859e9d8 100644 --- a/libavfilter/af_drmeter.c +++ b/libavfilter/af_drmeter.c @@ -21,10 +21,11 @@ #include #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #define BINS 32768 diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c index fb0581b6e..90b3f8bbe 100644 --- a/libavfilter/af_dynaudnorm.c +++ b/libavfilter/af_dynaudnorm.c @@ -29,6 +29,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #define MIN_FILTER_SIZE 3 @@ -40,7 +41,6 @@ #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" static const char * const var_names[] = { "ch", ///< the value of the current channel @@ -724,6 +724,7 @@ static void perform_compression(DynamicAudioNormalizerContext *s, AVFrame *frame static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame **frame) { + FilterLink *outl = ff_filter_link(outlink); DynamicAudioNormalizerContext *s = ctx->priv; AVFrame *analyze_frame; @@ -779,7 +780,7 @@ static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame ** analyze_frame = *frame; } - s->var_values[VAR_SN] = outlink->sample_count_in; + s->var_values[VAR_SN] = outl->sample_count_in; s->var_values[VAR_T] = s->var_values[VAR_SN] * (double)1/outlink->sample_rate; if (s->channels_coupled) { diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c index 38ff9c1f3..a45748174 100644 --- a/libavfilter/af_earwax.c +++ b/libavfilter/af_earwax.c @@ -32,6 +32,7 @@ #include "libavutil/channel_layout.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "formats.h" #define NUMTAPS 32 @@ -78,19 +79,32 @@ typedef struct EarwaxContext { AVFrame *frame[2]; } EarwaxContext; -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_NONE, + }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; static const int sample_rates[] = { 44100, -1 }; + int ret; - AVFilterFormats *formats = NULL; - AVFilterChannelLayouts *layout = NULL; + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) + return ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_S16P )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_set_common_channel_layouts (ctx , layout )) < 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; + + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) return ret; return 0; @@ -229,5 +243,5 @@ const AVFilter ff_af_earwax = { .uninit = uninit, FILTER_INPUTS(earwax_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_extrastereo.c b/libavfilter/af_extrastereo.c index 2b1b09f9c..e511a2b96 100644 --- a/libavfilter/af_extrastereo.c +++ b/libavfilter/af_extrastereo.c @@ -22,6 +22,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "formats.h" typedef struct ExtraStereoContext { @@ -41,19 +42,30 @@ static const AVOption extrastereo_options[] = { AVFILTER_DEFINE_CLASS(extrastereo); -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; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE, + }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; + int ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_FLT )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_set_common_channel_layouts (ctx , layout )) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) + return ret; + + return 0; } static int filter_frame(AVFilterLink *inlink, AVFrame *in) @@ -117,7 +129,7 @@ const AVFilter ff_af_extrastereo = { .priv_class = &extrastereo_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + 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 657dfbc0c..386d8cd24 100644 --- a/libavfilter/af_firequalizer.c +++ b/libavfilter/af_firequalizer.c @@ -20,12 +20,13 @@ #include "libavutil/channel_layout.h" #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/eval.h" #include "libavutil/avassert.h" #include "libavutil/tx.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "audio.h" #define RDFT_BITS_MIN 4 @@ -724,6 +725,7 @@ static int generate_kernel(AVFilterContext *ctx, const char *gain, const char *g static int config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; FIREqualizerContext *s = ctx->priv; float iscale, scale = 1.f; @@ -823,7 +825,7 @@ static int config_input(AVFilterLink *inlink) inlink->sample_rate, inlink->ch_layout.nb_channels, s->analysis_rdft_len, s->rdft_len, s->fir_len, s->nsamples_max); if (s->fixed) - inlink->min_samples = inlink->max_samples = s->nsamples_max; + l->min_samples = l->max_samples = s->nsamples_max; return generate_kernel(ctx, SELECT_GAIN(s), SELECT_GAIN_ENTRY(s)); } diff --git a/libavfilter/af_flanger.c b/libavfilter/af_flanger.c index 453704ea6..092ffcaa2 100644 --- a/libavfilter/af_flanger.c +++ b/libavfilter/af_flanger.c @@ -18,12 +18,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "avfilter.h" #include "audio.h" -#include "internal.h" +#include "filters.h" #include "generate_wave_table.h" #define INTERPOLATION_LINEAR 0 diff --git a/libavfilter/af_haas.c b/libavfilter/af_haas.c index dd2ea26ec..6726c8529 100644 --- a/libavfilter/af_haas.c +++ b/libavfilter/af_haas.c @@ -19,9 +19,11 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "formats.h" #define MAX_HAAS_DELAY 40 @@ -79,19 +81,29 @@ static const AVOption haas_options[] = { AVFILTER_DEFINE_CLASS(haas); -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; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_DBL, + AV_SAMPLE_FMT_NONE, + }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; int ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_DBL )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_set_common_channel_layouts (ctx , layout )) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) + return ret; + + return 0; } static int config_input(AVFilterLink *inlink) @@ -214,5 +226,5 @@ const AVFilter ff_af_haas = { .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index 27f35dd19..c9d992d01 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -47,8 +47,8 @@ #include "libavutil/opt.h" #include "libavutil/avassert.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "audio.h" #define PEAK_EXT_LEVEL 0x5981 /* + sizeof(peaktab)-1 = 0x8000 */ @@ -1601,8 +1601,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ff_filter_frame(outlink, out); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_MONO, + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; static const int sample_rates[] = { 44100, 48000, 88200, 96000, @@ -1611,9 +1618,6 @@ static int query_formats(AVFilterContext *ctx) }; AVFilterFormats *in_formats; AVFilterFormats *out_formats; - AVFilterChannelLayouts *layouts = NULL; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; static const enum AVSampleFormat sample_fmts_in[] = { AV_SAMPLE_FMT_S16, @@ -1628,28 +1632,21 @@ static int query_formats(AVFilterContext *ctx) }; int ret; - ret = ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO); - if (ret < 0) - return ret; - ret = ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); - if (ret < 0) - return ret; - - ret = ff_set_common_channel_layouts(ctx, layouts); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); if (ret < 0) return ret; in_formats = ff_make_format_list(sample_fmts_in); - ret = ff_formats_ref(in_formats, &inlink->outcfg.formats); + ret = ff_formats_ref(in_formats, &cfg_in[0]->formats); if (ret < 0) return ret; out_formats = ff_make_format_list(sample_fmts_out); - ret = ff_formats_ref(out_formats, &outlink->incfg.formats); + ret = ff_formats_ref(out_formats, &cfg_out[0]->formats); 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 void uninit(AVFilterContext *ctx) @@ -1770,5 +1767,5 @@ const AVFilter ff_af_hdcd = { .uninit = uninit, FILTER_INPUTS(avfilter_af_hdcd_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_headphone.c b/libavfilter/af_headphone.c index 9124f945a..fccd8d3f1 100644 --- a/libavfilter/af_headphone.c +++ b/libavfilter/af_headphone.c @@ -24,13 +24,13 @@ #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" #include "libavutil/intmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "audio.h" #define TIME_DOMAIN 0 @@ -594,19 +594,23 @@ static int activate(AVFilterContext *ctx) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - struct HeadphoneContext *s = ctx->priv; - AVFilterFormats *formats = NULL; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE, + }; + + const HeadphoneContext *s = ctx->priv; + AVFilterChannelLayouts *layouts = NULL; AVFilterChannelLayouts *stereo_layout = NULL; AVFilterChannelLayouts *hrir_layouts = NULL; int ret, i; - ret = ff_add_format(&formats, AV_SAMPLE_FMT_FLT); - if (ret) - return ret; - ret = ff_set_common_formats(ctx, formats); + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret) return ret; @@ -614,14 +618,14 @@ static int query_formats(AVFilterContext *ctx) if (!layouts) return AVERROR(ENOMEM); - ret = ff_channel_layouts_ref(layouts, &ctx->inputs[0]->outcfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_in[0]->channel_layouts); if (ret) return ret; ret = ff_add_channel_layout(&stereo_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); if (ret) return ret; - ret = ff_channel_layouts_ref(stereo_layout, &ctx->outputs[0]->incfg.channel_layouts); + ret = ff_channel_layouts_ref(stereo_layout, &cfg_out[0]->channel_layouts); if (ret) return ret; @@ -629,18 +633,18 @@ static int query_formats(AVFilterContext *ctx) hrir_layouts = ff_all_channel_counts(); if (!hrir_layouts) return AVERROR(ENOMEM); - ret = ff_channel_layouts_ref(hrir_layouts, &ctx->inputs[1]->outcfg.channel_layouts); + ret = ff_channel_layouts_ref(hrir_layouts, &cfg_in[1]->channel_layouts); if (ret) return ret; } else { for (i = 1; i <= s->nb_hrir_inputs; i++) { - ret = ff_channel_layouts_ref(stereo_layout, &ctx->inputs[i]->outcfg.channel_layouts); + ret = ff_channel_layouts_ref(stereo_layout, &cfg_in[1]->channel_layouts); if (ret) return ret; } } - return ff_set_common_all_samplerates(ctx); + return 0; } static int config_input(AVFilterLink *inlink) @@ -782,6 +786,6 @@ const AVFilter ff_af_headphone = { .activate = activate, .inputs = NULL, FILTER_OUTPUTS(outputs), - FILTER_QUERY_FUNC(query_formats), + 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 8dab3f093..0ea53248b 100644 --- a/libavfilter/af_join.c +++ b/libavfilter/af_join.c @@ -28,13 +28,13 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "formats.h" #include "filters.h" -#include "internal.h" typedef struct ChannelMap { int input; ///< input stream index @@ -201,24 +201,25 @@ static av_cold void join_uninit(AVFilterContext *ctx) av_freep(&s->input_frames); } -static int join_query_formats(AVFilterContext *ctx) +static int join_query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - JoinContext *s = ctx->priv; + const JoinContext *s = ctx->priv; AVFilterChannelLayouts *layouts = NULL; int i, ret; if ((ret = ff_add_channel_layout(&layouts, &s->ch_layout)) < 0 || - (ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts)) < 0) + (ret = ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts)) < 0) return ret; for (i = 0; i < ctx->nb_inputs; i++) { layouts = ff_all_channel_layouts(); - if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->outcfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &cfg_in[i]->channel_layouts)) < 0) return ret; } - if ((ret = ff_set_common_formats(ctx, ff_planar_sample_fmts())) < 0 || - (ret = ff_set_common_all_samplerates(ctx)) < 0) + if ((ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, ff_planar_sample_fmts())) < 0) return ret; return 0; @@ -605,6 +606,6 @@ const AVFilter ff_af_join = { .activate = activate, .inputs = NULL, FILTER_OUTPUTS(avfilter_af_join_outputs), - FILTER_QUERY_FUNC(join_query_formats), + FILTER_QUERY_FUNC2(join_query_formats), .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_ladspa.c b/libavfilter/af_ladspa.c index 7567c0577..35ff90b1a 100644 --- a/libavfilter/af_ladspa.c +++ b/libavfilter/af_ladspa.c @@ -30,11 +30,12 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/fifo.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" typedef struct MetaItem { int64_t pts; @@ -693,31 +694,29 @@ 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) { - LADSPAContext *s = ctx->priv; + const LADSPAContext *s = ctx->priv; AVFilterChannelLayouts *layouts; 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_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - if (s->nb_inputs) { - ret = ff_set_common_all_samplerates(ctx); - if (ret < 0) - return ret; - } else { + if (!s->nb_inputs) { int sample_rates[] = { s->sample_rate, -1 }; - ret = ff_set_common_samplerates_from_list(ctx, sample_rates); + ret = ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); if (ret < 0) return ret; } if (s->nb_inputs == 1 && s->nb_outputs == 1) { // We will instantiate multiple LADSPA_Handle, one over each channel - ret = ff_set_common_all_channel_counts(ctx); + ret = ff_set_common_all_channel_counts2(ctx, cfg_in, cfg_out); if (ret < 0) return ret; } else if (s->nb_inputs == 2 && s->nb_outputs == 2) { @@ -725,26 +724,23 @@ static int query_formats(AVFilterContext *ctx) ret = ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts(ctx, layouts); + ret = ff_set_common_channel_layouts2(ctx, cfg_in, cfg_out, layouts); if (ret < 0) return ret; } else { - AVFilterLink *outlink = ctx->outputs[0]; - if (s->nb_inputs >= 1) { - AVFilterLink *inlink = ctx->inputs[0]; AVChannelLayout inlayout = FF_COUNT2LAYOUT(s->nb_inputs); layouts = NULL; ret = ff_add_channel_layout(&layouts, &inlayout); if (ret < 0) return ret; - ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_in[0]->channel_layouts); if (ret < 0) return ret; if (!s->nb_outputs) { - ret = ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts); if (ret < 0) return ret; } @@ -757,7 +753,7 @@ static int query_formats(AVFilterContext *ctx) ret = ff_add_channel_layout(&layouts, &outlayout); if (ret < 0) return ret; - ret = ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts); if (ret < 0) return ret; } @@ -824,6 +820,6 @@ const AVFilter ff_af_ladspa = { .process_command = process_command, .inputs = 0, FILTER_OUTPUTS(ladspa_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_loudnorm.c b/libavfilter/af_loudnorm.c index 6cb9c0606..d63a71381 100644 --- a/libavfilter/af_loudnorm.c +++ b/libavfilter/af_loudnorm.c @@ -20,11 +20,11 @@ /* http://k.ylo.ph/2016/04/04/loudnorm.html */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "audio.h" #include "ebur128.h" @@ -728,7 +728,9 @@ static int activate(AVFilterContext *ctx) return FFERROR_NOT_READY; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { LoudNormContext *s = ctx->priv; static const int input_srate[] = {192000, -1}; @@ -736,19 +738,16 @@ static int query_formats(AVFilterContext *ctx) AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE }; - int ret = ff_set_common_all_channel_counts(ctx); + int ret; + + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - ret = ff_set_common_formats_from_list(ctx, sample_fmts); - if (ret < 0) - return ret; - - if (s->frame_type == LINEAR_MODE) { - return ff_set_common_all_samplerates(ctx); - } else { - return ff_set_common_samplerates_from_list(ctx, input_srate); + if (s->frame_type != LINEAR_MODE) { + return ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, input_srate); } + return 0; } static int config_input(AVFilterLink *inlink) @@ -937,5 +936,5 @@ const AVFilter ff_af_loudnorm = { .uninit = uninit, FILTER_INPUTS(avfilter_af_loudnorm_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_lv2.c b/libavfilter/af_lv2.c index 7b3ddf944..db9b1e363 100644 --- a/libavfilter/af_lv2.c +++ b/libavfilter/af_lv2.c @@ -30,11 +30,12 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" typedef struct URITable { char **uris; @@ -380,7 +381,7 @@ static int config_output(AVFilterLink *outlink) (lilv_plugin_has_feature(s->plugin, s->powerOf2BlockLength) || lilv_plugin_has_feature(s->plugin, s->fixedBlockLength) || lilv_plugin_has_feature(s->plugin, s->boundedBlockLength))) { - AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inlink = ff_filter_link(ctx->inputs[0]); inlink->min_samples = inlink->max_samples = 4096; } @@ -473,25 +474,22 @@ 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) { - LV2Context *s = ctx->priv; + const LV2Context *s = ctx->priv; AVFilterChannelLayouts *layouts; - AVFilterLink *outlink = ctx->outputs[0]; 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_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret < 0) return ret; - if (s->nb_inputs) { - ret = ff_set_common_all_samplerates(ctx); - if (ret < 0) - return ret; - } else { + if (!s->nb_inputs) { int sample_rates[] = { s->sample_rate, -1 }; - ret = ff_set_common_samplerates_from_list(ctx, sample_rates); + ret = ff_set_common_samplerates_from_list2(ctx, cfg_in, cfg_out, sample_rates); if (ret < 0) return ret; } @@ -501,24 +499,23 @@ static int query_formats(AVFilterContext *ctx) ret = ff_add_channel_layout(&layouts, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO); if (ret < 0) return ret; - ret = ff_set_common_channel_layouts(ctx, layouts); + ret = ff_set_common_channel_layouts2(ctx, cfg_in, cfg_out, layouts); if (ret < 0) return ret; } else { if (s->nb_inputs >= 1) { - AVFilterLink *inlink = ctx->inputs[0]; AVChannelLayout inlayout = FF_COUNT2LAYOUT(s->nb_inputs); layouts = NULL; ret = ff_add_channel_layout(&layouts, &inlayout); if (ret < 0) return ret; - ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_in[0]->channel_layouts); if (ret < 0) return ret; if (!s->nb_outputs) { - ret = ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts); if (ret < 0) return ret; } @@ -531,7 +528,7 @@ static int query_formats(AVFilterContext *ctx) ret = ff_add_channel_layout(&layouts, &outlayout); if (ret < 0) return ret; - ret = ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts); if (ret < 0) return ret; } @@ -603,6 +600,6 @@ const AVFilter ff_af_lv2 = { .process_command = process_command, .inputs = 0, FILTER_OUTPUTS(lv2_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, }; diff --git a/libavfilter/af_mcompand.c b/libavfilter/af_mcompand.c index 9347f06d8..b2f61fc5f 100644 --- a/libavfilter/af_mcompand.c +++ b/libavfilter/af_mcompand.c @@ -30,11 +30,12 @@ #include "libavutil/avstring.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct CompandSegment { double x, y; diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index 04bf7d3fe..5feb2439c 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -30,12 +30,13 @@ #include #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libswresample/swresample.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #define MAX_CHANNELS 64 @@ -90,6 +91,28 @@ static int parse_channel_name(char **arg, int *rchannel, int *rnamed) return AVERROR(EINVAL); } +static int are_gains_pure(const PanContext *pan) +{ + int i, j; + + for (i = 0; i < MAX_CHANNELS; i++) { + int nb_gain = 0; + + for (j = 0; j < MAX_CHANNELS; j++) { + double gain = pan->gain[i][j]; + + /* channel mapping is effective only if 0% or 100% of a channel is + * selected... */ + if (gain != 0. && gain != 1.) + return 0; + /* ...and if the output channel is only composed of one input */ + if (gain && nb_gain++) + return 0; + } + } + return 1; +} + static av_cold int init(AVFilterContext *ctx) { PanContext *const pan = ctx->priv; @@ -173,7 +196,7 @@ static av_cold int init(AVFilterContext *ctx) sign = 1; while (1) { gain = 1; - if (sscanf(arg, "%lf%n *%n", &gain, &len, &len)) + if (sscanf(arg, "%lf%n *%n", &gain, &len, &len) >= 1) arg += len; if (parse_channel_name(&arg, &in_ch_id, &named)){ av_log(ctx, AV_LOG_ERROR, @@ -212,6 +235,7 @@ static av_cold int init(AVFilterContext *ctx) } } pan->need_renumber = !!nb_in_channels[1]; + pan->pure_gains = are_gains_pure(pan); ret = 0; fail: @@ -219,54 +243,24 @@ fail: return ret; } -static int are_gains_pure(const PanContext *pan) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - int i, j; - - for (i = 0; i < MAX_CHANNELS; i++) { - int nb_gain = 0; - - for (j = 0; j < MAX_CHANNELS; j++) { - double gain = pan->gain[i][j]; - - /* channel mapping is effective only if 0% or 100% of a channel is - * selected... */ - if (gain != 0. && gain != 1.) - return 0; - /* ...and if the output channel is only composed of one input */ - if (gain && nb_gain++) - return 0; - } - } - return 1; -} - -static int query_formats(AVFilterContext *ctx) -{ - PanContext *pan = ctx->priv; - AVFilterLink *inlink = ctx->inputs[0]; - AVFilterLink *outlink = ctx->outputs[0]; + const PanContext *pan = ctx->priv; AVFilterChannelLayouts *layouts; int ret; - pan->pure_gains = are_gains_pure(pan); - /* libswr supports any sample and packing formats */ - if ((ret = ff_set_common_formats(ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO))) < 0) - return ret; - - if ((ret = ff_set_common_all_samplerates(ctx)) < 0) - return ret; - // inlink supports any channel layout layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &cfg_in[0]->channel_layouts)) < 0) return ret; // outlink supports only requested output channel layout layouts = NULL; if ((ret = ff_add_channel_layout(&layouts, &pan->out_channel_layout)) < 0) return ret; - return ff_channel_layouts_ref(layouts, &outlink->incfg.channel_layouts); + return ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts); } static int config_props(AVFilterLink *link) @@ -431,5 +425,5 @@ const AVFilter ff_af_pan = { .uninit = uninit, FILTER_INPUTS(pan_inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_replaygain.c b/libavfilter/af_replaygain.c index 266121e2c..e3e2e921c 100644 --- a/libavfilter/af_replaygain.c +++ b/libavfilter/af_replaygain.c @@ -30,8 +30,8 @@ #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #define HISTOGRAM_SLOTS 12000 #define BUTTER_ORDER 2 @@ -326,29 +326,43 @@ typedef struct ReplayGainContext { float butter_hist_b[256]; } ReplayGainContext; -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; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE, + }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; + + AVFilterFormats *rates; + int i, ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_FLT )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_set_common_channel_layouts (ctx , layout )) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) return ret; - formats = NULL; + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) + return ret; + + rates = NULL; for (i = 0; i < FF_ARRAY_ELEMS(freqinfos); i++) { - if ((ret = ff_add_format(&formats, freqinfos[i].sample_rate)) < 0) + if ((ret = ff_add_format(&rates, freqinfos[i].sample_rate)) < 0) return ret; } - return ff_set_common_samplerates(ctx, formats); + return ff_set_common_samplerates2(ctx, cfg_in, cfg_out, rates); } static int config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; ReplayGainContext *s = ctx->priv; int i; @@ -366,8 +380,8 @@ static int config_input(AVFilterLink *inlink) s->yule_hist_i = 20; s->butter_hist_i = 4; - inlink->min_samples = - inlink->max_samples = inlink->sample_rate / 20; + l->min_samples = + l->max_samples = inlink->sample_rate / 20; return 0; } @@ -637,5 +651,5 @@ const AVFilter ff_af_replaygain = { .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(replaygain_inputs), FILTER_OUTPUTS(replaygain_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), }; diff --git a/libavfilter/af_rubberband.c b/libavfilter/af_rubberband.c index a820ba753..cf055f77d 100644 --- a/libavfilter/af_rubberband.c +++ b/libavfilter/af_rubberband.c @@ -25,7 +25,6 @@ #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" typedef struct RubberBandContext { const AVClass *class; diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c index d152a8295..d2bc63f5d 100644 --- a/libavfilter/af_sidechaincompress.c +++ b/libavfilter/af_sidechaincompress.c @@ -36,7 +36,6 @@ #include "filters.h" #include "formats.h" #include "hermite.h" -#include "internal.h" typedef struct SidechainCompressContext { const AVClass *class; @@ -298,26 +297,27 @@ static int activate(AVFilterContext *ctx) return 0; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE }; - int ret = ff_channel_layouts_ref(ff_all_channel_counts(), - &ctx->inputs[1]->outcfg.channel_layouts); + int ret; + + /* Generic code will link the channel properties of the main input and the output; + * it won't touch the second input as its channel_layouts is already set. */ + ret = ff_channel_layouts_ref(ff_all_channel_counts(), + &cfg_in[1]->channel_layouts); if (ret < 0) return ret; - /* This will link the channel properties of the main input and the output; - * it won't touch the second input as its channel_layouts is already set. */ - if ((ret = ff_set_common_all_channel_counts(ctx)) < 0) + if ((ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts)) < 0) return ret; - if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts)) < 0) - return ret; - - return ff_set_common_all_samplerates(ctx); + return 0; } static int config_output(AVFilterLink *outlink) @@ -372,7 +372,7 @@ const AVFilter ff_af_sidechaincompress = { .uninit = uninit, FILTER_INPUTS(sidechaincompress_inputs), FILTER_OUTPUTS(sidechaincompress_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .process_command = process_command, }; #endif /* CONFIG_SIDECHAINCOMPRESS_FILTER */ diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c index 845c65bfe..9bb17400e 100644 --- a/libavfilter/af_silencedetect.c +++ b/libavfilter/af_silencedetect.c @@ -25,11 +25,12 @@ #include /* DBL_MAX */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/timestamp.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct SilenceDetectContext { const AVClass *class; diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c index d60c86ad9..3cc518a7e 100644 --- a/libavfilter/af_silenceremove.c +++ b/libavfilter/af_silenceremove.c @@ -24,11 +24,11 @@ #include /* DBL_MAX */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "filters.h" #include "avfilter.h" -#include "internal.h" enum SilenceDetect { D_AVG, diff --git a/libavfilter/af_sofalizer.c b/libavfilter/af_sofalizer.c index 7349fa06f..178b9c0b5 100644 --- a/libavfilter/af_sofalizer.c +++ b/libavfilter/af_sofalizer.c @@ -28,6 +28,7 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" @@ -37,7 +38,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "audio.h" #define TIME_DOMAIN 0 @@ -634,9 +634,11 @@ static int activate(AVFilterContext *ctx) return FFERROR_NOT_READY; } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - struct SOFAlizerContext *s = ctx->priv; + const SOFAlizerContext *s = ctx->priv; AVFilterChannelLayouts *layouts = NULL; int ret, sample_rates[] = { 48000, -1 }; static const enum AVSampleFormat sample_fmts[] = { @@ -644,7 +646,7 @@ static int query_formats(AVFilterContext *ctx) AV_SAMPLE_FMT_NONE }; - ret = ff_set_common_formats_from_list(ctx, sample_fmts); + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts); if (ret) return ret; @@ -652,7 +654,7 @@ static int query_formats(AVFilterContext *ctx) if (!layouts) return AVERROR(ENOMEM); - ret = ff_channel_layouts_ref(layouts, &ctx->inputs[0]->outcfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_in[0]->channel_layouts); if (ret) return ret; @@ -661,12 +663,12 @@ static int query_formats(AVFilterContext *ctx) if (ret) return ret; - ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts); if (ret) return ret; sample_rates[0] = s->sample_rate; - 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 getfilter_float(AVFilterContext *ctx, float x, float y, float z, @@ -1096,6 +1098,6 @@ const AVFilter ff_af_sofalizer = { .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_speechnorm.c b/libavfilter/af_speechnorm.c index a8bed2cb8..840c432c1 100644 --- a/libavfilter/af_speechnorm.c +++ b/libavfilter/af_speechnorm.c @@ -29,6 +29,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #define FF_BUFQUEUE_SIZE (1024) @@ -37,7 +38,6 @@ #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #define MAX_ITEMS 882000 #define MIN_PEAK (1. / 32768.) diff --git a/libavfilter/af_stereotools.c b/libavfilter/af_stereotools.c index 330d91cd2..bbbc88cd4 100644 --- a/libavfilter/af_stereotools.c +++ b/libavfilter/af_stereotools.c @@ -19,9 +19,11 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "formats.h" typedef struct StereoToolsContext { @@ -99,19 +101,31 @@ static const AVOption stereotools_options[] = { AVFILTER_DEFINE_CLASS(stereotools); -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; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_DBL, + AV_SAMPLE_FMT_NONE, + }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; + int ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_DBL )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_set_common_channel_layouts (ctx , layout )) < 0) + + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) + return ret; + + return 0; } static int config_input(AVFilterLink *inlink) @@ -373,7 +387,7 @@ const AVFilter ff_af_stereotools = { .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + 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 1273c7711..66aa24a03 100644 --- a/libavfilter/af_stereowiden.c +++ b/libavfilter/af_stereowiden.c @@ -20,9 +20,11 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "formats.h" typedef struct StereoWidenContext { @@ -52,19 +54,30 @@ static const AVOption stereowiden_options[] = { AVFILTER_DEFINE_CLASS(stereowiden); -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; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE, + }; + static const AVChannelLayout layouts[] = { + AV_CHANNEL_LAYOUT_STEREO, + { .nb_channels = 0 }, + }; + int ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_FLT )) < 0 || - (ret = ff_set_common_formats (ctx , formats )) < 0 || - (ret = ff_add_channel_layout (&layout , &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_set_common_channel_layouts (ctx , layout )) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + ret = ff_set_common_channel_layouts_from_list2(ctx, cfg_in, cfg_out, layouts); + if (ret < 0) + return ret; + + return 0; } static int config_input(AVFilterLink *inlink) @@ -156,7 +169,7 @@ const AVFilter ff_af_stereowiden = { .uninit = uninit, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + 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 fbe707cb2..bdf6e12af 100644 --- a/libavfilter/af_superequalizer.c +++ b/libavfilter/af_superequalizer.c @@ -19,13 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #define NBANDS 17 #define M 15 diff --git a/libavfilter/af_surround.c b/libavfilter/af_surround.c index 595786028..95efe4685 100644 --- a/libavfilter/af_surround.c +++ b/libavfilter/af_surround.c @@ -20,12 +20,12 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "avfilter.h" #include "audio.h" #include "filters.h" -#include "internal.h" #include "formats.h" #include "window_func.h" @@ -146,17 +146,20 @@ typedef struct AudioSurroundContext { int n); } AudioSurroundContext; -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - AudioSurroundContext *s = ctx->priv; - AVFilterFormats *formats = NULL; + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE, + }; + + const AudioSurroundContext *s = ctx->priv; AVFilterChannelLayouts *layouts = NULL; int ret; - ret = ff_add_format(&formats, AV_SAMPLE_FMT_FLTP); - if (ret) - return ret; - ret = ff_set_common_formats(ctx, formats); + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); if (ret) return ret; @@ -165,7 +168,7 @@ static int query_formats(AVFilterContext *ctx) if (ret) return ret; - ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts); if (ret) return ret; @@ -174,11 +177,11 @@ static int query_formats(AVFilterContext *ctx) if (ret) return ret; - ret = ff_channel_layouts_ref(layouts, &ctx->inputs[0]->outcfg.channel_layouts); + ret = ff_channel_layouts_ref(layouts, &cfg_in[0]->channel_layouts); if (ret) return ret; - return ff_set_common_all_samplerates(ctx); + return 0; } static void set_input_levels(AVFilterContext *ctx) @@ -1122,6 +1125,31 @@ static av_cold int init(AVFilterContext *ctx) s->create_lfe = av_channel_layout_index_from_channel(&s->out_ch_layout, AV_CHAN_LOW_FREQUENCY) >= 0; + switch (out_channel_layout) { + case AV_CH_LAYOUT_MONO: + case AV_CH_LAYOUT_STEREO: + case AV_CH_LAYOUT_2POINT1: + case AV_CH_LAYOUT_2_1: + case AV_CH_LAYOUT_2_2: + case AV_CH_LAYOUT_SURROUND: + case AV_CH_LAYOUT_3POINT1: + case AV_CH_LAYOUT_QUAD: + case AV_CH_LAYOUT_4POINT0: + case AV_CH_LAYOUT_4POINT1: + case AV_CH_LAYOUT_5POINT0: + case AV_CH_LAYOUT_5POINT1: + case AV_CH_LAYOUT_5POINT0_BACK: + case AV_CH_LAYOUT_5POINT1_BACK: + case AV_CH_LAYOUT_6POINT0: + case AV_CH_LAYOUT_6POINT1: + case AV_CH_LAYOUT_7POINT0: + case AV_CH_LAYOUT_7POINT1: + case AV_CH_LAYOUT_OCTAGONAL: + break; + default: + goto fail; + } + switch (in_channel_layout) { case AV_CH_LAYOUT_STEREO: s->filter = filter_stereo; @@ -1492,7 +1520,7 @@ const AVFilter ff_af_surround = { .activate = activate, FILTER_INPUTS(inputs), FILTER_OUTPUTS(outputs), - FILTER_QUERY_FUNC(query_formats), + 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 024c402b7..0c781a2de 100644 --- a/libavfilter/af_tremolo.c +++ b/libavfilter/af_tremolo.c @@ -18,9 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "audio.h" typedef struct TremoloContext { diff --git a/libavfilter/af_vibrato.c b/libavfilter/af_vibrato.c index e54ae2ad4..a3bf90ae8 100644 --- a/libavfilter/af_vibrato.c +++ b/libavfilter/af_vibrato.c @@ -18,9 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "audio.h" #include "generate_wave_table.h" diff --git a/libavfilter/af_virtualbass.c b/libavfilter/af_virtualbass.c index 9b9967c41..d2f28ab1a 100644 --- a/libavfilter/af_virtualbass.c +++ b/libavfilter/af_virtualbass.c @@ -24,7 +24,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include @@ -49,21 +48,29 @@ static const AVOption virtualbass_options[] = { AVFILTER_DEFINE_CLASS(virtualbass); -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { + static const enum AVSampleFormat formats[] = { + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE, + }; + AVFilterChannelLayouts *in_layout = NULL, *out_layout = NULL; - AVFilterFormats *formats = NULL; int ret; - if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_DBLP )) < 0 || - (ret = ff_set_common_formats (ctx, formats )) < 0 || - (ret = ff_add_channel_layout (&in_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || - (ret = ff_channel_layouts_ref(in_layout, &ctx->inputs[0]->outcfg.channel_layouts)) < 0 || - (ret = ff_add_channel_layout (&out_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_2POINT1)) < 0 || - (ret = ff_channel_layouts_ref(out_layout, &ctx->outputs[0]->incfg.channel_layouts)) < 0) + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, formats); + if (ret < 0) return ret; - return ff_set_common_all_samplerates(ctx); + if ((ret = ff_add_channel_layout (&in_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO)) < 0 || + (ret = ff_channel_layouts_ref(in_layout, &cfg_in[0]->channel_layouts)) < 0 || + (ret = ff_add_channel_layout (&out_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_2POINT1)) < 0 || + (ret = ff_channel_layouts_ref(out_layout, &cfg_out[0]->channel_layouts)) < 0) + return ret; + + return 0; } static int config_input(AVFilterLink *inlink) @@ -171,7 +178,7 @@ const AVFilter ff_af_virtualbass = { .priv_class = &virtualbass_class, FILTER_INPUTS(inputs), FILTER_OUTPUTS(ff_audio_default_filterpad), - FILTER_QUERY_FUNC(query_formats), + 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 686e8c651..ed924cf45 100644 --- a/libavfilter/af_volume.c +++ b/libavfilter/af_volume.c @@ -29,14 +29,14 @@ #include "libavutil/eval.h" #include "libavutil/ffmath.h" #include "libavutil/float_dsp.h" -#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/replaygain.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "af_volume.h" static const char * const precision_str[] = { @@ -127,13 +127,14 @@ static av_cold void uninit(AVFilterContext *ctx) { VolumeContext *vol = ctx->priv; av_expr_free(vol->volume_pexpr); - av_opt_free(vol); av_freep(&vol->fdsp); } -static int query_formats(AVFilterContext *ctx) +static int query_formats(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) { - VolumeContext *vol = ctx->priv; + const VolumeContext *vol = ctx->priv; static const enum AVSampleFormat sample_fmts[][7] = { [PRECISION_FIXED] = { AV_SAMPLE_FMT_U8, @@ -155,15 +156,13 @@ static int query_formats(AVFilterContext *ctx) AV_SAMPLE_FMT_NONE } }; - int ret = ff_set_common_all_channel_counts(ctx); + int ret; + + ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts[vol->precision]); if (ret < 0) return ret; - ret = ff_set_common_formats_from_list(ctx, sample_fmts[vol->precision]); - if (ret < 0) - return ret; - - return ff_set_common_all_samplerates(ctx); + return 0; } static inline void scale_samples_u8(uint8_t *dst, const uint8_t *src, @@ -329,6 +328,7 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar static int filter_frame(AVFilterLink *inlink, AVFrame *buf) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; VolumeContext *vol = inlink->dst->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; @@ -381,7 +381,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) } vol->var_values[VAR_PTS] = TS2D(buf->pts); vol->var_values[VAR_T ] = TS2T(buf->pts, inlink->time_base); - vol->var_values[VAR_N ] = inlink->frame_count_out; + vol->var_values[VAR_N ] = inl->frame_count_out; #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS @@ -480,7 +480,7 @@ const AVFilter ff_af_volume = { .uninit = uninit, FILTER_INPUTS(avfilter_af_volume_inputs), FILTER_OUTPUTS(avfilter_af_volume_outputs), - FILTER_QUERY_FUNC(query_formats), + FILTER_QUERY_FUNC2(query_formats), .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, .process_command = process_command, }; diff --git a/libavfilter/af_volumedetect.c b/libavfilter/af_volumedetect.c index 8b001d1cf..25f7bf569 100644 --- a/libavfilter/af_volumedetect.c +++ b/libavfilter/af_volumedetect.c @@ -22,7 +22,7 @@ #include "libavutil/avassert.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct VolDetectContext { /** diff --git a/libavfilter/afir_template.c b/libavfilter/afir_template.c index 08e1ca469..c45b29902 100644 --- a/libavfilter/afir_template.c +++ b/libavfilter/afir_template.c @@ -20,7 +20,6 @@ #include "libavutil/tx.h" #include "avfilter.h" -#include "internal.h" #include "audio.h" #undef ctype diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 149bf5099..9819f0f95 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -337,6 +337,7 @@ 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; @@ -532,6 +533,7 @@ 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; @@ -546,6 +548,8 @@ 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 AVFilter ff_vsrc_allrgb; extern const AVFilter ff_vsrc_allyuv; @@ -567,6 +571,7 @@ 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; diff --git a/libavfilter/anlms_template.c b/libavfilter/anlms_template.c index b25df4fa1..a8d1dbfe0 100644 --- a/libavfilter/anlms_template.c +++ b/libavfilter/anlms_template.c @@ -33,18 +33,6 @@ #define fn2(a,b) fn3(a,b) #define fn(a) fn2(a, SAMPLE_FORMAT) -#if DEPTH == 64 -static double scalarproduct_double(const double *v1, const double *v2, int len) -{ - double p = 0.0; - - for (int i = 0; i < len; i++) - p += v1[i] * v2[i]; - - return p; -} -#endif - static ftype fn(fir_sample)(AudioNLMSContext *s, ftype sample, ftype *delay, ftype *coeffs, ftype *tmp, int *offset) { @@ -58,7 +46,7 @@ static ftype fn(fir_sample)(AudioNLMSContext *s, ftype sample, ftype *delay, #if DEPTH == 32 output = s->fdsp->scalarproduct_float(delay, tmp, s->kernel_size); #else - output = scalarproduct_double(delay, tmp, s->kernel_size); + output = s->fdsp->scalarproduct_double(delay, tmp, s->kernel_size); #endif if (--(*offset) < 0) @@ -85,7 +73,7 @@ static ftype fn(process_sample)(AudioNLMSContext *s, ftype input, ftype desired, #if DEPTH == 32 sum = s->fdsp->scalarproduct_float(delay, delay, s->kernel_size); #else - sum = scalarproduct_double(delay, delay, s->kernel_size); + sum = s->fdsp->scalarproduct_double(delay, delay, s->kernel_size); #endif norm = s->eps + sum; b = mu * e / norm; diff --git a/libavfilter/arls_template.c b/libavfilter/arls_template.c index d8b19d89a..c67b48cf6 100644 --- a/libavfilter/arls_template.c +++ b/libavfilter/arls_template.c @@ -39,18 +39,6 @@ #define fn2(a,b) fn3(a,b) #define fn(a) fn2(a, SAMPLE_FORMAT) -#if DEPTH == 64 -static double scalarproduct_double(const double *v1, const double *v2, int len) -{ - double p = 0.0; - - for (int i = 0; i < len; i++) - p += v1[i] * v2[i]; - - return p; -} -#endif - static ftype fn(fir_sample)(AudioRLSContext *s, ftype sample, ftype *delay, ftype *coeffs, ftype *tmp, int *offset) { @@ -64,7 +52,7 @@ static ftype fn(fir_sample)(AudioRLSContext *s, ftype sample, ftype *delay, #if DEPTH == 32 output = s->fdsp->scalarproduct_float(delay, tmp, s->kernel_size); #else - output = scalarproduct_double(delay, tmp, s->kernel_size); + output = s->fdsp->scalarproduct_double(delay, tmp, s->kernel_size); #endif if (--(*offset) < 0) diff --git a/libavfilter/asink_anullsink.c b/libavfilter/asink_anullsink.c index 64a733e16..5ba1c7288 100644 --- a/libavfilter/asink_anullsink.c +++ b/libavfilter/asink_anullsink.c @@ -20,7 +20,7 @@ #include "libavutil/internal.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" static int null_filter_frame(AVFilterLink *link, AVFrame *frame) { diff --git a/libavfilter/asrc_afdelaysrc.c b/libavfilter/asrc_afdelaysrc.c index f3f0b080a..c235f0c27 100644 --- a/libavfilter/asrc_afdelaysrc.c +++ b/libavfilter/asrc_afdelaysrc.c @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/opt.h" @@ -26,7 +25,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" typedef struct AFDelaySrcContext { const AVClass *class; diff --git a/libavfilter/asrc_afirsrc.c b/libavfilter/asrc_afirsrc.c index 20cb84bc0..bc450ec82 100644 --- a/libavfilter/asrc_afirsrc.c +++ b/libavfilter/asrc_afirsrc.c @@ -22,13 +22,13 @@ #include "libavutil/channel_layout.h" #include "libavutil/ffmath.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" #include "audio.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "window_func.h" typedef struct AudioFIRSourceContext { diff --git a/libavfilter/asrc_anoisesrc.c b/libavfilter/asrc_anoisesrc.c index d98bc4fc8..a67b2abe9 100644 --- a/libavfilter/asrc_anoisesrc.c +++ b/libavfilter/asrc_anoisesrc.c @@ -24,7 +24,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "libavutil/lfg.h" #include "libavutil/random_seed.h" diff --git a/libavfilter/asrc_anullsrc.c b/libavfilter/asrc_anullsrc.c index a48728eaf..3249cc33a 100644 --- a/libavfilter/asrc_anullsrc.c +++ b/libavfilter/asrc_anullsrc.c @@ -34,7 +34,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" typedef struct ANullContext { const AVClass *class; diff --git a/libavfilter/asrc_flite.c b/libavfilter/asrc_flite.c index 6055db52b..5962bf55b 100644 --- a/libavfilter/asrc_flite.c +++ b/libavfilter/asrc_flite.c @@ -28,13 +28,13 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/file.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/thread.h" #include "avfilter.h" #include "filters.h" #include "audio.h" #include "formats.h" -#include "internal.h" typedef struct FliteContext { const AVClass *class; diff --git a/libavfilter/asrc_hilbert.c b/libavfilter/asrc_hilbert.c index 98248e7e4..e38af7123 100644 --- a/libavfilter/asrc_hilbert.c +++ b/libavfilter/asrc_hilbert.c @@ -19,11 +19,11 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "formats.h" -#include "internal.h" #include "filters.h" #include "window_func.h" diff --git a/libavfilter/asrc_sinc.c b/libavfilter/asrc_sinc.c index 6366fb802..94046f76b 100644 --- a/libavfilter/asrc_sinc.c +++ b/libavfilter/asrc_sinc.c @@ -21,6 +21,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tx.h" @@ -28,7 +29,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" typedef struct SincContext { const AVClass *class; diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c index c576b57fe..2e444ba19 100644 --- a/libavfilter/asrc_sine.c +++ b/libavfilter/asrc_sine.c @@ -23,12 +23,12 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" typedef struct SineContext { const AVClass *class; @@ -206,10 +206,11 @@ static av_cold int config_props(AVFilterLink *outlink) static int activate(AVFilterContext *ctx) { AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); SineContext *sine = ctx->priv; AVFrame *frame; double values[VAR_VARS_NB] = { - [VAR_N] = outlink->frame_count_in, + [VAR_N] = outl->frame_count_in, [VAR_PTS] = sine->pts, [VAR_T] = sine->pts * av_q2d(outlink->time_base), [VAR_TB] = av_q2d(outlink->time_base), diff --git a/libavfilter/audio.c b/libavfilter/audio.c index 22f64d173..7d87e9e9a 100644 --- a/libavfilter/audio.c +++ b/libavfilter/audio.c @@ -23,12 +23,13 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/cpu.h" +#include "libavutil/eval.h" #include "audio.h" #include "avfilter.h" #include "avfilter_internal.h" +#include "filters.h" #include "framepool.h" -#include "internal.h" const AVFilterPad ff_audio_default_filterpad[1] = { { @@ -106,3 +107,38 @@ AVFrame *ff_get_audio_buffer(AVFilterLink *link, int nb_samples) return ret; } + +int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx) +{ + char *tail; + double srate = av_strtod(arg, &tail); + if (*tail || srate < 1 || (int)srate != srate || srate > INT_MAX) { + av_log(log_ctx, AV_LOG_ERROR, "Invalid sample rate '%s'\n", arg); + return AVERROR(EINVAL); + } + *ret = srate; + return 0; +} + +int ff_parse_channel_layout(AVChannelLayout *ret, int *nret, const char *arg, + void *log_ctx) +{ + AVChannelLayout chlayout = { 0 }; + int res; + + res = av_channel_layout_from_string(&chlayout, arg); + if (res < 0) { + av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg); + return AVERROR(EINVAL); + } + + if (chlayout.order == AV_CHANNEL_ORDER_UNSPEC && !nret) { + av_log(log_ctx, AV_LOG_ERROR, "Unknown channel layout '%s' is not supported.\n", arg); + return AVERROR(EINVAL); + } + *ret = chlayout; + if (nret) + *nret = chlayout.nb_channels; + + return 0; +} diff --git a/libavfilter/audio.h b/libavfilter/audio.h index be90fa347..881df0cf8 100644 --- a/libavfilter/audio.h +++ b/libavfilter/audio.h @@ -23,7 +23,7 @@ #define AVFILTER_AUDIO_H #include "avfilter.h" -#include "internal.h" +#include "filters.h" /** * An AVFilterPad array whose only entry has name "default" @@ -47,4 +47,29 @@ AVFrame *ff_null_get_audio_buffer(AVFilterLink *link, int nb_samples); */ AVFrame *ff_get_audio_buffer(AVFilterLink *link, int nb_samples); +/** + * Parse a sample rate. + * + * @param ret unsigned integer pointer to where the value should be written + * @param arg string to parse + * @param log_ctx log context + * @return >= 0 in case of success, a negative AVERROR code on error + */ +av_warn_unused_result +int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx); + +/** + * Parse a channel layout or a corresponding integer representation. + * + * @param ret 64bit integer pointer to where the value should be written. + * @param nret integer pointer to the number of channels; + * if not NULL, then unknown channel layouts are accepted + * @param arg string to parse + * @param log_ctx log context + * @return >= 0 in case of success, a negative AVERROR code on error + */ +av_warn_unused_result +int ff_parse_channel_layout(AVChannelLayout *ret, int *nret, const char *arg, + void *log_ctx); + #endif /* AVFILTER_AUDIO_H */ diff --git a/libavfilter/avf_a3dscope.c b/libavfilter/avf_a3dscope.c index d7fe2dcb7..dd0899051 100644 --- a/libavfilter/avf_a3dscope.c +++ b/libavfilter/avf_a3dscope.c @@ -27,7 +27,6 @@ #include "formats.h" #include "audio.h" #include "video.h" -#include "internal.h" typedef struct Audio3dScopeContext { const AVClass *class; @@ -115,13 +114,14 @@ static int config_input(AVFilterLink *inlink) static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); Audio3dScopeContext *s = outlink->src->priv; outlink->w = s->w; outlink->h = s->h; outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); return 0; } diff --git a/libavfilter/avf_abitscope.c b/libavfilter/avf_abitscope.c index 60dba21be..30ed7d95e 100644 --- a/libavfilter/avf_abitscope.c +++ b/libavfilter/avf_abitscope.c @@ -20,6 +20,7 @@ #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" @@ -27,7 +28,6 @@ #include "formats.h" #include "audio.h" #include "video.h" -#include "internal.h" typedef struct AudioBitScopeContext { const AVClass *class; @@ -138,12 +138,13 @@ static int config_input(AVFilterLink *inlink) static int config_output(AVFilterLink *outlink) { AudioBitScopeContext *s = outlink->src->priv; + FilterLink *l = ff_filter_link(outlink); outlink->w = s->w; outlink->h = s->h; outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); return 0; } diff --git a/libavfilter/avf_ahistogram.c b/libavfilter/avf_ahistogram.c index f80f341e3..b77307f13 100644 --- a/libavfilter/avf_ahistogram.c +++ b/libavfilter/avf_ahistogram.c @@ -19,14 +19,12 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "audio.h" #include "video.h" -#include "internal.h" enum DisplayScale { LINEAR, SQRT, CBRT, LOG, RLOG, NB_SCALES }; enum AmplitudeScale { ALINEAR, ALOG, NB_ASCALES }; @@ -162,12 +160,13 @@ static int get_log_bin_sign(float in, int w) static int config_output(AVFilterLink *outlink) { AudioHistogramContext *s = outlink->src->priv; + FilterLink *l = ff_filter_link(outlink); outlink->w = s->w; outlink->h = s->h; outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); s->histogram_h = s->h * s->phisto; s->ypos = s->h * s->phisto; diff --git a/libavfilter/avf_aphasemeter.c b/libavfilter/avf_aphasemeter.c index fac8d7c04..fe0968c97 100644 --- a/libavfilter/avf_aphasemeter.c +++ b/libavfilter/avf_aphasemeter.c @@ -23,6 +23,8 @@ * audio to video multimedia aphasemeter filter */ +#include + #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" @@ -33,8 +35,6 @@ #include "formats.h" #include "audio.h" #include "video.h" -#include "internal.h" -#include "float.h" typedef struct AudioPhaseMeterContext { const AVClass *class; @@ -141,14 +141,15 @@ static int config_video_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AudioPhaseMeterContext *s = ctx->priv; + FilterLink *l = ff_filter_link(outlink); s->last_pts = AV_NOPTS_VALUE; outlink->w = s->w; outlink->h = s->h; outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); if (!strcmp(s->mpc_str, "none")) s->draw_median_phase = 0; diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c index 1b3461d91..96bef32e2 100644 --- a/libavfilter/avf_avectorscope.c +++ b/libavfilter/avf_avectorscope.c @@ -32,7 +32,6 @@ #include "formats.h" #include "audio.h" #include "video.h" -#include "internal.h" enum VectorScopeMode { LISSAJOUS, @@ -271,12 +270,13 @@ static int config_input(AVFilterLink *inlink) static int config_output(AVFilterLink *outlink) { AudioVectorScopeContext *s = outlink->src->priv; + FilterLink *l = ff_filter_link(outlink); outlink->w = s->w; outlink->h = s->h; outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); s->prev_x = s->hw = s->w / 2; s->prev_y = s->hh = s->mode == POLAR ? s->h - 1 : s->h / 2; diff --git a/libavfilter/avf_concat.c b/libavfilter/avf_concat.c index 33edd7a39..2a3d4c8b5 100644 --- a/libavfilter/avf_concat.c +++ b/libavfilter/avf_concat.c @@ -25,11 +25,11 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "audio.h" @@ -119,11 +119,13 @@ static int query_formats(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; ConcatContext *cat = ctx->priv; unsigned out_no = FF_OUTLINK_IDX(outlink); unsigned in_no = out_no, seg; AVFilterLink *inlink = ctx->inputs[in_no]; + FilterLink *inl = ff_filter_link(inlink); /* enhancement: find a common one */ outlink->time_base = AV_TIME_BASE_Q; @@ -131,15 +133,16 @@ static int config_output(AVFilterLink *outlink) outlink->h = inlink->h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->format = inlink->format; - outlink->frame_rate = inlink->frame_rate; + outl->frame_rate = inl->frame_rate; for (seg = 1; seg < cat->nb_segments; seg++) { inlink = ctx->inputs[in_no + seg * ctx->nb_outputs]; - if (outlink->frame_rate.num != inlink->frame_rate.num || - outlink->frame_rate.den != inlink->frame_rate.den) { + inl = ff_filter_link(inlink); + if (outl->frame_rate.num != inl->frame_rate.num || + outl->frame_rate.den != inl->frame_rate.den) { av_log(ctx, AV_LOG_VERBOSE, "Video inputs have different frame rates, output will be VFR\n"); - outlink->frame_rate = av_make_q(1, 0); + outl->frame_rate = av_make_q(1, 0); break; } } diff --git a/libavfilter/avf_showcqt.c b/libavfilter/avf_showcqt.c index 676f77ecb..00f679bc9 100644 --- a/libavfilter/avf_showcqt.c +++ b/libavfilter/avf_showcqt.c @@ -19,6 +19,7 @@ */ #include "config.h" +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "libavutil/channel_layout.h" #include "libavutil/opt.h" @@ -30,7 +31,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "lavfutils.h" #include "lswsutils.h" #include "video.h" @@ -1352,6 +1352,7 @@ static int query_formats(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; ShowCQTContext *s = ctx->priv; @@ -1364,7 +1365,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = s->height; s->format = outlink->format; outlink->sample_aspect_ratio = av_make_q(1, 1); - outlink->frame_rate = s->rate; + l->frame_rate = s->rate; outlink->time_base = av_inv_q(s->rate); av_log(ctx, AV_LOG_VERBOSE, "video: %dx%d %s %d/%d fps, bar_h = %d, axis_h = %d, sono_h = %d.\n", s->width, s->height, av_get_pix_fmt_name(s->format), s->rate.num, s->rate.den, diff --git a/libavfilter/avf_showcqt.h b/libavfilter/avf_showcqt.h index b6c1e0e10..186215c1e 100644 --- a/libavfilter/avf_showcqt.h +++ b/libavfilter/avf_showcqt.h @@ -23,7 +23,6 @@ #include "libavutil/tx.h" #include "avfilter.h" -#include "internal.h" typedef struct Coeffs { float *val; diff --git a/libavfilter/avf_showcwt.c b/libavfilter/avf_showcwt.c index c498f0a7b..760a07f2f 100644 --- a/libavfilter/avf_showcwt.c +++ b/libavfilter/avf_showcwt.c @@ -21,9 +21,8 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/tx.h" -#include "libavutil/avassert.h" -#include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" #include "libavutil/cpu.h" @@ -34,7 +33,6 @@ #include "video.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" enum FrequencyScale { FSCALE_LINEAR, @@ -811,6 +809,7 @@ static int compute_kernel(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; ShowCWTContext *s = ctx->priv; @@ -1034,8 +1033,8 @@ static int config_output(AVFilterLink *outlink) } else { s->frame_rate = s->auto_frame_rate; } - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); ret = compute_kernel(ctx); if (ret < 0) diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c index e3c7ce96f..da31b3215 100644 --- a/libavfilter/avf_showfreqs.c +++ b/libavfilter/avf_showfreqs.c @@ -21,6 +21,7 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -33,7 +34,6 @@ #include "formats.h" #include "video.h" #include "avfilter.h" -#include "internal.h" #include "window_func.h" enum DataMode { MAGNITUDE, PHASE, DELAY, NB_DATA }; @@ -149,6 +149,7 @@ static int query_formats(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; ShowFreqsContext *s = ctx->priv; @@ -222,8 +223,8 @@ static int config_output(AVFilterLink *outlink) if (!s->window) return AVERROR(ENOMEM); - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); outlink->sample_aspect_ratio = (AVRational){1,1}; outlink->w = s->w; outlink->h = s->h; @@ -296,6 +297,7 @@ static inline void plot_freq(ShowFreqsContext *s, int ch, double a, int f, uint8_t fg[4], int *prev_y, AVFrame *out, AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); const int w = s->w; const float min = s->minamp; const float avg = s->avg_data[ch][f]; @@ -335,12 +337,12 @@ static inline void plot_freq(ShowFreqsContext *s, int ch, switch (s->avg) { case 0: - y = s->avg_data[ch][f] = !outlink->frame_count_in ? y : FFMIN(0, y); + y = s->avg_data[ch][f] = !outl->frame_count_in ? y : FFMIN(0, y); break; case 1: break; default: - s->avg_data[ch][f] = avg + y * (y - avg) / (FFMIN(outlink->frame_count_in + 1, s->avg) * (float)y); + s->avg_data[ch][f] = avg + y * (y - avg) / (FFMIN(outl->frame_count_in + 1, s->avg) * (float)y); y = av_clip(s->avg_data[ch][f], 0, outlink->h - 1); break; } diff --git a/libavfilter/avf_showspatial.c b/libavfilter/avf_showspatial.c index 29b41bee8..f7380f885 100644 --- a/libavfilter/avf_showspatial.c +++ b/libavfilter/avf_showspatial.c @@ -18,21 +18,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "libavutil/audio_fifo.h" #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "audio.h" #include "formats.h" #include "video.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "window_func.h" typedef struct ShowSpatialContext { @@ -129,6 +127,7 @@ static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; ShowSpatialContext *s = ctx->priv; @@ -139,8 +138,8 @@ static int config_output(AVFilterLink *outlink) outlink->h = s->h; outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); /* (re-)configuration if the video output changed (or first init) */ if (s->win_size != s->buf_size) { diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 5d76da3bf..565f23c28 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -31,6 +31,7 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -44,7 +45,6 @@ #include "video.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "window_func.h" enum DisplayMode { COMBINED, SEPARATE, NB_MODES }; @@ -1060,6 +1060,7 @@ static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_j static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; ShowSpectrumContext *s = ctx->priv; @@ -1282,8 +1283,8 @@ static int config_output(AVFilterLink *outlink) } else { s->frame_rate = s->auto_frame_rate; } - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); if (s->orientation == VERTICAL) { s->combine_buffer = diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c index f359e4d97..d26fc8841 100644 --- a/libavfilter/avf_showvolume.c +++ b/libavfilter/avf_showvolume.c @@ -18,19 +18,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/eval.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "libavutil/xga_font_data.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "audio.h" #include "video.h" -#include "internal.h" static const char *const var_names[] = { "VOLUME", "CHANNEL", "PEAK", NULL }; enum { VAR_VOLUME, VAR_CHANNEL, VAR_PEAK, VAR_VARS_NB }; @@ -198,6 +195,7 @@ static int config_input(AVFilterLink *inlink) static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); ShowVolumeContext *s = outlink->src->priv; AVFilterLink *inlink = outlink->src->inputs[0]; int ch; @@ -211,8 +209,8 @@ static int config_output(AVFilterLink *outlink) } outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); for (ch = 0; ch < inlink->ch_layout.nb_channels; ch++) { int i; diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c index f090d9371..868e6a22d 100644 --- a/libavfilter/avf_showwaves.c +++ b/libavfilter/avf_showwaves.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" @@ -36,7 +37,6 @@ #include "formats.h" #include "audio.h" #include "video.h" -#include "internal.h" enum ShowWavesMode { MODE_POINT, @@ -408,6 +408,7 @@ static void draw_sample_cline_gray(uint8_t *buf, int height, int linesize, static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; ShowWavesContext *showwaves = ctx->priv; @@ -421,14 +422,14 @@ static int config_output(AVFilterLink *outlink) if (showwaves->single_pic) { showwaves->n = av_make_q(1, 1); - outlink->frame_rate = av_make_q(1, 1); + l->frame_rate = av_make_q(1, 1); } else { if (!showwaves->n.num || !showwaves->n.den) { showwaves->n = av_mul_q(av_make_q(inlink->sample_rate, showwaves->w), av_inv_q(showwaves->rate)); - outlink->frame_rate = showwaves->rate; + l->frame_rate = showwaves->rate; } else { - outlink->frame_rate = av_div_q(av_make_q(inlink->sample_rate, showwaves->w), showwaves->n); + l->frame_rate = av_div_q(av_make_q(inlink->sample_rate, showwaves->w), showwaves->n); } } @@ -447,13 +448,13 @@ static int config_output(AVFilterLink *outlink) if (!showwaves->history) return AVERROR(ENOMEM); - outlink->time_base = av_inv_q(outlink->frame_rate); + outlink->time_base = av_inv_q(l->frame_rate); outlink->w = showwaves->w; outlink->h = showwaves->h; outlink->sample_aspect_ratio = (AVRational){1,1}; av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d r:%f n:%f\n", - showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), av_q2d(showwaves->n)); + showwaves->w, showwaves->h, av_q2d(l->frame_rate), av_q2d(showwaves->n)); switch (outlink->format) { case AV_PIX_FMT_GRAY8: diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 831871de9..8a2a9e059 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -29,6 +29,7 @@ #include "libavutil/frame.h" #include "libavutil/hwcontext.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/rational.h" @@ -41,7 +42,6 @@ #include "formats.h" #include "framequeue.h" #include "framepool.h" -#include "internal.h" #include "video.h" static void tlog_ref(void *ctx, AVFrame *ref, int end) @@ -175,7 +175,7 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, li = av_mallocz(sizeof(*li)); if (!li) return AVERROR(ENOMEM); - link = &li->l; + link = &li->l.pub; src->outputs[srcpad] = dst->inputs[dstpad] = link; @@ -184,6 +184,7 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, link->srcpad = &src->output_pads[srcpad]; link->dstpad = &dst->input_pads[dstpad]; link->type = src->output_pads[srcpad].type; + li->l.graph = src->graph; av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1); link->format = -1; link->colorspace = AVCOL_SPC_UNSPECIFIED; @@ -204,6 +205,8 @@ static void link_free(AVFilterLink **link) ff_frame_pool_uninit(&li->frame_pool); av_channel_layout_uninit(&(*link)->ch_layout); + av_buffer_unref(&li->l.hw_frames_ctx); + av_freep(link); } @@ -220,15 +223,15 @@ int avfilter_config_links(AVFilterContext *filter) static void update_link_current_pts(FilterLinkInternal *li, int64_t pts) { - AVFilterLink *const link = &li->l; + AVFilterLink *const link = &li->l.pub; if (pts == AV_NOPTS_VALUE) return; - link->current_pts = pts; - link->current_pts_us = av_rescale_q(pts, link->time_base, AV_TIME_BASE_Q); + li->l.current_pts = pts; + li->l.current_pts_us = av_rescale_q(pts, link->time_base, AV_TIME_BASE_Q); /* TODO use duration */ - if (link->graph && li->age_index >= 0) - ff_avfilter_graph_update_heap(link->graph, li); + if (li->l.graph && li->age_index >= 0) + ff_avfilter_graph_update_heap(li->l.graph, li); } void ff_filter_set_ready(AVFilterContext *filter, unsigned priority) @@ -260,7 +263,7 @@ void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts) av_assert0(!li->status_in); li->status_in = status; li->status_in_pts = pts; - link->frame_wanted_out = 0; + li->frame_wanted_out = 0; li->frame_blocked_in = 0; filter_unblock(link->dst); ff_filter_set_ready(link->dst, 200); @@ -274,7 +277,7 @@ static void link_set_out_status(AVFilterLink *link, int status, int64_t pts) { FilterLinkInternal * const li = ff_link_internal(link); - av_assert0(!link->frame_wanted_out); + av_assert0(!li->frame_wanted_out); av_assert0(!li->status_out); li->status_out = status; if (pts != AV_NOPTS_VALUE) @@ -336,6 +339,7 @@ int ff_filter_config_links(AVFilterContext *filter) AVFilterLink *link = filter->inputs[i]; AVFilterLink *inlink; FilterLinkInternal *li = ff_link_internal(link); + FilterLinkInternal *li_in; if (!link) continue; if (!link->src || !link->dst) { @@ -345,8 +349,9 @@ int ff_filter_config_links(AVFilterContext *filter) } inlink = link->src->nb_inputs ? link->src->inputs[0] : NULL; - link->current_pts = - link->current_pts_us = AV_NOPTS_VALUE; + li_in = inlink ? ff_link_internal(inlink) : NULL; + li->l.current_pts = + li->l.current_pts_us = AV_NOPTS_VALUE; switch (li->init_state) { case AVLINK_INIT: @@ -385,8 +390,8 @@ int ff_filter_config_links(AVFilterContext *filter) inlink->sample_aspect_ratio : (AVRational){1,1}; if (inlink) { - if (!link->frame_rate.num && !link->frame_rate.den) - link->frame_rate = inlink->frame_rate; + if (!li->l.frame_rate.num && !li->l.frame_rate.den) + li->l.frame_rate = li_in->l.frame_rate; if (!link->w) link->w = inlink->w; if (!link->h) @@ -409,13 +414,18 @@ int ff_filter_config_links(AVFilterContext *filter) link->time_base = (AVRational) {1, link->sample_rate}; } - if (link->src->nb_inputs && link->src->inputs[0]->hw_frames_ctx && + if (link->src->nb_inputs && !(link->src->filter->flags_internal & FF_FILTER_FLAG_HWFRAME_AWARE)) { - av_assert0(!link->hw_frames_ctx && + FilterLink *l0 = ff_filter_link(link->src->inputs[0]); + + av_assert0(!li->l.hw_frames_ctx && "should not be set by non-hwframe-aware filter"); - link->hw_frames_ctx = av_buffer_ref(link->src->inputs[0]->hw_frames_ctx); - if (!link->hw_frames_ctx) - return AVERROR(ENOMEM); + + if (l0->hw_frames_ctx) { + li->l.hw_frames_ctx = av_buffer_ref(l0->hw_frames_ctx); + if (!li->l.hw_frames_ctx) + return AVERROR(ENOMEM); + } } if ((config_link = link->dstpad->config_props)) @@ -470,7 +480,7 @@ int ff_request_frame(AVFilterLink *link) return li->status_out; if (li->status_in) { if (ff_framequeue_queued_frames(&li->fifo)) { - av_assert1(!link->frame_wanted_out); + av_assert1(!li->frame_wanted_out); av_assert1(link->dst->ready >= 300); return 0; } else { @@ -481,7 +491,7 @@ int ff_request_frame(AVFilterLink *link) return li->status_out; } } - link->frame_wanted_out = 1; + li->frame_wanted_out = 1; ff_filter_set_ready(link->src, 100); return 0; } @@ -494,7 +504,7 @@ static int64_t guess_status_pts(AVFilterContext *ctx, int status, AVRational lin for (i = 0; i < ctx->nb_inputs; i++) { FilterLinkInternal * const li = ff_link_internal(ctx->inputs[i]); if (li->status_out == status) - r = FFMIN(r, av_rescale_q(ctx->inputs[i]->current_pts, ctx->inputs[i]->time_base, link_time_base)); + r = FFMIN(r, av_rescale_q(li->l.current_pts, ctx->inputs[i]->time_base, link_time_base)); } if (r < INT64_MAX) return r; @@ -651,7 +661,8 @@ static const AVOption avfilter_options[] = { { "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .flags = FLAGS, .unit = "thread_type" }, { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = TFLAGS }, { "threads", "Allowed number of threads", OFFSET(nb_threads), AV_OPT_TYPE_INT, - { .i64 = 0 }, 0, INT_MAX, FLAGS }, + { .i64 = 0 }, 0, INT_MAX, FLAGS, .unit = "threads" }, + {"auto", "autodetect a suitable number of threads to use", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, .flags = FLAGS, .unit = "threads"}, { "extra_hw_frames", "Number of extra hardware frames to allocate for the user", OFFSET(extra_hw_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS }, { NULL }, @@ -762,8 +773,6 @@ static void free_link(AVFilterLink *link) if (link->dst) link->dst->inputs[link->dstpad - link->dst->input_pads] = NULL; - av_buffer_unref(&link->hw_frames_ctx); - ff_formats_unref(&link->incfg.formats); ff_formats_unref(&link->outcfg.formats); ff_formats_unref(&link->incfg.color_spaces); @@ -834,19 +843,18 @@ int ff_filter_opt_parse(void *logctx, const AVClass *priv_class, { const AVOption *o = NULL; int ret; - char *av_uninit(parsed_key), *av_uninit(value); - const char *key; int offset= -1; if (!args) return 0; while (*args) { + char *parsed_key, *value; + const char *key; const char *shorthand = NULL; + int additional_flags = 0; - if (priv_class) - o = av_opt_next(&priv_class, o); - if (o) { + if (priv_class && (o = av_opt_next(&priv_class, o))) { if (o->type == AV_OPT_TYPE_CONST || o->offset == offset) continue; offset = o->offset; @@ -868,20 +876,16 @@ int ff_filter_opt_parse(void *logctx, const AVClass *priv_class, args++; if (parsed_key) { key = parsed_key; - - /* discard all remaining shorthand */ - if (priv_class) - while ((o = av_opt_next(&priv_class, o))); + additional_flags = AV_DICT_DONT_STRDUP_KEY; + priv_class = NULL; /* reject all remaining shorthand */ } else { key = shorthand; } av_log(logctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); - av_dict_set(options, key, value, AV_DICT_MULTIKEY); - - av_free(value); - av_free(parsed_key); + av_dict_set(options, key, value, + additional_flags | AV_DICT_DONT_STRDUP_VAL | AV_DICT_MULTIKEY); } return 0; @@ -944,7 +948,7 @@ int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options) int avfilter_init_str(AVFilterContext *filter, const char *args) { AVDictionary *options = NULL; - AVDictionaryEntry *e; + const AVDictionaryEntry *e; int ret = 0; if (args && *args) { @@ -957,7 +961,7 @@ int avfilter_init_str(AVFilterContext *filter, const char *args) if (ret < 0) goto fail; - if ((e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX))) { + if ((e = av_dict_iterate(options, NULL))) { av_log(filter, AV_LOG_ERROR, "No such option: %s.\n", e->key); ret = AVERROR_OPTION_NOT_FOUND; goto fail; @@ -986,6 +990,7 @@ static int default_filter_frame(AVFilterLink *link, AVFrame *frame) static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) { + FilterLink *l = ff_filter_link(link); int (*filter_frame)(AVFilterLink *, AVFrame *); AVFilterContext *dstctx = link->dst; AVFilterPad *dst = link->dstpad; @@ -1007,7 +1012,7 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) (dstctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC)) filter_frame = default_filter_frame; ret = filter_frame(link, frame); - link->frame_count_out++; + l->frame_count_out++; return ret; fail: @@ -1052,9 +1057,9 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame) link->time_base); } - li->frame_blocked_in = link->frame_wanted_out = 0; - link->frame_count_in++; - link->sample_count_in += frame->nb_samples; + li->frame_blocked_in = li->frame_wanted_out = 0; + li->l.frame_count_in++; + li->l.sample_count_in += frame->nb_samples; filter_unblock(link->dst); ret = ff_framequeue_add(&li->fifo, frame); if (ret < 0) { @@ -1079,14 +1084,15 @@ static int samples_ready(FilterLinkInternal *link, unsigned min) static int take_samples(FilterLinkInternal *li, unsigned min, unsigned max, AVFrame **rframe) { - AVFilterLink *link = &li->l; + FilterLink *l = &li->l; + AVFilterLink *link = &l->pub; AVFrame *frame0, *frame, *buf; unsigned nb_samples, nb_frames, i, p; int ret; /* Note: this function relies on no format changes and must only be called with enough samples. */ - av_assert1(samples_ready(li, link->min_samples)); + av_assert1(samples_ready(li, l->min_samples)); frame0 = frame = ff_framequeue_peek(&li->fifo, 0); if (!li->fifo.samples_skipped && frame->nb_samples >= min && frame->nb_samples <= max) { *rframe = ff_framequeue_take(&li->fifo); @@ -1144,8 +1150,8 @@ static int ff_filter_frame_to_filter(AVFilterLink *link) int ret; av_assert1(ff_framequeue_queued_frames(&li->fifo)); - ret = link->min_samples ? - ff_inlink_consume_samples(link, link->min_samples, link->max_samples, &frame) : + ret = li->l.min_samples ? + ff_inlink_consume_samples(link, li->l.min_samples, li->l.max_samples, &frame) : ff_inlink_consume_frame(link, &frame); av_assert1(ret); if (ret < 0) { @@ -1157,7 +1163,7 @@ static int ff_filter_frame_to_filter(AVFilterLink *link) 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. */ - link->frame_count_out--; + li->l.frame_count_out--; ret = ff_filter_frame_framed(link, frame); if (ret < 0 && ret != li->status_out) { link_set_out_status(link, ret, AV_NOPTS_VALUE); @@ -1171,7 +1177,7 @@ static int ff_filter_frame_to_filter(AVFilterLink *link) static int forward_status_change(AVFilterContext *filter, FilterLinkInternal *li_in) { - AVFilterLink *in = &li_in->l; + AVFilterLink *in = &li_in->l.pub; unsigned out = 0, progress = 0; int ret; @@ -1220,8 +1226,8 @@ static int ff_filter_activate_default(AVFilterContext *filter) } for (i = 0; i < filter->nb_inputs; i++) { - if (samples_ready(ff_link_internal(filter->inputs[i]), - filter->inputs[i]->min_samples)) { + 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]); } } @@ -1234,7 +1240,7 @@ static int ff_filter_activate_default(AVFilterContext *filter) } for (i = 0; i < filter->nb_outputs; i++) { FilterLinkInternal * const li = ff_link_internal(filter->outputs[i]); - if (filter->outputs[i]->frame_wanted_out && + if (li->frame_wanted_out && !li->frame_blocked_in) { return ff_request_frame_to_filter(filter->outputs[i]); } @@ -1392,7 +1398,7 @@ int ff_filter_activate(AVFilterContext *filter) int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts) { FilterLinkInternal * const li = ff_link_internal(link); - *rpts = link->current_pts; + *rpts = li->l.current_pts; if (ff_framequeue_queued_frames(&li->fifo)) return *rstatus = 0; if (li->status_out) @@ -1401,7 +1407,7 @@ int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts return *rstatus = 0; *rstatus = li->status_out = li->status_in; update_link_current_pts(li, li->status_in_pts); - *rpts = link->current_pts; + *rpts = li->l.current_pts; return 1; } @@ -1433,13 +1439,13 @@ int ff_inlink_check_available_samples(AVFilterLink *link, unsigned min) static void consume_update(FilterLinkInternal *li, const AVFrame *frame) { - AVFilterLink *const link = &li->l; + AVFilterLink *const link = &li->l.pub; 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->frame_count_out++; - link->sample_count_out += frame->nb_samples; + li->l.frame_count_out++; + li->l.sample_count_out += frame->nb_samples; } int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe) @@ -1546,6 +1552,7 @@ int ff_inlink_process_commands(AVFilterLink *link, const AVFrame *frame) 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 @@ -1557,7 +1564,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (!dstctx->enable_str) return 1; - dstctx->var_values[VAR_N] = link->frame_count_out; + 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; @@ -1573,7 +1580,7 @@ void ff_inlink_request_frame(AVFilterLink *link) av_unused FilterLinkInternal *li = ff_link_internal(link); av_assert1(!li->status_in); av_assert1(!li->status_out); - link->frame_wanted_out = 1; + li->frame_wanted_out = 1; ff_filter_set_ready(link->src, 100); } @@ -1582,7 +1589,7 @@ void ff_inlink_set_status(AVFilterLink *link, int status) FilterLinkInternal * const li = ff_link_internal(link); if (li->status_out) return; - link->frame_wanted_out = 0; + li->frame_wanted_out = 0; li->frame_blocked_in = 0; link_set_out_status(link, status, AV_NOPTS_VALUE); while (ff_framequeue_queued_frames(&li->fifo)) { @@ -1616,12 +1623,13 @@ const AVClass *avfilter_get_class(void) int ff_filter_init_hw_frames(AVFilterContext *avctx, AVFilterLink *link, int default_pool_size) { + FilterLink *l = ff_filter_link(link); AVHWFramesContext *frames; // Must already be set by caller. - av_assert0(link->hw_frames_ctx); + av_assert0(l->hw_frames_ctx); - frames = (AVHWFramesContext*)link->hw_frames_ctx->data; + frames = (AVHWFramesContext*)l->hw_frames_ctx->data; if (frames->initial_pool_size == 0) { // Dynamic allocation is necessarily supported. @@ -1633,3 +1641,15 @@ int ff_filter_init_hw_frames(AVFilterContext *avctx, AVFilterLink *link, return 0; } + +int ff_outlink_frame_wanted(AVFilterLink *link) +{ + FilterLinkInternal * const li = ff_link_internal(link); + return li->frame_wanted_out; +} + +int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, + void *arg, int *ret, int nb_jobs) +{ + return fffilterctx(ctx)->execute(ctx, func, arg, ret, nb_jobs); +} diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index a34e61f23..1401577c5 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -98,6 +98,41 @@ const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx); */ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx); +/** + * Lists of formats / etc. supported by an end of a link. + * + * This structure is directly part of AVFilterLink, in two copies: + * one for the source filter, one for the destination filter. + + * These lists are used for negotiating the format to actually be used, + * which will be loaded into the format and channel_layout members of + * AVFilterLink, when chosen. + */ +typedef struct AVFilterFormatsConfig { + + /** + * List of supported formats (pixel or sample). + */ + AVFilterFormats *formats; + + /** + * Lists of supported sample rates, only for audio. + */ + AVFilterFormats *samplerates; + + /** + * Lists of supported channel layouts, only for audio. + */ + AVFilterChannelLayouts *channel_layouts; + + /** + * Lists of supported YUV color metadata, only for YUV video. + */ + AVFilterFormats *color_spaces; ///< AVColorSpace + AVFilterFormats *color_ranges; ///< AVColorRange + +} AVFilterFormatsConfig; + /** * The number of the filter inputs is not determined just by AVFilter.inputs. * The filter might add additional inputs during initialization depending on the @@ -324,6 +359,21 @@ typedef struct AVFilter { * 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 @@ -492,41 +542,6 @@ struct AVFilterContext { int extra_hw_frames; }; -/** - * Lists of formats / etc. supported by an end of a link. - * - * This structure is directly part of AVFilterLink, in two copies: - * one for the source filter, one for the destination filter. - - * These lists are used for negotiating the format to actually be used, - * which will be loaded into the format and channel_layout members of - * AVFilterLink, when chosen. - */ -typedef struct AVFilterFormatsConfig { - - /** - * List of supported formats (pixel or sample). - */ - AVFilterFormats *formats; - - /** - * Lists of supported sample rates, only for audio. - */ - AVFilterFormats *samplerates; - - /** - * Lists of supported channel layouts, only for audio. - */ - AVFilterChannelLayouts *channel_layouts; - - /** - * Lists of supported YUV color metadata, only for YUV video. - */ - AVFilterFormats *color_spaces; ///< AVColorSpace - AVFilterFormats *color_ranges; ///< AVColorRange - -} AVFilterFormatsConfig; - /** * A link between two filters. This contains pointers to the source and * destination filters between which this link exists, and the indexes of @@ -594,74 +609,6 @@ struct AVFilterLink { * Lists of supported formats / etc. supported by the output filter. */ AVFilterFormatsConfig outcfg; - - /** - * Graph the filter belongs to. - */ - struct AVFilterGraph *graph; - - /** - * Current timestamp of the link, as defined by the most recent - * frame(s), in link time_base units. - */ - int64_t current_pts; - - /** - * Current timestamp of the link, as defined by the most recent - * frame(s), in AV_TIME_BASE units. - */ - int64_t current_pts_us; - - /** - * Frame rate of the stream on the link, or 1/0 if unknown or variable; - * if left to 0/0, will be automatically copied from the first input - * of the source filter if it exists. - * - * Sources should set it to the best estimation of the real frame rate. - * If the source frame rate is unknown or variable, set this to 1/0. - * Filters should update it if necessary depending on their function. - * Sinks can use it to set a default output frame rate. - * It is similar to the r_frame_rate field in AVStream. - */ - AVRational frame_rate; - - /** - * Minimum number of samples to filter at once. If filter_frame() is - * called with fewer samples, it will accumulate them in fifo. - * This field and the related ones must not be changed after filtering - * has started. - * If 0, all related fields are ignored. - */ - int min_samples; - - /** - * Maximum number of samples to filter at once. If filter_frame() is - * called with more samples, it will split them. - */ - int max_samples; - - /** - * Number of past frames sent through the link. - */ - int64_t frame_count_in, frame_count_out; - - /** - * Number of past samples sent through the link. - */ - int64_t sample_count_in, sample_count_out; - - /** - * True if a frame is currently wanted on the output of this filter. - * Set when ff_request_frame() is called by the output, - * cleared when a frame is filtered. - */ - int frame_wanted_out; - - /** - * For hwaccel pixel formats, this should be a reference to the - * AVHWFramesContext describing the frames. - */ - AVBufferRef *hw_frames_ctx; }; /** diff --git a/libavfilter/avfilter_internal.h b/libavfilter/avfilter_internal.h index 2c31c3e7d..ec3933b1d 100644 --- a/libavfilter/avfilter_internal.h +++ b/libavfilter/avfilter_internal.h @@ -28,10 +28,11 @@ #include #include "avfilter.h" +#include "filters.h" #include "framequeue.h" typedef struct FilterLinkInternal { - AVFilterLink l; + FilterLink l; struct FFFramePool *frame_pool; @@ -66,6 +67,13 @@ typedef struct FilterLinkInternal { */ int status_out; + /** + * True if a frame is currently wanted on the output of this filter. + * Set when ff_request_frame() is called by the output, + * cleared when a frame is filtered. + */ + int frame_wanted_out; + /** * Index in the age array. */ @@ -84,6 +92,24 @@ static inline FilterLinkInternal *ff_link_internal(AVFilterLink *link) return (FilterLinkInternal*)link; } +typedef struct FFFilterContext { + /** + * The public AVFilterContext. See avfilter.h for it. + */ + AVFilterContext p; + + avfilter_execute_func *execute; + + // 1 when avfilter_init_*() was successfully called on this filter + // 0 otherwise + int initialized; +} FFFilterContext; + +static inline FFFilterContext *fffilterctx(AVFilterContext *ctx) +{ + return (FFFilterContext*)ctx; +} + typedef struct AVFilterCommand { double time; ///< time expressed in seconds char *command; ///< command @@ -153,4 +179,42 @@ int ff_graph_thread_init(FFFilterGraph *graph); void ff_graph_thread_free(FFFilterGraph *graph); +/** + * Negotiate the media format, dimensions, etc of all inputs to a filter. + * + * @param filter the filter to negotiate the properties for its inputs + * @return zero on successful negotiation + */ +int ff_filter_config_links(AVFilterContext *filter); + +/* misc trace functions */ + +#define FF_TPRINTF_START(ctx, func) ff_tlog(NULL, "%-16s: ", #func) + +#ifdef TRACE +void ff_tlog_link(void *ctx, AVFilterLink *link, int end); +#else +#define ff_tlog_link(ctx, link, end) do { } while(0) +#endif + +/** + * Run one round of processing on a filter graph. + */ +int ff_filter_graph_run_once(AVFilterGraph *graph); + +/** + * Process the commands queued in the link up to the time of the frame. + * Commands will trigger the process_command() callback. + * @return >= 0 or AVERROR code. + */ +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 8e091d95e..38077ff70 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -27,8 +27,8 @@ #include "libavutil/avassert.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" -#include "libavutil/hwcontext.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -36,9 +36,10 @@ #include "avfilter.h" #include "avfilter_internal.h" #include "buffersink.h" +#include "filters.h" #include "formats.h" #include "framequeue.h" -#include "internal.h" +#include "video.h" #define OFFSET(x) offsetof(AVFilterGraph, x) #define F AV_OPT_FLAG_FILTERING_PARAM @@ -106,7 +107,7 @@ void ff_filter_graph_remove_filter(AVFilterGraph *graph, AVFilterContext *filter filter->graph = NULL; for (j = 0; jnb_outputs; j++) if (filter->outputs[j]) - filter->outputs[j]->graph = NULL; + ff_filter_link(filter->outputs[j])->graph = NULL; return; } @@ -351,7 +352,52 @@ static int filter_query_formats(AVFilterContext *ctx) ctx->name, av_err2str(ret)); return ret; } + } else if (ctx->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; + if (ctx->nb_inputs > FF_ARRAY_ELEMS(cfg_in_stack)) { + cfg_in_dyn = av_malloc_array(ctx->nb_inputs, sizeof(*cfg_in_dyn)); + if (!cfg_in_dyn) + return AVERROR(ENOMEM); + cfg_in = cfg_in_dyn; + } else + cfg_in = ctx->nb_inputs ? cfg_in_stack : NULL; + + for (unsigned i = 0; i < ctx->nb_inputs; i++) { + AVFilterLink *l = ctx->inputs[i]; + cfg_in[i] = &l->outcfg; + } + + if (ctx->nb_outputs > FF_ARRAY_ELEMS(cfg_out_stack)) { + cfg_out_dyn = av_malloc_array(ctx->nb_outputs, sizeof(*cfg_out_dyn)); + if (!cfg_out_dyn) { + av_freep(&cfg_in_dyn); + return AVERROR(ENOMEM); + } + cfg_out = cfg_out_dyn; + } else + cfg_out = ctx->nb_outputs ? cfg_out_stack : NULL; + + for (unsigned i = 0; i < ctx->nb_outputs; i++) { + AVFilterLink *l = ctx->outputs[i]; + cfg_out[i] = &l->incfg; + } + + ret = ctx->filter->formats.query_func2(ctx, cfg_in, cfg_out); + av_freep(&cfg_in_dyn); + av_freep(&cfg_out_dyn); + if (ret < 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; + } + } + + if (ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC || + ctx->filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { ret = filter_check_formats(ctx); if (ret < 0) return ret; @@ -610,19 +656,22 @@ int ff_fmt_is_regular_yuv(enum AVPixelFormat fmt) if (desc->nb_components < 3) return 0; /* Grayscale is explicitly full-range in swscale */ av_assert1(!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)); - if (desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PAL | - AV_PIX_FMT_FLAG_XYZ | AV_PIX_FMT_FLAG_FLOAT)) - return 0; + return !(desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PAL | + AV_PIX_FMT_FLAG_XYZ | AV_PIX_FMT_FLAG_FLOAT)); +} + +int ff_fmt_is_forced_full_range(enum AVPixelFormat fmt) +{ switch (fmt) { case AV_PIX_FMT_YUVJ420P: case AV_PIX_FMT_YUVJ422P: case AV_PIX_FMT_YUVJ444P: case AV_PIX_FMT_YUVJ440P: case AV_PIX_FMT_YUVJ411P: - return 0; - default: return 1; + default: + return 0; } } @@ -698,14 +747,18 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) link->incfg.color_spaces->nb_formats = 1; link->colorspace = link->incfg.color_spaces->formats[0]; - if (!link->incfg.color_ranges->nb_formats) { - av_log(link->src, AV_LOG_ERROR, "Cannot select color range for" - " the link between filters %s and %s.\n", link->src->name, - link->dst->name); - return AVERROR(EINVAL); + if (ff_fmt_is_forced_full_range(swfmt)) { + link->color_range = AVCOL_RANGE_JPEG; + } else { + if (!link->incfg.color_ranges->nb_formats) { + av_log(link->src, AV_LOG_ERROR, "Cannot select color range for" + " the link between filters %s and %s.\n", link->src->name, + link->dst->name); + return AVERROR(EINVAL); + } + link->incfg.color_ranges->nb_formats = 1; + link->color_range = link->incfg.color_ranges->formats[0]; } - link->incfg.color_ranges->nb_formats = 1; - link->color_range = link->incfg.color_ranges->formats[0]; } } else if (link->type == AVMEDIA_TYPE_AUDIO) { int ret; @@ -1208,11 +1261,9 @@ static int graph_config_pointers(AVFilterGraph *graph, void *log_ctx) for (i = 0; i < graph->nb_filters; i++) { f = graph->filters[i]; for (j = 0; j < f->nb_inputs; j++) { - f->inputs[j]->graph = graph; ff_link_internal(f->inputs[j])->age_index = -1; } for (j = 0; j < f->nb_outputs; j++) { - f->outputs[j]->graph = graph; ff_link_internal(f->outputs[j])->age_index = -1; } if (!f->nb_outputs) { @@ -1374,13 +1425,13 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) { FFFilterGraph *graphi = fffiltergraph(graph); FilterLinkInternal *oldesti = graphi->sink_links[0]; - AVFilterLink *oldest = &oldesti->l; + AVFilterLink *oldest = &oldesti->l.pub; int64_t frame_count; int r; while (graphi->sink_links_count) { oldesti = graphi->sink_links[0]; - oldest = &oldesti->l; + oldest = &oldesti->l.pub; if (oldest->dst->filter->activate) { r = av_buffersink_get_frame_flags(oldest->dst, NULL, AV_BUFFERSINK_FLAG_PEEK); @@ -1404,11 +1455,11 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph) return AVERROR_EOF; av_assert1(!oldest->dst->filter->activate); av_assert1(oldesti->age_index >= 0); - frame_count = oldest->frame_count_out; - while (frame_count == oldest->frame_count_out) { + frame_count = oldesti->l.frame_count_out; + while (frame_count == oldesti->l.frame_count_out) { r = ff_filter_graph_run_once(graph); if (r == AVERROR(EAGAIN) && - !oldest->frame_wanted_out && !oldesti->frame_blocked_in && + !oldesti->frame_wanted_out && !oldesti->frame_blocked_in && !oldesti->status_in) (void)ff_request_frame(oldest); else if (r < 0) diff --git a/libavfilter/blend.h b/libavfilter/blend.h index b046e062b..e6636839d 100644 --- a/libavfilter/blend.h +++ b/libavfilter/blend.h @@ -69,16 +69,22 @@ enum BlendMode { BLEND_NB }; +typedef struct SliceParams { + double *values; + int starty; + AVExpr *e; +} SliceParams; + typedef struct FilterParams { enum BlendMode mode; double opacity; - AVExpr *e; + AVExpr **e; char *expr_str; void (*blend)(const uint8_t *top, ptrdiff_t top_linesize, const uint8_t *bottom, ptrdiff_t bottom_linesize, uint8_t *dst, ptrdiff_t dst_linesize, ptrdiff_t width, ptrdiff_t height, - struct FilterParams *param, double *values, int starty); + struct FilterParams *param, SliceParams *sliceparam); } FilterParams; void ff_blend_init_x86(FilterParams *param, int depth); diff --git a/libavfilter/blend_modes.c b/libavfilter/blend_modes.c index 65c5e6f89..9b1e78b14 100644 --- a/libavfilter/blend_modes.c +++ b/libavfilter/blend_modes.c @@ -21,7 +21,6 @@ #include "libavutil/common.h" #include "libavutil/intfloat.h" #include "avfilter.h" -#include "internal.h" #include "video.h" #include "blend.h" @@ -91,7 +90,7 @@ static void fn0(NAME)(const uint8_t *_top, ptrdiff_t top_linesize, \ const uint8_t *_bottom, ptrdiff_t bottom_linesize, \ uint8_t *_dst, ptrdiff_t dst_linesize, \ ptrdiff_t width, ptrdiff_t height, \ - FilterParams *param, double *values, int starty) \ + FilterParams *param, SliceParams *sliceparam) \ { \ const PIXEL *top = (const PIXEL *)_top; \ const PIXEL *bottom = (const PIXEL *)_bottom; \ diff --git a/libavfilter/boxblur.c b/libavfilter/boxblur.c index 2287396f2..43c724dae 100644 --- a/libavfilter/boxblur.c +++ b/libavfilter/boxblur.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "boxblur.h" static const char *const var_names[] = { diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c index e05bd0a57..5811720c6 100644 --- a/libavfilter/buffersink.c +++ b/libavfilter/buffersink.c @@ -37,7 +37,6 @@ #include "filters.h" #include "formats.h" #include "framequeue.h" -#include "internal.h" #include "video.h" typedef struct BufferSinkContext { @@ -88,6 +87,7 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i { BufferSinkContext *buf = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLinkInternal *li = ff_link_internal(inlink); int status, ret; AVFrame *cur_frame; int64_t pts; @@ -107,7 +107,7 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i return status; } else if ((flags & AV_BUFFERSINK_FLAG_NO_REQUEST)) { return AVERROR(EAGAIN); - } else if (inlink->frame_wanted_out) { + } else if (li->frame_wanted_out) { ret = ff_filter_graph_run_once(ctx->graph); if (ret < 0) return ret; @@ -119,7 +119,8 @@ static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, i int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags) { - return get_frame_internal(ctx, frame, flags, ctx->inputs[0]->min_samples); + return get_frame_internal(ctx, frame, flags, + ff_filter_link(ctx->inputs[0])->min_samples); } int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx, @@ -163,7 +164,7 @@ static int activate(AVFilterContext *ctx) void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size) { - AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inlink = ff_filter_link(ctx->inputs[0]); inlink->min_samples = inlink->max_samples = frame_size; } @@ -178,7 +179,6 @@ MAKE_AVFILTERLINK_ACCESSOR(enum AVMediaType , type ) MAKE_AVFILTERLINK_ACCESSOR(AVRational , time_base ) MAKE_AVFILTERLINK_ACCESSOR(int , format ) -MAKE_AVFILTERLINK_ACCESSOR(AVRational , frame_rate ) MAKE_AVFILTERLINK_ACCESSOR(int , w ) MAKE_AVFILTERLINK_ACCESSOR(int , h ) MAKE_AVFILTERLINK_ACCESSOR(AVRational , sample_aspect_ratio) @@ -187,7 +187,19 @@ MAKE_AVFILTERLINK_ACCESSOR(enum AVColorRange, color_range) MAKE_AVFILTERLINK_ACCESSOR(int , sample_rate ) -MAKE_AVFILTERLINK_ACCESSOR(AVBufferRef * , hw_frames_ctx ) +AVRational av_buffersink_get_frame_rate(const AVFilterContext *ctx) +{ + FilterLink *l = ff_filter_link(ctx->inputs[0]); + av_assert0(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); + return l->hw_frames_ctx; +} int av_buffersink_get_channels(const AVFilterContext *ctx) { diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index fcae4f8e6..ec5898fcf 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -26,20 +26,19 @@ #include #include "libavutil/channel_layout.h" -#include "libavutil/common.h" #include "libavutil/frame.h" #include "libavutil/hwcontext.h" -#include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "libavutil/samplefmt.h" #include "libavutil/timestamp.h" -#include "audio.h" #include "avfilter.h" +#include "avfilter_internal.h" #include "buffersrc.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct BufferSourceContext { @@ -217,7 +216,7 @@ int attribute_align_arg av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFra break; case AVMEDIA_TYPE_AUDIO: /* For layouts unknown on input but known on link after negotiation. */ - if (frame->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) { + if (frame->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC && frame->ch_layout.nb_channels == s->ch_layout.nb_channels) { ret = av_channel_layout_copy(&frame->ch_layout, &s->ch_layout); if (ret < 0) return ret; @@ -337,12 +336,15 @@ static const AVOption buffer_options[] = { { "smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE170M}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, { "smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE240M}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, { "ycgco", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, + { "ycgco-re", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO_RE}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, + { "ycgco-ro", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO_RO}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, { "bt2020nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, { "bt2020c", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_CL}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, { "smpte2085", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE2085}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, { "chroma-derived-nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_NCL},INT_MIN, INT_MAX, V, .unit = "colorspace"}, { "chroma-derived-c", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_CL}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, { "ictcp", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_ICTCP}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, + { "ipt-c2", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_IPT_C2}, INT_MIN, INT_MAX, V, .unit = "colorspace"}, { "range", "select color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, AVCOL_RANGE_NB-1, V, .unit = "range"}, { "unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, V, .unit = "range"}, { "unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, V, .unit = "range"}, @@ -412,6 +414,11 @@ static av_cold int init_audio(AVFilterContext *ctx) av_channel_layout_describe(&s->ch_layout, buf, sizeof(buf)); } + if (s->sample_rate <= 0) { + av_log(ctx, AV_LOG_ERROR, "Sample rate not set\n"); + return AVERROR(EINVAL); + } + if (!s->time_base.num) s->time_base = (AVRational){1, s->sample_rate}; @@ -459,12 +466,17 @@ static int query_formats(AVFilterContext *ctx) if ((ret = ff_add_format(&color_spaces, c->color_space)) < 0 || (ret = ff_set_common_color_spaces(ctx, color_spaces)) < 0) return ret; - if ((ret = ff_add_format(&color_ranges, c->color_range)) < 0) - return ret; - if (c->color_range == AVCOL_RANGE_UNSPECIFIED) { - /* allow implicitly promoting unspecified to mpeg */ - if ((ret = ff_add_format(&color_ranges, AVCOL_RANGE_MPEG)) < 0) + if (ff_fmt_is_forced_full_range(swfmt)) { + if ((ret = ff_add_format(&color_ranges, AVCOL_RANGE_JPEG)) < 0) return ret; + } else { + if ((ret = ff_add_format(&color_ranges, c->color_range)) < 0) + return ret; + if (c->color_range == AVCOL_RANGE_UNSPECIFIED) { + /* allow implicitly promoting unspecified to mpeg */ + if ((ret = ff_add_format(&color_ranges, AVCOL_RANGE_MPEG)) < 0) + return ret; + } } if ((ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0) return ret; @@ -492,6 +504,7 @@ static int query_formats(AVFilterContext *ctx) static int config_props(AVFilterLink *link) { + FilterLink *l = ff_filter_link(link); BufferSourceContext *c = link->src->priv; switch (link->type) { @@ -501,8 +514,8 @@ static int config_props(AVFilterLink *link) link->sample_aspect_ratio = c->pixel_aspect; if (c->hw_frames_ctx) { - link->hw_frames_ctx = av_buffer_ref(c->hw_frames_ctx); - if (!link->hw_frames_ctx) + l->hw_frames_ctx = av_buffer_ref(c->hw_frames_ctx); + if (!l->hw_frames_ctx) return AVERROR(ENOMEM); } break; @@ -518,7 +531,7 @@ static int config_props(AVFilterLink *link) } link->time_base = c->time_base; - link->frame_rate = c->frame_rate; + l->frame_rate = c->frame_rate; return 0; } diff --git a/libavfilter/convolution.h b/libavfilter/convolution.h index ee7477ef8..1196c1fcd 100644 --- a/libavfilter/convolution.h +++ b/libavfilter/convolution.h @@ -119,7 +119,7 @@ static void filter16_sobel(uint8_t *dstp, int width, } } -static av_unused void ff_sobel_init(ConvolutionContext *s, int depth, int nb_planes) +static inline void ff_sobel_init(ConvolutionContext *s, int depth, int nb_planes) { for (int i = 0; i < 4; i++) { s->filter[i] = filter_sobel; diff --git a/libavfilter/cuda/load_helper.c b/libavfilter/cuda/load_helper.c index 280e596ec..b049ec713 100644 --- a/libavfilter/cuda/load_helper.c +++ b/libavfilter/cuda/load_helper.c @@ -21,6 +21,7 @@ #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" #include "libavutil/cuda_check.h" +#include "libavutil/mem.h" #if CONFIG_PTX_COMPRESSION #include diff --git a/libavfilter/dialoguenhance_template.c b/libavfilter/dialoguenhance_template.c index 26650f7d8..d95d7dba5 100644 --- a/libavfilter/dialoguenhance_template.c +++ b/libavfilter/dialoguenhance_template.c @@ -16,9 +16,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "avfilter.h" -#include "internal.h" #include "audio.h" #undef ctype diff --git a/libavfilter/dnn/dnn_backend_common.c b/libavfilter/dnn/dnn_backend_common.c index 632832ec3..e45eefd14 100644 --- a/libavfilter/dnn/dnn_backend_common.c +++ b/libavfilter/dnn/dnn_backend_common.c @@ -21,6 +21,7 @@ * DNN common functions different backends. */ +#include "libavutil/mem.h" #include "dnn_backend_common.h" #define DNN_ASYNC_SUCCESS (void *)0 diff --git a/libavfilter/dnn/dnn_backend_common.h b/libavfilter/dnn/dnn_backend_common.h index 42c67c704..9f5d37b3e 100644 --- a/libavfilter/dnn/dnn_backend_common.h +++ b/libavfilter/dnn/dnn_backend_common.h @@ -28,9 +28,16 @@ #include "../dnn_interface.h" #include "libavutil/thread.h" -#define DNN_BACKEND_COMMON_OPTIONS \ - { "nireq", "number of request", OFFSET(options.nireq), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, \ - { "async", "use DNN async inference", OFFSET(options.async), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, +#define DNN_DEFINE_CLASS_EXT(name, desc, options) \ + { \ + .class_name = desc, \ + .item_name = av_default_item_name, \ + .option = options, \ + .version = LIBAVUTIL_VERSION_INT, \ + .category = AV_CLASS_CATEGORY_FILTER, \ + } +#define DNN_DEFINE_CLASS(fname) \ + DNN_DEFINE_CLASS_EXT(fname, #fname, fname##_options) // one task for one function call from dnn interface typedef struct TaskItem { diff --git a/libavfilter/dnn/dnn_backend_openvino.c b/libavfilter/dnn/dnn_backend_openvino.c index 375643377..2f6706dcd 100644 --- a/libavfilter/dnn/dnn_backend_openvino.c +++ b/libavfilter/dnn/dnn_backend_openvino.c @@ -27,10 +27,10 @@ #include "libavformat/avio.h" #include "libavutil/avassert.h" #include "libavutil/cpu.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/avstring.h" #include "libavutil/detection_bbox.h" -#include "../internal.h" #include "safe_queue.h" #if HAVE_OPENVINO2 #include @@ -39,25 +39,9 @@ #endif #include "dnn_backend_common.h" -typedef struct OVOptions{ - char *device_type; - int nireq; - uint8_t async; - int batch_size; - int input_resizable; - DNNLayout layout; - float scale; - float mean; -} OVOptions; - -typedef struct OVContext { - const AVClass *class; - OVOptions options; -} OVContext; - typedef struct OVModel{ - OVContext ctx; - DNNModel *model; + DNNModel model; + DnnContext *ctx; #if HAVE_OPENVINO2 ov_core_t *core; ov_model_t *ov_model; @@ -97,24 +81,20 @@ typedef struct OVRequestItem { generated_string = generated_string ? av_asprintf("%s %s", generated_string, iterate_string) : \ av_asprintf("%s", iterate_string); -#define OFFSET(x) offsetof(OVContext, x) +#define OFFSET(x) offsetof(OVOptions, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM static const AVOption dnn_openvino_options[] = { - { "device", "device to run model", OFFSET(options.device_type), AV_OPT_TYPE_STRING, { .str = "CPU" }, 0, 0, FLAGS }, - DNN_BACKEND_COMMON_OPTIONS - { "batch_size", "batch size per request", OFFSET(options.batch_size), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 1000, FLAGS}, - { "input_resizable", "can input be resizable or not", OFFSET(options.input_resizable), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, - { "layout", "input layout of model", OFFSET(options.layout), AV_OPT_TYPE_INT, { .i64 = DL_NONE}, DL_NONE, DL_NHWC, FLAGS, .unit = "layout" }, + { "batch_size", "batch size per request", OFFSET(batch_size), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 1000, FLAGS}, + { "input_resizable", "can input be resizable or not", OFFSET(input_resizable), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { "layout", "input layout of model", OFFSET(layout), AV_OPT_TYPE_INT, { .i64 = DL_NONE}, DL_NONE, DL_NHWC, FLAGS, .unit = "layout" }, { "none", "none", 0, AV_OPT_TYPE_CONST, { .i64 = DL_NONE }, 0, 0, FLAGS, .unit = "layout"}, { "nchw", "nchw", 0, AV_OPT_TYPE_CONST, { .i64 = DL_NCHW }, 0, 0, FLAGS, .unit = "layout"}, { "nhwc", "nhwc", 0, AV_OPT_TYPE_CONST, { .i64 = DL_NHWC }, 0, 0, FLAGS, .unit = "layout"}, - { "scale", "Add scale preprocess operation. Divide each element of input by specified value.", OFFSET(options.scale), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, INT_MIN, INT_MAX, FLAGS}, - { "mean", "Add mean preprocess operation. Subtract specified value from each element of input.", OFFSET(options.mean), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, INT_MIN, INT_MAX, FLAGS}, + { "scale", "Add scale preprocess operation. Divide each element of input by specified value.", OFFSET(scale), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, INT_MIN, INT_MAX, FLAGS}, + { "mean", "Add mean preprocess operation. Subtract specified value from each element of input.", OFFSET(mean), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, INT_MIN, INT_MAX, FLAGS}, { NULL } }; -AVFILTER_DEFINE_CLASS(dnn_openvino); - #if HAVE_OPENVINO2 static const struct { ov_status_e status; @@ -198,7 +178,7 @@ static int fill_model_input_ov(OVModel *ov_model, OVRequestItem *request) DNNData input; LastLevelTaskItem *lltask; TaskItem *task; - OVContext *ctx = &ov_model->ctx; + DnnContext *ctx = ov_model->ctx; #if HAVE_OPENVINO2 int64_t* dims; ov_status_e status; @@ -291,7 +271,7 @@ static int fill_model_input_ov(OVModel *ov_model, OVRequestItem *request) input.scale = 1; input.mean = 0; - for (int i = 0; i < ctx->options.batch_size; ++i) { + for (int i = 0; i < ctx->ov_option.batch_size; ++i) { lltask = ff_queue_pop_front(ov_model->lltask_queue); if (!lltask) { break; @@ -319,11 +299,11 @@ static int fill_model_input_ov(OVModel *ov_model, OVRequestItem *request) return ov2_map_error(status, NULL); } #endif - switch (ov_model->model->func_type) { + switch (ov_model->model.func_type) { case DFT_PROCESS_FRAME: if (task->do_ioproc) { - if (ov_model->model->frame_pre_proc != NULL) { - ov_model->model->frame_pre_proc(task->in_frame, &input, ov_model->model->filter_ctx); + if (ov_model->model.frame_pre_proc != NULL) { + ov_model->model.frame_pre_proc(task->in_frame, &input, ov_model->model.filter_ctx); } else { ff_proc_from_frame_to_dnn(task->in_frame, &input, ctx); } @@ -359,7 +339,7 @@ static void infer_completion_callback(void *args) OVModel *ov_model = task->model; SafeQueue *requestq = ov_model->request_queue; DNNData *outputs; - OVContext *ctx = &ov_model->ctx; + DnnContext *ctx = ov_model->ctx; #if HAVE_OPENVINO2 size_t* dims; ov_status_e status; @@ -409,9 +389,9 @@ static void infer_completion_callback(void *args) outputs[i].dims[2] = output_shape.rank > 1 ? dims[output_shape.rank - 2] : 1; outputs[i].dims[3] = output_shape.rank > 0 ? dims[output_shape.rank - 1] : 1; av_assert0(request->lltask_count <= dims[0]); - outputs[i].layout = ctx->options.layout; - outputs[i].scale = ctx->options.scale; - outputs[i].mean = ctx->options.mean; + outputs[i].layout = ctx->ov_option.layout; + outputs[i].scale = ctx->ov_option.scale; + outputs[i].mean = ctx->ov_option.mean; ov_shape_free(&output_shape); ov_tensor_free(output_tensor); output_tensor = NULL; @@ -451,9 +431,9 @@ static void infer_completion_callback(void *args) output.dims[i] = dims.dims[i]; av_assert0(request->lltask_count <= dims.dims[0]); output.dt = precision_to_datatype(precision); - output.layout = ctx->options.layout; - output.scale = ctx->options.scale; - output.mean = ctx->options.mean; + output.layout = ctx->ov_option.layout; + output.scale = ctx->ov_option.scale; + output.mean = ctx->ov_option.mean; outputs = &output; #endif @@ -461,11 +441,11 @@ static void infer_completion_callback(void *args) for (int i = 0; i < request->lltask_count; ++i) { task = request->lltasks[i]->task; - switch (ov_model->model->func_type) { + switch (ov_model->model.func_type) { case DFT_PROCESS_FRAME: if (task->do_ioproc) { - if (ov_model->model->frame_post_proc != NULL) { - ov_model->model->frame_post_proc(task->out_frame, outputs, ov_model->model->filter_ctx); + if (ov_model->model.frame_post_proc != NULL) { + ov_model->model.frame_post_proc(task->out_frame, outputs, ov_model->model.filter_ctx); } else { ff_proc_from_dnn_to_frame(task->out_frame, outputs, ctx); } @@ -477,23 +457,23 @@ static void infer_completion_callback(void *args) } break; case DFT_ANALYTICS_DETECT: - if (!ov_model->model->detect_post_proc) { + if (!ov_model->model.detect_post_proc) { av_log(ctx, AV_LOG_ERROR, "detect filter needs to provide post proc\n"); goto end; } - ov_model->model->detect_post_proc(task->in_frame, outputs, + ov_model->model.detect_post_proc(task->in_frame, outputs, ov_model->nb_outputs, - ov_model->model->filter_ctx); + ov_model->model.filter_ctx); break; case DFT_ANALYTICS_CLASSIFY: - if (!ov_model->model->classify_post_proc) { + if (!ov_model->model.classify_post_proc) { av_log(ctx, AV_LOG_ERROR, "classify filter needs to provide post proc\n"); goto end; } for (int output_i = 0; output_i < ov_model->nb_outputs; output_i++) - ov_model->model->classify_post_proc(task->in_frame, outputs, + ov_model->model.classify_post_proc(task->in_frame, outputs, request->lltasks[i]->bbox_index, - ov_model->model->filter_ctx); + ov_model->model.filter_ctx); break; default: av_assert0(!"should not reach here"); @@ -536,7 +516,7 @@ static void dnn_free_model_ov(DNNModel **model) if (!model || !*model) return; - ov_model = (*model)->model; + ov_model = (OVModel *)(*model); while (ff_safe_queue_size(ov_model->request_queue) != 0) { OVRequestItem *item = ff_safe_queue_pop_front(ov_model->request_queue); if (item && item->infer_request) { @@ -589,16 +569,15 @@ static void dnn_free_model_ov(DNNModel **model) av_free(ov_model->all_output_names); av_free(ov_model->all_input_names); #endif - av_opt_free(&ov_model->ctx); av_freep(&ov_model); - av_freep(model); + *model = NULL; } static int init_model_ov(OVModel *ov_model, const char *input_name, const char **output_names, int nb_outputs) { int ret = 0; - OVContext *ctx = &ov_model->ctx; + DnnContext *ctx = ov_model->ctx; #if HAVE_OPENVINO2 ov_status_e status; ov_preprocess_input_tensor_info_t* input_tensor_info = NULL; @@ -609,7 +588,7 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * ov_layout_t* NCHW_layout = NULL; const char* NHWC_desc = "NHWC"; const char* NCHW_desc = "NCHW"; - const char* device = ctx->options.device_type; + const char* device = ctx->device ? ctx->device : "CPU"; #else IEStatusCode status; ie_available_devices_t a_dev; @@ -617,17 +596,17 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * char *all_dev_names = NULL; #endif // We scale pixel by default when do frame processing. - if (fabsf(ctx->options.scale) < 1e-6f) - ctx->options.scale = ov_model->model->func_type == DFT_PROCESS_FRAME ? 255 : 1; + if (fabsf(ctx->ov_option.scale) < 1e-6f) + ctx->ov_option.scale = ov_model->model.func_type == DFT_PROCESS_FRAME ? 255 : 1; // batch size - if (ctx->options.batch_size <= 0) { - ctx->options.batch_size = 1; + if (ctx->ov_option.batch_size <= 0) { + ctx->ov_option.batch_size = 1; } #if HAVE_OPENVINO2 - if (ctx->options.batch_size > 1) { + if (ctx->ov_option.batch_size > 1) { avpriv_report_missing_feature(ctx, "Do not support batch_size > 1 for now," "change batch_size to 1.\n"); - ctx->options.batch_size = 1; + ctx->ov_option.batch_size = 1; } status = ov_preprocess_prepostprocessor_create(ov_model->ov_model, &ov_model->preprocess); @@ -676,9 +655,9 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * ret = ov2_map_error(status, NULL); goto err; } - if (ctx->options.layout == DL_NCHW) + if (ctx->ov_option.layout == DL_NCHW) status = ov_preprocess_input_model_info_set_layout(input_model_info, NCHW_layout); - else if (ctx->options.layout == DL_NHWC) + else if (ctx->ov_option.layout == DL_NHWC) status = ov_preprocess_input_model_info_set_layout(input_model_info, NHWC_layout); if (status != OK) { av_log(ctx, AV_LOG_ERROR, "Failed to get set input model layout\n"); @@ -722,9 +701,9 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * ret = ov2_map_error(status, NULL); goto err; } - if (ov_model->model->func_type != DFT_PROCESS_FRAME) + if (ov_model->model.func_type != DFT_PROCESS_FRAME) status |= ov_preprocess_output_set_element_type(output_tensor_info, F32); - else if (fabsf(ctx->options.scale - 1) > 1e-6f || fabsf(ctx->options.mean) > 1e-6f) + else if (fabsf(ctx->ov_option.scale - 1) > 1e-6f || fabsf(ctx->ov_option.mean) > 1e-6f) status |= ov_preprocess_output_set_element_type(output_tensor_info, F32); else status |= ov_preprocess_output_set_element_type(output_tensor_info, U8); @@ -739,7 +718,7 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * ov_model->output_info = NULL; } // set preprocess steps. - if (fabsf(ctx->options.scale - 1) > 1e-6f || fabsf(ctx->options.mean) > 1e-6f) { + if (fabsf(ctx->ov_option.scale - 1) > 1e-6f || fabsf(ctx->ov_option.mean) > 1e-6f) { ov_preprocess_preprocess_steps_t* input_process_steps = NULL; status = ov_preprocess_input_info_get_preprocess_steps(ov_model->input_info, &input_process_steps); if (status != OK) { @@ -748,8 +727,8 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * goto err; } status = ov_preprocess_preprocess_steps_convert_element_type(input_process_steps, F32); - status |= ov_preprocess_preprocess_steps_mean(input_process_steps, ctx->options.mean); - status |= ov_preprocess_preprocess_steps_scale(input_process_steps, ctx->options.scale); + status |= ov_preprocess_preprocess_steps_mean(input_process_steps, ctx->ov_option.mean); + status |= ov_preprocess_preprocess_steps_scale(input_process_steps, ctx->ov_option.scale); if (status != OK) { av_log(ctx, AV_LOG_ERROR, "Failed to set preprocess steps\n"); ov_preprocess_preprocess_steps_free(input_process_steps); @@ -823,7 +802,7 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * ov_layout_free(NCHW_layout); ov_layout_free(NHWC_layout); #else - if (ctx->options.batch_size > 1) { + if (ctx->ov_option.batch_size > 1) { input_shapes_t input_shapes; status = ie_network_get_input_shapes(ov_model->network, &input_shapes); if (status != OK) { @@ -831,7 +810,7 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * goto err; } for (int i = 0; i < input_shapes.shape_num; i++) - input_shapes.shapes[i].shape.dims[0] = ctx->options.batch_size; + input_shapes.shapes[i].shape.dims[0] = ctx->ov_option.batch_size; status = ie_network_reshape(ov_model->network, input_shapes); ie_network_input_shapes_free(&input_shapes); if (status != OK) { @@ -881,7 +860,7 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * } } - status = ie_core_load_network(ov_model->core, ov_model->network, ctx->options.device_type, &config, &ov_model->exe_network); + status = ie_core_load_network(ov_model->core, ov_model->network, ctx->device, &config, &ov_model->exe_network); if (status != OK) { av_log(ctx, AV_LOG_ERROR, "Failed to load OpenVINO model network\n"); status = ie_core_get_available_devices(ov_model->core, &a_dev); @@ -894,15 +873,15 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * APPEND_STRING(all_dev_names, a_dev.devices[i]) } av_log(ctx, AV_LOG_ERROR,"device %s may not be supported, all available devices are: \"%s\"\n", - ctx->options.device_type, all_dev_names); + ctx->device, all_dev_names); ret = AVERROR(ENODEV); goto err; } #endif // create infer_requests for async execution - if (ctx->options.nireq <= 0) { + if (ctx->nireq <= 0) { // the default value is a rough estimation - ctx->options.nireq = av_cpu_count() / 2 + 1; + ctx->nireq = av_cpu_count() / 2 + 1; } ov_model->request_queue = ff_safe_queue_create(); @@ -911,7 +890,7 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * goto err; } - for (int i = 0; i < ctx->options.nireq; i++) { + for (int i = 0; i < ctx->nireq; i++) { OVRequestItem *item = av_mallocz(sizeof(*item)); if (!item) { ret = AVERROR(ENOMEM); @@ -944,7 +923,7 @@ static int init_model_ov(OVModel *ov_model, const char *input_name, const char * } #endif - item->lltasks = av_malloc_array(ctx->options.batch_size, sizeof(*item->lltasks)); + item->lltasks = av_malloc_array(ctx->ov_option.batch_size, sizeof(*item->lltasks)); if (!item->lltasks) { ret = AVERROR(ENOMEM); goto err; @@ -979,7 +958,6 @@ err: if (input_model_info) ov_preprocess_input_model_info_free(input_model_info); #endif - dnn_free_model_ov(&ov_model->model); return ret; } @@ -993,7 +971,7 @@ static int execute_model_ov(OVRequestItem *request, Queue *inferenceq) LastLevelTaskItem *lltask; int ret = 0; TaskItem *task; - OVContext *ctx; + DnnContext *ctx; OVModel *ov_model; if (ff_queue_size(inferenceq) == 0) { @@ -1009,7 +987,7 @@ static int execute_model_ov(OVRequestItem *request, Queue *inferenceq) lltask = ff_queue_peek_front(inferenceq); task = lltask->task; ov_model = task->model; - ctx = &ov_model->ctx; + ctx = ov_model->ctx; ret = fill_model_input_ov(ov_model, request); if (ret != 0) { @@ -1080,11 +1058,11 @@ err: return ret; } -static int get_input_ov(void *model, DNNData *input, const char *input_name) +static int get_input_ov(DNNModel *model, DNNData *input, const char *input_name) { - OVModel *ov_model = model; - OVContext *ctx = &ov_model->ctx; - int input_resizable = ctx->options.input_resizable; + OVModel *ov_model = (OVModel *)model; + DnnContext *ctx = ov_model->ctx; + int input_resizable = ctx->ov_option.input_resizable; #if HAVE_OPENVINO2 ov_shape_t input_shape = {0}; @@ -1198,7 +1176,7 @@ static int contain_valid_detection_bbox(AVFrame *frame) if (bbox->x < 0 || bbox->w < 0 || bbox->x + bbox->w >= frame->width) { return 0; } - if (bbox->y < 0 || bbox->h < 0 || bbox->y + bbox->h >= frame->width) { + if (bbox->y < 0 || bbox->h < 0 || bbox->y + bbox->h >= frame->height) { return 0; } @@ -1276,7 +1254,7 @@ static int extract_lltask_from_task(DNNFunctionType func_type, TaskItem *task, Q } } -static int get_output_ov(void *model, const char *input_name, int input_width, int input_height, +static int get_output_ov(DNNModel *model, const char *input_name, int input_width, int input_height, const char *output_name, int *output_width, int *output_height) { #if HAVE_OPENVINO2 @@ -1289,8 +1267,8 @@ static int get_output_ov(void *model, const char *input_name, int input_width, i input_shapes_t input_shapes; #endif int ret; - OVModel *ov_model = model; - OVContext *ctx = &ov_model->ctx; + OVModel *ov_model = (OVModel *)model; + DnnContext *ctx = ov_model->ctx; TaskItem task; OVRequestItem *request; DNNExecBaseParams exec_params = { @@ -1301,13 +1279,13 @@ static int get_output_ov(void *model, const char *input_name, int input_width, i .out_frame = NULL, }; - if (ov_model->model->func_type != DFT_PROCESS_FRAME) { + if (ov_model->model.func_type != DFT_PROCESS_FRAME) { av_log(ctx, AV_LOG_ERROR, "Get output dim only when processing frame.\n"); return AVERROR(EINVAL); } #if HAVE_OPENVINO2 - if (ctx->options.input_resizable) { + if (ctx->ov_option.input_resizable) { status = ov_partial_shape_create(4, dims, &partial_shape); if (status != OK) { av_log(ctx, AV_LOG_ERROR, "Failed to create partial shape.\n"); @@ -1338,7 +1316,7 @@ static int get_output_ov(void *model, const char *input_name, int input_width, i if (!ov_model->compiled_model) { #else - if (ctx->options.input_resizable) { + if (ctx->ov_option.input_resizable) { status = ie_network_get_input_shapes(ov_model->network, &input_shapes); input_shapes.shapes->shape.dims[2] = input_height; input_shapes.shapes->shape.dims[3] = input_width; @@ -1363,7 +1341,7 @@ static int get_output_ov(void *model, const char *input_name, int input_width, i goto err; } - ret = extract_lltask_from_task(ov_model->model->func_type, &task, ov_model->lltask_queue, NULL); + ret = extract_lltask_from_task(ov_model->model.func_type, &task, ov_model->lltask_queue, NULL); if (ret != 0) { av_log(ctx, AV_LOG_ERROR, "unable to extract inference from task.\n"); goto err; @@ -1385,11 +1363,10 @@ err: return ret; } -static DNNModel *dnn_load_model_ov(const char *model_filename, DNNFunctionType func_type, const char *options, AVFilterContext *filter_ctx) +static DNNModel *dnn_load_model_ov(DnnContext *ctx, DNNFunctionType func_type, AVFilterContext *filter_ctx) { DNNModel *model = NULL; OVModel *ov_model = NULL; - OVContext *ctx = NULL; #if HAVE_OPENVINO2 ov_core_t* core = NULL; ov_model_t* ovmodel = NULL; @@ -1400,27 +1377,11 @@ static DNNModel *dnn_load_model_ov(const char *model_filename, DNNFunctionType f IEStatusCode status; #endif - model = av_mallocz(sizeof(DNNModel)); - if (!model){ - return NULL; - } - ov_model = av_mallocz(sizeof(OVModel)); - if (!ov_model) { - av_freep(&model); + if (!ov_model) return NULL; - } - model->model = ov_model; - ov_model->model = model; - ov_model->ctx.class = &dnn_openvino_class; - ctx = &ov_model->ctx; - - //parse options - av_opt_set_defaults(ctx); - if (av_opt_set_from_string(ctx, options, NULL, "=", "&") < 0) { - av_log(ctx, AV_LOG_ERROR, "Failed to parse options \"%s\"\n", options); - goto err; - } + ov_model->ctx = ctx; + model = &ov_model->model; #if HAVE_OPENVINO2 status = ov_core_create(&core); @@ -1429,13 +1390,13 @@ static DNNModel *dnn_load_model_ov(const char *model_filename, DNNFunctionType f } ov_model->core = core; - status = ov_core_read_model(core, model_filename, NULL, &ovmodel); + status = ov_core_read_model(core, ctx->model_filename, NULL, &ovmodel); if (status != OK) { ov_version_t ver; status = ov_get_openvino_version(&ver); av_log(NULL, AV_LOG_ERROR, "Failed to read the network from model file %s,\n" "Please check if the model version matches the runtime OpenVINO Version:\n", - model_filename); + ctx->model_filename); if (status == OK) { av_log(NULL, AV_LOG_ERROR, "BuildNumber: %s\n", ver.buildNumber); } @@ -1451,13 +1412,13 @@ static DNNModel *dnn_load_model_ov(const char *model_filename, DNNFunctionType f if (status != OK) goto err; - status = ie_core_read_network(ov_model->core, model_filename, NULL, &ov_model->network); + status = ie_core_read_network(ov_model->core, ctx->model_filename, NULL, &ov_model->network); if (status != OK) { ie_version_t ver; ver = ie_c_api_version(); av_log(ctx, AV_LOG_ERROR, "Failed to read the network from model file %s,\n" "Please check if the model version matches the runtime OpenVINO %s\n", - model_filename, ver.api_version); + ctx->model_filename, ver.api_version); ie_version_free(&ver); goto err; } @@ -1495,7 +1456,6 @@ static DNNModel *dnn_load_model_ov(const char *model_filename, DNNFunctionType f model->get_input = &get_input_ov; model->get_output = &get_output_ov; - model->options = options; model->filter_ctx = filter_ctx; model->func_type = func_type; @@ -1508,8 +1468,8 @@ err: static int dnn_execute_model_ov(const DNNModel *model, DNNExecBaseParams *exec_params) { - OVModel *ov_model = model->model; - OVContext *ctx = &ov_model->ctx; + OVModel *ov_model = (OVModel *)model; + DnnContext *ctx = ov_model->ctx; OVRequestItem *request; TaskItem *task; int ret; @@ -1538,7 +1498,7 @@ static int dnn_execute_model_ov(const DNNModel *model, DNNExecBaseParams *exec_p return AVERROR(ENOMEM); } - ret = ff_dnn_fill_task(task, exec_params, ov_model, ctx->options.async, 1); + ret = ff_dnn_fill_task(task, exec_params, ov_model, ctx->async, 1); if (ret != 0) { av_freep(&task); return ret; @@ -1556,8 +1516,8 @@ static int dnn_execute_model_ov(const DNNModel *model, DNNExecBaseParams *exec_p return ret; } - if (ctx->options.async) { - while (ff_queue_size(ov_model->lltask_queue) >= ctx->options.batch_size) { + if (ctx->async) { + while (ff_queue_size(ov_model->lltask_queue) >= ctx->ov_option.batch_size) { request = ff_safe_queue_pop_front(ov_model->request_queue); if (!request) { av_log(ctx, AV_LOG_ERROR, "unable to get infer request.\n"); @@ -1580,7 +1540,7 @@ static int dnn_execute_model_ov(const DNNModel *model, DNNExecBaseParams *exec_p return AVERROR(ENOSYS); } - if (ctx->options.batch_size > 1) { + if (ctx->ov_option.batch_size > 1) { avpriv_report_missing_feature(ctx, "batch mode for sync execution"); return AVERROR(ENOSYS); } @@ -1596,14 +1556,14 @@ static int dnn_execute_model_ov(const DNNModel *model, DNNExecBaseParams *exec_p static DNNAsyncStatusType dnn_get_result_ov(const DNNModel *model, AVFrame **in, AVFrame **out) { - OVModel *ov_model = model->model; + OVModel *ov_model = (OVModel *)model; return ff_dnn_get_result_common(ov_model->task_queue, in, out); } static int dnn_flush_ov(const DNNModel *model) { - OVModel *ov_model = model->model; - OVContext *ctx = &ov_model->ctx; + OVModel *ov_model = (OVModel *)model; + DnnContext *ctx = ov_model->ctx; OVRequestItem *request; #if HAVE_OPENVINO2 ov_status_e status; @@ -1651,6 +1611,8 @@ static int dnn_flush_ov(const DNNModel *model) } const DNNModule ff_dnn_backend_openvino = { + .clazz = DNN_DEFINE_CLASS(dnn_openvino), + .type = DNN_OV, .load_model = dnn_load_model_ov, .execute_model = dnn_execute_model_ov, .get_result = dnn_get_result_ov, diff --git a/libavfilter/dnn/dnn_backend_tf.c b/libavfilter/dnn/dnn_backend_tf.c index 27c5178bb..6ca7fb691 100644 --- a/libavfilter/dnn/dnn_backend_tf.c +++ b/libavfilter/dnn/dnn_backend_tf.c @@ -27,28 +27,17 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/cpu.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/defs.h" -#include "../internal.h" #include "dnn_io_proc.h" #include "dnn_backend_common.h" #include "safe_queue.h" #include -typedef struct TFOptions{ - char *sess_config; - uint8_t async; - uint32_t nireq; -} TFOptions; - -typedef struct TFContext { - const AVClass *class; - TFOptions options; -} TFContext; - -typedef struct TFModel{ - TFContext ctx; - DNNModel *model; +typedef struct TFModel { + DNNModel model; + DnnContext *ctx; TF_Graph *graph; TF_Session *session; TF_Status *status; @@ -75,15 +64,13 @@ typedef struct TFRequestItem { DNNAsyncExecModule exec_module; } TFRequestItem; -#define OFFSET(x) offsetof(TFContext, x) +#define OFFSET(x) offsetof(TFOptions, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM static const AVOption dnn_tensorflow_options[] = { - { "sess_config", "config for SessionOptions", OFFSET(options.sess_config), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS }, - DNN_BACKEND_COMMON_OPTIONS + { "sess_config", "config for SessionOptions", OFFSET(sess_config), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS }, { NULL } }; -AVFILTER_DEFINE_CLASS(dnn_tensorflow); static int execute_model_tf(TFRequestItem *request, Queue *lltask_queue); static void infer_completion_callback(void *args); @@ -159,7 +146,7 @@ static int tf_start_inference(void *args) TFModel *tf_model = task->model; if (!request) { - av_log(&tf_model->ctx, AV_LOG_ERROR, "TFRequestItem is NULL\n"); + av_log(tf_model->ctx, AV_LOG_ERROR, "TFRequestItem is NULL\n"); return AVERROR(EINVAL); } @@ -169,7 +156,7 @@ static int tf_start_inference(void *args) task->nb_output, NULL, 0, NULL, request->status); if (TF_GetCode(request->status) != TF_OK) { - av_log(&tf_model->ctx, AV_LOG_ERROR, "%s", TF_Message(request->status)); + av_log(tf_model->ctx, AV_LOG_ERROR, "%s", TF_Message(request->status)); return DNN_GENERIC_ERROR; } return 0; @@ -197,7 +184,7 @@ static inline void destroy_request_item(TFRequestItem **arg) { static int extract_lltask_from_task(TaskItem *task, Queue *lltask_queue) { TFModel *tf_model = task->model; - TFContext *ctx = &tf_model->ctx; + DnnContext *ctx = tf_model->ctx; LastLevelTaskItem *lltask = av_malloc(sizeof(*lltask)); if (!lltask) { av_log(ctx, AV_LOG_ERROR, "Unable to allocate space for LastLevelTaskItem\n"); @@ -274,10 +261,10 @@ static TF_Tensor *allocate_input_tensor(const DNNData *input) input_dims[1] * input_dims[2] * input_dims[3] * size); } -static int get_input_tf(void *model, DNNData *input, const char *input_name) +static int get_input_tf(DNNModel *model, DNNData *input, const char *input_name) { - TFModel *tf_model = model; - TFContext *ctx = &tf_model->ctx; + TFModel *tf_model = (TFModel *)model; + DnnContext *ctx = tf_model->ctx; TF_Status *status; TF_DataType dt; int64_t dims[4]; @@ -322,12 +309,12 @@ static int get_input_tf(void *model, DNNData *input, const char *input_name) return 0; } -static int get_output_tf(void *model, const char *input_name, int input_width, int input_height, +static int get_output_tf(DNNModel *model, const char *input_name, int input_width, int input_height, const char *output_name, int *output_width, int *output_height) { int ret; - TFModel *tf_model = model; - TFContext *ctx = &tf_model->ctx; + TFModel *tf_model = (TFModel *)model; + DnnContext *ctx = tf_model->ctx; TaskItem task; TFRequestItem *request; DNNExecBaseParams exec_params = { @@ -398,7 +385,7 @@ static int hex_to_data(uint8_t *data, const char *p) static int load_tf_model(TFModel *tf_model, const char *model_filename) { - TFContext *ctx = &tf_model->ctx; + DnnContext *ctx = tf_model->ctx; TF_Buffer *graph_def; TF_ImportGraphDefOptions *graph_opts; TF_SessionOptions *sess_opts; @@ -407,7 +394,7 @@ static int load_tf_model(TFModel *tf_model, const char *model_filename) int sess_config_length = 0; // prepare the sess config data - if (tf_model->ctx.options.sess_config != NULL) { + if (ctx->tf_option.sess_config != NULL) { const char *config; /* tf_model->ctx.options.sess_config is hex to present the serialized proto @@ -415,11 +402,11 @@ static int load_tf_model(TFModel *tf_model, const char *model_filename) proto in a python script, tools/python/tf_sess_config.py is a script example to generate the configs of sess_config. */ - if (strncmp(tf_model->ctx.options.sess_config, "0x", 2) != 0) { + if (strncmp(ctx->tf_option.sess_config, "0x", 2) != 0) { av_log(ctx, AV_LOG_ERROR, "sess_config should start with '0x'\n"); return AVERROR(EINVAL); } - config = tf_model->ctx.options.sess_config + 2; + config = ctx->tf_option.sess_config + 2; sess_config_length = hex_to_data(NULL, config); sess_config = av_mallocz(sess_config_length + AV_INPUT_BUFFER_PADDING_SIZE); @@ -460,7 +447,7 @@ static int load_tf_model(TFModel *tf_model, const char *model_filename) if (TF_GetCode(tf_model->status) != TF_OK) { TF_DeleteSessionOptions(sess_opts); av_log(ctx, AV_LOG_ERROR, "Failed to set config for sess options with %s\n", - tf_model->ctx.options.sess_config); + ctx->tf_option.sess_config); return DNN_GENERIC_ERROR; } } @@ -495,78 +482,62 @@ static void dnn_free_model_tf(DNNModel **model) { TFModel *tf_model; - if (*model){ - tf_model = (*model)->model; - while (ff_safe_queue_size(tf_model->request_queue) != 0) { - TFRequestItem *item = ff_safe_queue_pop_front(tf_model->request_queue); - destroy_request_item(&item); - } - ff_safe_queue_destroy(tf_model->request_queue); + if (!model || !*model) + return; - while (ff_queue_size(tf_model->lltask_queue) != 0) { - LastLevelTaskItem *item = ff_queue_pop_front(tf_model->lltask_queue); - av_freep(&item); - } - ff_queue_destroy(tf_model->lltask_queue); - - while (ff_queue_size(tf_model->task_queue) != 0) { - TaskItem *item = ff_queue_pop_front(tf_model->task_queue); - av_frame_free(&item->in_frame); - av_frame_free(&item->out_frame); - av_freep(&item); - } - ff_queue_destroy(tf_model->task_queue); - - if (tf_model->graph){ - TF_DeleteGraph(tf_model->graph); - } - if (tf_model->session){ - TF_CloseSession(tf_model->session, tf_model->status); - TF_DeleteSession(tf_model->session, tf_model->status); - } - if (tf_model->status){ - TF_DeleteStatus(tf_model->status); - } - av_freep(&tf_model); - av_freep(model); + tf_model = (TFModel *)(*model); + while (ff_safe_queue_size(tf_model->request_queue) != 0) { + TFRequestItem *item = ff_safe_queue_pop_front(tf_model->request_queue); + destroy_request_item(&item); } + ff_safe_queue_destroy(tf_model->request_queue); + + while (ff_queue_size(tf_model->lltask_queue) != 0) { + LastLevelTaskItem *item = ff_queue_pop_front(tf_model->lltask_queue); + av_freep(&item); + } + ff_queue_destroy(tf_model->lltask_queue); + + while (ff_queue_size(tf_model->task_queue) != 0) { + TaskItem *item = ff_queue_pop_front(tf_model->task_queue); + av_frame_free(&item->in_frame); + av_frame_free(&item->out_frame); + av_freep(&item); + } + ff_queue_destroy(tf_model->task_queue); + + if (tf_model->graph){ + TF_DeleteGraph(tf_model->graph); + } + if (tf_model->session){ + TF_CloseSession(tf_model->session, tf_model->status); + TF_DeleteSession(tf_model->session, tf_model->status); + } + if (tf_model->status){ + TF_DeleteStatus(tf_model->status); + } + av_freep(&tf_model); + *model = NULL; } -static DNNModel *dnn_load_model_tf(const char *model_filename, DNNFunctionType func_type, const char *options, AVFilterContext *filter_ctx) +static DNNModel *dnn_load_model_tf(DnnContext *ctx, DNNFunctionType func_type, AVFilterContext *filter_ctx) { DNNModel *model = NULL; TFModel *tf_model = NULL; - TFContext *ctx = NULL; - - model = av_mallocz(sizeof(DNNModel)); - if (!model){ - return NULL; - } tf_model = av_mallocz(sizeof(TFModel)); - if (!tf_model){ - av_freep(&model); + if (!tf_model) return NULL; - } - model->model = tf_model; - tf_model->model = model; - ctx = &tf_model->ctx; - ctx->class = &dnn_tensorflow_class; + model = &tf_model->model; + tf_model->ctx = ctx; - //parse options - av_opt_set_defaults(ctx); - if (av_opt_set_from_string(ctx, options, NULL, "=", "&") < 0) { - av_log(ctx, AV_LOG_ERROR, "Failed to parse options \"%s\"\n", options); + if (load_tf_model(tf_model, ctx->model_filename) != 0){ + av_log(ctx, AV_LOG_ERROR, "Failed to load TensorFlow model: \"%s\"\n", ctx->model_filename); goto err; } - if (load_tf_model(tf_model, model_filename) != 0){ - av_log(ctx, AV_LOG_ERROR, "Failed to load TensorFlow model: \"%s\"\n", model_filename); - goto err; - } - - if (ctx->options.nireq <= 0) { - ctx->options.nireq = av_cpu_count() / 2 + 1; + if (ctx->nireq <= 0) { + ctx->nireq = av_cpu_count() / 2 + 1; } #if !HAVE_PTHREAD_CANCEL @@ -581,7 +552,7 @@ static DNNModel *dnn_load_model_tf(const char *model_filename, DNNFunctionType f goto err; } - for (int i = 0; i < ctx->options.nireq; i++) { + for (int i = 0; i < ctx->nireq; i++) { TFRequestItem *item = av_mallocz(sizeof(*item)); if (!item) { goto err; @@ -616,7 +587,6 @@ static DNNModel *dnn_load_model_tf(const char *model_filename, DNNFunctionType f model->get_input = &get_input_tf; model->get_output = &get_output_tf; - model->options = options; model->filter_ctx = filter_ctx; model->func_type = func_type; @@ -631,7 +601,7 @@ static int fill_model_input_tf(TFModel *tf_model, TFRequestItem *request) { LastLevelTaskItem *lltask; TaskItem *task; TFInferRequest *infer_request = NULL; - TFContext *ctx = &tf_model->ctx; + DnnContext *ctx = tf_model->ctx; int ret = 0; lltask = ff_queue_pop_front(tf_model->lltask_queue); @@ -639,7 +609,7 @@ static int fill_model_input_tf(TFModel *tf_model, TFRequestItem *request) { task = lltask->task; request->lltask = lltask; - ret = get_input_tf(tf_model, &input, task->input_name); + ret = get_input_tf(&tf_model->model, &input, task->input_name); if (ret != 0) { goto err; } @@ -671,11 +641,11 @@ static int fill_model_input_tf(TFModel *tf_model, TFRequestItem *request) { } input.data = (float *)TF_TensorData(infer_request->input_tensor); - switch (tf_model->model->func_type) { + switch (tf_model->model.func_type) { case DFT_PROCESS_FRAME: if (task->do_ioproc) { - if (tf_model->model->frame_pre_proc != NULL) { - tf_model->model->frame_pre_proc(task->in_frame, &input, tf_model->model->filter_ctx); + if (tf_model->model.frame_pre_proc != NULL) { + tf_model->model.frame_pre_proc(task->in_frame, &input, tf_model->model.filter_ctx); } else { ff_proc_from_frame_to_dnn(task->in_frame, &input, ctx); } @@ -685,7 +655,7 @@ static int fill_model_input_tf(TFModel *tf_model, TFRequestItem *request) { ff_frame_to_dnn_detect(task->in_frame, &input, ctx); break; default: - avpriv_report_missing_feature(ctx, "model function type %d", tf_model->model->func_type); + avpriv_report_missing_feature(ctx, "model function type %d", tf_model->model.func_type); break; } @@ -727,7 +697,7 @@ static void infer_completion_callback(void *args) { DNNData *outputs; TFInferRequest *infer_request = request->infer_request; TFModel *tf_model = task->model; - TFContext *ctx = &tf_model->ctx; + DnnContext *ctx = tf_model->ctx; outputs = av_calloc(task->nb_output, sizeof(*outputs)); if (!outputs) { @@ -745,12 +715,12 @@ static void infer_completion_callback(void *args) { outputs[i].data = TF_TensorData(infer_request->output_tensors[i]); outputs[i].dt = (DNNDataType)TF_TensorType(infer_request->output_tensors[i]); } - switch (tf_model->model->func_type) { + switch (tf_model->model.func_type) { case DFT_PROCESS_FRAME: //it only support 1 output if it's frame in & frame out if (task->do_ioproc) { - if (tf_model->model->frame_post_proc != NULL) { - tf_model->model->frame_post_proc(task->out_frame, outputs, tf_model->model->filter_ctx); + if (tf_model->model.frame_post_proc != NULL) { + tf_model->model.frame_post_proc(task->out_frame, outputs, tf_model->model.filter_ctx); } else { ff_proc_from_dnn_to_frame(task->out_frame, outputs, ctx); } @@ -762,11 +732,11 @@ static void infer_completion_callback(void *args) { } break; case DFT_ANALYTICS_DETECT: - if (!tf_model->model->detect_post_proc) { + if (!tf_model->model.detect_post_proc) { av_log(ctx, AV_LOG_ERROR, "Detect filter needs provide post proc\n"); return; } - tf_model->model->detect_post_proc(task->in_frame, outputs, task->nb_output, tf_model->model->filter_ctx); + tf_model->model.detect_post_proc(task->in_frame, outputs, task->nb_output, tf_model->model.filter_ctx); break; default: av_log(ctx, AV_LOG_ERROR, "Tensorflow backend does not support this kind of dnn filter now\n"); @@ -786,7 +756,7 @@ err: static int execute_model_tf(TFRequestItem *request, Queue *lltask_queue) { TFModel *tf_model; - TFContext *ctx; + DnnContext *ctx; LastLevelTaskItem *lltask; TaskItem *task; int ret = 0; @@ -799,7 +769,7 @@ static int execute_model_tf(TFRequestItem *request, Queue *lltask_queue) lltask = ff_queue_peek_front(lltask_queue); task = lltask->task; tf_model = task->model; - ctx = &tf_model->ctx; + ctx = tf_model->ctx; ret = fill_model_input_tf(tf_model, request); if (ret != 0) { @@ -825,14 +795,14 @@ err: if (ff_safe_queue_push_back(tf_model->request_queue, request) < 0) { destroy_request_item(&request); } - dnn_free_model_tf(&tf_model->model); + return ret; } static int dnn_execute_model_tf(const DNNModel *model, DNNExecBaseParams *exec_params) { - TFModel *tf_model = model->model; - TFContext *ctx = &tf_model->ctx; + TFModel *tf_model = (TFModel *)model; + DnnContext *ctx = tf_model->ctx; TaskItem *task; TFRequestItem *request; int ret = 0; @@ -848,7 +818,7 @@ static int dnn_execute_model_tf(const DNNModel *model, DNNExecBaseParams *exec_p return AVERROR(ENOMEM); } - ret = ff_dnn_fill_task(task, exec_params, tf_model, ctx->options.async, 1); + ret = ff_dnn_fill_task(task, exec_params, tf_model, ctx->async, 1); if (ret != 0) { av_log(ctx, AV_LOG_ERROR, "Fill task with invalid parameter(s).\n"); av_freep(&task); @@ -879,14 +849,14 @@ static int dnn_execute_model_tf(const DNNModel *model, DNNExecBaseParams *exec_p static DNNAsyncStatusType dnn_get_result_tf(const DNNModel *model, AVFrame **in, AVFrame **out) { - TFModel *tf_model = model->model; + TFModel *tf_model = (TFModel *)model; return ff_dnn_get_result_common(tf_model->task_queue, in, out); } static int dnn_flush_tf(const DNNModel *model) { - TFModel *tf_model = model->model; - TFContext *ctx = &tf_model->ctx; + TFModel *tf_model = (TFModel *)model; + DnnContext *ctx = tf_model->ctx; TFRequestItem *request; int ret; @@ -914,6 +884,8 @@ static int dnn_flush_tf(const DNNModel *model) } const DNNModule ff_dnn_backend_tf = { + .clazz = DNN_DEFINE_CLASS(dnn_tensorflow), + .type = DNN_TF, .load_model = dnn_load_model_tf, .execute_model = dnn_execute_model_tf, .get_result = dnn_get_result_tf, diff --git a/libavfilter/dnn/dnn_backend_torch.cpp b/libavfilter/dnn/dnn_backend_torch.cpp index fa9a2e6d9..2e4326d9d 100644 --- a/libavfilter/dnn/dnn_backend_torch.cpp +++ b/libavfilter/dnn/dnn_backend_torch.cpp @@ -27,27 +27,17 @@ #include extern "C" { -#include "../internal.h" #include "dnn_io_proc.h" #include "dnn_backend_common.h" #include "libavutil/opt.h" +#include "libavutil/mem.h" #include "queue.h" #include "safe_queue.h" } -typedef struct THOptions{ - char *device_name; - int optimize; -} THOptions; - -typedef struct THContext { - const AVClass *c_class; - THOptions options; -} THContext; - typedef struct THModel { - THContext ctx; - DNNModel *model; + DNNModel model; + DnnContext *ctx; torch::jit::Module *jit_model; SafeQueue *request_queue; Queue *task_queue; @@ -66,20 +56,17 @@ typedef struct THRequestItem { } THRequestItem; -#define OFFSET(x) offsetof(THContext, x) +#define OFFSET(x) offsetof(THOptions, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM static const AVOption dnn_th_options[] = { - { "device", "device to run model", OFFSET(options.device_name), AV_OPT_TYPE_STRING, { .str = "cpu" }, 0, 0, FLAGS }, - { "optimize", "turn on graph executor optimization", OFFSET(options.optimize), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS}, + { "optimize", "turn on graph executor optimization", OFFSET(optimize), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS}, { NULL } }; -AVFILTER_DEFINE_CLASS(dnn_th); - static int extract_lltask_from_task(TaskItem *task, Queue *lltask_queue) { THModel *th_model = (THModel *)task->model; - THContext *ctx = &th_model->ctx; + DnnContext *ctx = th_model->ctx; LastLevelTaskItem *lltask = (LastLevelTaskItem *)av_malloc(sizeof(*lltask)); if (!lltask) { av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory for LastLevelTaskItem\n"); @@ -131,7 +118,7 @@ static void dnn_free_model_th(DNNModel **model) if (!model || !*model) return; - th_model = (THModel *) (*model)->model; + 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); @@ -152,12 +139,11 @@ static void dnn_free_model_th(DNNModel **model) } ff_queue_destroy(th_model->task_queue); delete th_model->jit_model; - av_opt_free(&th_model->ctx); av_freep(&th_model); - av_freep(model); + *model = NULL; } -static int get_input_th(void *model, DNNData *input, const char *input_name) +static int get_input_th(DNNModel *model, DNNData *input, const char *input_name) { input->dt = DNN_FLOAT; input->order = DCO_RGB; @@ -180,7 +166,7 @@ static int fill_model_input_th(THModel *th_model, THRequestItem *request) TaskItem *task = NULL; THInferRequest *infer_request = NULL; DNNData input = { 0 }; - THContext *ctx = &th_model->ctx; + DnnContext *ctx = th_model->ctx; int ret, width_idx, height_idx, channel_idx; lltask = (LastLevelTaskItem *)ff_queue_pop_front(th_model->lltask_queue); @@ -192,7 +178,7 @@ static int fill_model_input_th(THModel *th_model, THRequestItem *request) task = lltask->task; infer_request = request->infer_request; - ret = get_input_th(th_model, &input, NULL); + ret = get_input_th(&th_model->model, &input, NULL); if ( ret != 0) { goto err; } @@ -208,19 +194,19 @@ static int fill_model_input_th(THModel *th_model, THRequestItem *request) infer_request->input_tensor = new torch::Tensor(); infer_request->output = new torch::Tensor(); - switch (th_model->model->func_type) { + switch (th_model->model.func_type) { case DFT_PROCESS_FRAME: input.scale = 255; if (task->do_ioproc) { - if (th_model->model->frame_pre_proc != NULL) { - th_model->model->frame_pre_proc(task->in_frame, &input, th_model->model->filter_ctx); + if (th_model->model.frame_pre_proc != NULL) { + th_model->model.frame_pre_proc(task->in_frame, &input, th_model->model.filter_ctx); } else { ff_proc_from_frame_to_dnn(task->in_frame, &input, ctx); } } break; default: - avpriv_report_missing_feature(NULL, "model function type %d", th_model->model->func_type); + avpriv_report_missing_feature(NULL, "model function type %d", th_model->model.func_type); break; } *infer_request->input_tensor = torch::from_blob(input.data, @@ -240,7 +226,7 @@ static int th_start_inference(void *args) LastLevelTaskItem *lltask = NULL; TaskItem *task = NULL; THModel *th_model = NULL; - THContext *ctx = NULL; + DnnContext *ctx = NULL; std::vector inputs; torch::NoGradGuard no_grad; @@ -252,9 +238,9 @@ static int th_start_inference(void *args) lltask = request->lltask; task = lltask->task; th_model = (THModel *)task->model; - ctx = &th_model->ctx; + ctx = th_model->ctx; - if (ctx->options.optimize) + if (ctx->torch_option.optimize) torch::jit::setGraphExecutorOptimize(true); else torch::jit::setGraphExecutorOptimize(false); @@ -263,6 +249,10 @@ static int th_start_inference(void *args) av_log(ctx, AV_LOG_ERROR, "input or output tensor is NULL\n"); return DNN_GENERIC_ERROR; } + // Transfer tensor to the same device as model + c10::Device device = (*th_model->jit_model->parameters().begin()).device(); + if (infer_request->input_tensor->device() != device) + *infer_request->input_tensor = infer_request->input_tensor->to(device); inputs.push_back(*infer_request->input_tensor); *infer_request->output = th_model->jit_model->forward(inputs).toTensor(); @@ -291,19 +281,22 @@ static void infer_completion_callback(void *args) { outputs.dims[2] = sizes.at(2); // H outputs.dims[3] = sizes.at(3); // W } else { - avpriv_report_missing_feature(&th_model->ctx, "Support of this kind of model"); + avpriv_report_missing_feature(th_model->ctx, "Support of this kind of model"); goto err; } - switch (th_model->model->func_type) { + switch (th_model->model.func_type) { case DFT_PROCESS_FRAME: if (task->do_ioproc) { + // Post process can only deal with CPU memory. + if (output->device() != torch::kCPU) + *output = output->to(torch::kCPU); outputs.scale = 255; outputs.data = output->data_ptr(); - if (th_model->model->frame_post_proc != NULL) { - th_model->model->frame_post_proc(task->out_frame, &outputs, th_model->model->filter_ctx); + if (th_model->model.frame_post_proc != NULL) { + th_model->model.frame_post_proc(task->out_frame, &outputs, th_model->model.filter_ctx); } else { - ff_proc_from_dnn_to_frame(task->out_frame, &outputs, &th_model->ctx); + ff_proc_from_dnn_to_frame(task->out_frame, &outputs, th_model->ctx); } } else { task->out_frame->width = outputs.dims[dnn_get_width_idx_by_layout(outputs.layout)]; @@ -311,7 +304,7 @@ static void infer_completion_callback(void *args) { } break; default: - avpriv_report_missing_feature(&th_model->ctx, "model function type %d", th_model->model->func_type); + avpriv_report_missing_feature(th_model->ctx, "model function type %d", th_model->model.func_type); goto err; } task->inference_done++; @@ -321,7 +314,7 @@ err: if (ff_safe_queue_push_back(th_model->request_queue, request) < 0) { destroy_request_item(&request); - av_log(&th_model->ctx, AV_LOG_ERROR, "Unable to push back request_queue when failed to start inference.\n"); + av_log(th_model->ctx, AV_LOG_ERROR, "Unable to push back request_queue when failed to start inference.\n"); } } @@ -351,7 +344,7 @@ static int execute_model_th(THRequestItem *request, Queue *lltask_queue) goto err; } if (task->async) { - avpriv_report_missing_feature(&th_model->ctx, "LibTorch async"); + avpriv_report_missing_feature(th_model->ctx, "LibTorch async"); } else { ret = th_start_inference((void *)(request)); if (ret != 0) { @@ -369,12 +362,12 @@ err: return ret; } -static int get_output_th(void *model, const char *input_name, int input_width, int input_height, +static int get_output_th(DNNModel *model, const char *input_name, int input_width, int input_height, const char *output_name, int *output_width, int *output_height) { int ret = 0; THModel *th_model = (THModel*) model; - THContext *ctx = &th_model->ctx; + DnnContext *ctx = th_model->ctx; TaskItem task = { 0 }; THRequestItem *request = NULL; DNNExecBaseParams exec_params = { @@ -423,43 +416,35 @@ static THInferRequest *th_create_inference_request(void) return request; } -static DNNModel *dnn_load_model_th(const char *model_filename, DNNFunctionType func_type, const char *options, AVFilterContext *filter_ctx) +static DNNModel *dnn_load_model_th(DnnContext *ctx, DNNFunctionType func_type, AVFilterContext *filter_ctx) { DNNModel *model = NULL; THModel *th_model = NULL; THRequestItem *item = NULL; - THContext *ctx; - - model = (DNNModel *)av_mallocz(sizeof(DNNModel)); - if (!model) { - return NULL; - } + const char *device_name = ctx->device ? ctx->device : "cpu"; th_model = (THModel *)av_mallocz(sizeof(THModel)); - if (!th_model) { - av_freep(&model); + if (!th_model) return NULL; - } - th_model->model = model; - model->model = th_model; - th_model->ctx.c_class = &dnn_th_class; - ctx = &th_model->ctx; - //parse options - av_opt_set_defaults(ctx); - if (av_opt_set_from_string(ctx, options, NULL, "=", "&") < 0) { - av_log(ctx, AV_LOG_ERROR, "Failed to parse options \"%s\"\n", options); - return NULL; - } + model = &th_model->model; + th_model->ctx = ctx; - c10::Device device = c10::Device(ctx->options.device_name); - if (!device.is_cpu()) { - av_log(ctx, AV_LOG_ERROR, "Not supported device:\"%s\"\n", ctx->options.device_name); + c10::Device device = c10::Device(device_name); + if (device.is_xpu()) { + if (!at::hasXPU()) { + av_log(ctx, AV_LOG_ERROR, "No XPU device found\n"); + goto fail; + } + at::detail::getXPUHooks().initXPU(); + } else if (!device.is_cpu()) { + av_log(ctx, AV_LOG_ERROR, "Not supported device:\"%s\"\n", device_name); goto fail; } try { th_model->jit_model = new torch::jit::Module; - (*th_model->jit_model) = torch::jit::load(model_filename); + (*th_model->jit_model) = torch::jit::load(ctx->model_filename); + th_model->jit_model->to(device); } catch (const c10::Error& e) { av_log(ctx, AV_LOG_ERROR, "Failed to load torch model\n"); goto fail; @@ -501,7 +486,6 @@ static DNNModel *dnn_load_model_th(const char *model_filename, DNNFunctionType f model->get_input = &get_input_th; model->get_output = &get_output_th; - model->options = NULL; model->filter_ctx = filter_ctx; model->func_type = func_type; return model; @@ -517,8 +501,8 @@ fail: static int dnn_execute_model_th(const DNNModel *model, DNNExecBaseParams *exec_params) { - THModel *th_model = (THModel *)model->model; - THContext *ctx = &th_model->ctx; + THModel *th_model = (THModel *)model; + DnnContext *ctx = th_model->ctx; TaskItem *task; THRequestItem *request; int ret = 0; @@ -566,13 +550,13 @@ static int dnn_execute_model_th(const DNNModel *model, DNNExecBaseParams *exec_p static DNNAsyncStatusType dnn_get_result_th(const DNNModel *model, AVFrame **in, AVFrame **out) { - THModel *th_model = (THModel *)model->model; + THModel *th_model = (THModel *)model; return ff_dnn_get_result_common(th_model->task_queue, in, out); } static int dnn_flush_th(const DNNModel *model) { - THModel *th_model = (THModel *)model->model; + THModel *th_model = (THModel *)model; THRequestItem *request; if (ff_queue_size(th_model->lltask_queue) == 0) @@ -581,7 +565,7 @@ static int dnn_flush_th(const DNNModel *model) request = (THRequestItem *)ff_safe_queue_pop_front(th_model->request_queue); if (!request) { - av_log(&th_model->ctx, AV_LOG_ERROR, "unable to get infer request.\n"); + av_log(th_model->ctx, AV_LOG_ERROR, "unable to get infer request.\n"); return AVERROR(EINVAL); } @@ -589,6 +573,8 @@ static int dnn_flush_th(const DNNModel *model) } extern const DNNModule ff_dnn_backend_torch = { + .clazz = DNN_DEFINE_CLASS(dnn_th), + .type = DNN_TH, .load_model = dnn_load_model_th, .execute_model = dnn_execute_model_th, .get_result = dnn_get_result_th, diff --git a/libavfilter/dnn/dnn_interface.c b/libavfilter/dnn/dnn_interface.c index b9f71aea5..bb477348d 100644 --- a/libavfilter/dnn/dnn_interface.c +++ b/libavfilter/dnn/dnn_interface.c @@ -24,31 +24,117 @@ */ #include "../dnn_interface.h" +#include "libavutil/avassert.h" #include "libavutil/mem.h" +#include "libavutil/opt.h" + +#include "libavfilter/filters.h" extern const DNNModule ff_dnn_backend_openvino; extern const DNNModule ff_dnn_backend_tf; extern const DNNModule ff_dnn_backend_torch; +#define OFFSET(x) offsetof(DnnContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM +static const AVOption dnn_base_options[] = { + {"model", "path to model file", + OFFSET(model_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, + {"input", "input name of the model", + OFFSET(model_inputname), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, + {"output", "output name of the model", + OFFSET(model_outputnames_string), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, + {"backend_configs", "backend configs (deprecated)", + OFFSET(backend_options), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS | AV_OPT_FLAG_DEPRECATED}, + {"options", "backend configs (deprecated)", + OFFSET(backend_options), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS | AV_OPT_FLAG_DEPRECATED}, + {"nireq", "number of request", + OFFSET(nireq), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS}, + {"async", "use DNN async inference", + OFFSET(async), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS}, + {"device", "device to run model", + OFFSET(device), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, + {NULL} +}; + +AVFILTER_DEFINE_CLASS(dnn_base); + +typedef struct DnnBackendInfo { + const size_t offset; + union { + const AVClass *class; + const DNNModule *module; + }; +} DnnBackendInfo; + +static const DnnBackendInfo dnn_backend_info_list[] = { + {0, .class = &dnn_base_class}, + // Must keep the same order as in DNNOptions, so offset value in incremental order +#if CONFIG_LIBTENSORFLOW + {offsetof(DnnContext, tf_option), .module = &ff_dnn_backend_tf}, +#endif +#if CONFIG_LIBOPENVINO + {offsetof(DnnContext, ov_option), .module = &ff_dnn_backend_openvino}, +#endif +#if CONFIG_LIBTORCH + {offsetof(DnnContext, torch_option), .module = &ff_dnn_backend_torch}, +#endif +}; + const DNNModule *ff_get_dnn_module(DNNBackendType backend_type, void *log_ctx) { - switch(backend_type){ - #if (CONFIG_LIBTENSORFLOW == 1) - case DNN_TF: - return &ff_dnn_backend_tf; - #endif - #if (CONFIG_LIBOPENVINO == 1) - case DNN_OV: - return &ff_dnn_backend_openvino; - #endif - #if (CONFIG_LIBTORCH == 1) - case DNN_TH: - return &ff_dnn_backend_torch; - #endif - default: - av_log(log_ctx, AV_LOG_ERROR, - "Module backend_type %d is not supported or enabled.\n", - backend_type); - return NULL; + for (int i = 1; i < FF_ARRAY_ELEMS(dnn_backend_info_list); i++) { + if (dnn_backend_info_list[i].module->type == backend_type) + return dnn_backend_info_list[i].module; + } + + av_log(log_ctx, AV_LOG_ERROR, + "Module backend_type %d is not supported or enabled.\n", + backend_type); + return NULL; +} + +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; } } + +void *ff_dnn_child_next(DnnContext *obj, void *prev) { + size_t pre_offset; + + if (!prev) { + av_assert0(obj->clazz); + return obj; + } + + pre_offset = (char *)prev - (char *)obj; + for (int i = 0; i < FF_ARRAY_ELEMS(dnn_backend_info_list) - 1; i++) { + if (dnn_backend_info_list[i].offset == pre_offset) { + const AVClass **ptr = (const AVClass **) ((char *) obj + dnn_backend_info_list[i + 1].offset); + av_assert0(*ptr); + return ptr; + } + } + + return NULL; +} + +const AVClass *ff_dnn_child_class_iterate_with_mask(void **iter, uint32_t backend_mask) +{ + for (uintptr_t i = (uintptr_t)*iter; i < FF_ARRAY_ELEMS(dnn_backend_info_list); i++) { + if (i > 0) { + const DNNModule *module = dnn_backend_info_list[i].module; + + if (!(module->type & backend_mask)) + continue; + } + + *iter = (void *)(i + 1); + return dnn_backend_info_list[i].class; + } + + return NULL; +} + diff --git a/libavfilter/dnn/dnn_io_proc.c b/libavfilter/dnn/dnn_io_proc.c index e5d6edb30..826110dab 100644 --- a/libavfilter/dnn/dnn_io_proc.c +++ b/libavfilter/dnn/dnn_io_proc.c @@ -20,6 +20,7 @@ #include "dnn_io_proc.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libswscale/swscale.h" #include "libavutil/avassert.h" #include "libavutil/detection_bbox.h" @@ -350,6 +351,7 @@ int ff_frame_to_dnn_classify(AVFrame *frame, DNNData *input, uint32_t bbox_index const AVDetectionBBoxHeader *header; const AVDetectionBBox *bbox; AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DETECTION_BBOXES); + int max_step[4] = { 0 }; av_assert0(sd); /* (scale != 1 and scale != 0) or mean != 0 */ @@ -405,8 +407,9 @@ int ff_frame_to_dnn_classify(AVFrame *frame, DNNData *input, uint32_t bbox_index offsety[1] = offsety[2] = AV_CEIL_RSHIFT(top, desc->log2_chroma_h); offsety[0] = offsety[3] = top; + av_image_fill_max_pixsteps(max_step, NULL, desc); for (int k = 0; frame->data[k]; k++) - bbox_data[k] = frame->data[k] + offsety[k] * frame->linesize[k] + offsetx[k]; + bbox_data[k] = frame->data[k] + offsety[k] * frame->linesize[k] + offsetx[k] * max_step[k]; sws_scale(sws_ctx, (const uint8_t *const *)&bbox_data, frame->linesize, 0, height, diff --git a/libavfilter/dnn_filter_common.c b/libavfilter/dnn_filter_common.c index 7d194c9ad..6b9c6f8d7 100644 --- a/libavfilter/dnn_filter_common.c +++ b/libavfilter/dnn_filter_common.c @@ -18,6 +18,8 @@ #include "dnn_filter_common.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" #define MAX_SUPPORTED_OUTPUTS_NB 4 @@ -51,6 +53,23 @@ static char **separate_output_names(const char *expr, const char *val_sep, int * return parsed_vals; } +typedef struct DnnFilterBase { + const AVClass *class; + DnnContext dnnctx; +} DnnFilterBase; + +int ff_dnn_filter_init_child_class(AVFilterContext *filter) { + DnnFilterBase *base = filter->priv; + ff_dnn_init_child_class(&base->dnnctx); + return 0; +} + +void *ff_dnn_filter_child_next(void *obj, void *prev) +{ + DnnFilterBase *base = obj; + return ff_dnn_child_next(&base->dnnctx, prev); +} + int ff_dnn_init(DnnContext *ctx, DNNFunctionType func_type, AVFilterContext *filter_ctx) { DNNBackendType backend = ctx->backend_type; @@ -90,7 +109,25 @@ int ff_dnn_init(DnnContext *ctx, DNNFunctionType func_type, AVFilterContext *fil return AVERROR(EINVAL); } - ctx->model = (ctx->dnn_module->load_model)(ctx->model_filename, func_type, ctx->backend_options, filter_ctx); + if (ctx->backend_options) { + void *child = NULL; + + av_log(filter_ctx, AV_LOG_WARNING, + "backend_configs is deprecated, please set backend options directly\n"); + while (child = ff_dnn_child_next(ctx, child)) { + if (*(const AVClass **)child == &ctx->dnn_module->clazz) { + int ret = av_opt_set_from_string(child, ctx->backend_options, + NULL, "=", "&"); + if (ret < 0) { + av_log(filter_ctx, AV_LOG_ERROR, "failed to parse options \"%s\"\n", + ctx->backend_options); + return ret; + } + } + } + } + + ctx->model = (ctx->dnn_module->load_model)(ctx, func_type, filter_ctx); if (!ctx->model) { av_log(filter_ctx, AV_LOG_ERROR, "could not load DNN model\n"); return AVERROR(EINVAL); @@ -120,15 +157,15 @@ int ff_dnn_set_classify_post_proc(DnnContext *ctx, ClassifyPostProc post_proc) int ff_dnn_get_input(DnnContext *ctx, DNNData *input) { - return ctx->model->get_input(ctx->model->model, input, ctx->model_inputname); + return ctx->model->get_input(ctx->model, input, ctx->model_inputname); } int ff_dnn_get_output(DnnContext *ctx, int input_width, int input_height, int *output_width, int *output_height) { char * output_name = ctx->model_outputnames && ctx->backend_type != DNN_TH ? ctx->model_outputnames[0] : NULL; - return ctx->model->get_output(ctx->model->model, ctx->model_inputname, input_width, input_height, - (const char *)output_name, output_width, output_height); + return ctx->model->get_output(ctx->model, ctx->model_inputname, input_width, input_height, + (const char *)output_name, output_width, output_height); } int ff_dnn_execute_model(DnnContext *ctx, AVFrame *in_frame, AVFrame *out_frame) diff --git a/libavfilter/dnn_filter_common.h b/libavfilter/dnn_filter_common.h index 30871ee38..42a471999 100644 --- a/libavfilter/dnn_filter_common.h +++ b/libavfilter/dnn_filter_common.h @@ -26,28 +26,30 @@ #include "dnn_interface.h" -typedef struct DnnContext { - char *model_filename; - DNNBackendType backend_type; - char *model_inputname; - char *model_outputnames_string; - char *backend_options; - int async; +#define DNN_FILTER_CHILD_CLASS_ITERATE(name, backend_mask) \ + static const AVClass *name##_child_class_iterate(void **iter) \ + { \ + return ff_dnn_child_class_iterate_with_mask(iter, (backend_mask)); \ + } - char **model_outputnames; - uint32_t nb_outputs; - const DNNModule *dnn_module; - DNNModel *model; -} DnnContext; +#define AVFILTER_DNN_DEFINE_CLASS_EXT(name, desc, options) \ + static const AVClass name##_class = { \ + .class_name = desc, \ + .item_name = av_default_item_name, \ + .option = options, \ + .version = LIBAVUTIL_VERSION_INT, \ + .category = AV_CLASS_CATEGORY_FILTER, \ + .child_next = ff_dnn_filter_child_next, \ + .child_class_iterate = name##_child_class_iterate, \ + } -#define DNN_COMMON_OPTIONS \ - { "model", "path to model file", OFFSET(model_filename), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },\ - { "input", "input name of the model", OFFSET(model_inputname), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },\ - { "output", "output name of the model", OFFSET(model_outputnames_string), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },\ - { "backend_configs", "backend configs", OFFSET(backend_options), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },\ - { "options", "backend configs (deprecated, use backend_configs)", OFFSET(backend_options), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS | AV_OPT_FLAG_DEPRECATED},\ - { "async", "use DNN async inference (ignored, use backend_configs='async=1')", OFFSET(async), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, FLAGS}, +#define AVFILTER_DNN_DEFINE_CLASS(fname, backend_mask) \ + DNN_FILTER_CHILD_CLASS_ITERATE(fname, backend_mask) \ + AVFILTER_DNN_DEFINE_CLASS_EXT(fname, #fname, fname##_options) +void *ff_dnn_filter_child_next(void *obj, void *prev); + +int ff_dnn_filter_init_child_class(AVFilterContext *filter); int ff_dnn_init(DnnContext *ctx, DNNFunctionType func_type, AVFilterContext *filter_ctx); int ff_dnn_set_frame_proc(DnnContext *ctx, FramePrePostProc pre_proc, FramePrePostProc post_proc); diff --git a/libavfilter/dnn_interface.h b/libavfilter/dnn_interface.h index 63f492e69..66086409b 100644 --- a/libavfilter/dnn_interface.h +++ b/libavfilter/dnn_interface.h @@ -32,7 +32,11 @@ #define DNN_GENERIC_ERROR FFERRTAG('D','N','N','!') -typedef enum {DNN_TF = 1, DNN_OV, DNN_TH} DNNBackendType; +typedef enum { + DNN_TF = 1, + DNN_OV = 1 << 1, + DNN_TH = 1 << 2 +} DNNBackendType; typedef enum {DNN_FLOAT = 1, DNN_UINT8 = 4} DNNDataType; @@ -91,19 +95,15 @@ typedef int (*DetectPostProc)(AVFrame *frame, DNNData *output, uint32_t nb, AVFi typedef int (*ClassifyPostProc)(AVFrame *frame, DNNData *output, uint32_t bbox_index, AVFilterContext *filter_ctx); typedef struct DNNModel{ - // Stores model that can be different for different backends. - void *model; - // Stores options when the model is executed by the backend - const char *options; // Stores FilterContext used for the interaction between AVFrame and DNNData AVFilterContext *filter_ctx; // Stores function type of the model DNNFunctionType func_type; // Gets model input information // Just reuse struct DNNData here, actually the DNNData.data field is not needed. - int (*get_input)(void *model, DNNData *input, const char *input_name); + int (*get_input)(struct DNNModel *model, DNNData *input, const char *input_name); // Gets model output width/height with given input w/h - int (*get_output)(void *model, const char *input_name, int input_width, int input_height, + int (*get_output)(struct DNNModel *model, const char *input_name, int input_width, int input_height, const char *output_name, int *output_width, int *output_height); // set the pre process to transfer data from AVFrame to DNNData // the default implementation within DNN is used if it is not provided by the filter @@ -117,10 +117,66 @@ typedef struct DNNModel{ ClassifyPostProc classify_post_proc; } DNNModel; +typedef struct TFOptions{ + const AVClass *clazz; + + char *sess_config; +} TFOptions; + +typedef struct OVOptions { + const AVClass *clazz; + + int batch_size; + int input_resizable; + DNNLayout layout; + float scale; + float mean; +} OVOptions; + +typedef struct THOptions { + const AVClass *clazz; + int optimize; +} THOptions; + +typedef struct DNNModule DNNModule; + +typedef struct DnnContext { + const AVClass *clazz; + + DNNModel *model; + + char *model_filename; + DNNBackendType backend_type; + char *model_inputname; + char *model_outputnames_string; + char *backend_options; + int async; + + char **model_outputnames; + uint32_t nb_outputs; + const DNNModule *dnn_module; + + int nireq; + char *device; + +#if CONFIG_LIBTENSORFLOW + TFOptions tf_option; +#endif + +#if CONFIG_LIBOPENVINO + OVOptions ov_option; +#endif +#if CONFIG_LIBTORCH + THOptions torch_option; +#endif +} DnnContext; + // Stores pointers to functions for loading, executing, freeing DNN models for one of the backends. -typedef struct DNNModule{ +struct DNNModule { + const AVClass clazz; + DNNBackendType type; // Loads model and parameters from given file. Returns NULL if it is not possible. - DNNModel *(*load_model)(const char *model_filename, DNNFunctionType func_type, const char *options, AVFilterContext *filter_ctx); + DNNModel *(*load_model)(DnnContext *ctx, DNNFunctionType func_type, AVFilterContext *filter_ctx); // Executes model with specified input and output. Returns the error code otherwise. int (*execute_model)(const DNNModel *model, DNNExecBaseParams *exec_params); // Retrieve inference result. @@ -129,11 +185,15 @@ typedef struct DNNModule{ int (*flush)(const DNNModel *model); // Frees memory allocated for model. void (*free_model)(DNNModel **model); -} DNNModule; +}; // Initializes DNNModule depending on chosen backend. const DNNModule *ff_get_dnn_module(DNNBackendType backend_type, void *log_ctx); +void ff_dnn_init_child_class(DnnContext *ctx); +void *ff_dnn_child_next(DnnContext *obj, void *prev); +const AVClass *ff_dnn_child_class_iterate_with_mask(void **iter, uint32_t backend_mask); + static inline int dnn_get_width_idx_by_layout(DNNLayout layout) { return layout == DL_NHWC ? 2 : 3; diff --git a/libavfilter/edge_template.c b/libavfilter/edge_template.c index ce45e579d..100fe1e42 100644 --- a/libavfilter/edge_template.c +++ b/libavfilter/edge_template.c @@ -22,7 +22,6 @@ #include "libavutil/avassert.h" #include "avfilter.h" -#include "internal.h" #include "video.h" #undef pixel diff --git a/libavfilter/f_bench.c b/libavfilter/f_bench.c index a9bcd2149..3f1fa23ae 100644 --- a/libavfilter/f_bench.c +++ b/libavfilter/f_bench.c @@ -22,7 +22,7 @@ #include "libavutil/time.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum BenchAction { diff --git a/libavfilter/f_cue.c b/libavfilter/f_cue.c index 7748e8f1f..38500bb51 100644 --- a/libavfilter/f_cue.c +++ b/libavfilter/f_cue.c @@ -25,7 +25,6 @@ #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" typedef struct CueContext { diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c index fd8641ff7..7c6a83be7 100644 --- a/libavfilter/f_drawgraph.c +++ b/libavfilter/f_drawgraph.c @@ -20,15 +20,14 @@ #include "config_components.h" -#include "float.h" - #include "libavutil/avstring.h" #include "libavutil/eval.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct DrawGraphContext { @@ -425,13 +424,14 @@ static int request_frame(AVFilterLink *outlink) static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); DrawGraphContext *s = outlink->src->priv; outlink->w = s->w; outlink->h = s->h; outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = s->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(l->frame_rate); s->prev_pts = AV_NOPTS_VALUE; return 0; diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c index 3a8dba581..f71c230b4 100644 --- a/libavfilter/f_ebur128.c +++ b/libavfilter/f_ebur128.c @@ -30,19 +30,17 @@ #include #include "libavutil/avassert.h" -#include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/dict.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/xga_font_data.h" #include "libavutil/opt.h" #include "libavutil/timestamp.h" #include "libswresample/swresample.h" -#include "audio.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #define ABS_THRES -70 ///< silence gate: we discard anything below this absolute (LUFS) threshold @@ -295,6 +293,7 @@ static int config_video_output(AVFilterLink *outlink) { int i, x, y; uint8_t *p; + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; EBUR128Context *ebur128 = ctx->priv; AVFrame *outpicref; @@ -308,8 +307,8 @@ static int config_video_output(AVFilterLink *outlink) outlink->w = ebur128->w; outlink->h = ebur128->h; outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = av_make_q(10, 1); - outlink->time_base = av_inv_q(outlink->frame_rate); + l->frame_rate = av_make_q(10, 1); + outlink->time_base = av_inv_q(l->frame_rate); #define PAD 8 diff --git a/libavfilter/f_graphmonitor.c b/libavfilter/f_graphmonitor.c index e0b20114e..0ed108561 100644 --- a/libavfilter/f_graphmonitor.c +++ b/libavfilter/f_graphmonitor.c @@ -20,10 +20,8 @@ #include "config_components.h" -#include "float.h" - +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" -#include "libavutil/eval.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "libavutil/timestamp.h" @@ -32,7 +30,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct CacheItem { @@ -260,8 +257,9 @@ static int draw_items(AVFilterContext *ctx, size_t frames) { GraphMonitorContext *s = ctx->priv; + FilterLink *fl = ff_filter_link(l); int64_t previous_pts_us = s->cache[s->cache_index].previous_pts_us; - int64_t current_pts_us = l->current_pts_us; + int64_t current_pts_us = fl->current_pts_us; const int flags = s->flags; const int mode = s->mode; char buffer[1024] = { 0 }; @@ -289,7 +287,7 @@ static int draw_items(AVFilterContext *ctx, } if (flags & FLAG_RATE) { if (l->type == AVMEDIA_TYPE_VIDEO) { - len = snprintf(buffer, sizeof(buffer)-1, " | fps: %d/%d", l->frame_rate.num, l->frame_rate.den); + len = snprintf(buffer, sizeof(buffer)-1, " | fps: %d/%d", fl->frame_rate.num, fl->frame_rate.den); } else if (l->type == AVMEDIA_TYPE_AUDIO) { len = snprintf(buffer, sizeof(buffer)-1, " | samplerate: %d", l->sample_rate); } @@ -309,33 +307,33 @@ static int draw_items(AVFilterContext *ctx, drawtext(out, xpos, ypos, buffer, len, frames > 0 ? frames >= 10 ? frames >= 50 ? s->red : s->yellow : s->green : s->white); xpos += len * 8; } - if ((flags & FLAG_FCIN) && (!(mode & MODE_NOZERO) || l->frame_count_in)) { - len = snprintf(buffer, sizeof(buffer)-1, " | in: %"PRId64, l->frame_count_in); + if ((flags & FLAG_FCIN) && (!(mode & MODE_NOZERO) || fl->frame_count_in)) { + len = snprintf(buffer, sizeof(buffer)-1, " | in: %"PRId64, fl->frame_count_in); drawtext(out, xpos, ypos, buffer, len, s->white); xpos += len * 8; } - if ((flags & FLAG_FCOUT) && (!(mode & MODE_NOZERO) || l->frame_count_out)) { - len = snprintf(buffer, sizeof(buffer)-1, " | out: %"PRId64, l->frame_count_out); + if ((flags & FLAG_FCOUT) && (!(mode & MODE_NOZERO) || fl->frame_count_out)) { + len = snprintf(buffer, sizeof(buffer)-1, " | out: %"PRId64, fl->frame_count_out); drawtext(out, xpos, ypos, buffer, len, s->white); xpos += len * 8; } - if ((flags & FLAG_FC_DELTA) && (!(mode & MODE_NOZERO) || (l->frame_count_in - l->frame_count_out))) { - len = snprintf(buffer, sizeof(buffer)-1, " | delta: %"PRId64, l->frame_count_in - l->frame_count_out); + if ((flags & FLAG_FC_DELTA) && (!(mode & MODE_NOZERO) || (fl->frame_count_in - fl->frame_count_out))) { + len = snprintf(buffer, sizeof(buffer)-1, " | delta: %"PRId64, fl->frame_count_in - fl->frame_count_out); drawtext(out, xpos, ypos, buffer, len, s->white); xpos += len * 8; } - if ((flags & FLAG_SCIN) && (!(mode & MODE_NOZERO) || l->sample_count_in)) { - len = snprintf(buffer, sizeof(buffer)-1, " | sin: %"PRId64, l->sample_count_in); + if ((flags & FLAG_SCIN) && (!(mode & MODE_NOZERO) || fl->sample_count_in)) { + len = snprintf(buffer, sizeof(buffer)-1, " | sin: %"PRId64, fl->sample_count_in); drawtext(out, xpos, ypos, buffer, len, s->white); xpos += len * 8; } - if ((flags & FLAG_SCOUT) && (!(mode & MODE_NOZERO) || l->sample_count_out)) { - len = snprintf(buffer, sizeof(buffer)-1, " | sout: %"PRId64, l->sample_count_out); + if ((flags & FLAG_SCOUT) && (!(mode & MODE_NOZERO) || fl->sample_count_out)) { + len = snprintf(buffer, sizeof(buffer)-1, " | sout: %"PRId64, fl->sample_count_out); drawtext(out, xpos, ypos, buffer, len, s->white); xpos += len * 8; } - if ((flags & FLAG_SC_DELTA) && (!(mode & MODE_NOZERO) || (l->sample_count_in - l->sample_count_out))) { - len = snprintf(buffer, sizeof(buffer)-1, " | sdelta: %"PRId64, l->sample_count_in - l->sample_count_out); + if ((flags & FLAG_SC_DELTA) && (!(mode & MODE_NOZERO) || (fl->sample_count_in - fl->sample_count_out))) { + len = snprintf(buffer, sizeof(buffer)-1, " | sdelta: %"PRId64, fl->sample_count_in - fl->sample_count_out); drawtext(out, xpos, ypos, buffer, len, s->white); xpos += len * 8; } @@ -370,7 +368,7 @@ static int draw_items(AVFilterContext *ctx, xpos += len * 8; } - s->cache[s->cache_index].previous_pts_us = l->current_pts_us; + s->cache[s->cache_index].previous_pts_us = current_pts_us; if (s->cache_index + 1 >= s->cache_size / sizeof(*(s->cache))) { void *ptr = av_fast_realloc(s->cache, &s->cache_size, s->cache_size * 2); @@ -539,6 +537,7 @@ static int activate(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); GraphMonitorContext *s = outlink->src->priv; s->white[0] = s->white[1] = s->white[2] = 255; @@ -552,7 +551,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = s->w; outlink->h = s->h; outlink->sample_aspect_ratio = (AVRational){1,1}; - outlink->frame_rate = s->frame_rate; + l->frame_rate = s->frame_rate; outlink->time_base = av_inv_q(s->frame_rate); return 0; diff --git a/libavfilter/f_interleave.c b/libavfilter/f_interleave.c index 93ad54882..1bfd002ba 100644 --- a/libavfilter/f_interleave.c +++ b/libavfilter/f_interleave.c @@ -31,7 +31,6 @@ #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "audio.h" #include "video.h" @@ -183,6 +182,7 @@ static av_cold int init(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink0 = ctx->inputs[0]; int i; @@ -193,7 +193,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = inlink0->h; outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio; outlink->format = inlink0->format; - outlink->frame_rate = (AVRational) {1, 0}; + l->frame_rate = (AVRational) {1, 0}; for (i = 1; i < ctx->nb_inputs; i++) { AVFilterLink *inlink = ctx->inputs[i]; diff --git a/libavfilter/f_latency.c b/libavfilter/f_latency.c index a39c3c7d2..85bdc4a1f 100644 --- a/libavfilter/f_latency.c +++ b/libavfilter/f_latency.c @@ -23,7 +23,6 @@ #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" typedef struct LatencyContext { @@ -46,6 +45,7 @@ static int activate(AVFilterContext *ctx) { LatencyContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); AVFilterLink *outlink = ctx->outputs[0]; FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); @@ -53,14 +53,15 @@ static int activate(AVFilterContext *ctx) if (!ctx->is_disabled && ctx->inputs[0]->src && ctx->inputs[0]->src->nb_inputs > 0) { AVFilterLink *prevlink = ctx->inputs[0]->src->inputs[0]; + FilterLink *prevl = ff_filter_link(prevlink); int64_t delta = 0; switch (prevlink->type) { case AVMEDIA_TYPE_AUDIO: - delta = prevlink->sample_count_in - inlink->sample_count_out; + delta = prevl->sample_count_in - inl->sample_count_out; break; case AVMEDIA_TYPE_VIDEO: - delta = prevlink->frame_count_in - inlink->frame_count_out; + delta = prevl->frame_count_in - inl->frame_count_out; break; } diff --git a/libavfilter/f_loop.c b/libavfilter/f_loop.c index 0b08a2ead..4e5e8d0e7 100644 --- a/libavfilter/f_loop.c +++ b/libavfilter/f_loop.c @@ -21,12 +21,13 @@ #include "config_components.h" #include "libavutil/audio_fifo.h" +#include "libavutil/avassert.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" #include "filters.h" -#include "internal.h" #include "video.h" typedef struct LoopContext { @@ -104,7 +105,7 @@ static av_cold void auninit(AVFilterContext *ctx) av_audio_fifo_free(s->left); } -static int push_samples(AVFilterContext *ctx, int nb_samples) +static int push_samples(AVFilterContext *ctx, int nb_samples, AVFrame **frame) { AVFilterLink *outlink = ctx->outputs[0]; LoopContext *s = ctx->priv; @@ -126,9 +127,7 @@ static int push_samples(AVFilterContext *ctx, int nb_samples) i += out->nb_samples; s->current_sample += out->nb_samples; - ret = ff_filter_frame(outlink, out); - if (ret < 0) - return ret; + *frame = out; if (s->current_sample >= s->nb_samples) { s->current_sample = 0; @@ -136,6 +135,8 @@ static int push_samples(AVFilterContext *ctx, int nb_samples) if (s->loop > 0) s->loop--; } + + return 0; } return ret; @@ -143,6 +144,7 @@ static int push_samples(AVFilterContext *ctx, int nb_samples) static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; LoopContext *s = ctx->priv; @@ -157,7 +159,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) int drain = 0; if (s->start < 0) - s->start = inlink->sample_count_out - written; + s->start = inl->sample_count_out - written; ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, written); if (ret < 0) @@ -169,23 +171,19 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) s->pts += av_rescale_q(s->start - s->ignored_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); } s->nb_samples += ret - drain; - drain = frame->nb_samples - written; - if (s->nb_samples == s->size && drain > 0) { + if (s->nb_samples == s->size && frame->nb_samples > written) { int ret2; ret2 = av_audio_fifo_write(s->left, (void **)frame->extended_data, frame->nb_samples); if (ret2 < 0) return ret2; - av_audio_fifo_drain(s->left, drain); + av_audio_fifo_drain(s->left, written); } frame->nb_samples = ret; s->pts += av_rescale_q(ret, (AVRational){1, outlink->sample_rate}, outlink->time_base); ret = ff_filter_frame(outlink, frame); } else { - int nb_samples = frame->nb_samples; - - av_frame_free(&frame); - ret = push_samples(ctx, nb_samples); + av_assert0(0); } } else { s->ignored_samples += frame->nb_samples; @@ -197,7 +195,7 @@ static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) return ret; } -static int arequest_frame(AVFilterLink *outlink) +static int arequest_frame(AVFilterLink *outlink, AVFrame **frame) { AVFilterContext *ctx = outlink->src; LoopContext *s = ctx->priv; @@ -217,17 +215,11 @@ static int arequest_frame(AVFilterLink *outlink) av_audio_fifo_read(s->left, (void **)out->extended_data, nb_samples); out->pts = s->pts; s->pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); - ret = ff_filter_frame(outlink, out); - if (ret < 0) - return ret; + *frame = out; } - ret = ff_request_frame(ctx->inputs[0]); + return 0; } else { - ret = push_samples(ctx, 1024); - } - - if (s->eof && s->nb_samples > 0 && s->loop != 0) { - ret = push_samples(ctx, 1024); + ret = push_samples(ctx, 1024, frame); } return ret; @@ -245,37 +237,31 @@ static int aactivate(AVFilterContext *ctx) update_time(ctx, inlink->time_base); - if (!s->eof && (s->nb_samples < s->size || !s->loop || !s->size)) { - const int in_nb_samples = FFMIN(1024, s->size - s->nb_samples); - if (in_nb_samples == 0) - ret = ff_inlink_consume_frame(inlink, &frame); - else - ret = ff_inlink_consume_samples(inlink, in_nb_samples, in_nb_samples, &frame); - if (ret < 0) - return ret; - if (ret > 0) - return afilter_frame(inlink, frame); - } +retry: + ret = arequest_frame(outlink, &frame); + if (ret < 0) + return ret; + if (frame) + return ff_filter_frame(outlink, frame); - if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &s->eof_pts)) { - if (status == AVERROR_EOF) { + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) + return afilter_frame(inlink, frame); + + ret = ff_inlink_acknowledge_status(inlink, &status, &s->eof_pts); + if (ret) { + if (status == AVERROR_EOF && !s->eof) { s->size = s->nb_samples; s->eof = 1; + goto retry; } - } - - if (s->eof && (!s->loop || !s->size)) { - ff_outlink_set_status(outlink, AVERROR_EOF, s->eof_pts + s->pts_offset); + ff_outlink_set_status(outlink, status, s->eof_pts); return 0; } - if (!s->eof && (!s->size || - (s->nb_samples < s->size) || - (s->nb_samples >= s->size && s->loop == 0))) { - FF_FILTER_FORWARD_WANTED(outlink, inlink); - } else if (s->loop && s->nb_samples == s->size) { - return arequest_frame(outlink); - } + FF_FILTER_FORWARD_WANTED(outlink, inlink); return FFERROR_NOT_READY; } @@ -373,13 +359,15 @@ static int push_frame(AVFilterContext *ctx) static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); LoopContext *s = ctx->priv; int64_t duration; int ret = 0; - if (((s->start >= 0 && inlink->frame_count_out >= s->start) || + if (((s->start >= 0 && inl->frame_count_out >= s->start) || (s->time_pts != AV_NOPTS_VALUE && frame->pts >= s->time_pts)) && s->size > 0 && s->loop != 0) { @@ -393,7 +381,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (frame->duration) duration = frame->duration; else - duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + duration = av_rescale_q(1, av_inv_q(outl->frame_rate), outlink->time_base); s->duration += duration; s->pts_offset = s->duration; ret = ff_filter_frame(outlink, frame); diff --git a/libavfilter/f_metadata.c b/libavfilter/f_metadata.c index b6d548612..abdfb1802 100644 --- a/libavfilter/f_metadata.c +++ b/libavfilter/f_metadata.c @@ -36,7 +36,7 @@ #include "libavformat/avio.h" #include "avfilter.h" #include "audio.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum MetadataMode { @@ -276,10 +276,8 @@ static av_cold int init(AVFilterContext *ctx) } if (ret < 0) { - char buf[128]; - av_strerror(ret, buf, sizeof(buf)); av_log(ctx, AV_LOG_ERROR, "Could not open %s: %s\n", - s->file_str, buf); + s->file_str, av_err2str(ret)); return ret; } @@ -303,6 +301,7 @@ static av_cold void uninit(AVFilterContext *ctx) static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; MetadataContext *s = ctx->priv; @@ -336,14 +335,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) case METADATA_PRINT: if (!s->key && e) { s->print(ctx, "frame:%-4"PRId64" pts:%-7s pts_time:%s\n", - inlink->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base)); + inl->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base)); s->print(ctx, "%s=%s\n", e->key, e->value); while ((e = av_dict_iterate(*metadata, e)) != NULL) { s->print(ctx, "%s=%s\n", e->key, e->value); } } else if (e && e->value && (!s->value || (e->value && s->compare(s, e->value, s->value)))) { s->print(ctx, "frame:%-4"PRId64" pts:%-7s pts_time:%s\n", - inlink->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base)); + inl->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base)); s->print(ctx, "%s=%s\n", s->key, e->value); } return ff_filter_frame(outlink, frame); diff --git a/libavfilter/f_realtime.c b/libavfilter/f_realtime.c index 83793bbe1..d85bef571 100644 --- a/libavfilter/f_realtime.c +++ b/libavfilter/f_realtime.c @@ -24,7 +24,7 @@ #include "libavutil/time.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include diff --git a/libavfilter/f_reverse.c b/libavfilter/f_reverse.c index 744f4a3cc..a939ca751 100644 --- a/libavfilter/f_reverse.c +++ b/libavfilter/f_reverse.c @@ -20,8 +20,9 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #define DEFAULT_LENGTH 300 diff --git a/libavfilter/f_segment.c b/libavfilter/f_segment.c index 03a071a05..4bcda427a 100644 --- a/libavfilter/f_segment.c +++ b/libavfilter/f_segment.c @@ -21,18 +21,14 @@ #include #include "libavutil/avstring.h" -#include "libavutil/channel_layout.h" -#include "libavutil/common.h" #include "libavutil/log.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" -#include "libavutil/samplefmt.h" -#include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" typedef struct SegmentContext { const AVClass *class; @@ -165,6 +161,7 @@ static int current_segment_finished(AVFilterContext *ctx, AVFrame *frame) { SegmentContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); int ret = 0; if (s->use_timestamps) { @@ -172,10 +169,10 @@ static int current_segment_finished(AVFilterContext *ctx, AVFrame *frame) } else { switch (inlink->type) { case AVMEDIA_TYPE_VIDEO: - ret = inlink->frame_count_out - 1 >= s->points[s->current_point]; + ret = inl->frame_count_out - 1 >= s->points[s->current_point]; break; case AVMEDIA_TYPE_AUDIO: - ret = inlink->sample_count_out - frame->nb_samples >= s->points[s->current_point]; + ret = inl->sample_count_out - frame->nb_samples >= s->points[s->current_point]; break; } } @@ -186,6 +183,7 @@ static int current_segment_finished(AVFilterContext *ctx, AVFrame *frame) static int activate(AVFilterContext *ctx) { AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); SegmentContext *s = ctx->priv; AVFrame *frame = NULL; int ret, status; @@ -202,14 +200,14 @@ static int activate(AVFilterContext *ctx) ret = ff_inlink_consume_frame(inlink, &frame); break; case AVMEDIA_TYPE_AUDIO: - diff = s->points[s->current_point] - inlink->sample_count_out; + diff = s->points[s->current_point] - inl->sample_count_out; while (diff <= 0) { ff_outlink_set_status(ctx->outputs[s->current_point], AVERROR_EOF, s->last_pts); s->current_point++; if (s->current_point >= s->nb_points) return AVERROR(EINVAL); - diff = s->points[s->current_point] - inlink->sample_count_out; + diff = s->points[s->current_point] - inl->sample_count_out; } if (s->use_timestamps) { max_samples = av_rescale_q(diff, av_make_q(1, inlink->sample_rate), inlink->time_base); diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c index 9b330a067..ba0ae31f1 100644 --- a/libavfilter/f_select.c +++ b/libavfilter/f_select.c @@ -34,8 +34,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "scene_sad.h" @@ -90,6 +90,11 @@ static const char *const var_names[] = { "concatdec_select", ///< frame is within the interval set by the concat demuxer + "ih", ///< ih: Represents the height of the input video frame. + "iw", ///< iw: Represents the width of the input video frame. + + "view", + NULL }; @@ -144,6 +149,11 @@ enum var_name { VAR_CONCATDEC_SELECT, + VAR_IH, + VAR_IW, + + VAR_VIEW, + VAR_VARS_NB }; @@ -264,6 +274,9 @@ static int config_input(AVFilterLink *inlink) select->var_values[VAR_CONSUMED_SAMPLES_N] = NAN; select->var_values[VAR_SAMPLES_N] = NAN; + select->var_values[VAR_IH] = NAN; + select->var_values[VAR_IW] = NAN; + select->var_values[VAR_SAMPLE_RATE] = inlink->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN; @@ -333,6 +346,8 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame) { SelectContext *select = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); + const AVFrameSideData *sd; double res; if (isnan(select->var_values[VAR_START_PTS])) @@ -340,7 +355,7 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame) if (isnan(select->var_values[VAR_START_T])) select->var_values[VAR_START_T] = TS2D(frame->pts) * av_q2d(inlink->time_base); - select->var_values[VAR_N ] = inlink->frame_count_out; + select->var_values[VAR_N ] = inl->frame_count_out; select->var_values[VAR_PTS] = TS2D(frame->pts); select->var_values[VAR_T ] = TS2D(frame->pts) * av_q2d(inlink->time_base); #if FF_API_FRAME_PKT @@ -357,6 +372,9 @@ FF_ENABLE_DEPRECATION_WARNINGS break; case AVMEDIA_TYPE_VIDEO: + select->var_values[VAR_IH] = frame->height; + select->var_values[VAR_IW] = frame->width; + select->var_values[VAR_INTERLACE_TYPE] = !(frame->flags & AV_FRAME_FLAG_INTERLACED) ? INTERLACE_TYPE_P : (frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? INTERLACE_TYPE_T : INTERLACE_TYPE_B; @@ -368,6 +386,10 @@ FF_ENABLE_DEPRECATION_WARNINGS snprintf(buf, sizeof(buf), "%f", select->var_values[VAR_SCENE]); av_dict_set(&frame->metadata, "lavfi.scene_score", buf, 0); } + + sd = av_frame_side_data_get(frame->side_data, frame->nb_side_data, + AV_FRAME_DATA_VIEW_ID); + select->var_values[VAR_VIEW] = sd ? *(int*)sd->data : NAN; break; } diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c index 922ce7828..f89527162 100644 --- a/libavfilter/f_sendcmd.c +++ b/libavfilter/f_sendcmd.c @@ -29,10 +29,11 @@ #include "libavutil/bprint.h" #include "libavutil/eval.h" #include "libavutil/file.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "audio.h" #include "video.h" @@ -487,6 +488,7 @@ static av_cold void uninit(AVFilterContext *ctx) static int filter_frame(AVFilterLink *inlink, AVFrame *ref) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; SendCmdContext *s = ctx->priv; int64_t ts; @@ -534,7 +536,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *ref) double end = TS2T(interval->end_ts, AV_TIME_BASE_Q); double current = TS2T(ref->pts, inlink->time_base); - var_values[VAR_N] = inlink->frame_count_in; + var_values[VAR_N] = inl->frame_count_in; #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS var_values[VAR_POS] = ref->pkt_pos == -1 ? NAN : ref->pkt_pos; @@ -564,7 +566,7 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(ctx, AV_LOG_VERBOSE, "Processing command #%d target:%s command:%s arg:%s\n", cmd->index, cmd->target, cmd->command, cmd_arg); - ret = avfilter_graph_send_command(inlink->graph, + ret = avfilter_graph_send_command(inl->graph, cmd->target, cmd->command, cmd_arg, buf, sizeof(buf), AVFILTER_CMD_FLAG_ONE); diff --git a/libavfilter/f_sidedata.c b/libavfilter/f_sidedata.c index fe9607ed5..23dffec80 100644 --- a/libavfilter/f_sidedata.c +++ b/libavfilter/f_sidedata.c @@ -29,7 +29,7 @@ #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum SideDataMode { @@ -71,8 +71,16 @@ static const AVOption filt_name##_options[] = { \ { "S12M_TIMECOD", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_S12M_TIMECODE }, 0, 0, FLAGS, .unit = "type" }, \ { "DYNAMIC_HDR_PLUS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DYNAMIC_HDR_PLUS }, 0, 0, FLAGS, .unit = "type" }, \ { "REGIONS_OF_INTEREST", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_REGIONS_OF_INTEREST }, 0, 0, FLAGS, .unit = "type" }, \ - { "DETECTION_BOUNDING_BOXES", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DETECTION_BBOXES }, 0, 0, FLAGS, .unit = "type" }, \ + { "VIDEO_ENC_PARAMS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_VIDEO_ENC_PARAMS }, 0, 0, FLAGS, .unit = "type" }, \ { "SEI_UNREGISTERED", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_SEI_UNREGISTERED }, 0, 0, FLAGS, .unit = "type" }, \ + { "FILM_GRAIN_PARAMS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_FILM_GRAIN_PARAMS }, 0, 0, FLAGS, .unit = "type" }, \ + { "DETECTION_BOUNDING_BOXES", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DETECTION_BBOXES }, 0, 0, FLAGS, .unit = "type" }, \ + { "DETECTION_BBOXES", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DETECTION_BBOXES }, 0, 0, FLAGS, .unit = "type" }, \ + { "DOVI_RPU_BUFFER", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DOVI_RPU_BUFFER }, 0, 0, FLAGS, .unit = "type" }, \ + { "DOVI_METADATA", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DOVI_METADATA }, 0, 0, FLAGS, .unit = "type" }, \ + { "DYNAMIC_HDR_VIVID", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DYNAMIC_HDR_VIVID }, 0, 0, FLAGS, .unit = "type" }, \ + { "AMBIENT_VIEWING_ENVIRONMENT","", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT}, 0, 0, FLAGS, .unit = "type" }, \ + { "VIDEO_HINT", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_VIDEO_HINT }, 0, 0, FLAGS, .unit = "type" }, \ { NULL } \ } diff --git a/libavfilter/f_streamselect.c b/libavfilter/f_streamselect.c index 5fbb13a32..4ff4e856e 100644 --- a/libavfilter/f_streamselect.c +++ b/libavfilter/f_streamselect.c @@ -18,13 +18,13 @@ #include "libavutil/avstring.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" #include "filters.h" #include "formats.h" #include "framesync.h" -#include "internal.h" #include "video.h" typedef struct StreamSelectContext { @@ -64,11 +64,12 @@ static int process_frame(FFFrameSync *fs) for (j = 0; j < ctx->nb_inputs; j++) { for (i = 0; i < s->nb_map; i++) { + FilterLink *outl = ff_filter_link(ctx->outputs[i]); if (s->map[i] == j) { AVFrame *out; if (s->is_audio && s->last_pts[j] == in[j]->pts && - ctx->outputs[i]->frame_count_in > 0) + outl->frame_count_in > 0) continue; out = av_frame_clone(in[j]); if (!out) @@ -97,11 +98,13 @@ static int activate(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; StreamSelectContext *s = ctx->priv; const int outlink_idx = FF_OUTLINK_IDX(outlink); const int inlink_idx = s->map[outlink_idx]; AVFilterLink *inlink = ctx->inputs[inlink_idx]; + FilterLink *inl = ff_filter_link(inlink); FFFrameSyncIn *in; int i, ret; @@ -114,7 +117,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = inlink->w; outlink->h = inlink->h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; - outlink->frame_rate = inlink->frame_rate; + outl->frame_rate = inl->frame_rate; break; case AVMEDIA_TYPE_AUDIO: outlink->sample_rate = inlink->sample_rate; @@ -245,7 +248,7 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar if (ret < 0) return ret; - return ff_filter_config_links(ctx); + return 0; } return AVERROR(ENOSYS); } diff --git a/libavfilter/f_zmq.c b/libavfilter/f_zmq.c index 3829b5522..84acc75ef 100644 --- a/libavfilter/f_zmq.c +++ b/libavfilter/f_zmq.c @@ -27,10 +27,10 @@ #include #include "libavutil/avstring.h" -#include "libavutil/bprint.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "audio.h" #include "video.h" @@ -176,7 +176,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *ref) av_log(ctx, AV_LOG_VERBOSE, "Processing command #%d target:%s command:%s arg:%s\n", zmq->command_count, cmd.target, cmd.command, cmd.arg); - ret = avfilter_graph_send_command(inlink->graph, + ret = avfilter_graph_send_command(ff_filter_link(inlink)->graph, cmd.target, cmd.command, cmd.arg, cmd_buf, sizeof(cmd_buf), AVFILTER_CMD_FLAG_ONE); diff --git a/libavfilter/filters.h b/libavfilter/filters.h index 86bc49d45..fdc7a95ce 100644 --- a/libavfilter/filters.h +++ b/libavfilter/filters.h @@ -26,13 +26,257 @@ */ #include "avfilter.h" -#include "internal.h" /** * Special return code when activate() did not do anything. */ #define FFERROR_NOT_READY FFERRTAG('N','R','D','Y') +/** + * A filter pad used for either input or output. + */ +struct AVFilterPad { + /** + * Pad name. The name is unique among inputs and among outputs, but an + * input may have the same name as an output. This may be NULL if this + * pad has no need to ever be referenced by name. + */ + const char *name; + + /** + * AVFilterPad type. + */ + enum AVMediaType type; + + /** + * The filter expects writable frames from its input link, + * duplicating data buffers if needed. + * + * input pads only. + */ +#define AVFILTERPAD_FLAG_NEEDS_WRITABLE (1 << 0) + + /** + * The pad's name is allocated and should be freed generically. + */ +#define AVFILTERPAD_FLAG_FREE_NAME (1 << 1) + + /** + * A combination of AVFILTERPAD_FLAG_* flags. + */ + int flags; + + /** + * Callback functions to get a video/audio buffers. If NULL, + * the filter system will use ff_default_get_video_buffer() for video + * and ff_default_get_audio_buffer() for audio. + * + * The state of the union is determined by type. + * + * Input pads only. + */ + union { + AVFrame *(*video)(AVFilterLink *link, int w, int h); + AVFrame *(*audio)(AVFilterLink *link, int nb_samples); + } get_buffer; + + /** + * Filtering callback. This is where a filter receives a frame with + * audio/video data and should do its processing. + * + * Input pads only. + * + * @return >= 0 on success, a negative AVERROR on error. This function + * must ensure that frame is properly unreferenced on error if it + * hasn't been passed on to another filter. + */ + int (*filter_frame)(AVFilterLink *link, AVFrame *frame); + + /** + * Frame request callback. A call to this should result in some progress + * towards producing output over the given link. This should return zero + * on success, and another value on error. + * + * Output pads only. + */ + int (*request_frame)(AVFilterLink *link); + + /** + * Link configuration callback. + * + * For output pads, this should set the link properties such as + * width/height. This should NOT set the format property - that is + * negotiated between filters by the filter system using the + * query_formats() callback before this function is called. + * + * For input pads, this should check the properties of the link, and update + * the filter's internal state as necessary. + * + * For both input and output filters, this should return zero on success, + * and another value on error. + */ + int (*config_props)(AVFilterLink *link); +}; + +/** + * Link properties exposed to filter code, but not external callers. + * + * Cf. AVFilterLink for public properties, FilterLinkInternal for + * properties private to the generic layer. + */ +typedef struct FilterLink { + AVFilterLink pub; + + /** + * Graph the filter belongs to. + */ + struct AVFilterGraph *graph; + + /** + * Current timestamp of the link, as defined by the most recent + * frame(s), in link time_base units. + */ + int64_t current_pts; + + /** + * Current timestamp of the link, as defined by the most recent + * frame(s), in AV_TIME_BASE units. + */ + int64_t current_pts_us; + + /** + * Minimum number of samples to filter at once. + * + * May be set by the link destination filter in its config_props(). + * If 0, all related fields are ignored. + */ + int min_samples; + + /** + * Maximum number of samples to filter at once. If filter_frame() is + * called with more samples, it will split them. + * + * May be set by the link destination filter in its config_props(). + */ + int max_samples; + + /** + * Number of past frames sent through the link. + */ + int64_t frame_count_in, frame_count_out; + + /** + * Number of past samples sent through the link. + */ + int64_t sample_count_in, sample_count_out; + + /** + * Frame rate of the stream on the link, or 1/0 if unknown or variable. + * + * May be set by the link source filter in its config_props(); if left to + * 0/0, will be automatically copied from the first input of the source + * filter if it exists. + * + * Sources should set it to the best estimation of the real frame rate. + * If the source frame rate is unknown or variable, set this to 1/0. + * Filters should update it if necessary depending on their function. + * Sinks can use it to set a default output frame rate. + * It is similar to the r_frame_rate field in AVStream. + */ + AVRational frame_rate; + + /** + * For hwaccel pixel formats, this should be a reference to the + * AVHWFramesContext describing the frames. + * + * May be set by the link source filter in its config_props(). + */ + AVBufferRef *hw_frames_ctx; +} FilterLink; + +static inline FilterLink* ff_filter_link(AVFilterLink *link) +{ + return (FilterLink*)link; +} + +/** + * The filter is aware of hardware frames, and any hardware frame context + * should not be automatically propagated through it. + */ +#define FF_FILTER_FLAG_HWFRAME_AWARE (1 << 0) + +/** + * Find the index of a link. + * + * I.e. find i such that link == ctx->(in|out)puts[i] + */ +#define FF_INLINK_IDX(link) ((int)((link)->dstpad - (link)->dst->input_pads)) +#define FF_OUTLINK_IDX(link) ((int)((link)->srcpad - (link)->src->output_pads)) + +enum FilterFormatsState { + /** + * The default value meaning that this filter supports all formats + * and (for audio) sample rates and channel layouts/counts as long + * as these properties agree for all inputs and outputs. + * This state is only allowed in case all inputs and outputs actually + * have the same type. + * The union is unused in this state. + * + * This value must always be zero (for default static initialization). + */ + FF_FILTER_FORMATS_PASSTHROUGH = 0, + FF_FILTER_FORMATS_QUERY_FUNC, ///< formats.query active. + FF_FILTER_FORMATS_QUERY_FUNC2, ///< formats.query_func2 active. + FF_FILTER_FORMATS_PIXFMT_LIST, ///< formats.pixels_list active. + FF_FILTER_FORMATS_SAMPLEFMTS_LIST, ///< formats.samples_list active. + FF_FILTER_FORMATS_SINGLE_PIXFMT, ///< formats.pix_fmt active + FF_FILTER_FORMATS_SINGLE_SAMPLEFMT, ///< formats.sample_fmt active. +}; + +#define FILTER_QUERY_FUNC(func) \ + .formats.query_func = func, \ + .formats_state = FF_FILTER_FORMATS_QUERY_FUNC +#define FILTER_QUERY_FUNC2(func) \ + .formats.query_func2 = func, \ + .formats_state = FF_FILTER_FORMATS_QUERY_FUNC2 +#define FILTER_PIXFMTS_ARRAY(array) \ + .formats.pixels_list = array, \ + .formats_state = FF_FILTER_FORMATS_PIXFMT_LIST +#define FILTER_SAMPLEFMTS_ARRAY(array) \ + .formats.samples_list = array, \ + .formats_state = FF_FILTER_FORMATS_SAMPLEFMTS_LIST +#define FILTER_PIXFMTS(...) \ + FILTER_PIXFMTS_ARRAY(((const enum AVPixelFormat []) { __VA_ARGS__, AV_PIX_FMT_NONE })) +#define FILTER_SAMPLEFMTS(...) \ + FILTER_SAMPLEFMTS_ARRAY(((const enum AVSampleFormat[]) { __VA_ARGS__, AV_SAMPLE_FMT_NONE })) +#define FILTER_SINGLE_PIXFMT(pix_fmt_) \ + .formats.pix_fmt = pix_fmt_, \ + .formats_state = FF_FILTER_FORMATS_SINGLE_PIXFMT +#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_) \ + .formats.sample_fmt = sample_fmt_, \ + .formats_state = FF_FILTER_FORMATS_SINGLE_SAMPLEFMT + +#define FILTER_INOUTPADS(inout, array) \ + .inout = array, \ + .nb_ ## inout = FF_ARRAY_ELEMS(array) +#define FILTER_INPUTS(array) FILTER_INOUTPADS(inputs, (array)) +#define FILTER_OUTPUTS(array) FILTER_INOUTPADS(outputs, (array)) + +#define AVFILTER_DEFINE_CLASS_EXT(name, desc, options) \ + static const AVClass name##_class = { \ + .class_name = desc, \ + .item_name = av_default_item_name, \ + .option = options, \ + .version = LIBAVUTIL_VERSION_INT, \ + .category = AV_CLASS_CATEGORY_FILTER, \ + } +#define AVFILTER_DEFINE_CLASS(fname) \ + AVFILTER_DEFINE_CLASS_EXT(fname, #fname, fname##_options) + +#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) +#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) +#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb)) + /** * Mark a filter ready and schedule it for activation. * @@ -45,21 +289,6 @@ */ void ff_filter_set_ready(AVFilterContext *filter, unsigned priority); -/** - * Process the commands queued in the link up to the time of the frame. - * Commands will trigger the process_command() callback. - * @return >= 0 or AVERROR code. - */ -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); - /** * Get the number of frames available on the link. * @return the number of frames available in the link fifo. @@ -169,16 +398,22 @@ void ff_inlink_set_status(AVFilterLink *link, int status); /** * Test if a frame is wanted on an output link. */ -static inline int ff_outlink_frame_wanted(AVFilterLink *link) -{ - return link->frame_wanted_out; -} +int ff_outlink_frame_wanted(AVFilterLink *link); /** * Get the status on an output link. */ int ff_outlink_get_status(AVFilterLink *link); +/** + * Set the status field of a link from the source filter. + * The pts should reflect the timestamp of the status change, + * in link time base and relative to the frames timeline. + * In particular, for AVERROR_EOF, it should reflect the + * end time of the last frame. + */ +void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts); + /** * Set the status field of a link from the source filter. * The pts should reflect the timestamp of the status change, @@ -266,4 +501,106 @@ static inline void ff_outlink_set_status(AVFilterLink *link, int status, int64_t */ int ff_inoutlink_check_flow(AVFilterLink *inlink, AVFilterLink *outlink); +/** + * Perform any additional setup required for hardware frames. + * + * link->hw_frames_ctx must be set before calling this function. + * Inside link->hw_frames_ctx, the fields format, sw_format, width and + * height must be set. If dynamically allocated pools are not supported, + * then initial_pool_size must also be set, to the minimum hardware frame + * pool size necessary for the filter to work (taking into account any + * frames which need to stored for use in operations as appropriate). If + * default_pool_size is nonzero, then it will be used as the pool size if + * no other modification takes place (this can be used to preserve + * compatibility). + */ +int ff_filter_init_hw_frames(AVFilterContext *avctx, AVFilterLink *link, + int default_pool_size); + +/** + * Generic processing of user supplied commands that are set + * in the same way as the filter options. + * NOTE: 'enable' option is handled separately, and not by + * this function. + */ +int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, + const char *arg, char *res, int res_len, int flags); + +/** + * Get number of threads for current filter instance. + * This number is always same or less than graph->nb_threads. + */ +int ff_filter_get_nb_threads(AVFilterContext *ctx) av_pure; + +/** + * Send a frame of data to the next filter. + * + * @param link the output link over which the data is being sent + * @param frame a reference to the buffer of data being sent. The + * receiving filter will free this reference when it no longer + * needs it or pass it on to the next filter. + * + * @return >= 0 on success, a negative AVERROR on error. The receiving filter + * is responsible for unreferencing frame in case of error. + */ +int ff_filter_frame(AVFilterLink *link, AVFrame *frame); + +/** + * Request an input frame from the filter at the other end of the link. + * + * This function must not be used by filters using the activate callback, + * use ff_link_set_frame_wanted() instead. + * + * The input filter may pass the request on to its inputs, fulfill the + * request from an internal buffer or any other means specific to its function. + * + * When the end of a stream is reached AVERROR_EOF is returned and no further + * frames are returned after that. + * + * When a filter is unable to output a frame for example due to its sources + * being unable to do so or because it depends on external means pushing data + * into it then AVERROR(EAGAIN) is returned. + * It is important that a AVERROR(EAGAIN) return is returned all the way to the + * caller (generally eventually a user application) as this step may (but does + * not have to be) necessary to provide the input with the next frame. + * + * If a request is successful then some progress has been made towards + * providing a frame on the link (through ff_filter_frame()). A filter that + * needs several frames to produce one is allowed to return success if one + * more frame has been processed but no output has been produced yet. A + * filter is also allowed to simply forward a success return value. + * + * @param link the input link + * @return zero on success + * AVERROR_EOF on end of file + * AVERROR(EAGAIN) if the previous filter cannot output a frame + * currently and can neither guarantee that EOF has been reached. + */ +int ff_request_frame(AVFilterLink *link); + +/** + * Append a new input/output pad to the filter's list of such pads. + * + * The *_free_name versions will set the AVFILTERPAD_FLAG_FREE_NAME flag + * ensuring that the name will be freed generically (even on insertion error). + */ +int ff_append_inpad (AVFilterContext *f, AVFilterPad *p); +int ff_append_outpad(AVFilterContext *f, AVFilterPad *p); +int ff_append_inpad_free_name (AVFilterContext *f, AVFilterPad *p); +int ff_append_outpad_free_name(AVFilterContext *f, AVFilterPad *p); + +/** + * Tell if an integer is contained in the provided -1-terminated list of integers. + * This is useful for determining (for instance) if an AVPixelFormat is in an + * array of supported formats. + * + * @param fmt provided format + * @param fmts -1-terminated list of formats + * @return 1 if present, 0 if absent + */ +int ff_fmt_is_in(int fmt, const int *fmts); + +int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, + void *arg, int *ret, int nb_jobs); + #endif /* AVFILTER_FILTERS_H */ diff --git a/libavfilter/formats.c b/libavfilter/formats.c index d3f4c7f09..21539b35d 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -22,10 +22,10 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/common.h" -#include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "formats.h" /** @@ -876,6 +876,153 @@ int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts) return ff_set_common_formats(ctx, ff_make_format_list(fmts)); } +#define SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, fmts, media_type, \ + ref_fn, unref_fn) \ + if (!fmts) \ + return AVERROR(ENOMEM); \ + \ + for (unsigned i = 0; i < ctx->nb_inputs; i++) { \ + const AVFilterLink *const link = ctx->inputs[i]; \ + if (!cfg_in[i]->fmts && \ + (media_type == AVMEDIA_TYPE_UNKNOWN || \ + link->type == media_type)) { \ + int ret = ref_fn(fmts, &cfg_in[i]->fmts); \ + if (ret < 0) { \ + return ret; \ + } \ + } \ + } \ + for (unsigned i = 0; i < ctx->nb_outputs; i++) { \ + const AVFilterLink *const link = ctx->outputs[i]; \ + if (!cfg_out[i]->fmts && \ + (media_type == AVMEDIA_TYPE_UNKNOWN || \ + link->type == media_type)) { \ + int ret = ref_fn(fmts, &cfg_out[i]->fmts); \ + if (ret < 0) { \ + return ret; \ + } \ + } \ + } \ + \ + if (!fmts->refcount) \ + unref_fn(&fmts); \ + \ + return 0; + +int ff_set_common_channel_layouts2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterChannelLayouts *channel_layouts) +{ + SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, channel_layouts, AVMEDIA_TYPE_AUDIO, + ff_channel_layouts_ref, ff_channel_layouts_unref); +} + +int ff_set_common_channel_layouts_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const AVChannelLayout *fmts) +{ + return ff_set_common_channel_layouts2(ctx, cfg_in, cfg_out, ff_make_channel_layout_list(fmts)); +} + +int ff_set_common_all_channel_counts2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) +{ + return ff_set_common_channel_layouts2(ctx, cfg_in, cfg_out, ff_all_channel_counts()); +} + +int ff_set_common_samplerates2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterFormats *samplerates) +{ + SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, samplerates, AVMEDIA_TYPE_AUDIO, + ff_formats_ref, ff_formats_unref); +} + +int ff_set_common_samplerates_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const int *samplerates) +{ + return ff_set_common_samplerates2(ctx, cfg_in, cfg_out, ff_make_format_list(samplerates)); +} + +int ff_set_common_all_samplerates2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) +{ + return ff_set_common_samplerates2(ctx, cfg_in, cfg_out, ff_all_samplerates()); +} + +int ff_set_common_color_spaces2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterFormats *color_spaces) +{ + SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, color_spaces, AVMEDIA_TYPE_VIDEO, + ff_formats_ref, ff_formats_unref); +} + +int ff_set_common_color_spaces_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const int *color_ranges) +{ + return ff_set_common_color_spaces2(ctx, cfg_in, cfg_out, ff_make_format_list(color_ranges)); +} + +int ff_set_common_all_color_spaces2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) +{ + return ff_set_common_color_spaces2(ctx, cfg_in, cfg_out, ff_all_color_spaces()); +} + +int ff_set_common_color_ranges2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterFormats *color_ranges) +{ + SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, color_ranges, AVMEDIA_TYPE_VIDEO, + ff_formats_ref, ff_formats_unref); +} + +int ff_set_common_color_ranges_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const int *color_ranges) +{ + return ff_set_common_color_ranges2(ctx, cfg_in, cfg_out, ff_make_format_list(color_ranges)); +} + +int ff_set_common_all_color_ranges2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out) +{ + return ff_set_common_color_ranges2(ctx, cfg_in, cfg_out, ff_all_color_ranges()); +} + +int ff_set_common_formats2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterFormats *formats) +{ + SET_COMMON_FORMATS2(ctx, cfg_in, cfg_out, formats, AVMEDIA_TYPE_UNKNOWN, + ff_formats_ref, ff_formats_unref); +} + +int ff_set_common_formats_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const int *fmts) +{ + return ff_set_common_formats2(ctx, cfg_in, cfg_out, ff_make_format_list(fmts)); +} + + int ff_default_query_formats(AVFilterContext *ctx) { const AVFilter *const f = ctx->filter; @@ -905,6 +1052,7 @@ int ff_default_query_formats(AVFilterContext *ctx) /* Intended fallthrough */ case FF_FILTER_FORMATS_PASSTHROUGH: case FF_FILTER_FORMATS_QUERY_FUNC: + case FF_FILTER_FORMATS_QUERY_FUNC2: type = AVMEDIA_TYPE_UNKNOWN; formats = ff_all_formats(ctx->nb_inputs ? ctx->inputs [0]->type : ctx->nb_outputs ? ctx->outputs[0]->type : @@ -935,58 +1083,6 @@ int ff_default_query_formats(AVFilterContext *ctx) return 0; } -/* internal functions for parsing audio format arguments */ - -int ff_parse_pixel_format(enum AVPixelFormat *ret, const char *arg, void *log_ctx) -{ - char *tail; - int pix_fmt = av_get_pix_fmt(arg); - if (pix_fmt == AV_PIX_FMT_NONE) { - pix_fmt = strtol(arg, &tail, 0); - if (*tail || !av_pix_fmt_desc_get(pix_fmt)) { - av_log(log_ctx, AV_LOG_ERROR, "Invalid pixel format '%s'\n", arg); - return AVERROR(EINVAL); - } - } - *ret = pix_fmt; - return 0; -} - -int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx) -{ - char *tail; - double srate = av_strtod(arg, &tail); - if (*tail || srate < 1 || (int)srate != srate || srate > INT_MAX) { - av_log(log_ctx, AV_LOG_ERROR, "Invalid sample rate '%s'\n", arg); - return AVERROR(EINVAL); - } - *ret = srate; - return 0; -} - -int ff_parse_channel_layout(AVChannelLayout *ret, int *nret, const char *arg, - void *log_ctx) -{ - AVChannelLayout chlayout = { 0 }; - int res; - - res = av_channel_layout_from_string(&chlayout, arg); - if (res < 0) { - av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg); - return AVERROR(EINVAL); - } - - if (chlayout.order == AV_CHANNEL_ORDER_UNSPEC && !nret) { - av_log(log_ctx, AV_LOG_ERROR, "Unknown channel layout '%s' is not supported.\n", arg); - return AVERROR(EINVAL); - } - *ret = chlayout; - if (nret) - *nret = chlayout.nb_channels; - - return 0; -} - static int check_list(void *log, const char *name, const AVFilterFormats *fmts) { unsigned i, j; @@ -1029,7 +1125,7 @@ int ff_formats_check_color_spaces(void *log, const AVFilterFormats *fmts) { for (int i = 0; fmts && i < fmts->nb_formats; i++) { if (fmts->formats[i] == AVCOL_SPC_RESERVED) { - av_log(log, AV_LOG_ERROR, "Invalid color range\n"); + av_log(log, AV_LOG_ERROR, "Invalid color space\n"); return AVERROR(EINVAL); } } diff --git a/libavfilter/formats.h b/libavfilter/formats.h index 82b3af4be..380e9dfd0 100644 --- a/libavfilter/formats.h +++ b/libavfilter/formats.h @@ -225,6 +225,90 @@ int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats); av_warn_unused_result int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts); +/** + * Helpers for query_formats2() which set all free audio links to the same list + * of channel layouts/sample rates. If there are no links hooked to this list, + * the list is freed. + */ +av_warn_unused_result +int ff_set_common_channel_layouts2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterChannelLayouts *channel_layouts); + +av_warn_unused_result +int ff_set_common_channel_layouts_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const AVChannelLayout *fmts); +av_warn_unused_result +int ff_set_common_all_channel_counts2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out); + +av_warn_unused_result +int ff_set_common_samplerates2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterFormats *samplerates); + +av_warn_unused_result +int ff_set_common_samplerates_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const int *samplerates); + +av_warn_unused_result +int ff_set_common_all_samplerates2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out); + +av_warn_unused_result +int ff_set_common_color_spaces2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterFormats *color_spaces); + +av_warn_unused_result +int ff_set_common_color_spaces_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const int *color_ranges); + +av_warn_unused_result +int ff_set_common_all_color_spaces2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out); + +av_warn_unused_result +int ff_set_common_color_ranges2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterFormats *color_ranges); + +av_warn_unused_result +int ff_set_common_color_ranges_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const int *color_ranges); + +av_warn_unused_result +int ff_set_common_all_color_ranges2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out); + +av_warn_unused_result +int ff_set_common_formats2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + AVFilterFormats *formats); + +av_warn_unused_result +int ff_set_common_formats_from_list2(const AVFilterContext *ctx, + AVFilterFormatsConfig **cfg_in, + AVFilterFormatsConfig **cfg_out, + const int *fmts); + av_warn_unused_result int ff_add_channel_layout(AVFilterChannelLayouts **l, const AVChannelLayout *channel_layout); diff --git a/libavfilter/framepool.c b/libavfilter/framepool.c index 841caa046..1a1fc0de1 100644 --- a/libavfilter/framepool.c +++ b/libavfilter/framepool.c @@ -24,6 +24,7 @@ #include "libavutil/buffer.h" #include "libavutil/frame.h" #include "libavutil/imgutils.h" +#include "libavutil/imgutils_internal.h" #include "libavutil/mem.h" #include "libavutil/pixfmt.h" @@ -138,7 +139,9 @@ FFFramePool *ff_frame_pool_audio_init(AVBufferRef* (*alloc)(size_t size), if (ret < 0) goto fail; - pool->pools[0] = av_buffer_pool_init(pool->linesize[0], NULL); + if (pool->linesize[0] > SIZE_MAX - align) + goto fail; + pool->pools[0] = av_buffer_pool_init(pool->linesize[0] + align, NULL); if (!pool->pools[0]) goto fail; @@ -218,7 +221,7 @@ AVFrame *ff_frame_pool_get(FFFramePool *pool) if (!frame->buf[i]) goto fail; - frame->data[i] = frame->buf[i]->data; + frame->data[i] = (uint8_t *)FFALIGN((uintptr_t)frame->buf[i]->data, pool->align); } if (desc->flags & AV_PIX_FMT_FLAG_PAL) { @@ -255,13 +258,15 @@ AVFrame *ff_frame_pool_get(FFFramePool *pool) frame->buf[i] = av_buffer_pool_get(pool->pools[0]); if (!frame->buf[i]) goto fail; - frame->extended_data[i] = frame->data[i] = frame->buf[i]->data; + frame->extended_data[i] = frame->data[i] = + (uint8_t *)FFALIGN((uintptr_t)frame->buf[i]->data, pool->align); } for (i = 0; i < frame->nb_extended_buf; i++) { frame->extended_buf[i] = av_buffer_pool_get(pool->pools[0]); if (!frame->extended_buf[i]) goto fail; - frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data; + frame->extended_data[i + AV_NUM_DATA_POINTERS] = + (uint8_t *)FFALIGN((uintptr_t)frame->extended_buf[i]->data, pool->align); } break; diff --git a/libavfilter/framequeue.c b/libavfilter/framequeue.c index ace0dad68..79255fe53 100644 --- a/libavfilter/framequeue.c +++ b/libavfilter/framequeue.c @@ -20,6 +20,7 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "framequeue.h" static inline FFFrameBucket *bucket(FFFrameQueue *fq, size_t idx) diff --git a/libavfilter/framesync.c b/libavfilter/framesync.c index cf2f355c8..0d5779f83 100644 --- a/libavfilter/framesync.c +++ b/libavfilter/framesync.c @@ -19,11 +19,11 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "filters.h" #include "framesync.h" -#include "internal.h" #define OFFSET(member) offsetof(FFFrameSync, member) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM @@ -51,7 +51,7 @@ static const AVOption framesync_options[] = { 0, AV_OPT_TYPE_CONST, { .i64 = TS_NEAREST }, .flags = FLAGS, .unit = "ts_sync_mode" }, { NULL } }; -static const AVClass framesync_class = { +const AVClass ff_framesync_class = { .version = LIBAVUTIL_VERSION_INT, .class_name = "framesync", .item_name = framesync_name, @@ -62,7 +62,7 @@ static const AVClass framesync_class = { const AVClass *ff_framesync_child_class_iterate(void **iter) { - const AVClass *c = *iter ? NULL : &framesync_class; + const AVClass *c = *iter ? NULL : &ff_framesync_class; *iter = (void *)(uintptr_t)c; return c; } @@ -79,7 +79,7 @@ void ff_framesync_preinit(FFFrameSync *fs) { if (fs->class) return; - fs->class = &framesync_class; + fs->class = &ff_framesync_class; av_opt_set_defaults(fs); } @@ -95,19 +95,22 @@ int ff_framesync_init(FFFrameSync *fs, AVFilterContext *parent, unsigned nb_in) fs->nb_in = nb_in; fs->in = av_calloc(nb_in, sizeof(*fs->in)); - if (!fs->in) + if (!fs->in) { + fs->nb_in = 0; return AVERROR(ENOMEM); + } + return 0; } -static void framesync_eof(FFFrameSync *fs) +static void framesync_eof(FFFrameSync *fs, int64_t pts) { fs->eof = 1; fs->frame_ready = 0; - ff_outlink_set_status(fs->parent->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE); + ff_outlink_set_status(fs->parent->outputs[0], AVERROR_EOF, pts); } -static void framesync_sync_level_update(FFFrameSync *fs) +static void framesync_sync_level_update(FFFrameSync *fs, int64_t eof_pts) { unsigned i, level = 0; @@ -128,7 +131,7 @@ static void framesync_sync_level_update(FFFrameSync *fs) if (level) fs->sync_level = level; else - framesync_eof(fs); + framesync_eof(fs, eof_pts); } int ff_framesync_configure(FFFrameSync *fs) @@ -176,7 +179,7 @@ int ff_framesync_configure(FFFrameSync *fs) for (i = 0; i < fs->nb_in; i++) fs->in[i].pts = fs->in[i].pts_next = AV_NOPTS_VALUE; fs->sync_level = UINT_MAX; - framesync_sync_level_update(fs); + framesync_sync_level_update(fs, AV_NOPTS_VALUE); return 0; } @@ -197,7 +200,7 @@ static int framesync_advance(FFFrameSync *fs) if (fs->in[i].have_next && fs->in[i].pts_next < pts) pts = fs->in[i].pts_next; if (pts == INT64_MAX) { - framesync_eof(fs); + framesync_eof(fs, AV_NOPTS_VALUE); break; } for (i = 0; i < fs->nb_in; i++) { @@ -219,7 +222,7 @@ static int framesync_advance(FFFrameSync *fs) fs->frame_ready = 1; if (fs->in[i].state == STATE_EOF && fs->in[i].after == EXT_STOP) - framesync_eof(fs); + framesync_eof(fs, AV_NOPTS_VALUE); } } if (fs->frame_ready) @@ -252,15 +255,14 @@ static void framesync_inject_frame(FFFrameSync *fs, unsigned in, AVFrame *frame) fs->in[in].have_next = 1; } -static void framesync_inject_status(FFFrameSync *fs, unsigned in, int status, int64_t pts) +static void framesync_inject_status(FFFrameSync *fs, unsigned in, int status, int64_t eof_pts) { av_assert0(!fs->in[in].have_next); - pts = fs->in[in].state != STATE_RUN || fs->in[in].after == EXT_INFINITY - ? INT64_MAX : framesync_pts_extrapolate(fs, in, fs->in[in].pts); fs->in[in].sync = 0; - framesync_sync_level_update(fs); + framesync_sync_level_update(fs, status == AVERROR_EOF ? eof_pts : AV_NOPTS_VALUE); fs->in[in].frame_next = NULL; - fs->in[in].pts_next = pts; + fs->in[in].pts_next = fs->in[in].state != STATE_RUN || fs->in[in].after == EXT_INFINITY + ? INT64_MAX : framesync_pts_extrapolate(fs, in, fs->in[in].pts); fs->in[in].have_next = 1; } @@ -270,7 +272,6 @@ int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe, AVFrame *frame; unsigned need_copy = 0, i; int64_t pts_next; - int ret; if (!fs->in[in].frame) { *rframe = NULL; @@ -288,10 +289,6 @@ int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe, if (need_copy) { if (!(frame = av_frame_clone(frame))) return AVERROR(ENOMEM); - if ((ret = ff_inlink_make_frame_writable(fs->parent->inputs[in], &frame)) < 0) { - av_frame_free(&frame); - return ret; - } } else { fs->in[in].frame = NULL; } diff --git a/libavfilter/framesync.h b/libavfilter/framesync.h index 233f50a0e..130d067ba 100644 --- a/libavfilter/framesync.h +++ b/libavfilter/framesync.h @@ -316,6 +316,7 @@ int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1); int ff_framesync_dualinput_get_writable(FFFrameSync *fs, AVFrame **f0, AVFrame **f1); const AVClass *ff_framesync_child_class_iterate(void **iter); +extern const AVClass ff_framesync_class; #define FRAMESYNC_DEFINE_PURE_CLASS(name, desc, func_prefix, options) \ static const AVClass name##_class = { \ diff --git a/libavfilter/graphdump.c b/libavfilter/graphdump.c index df79903c5..1bb59e430 100644 --- a/libavfilter/graphdump.c +++ b/libavfilter/graphdump.c @@ -23,9 +23,10 @@ #include "libavutil/channel_layout.h" #include "libavutil/bprint.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" static int print_link_prop(AVBPrint *buf, AVFilterLink *link) { diff --git a/libavfilter/graphparser.c b/libavfilter/graphparser.c index 5d6dcdb9d..912804ecd 100644 --- a/libavfilter/graphparser.c +++ b/libavfilter/graphparser.c @@ -30,7 +30,7 @@ #include "avfilter.h" #include "avfilter_internal.h" -#include "internal.h" +#include "filters.h" #define WHITESPACES " \n\t\r" diff --git a/libavfilter/hflip.h b/libavfilter/hflip.h index 8532dc0f4..0d8b1025f 100644 --- a/libavfilter/hflip.h +++ b/libavfilter/hflip.h @@ -22,10 +22,9 @@ #ifndef AVFILTER_HFLIP_H #define AVFILTER_HFLIP_H -#include "avfilter.h" +#include typedef struct FlipContext { - const AVClass *class; int max_step[4]; ///< max pixel step for each plane, expressed as a number of bytes int bayer_plus1; ///< 1 .. not a Bayer input format, 2 .. Bayer input format int planewidth[4]; ///< width of each plane diff --git a/libavfilter/internal.h b/libavfilter/internal.h deleted file mode 100644 index 000f94cb1..000000000 --- a/libavfilter/internal.h +++ /dev/null @@ -1,389 +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 AVFILTER_INTERNAL_H -#define AVFILTER_INTERNAL_H - -/** - * @file - * internal API functions - */ - -#include "libavutil/internal.h" -#include "avfilter.h" - -/** - * A filter pad used for either input or output. - */ -struct AVFilterPad { - /** - * Pad name. The name is unique among inputs and among outputs, but an - * input may have the same name as an output. This may be NULL if this - * pad has no need to ever be referenced by name. - */ - const char *name; - - /** - * AVFilterPad type. - */ - enum AVMediaType type; - - /** - * The filter expects writable frames from its input link, - * duplicating data buffers if needed. - * - * input pads only. - */ -#define AVFILTERPAD_FLAG_NEEDS_WRITABLE (1 << 0) - - /** - * The pad's name is allocated and should be freed generically. - */ -#define AVFILTERPAD_FLAG_FREE_NAME (1 << 1) - - /** - * A combination of AVFILTERPAD_FLAG_* flags. - */ - int flags; - - /** - * Callback functions to get a video/audio buffers. If NULL, - * the filter system will use ff_default_get_video_buffer() for video - * and ff_default_get_audio_buffer() for audio. - * - * The state of the union is determined by type. - * - * Input pads only. - */ - union { - AVFrame *(*video)(AVFilterLink *link, int w, int h); - AVFrame *(*audio)(AVFilterLink *link, int nb_samples); - } get_buffer; - - /** - * Filtering callback. This is where a filter receives a frame with - * audio/video data and should do its processing. - * - * Input pads only. - * - * @return >= 0 on success, a negative AVERROR on error. This function - * must ensure that frame is properly unreferenced on error if it - * hasn't been passed on to another filter. - */ - int (*filter_frame)(AVFilterLink *link, AVFrame *frame); - - /** - * Frame request callback. A call to this should result in some progress - * towards producing output over the given link. This should return zero - * on success, and another value on error. - * - * Output pads only. - */ - int (*request_frame)(AVFilterLink *link); - - /** - * Link configuration callback. - * - * For output pads, this should set the link properties such as - * width/height. This should NOT set the format property - that is - * negotiated between filters by the filter system using the - * query_formats() callback before this function is called. - * - * For input pads, this should check the properties of the link, and update - * the filter's internal state as necessary. - * - * For both input and output filters, this should return zero on success, - * and another value on error. - */ - int (*config_props)(AVFilterLink *link); -}; - -typedef struct FFFilterContext { - /** - * The public AVFilterContext. See avfilter.h for it. - */ - AVFilterContext p; - - avfilter_execute_func *execute; - - // 1 when avfilter_init_*() was successfully called on this filter - // 0 otherwise - int initialized; -} FFFilterContext; - -static inline FFFilterContext *fffilterctx(AVFilterContext *ctx) -{ - return (FFFilterContext*)ctx; -} - -static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, - void *arg, int *ret, int nb_jobs) -{ - return fffilterctx(ctx)->execute(ctx, func, arg, ret, nb_jobs); -} - -enum FilterFormatsState { - /** - * The default value meaning that this filter supports all formats - * and (for audio) sample rates and channel layouts/counts as long - * as these properties agree for all inputs and outputs. - * This state is only allowed in case all inputs and outputs actually - * have the same type. - * The union is unused in this state. - * - * This value must always be zero (for default static initialization). - */ - FF_FILTER_FORMATS_PASSTHROUGH = 0, - FF_FILTER_FORMATS_QUERY_FUNC, ///< formats.query active. - FF_FILTER_FORMATS_PIXFMT_LIST, ///< formats.pixels_list active. - FF_FILTER_FORMATS_SAMPLEFMTS_LIST, ///< formats.samples_list active. - FF_FILTER_FORMATS_SINGLE_PIXFMT, ///< formats.pix_fmt active - FF_FILTER_FORMATS_SINGLE_SAMPLEFMT, ///< formats.sample_fmt active. -}; - -#define FILTER_QUERY_FUNC(func) \ - .formats.query_func = func, \ - .formats_state = FF_FILTER_FORMATS_QUERY_FUNC -#define FILTER_PIXFMTS_ARRAY(array) \ - .formats.pixels_list = array, \ - .formats_state = FF_FILTER_FORMATS_PIXFMT_LIST -#define FILTER_SAMPLEFMTS_ARRAY(array) \ - .formats.samples_list = array, \ - .formats_state = FF_FILTER_FORMATS_SAMPLEFMTS_LIST -#define FILTER_PIXFMTS(...) \ - FILTER_PIXFMTS_ARRAY(((const enum AVPixelFormat []) { __VA_ARGS__, AV_PIX_FMT_NONE })) -#define FILTER_SAMPLEFMTS(...) \ - FILTER_SAMPLEFMTS_ARRAY(((const enum AVSampleFormat[]) { __VA_ARGS__, AV_SAMPLE_FMT_NONE })) -#define FILTER_SINGLE_PIXFMT(pix_fmt_) \ - .formats.pix_fmt = pix_fmt_, \ - .formats_state = FF_FILTER_FORMATS_SINGLE_PIXFMT -#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_) \ - .formats.sample_fmt = sample_fmt_, \ - .formats_state = FF_FILTER_FORMATS_SINGLE_SAMPLEFMT - -#define FILTER_INOUTPADS(inout, array) \ - .inout = array, \ - .nb_ ## inout = FF_ARRAY_ELEMS(array) -#define FILTER_INPUTS(array) FILTER_INOUTPADS(inputs, (array)) -#define FILTER_OUTPUTS(array) FILTER_INOUTPADS(outputs, (array)) - -/** - * Tell if an integer is contained in the provided -1-terminated list of integers. - * This is useful for determining (for instance) if an AVPixelFormat is in an - * array of supported formats. - * - * @param fmt provided format - * @param fmts -1-terminated list of formats - * @return 1 if present, 0 if absent - */ -int ff_fmt_is_in(int fmt, const int *fmts); - -/** - * Returns true if a pixel format is "regular YUV", which includes all pixel - * formats that are affected by YUV colorspace negotiation. - */ -int ff_fmt_is_regular_yuv(enum AVPixelFormat fmt); - -/* Functions to parse audio format arguments */ - -/** - * Parse a pixel format. - * - * @param ret pixel format pointer to where the value should be written - * @param arg string to parse - * @param log_ctx log context - * @return >= 0 in case of success, a negative AVERROR code on error - */ -av_warn_unused_result -int ff_parse_pixel_format(enum AVPixelFormat *ret, const char *arg, void *log_ctx); - -/** - * Parse a sample rate. - * - * @param ret unsigned integer pointer to where the value should be written - * @param arg string to parse - * @param log_ctx log context - * @return >= 0 in case of success, a negative AVERROR code on error - */ -av_warn_unused_result -int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx); - -/** - * Parse a channel layout or a corresponding integer representation. - * - * @param ret 64bit integer pointer to where the value should be written. - * @param nret integer pointer to the number of channels; - * if not NULL, then unknown channel layouts are accepted - * @param arg string to parse - * @param log_ctx log context - * @return >= 0 in case of success, a negative AVERROR code on error - */ -av_warn_unused_result -int ff_parse_channel_layout(AVChannelLayout *ret, int *nret, const char *arg, - void *log_ctx); - -/** - * Set the status field of a link from the source filter. - * The pts should reflect the timestamp of the status change, - * in link time base and relative to the frames timeline. - * In particular, for AVERROR_EOF, it should reflect the - * end time of the last frame. - */ -void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts); - -/** - * Negotiate the media format, dimensions, etc of all inputs to a filter. - * - * @param filter the filter to negotiate the properties for its inputs - * @return zero on successful negotiation - */ -int ff_filter_config_links(AVFilterContext *filter); - -#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) -#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) -#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb)) - -/* misc trace functions */ - -#define FF_TPRINTF_START(ctx, func) ff_tlog(NULL, "%-16s: ", #func) - -#ifdef TRACE -void ff_tlog_link(void *ctx, AVFilterLink *link, int end); -#else -#define ff_tlog_link(ctx, link, end) do { } while(0) -#endif - -/** - * Append a new input/output pad to the filter's list of such pads. - * - * The *_free_name versions will set the AVFILTERPAD_FLAG_FREE_NAME flag - * ensuring that the name will be freed generically (even on insertion error). - */ -int ff_append_inpad (AVFilterContext *f, AVFilterPad *p); -int ff_append_outpad(AVFilterContext *f, AVFilterPad *p); -int ff_append_inpad_free_name (AVFilterContext *f, AVFilterPad *p); -int ff_append_outpad_free_name(AVFilterContext *f, AVFilterPad *p); - -/** - * Request an input frame from the filter at the other end of the link. - * - * This function must not be used by filters using the activate callback, - * use ff_link_set_frame_wanted() instead. - * - * The input filter may pass the request on to its inputs, fulfill the - * request from an internal buffer or any other means specific to its function. - * - * When the end of a stream is reached AVERROR_EOF is returned and no further - * frames are returned after that. - * - * When a filter is unable to output a frame for example due to its sources - * being unable to do so or because it depends on external means pushing data - * into it then AVERROR(EAGAIN) is returned. - * It is important that a AVERROR(EAGAIN) return is returned all the way to the - * caller (generally eventually a user application) as this step may (but does - * not have to be) necessary to provide the input with the next frame. - * - * If a request is successful then some progress has been made towards - * providing a frame on the link (through ff_filter_frame()). A filter that - * needs several frames to produce one is allowed to return success if one - * more frame has been processed but no output has been produced yet. A - * filter is also allowed to simply forward a success return value. - * - * @param link the input link - * @return zero on success - * AVERROR_EOF on end of file - * AVERROR(EAGAIN) if the previous filter cannot output a frame - * currently and can neither guarantee that EOF has been reached. - */ -int ff_request_frame(AVFilterLink *link); - -#define AVFILTER_DEFINE_CLASS_EXT(name, desc, options) \ - static const AVClass name##_class = { \ - .class_name = desc, \ - .item_name = av_default_item_name, \ - .option = options, \ - .version = LIBAVUTIL_VERSION_INT, \ - .category = AV_CLASS_CATEGORY_FILTER, \ - } -#define AVFILTER_DEFINE_CLASS(fname) \ - AVFILTER_DEFINE_CLASS_EXT(fname, #fname, fname##_options) - -/** - * Find the index of a link. - * - * I.e. find i such that link == ctx->(in|out)puts[i] - */ -#define FF_INLINK_IDX(link) ((int)((link)->dstpad - (link)->dst->input_pads)) -#define FF_OUTLINK_IDX(link) ((int)((link)->srcpad - (link)->src->output_pads)) - -/** - * Send a frame of data to the next filter. - * - * @param link the output link over which the data is being sent - * @param frame a reference to the buffer of data being sent. The - * receiving filter will free this reference when it no longer - * needs it or pass it on to the next filter. - * - * @return >= 0 on success, a negative AVERROR on error. The receiving filter - * is responsible for unreferencing frame in case of error. - */ -int ff_filter_frame(AVFilterLink *link, AVFrame *frame); - -/** - * The filter is aware of hardware frames, and any hardware frame context - * should not be automatically propagated through it. - */ -#define FF_FILTER_FLAG_HWFRAME_AWARE (1 << 0) - -/** - * Run one round of processing on a filter graph. - */ -int ff_filter_graph_run_once(AVFilterGraph *graph); - -/** - * Get number of threads for current filter instance. - * This number is always same or less than graph->nb_threads. - */ -int ff_filter_get_nb_threads(AVFilterContext *ctx) av_pure; - -/** - * Generic processing of user supplied commands that are set - * in the same way as the filter options. - * NOTE: 'enable' option is handled separately, and not by - * this function. - */ -int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, - const char *arg, char *res, int res_len, int flags); - -/** - * Perform any additional setup required for hardware frames. - * - * link->hw_frames_ctx must be set before calling this function. - * Inside link->hw_frames_ctx, the fields format, sw_format, width and - * height must be set. If dynamically allocated pools are not supported, - * then initial_pool_size must also be set, to the minimum hardware frame - * pool size necessary for the filter to work (taking into account any - * frames which need to stored for use in operations as appropriate). If - * default_pool_size is nonzero, then it will be used as the pool size if - * no other modification takes place (this can be used to preserve - * compatibility). - */ -int ff_filter_init_hw_frames(AVFilterContext *avctx, AVFilterLink *link, - int default_pool_size); - -#endif /* AVFILTER_INTERNAL_H */ diff --git a/libavfilter/median_template.c b/libavfilter/median_template.c index 760a0278c..6f719df57 100644 --- a/libavfilter/median_template.c +++ b/libavfilter/median_template.c @@ -22,7 +22,6 @@ #include "libavutil/avassert.h" #include "avfilter.h" -#include "internal.h" #include "video.h" #undef pixel diff --git a/libavfilter/opencl.c b/libavfilter/opencl.c index 48752e953..e91610a10 100644 --- a/libavfilter/opencl.c +++ b/libavfilter/opencl.c @@ -23,6 +23,7 @@ #include "libavutil/mem.h" #include "libavutil/pixdesc.h" +#include "filters.h" #include "opencl.h" static int opencl_filter_set_device(AVFilterContext *avctx, @@ -44,12 +45,13 @@ static int opencl_filter_set_device(AVFilterContext *avctx, int ff_opencl_filter_config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *avctx = inlink->dst; OpenCLFilterContext *ctx = avctx->priv; AVHWFramesContext *input_frames; int err; - if (!inlink->hw_frames_ctx) { + if (!l->hw_frames_ctx) { av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires a " "hardware frames context on the input.\n"); return AVERROR(EINVAL); @@ -59,7 +61,7 @@ int ff_opencl_filter_config_input(AVFilterLink *inlink) if (avctx->inputs[0] != inlink) return 0; - input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data; + input_frames = (AVHWFramesContext*)l->hw_frames_ctx->data; if (input_frames->format != AV_PIX_FMT_OPENCL) return AVERROR(EINVAL); @@ -80,13 +82,14 @@ int ff_opencl_filter_config_input(AVFilterLink *inlink) int ff_opencl_filter_config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; OpenCLFilterContext *ctx = avctx->priv; AVBufferRef *output_frames_ref = NULL; AVHWFramesContext *output_frames; int err; - av_buffer_unref(&outlink->hw_frames_ctx); + av_buffer_unref(&l->hw_frames_ctx); if (!ctx->device_ref) { if (!avctx->hw_device_ctx) { @@ -119,7 +122,7 @@ int ff_opencl_filter_config_output(AVFilterLink *outlink) goto fail; } - outlink->hw_frames_ctx = output_frames_ref; + l->hw_frames_ctx = output_frames_ref; outlink->w = ctx->output_width; outlink->h = ctx->output_height; diff --git a/libavfilter/perlin.c b/libavfilter/perlin.c new file mode 100644 index 000000000..ffad8c1e4 --- /dev/null +++ b/libavfilter/perlin.c @@ -0,0 +1,224 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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 + * Perlin Noise generator, based on code from: + * https://adrianb.io/2014/08/09/perlinnoise.html + * + * Original article from Ken Perlin: + * http://mrl.nyu.edu/~perlin/paper445.pdf + */ + +#include + +#include "libavutil/lfg.h" +#include "libavutil/random_seed.h" +#include "perlin.h" + +static inline int inc(int num, int period) +{ + num++; + if (period > 0) + num %= period; + return num; +} + +static inline double grad(int hash, double x, double y, double z) +{ + // Take the hashed value and take the first 4 bits of it (15 == 0b1111) + int h = hash & 15; + // If the most significant bit (MSB) of the hash is 0 then set u = x. Otherwise y. + double u = h < 8 /* 0b1000 */ ? x : y; + double v; + + // In Ken Perlin's original implementation this was another + // conditional operator (?:), then expanded for readability. + if (h < 4 /* 0b0100 */) + // If the first and second significant bits are 0 set v = y + v = y; + // If the first and second significant bits are 1 set v = x + else if (h == 12 /* 0b1100 */ || h == 14 /* 0b1110 */) + v = x; + else + // If the first and second significant bits are not equal (0/1, 1/0) set v = z + v = z; + + // Use the last 2 bits to decide if u and v are positive or negative. Then return their addition. + return ((h&1) == 0 ? u : -u)+((h&2) == 0 ? v : -v); +} + +static inline double fade(double t) +{ + // Fade function as defined by Ken Perlin. This eases coordinate values + // so that they will "ease" towards integral values. This ends up smoothing + // the final output. + // use Horner method to compute: 6t^5 - 15t^4 + 10t^3 + return t * t * t * (t * (t * 6 - 15) + 10); +} + +static double lerp(double a, double b, double x) +{ + return a + x * (b - a); +} + +// Hash lookup table as defined by Ken Perlin. This is a randomly +// arranged array of all numbers from 0-255 inclusive. +static uint8_t ken_permutations[] = { + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, + 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, + 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, + 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, + 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, + 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, + 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, + 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, + 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, + 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, + 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, + 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, + 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, + 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, + 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 +}; + +int ff_perlin_init(FFPerlin *perlin, double period, int octaves, double persistence, + enum FFPerlinRandomMode random_mode, unsigned int random_seed) +{ + int i; + + perlin->period = period; + perlin->octaves = octaves; + perlin->persistence = persistence; + perlin->random_mode = random_mode; + perlin->random_seed = random_seed; + + if (perlin->random_mode == FF_PERLIN_RANDOM_MODE_KEN) { + for (i = 0; i < 512; i++) { + perlin->permutations[i] = ken_permutations[i % 256]; + } + } else { + AVLFG lfg; + uint8_t random_permutations[256]; + + if (perlin->random_mode == FF_PERLIN_RANDOM_MODE_RANDOM) + perlin->random_seed = av_get_random_seed(); + + av_lfg_init(&lfg, perlin->random_seed); + + for (i = 0; i < 256; i++) { + random_permutations[i] = i; + } + + for (i = 0; i < 256; i++) { + unsigned int random_idx = av_lfg_get(&lfg) % (256-i); + uint8_t random_val = random_permutations[random_idx]; + random_permutations[random_idx] = random_permutations[255-i]; + + perlin->permutations[i] = perlin->permutations[i+256] = random_val; + } + } + + return 0; +} + +static double perlin_get(FFPerlin *perlin, double x, double y, double z) +{ + int xi, yi, zi; + double xf, yf, zf; + double u, v, w; + const uint8_t *p = perlin->permutations; + double period = perlin->period; + int aaa, aba, aab, abb, baa, bba, bab, bbb; + double x1, x2, y1, y2; + + if (perlin->period > 0) { + // If we have any period on, change the coordinates to their "local" repetitions + x = fmod(x, perlin->period); + y = fmod(y, perlin->period); + z = fmod(z, perlin->period); + } + + // Calculate the "unit cube" that the point asked will be located in + // The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that + // plus 1. Next we calculate the location (from 0.0 to 1.0) in that cube. + xi = (int)x & 255; + yi = (int)y & 255; + zi = (int)z & 255; + + xf = x - (int)x; + yf = y - (int)y; + zf = z - (int)z; + + // We also fade the location to smooth the result. + u = fade(xf); + v = fade(yf); + w = fade(zf); + + aaa = p[p[p[ xi ] + yi ] + zi ]; + aba = p[p[p[ xi ] + inc(yi, period)] + zi ]; + aab = p[p[p[ xi ] + yi ] + inc(zi, period)]; + abb = p[p[p[ xi ] + inc(yi, period)] + inc(zi, period)]; + baa = p[p[p[inc(xi, period)] + yi ] + zi ]; + bba = p[p[p[inc(xi, period)] + inc(yi, period)] + zi ]; + bab = p[p[p[inc(xi, period)] + yi ] + inc(zi, period)]; + bbb = p[p[p[inc(xi, period)] + inc(yi, period)] + inc(zi, period)]; + + // The gradient function calculates the dot product between a pseudorandom + // gradient vector and the vector from the input coordinate to the 8 + // surrounding points in its unit cube. + // This is all then lerped together as a sort of weighted average based on the faded (u,v,w) + // values we made earlier. + x1 = lerp(grad(aaa, xf , yf , zf), + grad(baa, xf-1, yf , zf), + u); + x2 = lerp(grad(aba, xf , yf-1, zf), + grad(bba, xf-1, yf-1, zf), + u); + y1 = lerp(x1, x2, v); + + x1 = lerp(grad(aab, xf , yf , zf-1), + grad(bab, xf-1, yf , zf-1), + u); + x2 = lerp(grad(abb, xf , yf-1, zf-1), + grad(bbb, xf-1, yf-1, zf-1), + u); + y2 = lerp(x1, x2, v); + + // For convenience we bound it to 0 - 1 (theoretical min/max before is -1 - 1) + return (lerp(y1, y2, w) + 1) / 2; +} + +double ff_perlin_get(FFPerlin *perlin, double x, double y, double z) +{ + double total = 0; + double frequency = 1; + double amplitude = 1; + double max_value = 0; // Used for normalizing result to 0.0 - 1.0 + + for (int i = 0; i < perlin->octaves; i++) { + total += perlin_get(perlin, x * frequency, y * frequency, z * frequency) * amplitude; + max_value += amplitude; + amplitude *= perlin->persistence; + frequency *= 2; + } + + return total / max_value; +} + diff --git a/libavfilter/perlin.h b/libavfilter/perlin.h new file mode 100644 index 000000000..200c494be --- /dev/null +++ b/libavfilter/perlin.h @@ -0,0 +1,101 @@ +/* + * Perlin noise generator + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Perlin Noise generator + */ + +#ifndef AVFILTER_PERLIN_H +#define AVFILTER_PERLIN_H + +#include + +enum FFPerlinRandomMode { + FF_PERLIN_RANDOM_MODE_RANDOM, + FF_PERLIN_RANDOM_MODE_KEN, + FF_PERLIN_RANDOM_MODE_SEED, + FF_PERLIN_RANDOM_MODE_NB +}; + +/** + * Perlin generator context. This needs to be initialized with the + * parameters used to generate the Perlin noise. + */ +typedef struct FFPerlin { + /** + * spatial repeat period, if negative it is ignored + */ + double period; + + /** + * total number of components making up the noise, each one with + * doubled frequency + */ + int octaves; + + /** + * ratio used to compute the amplitude of the next octave + * component with respect to the previous component + */ + double persistence; + + /** + * permutations array used to compute the Perlin noise hash + */ + uint8_t permutations[512]; + + /** + * define how to compute the permutations array + */ + enum FFPerlinRandomMode random_mode; + + /** + * when random_mode is set FF_PERLIN_RANDOM_MODE_RANDOM, set random + * seed used to compute the permutations array + */ + unsigned int random_seed; +} FFPerlin; + +/** + * Initialize the Perlin noise generator with parameters. + * + * @param perlin Perlin noise generator context + * @param period spatial repeat period, if negative it is ignored + * @param octaves total number of components making up the noise, each one with doubled frequency + * @param persistence define ratio used to compute the amplitude of the next octave + * component with respect to the previous component + * @param random_mode define how to compute the permutations array + * @param random_seed when random_mode is set to FF_PERLIN_RANDOM_MODE_RANDOM, set random + * seed used to compute the permutations array + * @return a negative AVERROR code in case of error, a non negative value otherwise + */ +int ff_perlin_init(FFPerlin *perlin, double period, int octaves, double persistence, + enum FFPerlinRandomMode random_mode, unsigned int random_seed); + +/** + * Compute Perlin noise given the x, y, z coordinates. + * + * @param perlin Perlin noise generator context + * @return normalized value for the perlin noise, in the range [0, 1] + */ +double ff_perlin_get(FFPerlin *perlin, double x, double y, double z); + +#endif /* AVFILTER_PERLIN_H */ diff --git a/libavfilter/phase_template.c b/libavfilter/phase_template.c index c25bc8841..971cb4e34 100644 --- a/libavfilter/phase_template.c +++ b/libavfilter/phase_template.c @@ -20,7 +20,6 @@ #include "libavutil/avassert.h" #include "avfilter.h" -#include "internal.h" #include "video.h" #undef pixel diff --git a/libavfilter/qrencode.c b/libavfilter/qrencode.c index b084bf1d1..dae169b57 100644 --- a/libavfilter/qrencode.c +++ b/libavfilter/qrencode.c @@ -33,13 +33,14 @@ #include "libavutil/internal.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/lfg.h" #include "libavutil/random_seed.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "formats.h" #include "textutils.h" #include "video.h" @@ -283,7 +284,7 @@ static int func_eval_expr_formatted(void *ctx, AVBPrint *bp, const char *functio argv[1][0], positions); } -static FFExpandTextFunction expand_text_functions[] = { +static const FFExpandTextFunction expand_text_functions[] = { { "expr", 1, 1, func_eval_expr }, { "e", 1, 1, func_eval_expr }, { "expr_formatted", 2, 3, func_eval_expr_formatted }, @@ -585,6 +586,7 @@ AVFILTER_DEFINE_CLASS(qrencodesrc); static int qrencodesrc_config_props(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; QREncodeContext *qr = ctx->priv; int ret; @@ -644,7 +646,7 @@ static int qrencodesrc_config_props(AVFilterLink *outlink) outlink->w = qr->rendered_padded_qrcode_width; outlink->h = qr->rendered_padded_qrcode_width; outlink->time_base = av_inv_q(qr->frame_rate); - outlink->frame_rate = qr->frame_rate; + l->frame_rate = qr->frame_rate; return 0; } @@ -777,12 +779,13 @@ static int qrencode_query_formats(AVFilterContext *ctx) static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; QREncodeContext *qr = ctx->priv; int ret; - V(n) = inlink->frame_count_out; + V(n) = inl->frame_count_out; V(t) = frame->pts == AV_NOPTS_VALUE ? NAN : frame->pts * av_q2d(inlink->time_base); V(pict_type) = frame->pict_type; diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c index 5cdba7d54..0818ada11 100644 --- a/libavfilter/qsvvpp.c +++ b/libavfilter/qsvvpp.c @@ -23,10 +23,11 @@ #include "libavutil/common.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/time.h" #include "libavutil/pixdesc.h" -#include "internal.h" +#include "filters.h" #include "qsvvpp.h" #include "video.h" @@ -296,18 +297,19 @@ static int map_frame_to_surface(AVFrame *frame, mfxFrameSurface1 *surface) /* fill the surface info */ static int fill_frameinfo_by_link(mfxFrameInfo *frameinfo, AVFilterLink *link) { + FilterLink *l = ff_filter_link(link); enum AVPixelFormat pix_fmt; AVHWFramesContext *frames_ctx; AVQSVFramesContext *frames_hwctx; const AVPixFmtDescriptor *desc; if (link->format == AV_PIX_FMT_QSV) { - if (!link->hw_frames_ctx) + if (!l->hw_frames_ctx) return AVERROR(EINVAL); - frames_ctx = (AVHWFramesContext *)link->hw_frames_ctx->data; + frames_ctx = (AVHWFramesContext *)l->hw_frames_ctx->data; frames_hwctx = frames_ctx->hwctx; - *frameinfo = frames_hwctx->surfaces[0].Info; + *frameinfo = frames_hwctx->nb_surfaces ? frames_hwctx->surfaces[0].Info : *frames_hwctx->info; } else { pix_fmt = link->format; desc = av_pix_fmt_desc_get(pix_fmt); @@ -333,8 +335,8 @@ static int fill_frameinfo_by_link(mfxFrameInfo *frameinfo, AVFilterLink *link) frameinfo->CropW = link->w; frameinfo->CropH = link->h; - frameinfo->FrameRateExtN = link->frame_rate.num; - frameinfo->FrameRateExtD = link->frame_rate.den; + frameinfo->FrameRateExtN = l->frame_rate.num; + frameinfo->FrameRateExtD = l->frame_rate.den; /* Apparently VPP in the SDK requires the frame rate to be set to some value, otherwise * init will fail */ @@ -440,11 +442,6 @@ static QSVFrame *submit_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *p av_frame_free(&qsv_frame->frame); return NULL; } - - if (av_frame_copy_props(qsv_frame->frame, picref) < 0) { - av_frame_free(&qsv_frame->frame); - return NULL; - } } else qsv_frame->frame = av_frame_clone(picref); @@ -476,6 +473,7 @@ static QSVFrame *submit_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *p /* get the output surface */ static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink, const AVFrame *in) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; QSVFrame *out_frame; int ret; @@ -493,13 +491,7 @@ static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink, const AVFr if (!out_frame->frame) return NULL; - ret = av_frame_copy_props(out_frame->frame, in); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Failed to copy metadata fields from src to dst.\n"); - return NULL; - } - - ret = av_hwframe_get_buffer(outlink->hw_frames_ctx, out_frame->frame, 0); + ret = av_hwframe_get_buffer(l->hw_frames_ctx, out_frame->frame, 0); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Can't allocate a surface.\n"); return NULL; @@ -515,20 +507,14 @@ static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink, const AVFr if (!out_frame->frame) return NULL; - ret = av_frame_copy_props(out_frame->frame, in); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Failed to copy metadata fields from src to dst.\n"); - return NULL; - } - ret = map_frame_to_surface(out_frame->frame, &out_frame->surface); if (ret < 0) return NULL; } - if (outlink->frame_rate.num && outlink->frame_rate.den) - out_frame->frame->duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + if (l->frame_rate.num && l->frame_rate.den) + out_frame->frame->duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base); else out_frame->frame->duration = 0; @@ -562,7 +548,9 @@ FF_ENABLE_DEPRECATION_WARNINGS static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) { AVFilterLink *inlink = avctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); AVFilterLink *outlink = avctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); AVQSVFramesContext *in_frames_hwctx = NULL; AVQSVFramesContext *out_frames_hwctx = NULL; @@ -575,8 +563,8 @@ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) mfxIMPL impl; int ret, i; - if (inlink->hw_frames_ctx) { - AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data; + if (inl->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inl->hw_frames_ctx->data; device_ref = frames_ctx->device_ref; in_frames_hwctx = frames_ctx->hwctx; @@ -603,6 +591,26 @@ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) device_ctx = (AVHWDeviceContext *)device_ref->data; device_hwctx = device_ctx->hwctx; + /* extract the properties of the "master" session given to us */ + ret = MFXQueryIMPL(device_hwctx->session, &impl); + if (ret == MFX_ERR_NONE) + ret = MFXQueryVersion(device_hwctx->session, &ver); + if (ret != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, "Error querying the session attributes\n"); + return AVERROR_UNKNOWN; + } + + if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(impl)) { + handle_type = MFX_HANDLE_VA_DISPLAY; + } else if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(impl)) { + handle_type = MFX_HANDLE_D3D11_DEVICE; + } else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(impl)) { + handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER; + } else { + av_log(avctx, AV_LOG_ERROR, "Error unsupported handle type\n"); + return AVERROR_UNKNOWN; + } + if (outlink->format == AV_PIX_FMT_QSV) { AVHWFramesContext *out_frames_ctx; AVBufferRef *out_frames_ref = av_hwframe_ctx_alloc(device_ref); @@ -624,9 +632,15 @@ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) out_frames_ctx->width = FFALIGN(outlink->w, 32); out_frames_ctx->height = FFALIGN(outlink->h, 32); out_frames_ctx->sw_format = s->out_sw_format; - out_frames_ctx->initial_pool_size = 64; - if (avctx->extra_hw_frames > 0) - out_frames_ctx->initial_pool_size += avctx->extra_hw_frames; + + if (QSV_RUNTIME_VERSION_ATLEAST(ver, 2, 9) && handle_type != MFX_HANDLE_D3D9_DEVICE_MANAGER) + out_frames_ctx->initial_pool_size = 0; + else { + out_frames_ctx->initial_pool_size = 64; + if (avctx->extra_hw_frames > 0) + out_frames_ctx->initial_pool_size += avctx->extra_hw_frames; + } + out_frames_hwctx->frame_type = s->out_mem_mode; ret = av_hwframe_ctx_init(out_frames_ref); @@ -647,31 +661,11 @@ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) s->surface_ptrs_out[i] = out_frames_hwctx->surfaces + i; s->nb_surface_ptrs_out = out_frames_hwctx->nb_surfaces; - av_buffer_unref(&outlink->hw_frames_ctx); - outlink->hw_frames_ctx = out_frames_ref; + av_buffer_unref(&outl->hw_frames_ctx); + outl->hw_frames_ctx = out_frames_ref; } else s->out_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY; - /* extract the properties of the "master" session given to us */ - ret = MFXQueryIMPL(device_hwctx->session, &impl); - if (ret == MFX_ERR_NONE) - ret = MFXQueryVersion(device_hwctx->session, &ver); - if (ret != MFX_ERR_NONE) { - av_log(avctx, AV_LOG_ERROR, "Error querying the session attributes\n"); - return AVERROR_UNKNOWN; - } - - if (MFX_IMPL_VIA_VAAPI == MFX_IMPL_VIA_MASK(impl)) { - handle_type = MFX_HANDLE_VA_DISPLAY; - } else if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(impl)) { - handle_type = MFX_HANDLE_D3D11_DEVICE; - } else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(impl)) { - handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER; - } else { - av_log(avctx, AV_LOG_ERROR, "Error unsupported handle type\n"); - return AVERROR_UNKNOWN; - } - ret = MFXVideoCORE_GetHandle(device_hwctx->session, handle_type, &handle); if (ret < 0) return ff_qsvvpp_print_error(avctx, ret, "Error getting the session handle"); @@ -957,7 +951,7 @@ int ff_qsvvpp_close(AVFilterContext *avctx) return 0; } -int ff_qsvvpp_filter_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *picref) +int ff_qsvvpp_filter_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *picref, AVFrame *propref) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; @@ -1014,6 +1008,16 @@ int ff_qsvvpp_filter_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *picr return AVERROR(EAGAIN); break; } + + if (propref) { + ret1 = av_frame_copy_props(out_frame->frame, propref); + if (ret1 < 0) { + av_frame_free(&out_frame->frame); + av_log(ctx, AV_LOG_ERROR, "Failed to copy metadata fields from src to dst.\n"); + return ret1; + } + } + out_frame->frame->pts = av_rescale_q(out_frame->surface.Data.TimeStamp, default_tb, outlink->time_base); @@ -1099,11 +1103,6 @@ int ff_qsvvpp_create_mfx_session(void *ctx, if (sts < 0) return ff_qsvvpp_print_error(ctx, sts, "Error creating a MFX session"); - else if (sts > 0) { - ff_qsvvpp_print_warning(ctx, sts, - "Warning in MFX session creation"); - return AVERROR_UNKNOWN; - } *psession = session; diff --git a/libavfilter/qsvvpp.h b/libavfilter/qsvvpp.h index 4eea7a46c..3b9192b62 100644 --- a/libavfilter/qsvvpp.h +++ b/libavfilter/qsvvpp.h @@ -131,7 +131,7 @@ int ff_qsvvpp_init(AVFilterContext *avctx, QSVVPPParam *param); int ff_qsvvpp_close(AVFilterContext *avctx); /* vpp filter frame and call the cb if needed */ -int ff_qsvvpp_filter_frame(QSVVPPContext *vpp, AVFilterLink *inlink, AVFrame *frame); +int ff_qsvvpp_filter_frame(QSVVPPContext *vpp, AVFilterLink *inlink, AVFrame *frame, AVFrame *propref); int ff_qsvvpp_print_iopattern(void *log_ctx, int mfx_iopattern, const char *extra_string); diff --git a/libavfilter/riscv/Makefile b/libavfilter/riscv/Makefile index 0b968a9c0..14a4470d9 100644 --- a/libavfilter/riscv/Makefile +++ b/libavfilter/riscv/Makefile @@ -1,2 +1,4 @@ -OBJS += riscv/af_afir_init.o -RVV-OBJS += riscv/af_afir_rvv.o +OBJS-$(CONFIG_AFIR_FILTER) += riscv/af_afir_init.o +RVV-OBJS-$(CONFIG_AFIR_FILTER) += riscv/af_afir_rvv.o + +SHLIBOBJS += riscv/cpu_common.o diff --git a/libavfilter/riscv/af_afir_init.c b/libavfilter/riscv/af_afir_init.c index 52aa18c12..66402f5c1 100644 --- a/libavfilter/riscv/af_afir_init.c +++ b/libavfilter/riscv/af_afir_init.c @@ -34,7 +34,7 @@ av_cold void ff_afir_init_riscv(AudioFIRDSPContext *s) int flags = av_get_cpu_flags(); if (flags & AV_CPU_FLAG_RVV_F64) { - if (flags & AV_CPU_FLAG_RVB_ADDR) { + if (flags & AV_CPU_FLAG_RVB) { s->fcmul_add = ff_fcmul_add_rvv; } } diff --git a/libavfilter/riscv/af_afir_rvv.S b/libavfilter/riscv/af_afir_rvv.S index 04ec2e50d..5ebd020e7 100644 --- a/libavfilter/riscv/af_afir_rvv.S +++ b/libavfilter/riscv/af_afir_rvv.S @@ -21,7 +21,8 @@ #include "libavutil/riscv/asm.S" // void ff_fcmul_add(float *sum, const float *t, const float *c, int len) -func ff_fcmul_add_rvv, zve64f +func ff_fcmul_add_rvv, zve64f, zba + lpad 0 li t1, 32 1: vsetvli t0, a3, e32, m4, ta, ma diff --git a/libavfilter/riscv/cpu_common.c b/libavfilter/riscv/cpu_common.c new file mode 100644 index 000000000..17c9b392c --- /dev/null +++ b/libavfilter/riscv/cpu_common.c @@ -0,0 +1 @@ +#include "libavutil/riscv/cpu_common.c" diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c index 60cf2b642..b92573a7f 100644 --- a/libavfilter/setpts.c +++ b/libavfilter/setpts.c @@ -36,7 +36,6 @@ #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" static const char *const var_names[] = { @@ -131,6 +130,7 @@ static av_cold int init(AVFilterContext *ctx) static int config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; SetPTSContext *setpts = ctx->priv; @@ -142,8 +142,8 @@ static int config_input(AVFilterLink *inlink) setpts->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN; V(FRAME_RATE) = V(FR) = - inlink->frame_rate.num && inlink->frame_rate.den ? - av_q2d(inlink->frame_rate) : NAN; + l->frame_rate.num && l->frame_rate.den ? + av_q2d(l->frame_rate) : NAN; av_log(inlink->src, AV_LOG_VERBOSE, "TB:%f FRAME_RATE:%f SAMPLE_RATE:%f\n", V(TB), V(FRAME_RATE), V(SAMPLE_RATE)); @@ -152,7 +152,9 @@ static int config_input(AVFilterLink *inlink) static int config_output_video(AVFilterLink *outlink) { - outlink->frame_rate = (AVRational){ 1, 0 }; + FilterLink *l = ff_filter_link(outlink); + + l->frame_rate = (AVRational){ 1, 0 }; return 0; } diff --git a/libavfilter/settb.c b/libavfilter/settb.c index ba58abd9e..e6a227283 100644 --- a/libavfilter/settb.c +++ b/libavfilter/settb.c @@ -37,7 +37,6 @@ #include "audio.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" static const char *const var_names[] = { diff --git a/libavfilter/signature.h b/libavfilter/signature.h index cc198dbaa..c6b57cc05 100644 --- a/libavfilter/signature.h +++ b/libavfilter/signature.h @@ -31,7 +31,6 @@ #include "libavutil/opt.h" #include "libavutil/timestamp.h" #include "avfilter.h" -#include "internal.h" #define ELEMENT_COUNT 10 #define SIGELEM_SIZE 380 diff --git a/libavfilter/signature_lookup.c b/libavfilter/signature_lookup.c index ad59106cf..46602874d 100644 --- a/libavfilter/signature_lookup.c +++ b/libavfilter/signature_lookup.c @@ -23,6 +23,7 @@ * MPEG-7 video signature calculation and lookup filter */ +#include "libavutil/mem.h" #include "signature.h" #define HOUGH_MAX_OFFSET 90 @@ -126,9 +127,10 @@ static int get_jaccarddist(SignatureContext *sc, CoarseSignature *first, CoarseS { int jaccarddist, i, composdist = 0, cwthcount = 0; for (i = 0; i < 5; i++) { - if ((jaccarddist = intersection_word(first->data[i], second->data[i])) > 0) { + if ((jaccarddist = (1 << 16) * intersection_word(first->data[i], second->data[i])) > 0) { jaccarddist /= union_word(first->data[i], second->data[i]); } + jaccarddist = (1 << 16) - jaccarddist; if (jaccarddist >= sc->thworddist) { if (++cwthcount > 2) { /* more than half (5/2) of distances are too wide */ diff --git a/libavfilter/split.c b/libavfilter/split.c index 7935f2d51..8309cdb4e 100644 --- a/libavfilter/split.c +++ b/libavfilter/split.c @@ -33,7 +33,6 @@ #include "avfilter.h" #include "audio.h" #include "filters.h" -#include "internal.h" #include "video.h" typedef struct SplitContext { diff --git a/libavfilter/src_avsynctest.c b/libavfilter/src_avsynctest.c index 9fd0b590c..f78cdd1de 100644 --- a/libavfilter/src_avsynctest.c +++ b/libavfilter/src_avsynctest.c @@ -32,7 +32,6 @@ #include "drawutils.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "audio.h" #include "video.h" @@ -145,13 +144,14 @@ static av_cold int aconfig_props(AVFilterLink *outlink) static av_cold int config_props(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVSyncTestContext *s = ctx->priv; outlink->w = s->w; outlink->h = s->h; outlink->time_base = av_inv_q(s->frame_rate); - outlink->frame_rate = s->frame_rate; + l->frame_rate = s->frame_rate; outlink->sample_aspect_ratio = (AVRational) {1, 1}; s->delay_min = av_mul_q(s->frame_rate, av_make_q(-1, 2)); s->delay_max = av_mul_q(s->delay_min, av_make_q(-1, 1)); diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c index e50ebc99d..e7817c7ee 100644 --- a/libavfilter/src_movie.c +++ b/libavfilter/src_movie.c @@ -28,16 +28,14 @@ #include "config_components.h" -#include #include #include "libavutil/attributes.h" #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/imgutils.h" #include "libavutil/internal.h" -#include "libavutil/timestamp.h" #include "libavcodec/avcodec.h" @@ -47,7 +45,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct MovieStream { @@ -452,6 +449,7 @@ static int movie_query_formats(AVFilterContext *ctx) static int movie_config_output_props(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; MovieContext *movie = ctx->priv; unsigned out_id = FF_OUTLINK_IDX(outlink); @@ -464,7 +462,7 @@ static int movie_config_output_props(AVFilterLink *outlink) case AVMEDIA_TYPE_VIDEO: outlink->w = c->width; outlink->h = c->height; - outlink->frame_rate = st->st->r_frame_rate; + l->frame_rate = st->st->r_frame_rate; break; case AVMEDIA_TYPE_AUDIO: break; diff --git a/libavfilter/stack_internal.c b/libavfilter/stack_internal.c index 1ee20d66c..b473fa982 100644 --- a/libavfilter/stack_internal.c +++ b/libavfilter/stack_internal.c @@ -52,9 +52,11 @@ static int init_framesync(AVFilterContext *avctx) static int config_comm_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; StackBaseContext *sctx = avctx->priv; AVFilterLink *inlink0 = avctx->inputs[0]; + FilterLink *inl0 = ff_filter_link(inlink0); int width, height, ret; if (sctx->mode == STACK_H) { @@ -197,16 +199,16 @@ static int config_comm_output(AVFilterLink *outlink) outlink->w = width; outlink->h = height; - outlink->frame_rate = inlink0->frame_rate; + outl->frame_rate = inl0->frame_rate; outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio; for (int i = 1; i < sctx->nb_inputs; i++) { - AVFilterLink *inlink = avctx->inputs[i]; - if (outlink->frame_rate.num != inlink->frame_rate.num || - outlink->frame_rate.den != inlink->frame_rate.den) { + FilterLink *inlink = ff_filter_link(avctx->inputs[i]); + if (outl->frame_rate.num != inlink->frame_rate.num || + outl->frame_rate.den != inlink->frame_rate.den) { av_log(avctx, AV_LOG_VERBOSE, "Video inputs have different frame rates, output will be VFR\n"); - outlink->frame_rate = av_make_q(1, 0); + outl->frame_rate = av_make_q(1, 0); break; } } diff --git a/libavfilter/tests/filtfmts.c b/libavfilter/tests/filtfmts.c index 194792078..4ef696882 100644 --- a/libavfilter/tests/filtfmts.c +++ b/libavfilter/tests/filtfmts.c @@ -29,7 +29,6 @@ #include "libavfilter/avfilter_internal.h" #include "libavfilter/formats.h" #include "libavfilter/framequeue.h" -#include "libavfilter/internal.h" static void print_formats_internal(AVFilterLink **links, const AVFilterPad *pads, unsigned nb, size_t fmts_cfg_offset, @@ -144,7 +143,24 @@ int main(int argc, char **argv) if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC) ret = filter->formats.query_func(filter_ctx); - else + else if (filter->formats_state == FF_FILTER_FORMATS_QUERY_FUNC2) { + AVFilterFormatsConfig **cfg_in = NULL, **cfg_out = NULL; + + if (filter_ctx->nb_inputs) { + cfg_in = av_malloc_array(filter_ctx->nb_inputs, sizeof(*cfg_in)); + for (unsigned i = 0; i < filter_ctx->nb_inputs; i++) + cfg_in[i] = &filter_ctx->inputs[i]->outcfg; + } + if (filter_ctx->nb_outputs) { + cfg_out = av_malloc_array(filter_ctx->nb_outputs, sizeof(*cfg_out)); + for (unsigned i = 0; i < filter_ctx->nb_outputs; i++) + cfg_out[i] = &filter_ctx->outputs[i]->incfg; + } + + ret = filter->formats.query_func2(filter_ctx, cfg_in, cfg_out); + av_freep(&cfg_in); + av_freep(&cfg_out); + } else ret = ff_default_query_formats(filter_ctx); print_formats(filter_ctx); diff --git a/libavfilter/tests/formats.c b/libavfilter/tests/formats.c index ed1de24a4..5cc3ca337 100644 --- a/libavfilter/tests/formats.c +++ b/libavfilter/tests/formats.c @@ -19,6 +19,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavfilter/audio.h" #include "libavfilter/formats.c" #undef printf diff --git a/libavfilter/tests/integral.c b/libavfilter/tests/integral.c index 6bdf0fd7f..3d9487f6b 100644 --- a/libavfilter/tests/integral.c +++ b/libavfilter/tests/integral.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavfilter/vf_nlmeans.c" static void display_integral(const uint32_t *ii, int w, int h, int lz_32) diff --git a/libavfilter/textutils.c b/libavfilter/textutils.c index ef658d04a..e6b5239b2 100644 --- a/libavfilter/textutils.c +++ b/libavfilter/textutils.c @@ -29,13 +29,14 @@ #include "libavutil/avutil.h" #include "libavutil/error.h" #include "libavutil/file.h" +#include "libavutil/mem.h" #include "libavutil/time.h" static int ff_expand_text_function_internal(FFExpandTextContext *expand_text, AVBPrint *bp, char *name, unsigned argc, char **argv) { void *log_ctx = expand_text->log_ctx; - FFExpandTextFunction *functions = expand_text->functions; + const FFExpandTextFunction *functions = expand_text->functions; unsigned i; for (i = 0; i < expand_text->functions_nb; i++) { @@ -78,7 +79,7 @@ static int ff_expand_text_function_internal(FFExpandTextContext *expand_text, AV * @return negative value corresponding to an AVERROR error code in case of * errors, a non-negative value otherwise */ -static int ff_expand_text_function(FFExpandTextContext *expand_text, AVBPrint *bp, char **rtext) +static int ff_expand_text_function(FFExpandTextContext *expand_text, AVBPrint *bp, const char **rtext) { void *log_ctx = expand_text->log_ctx; const char *text = *rtext; @@ -111,7 +112,7 @@ static int ff_expand_text_function(FFExpandTextContext *expand_text, AVBPrint *b if ((ret = ff_expand_text_function_internal(expand_text, bp, argv[0], argc - 1, argv + 1)) < 0) goto end; ret = 0; - *rtext = (char *)text + 1; + *rtext = text + 1; end: for (i = 0; i < argc; i++) @@ -119,7 +120,7 @@ end: return ret; } -int ff_expand_text(FFExpandTextContext *expand_text, char *text, AVBPrint *bp) +int ff_expand_text(FFExpandTextContext *expand_text, const char *text, AVBPrint *bp) { int ret; diff --git a/libavfilter/textutils.h b/libavfilter/textutils.h index 7fa856c68..8c2399d15 100644 --- a/libavfilter/textutils.h +++ b/libavfilter/textutils.h @@ -74,7 +74,7 @@ typedef struct FFExpandTextContext { * list of functions to use to expand sequences in the format * FUNCTION_NAME{PARAMS} */ - FFExpandTextFunction *functions; + const FFExpandTextFunction *functions; /** * number of functions @@ -94,7 +94,7 @@ typedef struct FFExpandTextContext { * @return negative value corresponding to an AVERROR error code in case of * errors, a non-negative value otherwise */ -int ff_expand_text(FFExpandTextContext *expand_text, char *text, AVBPrint *bp); +int ff_expand_text(FFExpandTextContext *expand_text, const char *text, AVBPrint *bp); /** * Print PTS representation to an AVBPrint object. diff --git a/libavfilter/trim.c b/libavfilter/trim.c index 4c1a2b4f4..a795d7541 100644 --- a/libavfilter/trim.c +++ b/libavfilter/trim.c @@ -30,7 +30,6 @@ #include "audio.h" #include "avfilter.h" -#include "internal.h" #include "filters.h" #include "video.h" @@ -364,6 +363,7 @@ const AVFilter ff_vf_trim = { .activate = activate, .priv_size = sizeof(TrimContext), .priv_class = &trim_class, + .flags = AVFILTER_FLAG_METADATA_ONLY, FILTER_INPUTS(trim_inputs), FILTER_OUTPUTS(ff_video_default_filterpad), }; diff --git a/libavfilter/unsharp.h b/libavfilter/unsharp.h deleted file mode 100644 index 0da6f0503..000000000 --- a/libavfilter/unsharp.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVFILTER_UNSHARP_H -#define AVFILTER_UNSHARP_H - -#include "config.h" -#include "avfilter.h" - -#define MIN_MATRIX_SIZE 3 -#define MAX_MATRIX_SIZE 63 - - -typedef struct UnsharpFilterParam { - int msize_x; ///< matrix width - int msize_y; ///< matrix height - int amount; ///< effect amount - int steps_x; ///< horizontal step count - int steps_y; ///< vertical step count - int scalebits; ///< bits to shift pixel - int32_t halfscale; ///< amount to add to pixel - uint32_t *sr; ///< finite state machine storage within a row - uint32_t **sc; ///< finite state machine storage across rows -} UnsharpFilterParam; - -typedef struct UnsharpContext { - const AVClass *class; - int lmsize_x, lmsize_y, cmsize_x, cmsize_y; - int amsize_x, amsize_y; - float lamount, camount; - float aamount; - UnsharpFilterParam luma; ///< luma parameters (width, height, amount) - UnsharpFilterParam chroma; ///< chroma parameters (width, height, amount) - UnsharpFilterParam alpha; ///< alpha parameters (width, height, amount) - int hsub, vsub; - int nb_planes; - int bitdepth; - int bps; - int nb_threads; - int (* apply_unsharp)(AVFilterContext *ctx, AVFrame *in, AVFrame *out); - int (* unsharp_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); -} UnsharpContext; - -#endif /* AVFILTER_UNSHARP_H */ diff --git a/libavfilter/vaapi_vpp.c b/libavfilter/vaapi_vpp.c index 59961bfa4..0179977af 100644 --- a/libavfilter/vaapi_vpp.c +++ b/libavfilter/vaapi_vpp.c @@ -19,9 +19,11 @@ #include #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" + +#include "filters.h" #include "formats.h" -#include "internal.h" #include "vaapi_vpp.h" int ff_vaapi_vpp_query_formats(AVFilterContext *avctx) @@ -73,19 +75,20 @@ void ff_vaapi_vpp_pipeline_uninit(AVFilterContext *avctx) int ff_vaapi_vpp_config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *avctx = inlink->dst; VAAPIVPPContext *ctx = avctx->priv; if (ctx->pipeline_uninit) ctx->pipeline_uninit(avctx); - if (!inlink->hw_frames_ctx) { + if (!l->hw_frames_ctx) { av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " "required to associate the processing device.\n"); return AVERROR(EINVAL); } - ctx->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx); + ctx->input_frames_ref = av_buffer_ref(l->hw_frames_ctx); if (!ctx->input_frames_ref) { av_log(avctx, AV_LOG_ERROR, "A input frames reference create " "failed.\n"); @@ -98,8 +101,10 @@ int ff_vaapi_vpp_config_input(AVFilterLink *inlink) int ff_vaapi_vpp_config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; AVFilterLink *inlink = avctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); VAAPIVPPContext *ctx = avctx->priv; AVVAAPIHWConfig *hwconfig = NULL; AVHWFramesConstraints *constraints = NULL; @@ -120,8 +125,8 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink) outlink->h = ctx->output_height; if (ctx->passthrough) { - if (inlink->hw_frames_ctx) - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); + if (inl->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); av_log(ctx, AV_LOG_VERBOSE, "Using VAAPI filter passthrough mode.\n"); return 0; @@ -188,28 +193,31 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink) goto fail; } - outlink->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->device_ref); - if (!outlink->hw_frames_ctx) { + outl->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->device_ref); + if (!outl->hw_frames_ctx) { av_log(avctx, AV_LOG_ERROR, "Failed to create HW frame context " "for output.\n"); err = AVERROR(ENOMEM); goto fail; } - output_frames = (AVHWFramesContext*)outlink->hw_frames_ctx->data; + output_frames = (AVHWFramesContext*)outl->hw_frames_ctx->data; output_frames->format = AV_PIX_FMT_VAAPI; output_frames->sw_format = ctx->output_format; output_frames->width = ctx->output_width; output_frames->height = ctx->output_height; - output_frames->initial_pool_size = 4; + if (CONFIG_VAAPI_1) + output_frames->initial_pool_size = 0; + else + output_frames->initial_pool_size = 4; err = ff_filter_init_hw_frames(avctx, outlink, 10); if (err < 0) goto fail; - err = av_hwframe_ctx_init(outlink->hw_frames_ctx); + err = av_hwframe_ctx_init(outl->hw_frames_ctx); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise VAAPI frame " "context for output: %d\n", err); @@ -219,6 +227,8 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink) va_frames = output_frames->hwctx; av_assert0(ctx->va_context == VA_INVALID_ID); + av_assert0(output_frames->initial_pool_size || + (va_frames->surface_ids == NULL && va_frames->nb_surfaces == 0)); vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, ctx->output_width, ctx->output_height, VA_PROGRESSIVE, @@ -241,7 +251,7 @@ int ff_vaapi_vpp_config_output(AVFilterLink *outlink) return 0; fail: - av_buffer_unref(&outlink->hw_frames_ctx); + av_buffer_unref(&outl->hw_frames_ctx); av_freep(&hwconfig); av_hwframe_constraints_free(&constraints); return err; diff --git a/libavfilter/vaf_spectrumsynth.c b/libavfilter/vaf_spectrumsynth.c index 3a9aacd2b..a62151aa4 100644 --- a/libavfilter/vaf_spectrumsynth.c +++ b/libavfilter/vaf_spectrumsynth.c @@ -24,19 +24,16 @@ * @todo support float pixel format */ +#include "libavutil/mem.h" #include "libavutil/tx.h" #include "libavutil/avassert.h" -#include "libavutil/channel_layout.h" #include "libavutil/cpu.h" #include "libavutil/ffmath.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "avfilter.h" #include "formats.h" #include "audio.h" -#include "video.h" #include "filters.h" -#include "internal.h" #include "window_func.h" enum MagnitudeScale { LINEAR, LOG, NB_SCALES }; @@ -142,10 +139,12 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; SpectrumSynthContext *s = ctx->priv; + FilterLink *inl0 = ff_filter_link(ctx->inputs[0]); + FilterLink *inl1 = ff_filter_link(ctx->inputs[1]); int width = ctx->inputs[0]->w; int height = ctx->inputs[0]->h; AVRational time_base = ctx->inputs[0]->time_base; - AVRational frame_rate = ctx->inputs[0]->frame_rate; + AVRational frame_rate = inl0->frame_rate; float factor, overlap, scale; int i, ch, ret; @@ -166,12 +165,12 @@ static int config_output(AVFilterLink *outlink) ctx->inputs[1]->time_base.num, ctx->inputs[1]->time_base.den); return AVERROR_INVALIDDATA; - } else if (av_cmp_q(frame_rate, ctx->inputs[1]->frame_rate) != 0) { + } else if (av_cmp_q(frame_rate, inl1->frame_rate) != 0) { av_log(ctx, AV_LOG_ERROR, "Magnitude and Phase framerates differ (%d/%d vs %d/%d).\n", frame_rate.num, frame_rate.den, - ctx->inputs[1]->frame_rate.num, - ctx->inputs[1]->frame_rate.den); + inl1->frame_rate.num, + inl1->frame_rate.den); return AVERROR_INVALIDDATA; } diff --git a/libavfilter/version.c b/libavfilter/version.c index db1a2511e..54c286460 100644 --- a/libavfilter/version.c +++ b/libavfilter/version.c @@ -18,8 +18,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "config.h" -#include "libavutil/avassert.h" #include "avfilter.h" #include "version.h" @@ -28,7 +29,7 @@ const char av_filter_ffversion[] = "FFmpeg version " FFMPEG_VERSION; unsigned avfilter_version(void) { - av_assert0(LIBAVFILTER_VERSION_MICRO >= 100); + static_assert(LIBAVFILTER_VERSION_MICRO >= 100, "micro version starts at 100"); return LIBAVFILTER_VERSION_INT; } diff --git a/libavfilter/version.h b/libavfilter/version.h index 1e884d9b4..4d8f28e51 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -31,7 +31,7 @@ #include "version_major.h" -#define LIBAVFILTER_VERSION_MINOR 1 +#define LIBAVFILTER_VERSION_MINOR 4 #define LIBAVFILTER_VERSION_MICRO 100 diff --git a/libavfilter/vf_addroi.c b/libavfilter/vf_addroi.c index e7ad91621..d6765e9d8 100644 --- a/libavfilter/vf_addroi.c +++ b/libavfilter/vf_addroi.c @@ -20,7 +20,7 @@ #include "libavutil/eval.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum { @@ -39,6 +39,7 @@ enum { static const char *const addroi_var_names[] = { "iw", "ih", + NULL, }; typedef struct AddROIContext { diff --git a/libavfilter/vf_alphamerge.c b/libavfilter/vf_alphamerge.c index a5f5baf77..2abb7e558 100644 --- a/libavfilter/vf_alphamerge.c +++ b/libavfilter/vf_alphamerge.c @@ -33,7 +33,6 @@ #include "formats.h" #include "filters.h" #include "framesync.h" -#include "internal.h" #include "video.h" enum { Y, U, V, A }; @@ -128,9 +127,11 @@ static int config_input_main(AVFilterLink *inlink) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AlphaMergeContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *ml = ff_filter_link(mainlink); AVFilterLink *alphalink = ctx->inputs[1]; int ret; @@ -149,7 +150,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + outl->frame_rate = ml->frame_rate; return ff_framesync_configure(&s->fs); } diff --git a/libavfilter/vf_amplify.c b/libavfilter/vf_amplify.c index 0ebca60ea..69d751593 100644 --- a/libavfilter/vf_amplify.c +++ b/libavfilter/vf_amplify.c @@ -19,11 +19,12 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct AmplifyContext { diff --git a/libavfilter/vf_aspect.c b/libavfilter/vf_aspect.c index 129ae19d6..5b4b9fd6e 100644 --- a/libavfilter/vf_aspect.c +++ b/libavfilter/vf_aspect.c @@ -35,7 +35,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" static const char *const var_names[] = { diff --git a/libavfilter/vf_atadenoise.c b/libavfilter/vf_atadenoise.c index da132db1b..bb60ce849 100644 --- a/libavfilter/vf_atadenoise.c +++ b/libavfilter/vf_atadenoise.c @@ -34,7 +34,7 @@ #include "bufferqueue.h" #include "atadenoise.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define SIZE FF_BUFQUEUE_SIZE diff --git a/libavfilter/vf_avgblur.c b/libavfilter/vf_avgblur.c index d1ce029b5..013d83b1b 100644 --- a/libavfilter/vf_avgblur.c +++ b/libavfilter/vf_avgblur.c @@ -22,10 +22,11 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct AverageBlurContext { diff --git a/libavfilter/vf_avgblur_opencl.c b/libavfilter/vf_avgblur_opencl.c index c00d2f636..0790f25a2 100644 --- a/libavfilter/vf_avgblur_opencl.c +++ b/libavfilter/vf_avgblur_opencl.c @@ -26,7 +26,7 @@ #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" @@ -47,8 +47,8 @@ typedef struct AverageBlurOpenCLContext { FilterParam luma_param; FilterParam chroma_param; FilterParam alpha_param; - int radius[4]; - int power[4]; + int radius[AV_VIDEO_MAX_PLANES]; + int power[AV_VIDEO_MAX_PLANES]; } AverageBlurOpenCLContext; @@ -101,7 +101,7 @@ static int avgblur_opencl_make_filter_params(AVFilterLink *inlink) s->radiusV = s->radiusH; } - for (i = 0; i < 4; i++) { + for (i = 0; i < AV_VIDEO_MAX_PLANES; i++) { s->power[i] = 1; } return 0; @@ -133,7 +133,7 @@ static int boxblur_opencl_make_filter_params(AVFilterLink *inlink) s->power[U] = s->power[V] = s->chroma_param.power; s->power[A] = s->alpha_param.power; - for (i = 0; i < 4; i++) { + for (i = 0; i < AV_VIDEO_MAX_PLANES; i++) { if (s->power[i] == 0) { s->power[i] = 1; s->radius[i] = 0; @@ -191,7 +191,7 @@ static int avgblur_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) goto fail; } - for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { + for (p = 0; p < FFMIN(FF_ARRAY_ELEMS(output->data), AV_VIDEO_MAX_PLANES); p++) { src = (cl_mem) input->data[p]; dst = (cl_mem) output->data[p]; inter = (cl_mem)intermediate->data[p]; diff --git a/libavfilter/vf_avgblur_vulkan.c b/libavfilter/vf_avgblur_vulkan.c index 6bc1b616a..439766968 100644 --- a/libavfilter/vf_avgblur_vulkan.c +++ b/libavfilter/vf_avgblur_vulkan.c @@ -22,7 +22,8 @@ #include "libavutil/opt.h" #include "vulkan_filter.h" #include "vulkan_spirv.h" -#include "internal.h" + +#include "filters.h" #include "video.h" typedef struct AvgBlurVulkanContext { diff --git a/libavfilter/vf_backgroundkey.c b/libavfilter/vf_backgroundkey.c index 26fb08bf8..4a6ee5380 100644 --- a/libavfilter/vf_backgroundkey.c +++ b/libavfilter/vf_backgroundkey.c @@ -16,10 +16,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct BackgroundkeyContext { diff --git a/libavfilter/vf_bbox.c b/libavfilter/vf_bbox.c index 02893d500..b4f74dca6 100644 --- a/libavfilter/vf_bbox.c +++ b/libavfilter/vf_bbox.c @@ -28,7 +28,7 @@ #include "libavutil/timestamp.h" #include "avfilter.h" #include "bbox.h" -#include "internal.h" +#include "filters.h" typedef struct BBoxContext { const AVClass *class; @@ -75,6 +75,7 @@ static const enum AVPixelFormat pix_fmts[] = { static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; BBoxContext *bbox = ctx->priv; FFBoundingBox box; @@ -88,7 +89,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) h = box.y2 - box.y1 + 1; av_log(ctx, AV_LOG_INFO, - "n:%"PRId64" pts:%s pts_time:%s", inlink->frame_count_out, + "n:%"PRId64" pts:%s pts_time:%s", inl->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base)); if (has_bbox) { diff --git a/libavfilter/vf_bilateral.c b/libavfilter/vf_bilateral.c index fe1641902..66cc56d1c 100644 --- a/libavfilter/vf_bilateral.c +++ b/libavfilter/vf_bilateral.c @@ -22,10 +22,11 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct BilateralContext { diff --git a/libavfilter/vf_bilateral_cuda.c b/libavfilter/vf_bilateral_cuda.c index ba008b517..5e13acd33 100644 --- a/libavfilter/vf_bilateral_cuda.c +++ b/libavfilter/vf_bilateral_cuda.c @@ -30,7 +30,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "cuda/load_helper.h" @@ -178,16 +178,18 @@ static av_cold void set_format_info(AVFilterContext *ctx, enum AVPixelFormat in_ static av_cold int init_processing_chain(AVFilterContext *ctx, int width, int height) { + FilterLink *inl = ff_filter_link(ctx->inputs[0]); + FilterLink *outl = ff_filter_link(ctx->outputs[0]); CUDABilateralContext *s = ctx->priv; AVHWFramesContext *in_frames_ctx; int ret; /* check that we have a hw context */ - if (!ctx->inputs[0]->hw_frames_ctx) { + if (!inl->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n"); return AVERROR(EINVAL); } - in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; + in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; if (!format_is_supported(in_frames_ctx->sw_format)) { av_log(ctx, AV_LOG_ERROR, "Unsupported format: %s\n", av_get_pix_fmt_name(in_frames_ctx->sw_format)); @@ -200,8 +202,8 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int width, int he if (ret < 0) return ret; - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx); - if (!ctx->outputs[0]->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); return 0; @@ -248,18 +250,22 @@ static av_cold int cuda_bilateral_config_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); CUDABilateralContext *s = ctx->priv; - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; - AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + AVHWFramesContext *frames_ctx; + AVCUDADeviceContext *device_hwctx; int ret; - s->hwctx = device_hwctx; - s->cu_stream = s->hwctx->stream; - ret = init_processing_chain(ctx, inlink->w, inlink->h); if (ret < 0) return ret; + frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; + device_hwctx = frames_ctx->device_ctx->hwctx; + + s->hwctx = device_hwctx; + s->cu_stream = s->hwctx->stream; + outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; // the window_size makes more sense when it is odd, so add 1 if even diff --git a/libavfilter/vf_bitplanenoise.c b/libavfilter/vf_bitplanenoise.c index 32235ff23..24377d1fe 100644 --- a/libavfilter/vf_bitplanenoise.c +++ b/libavfilter/vf_bitplanenoise.c @@ -21,7 +21,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct BPNContext { diff --git a/libavfilter/vf_blackdetect.c b/libavfilter/vf_blackdetect.c index 55033ba5e..ac74ef74a 100644 --- a/libavfilter/vf_blackdetect.c +++ b/libavfilter/vf_blackdetect.c @@ -25,11 +25,12 @@ */ #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/timestamp.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct BlackDetectContext { @@ -172,6 +173,7 @@ static int black_counter(AVFilterContext *ctx, void *arg, static int filter_frame(AVFilterLink *inlink, AVFrame *picref) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; BlackDetectContext *s = ctx->priv; double picture_black_ratio = 0; @@ -194,7 +196,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) av_log(ctx, AV_LOG_DEBUG, "frame:%"PRId64" picture_black_ratio:%f pts:%s t:%s type:%c\n", - inlink->frame_count_out, picture_black_ratio, + inl->frame_count_out, picture_black_ratio, av_ts2str(picref->pts), av_ts2timestr(picref->pts, &s->time_base), av_get_picture_type_char(picref->pict_type)); diff --git a/libavfilter/vf_blackframe.c b/libavfilter/vf_blackframe.c index 10062c995..7b74aa61b 100644 --- a/libavfilter/vf_blackframe.c +++ b/libavfilter/vf_blackframe.c @@ -33,7 +33,7 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct BlackFrameContext { diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c index 74bc5989d..2e5dc9386 100644 --- a/libavfilter/vf_blend.c +++ b/libavfilter/vf_blend.c @@ -21,11 +21,12 @@ #include "config_components.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixfmt.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "vf_blend_init.h" #include "video.h" #include "blend.h" @@ -46,6 +47,7 @@ typedef struct BlendContext { FilterParams params[4]; int tblend; AVFrame *prev_frame; /* only used with tblend */ + int nb_threads; } BlendContext; static const char *const var_names[] = { "X", "Y", "W", "H", "SW", "SH", "T", "N", "A", "B", "TOP", "BOTTOM", NULL }; @@ -131,12 +133,14 @@ static void blend_expr_## name(const uint8_t *_top, ptrdiff_t top_linesize, const uint8_t *_bottom, ptrdiff_t bottom_linesize, \ uint8_t *_dst, ptrdiff_t dst_linesize, \ ptrdiff_t width, ptrdiff_t height, \ - FilterParams *param, double *values, int starty) \ + FilterParams *param, SliceParams *sliceparam) \ { \ const type *top = (const type*)_top; \ const type *bottom = (const type*)_bottom; \ + double *values = sliceparam->values; \ + int starty = sliceparam->starty; \ type *dst = (type*)_dst; \ - AVExpr *e = param->e; \ + AVExpr *e = sliceparam->e; \ int y, x; \ dst_linesize /= div; \ top_linesize /= div; \ @@ -169,9 +173,11 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) const uint8_t *top = td->top->data[td->plane]; const uint8_t *bottom = td->bottom->data[td->plane]; uint8_t *dst = td->dst->data[td->plane]; + FilterLink *inl = ff_filter_link(td->inlink); double values[VAR_VARS_NB]; + SliceParams sliceparam = {.values = &values[0], .starty = slice_start, .e = td->param->e ? td->param->e[jobnr] : NULL}; - values[VAR_N] = td->inlink->frame_count_out; + values[VAR_N] = inl->frame_count_out; values[VAR_T] = td->dst->pts == AV_NOPTS_VALUE ? NAN : td->dst->pts * av_q2d(td->inlink->time_base); values[VAR_W] = td->w; values[VAR_H] = td->h; @@ -184,7 +190,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) td->bottom->linesize[td->plane], dst + slice_start * td->dst->linesize[td->plane], td->dst->linesize[td->plane], - td->w, height, td->param, &values[0], slice_start); + td->w, height, td->param, &sliceparam); return 0; } @@ -217,7 +223,7 @@ static AVFrame *blend_frame(AVFilterContext *ctx, AVFrame *top_buf, .inlink = inlink }; ff_filter_execute(ctx, filter_slice, &td, NULL, - FFMIN(outh, ff_filter_get_nb_threads(ctx))); + FFMIN(outh, s->nb_threads)); } if (!s->tblend) @@ -246,6 +252,7 @@ static av_cold int init(AVFilterContext *ctx) BlendContext *s = ctx->priv; s->tblend = !strcmp(ctx->filter->name, "tblend"); + s->nb_threads = ff_filter_get_nb_threads(ctx); s->fs.on_event = blend_frame_for_dualinput; return 0; @@ -280,8 +287,14 @@ static av_cold void uninit(AVFilterContext *ctx) ff_framesync_uninit(&s->fs); av_frame_free(&s->prev_frame); - for (i = 0; i < FF_ARRAY_ELEMS(s->params); i++) - av_expr_free(s->params[i].e); + for (i = 0; i < FF_ARRAY_ELEMS(s->params); i++) { + if (s->params[i].e) { + for (int j = 0; j < s->nb_threads; j++) + av_expr_free(s->params[i].e[j]); + av_freep(&s->params[i].e); + } + } + } static int config_params(AVFilterContext *ctx) @@ -305,10 +318,19 @@ static int config_params(AVFilterContext *ctx) return AVERROR(ENOMEM); } if (param->expr_str) { - ret = av_expr_parse(¶m->e, param->expr_str, var_names, - NULL, NULL, NULL, NULL, 0, ctx); - if (ret < 0) - return ret; + if (!param->e) { + param->e = av_calloc(s->nb_threads, sizeof(*param->e)); + if (!param->e) + return AVERROR(ENOMEM); + } + for (int i = 0; i < s->nb_threads; i++) { + av_expr_free(param->e[i]); + param->e[i] = NULL; + ret = av_expr_parse(¶m->e[i], param->expr_str, var_names, + NULL, NULL, NULL, NULL, 0, ctx); + if (ret < 0) + return ret; + } param->blend = s->depth > 8 ? s->depth > 16 ? blend_expr_32bit : blend_expr_16bit : blend_expr_8bit; } } @@ -318,8 +340,10 @@ static int config_params(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *toplink = ctx->inputs[TOP]; + FilterLink *tl = ff_filter_link(toplink); BlendContext *s = ctx->priv; const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(toplink->format); int ret; @@ -341,7 +365,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = toplink->h; outlink->time_base = toplink->time_base; outlink->sample_aspect_ratio = toplink->sample_aspect_ratio; - outlink->frame_rate = toplink->frame_rate; + outl->frame_rate = tl->frame_rate; s->hsub = pix_desc->log2_chroma_w; s->vsub = pix_desc->log2_chroma_h; diff --git a/libavfilter/vf_blend_init.h b/libavfilter/vf_blend_init.h index d24f17803..956e1cb9f 100644 --- a/libavfilter/vf_blend_init.h +++ b/libavfilter/vf_blend_init.h @@ -58,7 +58,7 @@ static void blend_copy ## src##_##depth(const uint8_t *top, ptrdiff_t top_linesi const uint8_t *bottom, ptrdiff_t bottom_linesize,\ uint8_t *dst, ptrdiff_t dst_linesize, \ ptrdiff_t width, ptrdiff_t height, \ - FilterParams *param, double *values, int starty) \ + FilterParams *param, SliceParams *sliceparam) \ { \ av_image_copy_plane(dst, dst_linesize, src, src ## _linesize, \ width * depth / 8, height); \ @@ -80,7 +80,7 @@ static void blend_normal_##name(const uint8_t *_top, ptrdiff_t top_linesize, const uint8_t *_bottom, ptrdiff_t bottom_linesize,\ uint8_t *_dst, ptrdiff_t dst_linesize, \ ptrdiff_t width, ptrdiff_t height, \ - FilterParams *param, double *values, int starty) \ + FilterParams *param, SliceParams *sliceparam) \ { \ const type *top = (const type*)_top; \ const type *bottom = (const type*)_bottom; \ diff --git a/libavfilter/vf_blend_vulkan.c b/libavfilter/vf_blend_vulkan.c index 417be766b..f3eb5355f 100644 --- a/libavfilter/vf_blend_vulkan.c +++ b/libavfilter/vf_blend_vulkan.c @@ -25,7 +25,8 @@ #include "libavutil/opt.h" #include "vulkan_filter.h" #include "vulkan_spirv.h" -#include "internal.h" + +#include "filters.h" #include "framesync.h" #include "blend.h" #include "video.h" @@ -299,9 +300,11 @@ static av_cold void uninit(AVFilterContext *avctx) static int config_props_output(AVFilterLink *outlink) { int err; + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; BlendVulkanContext *s = avctx->priv; AVFilterLink *toplink = avctx->inputs[IN_TOP]; + FilterLink *tl = ff_filter_link(toplink); AVFilterLink *bottomlink = avctx->inputs[IN_BOTTOM]; if (toplink->w != bottomlink->w || toplink->h != bottomlink->h) { @@ -314,7 +317,7 @@ static int config_props_output(AVFilterLink *outlink) } outlink->sample_aspect_ratio = toplink->sample_aspect_ratio; - outlink->frame_rate = toplink->frame_rate; + outl->frame_rate = tl->frame_rate; RET(ff_vk_filter_config_output(outlink)); diff --git a/libavfilter/vf_blockdetect.c b/libavfilter/vf_blockdetect.c index d787aff5e..dc6d9a922 100644 --- a/libavfilter/vf_blockdetect.c +++ b/libavfilter/vf_blockdetect.c @@ -29,9 +29,11 @@ * @author Thilo Borgmann */ -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "internal.h" +#include "libavutil/pixdesc.h" + +#include "filters.h" #include "video.h" typedef struct BLKContext { @@ -197,6 +199,7 @@ static void set_meta(AVDictionary **metadata, const char *key, float d) static int blockdetect_filter_frame(AVFilterLink *inlink, AVFrame *in) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; BLKContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; @@ -235,7 +238,7 @@ static int blockdetect_filter_frame(AVFilterLink *inlink, AVFrame *in) set_meta(metadata, "lavfi.block", block); - s->nb_frames = inlink->frame_count_in; + s->nb_frames = inl->frame_count_in; return ff_filter_frame(outlink, in); } diff --git a/libavfilter/vf_blurdetect.c b/libavfilter/vf_blurdetect.c index 354a6b610..a99d61f88 100644 --- a/libavfilter/vf_blurdetect.c +++ b/libavfilter/vf_blurdetect.c @@ -30,10 +30,12 @@ * @author Thilo Borgmann */ -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "libavutil/qsort.h" -#include "internal.h" + +#include "filters.h" #include "edge_common.h" #include "video.h" @@ -255,6 +257,7 @@ static void set_meta(AVDictionary **metadata, const char *key, float d) static int blurdetect_filter_frame(AVFilterLink *inlink, AVFrame *in) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; BLRContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; @@ -315,7 +318,7 @@ static int blurdetect_filter_frame(AVFilterLink *inlink, AVFrame *in) set_meta(metadata, "lavfi.blur", blur); - s->nb_frames = inlink->frame_count_in; + s->nb_frames = inl->frame_count_in; return ff_filter_frame(outlink, in); } diff --git a/libavfilter/vf_bm3d.c b/libavfilter/vf_bm3d.c index 11d373c64..49597ea8f 100644 --- a/libavfilter/vf_bm3d.c +++ b/libavfilter/vf_bm3d.c @@ -33,13 +33,13 @@ #include "libavutil/cpu.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/tx.h" #include "avfilter.h" #include "filters.h" #include "framesync.h" -#include "internal.h" #include "video.h" #define MAX_NB_THREADS 32 @@ -952,9 +952,11 @@ static av_cold int init(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; BM3DContext *s = ctx->priv; AVFilterLink *src = ctx->inputs[0]; + FilterLink *srcl = ff_filter_link(src); AVFilterLink *ref; FFFrameSyncIn *in; int ret; @@ -977,7 +979,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = src->h; outlink->time_base = src->time_base; outlink->sample_aspect_ratio = src->sample_aspect_ratio; - outlink->frame_rate = src->frame_rate; + outl->frame_rate = srcl->frame_rate; if (!s->ref) return 0; diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c index 60375463a..27cf57a7c 100644 --- a/libavfilter/vf_boxblur.c +++ b/libavfilter/vf_boxblur.c @@ -25,12 +25,12 @@ * Ported from MPlayer libmpcodecs/vf_boxblur.c. */ -#include "libavutil/avstring.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "boxblur.h" diff --git a/libavfilter/vf_bwdif.c b/libavfilter/vf_bwdif.c index b8759d824..d41a25f8e 100644 --- a/libavfilter/vf_bwdif.c +++ b/libavfilter/vf_bwdif.c @@ -34,7 +34,7 @@ #include "avfilter.h" #include "bwdifdsp.h" #include "ccfifo.h" -#include "internal.h" +#include "filters.h" #include "yadif.h" typedef struct BWDIFContext { diff --git a/libavfilter/vf_bwdif_cuda.c b/libavfilter/vf_bwdif_cuda.c index 8c37dc880..396a24671 100644 --- a/libavfilter/vf_bwdif_cuda.c +++ b/libavfilter/vf_bwdif_cuda.c @@ -22,7 +22,8 @@ #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" #include "libavutil/cuda_check.h" -#include "internal.h" + +#include "filters.h" #include "yadif.h" #include "cuda/load_helper.h" @@ -217,16 +218,17 @@ static av_cold void deint_cuda_uninit(AVFilterContext *ctx) static int config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; DeintCUDAContext *s = ctx->priv; - if (!inlink->hw_frames_ctx) { + if (!l->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "A hardware frames reference is " "required to associate the processing device.\n"); return AVERROR(EINVAL); } - s->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx); + s->input_frames_ref = av_buffer_ref(l->hw_frames_ctx); if (!s->input_frames_ref) { av_log(ctx, AV_LOG_ERROR, "A input frames reference create " "failed.\n"); @@ -239,6 +241,7 @@ static int config_input(AVFilterLink *inlink) static int config_output(AVFilterLink *link) { + FilterLink *l = ff_filter_link(link); AVHWFramesContext *output_frames; AVFilterContext *ctx = link->src; DeintCUDAContext *s = ctx->priv; @@ -257,15 +260,15 @@ static int config_output(AVFilterLink *link) s->hwctx = ((AVHWDeviceContext*)s->device_ref->data)->hwctx; cu = s->hwctx->internal->cuda_dl; - link->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref); - if (!link->hw_frames_ctx) { + l->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref); + if (!l->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context " "for output.\n"); ret = AVERROR(ENOMEM); goto exit; } - output_frames = (AVHWFramesContext*)link->hw_frames_ctx->data; + output_frames = (AVHWFramesContext*)l->hw_frames_ctx->data; output_frames->format = AV_PIX_FMT_CUDA; output_frames->sw_format = s->input_frames->sw_format; @@ -278,7 +281,7 @@ static int config_output(AVFilterLink *link) if (ret < 0) goto exit; - ret = av_hwframe_ctx_init(link->hw_frames_ctx); + ret = av_hwframe_ctx_init(l->hw_frames_ctx); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Failed to initialise CUDA frame " "context for output: %d\n", ret); diff --git a/libavfilter/vf_bwdif_vulkan.c b/libavfilter/vf_bwdif_vulkan.c index 57711fb67..4e43ade1c 100644 --- a/libavfilter/vf_bwdif_vulkan.c +++ b/libavfilter/vf_bwdif_vulkan.c @@ -25,7 +25,7 @@ #include "vulkan_filter.h" #include "vulkan_spirv.h" #include "yadif.h" -#include "internal.h" +#include "filters.h" typedef struct BWDIFVulkanContext { YADIFContext yadif; @@ -303,18 +303,19 @@ static void bwdif_vulkan_uninit(AVFilterContext *avctx) static int bwdif_vulkan_config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVHWFramesContext *input_frames; AVFilterContext *avctx = inlink->dst; BWDIFVulkanContext *s = avctx->priv; FFVulkanContext *vkctx = &s->vkctx; - if (!inlink->hw_frames_ctx) { + if (!l->hw_frames_ctx) { av_log(inlink->dst, AV_LOG_ERROR, "Vulkan filtering requires a " "hardware frames context on the input.\n"); return AVERROR(EINVAL); } - input_frames = (AVHWFramesContext *)inlink->hw_frames_ctx->data; + input_frames = (AVHWFramesContext *)l->hw_frames_ctx->data; if (input_frames->format != AV_PIX_FMT_VULKAN) return AVERROR(EINVAL); @@ -323,7 +324,7 @@ static int bwdif_vulkan_config_input(AVFilterLink *inlink) return 0; /* Save the ref, without reffing it */ - vkctx->input_frames_ref = inlink->hw_frames_ctx; + vkctx->input_frames_ref = l->hw_frames_ctx; /* Defaults */ vkctx->output_format = input_frames->sw_format; @@ -335,13 +336,14 @@ static int bwdif_vulkan_config_input(AVFilterLink *inlink) static int bwdif_vulkan_config_output(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); int err; AVFilterContext *avctx = outlink->src; BWDIFVulkanContext *s = avctx->priv; YADIFContext *y = &s->yadif; FFVulkanContext *vkctx = &s->vkctx; - av_buffer_unref(&outlink->hw_frames_ctx); + av_buffer_unref(&l->hw_frames_ctx); err = ff_vk_filter_init_context(avctx, vkctx, vkctx->input_frames_ref, vkctx->output_width, vkctx->output_height, @@ -352,8 +354,8 @@ static int bwdif_vulkan_config_output(AVFilterLink *outlink) /* For logging */ vkctx->class = y->class; - outlink->hw_frames_ctx = av_buffer_ref(vkctx->frames_ref); - if (!outlink->hw_frames_ctx) + l->hw_frames_ctx = av_buffer_ref(vkctx->frames_ref); + if (!l->hw_frames_ctx) return AVERROR(ENOMEM); err = ff_yadif_config_output_common(outlink); diff --git a/libavfilter/vf_cas.c b/libavfilter/vf_cas.c index 5fa5055d7..7fc384026 100644 --- a/libavfilter/vf_cas.c +++ b/libavfilter/vf_cas.c @@ -19,7 +19,7 @@ #include "libavutil/opt.h" #include "libavutil/imgutils.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct CASContext { diff --git a/libavfilter/vf_ccrepack.c b/libavfilter/vf_ccrepack.c index 5213eab82..3e7262220 100644 --- a/libavfilter/vf_ccrepack.c +++ b/libavfilter/vf_ccrepack.c @@ -30,7 +30,7 @@ */ #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "ccfifo.h" #include "video.h" #include "libavutil/opt.h" @@ -49,9 +49,10 @@ AVFILTER_DEFINE_CLASS(ccrepack); static int config_input(AVFilterLink *link) { + FilterLink *l = ff_filter_link(link); CCRepackContext *ctx = link->dst->priv; - int ret = ff_ccfifo_init(&ctx->cc_fifo, link->frame_rate, ctx); + int ret = ff_ccfifo_init(&ctx->cc_fifo, l->frame_rate, ctx); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n"); return ret; diff --git a/libavfilter/vf_chromaber_vulkan.c b/libavfilter/vf_chromaber_vulkan.c index 0b96a7400..60c8378b1 100644 --- a/libavfilter/vf_chromaber_vulkan.c +++ b/libavfilter/vf_chromaber_vulkan.c @@ -22,7 +22,8 @@ #include "libavutil/opt.h" #include "vulkan_filter.h" #include "vulkan_spirv.h" -#include "internal.h" + +#include "filters.h" #include "video.h" typedef struct ChromaticAberrationVulkanContext { diff --git a/libavfilter/vf_chromakey.c b/libavfilter/vf_chromakey.c index 9c0918bb4..659ba2855 100644 --- a/libavfilter/vf_chromakey.c +++ b/libavfilter/vf_chromakey.c @@ -22,7 +22,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct ChromakeyContext { const AVClass *class; diff --git a/libavfilter/vf_chromakey_cuda.c b/libavfilter/vf_chromakey_cuda.c index ac644caea..c59ac7b26 100644 --- a/libavfilter/vf_chromakey_cuda.c +++ b/libavfilter/vf_chromakey_cuda.c @@ -30,7 +30,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "cuda/load_helper.h" static const enum AVPixelFormat supported_formats[] = { @@ -180,17 +180,18 @@ static av_cold void set_format_info(AVFilterContext *ctx, enum AVPixelFormat in_ static av_cold int init_processing_chain(AVFilterContext *ctx, int width, int height) { + FilterLink *inl = ff_filter_link(ctx->inputs[0]); + FilterLink *outl = ff_filter_link(ctx->outputs[0]); ChromakeyCUDAContext *s = ctx->priv; AVHWFramesContext *in_frames_ctx; int ret; /* check that we have a hw context */ - if (!ctx->inputs[0]->hw_frames_ctx) - { + if (!inl->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n"); return AVERROR(EINVAL); } - in_frames_ctx = (AVHWFramesContext *)ctx->inputs[0]->hw_frames_ctx->data; + in_frames_ctx = (AVHWFramesContext *)inl->hw_frames_ctx->data; if (!format_is_supported(in_frames_ctx->sw_format)) { @@ -204,8 +205,8 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int width, int he if (ret < 0) return ret; - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx); - if (!ctx->outputs[0]->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); return 0; @@ -258,14 +259,12 @@ static av_cold int cudachromakey_config_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); ChromakeyCUDAContext *s = ctx->priv; - AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data; - AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + AVHWFramesContext *frames_ctx; + AVCUDADeviceContext *device_hwctx; int ret; - s->hwctx = device_hwctx; - s->cu_stream = s->hwctx->stream; - if (s->is_yuv) { s->chromakey_uv[0] = s->chromakey_rgba[1]; s->chromakey_uv[1] = s->chromakey_rgba[2]; @@ -278,6 +277,12 @@ static av_cold int cudachromakey_config_props(AVFilterLink *outlink) if (ret < 0) return ret; + frames_ctx = (AVHWFramesContext *)inl->hw_frames_ctx->data; + device_hwctx = frames_ctx->device_ctx->hwctx; + + s->hwctx = device_hwctx; + s->cu_stream = s->hwctx->stream; + outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; ret = cudachromakey_load_functions(ctx); diff --git a/libavfilter/vf_chromanr.c b/libavfilter/vf_chromanr.c index ff7731331..6e1fba034 100644 --- a/libavfilter/vf_chromanr.c +++ b/libavfilter/vf_chromanr.c @@ -23,7 +23,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ChromaNRContext { diff --git a/libavfilter/vf_chromashift.c b/libavfilter/vf_chromashift.c index 6c929472a..58c4c1b5c 100644 --- a/libavfilter/vf_chromashift.c +++ b/libavfilter/vf_chromashift.c @@ -23,7 +23,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ChromaShiftContext { diff --git a/libavfilter/vf_ciescope.c b/libavfilter/vf_ciescope.c index d5f33a530..260ca2618 100644 --- a/libavfilter/vf_ciescope.c +++ b/libavfilter/vf_ciescope.c @@ -25,8 +25,8 @@ #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" enum CieSystem { diff --git a/libavfilter/vf_codecview.c b/libavfilter/vf_codecview.c index 77e541e37..b7396f666 100644 --- a/libavfilter/vf_codecview.c +++ b/libavfilter/vf_codecview.c @@ -29,13 +29,14 @@ * TODO: segmentation */ -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/motion_vector.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "libavutil/video_enc_params.h" #include "avfilter.h" +#include "filters.h" #include "qp_table.h" -#include "internal.h" #include "video.h" #define MV_P_FOR (1<<0) diff --git a/libavfilter/vf_colorbalance.c b/libavfilter/vf_colorbalance.c index 676e74c77..1c88aa4a1 100644 --- a/libavfilter/vf_colorbalance.c +++ b/libavfilter/vf_colorbalance.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define R 0 diff --git a/libavfilter/vf_colorchannelmixer.c b/libavfilter/vf_colorchannelmixer.c index 8402b5785..02ad3435f 100644 --- a/libavfilter/vf_colorchannelmixer.c +++ b/libavfilter/vf_colorchannelmixer.c @@ -20,11 +20,12 @@ #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "preserve_color.h" diff --git a/libavfilter/vf_colorconstancy.c b/libavfilter/vf_colorconstancy.c index 3d4d433cc..035880294 100644 --- a/libavfilter/vf_colorconstancy.c +++ b/libavfilter/vf_colorconstancy.c @@ -28,11 +28,12 @@ * J. van de Weijer, Th. Gevers, A. Gijsenij "Edge-Based Color Constancy". */ -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include diff --git a/libavfilter/vf_colorcontrast.c b/libavfilter/vf_colorcontrast.c index b086de71e..419f5a1e1 100644 --- a/libavfilter/vf_colorcontrast.c +++ b/libavfilter/vf_colorcontrast.c @@ -24,7 +24,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define R 0 diff --git a/libavfilter/vf_colorcorrect.c b/libavfilter/vf_colorcorrect.c index 3433b5c4c..db69a22e4 100644 --- a/libavfilter/vf_colorcorrect.c +++ b/libavfilter/vf_colorcorrect.c @@ -20,10 +20,11 @@ #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef enum AnalyzeMode { diff --git a/libavfilter/vf_colorize.c b/libavfilter/vf_colorize.c index e6c563e3e..e20008e79 100644 --- a/libavfilter/vf_colorize.c +++ b/libavfilter/vf_colorize.c @@ -19,7 +19,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ColorizeContext { diff --git a/libavfilter/vf_colorkey.c b/libavfilter/vf_colorkey.c index 58dd513b3..343a93c1d 100644 --- a/libavfilter/vf_colorkey.c +++ b/libavfilter/vf_colorkey.c @@ -24,7 +24,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" typedef struct ColorkeyContext { const AVClass *class; diff --git a/libavfilter/vf_colorkey_opencl.c b/libavfilter/vf_colorkey_opencl.c index 72a36df2d..24c6b1f74 100644 --- a/libavfilter/vf_colorkey_opencl.c +++ b/libavfilter/vf_colorkey_opencl.c @@ -18,7 +18,7 @@ #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" diff --git a/libavfilter/vf_colorlevels.c b/libavfilter/vf_colorlevels.c index 6f54628ec..e33bdf679 100644 --- a/libavfilter/vf_colorlevels.c +++ b/libavfilter/vf_colorlevels.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "preserve_color.h" diff --git a/libavfilter/vf_colormap.c b/libavfilter/vf_colormap.c index 31f33e7eb..77b7067d0 100644 --- a/libavfilter/vf_colormap.c +++ b/libavfilter/vf_colormap.c @@ -28,7 +28,7 @@ #include "libavutil/common.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "framesync.h" #include "video.h" @@ -482,16 +482,18 @@ static int process_frame(FFFrameSync *fs) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; ColorMapContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); AVFilterLink *source = ctx->inputs[1]; AVFilterLink *target = ctx->inputs[2]; FFFrameSyncIn *in; int ret; outlink->time_base = inlink->time_base; - outlink->frame_rate = inlink->frame_rate; + outl->frame_rate = inl->frame_rate; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->w = inlink->w; outlink->h = inlink->h; diff --git a/libavfilter/vf_colormatrix.c b/libavfilter/vf_colormatrix.c index 81254b046..d0e3043fd 100644 --- a/libavfilter/vf_colormatrix.c +++ b/libavfilter/vf_colormatrix.c @@ -30,7 +30,7 @@ #include #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" diff --git a/libavfilter/vf_colorspace.c b/libavfilter/vf_colorspace.c index f367ce17c..344dcd5f9 100644 --- a/libavfilter/vf_colorspace.c +++ b/libavfilter/vf_colorspace.c @@ -25,6 +25,7 @@ #include "libavutil/avassert.h" #include "libavutil/csp.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -32,8 +33,8 @@ #include "avfilter.h" #include "colorspacedsp.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "colorspace.h" @@ -432,8 +433,7 @@ static int create_filtergraph(AVFilterContext *ctx, if (out->color_trc != s->out_trc) s->out_txchr = NULL; if (in->colorspace != s->in_csp || in->color_range != s->in_rng) s->in_lumacoef = NULL; - if (out->colorspace != s->out_csp || - out->color_range != s->out_rng) s->out_lumacoef = NULL; + if (out->color_range != s->out_rng) s->rgb2yuv = NULL; if (!s->out_primaries || !s->in_primaries) { s->in_prm = in->color_primaries; @@ -562,26 +562,8 @@ static int create_filtergraph(AVFilterContext *ctx, redo_yuv2rgb = 1; } - if (!s->out_lumacoef) { - s->out_csp = out->colorspace; + if (!s->rgb2yuv) { s->out_rng = out->color_range; - s->out_lumacoef = av_csp_luma_coeffs_from_avcsp(s->out_csp); - if (!s->out_lumacoef) { - if (s->out_csp == AVCOL_SPC_UNSPECIFIED) { - if (s->user_all == CS_UNSPECIFIED) { - av_log(ctx, AV_LOG_ERROR, - "Please specify output colorspace\n"); - } else { - av_log(ctx, AV_LOG_ERROR, - "Unsupported output color property %d\n", s->user_all); - } - } else { - av_log(ctx, AV_LOG_ERROR, - "Unsupported output colorspace %d (%s)\n", s->out_csp, - av_color_space_name(s->out_csp)); - } - return AVERROR(EINVAL); - } redo_rgb2yuv = 1; } @@ -686,6 +668,26 @@ static av_cold int init(AVFilterContext *ctx) { ColorSpaceContext *s = ctx->priv; + s->out_csp = s->user_csp == AVCOL_SPC_UNSPECIFIED ? + default_csp[FFMIN(s->user_all, CS_NB)] : s->user_csp; + s->out_lumacoef = av_csp_luma_coeffs_from_avcsp(s->out_csp); + if (!s->out_lumacoef) { + if (s->out_csp == AVCOL_SPC_UNSPECIFIED) { + if (s->user_all == CS_UNSPECIFIED) { + av_log(ctx, AV_LOG_ERROR, + "Please specify output colorspace\n"); + } else { + av_log(ctx, AV_LOG_ERROR, + "Unsupported output color property %d\n", s->user_all); + } + } else { + av_log(ctx, AV_LOG_ERROR, + "Unsupported output colorspace %d (%s)\n", s->out_csp, + av_color_space_name(s->out_csp)); + } + return AVERROR(EINVAL); + } + ff_colorspacedsp_init(&s->dsp); return 0; @@ -734,6 +736,9 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) return res; } + out->colorspace = s->out_csp; + out->color_range = s->user_rng == AVCOL_RANGE_UNSPECIFIED ? + in->color_range : s->user_rng; out->color_primaries = s->user_prm == AVCOL_PRI_UNSPECIFIED ? default_prm[FFMIN(s->user_all, CS_NB)] : s->user_prm; if (s->user_trc == AVCOL_TRC_UNSPECIFIED) { @@ -745,10 +750,6 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) } else { out->color_trc = s->user_trc; } - out->colorspace = s->user_csp == AVCOL_SPC_UNSPECIFIED ? - default_csp[FFMIN(s->user_all, CS_NB)] : s->user_csp; - out->color_range = s->user_rng == AVCOL_RANGE_UNSPECIFIED ? - in->color_range : s->user_rng; if (rgb_sz != s->rgb_sz) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(out->format); int uvw = in->width >> desc->log2_chroma_w; @@ -840,8 +841,18 @@ static int query_formats(AVFilterContext *ctx) }; int res; ColorSpaceContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; AVFilterFormats *formats = ff_make_format_list(pix_fmts); + res = ff_formats_ref(ff_make_formats_list_singleton(s->out_csp), &outlink->incfg.color_spaces); + if (res < 0) + return res; + if (s->user_rng != AVCOL_RANGE_UNSPECIFIED) { + res = ff_formats_ref(ff_make_formats_list_singleton(s->user_rng), &outlink->incfg.color_ranges); + if (res < 0) + return res; + } + if (!formats) return AVERROR(ENOMEM); if (s->user_format == AV_PIX_FMT_NONE) @@ -854,7 +865,7 @@ static int query_formats(AVFilterContext *ctx) if (res < 0) return res; - return ff_formats_ref(formats, &ctx->outputs[0]->incfg.formats); + return ff_formats_ref(formats, &outlink->incfg.formats); } static int config_props(AVFilterLink *outlink) diff --git a/libavfilter/vf_colorspace_cuda.c b/libavfilter/vf_colorspace_cuda.c index 5ad81e959..9d1058ff7 100644 --- a/libavfilter/vf_colorspace_cuda.c +++ b/libavfilter/vf_colorspace_cuda.c @@ -31,7 +31,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "cuda/load_helper.h" @@ -151,17 +151,19 @@ static int format_is_supported(enum AVPixelFormat fmt) static av_cold int init_processing_chain(AVFilterContext* ctx, int width, int height) { + FilterLink *inl = ff_filter_link(ctx->inputs[0]); + FilterLink *outl = ff_filter_link(ctx->outputs[0]); CUDAColorspaceContext* s = ctx->priv; AVHWFramesContext* in_frames_ctx; int ret; - if (!ctx->inputs[0]->hw_frames_ctx) { + if (!inl->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n"); return AVERROR(EINVAL); } - in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; + in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; s->pix_fmt = in_frames_ctx->sw_format; if (!format_is_supported(s->pix_fmt)) { @@ -181,8 +183,8 @@ static av_cold int init_processing_chain(AVFilterContext* ctx, int width, if (ret < 0) return ret; - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx); - if (!ctx->outputs[0]->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); return 0; @@ -225,15 +227,12 @@ static av_cold int cudacolorspace_config_props(AVFilterLink* outlink) { AVFilterContext* ctx = outlink->src; AVFilterLink* inlink = outlink->src->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); CUDAColorspaceContext* s = ctx->priv; - AVHWFramesContext* frames_ctx = - (AVHWFramesContext*)inlink->hw_frames_ctx->data; - AVCUDADeviceContext* device_hwctx = frames_ctx->device_ctx->hwctx; + AVHWFramesContext* frames_ctx; + AVCUDADeviceContext* device_hwctx; int ret; - s->hwctx = device_hwctx; - s->cu_stream = s->hwctx->stream; - outlink->w = inlink->w; outlink->h = inlink->h; @@ -241,6 +240,12 @@ static av_cold int cudacolorspace_config_props(AVFilterLink* outlink) if (ret < 0) return ret; + frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; + device_hwctx = frames_ctx->device_ctx->hwctx; + + s->hwctx = device_hwctx; + s->cu_stream = s->hwctx->stream; + if (inlink->sample_aspect_ratio.num) { outlink->sample_aspect_ratio = av_mul_q( (AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, diff --git a/libavfilter/vf_colortemperature.c b/libavfilter/vf_colortemperature.c index b06b04e70..3c2f34788 100644 --- a/libavfilter/vf_colortemperature.c +++ b/libavfilter/vf_colortemperature.c @@ -24,7 +24,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define R 0 diff --git a/libavfilter/vf_convolution.c b/libavfilter/vf_convolution.c index 88b89289a..aacfe0add 100644 --- a/libavfilter/vf_convolution.c +++ b/libavfilter/vf_convolution.c @@ -24,12 +24,13 @@ #include "libavutil/avstring.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "convolution.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define OFFSET(x) offsetof(ConvolutionContext, x) @@ -760,8 +761,10 @@ static int param_init(AVFilterContext *ctx) s->rdiv[i] = s->scale; s->bias[i] = s->delta; } +#if CONFIG_SOBEL_FILTER } else if (!strcmp(ctx->filter->name, "sobel")) { ff_sobel_init(s, s->depth, s->nb_planes); +#endif } else if (!strcmp(ctx->filter->name, "kirsch")) { for (i = 0; i < 4; i++) { s->filter[i] = filter_kirsch; diff --git a/libavfilter/vf_convolution_opencl.c b/libavfilter/vf_convolution_opencl.c index 40938436f..ba6f08454 100644 --- a/libavfilter/vf_convolution_opencl.c +++ b/libavfilter/vf_convolution_opencl.c @@ -30,7 +30,7 @@ #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" diff --git a/libavfilter/vf_convolve.c b/libavfilter/vf_convolve.c index 95d174359..1c1e0ba08 100644 --- a/libavfilter/vf_convolve.c +++ b/libavfilter/vf_convolve.c @@ -22,13 +22,14 @@ #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/tx.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #define MAX_THREADS 16 @@ -743,10 +744,12 @@ static int do_convolve(FFFrameSync *fs) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); AVFilterContext *ctx = outlink->src; ConvolveContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *ml = ff_filter_link(mainlink); AVFilterLink *secondlink = ctx->inputs[1]; int ret, i, j; @@ -768,7 +771,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + outl->frame_rate = ml->frame_rate; if ((ret = ff_framesync_configure(&s->fs)) < 0) return ret; diff --git a/libavfilter/vf_copy.c b/libavfilter/vf_copy.c index 52ac9fb0e..8158414dc 100644 --- a/libavfilter/vf_copy.c +++ b/libavfilter/vf_copy.c @@ -24,8 +24,8 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" static int query_formats(AVFilterContext *ctx) diff --git a/libavfilter/vf_coreimage.m b/libavfilter/vf_coreimage.m index 979eab3b0..b4a4d6c47 100644 --- a/libavfilter/vf_coreimage.m +++ b/libavfilter/vf_coreimage.m @@ -27,10 +27,11 @@ #import #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -64,12 +65,13 @@ typedef struct CoreImageContext { static int config_output(AVFilterLink *link) { + FilterLink *l = ff_filter_link(link); CoreImageContext *ctx = link->src->priv; link->w = ctx->w; link->h = ctx->h; link->sample_aspect_ratio = ctx->sar; - link->frame_rate = ctx->frame_rate; + l->frame_rate = ctx->frame_rate; link->time_base = ctx->time_base; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); diff --git a/libavfilter/vf_corr.c b/libavfilter/vf_corr.c index 7e0f81921..9df1826c9 100644 --- a/libavfilter/vf_corr.c +++ b/libavfilter/vf_corr.c @@ -22,12 +22,13 @@ */ #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" typedef struct Sums { uint64_t s[2]; @@ -329,9 +330,11 @@ static int config_input_ref(AVFilterLink *inlink) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; CorrContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *ml = ff_filter_link(mainlink); int ret; ret = ff_framesync_init_dualinput(&s->fs, ctx); @@ -341,7 +344,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + outl->frame_rate = ml->frame_rate; if ((ret = ff_framesync_configure(&s->fs)) < 0) return ret; diff --git a/libavfilter/vf_cover_rect.c b/libavfilter/vf_cover_rect.c index a4321fdb1..95df291ba 100644 --- a/libavfilter/vf_cover_rect.c +++ b/libavfilter/vf_cover_rect.c @@ -22,10 +22,9 @@ * @todo switch to dualinput */ -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "filters.h" -#include "internal.h" #include "video.h" #include "lavfutils.h" diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c index 636120994..4742732b6 100644 --- a/libavfilter/vf_crop.c +++ b/libavfilter/vf_crop.c @@ -26,8 +26,8 @@ #include #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "libavutil/eval.h" #include "libavutil/avstring.h" @@ -206,7 +206,7 @@ static int config_input(AVFilterLink *link) AVRational dar = av_mul_q(link->sample_aspect_ratio, (AVRational){ link->w, link->h }); av_reduce(&s->out_sar.num, &s->out_sar.den, - dar.num * s->h, dar.den * s->w, INT_MAX); + (int64_t)dar.num * s->h, (int64_t)dar.den * s->w, INT_MAX); } else s->out_sar = link->sample_aspect_ratio; @@ -255,12 +255,13 @@ static int config_output(AVFilterLink *link) static int filter_frame(AVFilterLink *link, AVFrame *frame) { + FilterLink *l = ff_filter_link(link); AVFilterContext *ctx = link->dst; CropContext *s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); int i; - s->var_values[VAR_N] = link->frame_count_out; + s->var_values[VAR_N] = l->frame_count_out; s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ? NAN : frame->pts * av_q2d(link->time_base); #if FF_API_FRAME_PKT diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c index a1cfc465d..8b0277803 100644 --- a/libavfilter/vf_cropdetect.c +++ b/libavfilter/vf_cropdetect.c @@ -25,12 +25,13 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/motion_vector.h" #include "libavutil/qsort.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "edge_common.h" diff --git a/libavfilter/vf_curves.c b/libavfilter/vf_curves.c index 55c0a1236..dc399cf84 100644 --- a/libavfilter/vf_curves.c +++ b/libavfilter/vf_curves.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/bprint.h" #include "libavutil/eval.h" @@ -28,7 +29,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define R 0 @@ -181,20 +182,22 @@ static int parse_points_str(AVFilterContext *ctx, struct keypoint **points, cons if (point->x < 0 || point->x > 1 || point->y < 0 || point->y > 1) { av_log(ctx, AV_LOG_ERROR, "Invalid key point coordinates (%f;%f), " "x and y must be in the [0;1] range.\n", point->x, point->y); + av_free(point); return AVERROR(EINVAL); } - if (!*points) - *points = point; if (last) { if ((int)(last->x * scale) >= (int)(point->x * scale)) { av_log(ctx, AV_LOG_ERROR, "Key point coordinates (%f;%f) " "and (%f;%f) are too close from each other or not " "strictly increasing on the x-axis\n", last->x, last->y, point->x, point->y); + av_free(point); return AVERROR(EINVAL); } last->next = point; } + if (!*points) + *points = point; last = point; } diff --git a/libavfilter/vf_datascope.c b/libavfilter/vf_datascope.c index fedd57b83..7b4cb52ee 100644 --- a/libavfilter/vf_datascope.c +++ b/libavfilter/vf_datascope.c @@ -19,14 +19,14 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavutil/xga_font_data.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct DatascopeContext { @@ -1038,6 +1038,7 @@ static void draw_scope(OscilloscopeContext *s, int x0, int y0, int x1, int y1, static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; OscilloscopeContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; @@ -1047,7 +1048,7 @@ static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame) int i, c; s->nb_values = 0; - draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inlink->frame_count_in & 1); + draw_scope(s, s->x1, s->y1, s->x2, s->y2, frame, s->values, inl->frame_count_in & 1); ff_blend_rectangle(&s->draw, &s->dark, frame->data, frame->linesize, frame->width, frame->height, s->ox, s->oy, s->width, s->height + 20 * s->statistics); diff --git a/libavfilter/vf_dblur.c b/libavfilter/vf_dblur.c index 3110d1927..9ea42f2a5 100644 --- a/libavfilter/vf_dblur.c +++ b/libavfilter/vf_dblur.c @@ -19,10 +19,11 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct DBlurContext { diff --git a/libavfilter/vf_dctdnoiz.c b/libavfilter/vf_dctdnoiz.c index ab96dbe15..9d1247c8f 100644 --- a/libavfilter/vf_dctdnoiz.c +++ b/libavfilter/vf_dctdnoiz.c @@ -30,9 +30,11 @@ #include "libavutil/avassert.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" -#include "internal.h" + +#include "filters.h" #include "video.h" static const char *const var_names[] = { "c", NULL }; diff --git a/libavfilter/vf_deband.c b/libavfilter/vf_deband.c index 177d888be..31b864b76 100644 --- a/libavfilter/vf_deband.c +++ b/libavfilter/vf_deband.c @@ -21,11 +21,12 @@ * SOFTWARE. */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct DebandContext { diff --git a/libavfilter/vf_deblock.c b/libavfilter/vf_deblock.c index 7e4b1799d..3b07856dc 100644 --- a/libavfilter/vf_deblock.c +++ b/libavfilter/vf_deblock.c @@ -27,7 +27,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum FilterType { WEAK, STRONG, NB_FILTER }; diff --git a/libavfilter/vf_decimate.c b/libavfilter/vf_decimate.c index dbeca427f..2e3dba5e7 100644 --- a/libavfilter/vf_decimate.c +++ b/libavfilter/vf_decimate.c @@ -19,12 +19,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "libavutil/timestamp.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #define INPUT_MAIN 0 #define INPUT_CLEANSRC 1 @@ -381,10 +380,12 @@ static const enum AVPixelFormat pix_fmts[] = { static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; DecimateContext *dm = ctx->priv; const AVFilterLink *inlink = ctx->inputs[INPUT_MAIN]; - AVRational fps = inlink->frame_rate; + FilterLink *inl = ff_filter_link(ctx->inputs[INPUT_MAIN]); + AVRational fps = inl->frame_rate; int max_value; const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format); const int w = inlink->w; @@ -426,9 +427,9 @@ static int config_output(AVFilterLink *outlink) fps.num, fps.den, outlink->time_base.den, outlink->time_base.num); } else { outlink->time_base = dm->dec_tb; - outlink->frame_rate = av_inv_q(outlink->time_base); + outl->frame_rate = av_inv_q(outlink->time_base); av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n", - fps.num, fps.den, outlink->frame_rate.num, outlink->frame_rate.den); + fps.num, fps.den, outl->frame_rate.num, outl->frame_rate.den); } outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; if (dm->ppsrc) { diff --git a/libavfilter/vf_dedot.c b/libavfilter/vf_dedot.c index acdb03c70..09fd973e5 100644 --- a/libavfilter/vf_dedot.c +++ b/libavfilter/vf_dedot.c @@ -23,7 +23,6 @@ #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" typedef struct DedotContext { diff --git a/libavfilter/vf_deflicker.c b/libavfilter/vf_deflicker.c index f84fe5eaf..da16677f6 100644 --- a/libavfilter/vf_deflicker.c +++ b/libavfilter/vf_deflicker.c @@ -19,6 +19,7 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/qsort.h" @@ -27,7 +28,7 @@ #define FF_BUFQUEUE_SIZE 129 #include "bufferqueue.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define SIZE FF_BUFQUEUE_SIZE diff --git a/libavfilter/vf_deinterlace_vaapi.c b/libavfilter/vf_deinterlace_vaapi.c index dbaba26ab..0478d6dae 100644 --- a/libavfilter/vf_deinterlace_vaapi.c +++ b/libavfilter/vf_deinterlace_vaapi.c @@ -23,7 +23,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "vaapi_vpp.h" @@ -158,7 +158,9 @@ static int deint_vaapi_build_filter_params(AVFilterContext *avctx) static int deint_vaapi_config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *avctx = outlink->src; DeintVAAPIContext *ctx = avctx->priv; int err; @@ -168,8 +170,8 @@ static int deint_vaapi_config_output(AVFilterLink *outlink) return err; outlink->time_base = av_mul_q(inlink->time_base, (AVRational) { 1, ctx->field_rate }); - outlink->frame_rate = av_mul_q(inlink->frame_rate, - (AVRational) { ctx->field_rate, 1 }); + outl->frame_rate = av_mul_q(inl->frame_rate, + (AVRational) { ctx->field_rate, 1 }); return 0; } diff --git a/libavfilter/vf_dejudder.c b/libavfilter/vf_dejudder.c index d74cd7b15..75177e22a 100644 --- a/libavfilter/vf_dejudder.c +++ b/libavfilter/vf_dejudder.c @@ -49,11 +49,10 @@ * even output then setting frame_rate=1/0 in practice. */ +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/mathematics.h" #include "avfilter.h" -#include "internal.h" -#include "video.h" +#include "filters.h" typedef struct DejudderContext { const AVClass *class; @@ -79,12 +78,14 @@ AVFILTER_DEFINE_CLASS(dejudder); static int config_out_props(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; DejudderContext *s = ctx->priv; AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); outlink->time_base = av_mul_q(inlink->time_base, av_make_q(1, 2 * s->cycle)); - outlink->frame_rate = av_mul_q(inlink->frame_rate, av_make_q(2 * s->cycle, 1)); + outl->frame_rate = av_mul_q(inl->frame_rate, av_make_q(2 * s->cycle, 1)); av_log(ctx, AV_LOG_VERBOSE, "cycle:%d\n", s->cycle); diff --git a/libavfilter/vf_delogo.c b/libavfilter/vf_delogo.c index c049f273b..942deb1c5 100644 --- a/libavfilter/vf_delogo.c +++ b/libavfilter/vf_delogo.c @@ -33,7 +33,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/eval.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" static const char * const var_names[] = { "x", @@ -286,6 +286,7 @@ static int config_input(AVFilterLink *inlink) static int filter_frame(AVFilterLink *inlink, AVFrame *in) { + FilterLink *inl = ff_filter_link(inlink); DelogoContext *s = inlink->dst->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); @@ -297,7 +298,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVRational sar; int ret; - s->var_values[VAR_N] = inlink->frame_count_out; + s->var_values[VAR_N] = inl->frame_count_out; s->var_values[VAR_T] = TS2T(in->pts, inlink->time_base); s->x = av_expr_eval(s->x_pexpr, s->var_values, s); s->y = av_expr_eval(s->y_pexpr, s->var_values, s); diff --git a/libavfilter/vf_derain.c b/libavfilter/vf_derain.c index c8848dd7b..6dd179c94 100644 --- a/libavfilter/vf_derain.c +++ b/libavfilter/vf_derain.c @@ -27,7 +27,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "dnn_filter_common.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct DRContext { @@ -46,13 +46,10 @@ static const AVOption derain_options[] = { #if (CONFIG_LIBTENSORFLOW == 1) { "tensorflow", "tensorflow backend flag", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, .unit = "backend" }, #endif - { "model", "path to model file", OFFSET(dnnctx.model_filename), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS }, - { "input", "input name of the model", OFFSET(dnnctx.model_inputname), AV_OPT_TYPE_STRING, { .str = "x" }, 0, 0, FLAGS }, - { "output", "output name of the model", OFFSET(dnnctx.model_outputnames_string), AV_OPT_TYPE_STRING, { .str = "y" }, 0, 0, FLAGS }, { NULL } }; -AVFILTER_DEFINE_CLASS(derain); +AVFILTER_DNN_DEFINE_CLASS(derain, DNN_TF); static int filter_frame(AVFilterLink *inlink, AVFrame *in) { @@ -113,6 +110,7 @@ const AVFilter ff_vf_derain = { .name = "derain", .description = NULL_IF_CONFIG_SMALL("Apply derain filter to the input."), .priv_size = sizeof(DRContext), + .preinit = ff_dnn_filter_init_child_class, .init = init, .uninit = uninit, FILTER_INPUTS(derain_inputs), diff --git a/libavfilter/vf_deshake.c b/libavfilter/vf_deshake.c index 107b78a7d..af140b86d 100644 --- a/libavfilter/vf_deshake.c +++ b/libavfilter/vf_deshake.c @@ -50,7 +50,7 @@ */ #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "transform.h" #include "video.h" #include "libavutil/common.h" @@ -478,8 +478,10 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) aligned = !((intptr_t)in->data[0] & 15 | in->linesize[0] & 15); deshake->sad = av_pixelutils_get_sad_fn(4, 4, aligned, deshake); // 16x16, 2nd source unaligned - if (!deshake->sad) - return AVERROR(EINVAL); + if (!deshake->sad) { + ret = AVERROR(EINVAL); + goto fail; + } if (deshake->cx < 0 || deshake->cy < 0 || deshake->cw < 0 || deshake->ch < 0) { // Find the most likely global motion for the current frame diff --git a/libavfilter/vf_deshake_opencl.c b/libavfilter/vf_deshake_opencl.c index 128545a98..6f1d007a8 100644 --- a/libavfilter/vf_deshake_opencl.c +++ b/libavfilter/vf_deshake_opencl.c @@ -58,7 +58,6 @@ #include "framequeue.h" #include "filters.h" #include "transform.h" -#include "internal.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" @@ -1112,6 +1111,7 @@ static int deshake_opencl_init(AVFilterContext *avctx) DeshakeOpenCLContext *ctx = avctx->priv; AVFilterLink *outlink = avctx->outputs[0]; AVFilterLink *inlink = avctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); // Pointer to the host-side pattern buffer to be initialized and then copied // to the GPU PointPair *pattern_host = NULL; @@ -1146,7 +1146,7 @@ static int deshake_opencl_init(AVFilterContext *avctx) const int descriptor_buf_size = image_grid_32 * (BREIFN / 8); const int features_buf_size = image_grid_32 * sizeof(cl_float2); - const AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; + const AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hw_frames_ctx->sw_format); av_assert0(hw_frames_ctx); @@ -1155,7 +1155,7 @@ static int deshake_opencl_init(AVFilterContext *avctx) ff_framequeue_global_init(&fqg); ff_framequeue_init(&ctx->fq, &fqg); ctx->eof = 0; - ctx->smooth_window = (int)(av_q2d(avctx->inputs[0]->frame_rate) * ctx->smooth_window_multiplier); + ctx->smooth_window = (int)(av_q2d(inl->frame_rate) * ctx->smooth_window_multiplier); ctx->curr_frame = 0; memset(&zeroed_ulong8, 0, sizeof(cl_ulong8)); @@ -1369,6 +1369,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *input_frame) { AVFilterContext *avctx = link->dst; AVFilterLink *outlink = avctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); DeshakeOpenCLContext *deshake_ctx = avctx->priv; AVFrame *cropped_frame = NULL, *transformed_frame = NULL; int err; @@ -1387,8 +1388,8 @@ static int filter_frame(AVFilterLink *link, AVFrame *input_frame) size_t global_work[2]; int64_t duration; cl_mem src, transformed, dst; - cl_mem transforms[3]; - CropInfo crops[3]; + cl_mem transforms[AV_VIDEO_MAX_PLANES]; + CropInfo crops[AV_VIDEO_MAX_PLANES]; cl_event transform_event, crop_upscale_event; DebugMatches debug_matches; cl_int num_model_matches; @@ -1415,7 +1416,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *input_frame) if (input_frame->duration) { duration = input_frame->duration; } else { - duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + duration = av_rescale_q(1, av_inv_q(outl->frame_rate), outlink->time_base); } deshake_ctx->duration = input_frame->pts + duration; @@ -1518,7 +1519,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *input_frame) transforms[0] = deshake_ctx->transform_y; transforms[1] = transforms[2] = deshake_ctx->transform_uv; - for (int p = 0; p < FF_ARRAY_ELEMS(transformed_frame->data); p++) { + for (int p = 0; p < AV_VIDEO_MAX_PLANES; p++) { // Transform all of the planes appropriately src = (cl_mem)input_frame->data[p]; transformed = (cl_mem)transformed_frame->data[p]; @@ -1619,7 +1620,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *input_frame) crops[0] = deshake_ctx->crop_y; crops[1] = crops[2] = deshake_ctx->crop_uv; - for (int p = 0; p < FF_ARRAY_ELEMS(cropped_frame->data); p++) { + for (int p = 0; p < AV_VIDEO_MAX_PLANES; p++) { // Crop all of the planes appropriately dst = (cl_mem)cropped_frame->data[p]; transformed = (cl_mem)transformed_frame->data[p]; diff --git a/libavfilter/vf_despill.c b/libavfilter/vf_despill.c index 7e8ccf7fe..9365114b9 100644 --- a/libavfilter/vf_despill.c +++ b/libavfilter/vf_despill.c @@ -21,7 +21,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct DespillContext { const AVClass *class; diff --git a/libavfilter/vf_detelecine.c b/libavfilter/vf_detelecine.c index 255126da4..8eae7107c 100644 --- a/libavfilter/vf_detelecine.c +++ b/libavfilter/vf_detelecine.c @@ -28,8 +28,8 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct DetelecineContext { @@ -162,10 +162,12 @@ static int config_input(AVFilterLink *inlink) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; DetelecineContext *s = ctx->priv; const AVFilterLink *inlink = ctx->inputs[0]; - AVRational fps = inlink->frame_rate; + const FilterLink *inl = ff_filter_link(ctx->inputs[0]); + AVRational fps = inl->frame_rate; if (!fps.num || !fps.den) { av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; " @@ -174,9 +176,9 @@ static int config_output(AVFilterLink *outlink) } fps = av_mul_q(fps, av_inv_q(s->pts)); av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n", - inlink->frame_rate.num, inlink->frame_rate.den, fps.num, fps.den); + inl->frame_rate.num, inl->frame_rate.den, fps.num, fps.den); - outlink->frame_rate = fps; + outl->frame_rate = fps; outlink->time_base = av_mul_q(inlink->time_base, s->pts); av_log(ctx, AV_LOG_VERBOSE, "TB: %d/%d -> %d/%d\n", inlink->time_base.num, inlink->time_base.den, outlink->time_base.num, outlink->time_base.den); @@ -190,6 +192,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); DetelecineContext *s = ctx->priv; int i, len = 0, ret = 0, out = 0; @@ -329,7 +332,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) av_frame_copy_props(frame, inpicref); frame->pts = ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time) + - av_rescale(outlink->frame_count_in, s->ts_unit.num, + av_rescale(outl->frame_count_in, s->ts_unit.num, s->ts_unit.den); ret = ff_filter_frame(outlink, frame); } diff --git a/libavfilter/vf_displace.c b/libavfilter/vf_displace.c index 93de62fb5..6e3df139e 100644 --- a/libavfilter/vf_displace.c +++ b/libavfilter/vf_displace.c @@ -21,8 +21,8 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "video.h" enum EdgeMode { @@ -318,9 +318,11 @@ static int config_input(AVFilterLink *inlink) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; DisplaceContext *s = ctx->priv; AVFilterLink *srclink = ctx->inputs[0]; + FilterLink *sl = ff_filter_link(srclink); AVFilterLink *xlink = ctx->inputs[1]; AVFilterLink *ylink = ctx->inputs[2]; FFFrameSyncIn *in; @@ -343,7 +345,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = srclink->w; outlink->h = srclink->h; outlink->sample_aspect_ratio = srclink->sample_aspect_ratio; - outlink->frame_rate = srclink->frame_rate; + outl->frame_rate = sl->frame_rate; ret = ff_framesync_init(&s->fs, ctx, 3); if (ret < 0) diff --git a/libavfilter/vf_dnn_classify.c b/libavfilter/vf_dnn_classify.c index 11389c029..c52e50ca9 100644 --- a/libavfilter/vf_dnn_classify.c +++ b/libavfilter/vf_dnn_classify.c @@ -22,10 +22,10 @@ */ #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "filters.h" #include "dnn_filter_common.h" -#include "internal.h" #include "video.h" #include "libavutil/time.h" #include "libavutil/avstring.h" @@ -49,14 +49,13 @@ static const AVOption dnn_classify_options[] = { #if (CONFIG_LIBOPENVINO == 1) { "openvino", "openvino backend flag", 0, AV_OPT_TYPE_CONST, { .i64 = DNN_OV }, 0, 0, FLAGS, .unit = "backend" }, #endif - DNN_COMMON_OPTIONS { "confidence", "threshold of confidence", OFFSET2(confidence), AV_OPT_TYPE_FLOAT, { .dbl = 0.5 }, 0, 1, FLAGS}, { "labels", "path to labels file", OFFSET2(labels_filename), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS }, { "target", "which one to be classified", OFFSET2(target), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS }, { NULL } }; -AVFILTER_DEFINE_CLASS(dnn_classify); +AVFILTER_DNN_DEFINE_CLASS(dnn_classify, DNN_OV); static int dnn_classify_post_proc(AVFrame *frame, DNNData *output, uint32_t bbox_index, AVFilterContext *filter_ctx) { @@ -298,6 +297,7 @@ const AVFilter ff_vf_dnn_classify = { .name = "dnn_classify", .description = NULL_IF_CONFIG_SMALL("Apply DNN classify filter to the input."), .priv_size = sizeof(DnnClassifyContext), + .preinit = ff_dnn_filter_init_child_class, .init = dnn_classify_init, .uninit = dnn_classify_uninit, FILTER_INPUTS(ff_video_default_filterpad), diff --git a/libavfilter/vf_dnn_detect.c b/libavfilter/vf_dnn_detect.c index 8f5057352..f4abd38ec 100644 --- a/libavfilter/vf_dnn_detect.c +++ b/libavfilter/vf_dnn_detect.c @@ -22,10 +22,10 @@ */ #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "filters.h" #include "dnn_filter_common.h" -#include "internal.h" #include "video.h" #include "libavutil/time.h" #include "libavutil/avstring.h" @@ -69,7 +69,6 @@ static const AVOption dnn_detect_options[] = { #if (CONFIG_LIBOPENVINO == 1) { "openvino", "openvino backend flag", 0, AV_OPT_TYPE_CONST, { .i64 = DNN_OV }, 0, 0, FLAGS, .unit = "backend" }, #endif - DNN_COMMON_OPTIONS { "confidence", "threshold of confidence", OFFSET2(confidence), AV_OPT_TYPE_FLOAT, { .dbl = 0.5 }, 0, 1, FLAGS}, { "labels", "path to labels file", OFFSET2(labels_filename), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS }, { "model_type", "DNN detection model type", OFFSET2(model_type), AV_OPT_TYPE_INT, { .i64 = DDMT_SSD }, INT_MIN, INT_MAX, FLAGS, .unit = "model_type" }, @@ -84,7 +83,7 @@ static const AVOption dnn_detect_options[] = { { NULL } }; -AVFILTER_DEFINE_CLASS(dnn_detect); +AVFILTER_DNN_DEFINE_CLASS(dnn_detect, DNN_TF | DNN_OV); static inline float sigmoid(float x) { return 1.f / (1.f + exp(-x)); @@ -807,11 +806,13 @@ static av_cold void dnn_detect_uninit(AVFilterContext *context) DnnDetectContext *ctx = context->priv; AVDetectionBBox *bbox; ff_dnn_uninit(&ctx->dnnctx); - while(av_fifo_can_read(ctx->bboxes_fifo)) { - av_fifo_read(ctx->bboxes_fifo, &bbox, 1); - av_freep(&bbox); + if (ctx->bboxes_fifo) { + while (av_fifo_can_read(ctx->bboxes_fifo)) { + av_fifo_read(ctx->bboxes_fifo, &bbox, 1); + av_freep(&bbox); + } + av_fifo_freep2(&ctx->bboxes_fifo); } - av_fifo_freep2(&ctx->bboxes_fifo); av_freep(&ctx->anchors); free_detect_labels(ctx); } @@ -850,6 +851,7 @@ const AVFilter ff_vf_dnn_detect = { .name = "dnn_detect", .description = NULL_IF_CONFIG_SMALL("Apply DNN detect filter to the input."), .priv_size = sizeof(DnnDetectContext), + .preinit = ff_dnn_filter_init_child_class, .init = dnn_detect_init, .uninit = dnn_detect_uninit, FILTER_INPUTS(dnn_detect_inputs), diff --git a/libavfilter/vf_dnn_processing.c b/libavfilter/vf_dnn_processing.c index fdac31665..eb75f06f0 100644 --- a/libavfilter/vf_dnn_processing.c +++ b/libavfilter/vf_dnn_processing.c @@ -29,7 +29,6 @@ #include "libavutil/imgutils.h" #include "filters.h" #include "dnn_filter_common.h" -#include "internal.h" #include "video.h" #include "libswscale/swscale.h" #include "libavutil/time.h" @@ -54,11 +53,10 @@ static const AVOption dnn_processing_options[] = { #if (CONFIG_LIBTORCH == 1) { "torch", "torch backend flag", 0, AV_OPT_TYPE_CONST, { .i64 = DNN_TH }, 0, 0, FLAGS, "backend" }, #endif - DNN_COMMON_OPTIONS { NULL } }; -AVFILTER_DEFINE_CLASS(dnn_processing); +AVFILTER_DNN_DEFINE_CLASS(dnn_processing, DNN_TF | DNN_OV | DNN_TH); static av_cold int init(AVFilterContext *context) { @@ -373,6 +371,7 @@ const AVFilter ff_vf_dnn_processing = { .name = "dnn_processing", .description = NULL_IF_CONFIG_SMALL("Apply DNN processing filter to the input."), .priv_size = sizeof(DnnProcessingContext), + .preinit = ff_dnn_filter_init_child_class, .init = init, .uninit = uninit, FILTER_INPUTS(dnn_processing_inputs), diff --git a/libavfilter/vf_drawbox.c b/libavfilter/vf_drawbox.c index 27739dc89..46dfc59ab 100644 --- a/libavfilter/vf_drawbox.c +++ b/libavfilter/vf_drawbox.c @@ -36,7 +36,7 @@ #include "libavutil/detection_bbox.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" static const char *const var_names[] = { diff --git a/libavfilter/vf_drawbox_vaapi.c b/libavfilter/vf_drawbox_vaapi.c new file mode 100644 index 000000000..5b4f23066 --- /dev/null +++ b/libavfilter/vf_drawbox_vaapi.c @@ -0,0 +1,369 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/colorspace.h" +#include "libavutil/eval.h" +#include "libavutil/opt.h" + +#include "avfilter.h" +#include "filters.h" +#include "vaapi_vpp.h" +#include "video.h" + +static const char *const var_names[] = { + "in_h", "ih", + "in_w", "iw", + "x", + "y", + "h", + "w", + "t", + "fill", + NULL +}; + +enum var_name { + VAR_IN_H, VAR_IH, + VAR_IN_W, VAR_IW, + VAR_X, + VAR_Y, + VAR_H, + VAR_W, + VAR_T, + VAR_MAX, + VARS_NB +}; + +static const int NUM_EXPR_EVALS = 5; + +typedef struct DrawboxVAAPIContext { + VAAPIVPPContext vpp_ctx; // must be the first field + VARectangle outer_rect, inner_rect; + + /* The hardware frame context containing the frames for outer_rect. */ + AVBufferRef *outer_frames_ref; + AVHWFramesContext *outer_frames; + AVFrame *outer_frame; + + char *x_expr; + char *y_expr; + char *w_expr; + char *h_expr; + char *t_expr; + + int w, h; + int x, y; + int replace; + uint32_t thickness; + uint8_t drawbox_rgba[4]; + + int fill; + +} DrawboxVAAPIContext; + +static int drawbox_vaapi_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + AVFilterLink *inlink = avctx->inputs[0]; + DrawboxVAAPIContext *ctx = avctx->priv; + VAAPIVPPContext *vpp_ctx = avctx->priv; + double var_values[VARS_NB], res; + int ret, i; + char *expr; + + var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w; + var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h; + var_values[VAR_X] = NAN; + var_values[VAR_Y] = NAN; + var_values[VAR_H] = NAN; + var_values[VAR_W] = NAN; + var_values[VAR_T] = NAN; + + for (i = 0; i <= NUM_EXPR_EVALS; i++) { + /* evaluate expressions, fail on last iteration */ + var_values[VAR_MAX] = inlink->w; + if ((ret = av_expr_parse_and_eval(&res, (expr = ctx->x_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS) + goto fail; + ctx->x = var_values[VAR_X] = res; + + var_values[VAR_MAX] = inlink->h; + if ((ret = av_expr_parse_and_eval(&res, (expr = ctx->y_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS) + goto fail; + ctx->y = var_values[VAR_Y] = res; + + var_values[VAR_MAX] = inlink->w - ctx->x; + if ((ret = av_expr_parse_and_eval(&res, (expr = ctx->w_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS) + goto fail; + ctx->w = var_values[VAR_W] = res; + + var_values[VAR_MAX] = inlink->h - ctx->y; + if ((ret = av_expr_parse_and_eval(&res, (expr = ctx->h_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS) + goto fail; + ctx->h = var_values[VAR_H] = res; + + var_values[VAR_MAX] = INT_MAX; + if ((ret = av_expr_parse_and_eval(&res, (expr = ctx->t_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS) + goto fail; + ctx->thickness = var_values[VAR_T] = res; + } + + /* Sanity check */ + ctx->w = (ctx->w > 0) ? ctx->w : inlink->w; + ctx->h = (ctx->h > 0) ? ctx->h : inlink->h; + if (ctx->x + ctx->w > inlink->w) + ctx->w = inlink->w - ctx->x; + if (ctx->y + ctx->h > inlink->h) + ctx->h = inlink->h - ctx->y; + + ctx->outer_rect.x = ctx->x; + ctx->outer_rect.y = ctx->y; + ctx->outer_rect.width = ctx->w; + ctx->outer_rect.height = ctx->h; + + if (ctx->outer_rect.width <= ctx->thickness * 2 || + ctx->outer_rect.height <= ctx->thickness * 2) { + ctx->fill = 1; + } else { + ctx->fill = 0; + ctx->inner_rect.x = ctx->outer_rect.x + ctx->thickness; + ctx->inner_rect.y = ctx->outer_rect.y + ctx->thickness; + ctx->inner_rect.width = ctx->outer_rect.width - ctx->thickness * 2; + ctx->inner_rect.height = ctx->outer_rect.height - ctx->thickness * 2; + } + + vpp_ctx->output_width = inlink->w; + vpp_ctx->output_height = inlink->h; + + ret = ff_vaapi_vpp_config_output(outlink); + if (ret < 0) + return ret; + + ctx->outer_frames_ref = av_hwframe_ctx_alloc(vpp_ctx->device_ref); + if (!ctx->outer_frames_ref) { + return AVERROR(ENOMEM); + } + + ctx->outer_frames = (AVHWFramesContext*)ctx->outer_frames_ref->data; + + ctx->outer_frames->format = AV_PIX_FMT_VAAPI; + ctx->outer_frames->sw_format = vpp_ctx->input_frames->sw_format; + ctx->outer_frames->width = ctx->outer_rect.width; + ctx->outer_frames->height = ctx->outer_rect.height; + + return av_hwframe_ctx_init(ctx->outer_frames_ref); + +fail: + av_log(avctx, AV_LOG_ERROR, + "Error when evaluating the expression '%s'.\n", + expr); + return ret; +} + +static int drawbox_vaapi_filter_frame(AVFilterLink *link, AVFrame *input_frame) +{ + AVFilterContext *avctx = link->dst; + AVFilterLink *outlink = avctx->outputs[0]; + VAAPIVPPContext *vpp_ctx = avctx->priv; + DrawboxVAAPIContext *drawbox_ctx = avctx->priv; + AVFrame *output_frame = NULL; + VAProcPipelineParameterBuffer box_params; + VAProcPipelineParameterBuffer params[3]; + VABlendState blend_state = { + .flags = VA_BLEND_GLOBAL_ALPHA, + }; + VARectangle box[4]; + int err, nb_params = 0; + + if (!input_frame->hw_frames_ctx || + vpp_ctx->va_context == VA_INVALID_ID) { + err = AVERROR(EINVAL); + goto fail; + } + + if (!drawbox_ctx->outer_frame) { + drawbox_ctx->outer_frame = av_frame_alloc(); + if (!drawbox_ctx->outer_frame) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_hwframe_get_buffer(drawbox_ctx->outer_frames_ref, drawbox_ctx->outer_frame, 0); + if (err < 0) { + err = AVERROR(ENOMEM); + goto fail; + } + + /* Create image for the outer rect */ + err = ff_vaapi_vpp_init_params(avctx, &box_params, + input_frame, drawbox_ctx->outer_frame); + if (err < 0) + goto fail; + + blend_state.global_alpha = 0.0f; + box_params.surface_region = &drawbox_ctx->outer_rect; + box_params.blend_state = &blend_state; + box_params.output_background_color = (drawbox_ctx->drawbox_rgba[3] << 24 | + drawbox_ctx->drawbox_rgba[0] << 16 | + drawbox_ctx->drawbox_rgba[1] << 8 | + drawbox_ctx->drawbox_rgba[2]); + + err = ff_vaapi_vpp_render_picture(avctx, &box_params, drawbox_ctx->outer_frame); + if (err < 0) + goto fail; + } + + /* Draw outer & inner rects on the input video, then we can get a box*/ + output_frame = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output_frame) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + goto fail; + + err = ff_vaapi_vpp_init_params(avctx, ¶ms[nb_params], + input_frame, output_frame); + if (err < 0) + goto fail; + + box[0].x = 0; + box[0].y = 0; + box[0].width = link->w; + box[0].height = link->h; + params[nb_params].surface_region = &box[0]; + params[nb_params].output_background_color = 0; + nb_params++; + + err = ff_vaapi_vpp_init_params(avctx, ¶ms[nb_params], + drawbox_ctx->outer_frame, output_frame); + if (err < 0) + goto fail; + + box[1] = drawbox_ctx->outer_rect; + if (drawbox_ctx->drawbox_rgba[3] != 255 && !drawbox_ctx->replace) { + blend_state.global_alpha = (float)drawbox_ctx->drawbox_rgba[3] / 255; + params[nb_params].blend_state = &blend_state; + } + params[nb_params].output_region = &box[1]; + params[nb_params].output_background_color = 0; + nb_params++; + + if (!drawbox_ctx->fill) { + box[3] = box[2] = drawbox_ctx->inner_rect; + params[nb_params] = params[0]; + params[nb_params].surface_region = &box[2]; + params[nb_params].output_region = &box[3]; + params[nb_params].output_background_color = 0; + nb_params++; + } + + err = ff_vaapi_vpp_render_pictures(avctx, params, nb_params, output_frame); + if (err < 0) + goto fail; + + av_frame_free(&input_frame); + + return ff_filter_frame(outlink, output_frame); + +fail: + av_frame_free(&input_frame); + av_frame_free(&output_frame); + return err; +} + +static av_cold int drawbox_vaapi_init(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + + ff_vaapi_vpp_ctx_init(avctx); + vpp_ctx->pipeline_uninit = ff_vaapi_vpp_pipeline_uninit; + vpp_ctx->output_format = AV_PIX_FMT_NONE; + + return 0; +} + +static av_cold void drawbox_vaapi_uninit(AVFilterContext *avctx) +{ + DrawboxVAAPIContext *ctx = avctx->priv; + + av_frame_free(&ctx->outer_frame); + av_buffer_unref(&ctx->outer_frames_ref); + ff_vaapi_vpp_ctx_uninit(avctx); +} + +#define OFFSET(x) offsetof(DrawboxVAAPIContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption drawbox_vaapi_options[] = { + { "x", "set horizontal position of the left box edge", OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str="0" }, 0, 0, FLAGS }, + { "y", "set vertical position of the top box edge", OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str="0" }, 0, 0, FLAGS }, + { "width", "set width of the box", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, 0, 0, FLAGS }, + { "w", "set width of the box", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, 0, 0, FLAGS }, + { "height", "set height of the box", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, 0, 0, FLAGS }, + { "h", "set height of the box", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, 0, 0, FLAGS }, + { "color", "set color of the box", OFFSET(drawbox_rgba), AV_OPT_TYPE_COLOR, { .str = "black" }, 0, 0, FLAGS }, + { "c", "set color of the box", OFFSET(drawbox_rgba), AV_OPT_TYPE_COLOR, { .str = "black" }, 0, 0, FLAGS }, + { "thickness", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, 0, 0, FLAGS }, + { "t", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, 0, 0, FLAGS }, + { "replace", "replace color", OFFSET(replace), AV_OPT_TYPE_BOOL, { .i64=0 }, 0, 1, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(drawbox_vaapi); + +static const AVFilterPad drawbox_vaapi_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = drawbox_vaapi_filter_frame, + .config_props = &ff_vaapi_vpp_config_input, + }, +}; + +static const AVFilterPad drawbox_vaapi_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &drawbox_vaapi_config_output, + }, +}; + +const AVFilter ff_vf_drawbox_vaapi = { + .name = "drawbox_vaapi", + .description = NULL_IF_CONFIG_SMALL("Draw a colored box on the input video."), + .priv_size = sizeof(DrawboxVAAPIContext), + .priv_class = &drawbox_vaapi_class, + .init = &drawbox_vaapi_init, + .uninit = &drawbox_vaapi_uninit, + FILTER_INPUTS(drawbox_vaapi_inputs), + FILTER_OUTPUTS(drawbox_vaapi_outputs), + FILTER_QUERY_FUNC(&ff_vaapi_vpp_query_formats), + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c index 72629df2d..daaa1fd83 100644 --- a/libavfilter/vf_drawtext.c +++ b/libavfilter/vf_drawtext.c @@ -48,6 +48,7 @@ #include "libavutil/bprint.h" #include "libavutil/common.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/random_seed.h" #include "libavutil/parseutils.h" @@ -59,8 +60,8 @@ #include "libavutil/detection_bbox.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "textutils.h" #include "video.h" @@ -949,7 +950,7 @@ static int func_eval_expr_int_format(void *ctx, AVBPrint *bp, const char *functi argv[1][0], positions); } -static FFExpandTextFunction expand_text_functions[] = { +static const FFExpandTextFunction expand_text_functions[] = { { "e", 1, 1, func_eval_expr }, { "eif", 2, 3, func_eval_expr_int_format }, { "expr", 1, 1, func_eval_expr }, @@ -1216,6 +1217,7 @@ static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char ctx->priv = old; uninit(ctx); + av_opt_free(old); av_freep(&old); ctx->priv = new; @@ -1552,6 +1554,7 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame) { DrawTextContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); int x = 0, y = 0, ret; int shift_x64, shift_y64; int x64, y64; @@ -1595,7 +1598,7 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame) if (s->tc_opt_string) { char tcbuf[AV_TIMECODE_STR_SIZE]; - av_timecode_make_string(&s->tc, tcbuf, inlink->frame_count_out); + av_timecode_make_string(&s->tc, tcbuf, inl->frame_count_out); av_bprint_clear(bp); av_bprintf(bp, "%s%s", s->text, tcbuf); } @@ -1827,6 +1830,7 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame) static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; DrawTextContext *s = ctx->priv; @@ -1847,7 +1851,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) } } - if (s->reload && !(inlink->frame_count_out % s->reload)) { + if (s->reload && !(inl->frame_count_out % s->reload)) { if ((ret = ff_load_textfile(ctx, (const char *)s->textfile, &s->text, NULL)) < 0) { av_frame_free(&frame); return ret; @@ -1861,7 +1865,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) #endif } - s->var_values[VAR_N] = inlink->frame_count_out + s->start_number; + s->var_values[VAR_N] = inl->frame_count_out + s->start_number; s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ? NAN : frame->pts * av_q2d(inlink->time_base); diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c index 38c3503ce..32339a0d8 100644 --- a/libavfilter/vf_edgedetect.c +++ b/libavfilter/vf_edgedetect.c @@ -27,10 +27,11 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "edge_common.h" diff --git a/libavfilter/vf_elbg.c b/libavfilter/vf_elbg.c index 863366ccc..453147ca3 100644 --- a/libavfilter/vf_elbg.c +++ b/libavfilter/vf_elbg.c @@ -24,14 +24,15 @@ */ #include "libavcodec/elbg.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/random_seed.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct ELBGFilterContext { diff --git a/libavfilter/vf_entropy.c b/libavfilter/vf_entropy.c index 81772e6c9..e8dd7745d 100644 --- a/libavfilter/vf_entropy.c +++ b/libavfilter/vf_entropy.c @@ -18,11 +18,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct EntropyContext { diff --git a/libavfilter/vf_epx.c b/libavfilter/vf_epx.c index bae1b898b..6e66bdda3 100644 --- a/libavfilter/vf_epx.c +++ b/libavfilter/vf_epx.c @@ -18,7 +18,8 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "internal.h" + +#include "filters.h" #include "video.h" typedef struct EPXContext { diff --git a/libavfilter/vf_eq.c b/libavfilter/vf_eq.c index 30ff97694..f3855f66a 100644 --- a/libavfilter/vf_eq.c +++ b/libavfilter/vf_eq.c @@ -31,7 +31,8 @@ #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "internal.h" + +#include "filters.h" #include "vf_eq.h" #include "video.h" @@ -197,11 +198,12 @@ static av_cold void uninit(AVFilterContext *ctx) static int config_props(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); EQContext *eq = inlink->dst->priv; eq->var_values[VAR_N] = 0; - eq->var_values[VAR_R] = inlink->frame_rate.num == 0 || inlink->frame_rate.den == 0 ? - NAN : av_q2d(inlink->frame_rate); + eq->var_values[VAR_R] = l->frame_rate.num == 0 || l->frame_rate.den == 0 ? + NAN : av_q2d(l->frame_rate); return 0; } @@ -218,6 +220,7 @@ static const enum AVPixelFormat pixel_fmts_eq[] = { static int filter_frame(AVFilterLink *inlink, AVFrame *in) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = inlink->dst->outputs[0]; EQContext *eq = ctx->priv; @@ -234,7 +237,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); desc = av_pix_fmt_desc_get(inlink->format); - eq->var_values[VAR_N] = inlink->frame_count_out; + eq->var_values[VAR_N] = inl->frame_count_out; #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS { diff --git a/libavfilter/vf_estdif.c b/libavfilter/vf_estdif.c index b785c290f..477b8f8f9 100644 --- a/libavfilter/vf_estdif.c +++ b/libavfilter/vf_estdif.c @@ -23,7 +23,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ESTDIFContext { @@ -133,13 +133,15 @@ static const enum AVPixelFormat pix_fmts[] = { static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); ESTDIFContext *s = ctx->priv; outlink->time_base = av_mul_q(inlink->time_base, (AVRational){1, 2}); if (s->mode) - outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2, 1}); + outl->frame_rate = av_mul_q(inl->frame_rate, (AVRational){2, 1}); return 0; } @@ -526,6 +528,7 @@ static int config_input(AVFilterLink *inlink) static int request_frame(AVFilterLink *link) { + FilterLink *l = ff_filter_link(link); AVFilterContext *ctx = link->src; ESTDIFContext *s = ctx->priv; int ret; @@ -541,7 +544,7 @@ static int request_frame(AVFilterLink *link) if (!next) return AVERROR(ENOMEM); - next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(ctx->outputs[0]->frame_rate), + next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(l->frame_rate), ctx->outputs[0]->time_base); s->eof = 1; ret = filter_frame(ctx->inputs[0], next); diff --git a/libavfilter/vf_exposure.c b/libavfilter/vf_exposure.c index 926d784a8..efdae40e0 100644 --- a/libavfilter/vf_exposure.c +++ b/libavfilter/vf_exposure.c @@ -22,7 +22,7 @@ #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ExposureContext { diff --git a/libavfilter/vf_extractplanes.c b/libavfilter/vf_extractplanes.c index 8f1c9cca4..8873abf84 100644 --- a/libavfilter/vf_extractplanes.c +++ b/libavfilter/vf_extractplanes.c @@ -29,7 +29,6 @@ #include "drawutils.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #define PLANE_R 0x01 diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c index cd64a82f2..fb04c7ce3 100644 --- a/libavfilter/vf_fade.c +++ b/libavfilter/vf_fade.c @@ -33,8 +33,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #define R 0 @@ -442,6 +442,7 @@ static int config_input(AVFilterLink *inlink) static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; FadeContext *s = ctx->priv; @@ -449,7 +450,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (s->fade_state == VF_FADE_WAITING) { s->factor=0; if (frame->pts >= s->start_time_pts - && inlink->frame_count_out >= s->start_frame) { + && inl->frame_count_out >= s->start_frame) { // Time to start fading s->fade_state = VF_FADE_FADING; @@ -460,15 +461,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) // Save start frame in case we are starting based on time and fading based on frames if (s->start_time_pts != 0 && s->start_frame == 0) { - s->start_frame = inlink->frame_count_out; + s->start_frame = inl->frame_count_out; } } } if (s->fade_state == VF_FADE_FADING) { if (s->duration_pts == 0) { // Fading based on frame count - s->factor = (inlink->frame_count_out - s->start_frame) * s->fade_per_frame; - if (inlink->frame_count_out > s->start_frame + s->nb_frames) { + s->factor = (inl->frame_count_out - s->start_frame) * s->fade_per_frame; + if (inl->frame_count_out > s->start_frame + s->nb_frames) { s->fade_state = VF_FADE_DONE; } diff --git a/libavfilter/vf_feedback.c b/libavfilter/vf_feedback.c index 2fb7d4805..ddc53cad2 100644 --- a/libavfilter/vf_feedback.c +++ b/libavfilter/vf_feedback.c @@ -28,7 +28,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct FeedbackContext { diff --git a/libavfilter/vf_fftdnoiz.c b/libavfilter/vf_fftdnoiz.c index 93fc23bc4..cbc49fe9a 100644 --- a/libavfilter/vf_fftdnoiz.c +++ b/libavfilter/vf_fftdnoiz.c @@ -20,10 +20,12 @@ #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/tx.h" -#include "internal.h" + +#include "filters.h" #include "video.h" #include "window_func.h" diff --git a/libavfilter/vf_fftfilt.c b/libavfilter/vf_fftfilt.c index 634d2a491..b60d47edc 100644 --- a/libavfilter/vf_fftfilt.c +++ b/libavfilter/vf_fftfilt.c @@ -24,11 +24,11 @@ * FFT domain filtering. */ -#include "internal.h" +#include "filters.h" #include "video.h" #include "libavutil/common.h" #include "libavutil/cpu.h" -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/tx.h" @@ -284,10 +284,11 @@ static av_cold int initialize(AVFilterContext *ctx) static void do_eval(FFTFILTContext *s, AVFilterLink *inlink, int plane) { + FilterLink *l = ff_filter_link(inlink); double values[VAR_VARS_NB]; int i, j; - values[VAR_N] = inlink->frame_count_out; + values[VAR_N] = l->frame_count_out; values[VAR_W] = s->planewidth[plane]; values[VAR_H] = s->planeheight[plane]; values[VAR_WS] = s->rdft_hlen[plane]; @@ -382,11 +383,9 @@ static int config_props(AVFilterLink *inlink) if (s->depth <= 8) { s->rdft_horizontal = rdft_horizontal8; s->irdft_horizontal = irdft_horizontal8; - } else if (s->depth > 8) { + } else { s->rdft_horizontal = rdft_horizontal16; s->irdft_horizontal = irdft_horizontal16; - } else { - return AVERROR_BUG; } return 0; } diff --git a/libavfilter/vf_field.c b/libavfilter/vf_field.c index 525f1da4a..2d730b3dd 100644 --- a/libavfilter/vf_field.c +++ b/libavfilter/vf_field.c @@ -27,7 +27,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" enum FieldType { FIELD_TYPE_TOP = 0, FIELD_TYPE_BOTTOM }; diff --git a/libavfilter/vf_fieldhint.c b/libavfilter/vf_fieldhint.c index 8d0e71574..92e3c5c8b 100644 --- a/libavfilter/vf_fieldhint.c +++ b/libavfilter/vf_fieldhint.c @@ -25,8 +25,8 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" enum HintModes { @@ -113,8 +113,10 @@ static int config_input(AVFilterLink *inlink) static int filter_frame(AVFilterLink *inlink, AVFrame *in) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); FieldHintContext *s = ctx->priv; AVFrame *out, *top, *bottom; char buf[1024] = { 0 }; @@ -152,9 +154,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } switch (s->mode) { case ABSOLUTE_HINT: - if (tf > outlink->frame_count_in + 1 || tf < FFMAX(0, outlink->frame_count_in - 1) || - bf > outlink->frame_count_in + 1 || bf < FFMAX(0, outlink->frame_count_in - 1)) { - av_log(ctx, AV_LOG_ERROR, "Out of range frames %"PRId64" and/or %"PRId64" on line %"PRId64" for %"PRId64". input frame.\n", tf, bf, s->line, inlink->frame_count_out); + if (tf > outl->frame_count_in + 1 || tf < FFMAX(0, outl->frame_count_in - 1) || + bf > outl->frame_count_in + 1 || bf < FFMAX(0, outl->frame_count_in - 1)) { + av_log(ctx, AV_LOG_ERROR, "Out of range frames %"PRId64" and/or %"PRId64" on line %"PRId64" for %"PRId64". input frame.\n", tf, bf, s->line, inl->frame_count_out); return AVERROR_INVALIDDATA; } break; @@ -162,7 +164,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) case RELATIVE_HINT: if (tf > 1 || tf < -1 || bf > 1 || bf < -1) { - av_log(ctx, AV_LOG_ERROR, "Out of range %"PRId64" and/or %"PRId64" on line %"PRId64" for %"PRId64". input frame.\n", tf, bf, s->line, inlink->frame_count_out); + av_log(ctx, AV_LOG_ERROR, "Out of range %"PRId64" and/or %"PRId64" on line %"PRId64" for %"PRId64". input frame.\n", tf, bf, s->line, inl->frame_count_out); return AVERROR_INVALIDDATA; } break; @@ -175,7 +177,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) fseek(s->hint, 0, SEEK_SET); continue; } - av_log(ctx, AV_LOG_ERROR, "Missing entry for %"PRId64". input frame.\n", inlink->frame_count_out); + av_log(ctx, AV_LOG_ERROR, "Missing entry for %"PRId64". input frame.\n", inl->frame_count_out); return AVERROR_INVALIDDATA; } } @@ -187,8 +189,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) switch (s->mode) { case ABSOLUTE_HINT: - top = s->frame[tf - outlink->frame_count_in + 1]; - bottom = s->frame[bf - outlink->frame_count_in + 1]; + top = s->frame[tf - outl->frame_count_in + 1]; + bottom = s->frame[bf - outl->frame_count_in + 1]; break; case PATTERN_HINT: case RELATIVE_HINT: diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c index bcf0ba49e..9198c894f 100644 --- a/libavfilter/vf_fieldmatch.c +++ b/libavfilter/vf_fieldmatch.c @@ -34,12 +34,12 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/timestamp.h" #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #define INPUT_MAIN 0 @@ -680,6 +680,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); FieldMatchContext *fm = ctx->priv; int combs[] = { -1, -1, -1, -1, -1 }; int order, field, i, match, interlaced_frame, sc = 0, ret = 0; @@ -752,7 +753,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) /* scene change check */ if (fm->combmatch == COMBMATCH_SC) { - if (fm->lastn == outlink->frame_count_in - 1) { + if (fm->lastn == outl->frame_count_in - 1) { if (fm->lastscdiff > fm->scthresh) sc = 1; } else if (luma_abs_diff(fm->prv, fm->src) > fm->scthresh) { @@ -760,7 +761,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } if (!sc) { - fm->lastn = outlink->frame_count_in; + fm->lastn = outl->frame_count_in; fm->lastscdiff = luma_abs_diff(fm->src, fm->nxt); sc = fm->lastscdiff > fm->scthresh; } @@ -830,7 +831,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (interlaced_frame) { dst->flags |= AV_FRAME_FLAG_INTERLACED; av_log(ctx, AV_LOG_WARNING, "Frame #%"PRId64" at %s is still interlaced\n", - outlink->frame_count_in, av_ts2timestr(in->pts, &inlink->time_base)); + outl->frame_count_in, av_ts2timestr(in->pts, &inlink->time_base)); #if FF_API_INTERLACED_FRAME FF_DISABLE_DEPRECATION_WARNINGS dst->top_field_first = field; @@ -1045,16 +1046,18 @@ static av_cold void fieldmatch_uninit(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; FieldMatchContext *fm = ctx->priv; const AVFilterLink *inlink = ctx->inputs[fm->ppsrc ? INPUT_CLEANSRC : INPUT_MAIN]; + FilterLink *inl = ff_filter_link(ctx->inputs[fm->ppsrc ? INPUT_CLEANSRC : INPUT_MAIN]); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); fm->bpc = (desc->comp[0].depth + 7) / 8; outlink->time_base = inlink->time_base; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; - outlink->frame_rate = inlink->frame_rate; + outl->frame_rate = inl->frame_rate; outlink->w = inlink->w; outlink->h = inlink->h; return 0; diff --git a/libavfilter/vf_fieldorder.c b/libavfilter/vf_fieldorder.c index 21d62b93f..46b7f4bb3 100644 --- a/libavfilter/vf_fieldorder.c +++ b/libavfilter/vf_fieldorder.c @@ -28,8 +28,8 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct FieldOrderContext { diff --git a/libavfilter/vf_fillborders.c b/libavfilter/vf_fillborders.c index 2778cb486..619b2cf75 100644 --- a/libavfilter/vf_fillborders.c +++ b/libavfilter/vf_fillborders.c @@ -25,7 +25,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum { Y, U, V, A }; diff --git a/libavfilter/vf_find_rect.c b/libavfilter/vf_find_rect.c index 9f4ee1e32..1b11fbbb9 100644 --- a/libavfilter/vf_find_rect.c +++ b/libavfilter/vf_find_rect.c @@ -22,9 +22,10 @@ * @todo switch to dualinput */ -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "internal.h" + +#include "filters.h" #include "video.h" #include "lavfutils.h" @@ -172,6 +173,7 @@ static float search(FOCContext *foc, int pass, int maxpass, int xmin, int xmax, static int filter_frame(AVFilterLink *inlink, AVFrame *in) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; FOCContext *foc = ctx->priv; float best_score; @@ -208,7 +210,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } av_log(ctx, AV_LOG_INFO, "Found at n=%"PRId64" pts_time=%f x=%d y=%d with score=%f\n", - inlink->frame_count_out, TS2D(in->pts) * av_q2d(inlink->time_base), + inl->frame_count_out, TS2D(in->pts) * av_q2d(inlink->time_base), best_x, best_y, best_score); foc->last_x = best_x; foc->last_y = best_y; diff --git a/libavfilter/vf_flip_vulkan.c b/libavfilter/vf_flip_vulkan.c index ecd2567eb..127139680 100644 --- a/libavfilter/vf_flip_vulkan.c +++ b/libavfilter/vf_flip_vulkan.c @@ -23,7 +23,8 @@ #include "libavutil/opt.h" #include "vulkan_filter.h" #include "vulkan_spirv.h" -#include "internal.h" + +#include "filters.h" #include "video.h" enum FlipType { diff --git a/libavfilter/vf_floodfill.c b/libavfilter/vf_floodfill.c index d5fa42651..0d4c86173 100644 --- a/libavfilter/vf_floodfill.c +++ b/libavfilter/vf_floodfill.c @@ -18,12 +18,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/intreadwrite.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" typedef struct Points { diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c index 3a353bbb0..da39625fe 100644 --- a/libavfilter/vf_format.c +++ b/libavfilter/vf_format.c @@ -33,8 +33,8 @@ #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct FormatContext { @@ -85,6 +85,21 @@ static av_cold int invert_formats(AVFilterFormats **fmts, return 0; } +static int parse_pixel_format(enum AVPixelFormat *ret, const char *arg, void *log_ctx) +{ + char *tail; + int pix_fmt = av_get_pix_fmt(arg); + if (pix_fmt == AV_PIX_FMT_NONE) { + pix_fmt = strtol(arg, &tail, 0); + if (*tail || !av_pix_fmt_desc_get(pix_fmt)) { + av_log(log_ctx, AV_LOG_ERROR, "Invalid pixel format '%s'\n", arg); + return AVERROR(EINVAL); + } + } + *ret = pix_fmt; + return 0; +} + static av_cold int init(AVFilterContext *ctx) { FormatContext *s = ctx->priv; @@ -95,7 +110,7 @@ static av_cold int init(AVFilterContext *ctx) sep = strchr(cur, '|'); if (sep && *sep) *sep++ = 0; - if ((ret = ff_parse_pixel_format(&pix_fmt, cur, ctx)) < 0 || + if ((ret = parse_pixel_format(&pix_fmt, cur, ctx)) < 0 || (ret = ff_add_format(&s->formats, pix_fmt)) < 0) return ret; } diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c index 02636d0f7..3eb43c0b2 100644 --- a/libavfilter/vf_fps.c +++ b/libavfilter/vf_fps.c @@ -36,7 +36,6 @@ #include "avfilter.h" #include "ccfifo.h" #include "filters.h" -#include "internal.h" #include "video.h" enum EOFAction { @@ -178,12 +177,14 @@ static int config_props(AVFilterLink* outlink) { AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); FPSContext *s = ctx->priv; double var_values[VARS_NB], res; int ret; - var_values[VAR_SOURCE_FPS] = av_q2d(inlink->frame_rate); + var_values[VAR_SOURCE_FPS] = av_q2d(il->frame_rate); var_values[VAR_FPS_NTSC] = ntsc_fps; var_values[VAR_FPS_PAL] = pal_fps; var_values[VAR_FPS_FILM] = film_fps; @@ -194,8 +195,8 @@ static int config_props(AVFilterLink* outlink) if (ret < 0) return ret; - outlink->frame_rate = av_d2q(res, INT_MAX); - outlink->time_base = av_inv_q(outlink->frame_rate); + ol->frame_rate = av_d2q(res, INT_MAX); + outlink->time_base = av_inv_q(ol->frame_rate); /* Calculate the input and output pts offsets for start_time */ if (s->start_time != DBL_MAX && s->start_time != AV_NOPTS_VALUE) { @@ -214,13 +215,13 @@ static int config_props(AVFilterLink* outlink) s->in_pts_off, s->out_pts_off, s->start_time); } - ret = ff_ccfifo_init(&s->cc_fifo, outlink->frame_rate, ctx); + ret = ff_ccfifo_init(&s->cc_fifo, ol->frame_rate, ctx); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n"); return ret; } - av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", outlink->frame_rate.num, outlink->frame_rate.den); + av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", ol->frame_rate.num, ol->frame_rate.den); return 0; } diff --git a/libavfilter/vf_framepack.c b/libavfilter/vf_framepack.c index 3b915dddd..daab49cff 100644 --- a/libavfilter/vf_framepack.c +++ b/libavfilter/vf_framepack.c @@ -34,7 +34,6 @@ #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" #define LEFT 0 @@ -91,11 +90,14 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; FramepackContext *s = outlink->src->priv; + FilterLink *leftl = ff_filter_link(ctx->inputs[LEFT]); + FilterLink *rightl = ff_filter_link(ctx->inputs[RIGHT]); + FilterLink *ol = ff_filter_link(outlink); int width = ctx->inputs[LEFT]->w; int height = ctx->inputs[LEFT]->h; AVRational time_base = ctx->inputs[LEFT]->time_base; - AVRational frame_rate = ctx->inputs[LEFT]->frame_rate; + AVRational frame_rate = leftl->frame_rate; // check size and fps match on the other input if (width != ctx->inputs[RIGHT]->w || @@ -112,12 +114,12 @@ static int config_output(AVFilterLink *outlink) ctx->inputs[RIGHT]->time_base.num, ctx->inputs[RIGHT]->time_base.den); return AVERROR_INVALIDDATA; - } else if (av_cmp_q(frame_rate, ctx->inputs[RIGHT]->frame_rate) != 0) { + } else if (av_cmp_q(frame_rate, rightl->frame_rate) != 0) { av_log(ctx, AV_LOG_ERROR, "Left and right framerates differ (%d/%d vs %d/%d).\n", frame_rate.num, frame_rate.den, - ctx->inputs[RIGHT]->frame_rate.num, - ctx->inputs[RIGHT]->frame_rate.den); + rightl->frame_rate.num, + rightl->frame_rate.den); return AVERROR_INVALIDDATA; } @@ -148,7 +150,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = width; outlink->h = height; outlink->time_base = time_base; - outlink->frame_rate = frame_rate; + ol->frame_rate = frame_rate; return 0; } @@ -312,6 +314,7 @@ static int try_push_frame(AVFilterContext *ctx) { FramepackContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *l = ff_filter_link(outlink); AVStereo3D *stereo; int ret, i; @@ -323,8 +326,8 @@ static int try_push_frame(AVFilterContext *ctx) for (i = 0; i < 2; i++) { // set correct timestamps if (pts != AV_NOPTS_VALUE) { - s->input_views[i]->pts = i == 0 ? pts * 2 : pts * 2 + av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); - s->input_views[i]->duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + s->input_views[i]->pts = i == 0 ? pts * 2 : pts * 2 + av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base); + s->input_views[i]->duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base); } // set stereo3d side data diff --git a/libavfilter/vf_framerate.c b/libavfilter/vf_framerate.c index 0c31f77cc..9e7cac660 100644 --- a/libavfilter/vf_framerate.c +++ b/libavfilter/vf_framerate.c @@ -35,7 +35,6 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" #include "video.h" #include "filters.h" #include "framerate.h" @@ -374,6 +373,7 @@ retry: static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; + FilterLink *l = ff_filter_link(outlink); FrameRateContext *s = ctx->priv; int exact; @@ -399,7 +399,7 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_WARNING, "Timebase conversion is not exact\n"); } - outlink->frame_rate = s->dest_frame_rate; + l->frame_rate = s->dest_frame_rate; outlink->time_base = s->dest_time_base; ff_dlog(ctx, diff --git a/libavfilter/vf_framestep.c b/libavfilter/vf_framestep.c index b8eee53b5..98cbf0540 100644 --- a/libavfilter/vf_framestep.c +++ b/libavfilter/vf_framestep.c @@ -25,7 +25,7 @@ #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct NullContext { @@ -48,22 +48,25 @@ static int config_output_props(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; FrameStepContext *framestep = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); - outlink->frame_rate = - av_div_q(inlink->frame_rate, (AVRational){framestep->frame_step, 1}); + ol->frame_rate = + av_div_q(il->frame_rate, (AVRational){framestep->frame_step, 1}); av_log(ctx, AV_LOG_VERBOSE, "step:%d frame_rate:%d/%d(%f) -> frame_rate:%d/%d(%f)\n", framestep->frame_step, - inlink->frame_rate.num, inlink->frame_rate.den, av_q2d(inlink->frame_rate), - outlink->frame_rate.num, outlink->frame_rate.den, av_q2d(outlink->frame_rate)); + il->frame_rate.num, il->frame_rate.den, av_q2d(il->frame_rate), + ol->frame_rate.num, ol->frame_rate.den, av_q2d(ol->frame_rate)); return 0; } static int filter_frame(AVFilterLink *inlink, AVFrame *ref) { + FilterLink *inl = ff_filter_link(inlink); FrameStepContext *framestep = inlink->dst->priv; - if (!(inlink->frame_count_out % framestep->frame_step)) { + if (!(inl->frame_count_out % framestep->frame_step)) { return ff_filter_frame(inlink->dst->outputs[0], ref); } else { av_frame_free(&ref); diff --git a/libavfilter/vf_freezedetect.c b/libavfilter/vf_freezedetect.c index 18d392d9a..ef04a2764 100644 --- a/libavfilter/vf_freezedetect.c +++ b/libavfilter/vf_freezedetect.c @@ -146,6 +146,7 @@ static int activate(AVFilterContext *ctx) int ret; AVFilterLink *inlink = ctx->inputs[0]; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *l = ff_filter_link(inlink); FreezeDetectContext *s = ctx->priv; AVFrame *frame; @@ -162,7 +163,7 @@ static int activate(AVFilterContext *ctx) if (s->reference_frame) { int64_t duration; if (s->reference_frame->pts == AV_NOPTS_VALUE || frame->pts == AV_NOPTS_VALUE || frame->pts < s->reference_frame->pts) // Discontinuity? - duration = inlink->frame_rate.num > 0 ? av_rescale_q(s->n - s->reference_n, av_inv_q(inlink->frame_rate), AV_TIME_BASE_Q) : 0; + duration = l->frame_rate.num > 0 ? av_rescale_q(s->n - s->reference_n, av_inv_q(l->frame_rate), AV_TIME_BASE_Q) : 0; else duration = av_rescale_q(frame->pts - s->reference_frame->pts, inlink->time_base, AV_TIME_BASE_Q); diff --git a/libavfilter/vf_freezeframes.c b/libavfilter/vf_freezeframes.c index a272336ff..ff8112ce1 100644 --- a/libavfilter/vf_freezeframes.c +++ b/libavfilter/vf_freezeframes.c @@ -25,7 +25,6 @@ #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" typedef struct FreezeFramesContext { @@ -52,6 +51,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; AVFilterLink *sourcelink = ctx->inputs[0]; AVFilterLink *replacelink = ctx->inputs[1]; + FilterLink *il = ff_filter_link(sourcelink); + FilterLink *ol = ff_filter_link(outlink); if (sourcelink->w != replacelink->w || sourcelink->h != replacelink->h) { av_log(ctx, AV_LOG_ERROR, @@ -65,19 +66,21 @@ static int config_output(AVFilterLink *outlink) outlink->h = sourcelink->h; outlink->time_base = sourcelink->time_base; outlink->sample_aspect_ratio = sourcelink->sample_aspect_ratio; - outlink->frame_rate = sourcelink->frame_rate; + ol->frame_rate = il->frame_rate; return 0; } static int activate(AVFilterContext *ctx) { + FilterLink *inl0 = ff_filter_link(ctx->inputs[0]); + FilterLink *inl1 = ff_filter_link(ctx->inputs[1]); AVFilterLink *outlink = ctx->outputs[0]; FreezeFramesContext *s = ctx->priv; AVFrame *frame = NULL; - int drop = ctx->inputs[0]->frame_count_out >= s->first && - ctx->inputs[0]->frame_count_out <= s->last; - int replace = ctx->inputs[1]->frame_count_out == s->replace; + int drop = inl0->frame_count_out >= s->first && + inl0->frame_count_out <= s->last; + int replace = inl1->frame_count_out == s->replace; int ret; FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c index 7dccd5946..83ca9c98b 100644 --- a/libavfilter/vf_frei0r.c +++ b/libavfilter/vf_frei0r.c @@ -39,8 +39,8 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef f0r_instance_t (*f0r_construct_f)(unsigned int width, unsigned int height); @@ -450,6 +450,7 @@ static av_cold int source_init(AVFilterContext *ctx) static int source_config_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; + FilterLink *l = ff_filter_link(outlink); Frei0rContext *s = ctx->priv; if (av_image_check_size(s->w, s->h, 0, ctx) < 0) @@ -457,7 +458,7 @@ static int source_config_props(AVFilterLink *outlink) outlink->w = s->w; outlink->h = s->h; outlink->time_base = s->time_base; - outlink->frame_rate = av_inv_q(s->time_base); + l->frame_rate = av_inv_q(s->time_base); outlink->sample_aspect_ratio = (AVRational){1,1}; if (s->destruct && s->instance) diff --git a/libavfilter/vf_fspp.c b/libavfilter/vf_fspp.c index 8f4439011..c35217e9f 100644 --- a/libavfilter/vf_fspp.c +++ b/libavfilter/vf_fspp.c @@ -37,10 +37,12 @@ #include "libavutil/emms.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "internal.h" + +#include "filters.h" #include "qp_table.h" #include "vf_fspp.h" #include "video.h" diff --git a/libavfilter/vf_fsync.c b/libavfilter/vf_fsync.c index a18f1a009..8636ada0f 100644 --- a/libavfilter/vf_fsync.c +++ b/libavfilter/vf_fsync.c @@ -27,6 +27,7 @@ #include "libavutil/avstring.h" #include "libavutil/error.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavformat/avio.h" #include "video.h" @@ -223,6 +224,7 @@ end: static int fsync_config_props(AVFilterLink* outlink) { AVFilterContext *ctx = outlink->src; + FilterLink *l = ff_filter_link(outlink); FsyncContext *s = ctx->priv; int ret; @@ -234,7 +236,7 @@ static int fsync_config_props(AVFilterLink* outlink) return AVERROR_INVALIDDATA; } - outlink->frame_rate = av_make_q(1, 0); // unknown or dynamic + l->frame_rate = av_make_q(1, 0); // unknown or dynamic outlink->time_base = av_make_q(s->tb_num, s->tb_den); return 0; diff --git a/libavfilter/vf_gblur.c b/libavfilter/vf_gblur.c index 6ce2c8473..a994ee5dd 100644 --- a/libavfilter/vf_gblur.c +++ b/libavfilter/vf_gblur.c @@ -28,11 +28,12 @@ #include #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "gblur.h" -#include "internal.h" #include "vf_gblur_init.h" #include "video.h" diff --git a/libavfilter/vf_gblur_vulkan.c b/libavfilter/vf_gblur_vulkan.c index bac05b87b..d0fb6c994 100644 --- a/libavfilter/vf_gblur_vulkan.c +++ b/libavfilter/vf_gblur_vulkan.c @@ -19,11 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/random_seed.h" #include "libavutil/opt.h" #include "vulkan_filter.h" #include "vulkan_spirv.h" -#include "internal.h" + +#include "filters.h" #include "video.h" #define CGS 32 @@ -187,7 +189,7 @@ static int init_gblur_pipeline(GBlurVulkanContext *s, FFVulkanPipeline *pl, RET(ff_vk_unmap_buffer(&s->vkctx, params_buf, 1)); RET(ff_vk_set_descriptor_buffer(&s->vkctx, pl, NULL, 1, 0, 0, - params_buf->address, params_buf->size, + params_buf, 0, params_buf->size, VK_FORMAT_UNDEFINED)); fail: diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c index ff243ad84..bb95f45e2 100644 --- a/libavfilter/vf_geq.c +++ b/libavfilter/vf_geq.c @@ -29,10 +29,12 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" + +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #define MAX_NB_THREADS 32 @@ -111,8 +113,12 @@ static inline double getpix(void *priv, double x, double y, int plane) return 0; if (geq->interpolation == INTERP_BILINEAR) { - xi = x = av_clipd(x, 0, w - 2); - yi = y = av_clipd(y, 0, h - 2); + int xn, yn; + + xi = x = av_clipd(x, 0, w - 1); + yi = y = av_clipd(y, 0, h - 1); + xn = FFMIN(xi + 1, w - 1); + yn = FFMIN(yi + 1, h - 1); x -= xi; y -= yi; @@ -121,17 +127,17 @@ static inline double getpix(void *priv, double x, double y, int plane) const uint16_t *src16 = (const uint16_t*)src; linesize /= 2; - return (1-y)*((1-x)*src16[xi + yi * linesize] + x*src16[xi + 1 + yi * linesize]) - + y *((1-x)*src16[xi + (yi+1) * linesize] + x*src16[xi + 1 + (yi+1) * linesize]); + return (1-y)*((1-x)*src16[xi + yi * linesize] + x*src16[xn + yi * linesize]) + + y *((1-x)*src16[xi + yn * linesize] + x*src16[xn + yn * linesize]); } else if (geq->bps == 32) { const float *src32 = (const float*)src; linesize /= 4; - return (1-y)*((1-x)*src32[xi + yi * linesize] + x*src32[xi + 1 + yi * linesize]) - + y *((1-x)*src32[xi + (yi+1) * linesize] + x*src32[xi + 1 + (yi+1) * linesize]); + return (1-y)*((1-x)*src32[xi + yi * linesize] + x*src32[xn + yi * linesize]) + + y *((1-x)*src32[xi + yn * linesize] + x*src32[xn + yn * linesize]); } else if (geq->bps == 8) { - return (1-y)*((1-x)*src[xi + yi * linesize] + x*src[xi + 1 + yi * linesize]) - + y *((1-x)*src[xi + (yi+1) * linesize] + x*src[xi + 1 + (yi+1) * linesize]); + return (1-y)*((1-x)*src[xi + yi * linesize] + x*src[xn + yi * linesize]) + + y *((1-x)*src[xi + yn * linesize] + x*src[xn + yn * linesize]); } } else { xi = av_clipd(x, 0, w - 1); @@ -448,13 +454,14 @@ static int slice_geq_filter(AVFilterContext *ctx, void *arg, int jobnr, int nb_j static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in) { int plane; + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; const int nb_threads = FFMIN(MAX_NB_THREADS, ff_filter_get_nb_threads(ctx)); GEQContext *geq = ctx->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; AVFrame *out; - geq->values[VAR_N] = inlink->frame_count_out, + geq->values[VAR_N] = inl->frame_count_out, geq->values[VAR_T] = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base), geq->picref = in; diff --git a/libavfilter/vf_gradfun.c b/libavfilter/vf_gradfun.c index e8d9cae82..6b52e09f2 100644 --- a/libavfilter/vf_gradfun.c +++ b/libavfilter/vf_gradfun.c @@ -35,12 +35,13 @@ #include "libavutil/emms.h" #include "libavutil/imgutils.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "gradfun.h" -#include "internal.h" #include "video.h" DECLARE_ALIGNED(16, static const uint16_t, dither)[8][8] = { diff --git a/libavfilter/vf_grayworld.c b/libavfilter/vf_grayworld.c index e9c959416..91b097a4b 100644 --- a/libavfilter/vf_grayworld.c +++ b/libavfilter/vf_grayworld.c @@ -26,10 +26,10 @@ */ #include "libavutil/imgutils.h" -#include "libavutil/opt.h" +#include "libavutil/mem.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ThreadData { @@ -40,20 +40,11 @@ typedef struct ThreadData { } ThreadData; typedef struct GrayWorldContext { - const AVClass *class; float *tmpplab; int *line_count_pels; float *line_sum; } GrayWorldContext; -#define OFFSET(x) offsetof(GrayWorldContext, x) -#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_RUNTIME_PARAM -static const AVOption grayworld_options[] = { - { NULL } -}; - -AVFILTER_DEFINE_CLASS(grayworld); - static void apply_matrix(const float matrix[3][3], const float input[3], float output[3]) { output[0] = matrix[0][0] * input[0] + matrix[0][1] * input[1] + matrix[0][2] * input[2]; @@ -275,10 +266,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } /* input and output transfer will be linear */ if (in->color_trc == AVCOL_TRC_UNSPECIFIED) { - av_log(s, AV_LOG_WARNING, "Untagged transfer, assuming linear light.\n"); + av_log(ctx, AV_LOG_WARNING, "Untagged transfer, assuming linear light.\n"); out->color_trc = AVCOL_TRC_LINEAR; } else if (in->color_trc != AVCOL_TRC_LINEAR) { - av_log(s, AV_LOG_WARNING, "Gray world color correction works on linear light only.\n"); + av_log(ctx, AV_LOG_WARNING, "Gray world color correction works on linear light only.\n"); } td.in = in; @@ -310,7 +301,6 @@ const AVFilter ff_vf_grayworld = { .name = "grayworld", .description = NULL_IF_CONFIG_SMALL("Adjust white balance using LAB gray world algorithm"), .priv_size = sizeof(GrayWorldContext), - .priv_class = &grayworld_class, FILTER_INPUTS(grayworld_inputs), FILTER_OUTPUTS(ff_video_default_filterpad), FILTER_PIXFMTS(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32), diff --git a/libavfilter/vf_guided.c b/libavfilter/vf_guided.c index e5c534a6a..f0d9d8f9d 100644 --- a/libavfilter/vf_guided.c +++ b/libavfilter/vf_guided.c @@ -19,12 +19,12 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "filters.h" #include "framesync.h" -#include "internal.h" #include "video.h" enum FilterModes { @@ -336,6 +336,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; GuidedContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(mainlink); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int w, h, ret; @@ -351,7 +353,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + ol->frame_rate = il->frame_rate; s->I = av_calloc(w * h, sizeof(*s->I)); s->II = av_calloc(w * h, sizeof(*s->II)); diff --git a/libavfilter/vf_hflip.c b/libavfilter/vf_hflip.c index 09f4e08ea..47870a167 100644 --- a/libavfilter/vf_hflip.c +++ b/libavfilter/vf_hflip.c @@ -26,11 +26,10 @@ #include -#include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "hflip.h" -#include "internal.h" #include "vf_hflip_init.h" #include "video.h" #include "libavutil/pixdesc.h" @@ -38,12 +37,6 @@ #include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" -static const AVOption hflip_options[] = { - { NULL } -}; - -AVFILTER_DEFINE_CLASS(hflip); - static int query_formats(AVFilterContext *ctx) { AVFilterFormats *pix_fmts = NULL; @@ -155,7 +148,6 @@ const AVFilter ff_vf_hflip = { .name = "hflip", .description = NULL_IF_CONFIG_SMALL("Horizontally flip the input video."), .priv_size = sizeof(FlipContext), - .priv_class = &hflip_class, FILTER_INPUTS(avfilter_vf_hflip_inputs), FILTER_OUTPUTS(ff_video_default_filterpad), FILTER_QUERY_FUNC(query_formats), diff --git a/libavfilter/vf_hflip_init.h b/libavfilter/vf_hflip_init.h index d0319f463..5c1d69b2b 100644 --- a/libavfilter/vf_hflip_init.h +++ b/libavfilter/vf_hflip_init.h @@ -26,6 +26,7 @@ #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/error.h" #include "libavutil/intreadwrite.h" #include "hflip.h" diff --git a/libavfilter/vf_histeq.c b/libavfilter/vf_histeq.c index 24c95a024..6af96b635 100644 --- a/libavfilter/vf_histeq.c +++ b/libavfilter/vf_histeq.c @@ -34,7 +34,7 @@ #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" // #define DEBUG diff --git a/libavfilter/vf_histogram.c b/libavfilter/vf_histogram.c index 7da6d5d72..73fd78caf 100644 --- a/libavfilter/vf_histogram.c +++ b/libavfilter/vf_histogram.c @@ -27,8 +27,8 @@ #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct HistogramContext { diff --git a/libavfilter/vf_hqdn3d.c b/libavfilter/vf_hqdn3d.c index d95ae8f89..3ba1c539a 100644 --- a/libavfilter/vf_hqdn3d.c +++ b/libavfilter/vf_hqdn3d.c @@ -32,12 +32,13 @@ #include "libavutil/attributes.h" #include "libavutil/common.h" #include "libavutil/emms.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "vf_hqdn3d.h" diff --git a/libavfilter/vf_hqx.c b/libavfilter/vf_hqx.c index 4a8ed184f..20a78f2dc 100644 --- a/libavfilter/vf_hqx.c +++ b/libavfilter/vf_hqx.c @@ -30,7 +30,7 @@ #include "libavutil/opt.h" #include "libavutil/avassert.h" #include "libavutil/pixdesc.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef int (*hqxfunc_t)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); diff --git a/libavfilter/vf_hsvkey.c b/libavfilter/vf_hsvkey.c index 0bd8cace3..c5badd82c 100644 --- a/libavfilter/vf_hsvkey.c +++ b/libavfilter/vf_hsvkey.c @@ -24,7 +24,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" typedef struct HSVKeyContext { const AVClass *class; diff --git a/libavfilter/vf_hue.c b/libavfilter/vf_hue.c index 8fea2128f..56899a977 100644 --- a/libavfilter/vf_hue.c +++ b/libavfilter/vf_hue.c @@ -28,11 +28,12 @@ #include #include "libavutil/eval.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define SAT_MIN_VAL -10 @@ -264,6 +265,7 @@ static const enum AVPixelFormat pix_fmts[] = { static int config_props(AVFilterLink *inlink) { HueContext *hue = inlink->dst->priv; + FilterLink *l = ff_filter_link(inlink); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); hue->hsub = desc->log2_chroma_w; @@ -271,8 +273,8 @@ static int config_props(AVFilterLink *inlink) hue->var_values[VAR_N] = 0; hue->var_values[VAR_TB] = av_q2d(inlink->time_base); - hue->var_values[VAR_R] = inlink->frame_rate.num == 0 || inlink->frame_rate.den == 0 ? - NAN : av_q2d(inlink->frame_rate); + hue->var_values[VAR_R] = l->frame_rate.num == 0 || l->frame_rate.den == 0 ? + NAN : av_q2d(l->frame_rate); return 0; } @@ -357,6 +359,7 @@ static void apply_lut10(HueContext *s, static int filter_frame(AVFilterLink *inlink, AVFrame *inpic) { + FilterLink *inl = ff_filter_link(inlink); HueContext *hue = inlink->dst->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; AVFrame *outpic; @@ -378,7 +381,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic) av_frame_copy_props(outpic, inpic); } - hue->var_values[VAR_N] = inlink->frame_count_out; + hue->var_values[VAR_N] = inl->frame_count_out; hue->var_values[VAR_T] = TS2T(inpic->pts, inlink->time_base); hue->var_values[VAR_PTS] = TS2D(inpic->pts); diff --git a/libavfilter/vf_huesaturation.c b/libavfilter/vf_huesaturation.c index bea13deca..af58b114b 100644 --- a/libavfilter/vf_huesaturation.c +++ b/libavfilter/vf_huesaturation.c @@ -20,7 +20,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define R 0 diff --git a/libavfilter/vf_hwdownload.c b/libavfilter/vf_hwdownload.c index 5ef23cb5d..0b70727b2 100644 --- a/libavfilter/vf_hwdownload.c +++ b/libavfilter/vf_hwdownload.c @@ -24,8 +24,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct HWDownloadContext { @@ -50,18 +50,19 @@ static int hwdownload_query_formats(AVFilterContext *avctx) static int hwdownload_config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *avctx = inlink->dst; HWDownloadContext *ctx = avctx->priv; av_buffer_unref(&ctx->hwframes_ref); - if (!inlink->hw_frames_ctx) { + if (!l->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "The input must have a hardware frame " "reference.\n"); return AVERROR(EINVAL); } - ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx); + ctx->hwframes_ref = av_buffer_ref(l->hw_frames_ctx); if (!ctx->hwframes_ref) return AVERROR(ENOMEM); diff --git a/libavfilter/vf_hwmap.c b/libavfilter/vf_hwmap.c index 3f37dab2c..e999605eb 100644 --- a/libavfilter/vf_hwmap.c +++ b/libavfilter/vf_hwmap.c @@ -23,8 +23,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct HWMapContext { @@ -52,9 +52,11 @@ static int hwmap_query_formats(AVFilterContext *avctx) static int hwmap_config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; HWMapContext *ctx = avctx->priv; AVFilterLink *inlink = avctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); AVHWFramesContext *hwfc; AVBufferRef *device; const AVPixFmtDescriptor *desc; @@ -69,8 +71,8 @@ static int hwmap_config_output(AVFilterLink *outlink) device = avctx->hw_device_ctx; device_is_derived = 0; - if (inlink->hw_frames_ctx) { - hwfc = (AVHWFramesContext*)inlink->hw_frames_ctx->data; + if (inl->hw_frames_ctx) { + hwfc = (AVHWFramesContext*)inl->hw_frames_ctx->data; if (ctx->derive_device_type) { enum AVHWDeviceType type; @@ -114,7 +116,7 @@ static int hwmap_config_output(AVFilterLink *outlink) err = av_hwframe_ctx_create_derived(&ctx->hwframes_ref, outlink->format, device, - inlink->hw_frames_ctx, + inl->hw_frames_ctx, ctx->mode); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create derived " @@ -171,8 +173,8 @@ static int hwmap_config_output(AVFilterLink *outlink) // the format it expects. If there were any additional // constraints on the output frames there then this may // break nastily. - av_buffer_unref(&inlink->hw_frames_ctx); - inlink->hw_frames_ctx = source; + av_buffer_unref(&inl->hw_frames_ctx); + inl->hw_frames_ctx = source; } else if ((outlink->format == hwfc->format && inlink->format == hwfc->sw_format) || @@ -180,7 +182,7 @@ static int hwmap_config_output(AVFilterLink *outlink) // Map from a hardware format to a software format, or // undo an existing such mapping. - ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx); + ctx->hwframes_ref = av_buffer_ref(inl->hw_frames_ctx); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; @@ -241,8 +243,8 @@ static int hwmap_config_output(AVFilterLink *outlink) return AVERROR(EINVAL); } - outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref); - if (!outlink->hw_frames_ctx) { + outl->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref); + if (!outl->hw_frames_ctx) { err = AVERROR(ENOMEM); goto fail; } @@ -263,11 +265,12 @@ fail: static AVFrame *hwmap_get_buffer(AVFilterLink *inlink, int w, int h) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *avctx = inlink->dst; AVFilterLink *outlink = avctx->outputs[0]; HWMapContext *ctx = avctx->priv; - if (ctx->reverse && !inlink->hw_frames_ctx) { + if (ctx->reverse && !l->hw_frames_ctx) { AVFrame *src, *dst; int err; diff --git a/libavfilter/vf_hwupload.c b/libavfilter/vf_hwupload.c index ef61bb413..3afd67012 100644 --- a/libavfilter/vf_hwupload.c +++ b/libavfilter/vf_hwupload.c @@ -24,8 +24,8 @@ #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct HWUploadContext { @@ -106,8 +106,10 @@ fail: static int hwupload_config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; AVFilterLink *inlink = avctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); HWUploadContext *ctx = avctx->priv; int err; @@ -116,13 +118,13 @@ static int hwupload_config_output(AVFilterLink *outlink) if (inlink->format == outlink->format) { // The input is already a hardware format, so we just want to // pass through the input frames in their own hardware context. - if (!inlink->hw_frames_ctx) { + if (!inl->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "No input hwframe context.\n"); return AVERROR(EINVAL); } - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); - if (!outlink->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); return 0; @@ -138,9 +140,9 @@ static int hwupload_config_output(AVFilterLink *outlink) av_get_pix_fmt_name(inlink->format)); ctx->hwframes->format = outlink->format; - if (inlink->hw_frames_ctx) { + if (inl->hw_frames_ctx) { AVHWFramesContext *in_hwframe_ctx = - (AVHWFramesContext*)inlink->hw_frames_ctx->data; + (AVHWFramesContext*)inl->hw_frames_ctx->data; ctx->hwframes->sw_format = in_hwframe_ctx->sw_format; } else { ctx->hwframes->sw_format = inlink->format; @@ -155,8 +157,8 @@ static int hwupload_config_output(AVFilterLink *outlink) if (err < 0) goto fail; - outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref); - if (!outlink->hw_frames_ctx) { + outl->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref); + if (!outl->hw_frames_ctx) { err = AVERROR(ENOMEM); goto fail; } diff --git a/libavfilter/vf_hwupload_cuda.c b/libavfilter/vf_hwupload_cuda.c index f5fe3ddbb..1d0404555 100644 --- a/libavfilter/vf_hwupload_cuda.c +++ b/libavfilter/vf_hwupload_cuda.c @@ -22,8 +22,8 @@ #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct CudaUploadContext { @@ -86,8 +86,10 @@ static int cudaupload_query_formats(AVFilterContext *ctx) static int cudaupload_config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); CudaUploadContext *s = ctx->priv; AVHWFramesContext *hwframe_ctx; @@ -100,8 +102,8 @@ static int cudaupload_config_output(AVFilterLink *outlink) hwframe_ctx = (AVHWFramesContext*)s->hwframe->data; hwframe_ctx->format = AV_PIX_FMT_CUDA; - if (inlink->hw_frames_ctx) { - AVHWFramesContext *in_hwframe_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; + if (inl->hw_frames_ctx) { + AVHWFramesContext *in_hwframe_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; hwframe_ctx->sw_format = in_hwframe_ctx->sw_format; } else { hwframe_ctx->sw_format = inlink->format; @@ -113,8 +115,8 @@ static int cudaupload_config_output(AVFilterLink *outlink) if (ret < 0) return ret; - outlink->hw_frames_ctx = av_buffer_ref(s->hwframe); - if (!outlink->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(s->hwframe); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); return 0; diff --git a/libavfilter/vf_hysteresis.c b/libavfilter/vf_hysteresis.c index d2fd3011b..d2b85764f 100644 --- a/libavfilter/vf_hysteresis.c +++ b/libavfilter/vf_hysteresis.c @@ -20,10 +20,11 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "framesync.h" @@ -286,6 +287,8 @@ static int config_output(AVFilterLink *outlink) HysteresisContext *s = ctx->priv; AVFilterLink *base = ctx->inputs[0]; AVFilterLink *alt = ctx->inputs[1]; + FilterLink *il = ff_filter_link(base); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -302,7 +305,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = base->w; outlink->h = base->h; outlink->sample_aspect_ratio = base->sample_aspect_ratio; - outlink->frame_rate = base->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0) return ret; diff --git a/libavfilter/vf_iccdetect.c b/libavfilter/vf_iccdetect.c index 16eacbbb5..044a92ee0 100644 --- a/libavfilter/vf_iccdetect.c +++ b/libavfilter/vf_iccdetect.c @@ -30,7 +30,7 @@ #include "avfilter.h" #include "fflcms2.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct IccDetectContext { diff --git a/libavfilter/vf_iccgen.c b/libavfilter/vf_iccgen.c index aae7ae5d2..35c571d31 100644 --- a/libavfilter/vf_iccgen.c +++ b/libavfilter/vf_iccgen.c @@ -29,7 +29,7 @@ #include "avfilter.h" #include "fflcms2.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct IccGenContext { diff --git a/libavfilter/vf_identity.c b/libavfilter/vf_identity.c index d3a5ec14f..d06e9f3d6 100644 --- a/libavfilter/vf_identity.c +++ b/libavfilter/vf_identity.c @@ -26,12 +26,13 @@ #include "config_components.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "scene_sad.h" typedef struct IdentityContext { @@ -315,6 +316,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; IdentityContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(mainlink); + FilterLink *ol = ff_filter_link(outlink); int ret; ret = ff_framesync_init_dualinput(&s->fs, ctx); @@ -324,7 +327,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_configure(&s->fs)) < 0) return ret; diff --git a/libavfilter/vf_idet.c b/libavfilter/vf_idet.c index abd375230..c57e7ccb2 100644 --- a/libavfilter/vf_idet.c +++ b/libavfilter/vf_idet.c @@ -22,7 +22,7 @@ #include "libavutil/common.h" #include "libavutil/opt.h" -#include "internal.h" +#include "filters.h" #include "vf_idet.h" #define OFFSET(x) offsetof(IDETContext, x) diff --git a/libavfilter/vf_il.c b/libavfilter/vf_il.c index 5eaa40a6f..9a3a9d47a 100644 --- a/libavfilter/vf_il.c +++ b/libavfilter/vf_il.c @@ -28,8 +28,8 @@ #include "libavutil/imgutils.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" enum FilterMode { diff --git a/libavfilter/vf_kerndeint.c b/libavfilter/vf_kerndeint.c index bbad3f9bf..6114a58a5 100644 --- a/libavfilter/vf_kerndeint.c +++ b/libavfilter/vf_kerndeint.c @@ -28,11 +28,12 @@ #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct KerndeintContext { diff --git a/libavfilter/vf_lagfun.c b/libavfilter/vf_lagfun.c index 20cdd9fa6..b3020c28a 100644 --- a/libavfilter/vf_lagfun.c +++ b/libavfilter/vf_lagfun.c @@ -19,11 +19,12 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct LagfunContext { diff --git a/libavfilter/vf_lcevc.c b/libavfilter/vf_lcevc.c new file mode 100644 index 000000000..b83dc94e0 --- /dev/null +++ b/libavfilter/vf_lcevc.c @@ -0,0 +1,430 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2024 James Almer + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/internal.h" +#include "libavutil/opt.h" +#include "filters.h" +#include "video.h" + +typedef struct LCEVCContext { + LCEVC_DecoderHandle decoder; + int w, h; +} LCEVCContext; + +static LCEVC_ColorFormat map_format(int format) +{ + switch (format) { + case AV_PIX_FMT_YUV420P: + return LCEVC_I420_8; + case AV_PIX_FMT_YUV420P10: + return LCEVC_I420_10_LE; + case AV_PIX_FMT_NV12: + return LCEVC_NV12_8; + case AV_PIX_FMT_NV21: + return LCEVC_NV21_8; + case AV_PIX_FMT_GRAY8: + return LCEVC_GRAY_8; + case AV_PIX_FMT_GRAY10LE: + return LCEVC_GRAY_10_LE; + } + + return LCEVC_ColorFormat_Unknown; +} + +static inline LCEVC_ColorRange map_range(int range) +{ + switch (range) { + case AVCOL_RANGE_MPEG: + return LCEVC_ColorRange_Limited; + case AVCOL_RANGE_JPEG: + return LCEVC_ColorRange_Full; + } + + return LCEVC_ColorRange_Unknown; +} + +static inline enum AVColorRange map_av_range(int range) +{ + switch (range) { + case LCEVC_ColorRange_Limited: + return AVCOL_RANGE_MPEG; + case LCEVC_ColorRange_Full: + return AVCOL_RANGE_JPEG; + } + + return AVCOL_RANGE_UNSPECIFIED; +} + +static int alloc_base_frame(AVFilterLink *inlink, const AVFrame *in, + LCEVC_PictureHandle *picture) +{ + AVFilterContext *ctx = inlink->dst; + LCEVCContext *lcevc = ctx->priv; + LCEVC_PictureDesc desc; + LCEVC_PicturePlaneDesc planes[AV_VIDEO_MAX_PLANES] = { 0 }; + LCEVC_ColorFormat fmt = map_format(in->format); + int width = in->width - in->crop_left - in->crop_right; + int height = in->height - in->crop_top - in->crop_bottom; + LCEVC_ReturnCode res; + + res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_DefaultPictureDesc failed\n"); + return AVERROR_EXTERNAL; + } + + for (int i = 0; i < AV_VIDEO_MAX_PLANES; i++) { + planes[i].firstSample = in->data[i]; + planes[i].rowByteStride = in->linesize[i]; + } + + desc.cropTop = in->crop_top; + desc.cropBottom = in->crop_bottom; + desc.cropLeft = in->crop_left; + desc.cropRight = in->crop_right; + desc.sampleAspectRatioNum = in->sample_aspect_ratio.num; + desc.sampleAspectRatioDen = in->sample_aspect_ratio.den; + desc.colorRange = map_range(in->color_range); + desc.colorPrimaries = (LCEVC_ColorPrimaries)in->color_primaries; + desc.matrixCoefficients = (LCEVC_MatrixCoefficients)in->colorspace; + desc.transferCharacteristics = (LCEVC_TransferCharacteristics)in->color_trc; + av_log(ctx, AV_LOG_DEBUG, "in PTS %"PRId64", %dx%d, " + "%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER", " + "SAR %d:%d\n", + in->pts, in->width, in->height, + in->crop_top, in->crop_bottom, in->crop_left, in->crop_right, + in->sample_aspect_ratio.num, in->sample_aspect_ratio.den); + + res = LCEVC_AllocPictureExternal(lcevc->decoder, &desc, NULL, planes, picture); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_AllocPictureExternal to allocate a buffer for a base frame\n"); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int send_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + LCEVCContext *lcevc = ctx->priv; + LCEVC_PictureHandle picture; + const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC); + LCEVC_ReturnCode res; + int ret; + + ret = alloc_base_frame(inlink, in, &picture); + if (ret < 0) + return ret; + + if (sd) { + res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size); + if (res == LCEVC_Again) + return AVERROR(EAGAIN); + else if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_SendDecoderEnhancementData failed\n"); + return AVERROR_EXTERNAL; + } + } + + res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, in); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_SendDecoderBase failed\n"); + LCEVC_FreePicture(lcevc->decoder, picture); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int alloc_enhanced_frame(AVFilterLink *inlink, const AVFrame *out, + LCEVC_PictureHandle *picture) +{ + AVFilterContext *ctx = inlink->dst; + LCEVCContext *lcevc = ctx->priv; + LCEVC_PictureDesc desc; + LCEVC_PicturePlaneDesc planes[AV_VIDEO_MAX_PLANES] = { 0 }; + LCEVC_ColorFormat fmt = map_format(out->format); + LCEVC_ReturnCode res; + + res = LCEVC_DefaultPictureDesc(&desc, fmt, out->width, out->height); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + + for (int i = 0; i < AV_VIDEO_MAX_PLANES; i++) { + planes[i].firstSample = out->data[i]; + planes[i].rowByteStride = out->linesize[i]; + } + + res = LCEVC_AllocPictureExternal(lcevc->decoder, &desc, NULL, planes, picture); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_AllocPictureExternal to allocate a buffer for an enhanced frame\n"); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int generate_output(AVFilterLink *inlink, AVFrame *out) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + LCEVCContext *lcevc = ctx->priv; + LCEVC_PictureDesc desc; + LCEVC_DecodeInformation info; + LCEVC_PictureHandle picture; + LCEVC_ReturnCode res; + + res = LCEVC_ReceiveDecoderPicture(lcevc->decoder, &picture, &info); + if (res == LCEVC_Again) { + int64_t pts; + int status; + if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { + av_frame_free(&out); + ff_outlink_set_status(outlink, status, pts); + return 0; + } + // this shouldn't be reachable, but instead of asserting, just error out + return AVERROR_BUG; + } else if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_ReceiveDecoderPicture failed\n"); + return AVERROR_EXTERNAL; + } + + av_frame_copy_props(out, (AVFrame *)info.baseUserData); + av_frame_remove_side_data(out, AV_FRAME_DATA_LCEVC); + + av_frame_free((AVFrame **)&info.baseUserData); + + res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc); + LCEVC_FreePicture(lcevc->decoder, picture); + + out->crop_top = desc.cropTop; + out->crop_bottom = desc.cropBottom; + out->crop_left = desc.cropLeft; + out->crop_right = desc.cropRight; + out->sample_aspect_ratio.num = outlink->sample_aspect_ratio.num = desc.sampleAspectRatioNum; + out->sample_aspect_ratio.den = outlink->sample_aspect_ratio.den = desc.sampleAspectRatioDen; + out->color_range = map_range(desc.colorRange); + out->color_primaries = (enum AVColorPrimaries)desc.colorPrimaries; + out->colorspace = (enum AVColorSpace)desc.matrixCoefficients; + out->color_trc = (enum AVColorTransferCharacteristic)desc.transferCharacteristics; + out->width = outlink->w = desc.width + out->crop_left + out->crop_right; + out->height = outlink->h = desc.height + out->crop_top + out->crop_bottom; + + av_log(ctx, AV_LOG_DEBUG, "out PTS %"PRId64", %dx%d, " + "%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER", " + "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); + + return ff_filter_frame(outlink, out); +} + +static int receive_frame(AVFilterLink *inlink, AVFrame *out) +{ + AVFilterContext *ctx = inlink->dst; + LCEVCContext *lcevc = ctx->priv; + LCEVC_PictureHandle picture; + LCEVC_ReturnCode res; + int ret; + + ret = alloc_enhanced_frame(inlink, out, &picture); + if (ret < 0) + return ret; + + res = LCEVC_SendDecoderPicture(lcevc->decoder, picture); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_SendDecoderPicture failed\n"); + return AVERROR_EXTERNAL; + } + + return generate_output(inlink, out); +} + +static int config_props(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + LCEVCContext *lcevc = ctx->priv; + + outlink->w = lcevc->w = inlink->w * 2 / FFMAX(inlink->sample_aspect_ratio.den, 1); + outlink->h = lcevc->h = inlink->h * 2 / FFMAX(inlink->sample_aspect_ratio.den, 1); + outlink->sample_aspect_ratio = (AVRational) { 0, 1 }; + + return 0; +} + +static void flush_bases(AVFilterContext *ctx) +{ + LCEVCContext *lcevc = ctx->priv; + LCEVC_PictureHandle picture; + + while (LCEVC_ReceiveDecoderBase(lcevc->decoder, &picture) == LCEVC_Success) + LCEVC_FreePicture(lcevc->decoder, picture); +} + +static int activate(AVFilterContext *ctx) +{ + LCEVCContext *lcevc = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *in, *out; + int status, ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_frame(inlink, &in); + if (ret < 0) + return ret; + if (!ret) { + int64_t pts; + if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (!status) + ff_outlink_set_status(outlink, status, pts); + } + if (!status) + FF_FILTER_FORWARD_WANTED(outlink, inlink); + } + + if (in) { + if (in->width != inlink->w || + in->height != inlink->h || + in->sample_aspect_ratio.den != inlink->sample_aspect_ratio.den || + in->sample_aspect_ratio.num != inlink->sample_aspect_ratio.num) { + inlink->dst->inputs[0]->w = in->width; + inlink->dst->inputs[0]->h = in->height; + inlink->dst->inputs[0]->sample_aspect_ratio.den = in->sample_aspect_ratio.den; + inlink->dst->inputs[0]->sample_aspect_ratio.num = in->sample_aspect_ratio.num; + + config_props(outlink); + } + + ret = send_frame(inlink, in); + if (ret < 0) + return ret; + } + + out = ff_get_video_buffer(outlink, lcevc->w, lcevc->h); + if (!out) + return AVERROR(ENOMEM); + + ret = receive_frame(inlink, out); + if (ret < 0) { + av_frame_free(&out); + return ret; + } + + flush_bases(ctx); + + return ret; +} + +static void log_callback(LCEVC_DecoderHandle dec, LCEVC_Event event, + LCEVC_PictureHandle pic, const LCEVC_DecodeInformation *info, + const uint8_t *data, uint32_t size, void *logctx) +{ + if (event != LCEVC_Log) // shouldn't happen + return; + + if (strlen(data) != size) // sanitize input + return; + + av_log(logctx, AV_LOG_INFO, "LCEVC Log: %s\n", data); +} + +static av_cold int init(AVFilterContext *ctx) +{ + LCEVCContext *lcevc = ctx->priv; + LCEVC_AccelContextHandle dummy = { 0 }; + const int32_t event = LCEVC_Log; + LCEVC_ReturnCode res; + + res = LCEVC_CreateDecoder(&lcevc->decoder, dummy); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_CreateDecoder failed\n"); + return AVERROR_EXTERNAL; + } + + res = LCEVC_ConfigureDecoderInt(lcevc->decoder, "log_level", 4); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_ConfigureDecoderInt failed to set \"log_level\"\n"); + return AVERROR_EXTERNAL; + } + res = LCEVC_ConfigureDecoderIntArray(lcevc->decoder, "events", 1, &event); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_ConfigureDecoderIntArray failed to set \"events\"\n"); + return AVERROR_EXTERNAL; + } + res = LCEVC_SetDecoderEventCallback(lcevc->decoder, log_callback, ctx); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_SetDecoderEventCallback failed\n"); + return AVERROR_EXTERNAL; + } + + res = LCEVC_InitializeDecoder(lcevc->decoder); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_InitializeDecoder failed\n"); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + LCEVCContext *lcevc = ctx->priv; + + LCEVC_DestroyDecoder(lcevc->decoder); +} + +static const AVFilterPad lcevc_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_props, + }, +}; + +static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10LE, + AV_PIX_FMT_NV12, AV_PIX_FMT_NV21, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10LE, + AV_PIX_FMT_NONE +}; + +const AVFilter ff_vf_lcevc = { + .name = "lcevc", + .description = NULL_IF_CONFIG_SMALL("LCEVC"), + .activate = activate, + FILTER_INPUTS(ff_video_default_filterpad), + FILTER_OUTPUTS(lcevc_outputs), + FILTER_PIXFMTS_ARRAY(pix_fmts), + .priv_size = sizeof(LCEVCContext), + .init = init, + .uninit = uninit, +}; diff --git a/libavfilter/vf_lenscorrection.c b/libavfilter/vf_lenscorrection.c index aa545f71c..db80cdb4e 100644 --- a/libavfilter/vf_lenscorrection.c +++ b/libavfilter/vf_lenscorrection.c @@ -27,13 +27,13 @@ #include #include "libavutil/colorspace.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/intreadwrite.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct LenscorrectionCtx { diff --git a/libavfilter/vf_lensfun.c b/libavfilter/vf_lensfun.c index 3d7e6cd6b..7c428e3ca 100644 --- a/libavfilter/vf_lensfun.c +++ b/libavfilter/vf_lensfun.c @@ -28,10 +28,10 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" #include diff --git a/libavfilter/vf_libopencv.c b/libavfilter/vf_libopencv.c index 86407d18e..0250a5483 100644 --- a/libavfilter/vf_libopencv.c +++ b/libavfilter/vf_libopencv.c @@ -34,10 +34,11 @@ #include "libavutil/avstring.h" #include "libavutil/common.h" #include "libavutil/file.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" static void fill_iplimage_from_frame(IplImage *img, const AVFrame *frame, enum AVPixelFormat pixfmt) diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c index f0c34bd3b..2176a7188 100644 --- a/libavfilter/vf_libplacebo.c +++ b/libavfilter/vf_libplacebo.c @@ -20,10 +20,10 @@ #include "libavutil/eval.h" #include "libavutil/fifo.h" #include "libavutil/file.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "formats.h" -#include "internal.h" #include "filters.h" #include "video.h" #include "vulkan_filter.h" @@ -741,6 +741,7 @@ static const AVFrame *ref_frame(const struct pl_frame_mix *mix) static void update_crops(AVFilterContext *ctx, LibplaceboInput *in, struct pl_frame *target, double target_pts) { + FilterLink *outl = ff_filter_link(ctx->outputs[0]); LibplaceboContext *s = ctx->priv; const AVFrame *ref = ref_frame(&in->mix); @@ -760,7 +761,7 @@ static void update_crops(AVFilterContext *ctx, LibplaceboInput *in, av_q2d(in->link->sample_aspect_ratio) : 1.0; s->var_values[VAR_IN_T] = s->var_values[VAR_T] = image_pts; s->var_values[VAR_OUT_T] = s->var_values[VAR_OT] = target_pts; - s->var_values[VAR_N] = ctx->outputs[0]->frame_count_out; + s->var_values[VAR_N] = outl->frame_count_out; /* Clear these explicitly to avoid leaking previous frames' state */ s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] = NAN; @@ -885,7 +886,9 @@ static int output_frame(AVFilterContext *ctx, int64_t pts) opts->params.blend_params = NULL; for (int i = 0; i < s->nb_inputs; i++) { LibplaceboInput *in = &s->inputs[i]; - int high_fps = av_cmp_q(in->link->frame_rate, outlink->frame_rate) >= 0; + FilterLink *il = ff_filter_link(in->link); + FilterLink *ol = ff_filter_link(outlink); + int high_fps = av_cmp_q(il->frame_rate, ol->frame_rate) >= 0; if (in->qstatus != PL_QUEUE_OK) continue; opts->params.skip_caching_single_frame = high_fps; @@ -997,6 +1000,7 @@ static int libplacebo_activate(AVFilterContext *ctx) int ret, ok = 0, retry = 0; LibplaceboContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); int64_t pts, out_pts; FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); @@ -1009,7 +1013,7 @@ static int libplacebo_activate(AVFilterContext *ctx) if (ff_outlink_frame_wanted(outlink)) { if (s->fps.num) { - out_pts = outlink->frame_count_out; + out_pts = outl->frame_count_out; } else { /* Determine the PTS of the next frame from any active input */ out_pts = INT64_MAX; @@ -1030,6 +1034,7 @@ static int libplacebo_activate(AVFilterContext *ctx) /* Update all input queues to the chosen out_pts */ for (int i = 0; i < s->nb_inputs; i++) { LibplaceboInput *in = &s->inputs[i]; + FilterLink *l = ff_filter_link(outlink); if (in->status && out_pts >= in->status_pts) { in->qstatus = PL_QUEUE_EOF; continue; @@ -1038,7 +1043,7 @@ static int libplacebo_activate(AVFilterContext *ctx) in->qstatus = pl_queue_update(in->queue, &in->mix, pl_queue_params( .pts = out_pts * av_q2d(outlink->time_base), .radius = pl_frame_mix_radius(&s->opts->params), - .vsync_duration = av_q2d(av_inv_q(outlink->frame_rate)), + .vsync_duration = av_q2d(av_inv_q(l->frame_rate)), )); switch (in->qstatus) { @@ -1187,9 +1192,11 @@ static inline AVRational max_q(AVRational a, AVRational b) static int libplacebo_config_output(AVFilterLink *outlink) { int err; + FilterLink *l = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; LibplaceboContext *s = avctx->priv; AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *ol = ff_filter_link(outlink); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format); AVHWFramesContext *hwfc; @@ -1216,14 +1223,15 @@ static int libplacebo_config_output(AVFilterLink *outlink) /* Frame rate */ if (s->fps.num) { - outlink->frame_rate = s->fps; + ol->frame_rate = s->fps; outlink->time_base = av_inv_q(s->fps); } else { - outlink->frame_rate = avctx->inputs[0]->frame_rate; + FilterLink *il = ff_filter_link(avctx->inputs[0]); + ol->frame_rate = il->frame_rate; outlink->time_base = avctx->inputs[0]->time_base; for (int i = 1; i < s->nb_inputs; i++) { - outlink->frame_rate = max_q(outlink->frame_rate, - avctx->inputs[i]->frame_rate); + il = ff_filter_link(avctx->inputs[i]); + ol->frame_rate = max_q(ol->frame_rate, il->frame_rate); outlink->time_base = av_gcd_q(outlink->time_base, avctx->inputs[i]->time_base, AV_TIME_BASE / 2, AV_TIME_BASE_Q); @@ -1252,7 +1260,7 @@ static int libplacebo_config_output(AVFilterLink *outlink) s->vkctx.output_format = s->out_format; } RET(ff_vk_filter_config_output(outlink)); - hwfc = (AVHWFramesContext *) outlink->hw_frames_ctx->data; + hwfc = (AVHWFramesContext *)l->hw_frames_ctx->data; vkfc = hwfc->hwctx; vkfc->usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; diff --git a/libavfilter/vf_libvmaf.c b/libavfilter/vf_libvmaf.c index 180ada040..f655092b2 100644 --- a/libavfilter/vf_libvmaf.c +++ b/libavfilter/vf_libvmaf.c @@ -29,13 +29,14 @@ #include #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" #include "framesync.h" -#include "internal.h" #include "video.h" #if CONFIG_LIBVMAF_CUDA_FILTER @@ -496,6 +497,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; LIBVMAFContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(mainlink); + FilterLink *ol = ff_filter_link(outlink); int ret; ret = ff_framesync_init_dualinput(&s->fs, ctx); @@ -505,7 +508,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_configure(&s->fs)) < 0) return ret; @@ -650,7 +653,8 @@ static int config_props_cuda(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; LIBVMAFContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; - AVHWFramesContext *frames_ctx = (AVHWFramesContext*) inlink->hw_frames_ctx->data; + FilterLink *inl = ff_filter_link(inlink); + AVHWFramesContext *frames_ctx = (AVHWFramesContext*) inl->hw_frames_ctx->data; AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; CUcontext cu_ctx = device_hwctx->cuda_ctx; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frames_ctx->sw_format); @@ -755,7 +759,8 @@ static int do_vmaf_cuda(FFFrameSync* fs) AVFilterContext* ctx = fs->parent; LIBVMAFContext* s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; - AVHWFramesContext *frames_ctx = (AVHWFramesContext*) inlink->hw_frames_ctx->data; + FilterLink *inl = ff_filter_link(inlink); + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; VmafPicture pic_ref, pic_dist; AVFrame *ref, *dist; diff --git a/libavfilter/vf_limitdiff.c b/libavfilter/vf_limitdiff.c index 1e903d45a..a54942ad5 100644 --- a/libavfilter/vf_limitdiff.c +++ b/libavfilter/vf_limitdiff.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "framesync.h" @@ -243,6 +243,8 @@ static int config_output(AVFilterLink *outlink) LimitDiffContext *s = ctx->priv; AVFilterLink *filtered = ctx->inputs[0]; AVFilterLink *source = ctx->inputs[1]; + FilterLink *il = ff_filter_link(filtered); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -271,7 +273,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = filtered->w; outlink->h = filtered->h; outlink->sample_aspect_ratio = filtered->sample_aspect_ratio; - outlink->frame_rate = filtered->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_init(&s->fs, ctx, 2 + !!s->reference)) < 0) return ret; diff --git a/libavfilter/vf_limiter.c b/libavfilter/vf_limiter.c index f67f590d6..6826b4c30 100644 --- a/libavfilter/vf_limiter.c +++ b/libavfilter/vf_limiter.c @@ -22,7 +22,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "limiter.h" #include "video.h" diff --git a/libavfilter/vf_lumakey.c b/libavfilter/vf_lumakey.c index d426a5b67..773fe5df6 100644 --- a/libavfilter/vf_lumakey.c +++ b/libavfilter/vf_lumakey.c @@ -21,7 +21,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct LumakeyContext { diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c index 1a6ca0654..7e7fd2fa4 100644 --- a/libavfilter/vf_lut.c +++ b/libavfilter/vf_lut.c @@ -30,12 +30,13 @@ #include "libavutil/bswap.h" #include "libavutil/common.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" static const char *const var_names[] = { diff --git a/libavfilter/vf_lut2.c b/libavfilter/vf_lut2.c index 49755544b..2488c9fdc 100644 --- a/libavfilter/vf_lut2.c +++ b/libavfilter/vf_lut2.c @@ -23,12 +23,12 @@ #include "libavutil/attributes.h" #include "libavutil/common.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "drawutils.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "framesync.h" @@ -406,6 +406,8 @@ static int lut2_config_output(AVFilterLink *outlink) LUT2Context *s = ctx->priv; AVFilterLink *srcx = ctx->inputs[0]; AVFilterLink *srcy = ctx->inputs[1]; + FilterLink *il = ff_filter_link(srcx); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); int hsub = desc->log2_chroma_w; @@ -416,7 +418,7 @@ static int lut2_config_output(AVFilterLink *outlink) outlink->h = srcx->h; outlink->time_base = srcx->time_base; outlink->sample_aspect_ratio = srcx->sample_aspect_ratio; - outlink->frame_rate = srcx->frame_rate; + ol->frame_rate = il->frame_rate; s->nb_planes = av_pix_fmt_count_planes(outlink->format); s->height[1] = s->height[2] = AV_CEIL_RSHIFT(outlink->h, vsub); diff --git a/libavfilter/vf_lut3d.c b/libavfilter/vf_lut3d.c index a03fdb33a..46955b99a 100644 --- a/libavfilter/vf_lut3d.c +++ b/libavfilter/vf_lut3d.c @@ -24,17 +24,18 @@ * 3D Lookup table filter */ +#include + #include "config_components.h" -#include "float.h" - +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/file_open.h" #include "libavutil/intfloat.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "lut3d.h" @@ -1111,6 +1112,8 @@ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_NONE }; +#if CONFIG_LUT3D_FILTER || CONFIG_HALDCLUT_FILTER + static int config_input(AVFilterLink *inlink) { int depth, is16bit, isfloat, planar; @@ -1207,8 +1210,6 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar return config_input(ctx->inputs[0]); } -#if CONFIG_LUT3D_FILTER || CONFIG_HALDCLUT_FILTER - /* These options are shared between several filters; * &lut3d_haldclut_options[COMMON_OPTIONS_OFFSET] must always * point to the first of the COMMON_OPTIONS. */ diff --git a/libavfilter/vf_maskedclamp.c b/libavfilter/vf_maskedclamp.c index e6fbb1a6d..2e9778fe2 100644 --- a/libavfilter/vf_maskedclamp.c +++ b/libavfilter/vf_maskedclamp.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "framesync.h" #include "maskedclamp.h" @@ -222,6 +222,8 @@ static int config_output(AVFilterLink *outlink) AVFilterLink *base = ctx->inputs[0]; AVFilterLink *dark = ctx->inputs[1]; AVFilterLink *bright = ctx->inputs[2]; + FilterLink *il = ff_filter_link(base); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -240,7 +242,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = base->w; outlink->h = base->h; outlink->sample_aspect_ratio = base->sample_aspect_ratio; - outlink->frame_rate = base->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_init(&s->fs, ctx, 3)) < 0) return ret; diff --git a/libavfilter/vf_maskedmerge.c b/libavfilter/vf_maskedmerge.c index 4ca0c571c..a6dfb2d83 100644 --- a/libavfilter/vf_maskedmerge.c +++ b/libavfilter/vf_maskedmerge.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "maskedmerge.h" @@ -215,6 +215,8 @@ static int config_output(AVFilterLink *outlink) AVFilterLink *base = ctx->inputs[0]; AVFilterLink *overlay = ctx->inputs[1]; AVFilterLink *mask = ctx->inputs[2]; + FilterLink *il = ff_filter_link(base); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -233,7 +235,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = base->w; outlink->h = base->h; outlink->sample_aspect_ratio = base->sample_aspect_ratio; - outlink->frame_rate = base->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = av_image_fill_linesizes(s->linesize, outlink->format, outlink->w)) < 0) return ret; diff --git a/libavfilter/vf_maskedminmax.c b/libavfilter/vf_maskedminmax.c index b1c309cc7..b9582d153 100644 --- a/libavfilter/vf_maskedminmax.c +++ b/libavfilter/vf_maskedminmax.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "framesync.h" @@ -220,6 +220,8 @@ static int config_output(AVFilterLink *outlink) AVFilterLink *source = ctx->inputs[0]; AVFilterLink *f1 = ctx->inputs[1]; AVFilterLink *f2 = ctx->inputs[2]; + FilterLink *il = ff_filter_link(source); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -238,7 +240,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = source->w; outlink->h = source->h; outlink->sample_aspect_ratio = source->sample_aspect_ratio; - outlink->frame_rate = source->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_init(&s->fs, ctx, 3)) < 0) return ret; diff --git a/libavfilter/vf_maskedthreshold.c b/libavfilter/vf_maskedthreshold.c index e78e11810..5d2038564 100644 --- a/libavfilter/vf_maskedthreshold.c +++ b/libavfilter/vf_maskedthreshold.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "framesync.h" @@ -220,6 +220,8 @@ static int config_output(AVFilterLink *outlink) MaskedThresholdContext *s = ctx->priv; AVFilterLink *source = ctx->inputs[0]; AVFilterLink *ref = ctx->inputs[1]; + FilterLink *il = ff_filter_link(source); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -235,7 +237,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = source->w; outlink->h = source->h; outlink->sample_aspect_ratio = source->sample_aspect_ratio; - outlink->frame_rate = source->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0) return ret; diff --git a/libavfilter/vf_maskfun.c b/libavfilter/vf_maskfun.c index 1ac152fc8..cd74d2669 100644 --- a/libavfilter/vf_maskfun.c +++ b/libavfilter/vf_maskfun.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct MaskFunContext { diff --git a/libavfilter/vf_mcdeint.c b/libavfilter/vf_mcdeint.c index 76ab59912..05c9105f7 100644 --- a/libavfilter/vf_mcdeint.c +++ b/libavfilter/vf_mcdeint.c @@ -52,7 +52,7 @@ #include "libavutil/opt.h" #include "libavcodec/avcodec.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum MCDeintMode { diff --git a/libavfilter/vf_median.c b/libavfilter/vf_median.c index 57514f928..a5c51621d 100644 --- a/libavfilter/vf_median.c +++ b/libavfilter/vf_median.c @@ -21,10 +21,11 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "median.h" #include "video.h" diff --git a/libavfilter/vf_mergeplanes.c b/libavfilter/vf_mergeplanes.c index 91bc0d2c5..8c1537e0b 100644 --- a/libavfilter/vf_mergeplanes.c +++ b/libavfilter/vf_mergeplanes.c @@ -24,8 +24,8 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "framesync.h" #include "video.h" @@ -185,6 +185,8 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; MergePlanesContext *s = ctx->priv; + FilterLink *il = ff_filter_link(ctx->inputs[0]); + FilterLink *ol = ff_filter_link(outlink); InputParam inputsp[4]; FFFrameSyncIn *in; int i, ret; @@ -199,7 +201,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = ctx->inputs[0]->w; outlink->h = ctx->inputs[0]->h; outlink->time_base = ctx->inputs[0]->time_base; - outlink->frame_rate = ctx->inputs[0]->frame_rate; + ol->frame_rate = il->frame_rate; outlink->sample_aspect_ratio = ctx->inputs[0]->sample_aspect_ratio; s->planewidth[1] = diff --git a/libavfilter/vf_mestimate.c b/libavfilter/vf_mestimate.c index d551dab85..8662b5f66 100644 --- a/libavfilter/vf_mestimate.c +++ b/libavfilter/vf_mestimate.c @@ -21,10 +21,11 @@ #include "motion_estimation.h" #include "libavcodec/mathops.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/motion_vector.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct MEContext { diff --git a/libavfilter/vf_midequalizer.c b/libavfilter/vf_midequalizer.c index fae2b7ef1..9afbeb6f1 100644 --- a/libavfilter/vf_midequalizer.c +++ b/libavfilter/vf_midequalizer.c @@ -19,10 +19,11 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "framesync.h" @@ -296,13 +297,15 @@ static int config_output(AVFilterLink *outlink) MidEqualizerContext *s = ctx->priv; AVFilterLink *in0 = ctx->inputs[0]; AVFilterLink *in1 = ctx->inputs[1]; + FilterLink *il = ff_filter_link(in0); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; outlink->w = in0->w; outlink->h = in0->h; outlink->sample_aspect_ratio = in0->sample_aspect_ratio; - outlink->frame_rate = in0->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0) return ret; diff --git a/libavfilter/vf_minterpolate.c b/libavfilter/vf_minterpolate.c index 171f865b0..39a3f55f4 100644 --- a/libavfilter/vf_minterpolate.c +++ b/libavfilter/vf_minterpolate.c @@ -22,10 +22,11 @@ #include "motion_estimation.h" #include "libavcodec/mathops.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "scene_sad.h" @@ -397,8 +398,9 @@ static int config_input(AVFilterLink *inlink) static int config_output(AVFilterLink *outlink) { MIContext *mi_ctx = outlink->src->priv; + FilterLink *l = ff_filter_link(outlink); - outlink->frame_rate = mi_ctx->frame_rate; + l->frame_rate = mi_ctx->frame_rate; outlink->time_base = av_inv_q(mi_ctx->frame_rate); return 0; diff --git a/libavfilter/vf_misc_vaapi.c b/libavfilter/vf_misc_vaapi.c index d68e18b52..3717a2193 100644 --- a/libavfilter/vf_misc_vaapi.c +++ b/libavfilter/vf_misc_vaapi.c @@ -21,7 +21,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "vaapi_vpp.h" #include "video.h" diff --git a/libavfilter/vf_mix.c b/libavfilter/vf_mix.c index 10da1cadd..16d6bf328 100644 --- a/libavfilter/vf_mix.c +++ b/libavfilter/vf_mix.c @@ -22,13 +22,13 @@ #include "libavutil/avstring.h" #include "libavutil/imgutils.h" -#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "framesync.h" #include "video.h" @@ -316,7 +316,8 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; MixContext *s = ctx->priv; - AVRational frame_rate = ctx->inputs[0]->frame_rate; + FilterLink *il = ff_filter_link(ctx->inputs[0]); + FilterLink *ol = ff_filter_link(outlink); AVRational sar = ctx->inputs[0]->sample_aspect_ratio; AVFilterLink *inlink = ctx->inputs[0]; int height = ctx->inputs[0]->h; @@ -366,7 +367,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = width; outlink->h = height; - outlink->frame_rate = frame_rate; + ol->frame_rate = il->frame_rate; outlink->sample_aspect_ratio = sar; if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0) diff --git a/libavfilter/vf_monochrome.c b/libavfilter/vf_monochrome.c index 05c001707..b8242c045 100644 --- a/libavfilter/vf_monochrome.c +++ b/libavfilter/vf_monochrome.c @@ -23,7 +23,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct MonochromeContext { diff --git a/libavfilter/vf_morpho.c b/libavfilter/vf_morpho.c index 35d688a84..02e731cc4 100644 --- a/libavfilter/vf_morpho.c +++ b/libavfilter/vf_morpho.c @@ -26,11 +26,12 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "video.h" enum MorphModes { @@ -1001,6 +1002,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; MorphoContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(mainlink); + FilterLink *ol = ff_filter_link(outlink); int ret; s->fs.on_event = do_morpho; @@ -1011,7 +1014,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_configure(&s->fs)) < 0) return ret; diff --git a/libavfilter/vf_mpdecimate.c b/libavfilter/vf_mpdecimate.c index dab8941e4..e101565f6 100644 --- a/libavfilter/vf_mpdecimate.c +++ b/libavfilter/vf_mpdecimate.c @@ -29,7 +29,7 @@ #include "libavutil/pixelutils.h" #include "libavutil/timestamp.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct DecimateContext { diff --git a/libavfilter/vf_multiply.c b/libavfilter/vf_multiply.c index 54fbeff48..fd8ab1092 100644 --- a/libavfilter/vf_multiply.c +++ b/libavfilter/vf_multiply.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "framesync.h" @@ -164,6 +164,8 @@ static int config_output(AVFilterLink *outlink) MultiplyContext *s = ctx->priv; AVFilterLink *source = ctx->inputs[0]; AVFilterLink *ref = ctx->inputs[1]; + FilterLink *il = ff_filter_link(source); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -179,7 +181,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = source->w; outlink->h = source->h; outlink->sample_aspect_ratio = source->sample_aspect_ratio; - outlink->frame_rate = source->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0) return ret; diff --git a/libavfilter/vf_negate.c b/libavfilter/vf_negate.c index 40c0c2608..f857415ee 100644 --- a/libavfilter/vf_negate.c +++ b/libavfilter/vf_negate.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define COMP_R 0x01 diff --git a/libavfilter/vf_neighbor.c b/libavfilter/vf_neighbor.c index 915347d6b..29772ccb1 100644 --- a/libavfilter/vf_neighbor.c +++ b/libavfilter/vf_neighbor.c @@ -26,7 +26,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ThreadData { diff --git a/libavfilter/vf_neighbor_opencl.c b/libavfilter/vf_neighbor_opencl.c index b2939f841..d8238a138 100644 --- a/libavfilter/vf_neighbor_opencl.c +++ b/libavfilter/vf_neighbor_opencl.c @@ -28,7 +28,7 @@ #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" @@ -42,7 +42,7 @@ typedef struct NeighborOpenCLContext { char *matrix_str[4]; - cl_float threshold[4]; + cl_float threshold[AV_VIDEO_MAX_PLANES]; cl_int coordinates; cl_mem coord; @@ -93,7 +93,7 @@ static int neighbor_opencl_make_filter_params(AVFilterContext *avctx) cl_int cle; int i; - for (i = 0; i < 4; i++) { + for (i = 0; i < AV_VIDEO_MAX_PLANES; i++) { ctx->threshold[i] /= 255.0; } diff --git a/libavfilter/vf_nlmeans.c b/libavfilter/vf_nlmeans.c index dc935538f..86bf5b8e0 100644 --- a/libavfilter/vf_nlmeans.c +++ b/libavfilter/vf_nlmeans.c @@ -30,10 +30,11 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "vf_nlmeans.h" #include "vf_nlmeans_init.h" #include "video.h" diff --git a/libavfilter/vf_nlmeans_opencl.c b/libavfilter/vf_nlmeans_opencl.c index 5149be02c..b22428008 100644 --- a/libavfilter/vf_nlmeans_opencl.c +++ b/libavfilter/vf_nlmeans_opencl.c @@ -25,7 +25,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" diff --git a/libavfilter/vf_nlmeans_vulkan.c b/libavfilter/vf_nlmeans_vulkan.c index fac38d16f..fc9b522c8 100644 --- a/libavfilter/vf_nlmeans_vulkan.c +++ b/libavfilter/vf_nlmeans_vulkan.c @@ -18,11 +18,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/random_seed.h" #include "libavutil/opt.h" #include "vulkan_filter.h" #include "vulkan_spirv.h" -#include "internal.h" + +#include "filters.h" #include "video.h" #define TYPE_NAME "vec4" @@ -455,6 +457,10 @@ static av_cold int init_denoise_pipeline(FFVulkanContext *vkctx, FFVkExecPool *e .elems = planes, .stages = VK_SHADER_STAGE_COMPUTE_BIT, }, + }; + RET(ff_vk_pipeline_descriptor_set_add(vkctx, pl, shd, desc_set, 2, 0, 0)); + + desc_set = (FFVulkanDescriptorSetBinding []) { { .name = "weights_buffer_0", .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, @@ -512,7 +518,8 @@ static av_cold int init_denoise_pipeline(FFVulkanContext *vkctx, FFVkExecPool *e .buf_content = "float sums_3[];", }, }; - RET(ff_vk_pipeline_descriptor_set_add(vkctx, pl, shd, desc_set, 2 + 2*desc->nb_components, 0, 0)); + + RET(ff_vk_pipeline_descriptor_set_add(vkctx, pl, shd, desc_set, 2*desc->nb_components, 0, 0)); GLSLC(0, void main() ); GLSLC(0, { ); @@ -563,7 +570,7 @@ static av_cold int init_filter(AVFilterContext *ctx) NLMeansVulkanContext *s = ctx->priv; FFVulkanContext *vkctx = &s->vkctx; const int planes = av_pix_fmt_count_planes(s->vkctx.output_format); - FFVkSPIRVCompiler *spv; + FFVkSPIRVCompiler *spv = NULL; int *offsets_buf; int offsets_dispatched = 0, nb_dispatches = 0; @@ -655,7 +662,7 @@ static av_cold int init_filter(AVFilterContext *ctx) spv, desc, planes)); RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_weights, NULL, 1, 0, 0, - s->xyoffsets_buf.address, s->xyoffsets_buf.size, + &s->xyoffsets_buf, 0, s->xyoffsets_buf.size, VK_FORMAT_UNDEFINED)); do { @@ -685,14 +692,16 @@ static int denoise_pass(NLMeansVulkanContext *s, FFVkExecContext *exec, VkBufferMemoryBarrier2 buf_bar[8]; int nb_buf_bar = 0; + DenoisePushData pd = { + { ws_stride[0], ws_stride[1], ws_stride[2], ws_stride[3] }, + }; + /* Denoise pass pipeline */ ff_vk_exec_bind_pipeline(vkctx, exec, &s->pl_denoise); /* Push data */ ff_vk_update_push_exec(vkctx, exec, &s->pl_denoise, VK_SHADER_STAGE_COMPUTE_BIT, - 0, sizeof(DenoisePushData), &(DenoisePushData) { - { ws_stride[0], ws_stride[1], ws_stride[2], ws_stride[3] }, - }); + 0, sizeof(pd), &pd); buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, @@ -749,8 +758,8 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) /* Weights/sums */ AVBufferRef *ws_buf = NULL; FFVkBuffer *ws_vk; - VkDeviceAddress weights_addr[4]; - VkDeviceAddress sums_addr[4]; + VkDeviceSize weights_offs[4]; + VkDeviceSize sums_offs[4]; uint32_t ws_stride[4]; size_t ws_size[4]; size_t ws_total_size = 0; @@ -808,11 +817,11 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) return err; ws_vk = (FFVkBuffer *)ws_buf->data; - weights_addr[0] = ws_vk->address; - sums_addr[0] = ws_vk->address + ws_total_size; + weights_offs[0] = 0; + sums_offs[0] = ws_total_size; for (int i = 1; i < desc->nb_components; i++) { - weights_addr[i] = weights_addr[i - 1] + ws_size[i - 1]; - sums_addr[i] = sums_addr[i - 1] + ws_size[i - 1]; + weights_offs[i] = weights_offs[i - 1] + ws_size[i - 1]; + sums_offs[i] = sums_offs[i - 1] + ws_size[i - 1]; } /* Output frame */ @@ -842,9 +851,6 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) /* Input frame prep */ RET(ff_vk_create_imageviews(vkctx, exec, in_views, in)); - ff_vk_update_descriptor_img_array(vkctx, &s->pl_weights, exec, in, in_views, 0, 0, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - s->sampler); ff_vk_frame_barrier(vkctx, exec, in, img_bar, &nb_img_bar, VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, @@ -932,10 +938,10 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) s->sampler); for (int i = 0; i < desc->nb_components; i++) { RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_weights, exec, 0, 1 + i*2 + 0, 0, - weights_addr[i], ws_size[i], + ws_vk, weights_offs[i], ws_size[i], VK_FORMAT_UNDEFINED)); RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_weights, exec, 0, 1 + i*2 + 1, 0, - sums_addr[i], ws_size[i], + ws_vk, sums_offs[i], ws_size[i], VK_FORMAT_UNDEFINED)); } @@ -946,11 +952,11 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) ff_vk_update_descriptor_img_array(vkctx, &s->pl_denoise, exec, out, out_views, 0, 1, VK_IMAGE_LAYOUT_GENERAL, s->sampler); for (int i = 0; i < desc->nb_components; i++) { - RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_denoise, exec, 0, 2 + i*2 + 0, 0, - weights_addr[i], ws_size[i], + RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_denoise, exec, 1, i*2 + 0, 0, + ws_vk, weights_offs[i], ws_size[i], VK_FORMAT_UNDEFINED)); - RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_denoise, exec, 0, 2 + i*2 + 1, 0, - sums_addr[i], ws_size[i], + RET(ff_vk_set_descriptor_buffer(&s->vkctx, &s->pl_denoise, exec, 1, i*2 + 1, 0, + ws_vk, sums_offs[i], ws_size[i], VK_FORMAT_UNDEFINED)); } @@ -971,6 +977,10 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) offsets_dispatched, }; + /* Push data */ + ff_vk_update_push_exec(vkctx, exec, &s->pl_weights, VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pd), &pd); + if (offsets_dispatched) { nb_buf_bar = 0; buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) { @@ -996,10 +1006,6 @@ static int nlmeans_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) integral_vk->access = buf_bar[1].dstAccessMask; } - /* Push data */ - ff_vk_update_push_exec(vkctx, exec, &s->pl_weights, VK_SHADER_STAGE_COMPUTE_BIT, - 0, sizeof(pd), &pd); - wg_invoc = FFMIN((s->nb_offsets - offsets_dispatched)/TYPE_ELEMS, s->opts.t); wg_invoc = FFMIN(wg_invoc, vkctx->props.properties.limits.maxComputeWorkGroupCount[2]); diff --git a/libavfilter/vf_nnedi.c b/libavfilter/vf_nnedi.c index 436d7a339..1b1f9e8b4 100644 --- a/libavfilter/vf_nnedi.c +++ b/libavfilter/vf_nnedi.c @@ -25,11 +25,12 @@ #include "libavutil/file_open.h" #include "libavutil/float_dsp.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" static const size_t NNEDI_WEIGHTS_SIZE = 13574928; @@ -172,9 +173,11 @@ static int config_output(AVFilterLink *outlink) outlink->w = ctx->inputs[0]->w; outlink->h = ctx->inputs[0]->h; - if (s->field == -2 || s->field > 1) - outlink->frame_rate = av_mul_q(ctx->inputs[0]->frame_rate, - (AVRational){2, 1}); + if (s->field == -2 || s->field > 1) { + FilterLink *il = ff_filter_link(ctx->inputs[0]); + FilterLink *ol = ff_filter_link(outlink); + ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){2, 1}); + } return 0; } @@ -728,11 +731,12 @@ static int request_frame(AVFilterLink *link) if (ret == AVERROR_EOF && s->prev) { AVFrame *next = av_frame_clone(s->prev); + FilterLink *l = ff_filter_link(ctx->outputs[0]); if (!next) return AVERROR(ENOMEM); - next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(ctx->outputs[0]->frame_rate), + next->pts = s->prev->pts + av_rescale_q(1, av_inv_q(l->frame_rate), ctx->outputs[0]->time_base); s->eof = 1; diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c index af33a73ef..b5ef416de 100644 --- a/libavfilter/vf_noise.c +++ b/libavfilter/vf_noise.c @@ -25,14 +25,14 @@ */ #include "libavutil/emms.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/imgutils.h" #include "libavutil/lfg.h" -#include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "vf_noise.h" #include "video.h" diff --git a/libavfilter/vf_normalize.c b/libavfilter/vf_normalize.c index d81b2d645..613edd532 100644 --- a/libavfilter/vf_normalize.c +++ b/libavfilter/vf_normalize.c @@ -73,11 +73,12 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct NormalizeHistory { diff --git a/libavfilter/vf_null.c b/libavfilter/vf_null.c index 1502774f9..372503a08 100644 --- a/libavfilter/vf_null.c +++ b/libavfilter/vf_null.c @@ -23,7 +23,7 @@ #include "libavutil/internal.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" const AVFilter ff_vf_null = { diff --git a/libavfilter/vf_ocr.c b/libavfilter/vf_ocr.c index 3cece91ed..f0b4b2428 100644 --- a/libavfilter/vf_ocr.c +++ b/libavfilter/vf_ocr.c @@ -22,7 +22,7 @@ #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct OCRContext { diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c index 349b8d588..03b48bf68 100644 --- a/libavfilter/vf_overlay.c +++ b/libavfilter/vf_overlay.c @@ -35,7 +35,7 @@ #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/timestamp.h" -#include "internal.h" +#include "filters.h" #include "drawutils.h" #include "framesync.h" #include "video.h" @@ -881,6 +881,7 @@ static int do_blend(FFFrameSync *fs) AVFrame *mainpic, *second; OverlayContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); int ret; ret = ff_framesync_dualinput_get_writable(fs, &mainpic, &second); @@ -891,7 +892,7 @@ static int do_blend(FFFrameSync *fs) if (s->eval_mode == EVAL_MODE_FRAME) { - s->var_values[VAR_N] = inlink->frame_count_out; + s->var_values[VAR_N] = inl->frame_count_out; s->var_values[VAR_T] = mainpic->pts == AV_NOPTS_VALUE ? NAN : mainpic->pts * av_q2d(inlink->time_base); #if FF_API_FRAME_PKT diff --git a/libavfilter/vf_overlay_cuda.c b/libavfilter/vf_overlay_cuda.c index 77c7f9b4e..a35f6eda6 100644 --- a/libavfilter/vf_overlay_cuda.c +++ b/libavfilter/vf_overlay_cuda.c @@ -34,7 +34,6 @@ #include "avfilter.h" #include "filters.h" #include "framesync.h" -#include "internal.h" #include "cuda/load_helper.h" @@ -236,6 +235,7 @@ static int overlay_cuda_blend(FFFrameSync *fs) OverlayCUDAContext *ctx = avctx->priv; AVFilterLink *outlink = avctx->outputs[0]; AVFilterLink *inlink = avctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); CudaFunctions *cu = ctx->hwctx->internal->cuda_dl; CUcontext dummy, cuda_ctx = ctx->hwctx->cuda_ctx; @@ -270,7 +270,7 @@ static int overlay_cuda_blend(FFFrameSync *fs) } if (ctx->eval_mode == EVAL_MODE_FRAME) { - ctx->var_values[VAR_N] = inlink->frame_count_out; + ctx->var_values[VAR_N] = inl->frame_count_out; ctx->var_values[VAR_T] = input_main->pts == AV_NOPTS_VALUE ? NAN : input_main->pts * av_q2d(inlink->time_base); @@ -436,14 +436,17 @@ static int overlay_cuda_config_output(AVFilterLink *outlink) extern const unsigned int ff_vf_overlay_cuda_ptx_len; int err; + FilterLink *outl = ff_filter_link(outlink); AVFilterContext* avctx = outlink->src; OverlayCUDAContext* ctx = avctx->priv; AVFilterLink *inlink = avctx->inputs[0]; - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; + FilterLink *inl = ff_filter_link(inlink); + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; AVFilterLink *inlink_overlay = avctx->inputs[1]; - AVHWFramesContext *frames_ctx_overlay = (AVHWFramesContext*)inlink_overlay->hw_frames_ctx->data; + FilterLink *inl_overlay = ff_filter_link(inlink_overlay); + AVHWFramesContext *frames_ctx_overlay = (AVHWFramesContext*)inl_overlay->hw_frames_ctx->data; CUcontext dummy, cuda_ctx; CudaFunctions *cu; @@ -496,8 +499,8 @@ static int overlay_cuda_config_output(AVFilterLink *outlink) ctx->cu_stream = ctx->hwctx->stream; - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); - if (!outlink->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); // load functions diff --git a/libavfilter/vf_overlay_opencl.c b/libavfilter/vf_overlay_opencl.c index 9beb09f05..c8c9d8bf1 100644 --- a/libavfilter/vf_overlay_opencl.c +++ b/libavfilter/vf_overlay_opencl.c @@ -21,8 +21,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" diff --git a/libavfilter/vf_overlay_qsv.c b/libavfilter/vf_overlay_qsv.c index 19aaf03c1..39bc70063 100644 --- a/libavfilter/vf_overlay_qsv.c +++ b/libavfilter/vf_overlay_qsv.c @@ -21,19 +21,17 @@ * A hardware accelerated overlay filter based on Intel Quick Sync Video VPP */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/common.h" #include "libavutil/pixdesc.h" #include "libavutil/eval.h" #include "libavutil/hwcontext.h" -#include "libavutil/avstring.h" -#include "libavutil/imgutils.h" #include "libavutil/mathematics.h" -#include "internal.h" +#include "filters.h" #include "avfilter.h" #include "formats.h" -#include "video.h" #include "framesync.h" #include "qsvvpp.h" @@ -158,12 +156,13 @@ release: static int have_alpha_planar(AVFilterLink *link) { + FilterLink *l = ff_filter_link(link); enum AVPixelFormat pix_fmt = link->format; const AVPixFmtDescriptor *desc; AVHWFramesContext *fctx; if (link->format == AV_PIX_FMT_QSV) { - fctx = (AVHWFramesContext *)link->hw_frames_ctx->data; + fctx = (AVHWFramesContext *)l->hw_frames_ctx->data; pix_fmt = fctx->sw_format; } @@ -230,13 +229,16 @@ static int process_frame(FFFrameSync *fs) { AVFilterContext *ctx = fs->parent; QSVVPPContext *qsv = fs->opaque; - AVFrame *frame = NULL; + AVFrame *frame = NULL, *propref = NULL; int ret = 0, i; for (i = 0; i < ctx->nb_inputs; i++) { ret = ff_framesync_get_frame(fs, i, &frame, 0); - if (ret == 0) - ret = ff_qsvvpp_filter_frame(qsv, ctx->inputs[i], frame); + if (ret == 0) { + if (i == 0) + propref = frame; + ret = ff_qsvvpp_filter_frame(qsv, ctx->inputs[i], frame, propref); + } if (ret < 0 && ret != AVERROR(EAGAIN)) break; } @@ -272,6 +274,9 @@ static int config_output(AVFilterLink *outlink) QSVOverlayContext *vpp = ctx->priv; AVFilterLink *in0 = ctx->inputs[0]; AVFilterLink *in1 = ctx->inputs[1]; + FilterLink *l0 = ff_filter_link(in0); + FilterLink *l1 = ff_filter_link(in1); + FilterLink *ol = ff_filter_link(outlink); int ret; av_log(ctx, AV_LOG_DEBUG, "Output is of %s.\n", av_get_pix_fmt_name(outlink->format)); @@ -281,8 +286,8 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "Mixing hardware and software pixel formats is not supported.\n"); return AVERROR(EINVAL); } else if (in0->format == AV_PIX_FMT_QSV) { - AVHWFramesContext *hw_frame0 = (AVHWFramesContext *)in0->hw_frames_ctx->data; - AVHWFramesContext *hw_frame1 = (AVHWFramesContext *)in1->hw_frames_ctx->data; + AVHWFramesContext *hw_frame0 = (AVHWFramesContext *)l0->hw_frames_ctx->data; + AVHWFramesContext *hw_frame1 = (AVHWFramesContext *)l1->hw_frames_ctx->data; if (hw_frame0->device_ctx != hw_frame1->device_ctx) { av_log(ctx, AV_LOG_ERROR, "Inputs with different underlying QSV devices are forbidden.\n"); @@ -293,8 +298,8 @@ static int config_output(AVFilterLink *outlink) outlink->w = vpp->var_values[VAR_MW]; outlink->h = vpp->var_values[VAR_MH]; - outlink->frame_rate = in0->frame_rate; - outlink->time_base = av_inv_q(outlink->frame_rate); + ol->frame_rate = l0->frame_rate; + outlink->time_base = av_inv_q(ol->frame_rate); ret = init_framesync(ctx); if (ret < 0) diff --git a/libavfilter/vf_overlay_vaapi.c b/libavfilter/vf_overlay_vaapi.c index 9b1e12bdc..dde7f00a6 100644 --- a/libavfilter/vf_overlay_vaapi.c +++ b/libavfilter/vf_overlay_vaapi.c @@ -21,8 +21,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "vaapi_vpp.h" #include "video.h" #include "libavutil/eval.h" @@ -256,12 +256,13 @@ fail: static int have_alpha_planar(AVFilterLink *link) { + FilterLink *l = ff_filter_link(link); enum AVPixelFormat pix_fmt = link->format; const AVPixFmtDescriptor *desc; AVHWFramesContext *fctx; if (link->format == AV_PIX_FMT_VAAPI) { - fctx = (AVHWFramesContext *)link->hw_frames_ctx->data; + fctx = (AVHWFramesContext *)l->hw_frames_ctx->data; pix_fmt = fctx->sw_format; } diff --git a/libavfilter/vf_overlay_vulkan.c b/libavfilter/vf_overlay_vulkan.c index c09de2414..09444067a 100644 --- a/libavfilter/vf_overlay_vulkan.c +++ b/libavfilter/vf_overlay_vulkan.c @@ -22,7 +22,8 @@ #include "libavutil/opt.h" #include "vulkan_filter.h" #include "vulkan_spirv.h" -#include "internal.h" + +#include "filters.h" #include "framesync.h" #include "video.h" diff --git a/libavfilter/vf_owdenoise.c b/libavfilter/vf_owdenoise.c index fad85bfa8..624e2d8cf 100644 --- a/libavfilter/vf_owdenoise.c +++ b/libavfilter/vf_owdenoise.c @@ -34,11 +34,12 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/mem_internal.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct OWDenoiseContext { diff --git a/libavfilter/vf_pad.c b/libavfilter/vf_pad.c index 2cced46f2..e0cf84002 100644 --- a/libavfilter/vf_pad.c +++ b/libavfilter/vf_pad.c @@ -27,8 +27,8 @@ #include /* DBL_MAX */ #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "libavutil/avstring.h" #include "libavutil/common.h" diff --git a/libavfilter/vf_pad_opencl.c b/libavfilter/vf_pad_opencl.c index 7c163a1d0..d5447a997 100644 --- a/libavfilter/vf_pad_opencl.c +++ b/libavfilter/vf_pad_opencl.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" diff --git a/libavfilter/vf_pad_vaapi.c b/libavfilter/vf_pad_vaapi.c new file mode 100644 index 000000000..f45e50314 --- /dev/null +++ b/libavfilter/vf_pad_vaapi.c @@ -0,0 +1,283 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/colorspace.h" +#include "libavutil/eval.h" +#include "libavutil/opt.h" + +#include "avfilter.h" +#include "filters.h" +#include "vaapi_vpp.h" +#include "video.h" + +static const char *const var_names[] = { + "in_w", "iw", + "in_h", "ih", + "out_w", "ow", + "out_h", "oh", + "x", + "y", + "a", + "sar", + "dar", + NULL +}; + +enum var_name { + VAR_IN_W, VAR_IW, + VAR_IN_H, VAR_IH, + VAR_OUT_W, VAR_OW, + VAR_OUT_H, VAR_OH, + VAR_X, + VAR_Y, + VAR_A, + VAR_SAR, + VAR_DAR, + VARS_NB +}; + +typedef struct PadVAAPIContext { + VAAPIVPPContext vpp_ctx; // must be the first field + VARectangle rect; + + char *w_expr; + char *h_expr; + char *x_expr; + char *y_expr; + AVRational aspect; + + int w, h; + int x, y; + uint8_t pad_rgba[4]; +} PadVAAPIContext; + +static int pad_vaapi_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + AVFilterLink *inlink = avctx->inputs[0]; + PadVAAPIContext *ctx = avctx->priv; + VAAPIVPPContext *vpp_ctx = avctx->priv; + AVRational adjusted_aspect = ctx->aspect; + double var_values[VARS_NB], res; + int err, ret; + char *expr; + + var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w; + var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h; + var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN; + var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN; + var_values[VAR_A] = (double) inlink->w / inlink->h; + var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? + (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1; + var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR]; + + av_expr_parse_and_eval(&res, (expr = ctx->w_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx); + ctx->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; + if ((ret = av_expr_parse_and_eval(&res, (expr = ctx->h_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) + return ret; + ctx->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res; + if (!ctx->h) + var_values[VAR_OUT_H] = var_values[VAR_OH] = ctx->h = inlink->h; + + /* evaluate the width again, as it may depend on the evaluated output height */ + if ((ret = av_expr_parse_and_eval(&res, (expr = ctx->w_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) + return ret; + ctx->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; + if (!ctx->w) + var_values[VAR_OUT_W] = var_values[VAR_OW] = ctx->w = inlink->w; + + if (adjusted_aspect.num && adjusted_aspect.den) { + adjusted_aspect = av_div_q(adjusted_aspect, inlink->sample_aspect_ratio); + if (ctx->h < av_rescale(ctx->w, adjusted_aspect.den, adjusted_aspect.num)) { + ctx->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = av_rescale(ctx->w, adjusted_aspect.den, adjusted_aspect.num); + } else { + ctx->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = av_rescale(ctx->h, adjusted_aspect.num, adjusted_aspect.den); + } + } + + /* evaluate x and y */ + av_expr_parse_and_eval(&res, (expr = ctx->x_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx); + ctx->x = var_values[VAR_X] = res; + if ((ret = av_expr_parse_and_eval(&res, (expr = ctx->y_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) + return ret; + ctx->y = var_values[VAR_Y] = res; + /* evaluate x again, as it may depend on the evaluated y value */ + if ((ret = av_expr_parse_and_eval(&res, (expr = ctx->x_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) + return ret; + ctx->x = var_values[VAR_X] = res; + + if (ctx->x < 0 || ctx->x + inlink->w > ctx->w) + ctx->x = var_values[VAR_X] = (ctx->w - inlink->w) / 2; + if (ctx->y < 0 || ctx->y + inlink->h > ctx->h) + ctx->y = var_values[VAR_Y] = (ctx->h - inlink->h) / 2; + + /* sanity check params */ + if (ctx->w < inlink->w || ctx->h < inlink->h) { + av_log(ctx, AV_LOG_ERROR, "Padded dimensions cannot be smaller than input dimensions.\n"); + return AVERROR(EINVAL); + } + + if (ctx->w > avctx->inputs[0]->w) { + vpp_ctx->output_width = ctx->w; + } else { + vpp_ctx->output_width = avctx->inputs[0]->w; + } + + if (ctx->h > avctx->inputs[0]->h) { + vpp_ctx->output_height = ctx->h; + } else { + vpp_ctx->output_height = avctx->inputs[0]->h; + } + + if (ctx->x + avctx->inputs[0]->w > vpp_ctx->output_width || + ctx->y + avctx->inputs[0]->h > vpp_ctx->output_height) { + return AVERROR(EINVAL); + } + + err = ff_vaapi_vpp_config_output(outlink); + if (err < 0) + return err; + + return 0; +} + +static int pad_vaapi_filter_frame(AVFilterLink *link, AVFrame *input_frame) +{ + AVFilterContext *avctx = link->dst; + AVFilterLink *outlink = avctx->outputs[0]; + VAAPIVPPContext *vpp_ctx = avctx->priv; + PadVAAPIContext *pad_ctx = avctx->priv; + AVFrame *output_frame = NULL; + VAProcPipelineParameterBuffer params; + int err; + + if (!input_frame->hw_frames_ctx || + vpp_ctx->va_context == VA_INVALID_ID) { + err = AVERROR(EINVAL); + goto fail; + } + + output_frame = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output_frame) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + goto fail; + + err = ff_vaapi_vpp_init_params(avctx, ¶ms, + input_frame, output_frame); + if (err < 0) + goto fail; + + pad_ctx->rect.x = pad_ctx->x; + pad_ctx->rect.y = pad_ctx->y; + pad_ctx->rect.width = link->w; + pad_ctx->rect.height = link->h; + params.output_region = &pad_ctx->rect; + + params.output_background_color = (pad_ctx->pad_rgba[3] << 24 | + pad_ctx->pad_rgba[0] << 16 | + pad_ctx->pad_rgba[1] << 8 | + pad_ctx->pad_rgba[2]); + + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_frame); + if (err < 0) + goto fail; + + av_frame_free(&input_frame); + + return ff_filter_frame(outlink, output_frame); + +fail: + av_frame_free(&input_frame); + av_frame_free(&output_frame); + return err; +} + +static av_cold int pad_vaapi_init(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + + ff_vaapi_vpp_ctx_init(avctx); + vpp_ctx->pipeline_uninit = ff_vaapi_vpp_pipeline_uninit; + vpp_ctx->output_format = AV_PIX_FMT_NONE; + + return 0; +} + +#define OFFSET(x) offsetof(PadVAAPIContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption pad_vaapi_options[] = { + { "width", "set the pad area width", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, 0, 0, FLAGS }, + { "w", "set the pad area width", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, 0, 0, FLAGS }, + { "height", "set the pad area height", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, 0, 0, FLAGS }, + { "h", "set the pad area height", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, 0, 0, FLAGS }, + { "x", "set the x offset for the input image position", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str = "0"}, 0, INT16_MAX, FLAGS }, + { "y", "set the y offset for the input image position", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str = "0"}, 0, INT16_MAX, FLAGS }, + { "color", "set the color of the padded area border", OFFSET(pad_rgba), AV_OPT_TYPE_COLOR, { .str = "black" }, 0, 0, FLAGS }, + { "aspect", "pad to fit an aspect instead of a resolution", OFFSET(aspect), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, INT16_MAX, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(pad_vaapi); + +static const AVFilterPad pad_vaapi_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = pad_vaapi_filter_frame, + .config_props = &ff_vaapi_vpp_config_input, + }, +}; + +static const AVFilterPad pad_vaapi_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &pad_vaapi_config_output, + }, +}; + +const AVFilter ff_vf_pad_vaapi = { + .name = "pad_vaapi", + .description = NULL_IF_CONFIG_SMALL("Pad the input video."), + .priv_size = sizeof(PadVAAPIContext), + .priv_class = &pad_vaapi_class, + .init = &pad_vaapi_init, + .uninit = &ff_vaapi_vpp_ctx_uninit, + FILTER_INPUTS(pad_vaapi_inputs), + FILTER_OUTPUTS(pad_vaapi_outputs), + FILTER_QUERY_FUNC(&ff_vaapi_vpp_query_formats), + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c index dcd4e99af..666bb6e34 100644 --- a/libavfilter/vf_palettegen.c +++ b/libavfilter/vf_palettegen.c @@ -26,11 +26,12 @@ #include "libavutil/avassert.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/intreadwrite.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "palette.h" #include "video.h" diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c index 8394f62f0..0cd00d520 100644 --- a/libavfilter/vf_paletteuse.c +++ b/libavfilter/vf_paletteuse.c @@ -27,13 +27,13 @@ #include "libavutil/bprint.h" #include "libavutil/file_open.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/qsort.h" #include "avfilter.h" #include "filters.h" #include "formats.h" #include "framesync.h" -#include "internal.h" #include "palette.h" #include "video.h" diff --git a/libavfilter/vf_perspective.c b/libavfilter/vf_perspective.c index 0206c75b6..5dd56a7df 100644 --- a/libavfilter/vf_perspective.c +++ b/libavfilter/vf_perspective.c @@ -22,10 +22,11 @@ #include "libavutil/avassert.h" #include "libavutil/eval.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define SUB_PIXEL_BITS 8 @@ -121,13 +122,15 @@ enum { VAR_W, VAR_H, VAR_IN, VAR_ON, VAR_VARS_ static int calc_persp_luts(AVFilterContext *ctx, AVFilterLink *inlink) { + FilterLink *inl = ff_filter_link(inlink); PerspectiveContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); double (*ref)[2] = s->ref; double values[VAR_VARS_NB] = { [VAR_W] = inlink->w, [VAR_H] = inlink->h, - [VAR_IN] = inlink->frame_count_out + 1, - [VAR_ON] = outlink->frame_count_in + 1 }; + [VAR_IN] = inl->frame_count_out + 1, + [VAR_ON] = outl->frame_count_in + 1 }; const int h = values[VAR_H]; const int w = values[VAR_W]; double x0, x1, x2, x3, x4, x5, x6, x7, x8, q; diff --git a/libavfilter/vf_phase.c b/libavfilter/vf_phase.c index 4fd6d2b6e..6cd8d8bb9 100644 --- a/libavfilter/vf_phase.c +++ b/libavfilter/vf_phase.c @@ -23,7 +23,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum PhaseMode { diff --git a/libavfilter/vf_photosensitivity.c b/libavfilter/vf_photosensitivity.c index e7920b324..5ea987379 100644 --- a/libavfilter/vf_photosensitivity.c +++ b/libavfilter/vf_photosensitivity.c @@ -24,7 +24,6 @@ #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" #define MAX_FRAMES 240 diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c index c2638d058..f53f087f2 100644 --- a/libavfilter/vf_pixdesctest.c +++ b/libavfilter/vf_pixdesctest.c @@ -24,9 +24,10 @@ */ #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct PixdescTestContext { diff --git a/libavfilter/vf_pixelize.c b/libavfilter/vf_pixelize.c index 4eb236f12..bf9281863 100644 --- a/libavfilter/vf_pixelize.c +++ b/libavfilter/vf_pixelize.c @@ -24,7 +24,7 @@ #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum PixelizeModes { diff --git a/libavfilter/vf_pp.c b/libavfilter/vf_pp.c index aa37325a2..85ac79558 100644 --- a/libavfilter/vf_pp.c +++ b/libavfilter/vf_pp.c @@ -25,9 +25,10 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "internal.h" +#include "filters.h" #include "qp_table.h" #include "video.h" diff --git a/libavfilter/vf_pp7.c b/libavfilter/vf_pp7.c index c4f1b2008..6fe243bba 100644 --- a/libavfilter/vf_pp7.c +++ b/libavfilter/vf_pp7.c @@ -29,10 +29,12 @@ #include "libavutil/emms.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "internal.h" + +#include "filters.h" #include "qp_table.h" #include "vf_pp7.h" #include "video.h" diff --git a/libavfilter/vf_premultiply.c b/libavfilter/vf_premultiply.c index 5e97c2000..30be86991 100644 --- a/libavfilter/vf_premultiply.c +++ b/libavfilter/vf_premultiply.c @@ -27,7 +27,6 @@ #include "filters.h" #include "formats.h" #include "framesync.h" -#include "internal.h" #include "video.h" typedef struct ThreadData { @@ -696,6 +695,8 @@ static int config_output(AVFilterLink *outlink) PreMultiplyContext *s = ctx->priv; AVFilterLink *base = ctx->inputs[0]; AVFilterLink *alpha; + FilterLink *il = ff_filter_link(base); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -717,7 +718,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = base->h; outlink->time_base = base->time_base; outlink->sample_aspect_ratio = base->sample_aspect_ratio; - outlink->frame_rate = base->frame_rate; + ol->frame_rate = il->frame_rate; if (s->inplace) return 0; diff --git a/libavfilter/vf_procamp_vaapi.c b/libavfilter/vf_procamp_vaapi.c index b535a36d3..be3cdae8b 100644 --- a/libavfilter/vf_procamp_vaapi.c +++ b/libavfilter/vf_procamp_vaapi.c @@ -21,7 +21,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "vaapi_vpp.h" #include "video.h" diff --git a/libavfilter/vf_program_opencl.c b/libavfilter/vf_program_opencl.c index 8a4881b38..3b4982916 100644 --- a/libavfilter/vf_program_opencl.c +++ b/libavfilter/vf_program_opencl.c @@ -25,8 +25,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "opencl.h" #include "video.h" diff --git a/libavfilter/vf_pseudocolor.c b/libavfilter/vf_pseudocolor.c index cfdfac784..46c65da38 100644 --- a/libavfilter/vf_pseudocolor.c +++ b/libavfilter/vf_pseudocolor.c @@ -25,7 +25,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" static const char *const var_names[] = { diff --git a/libavfilter/vf_psnr.c b/libavfilter/vf_psnr.c index 058a8932f..4a5db5df2 100644 --- a/libavfilter/vf_psnr.c +++ b/libavfilter/vf_psnr.c @@ -27,12 +27,13 @@ #include "libavutil/avstring.h" #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "psnr.h" typedef struct PSNRContext { @@ -289,10 +290,8 @@ static av_cold int init(AVFilterContext *ctx) s->stats_file = avpriv_fopen_utf8(s->stats_file_str, "w"); if (!s->stats_file) { int err = AVERROR(errno); - char buf[128]; - av_strerror(err, buf, sizeof(buf)); av_log(ctx, AV_LOG_ERROR, "Could not open stats file %s: %s\n", - s->stats_file_str, buf); + s->stats_file_str, av_err2str(err)); return err; } } @@ -382,6 +381,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; PSNRContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(mainlink); + FilterLink *ol = ff_filter_link(outlink); int ret; ret = ff_framesync_init_dualinput(&s->fs, ctx); @@ -391,7 +392,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_configure(&s->fs)) < 0) return ret; diff --git a/libavfilter/vf_pullup.c b/libavfilter/vf_pullup.c index 231f09620..9c8ac7f91 100644 --- a/libavfilter/vf_pullup.c +++ b/libavfilter/vf_pullup.c @@ -21,10 +21,11 @@ #include "libavutil/avassert.h" #include "libavutil/emms.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "vf_pullup.h" diff --git a/libavfilter/vf_qp.c b/libavfilter/vf_qp.c index 37e575447..bc881ca6d 100644 --- a/libavfilter/vf_qp.c +++ b/libavfilter/vf_qp.c @@ -24,7 +24,7 @@ #include "libavutil/video_enc_params.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct QPContext { diff --git a/libavfilter/vf_quirc.c b/libavfilter/vf_quirc.c index 62eb29b7c..afd172fa3 100644 --- a/libavfilter/vf_quirc.c +++ b/libavfilter/vf_quirc.c @@ -27,6 +27,7 @@ #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "video.h" #include @@ -89,6 +90,7 @@ static int query_formats(AVFilterContext *ctx) static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; QuircContext *quirc = ctx->priv; @@ -104,7 +106,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) codes_count = quirc_count(quirc->quirc); av_log(ctx, AV_LOG_VERBOSE, - "Found count %d codes in image #%ld\n", codes_count, inlink->frame_count_out); + "Found count %d codes in image #%ld\n", codes_count, inl->frame_count_out); if (codes_count) { int i, j; diff --git a/libavfilter/vf_random.c b/libavfilter/vf_random.c index 8c7cf8b80..032153a05 100644 --- a/libavfilter/vf_random.c +++ b/libavfilter/vf_random.c @@ -22,7 +22,7 @@ #include "libavutil/opt.h" #include "libavutil/random_seed.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #define MAX_FRAMES 512 diff --git a/libavfilter/vf_readeia608.c b/libavfilter/vf_readeia608.c index 50bf91576..84ed2a27e 100644 --- a/libavfilter/vf_readeia608.c +++ b/libavfilter/vf_readeia608.c @@ -27,11 +27,12 @@ #include #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define LAG 25 diff --git a/libavfilter/vf_readvitc.c b/libavfilter/vf_readvitc.c index cb63a4d12..303703894 100644 --- a/libavfilter/vf_readvitc.c +++ b/libavfilter/vf_readvitc.c @@ -29,7 +29,7 @@ #include "libavutil/opt.h" #include "libavutil/timecode.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define LINE_DATA_SIZE 9 diff --git a/libavfilter/vf_remap.c b/libavfilter/vf_remap.c index 7cc56fa5f..df81c247e 100644 --- a/libavfilter/vf_remap.c +++ b/libavfilter/vf_remap.c @@ -42,9 +42,9 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" #include "framesync.h" -#include "internal.h" #include "video.h" typedef struct RemapContext { @@ -313,6 +313,8 @@ static int config_output(AVFilterLink *outlink) AVFilterLink *srclink = ctx->inputs[0]; AVFilterLink *xlink = ctx->inputs[1]; AVFilterLink *ylink = ctx->inputs[2]; + FilterLink *il = ff_filter_link(srclink); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -328,7 +330,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = xlink->w; outlink->h = xlink->h; outlink->sample_aspect_ratio = srclink->sample_aspect_ratio; - outlink->frame_rate = srclink->frame_rate; + ol->frame_rate = il->frame_rate; ret = ff_framesync_init(&s->fs, ctx, 3); if (ret < 0) diff --git a/libavfilter/vf_remap_opencl.c b/libavfilter/vf_remap_opencl.c index 8da48096d..89d3efd53 100644 --- a/libavfilter/vf_remap_opencl.c +++ b/libavfilter/vf_remap_opencl.c @@ -23,8 +23,8 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" @@ -233,6 +233,8 @@ static int config_output(AVFilterLink *outlink) AVFilterLink *srclink = ctx->inputs[0]; AVFilterLink *xlink = ctx->inputs[1]; AVFilterLink *ylink = ctx->inputs[2]; + FilterLink *il = ff_filter_link(srclink); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -248,7 +250,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = xlink->w; outlink->h = xlink->h; outlink->sample_aspect_ratio = srclink->sample_aspect_ratio; - outlink->frame_rate = srclink->frame_rate; + ol->frame_rate = il->frame_rate; ret = ff_framesync_init(&s->fs, ctx, 3); if (ret < 0) diff --git a/libavfilter/vf_removegrain.c b/libavfilter/vf_removegrain.c index 6e6e99198..5a0267023 100644 --- a/libavfilter/vf_removegrain.c +++ b/libavfilter/vf_removegrain.c @@ -26,7 +26,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/qsort.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "removegrain.h" #include "video.h" diff --git a/libavfilter/vf_removelogo.c b/libavfilter/vf_removelogo.c index b29305430..f17487eac 100644 --- a/libavfilter/vf_removelogo.c +++ b/libavfilter/vf_removelogo.c @@ -70,9 +70,10 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "bbox.h" #include "lavfutils.h" diff --git a/libavfilter/vf_repeatfields.c b/libavfilter/vf_repeatfields.c index bf0edb544..a89a295cc 100644 --- a/libavfilter/vf_repeatfields.c +++ b/libavfilter/vf_repeatfields.c @@ -21,7 +21,6 @@ #include "libavutil/imgutils.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" typedef struct RepeatFieldsContext { @@ -69,7 +68,9 @@ static int config_input(AVFilterLink *inlink) static void update_pts(AVFilterLink *link, AVFrame *f, int64_t pts, int fields) { - if (av_cmp_q(link->frame_rate, (AVRational){30000, 1001}) == 0 && + FilterLink *l = ff_filter_link(link); + + if (av_cmp_q(l->frame_rate, (AVRational){30000, 1001}) == 0 && av_cmp_q(link->time_base, (AVRational){1001, 60000}) <= 0 ) { f->pts = pts + av_rescale_q(fields, (AVRational){1001, 60000}, link->time_base); diff --git a/libavfilter/vf_rotate.c b/libavfilter/vf_rotate.c index 3e65f2655..0a4194648 100644 --- a/libavfilter/vf_rotate.c +++ b/libavfilter/vf_rotate.c @@ -33,7 +33,7 @@ #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include @@ -501,6 +501,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) static int filter_frame(AVFilterLink *inlink, AVFrame *in) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out; @@ -515,7 +516,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } av_frame_copy_props(out, in); - rot->var_values[VAR_N] = inlink->frame_count_out; + rot->var_values[VAR_N] = inl->frame_count_out; rot->var_values[VAR_T] = TS2T(in->pts, inlink->time_base); rot->angle = res = av_expr_eval(rot->angle_expr, rot->var_values, rot); diff --git a/libavfilter/vf_sab.c b/libavfilter/vf_sab.c index 5e0687c9a..d6fcb73a0 100644 --- a/libavfilter/vf_sab.c +++ b/libavfilter/vf_sab.c @@ -23,12 +23,13 @@ * Shape Adaptive Blur filter, ported from MPlayer libmpcodecs/vf_sab.c */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libswscale/swscale.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct FilterParam { diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index 960ce42b5..3319428d9 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -28,18 +28,18 @@ #include #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" +#include "framesync.h" #include "scale_eval.h" #include "video.h" -#include "libavutil/avstring.h" #include "libavutil/eval.h" +#include "libavutil/imgutils_internal.h" #include "libavutil/internal.h" -#include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" -#include "libavutil/imgutils.h" #include "libswscale/swscale.h" static const char *const var_names[] = { @@ -59,6 +59,17 @@ static const char *const var_names[] = { #if FF_API_FRAME_PKT "pos", #endif + "ref_w", "rw", + "ref_h", "rh", + "ref_a", + "ref_sar", + "ref_dar", "rdar", + "ref_hsub", + "ref_vsub", + "ref_n", + "ref_t", + "ref_pos", + /* Legacy variables for scale2ref */ "main_w", "main_h", "main_a", @@ -89,6 +100,16 @@ enum var_name { #if FF_API_FRAME_PKT VAR_POS, #endif + VAR_REF_W, VAR_RW, + VAR_REF_H, VAR_RH, + VAR_REF_A, + VAR_REF_SAR, + VAR_REF_DAR, VAR_RDAR, + VAR_REF_HSUB, + VAR_REF_VSUB, + VAR_REF_N, + VAR_REF_T, + VAR_REF_POS, VAR_S2R_MAIN_W, VAR_S2R_MAIN_H, VAR_S2R_MAIN_A, @@ -114,6 +135,7 @@ typedef struct ScaleContext { struct SwsContext *isws[2]; ///< software scaler context for interlaced material // context used for forwarding options to sws struct SwsContext *sws_opts; + FFFrameSync fs; /** * New dimensions. Special values are: @@ -130,6 +152,7 @@ typedef struct ScaleContext { int input_is_pal; ///< set to 1 if the input format is paletted int output_is_pal; ///< set to 1 if the output format is paletted int interlaced; + int uses_ref; char *w_expr; ///< width expression string char *h_expr; ///< height expression string @@ -145,6 +168,8 @@ typedef struct ScaleContext { int in_range; int out_range; + int in_chroma_loc; + int out_chroma_loc; int out_h_chr_pos; int out_v_chr_pos; int in_h_chr_pos; @@ -189,6 +214,38 @@ static int check_exprs(AVFilterContext *ctx) av_log(ctx, AV_LOG_WARNING, "Circular references detected for width '%s' and height '%s' - possibly invalid.\n", scale->w_expr, scale->h_expr); } + if (vars_w[VAR_REF_W] || vars_h[VAR_REF_W] || + vars_w[VAR_RW] || vars_h[VAR_RW] || + vars_w[VAR_REF_H] || vars_h[VAR_REF_H] || + vars_w[VAR_RH] || vars_h[VAR_RH] || + vars_w[VAR_REF_A] || vars_h[VAR_REF_A] || + vars_w[VAR_REF_SAR] || vars_h[VAR_REF_SAR] || + vars_w[VAR_REF_DAR] || vars_h[VAR_REF_DAR] || + vars_w[VAR_RDAR] || vars_h[VAR_RDAR] || + vars_w[VAR_REF_HSUB] || vars_h[VAR_REF_HSUB] || + vars_w[VAR_REF_VSUB] || vars_h[VAR_REF_VSUB] || + vars_w[VAR_REF_N] || vars_h[VAR_REF_N] || + vars_w[VAR_REF_T] || vars_h[VAR_REF_T] || + vars_w[VAR_REF_POS] || vars_h[VAR_REF_POS]) { + scale->uses_ref = 1; + } + + if (ctx->filter != &ff_vf_scale2ref && + (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] || + vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] || + vars_w[VAR_S2R_MAIN_A] || vars_h[VAR_S2R_MAIN_A] || + vars_w[VAR_S2R_MAIN_SAR] || vars_h[VAR_S2R_MAIN_SAR] || + vars_w[VAR_S2R_MAIN_DAR] || vars_h[VAR_S2R_MAIN_DAR] || + vars_w[VAR_S2R_MDAR] || vars_h[VAR_S2R_MDAR] || + vars_w[VAR_S2R_MAIN_HSUB] || vars_h[VAR_S2R_MAIN_HSUB] || + vars_w[VAR_S2R_MAIN_VSUB] || vars_h[VAR_S2R_MAIN_VSUB] || + vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] || + vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] || + vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS]) ) { + av_log(ctx, AV_LOG_ERROR, "Expressions with scale2ref variables are not valid in scale filter.\n"); + return AVERROR(EINVAL); + } + if (ctx->filter != &ff_vf_scale2ref && (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] || vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] || @@ -288,6 +345,8 @@ static av_cold int preinit(AVFilterContext *ctx) if (ret < 0) return ret; + ff_framesync_preinit(&scale->fs); + return 0; } @@ -303,12 +362,17 @@ static const int sws_colorspaces[] = { -1 }; +static int do_scale(FFFrameSync *fs); + static av_cold int init(AVFilterContext *ctx) { ScaleContext *scale = ctx->priv; int64_t threads; int ret; + if (ctx->filter == &ff_vf_scale2ref) + av_log(ctx, AV_LOG_WARNING, "scale2ref is deprecated, use scale=rw:rh instead\n"); + if (scale->size_str && (scale->w_expr || scale->h_expr)) { av_log(ctx, AV_LOG_ERROR, "Size and width/height expressions cannot be set at the same time.\n"); @@ -380,6 +444,16 @@ static av_cold int init(AVFilterContext *ctx) if (!threads) av_opt_set_int(scale->sws_opts, "threads", ff_filter_get_nb_threads(ctx), 0); + if (ctx->filter != &ff_vf_scale2ref && scale->uses_ref) { + AVFilterPad pad = { + .name = "ref", + .type = AVMEDIA_TYPE_VIDEO, + }; + ret = ff_append_inpad(ctx, &pad); + if (ret < 0) + return ret; + } + return 0; } @@ -389,6 +463,7 @@ static av_cold void uninit(AVFilterContext *ctx) av_expr_free(scale->w_pexpr); av_expr_free(scale->h_pexpr); scale->w_pexpr = scale->h_pexpr = NULL; + ff_framesync_uninit(&scale->fs); sws_freeContext(scale->sws_opts); sws_freeContext(scale->sws); sws_freeContext(scale->isws[0]); @@ -500,6 +575,20 @@ static int scale_eval_dimensions(AVFilterContext *ctx) scale->var_values[VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h; } + if (scale->uses_ref) { + const AVFilterLink *reflink = ctx->inputs[1]; + const AVPixFmtDescriptor *ref_desc = av_pix_fmt_desc_get(reflink->format); + scale->var_values[VAR_REF_W] = scale->var_values[VAR_RW] = reflink->w; + scale->var_values[VAR_REF_H] = scale->var_values[VAR_RH] = reflink->h; + scale->var_values[VAR_REF_A] = (double) reflink->w / reflink->h; + scale->var_values[VAR_REF_SAR] = reflink->sample_aspect_ratio.num ? + (double) reflink->sample_aspect_ratio.num / reflink->sample_aspect_ratio.den : 1; + scale->var_values[VAR_REF_DAR] = scale->var_values[VAR_RDAR] = + scale->var_values[VAR_REF_A] * scale->var_values[VAR_REF_SAR]; + scale->var_values[VAR_REF_HSUB] = 1 << ref_desc->log2_chroma_w; + scale->var_values[VAR_REF_VSUB] = 1 << ref_desc->log2_chroma_h; + } + res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL); eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res; @@ -530,6 +619,50 @@ fail: return ret; } +static void calc_chroma_pos(int *h_pos_out, int *v_pos_out, int chroma_loc, + int h_pos_override, int v_pos_override, + int h_sub, int v_sub, int index) +{ + int h_pos, v_pos; + + /* Explicitly default to center siting for compatibility with swscale */ + if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) + chroma_loc = AVCHROMA_LOC_CENTER; + + /* av_chroma_location_enum_to_pos() always gives us values in the range from + * 0 to 256, but we need to adjust this to the true value range of the + * subsampling grid, which may be larger for h/v_sub > 1 */ + av_chroma_location_enum_to_pos(&h_pos, &v_pos, chroma_loc); + h_pos *= (1 << h_sub) - 1; + v_pos *= (1 << v_sub) - 1; + + if (h_pos_override != -513) + h_pos = h_pos_override; + if (v_pos_override != -513) + v_pos = v_pos_override; + + /* Fix vertical chroma position for interlaced frames */ + if (v_sub && index > 0) { + /* When vertically subsampling, chroma samples are effectively only + * placed next to even rows. To access them from the odd field, we need + * to account for this shift by offsetting the distance of one luma row. + * + * For 4x vertical subsampling (v_sub == 2), they are only placed + * next to every *other* even row, so we need to shift by three luma + * rows to get to the chroma sample. */ + if (index == 2) + v_pos += (256 << v_sub) - 256; + + /* Luma row distance is doubled for fields, so halve offsets */ + v_pos >>= 1; + } + + /* Explicitly strip chroma offsets when not subsampling, because it + * interferes with the operation of flags like SWS_FULL_CHR_H_INP */ + *h_pos_out = h_sub ? h_pos : -513; + *v_pos_out = v_sub ? v_pos : -513; +} + static int config_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; @@ -589,15 +722,16 @@ static int config_props(AVFilterLink *outlink) inlink0->h == outlink->h && in_range == outlink->color_range && in_colorspace == outlink->colorspace && - inlink0->format == outlink->format) + inlink0->format == outlink->format && + scale->in_chroma_loc == scale->out_chroma_loc) ; else { struct SwsContext **swscs[3] = {&scale->sws, &scale->isws[0], &scale->isws[1]}; int i; for (i = 0; i < 3; i++) { - int in_v_chr_pos = scale->in_v_chr_pos, out_v_chr_pos = scale->out_v_chr_pos; int in_full, out_full, brightness, contrast, saturation; + int h_chr_pos, v_chr_pos; const int *inv_table, *table; struct SwsContext *const s = sws_alloc_context(); if (!s) @@ -621,22 +755,17 @@ static int config_props(AVFilterLink *outlink) av_opt_set_int(s, "dst_range", outlink->color_range == AVCOL_RANGE_JPEG, 0); - /* Override chroma location default settings to have the correct - * chroma positions. MPEG chroma positions are used by convention. - * Note that this works for both MPEG-1/JPEG and MPEG-2/4 chroma - * locations, since they share a vertical alignment */ - if (desc->log2_chroma_h == 1 && scale->in_v_chr_pos == -513) { - in_v_chr_pos = (i == 0) ? 128 : (i == 1) ? 64 : 192; - } + calc_chroma_pos(&h_chr_pos, &v_chr_pos, scale->in_chroma_loc, + scale->in_h_chr_pos, scale->in_v_chr_pos, + desc->log2_chroma_w, desc->log2_chroma_h, i); + av_opt_set_int(s, "src_h_chr_pos", h_chr_pos, 0); + av_opt_set_int(s, "src_v_chr_pos", v_chr_pos, 0); - if (outdesc->log2_chroma_h == 1 && scale->out_v_chr_pos == -513) { - out_v_chr_pos = (i == 0) ? 128 : (i == 1) ? 64 : 192; - } - - av_opt_set_int(s, "src_h_chr_pos", scale->in_h_chr_pos, 0); - av_opt_set_int(s, "src_v_chr_pos", in_v_chr_pos, 0); - av_opt_set_int(s, "dst_h_chr_pos", scale->out_h_chr_pos, 0); - av_opt_set_int(s, "dst_v_chr_pos", out_v_chr_pos, 0); + calc_chroma_pos(&h_chr_pos, &v_chr_pos, scale->out_chroma_loc, + scale->out_h_chr_pos, scale->out_v_chr_pos, + outdesc->log2_chroma_w, outdesc->log2_chroma_h, i); + av_opt_set_int(s, "dst_h_chr_pos", h_chr_pos, 0); + av_opt_set_int(s, "dst_v_chr_pos", v_chr_pos, 0); if ((ret = sws_init_context(s, NULL, NULL)) < 0) return ret; @@ -681,6 +810,29 @@ static int config_props(AVFilterLink *outlink) flags_val); av_freep(&flags_val); + if (ctx->filter != &ff_vf_scale2ref) { + ff_framesync_uninit(&scale->fs); + ret = ff_framesync_init(&scale->fs, ctx, ctx->nb_inputs); + if (ret < 0) + return ret; + scale->fs.on_event = do_scale; + scale->fs.in[0].time_base = ctx->inputs[0]->time_base; + scale->fs.in[0].sync = 1; + scale->fs.in[0].before = EXT_STOP; + scale->fs.in[0].after = EXT_STOP; + if (scale->uses_ref) { + av_assert0(ctx->nb_inputs == 2); + scale->fs.in[1].time_base = ctx->inputs[1]->time_base; + scale->fs.in[1].sync = 0; + scale->fs.in[1].before = EXT_NULL; + scale->fs.in[1].after = EXT_INFINITY; + } + + ret = ff_framesync_configure(&scale->fs); + if (ret < 0) + return ret; + } + return 0; fail: @@ -690,12 +842,14 @@ fail: static int config_props_ref(AVFilterLink *outlink) { AVFilterLink *inlink = outlink->src->inputs[1]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); outlink->w = inlink->w; outlink->h = inlink->h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->time_base = inlink->time_base; - outlink->frame_rate = inlink->frame_rate; + ol->frame_rate = il->frame_rate; outlink->colorspace = inlink->colorspace; outlink->color_range = inlink->color_range; @@ -762,18 +916,21 @@ static int scale_field(ScaleContext *scale, AVFrame *dst, AVFrame *src, return 0; } -static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out) +/* Takes over ownership of *frame_in, passes ownership of *frame_out to caller */ +static int scale_frame(AVFilterLink *link, AVFrame **frame_in, + AVFrame **frame_out) { + FilterLink *inl = ff_filter_link(link); AVFilterContext *ctx = link->dst; ScaleContext *scale = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - AVFrame *out; + AVFrame *out, *in = *frame_in; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); char buf[32]; int ret; int frame_changed; - *frame_out = NULL; + *frame_in = NULL; if (in->colorspace == AVCOL_SPC_YCGCO) av_log(link->dst, AV_LOG_WARNING, "Detected unsupported YCgCo colorspace.\n"); @@ -815,15 +972,15 @@ static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out) ret = scale_parse_expr(ctx, NULL, &scale->w_pexpr, "width", scale->w_expr); if (ret < 0) - return ret; + goto err; ret = scale_parse_expr(ctx, NULL, &scale->h_pexpr, "height", scale->h_expr); if (ret < 0) - return ret; + goto err; } if (ctx->filter == &ff_vf_scale2ref) { - scale->var_values[VAR_S2R_MAIN_N] = link->frame_count_out; + scale->var_values[VAR_S2R_MAIN_N] = inl->frame_count_out; scale->var_values[VAR_S2R_MAIN_T] = TS2T(in->pts, link->time_base); #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS @@ -831,7 +988,7 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif } else { - scale->var_values[VAR_N] = link->frame_count_out; + scale->var_values[VAR_N] = inl->frame_count_out; scale->var_values[VAR_T] = TS2T(in->pts, link->time_base); #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS @@ -850,7 +1007,7 @@ FF_ENABLE_DEPRECATION_WARNINGS link->dst->inputs[0]->sample_aspect_ratio.num = in->sample_aspect_ratio.num; if ((ret = config_props(outlink)) < 0) - return ret; + goto err; } scale: @@ -864,16 +1021,17 @@ scale: out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) { - av_frame_free(&in); - return AVERROR(ENOMEM); + ret = AVERROR(ENOMEM); + goto err; } - *frame_out = out; av_frame_copy_props(out, in); out->width = outlink->w; out->height = outlink->h; out->color_range = outlink->color_range; out->colorspace = outlink->colorspace; + if (scale->out_chroma_loc != AVCHROMA_LOC_UNSPECIFIED) + out->chroma_location = scale->out_chroma_loc; if (scale->output_is_pal) avpriv_set_systematic_pal2((uint32_t*)out->data[1], outlink->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : outlink->format); @@ -892,9 +1050,80 @@ scale: ret = sws_scale_frame(scale->sws, out, in); } - av_frame_free(&in); if (ret < 0) - av_frame_free(frame_out); + av_frame_free(&out); + *frame_out = out; + +err: + av_frame_free(&in); + return ret; +} + +static int do_scale(FFFrameSync *fs) +{ + AVFilterContext *ctx = fs->parent; + ScaleContext *scale = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out, *in = NULL, *ref = NULL; + int ret = 0, frame_changed; + + ret = ff_framesync_get_frame(fs, 0, &in, 1); + if (ret < 0) + goto err; + + if (scale->uses_ref) { + ret = ff_framesync_get_frame(fs, 1, &ref, 0); + if (ret < 0) + goto err; + } + + if (ref) { + AVFilterLink *reflink = ctx->inputs[1]; + FilterLink *rl = ff_filter_link(reflink); + + frame_changed = ref->width != reflink->w || + ref->height != reflink->h || + ref->format != reflink->format || + ref->sample_aspect_ratio.den != reflink->sample_aspect_ratio.den || + ref->sample_aspect_ratio.num != reflink->sample_aspect_ratio.num || + ref->colorspace != reflink->colorspace || + ref->color_range != reflink->color_range; + + if (frame_changed) { + reflink->format = ref->format; + reflink->w = ref->width; + reflink->h = ref->height; + reflink->sample_aspect_ratio.num = ref->sample_aspect_ratio.num; + reflink->sample_aspect_ratio.den = ref->sample_aspect_ratio.den; + reflink->colorspace = ref->colorspace; + reflink->color_range = ref->color_range; + + ret = config_props(outlink); + if (ret < 0) + goto err; + } + + if (scale->eval_mode == EVAL_MODE_FRAME) { + scale->var_values[VAR_REF_N] = rl->frame_count_out; + scale->var_values[VAR_REF_T] = TS2T(ref->pts, reflink->time_base); +#if FF_API_FRAME_PKT +FF_DISABLE_DEPRECATION_WARNINGS + scale->var_values[VAR_REF_POS] = ref->pkt_pos == -1 ? NAN : ref->pkt_pos; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + } + } + + ret = scale_frame(ctx->inputs[0], &in, &out); + if (ret < 0) + goto err; + + av_assert0(out); + out->pts = av_rescale_q(fs->pts, fs->time_base, outlink->time_base); + return ff_filter_frame(outlink, out); + +err: + av_frame_free(&in); return ret; } @@ -905,7 +1134,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) AVFrame *out; int ret; - ret = scale_frame(link, in, &out); + ret = scale_frame(link, &in, &out); if (out) return ff_filter_frame(outlink, out); @@ -914,6 +1143,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) static int filter_frame_ref(AVFilterLink *link, AVFrame *in) { + FilterLink *l = ff_filter_link(link); ScaleContext *scale = link->dst->priv; AVFilterLink *outlink = link->dst->outputs[1]; int frame_changed; @@ -939,7 +1169,7 @@ static int filter_frame_ref(AVFilterLink *link, AVFrame *in) } if (scale->eval_mode == EVAL_MODE_FRAME) { - scale->var_values[VAR_N] = link->frame_count_out; + scale->var_values[VAR_N] = l->frame_count_out; scale->var_values[VAR_T] = TS2T(in->pts, link->time_base); #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS @@ -976,11 +1206,24 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar return ret; } +static int activate(AVFilterContext *ctx) +{ + ScaleContext *scale = ctx->priv; + return ff_framesync_activate(&scale->fs); +} + static const AVClass *child_class_iterate(void **iter) { - const AVClass *c = *iter ? NULL : sws_get_class(); - *iter = (void*)(uintptr_t)c; - return c; + switch ((uintptr_t) *iter) { + case 0: + *iter = (void*)(uintptr_t) 1; + return sws_get_class(); + case 1: + *iter = (void*)(uintptr_t) 2; + return &ff_framesync_class; + } + + return NULL; } static void *child_next(void *obj, void *prev) @@ -988,6 +1231,8 @@ static void *child_next(void *obj, void *prev) ScaleContext *s = obj; if (!prev) return s->sws_opts; + if (prev == s->sws_opts) + return &s->fs; return NULL; } @@ -1002,8 +1247,8 @@ static const AVOption scale_options[] = { { "height","Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS }, { "flags", "Flags to pass to libswscale", OFFSET(flags_str), AV_OPT_TYPE_STRING, { .str = "" }, .flags = FLAGS }, { "interl", "set interlacing", OFFSET(interlaced), AV_OPT_TYPE_BOOL, {.i64 = 0 }, -1, 1, FLAGS }, - { "size", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS }, - { "s", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS }, + { "size", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, .flags = FLAGS }, + { "s", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, .flags = FLAGS }, { "in_color_matrix", "set input YCbCr type", OFFSET(in_color_matrix), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AVCOL_SPC_NB-1, .flags = FLAGS, .unit = "color" }, { "out_color_matrix", "set output YCbCr type", OFFSET(out_color_matrix), AV_OPT_TYPE_INT, { .i64 = AVCOL_SPC_UNSPECIFIED }, 0, AVCOL_SPC_NB-1, .flags = FLAGS, .unit = "color"}, { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, FLAGS, .unit = "color" }, @@ -1024,6 +1269,16 @@ static const AVOption scale_options[] = { { "mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" }, { "tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" }, { "pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" }, + { "in_chroma_loc", "set input chroma sample location", OFFSET(in_chroma_loc), AV_OPT_TYPE_INT, { .i64 = AVCHROMA_LOC_UNSPECIFIED }, 0, AVCHROMA_LOC_NB-1, .flags = FLAGS, .unit = "chroma_loc" }, + { "out_chroma_loc", "set output chroma sample location", OFFSET(out_chroma_loc), AV_OPT_TYPE_INT, { .i64 = AVCHROMA_LOC_UNSPECIFIED }, 0, AVCHROMA_LOC_NB-1, .flags = FLAGS, .unit = "chroma_loc" }, + {"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_loc"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_loc"}, + {"left", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_LEFT}, 0, 0, FLAGS, .unit = "chroma_loc"}, + {"center", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_CENTER}, 0, 0, FLAGS, .unit = "chroma_loc"}, + {"topleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOPLEFT}, 0, 0, FLAGS, .unit = "chroma_loc"}, + {"top", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOP}, 0, 0, FLAGS, .unit = "chroma_loc"}, + {"bottomleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOMLEFT}, 0, 0, FLAGS, .unit = "chroma_loc"}, + {"bottom", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOM}, 0, 0, FLAGS, .unit = "chroma_loc"}, { "in_v_chr_pos", "input vertical chroma position in luma grid/256" , OFFSET(in_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS }, { "in_h_chr_pos", "input horizontal chroma position in luma grid/256", OFFSET(in_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS }, { "out_v_chr_pos", "output vertical chroma position in luma grid/256" , OFFSET(out_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS }, @@ -1042,7 +1297,7 @@ static const AVOption scale_options[] = { }; static const AVClass scale_class = { - .class_name = "scale(2ref)", + .class_name = "scale", .item_name = av_default_item_name, .option = scale_options, .version = LIBAVUTIL_VERSION_INT, @@ -1055,7 +1310,6 @@ static const AVFilterPad avfilter_vf_scale_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, }, }; @@ -1078,7 +1332,34 @@ const AVFilter ff_vf_scale = { FILTER_INPUTS(avfilter_vf_scale_inputs), FILTER_OUTPUTS(avfilter_vf_scale_outputs), FILTER_QUERY_FUNC(query_formats), + .activate = activate, .process_command = process_command, + .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, +}; + +static const AVClass *scale2ref_child_class_iterate(void **iter) +{ + const AVClass *c = *iter ? NULL : sws_get_class(); + *iter = (void*)(uintptr_t)c; + return c; +} + +static void *scale2ref_child_next(void *obj, void *prev) +{ + ScaleContext *s = obj; + if (!prev) + return s->sws_opts; + return NULL; +} + +static const AVClass scale2ref_class = { + .class_name = "scale(2ref)", + .item_name = av_default_item_name, + .option = scale_options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_FILTER, + .child_class_iterate = scale2ref_child_class_iterate, + .child_next = scale2ref_child_next, }; static const AVFilterPad avfilter_vf_scale2ref_inputs[] = { @@ -1116,7 +1397,7 @@ const AVFilter ff_vf_scale2ref = { .init = init, .uninit = uninit, .priv_size = sizeof(ScaleContext), - .priv_class = &scale_class, + .priv_class = &scale2ref_class, FILTER_INPUTS(avfilter_vf_scale2ref_inputs), FILTER_OUTPUTS(avfilter_vf_scale2ref_outputs), FILTER_QUERY_FUNC(query_formats), diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c index 5571a52b1..54a340949 100644 --- a/libavfilter/vf_scale_cuda.c +++ b/libavfilter/vf_scale_cuda.c @@ -32,7 +32,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "scale_eval.h" #include "video.h" @@ -221,6 +221,8 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int int out_width, int out_height) { CUDAScaleContext *s = ctx->priv; + FilterLink *inl = ff_filter_link(ctx->inputs[0]); + FilterLink *outl = ff_filter_link(ctx->outputs[0]); AVHWFramesContext *in_frames_ctx; @@ -229,11 +231,11 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int int ret; /* check that we have a hw context */ - if (!ctx->inputs[0]->hw_frames_ctx) { + if (!inl->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n"); return AVERROR(EINVAL); } - in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; + in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; in_format = in_frames_ctx->sw_format; out_format = (s->format == AV_PIX_FMT_NONE) ? in_format : s->format; @@ -251,7 +253,7 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int set_format_info(ctx, in_format, out_format); if (s->passthrough && in_width == out_width && in_height == out_height && in_format == out_format) { - s->frames_ctx = av_buffer_ref(ctx->inputs[0]->hw_frames_ctx); + s->frames_ctx = av_buffer_ref(inl->hw_frames_ctx); if (!s->frames_ctx) return AVERROR(ENOMEM); } else { @@ -266,8 +268,8 @@ static av_cold int init_processing_chain(AVFilterContext *ctx, int in_width, int s->interp_algo = INTERP_ALGO_NEAREST; } - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx); - if (!ctx->outputs[0]->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); return 0; @@ -348,15 +350,13 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); CUDAScaleContext *s = ctx->priv; - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; - AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + AVHWFramesContext *frames_ctx; + AVCUDADeviceContext *device_hwctx; int w, h; int ret; - s->hwctx = device_hwctx; - s->cu_stream = s->hwctx->stream; - if ((ret = ff_scale_eval_dimensions(s, s->w_expr, s->h_expr, inlink, outlink, @@ -377,6 +377,12 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink) if (ret < 0) return ret; + frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; + device_hwctx = frames_ctx->device_ctx->hwctx; + + s->hwctx = device_hwctx; + s->cu_stream = s->hwctx->stream; + if (inlink->sample_aspect_ratio.num) { outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w, outlink->w*inlink->h}, diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c index 9e55fe699..0c3898768 100644 --- a/libavfilter/vf_scale_npp.c +++ b/libavfilter/vf_scale_npp.c @@ -29,14 +29,15 @@ #include "libavutil/hwcontext_cuda_internal.h" #include "libavutil/cuda_check.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/eval.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "scale_eval.h" #include "video.h" @@ -535,6 +536,8 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig int out_width, int out_height) { NPPScaleContext *s = ctx->priv; + FilterLink *inl = ff_filter_link(ctx->inputs[0]); + FilterLink *outl = ff_filter_link(ctx->outputs[0]); AVHWFramesContext *in_frames_ctx; @@ -546,11 +549,11 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig int i, ret, last_stage = -1; /* check that we have a hw context */ - if (!ctx->inputs[0]->hw_frames_ctx) { + if (!inl->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n"); return AVERROR(EINVAL); } - in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; + in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; in_format = in_frames_ctx->sw_format; out_format = (s->format == AV_PIX_FMT_NONE) ? in_format : s->format; @@ -628,11 +631,11 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig } if (last_stage >= 0) - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx); + outl->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx); else - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(ctx->inputs[0]->hw_frames_ctx); + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); - if (!ctx->outputs[0]->hw_frames_ctx) + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); return 0; @@ -685,16 +688,18 @@ fail: static int config_props_ref(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterLink *inlink = outlink->src->inputs[1]; - AVFilterContext *ctx = outlink->src; + FilterLink *inl = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); outlink->w = inlink->w; outlink->h = inlink->h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->time_base = inlink->time_base; - outlink->frame_rate = inlink->frame_rate; + ol->frame_rate = inl->frame_rate; - ctx->outputs[1]->hw_frames_ctx = av_buffer_ref(ctx->inputs[1]->hw_frames_ctx); + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); return 0; } @@ -785,6 +790,7 @@ static int (*const nppscale_process[])(AVFilterContext *ctx, NPPScaleStageContex static int nppscale_scale(AVFilterLink *link, AVFrame *out, AVFrame *in) { + FilterLink *inl = ff_filter_link(link); AVFilterContext *ctx = link->dst; NPPScaleContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; @@ -834,7 +840,7 @@ static int nppscale_scale(AVFilterLink *link, AVFrame *out, AVFrame *in) } if (ctx->filter == &ff_vf_scale2ref_npp) { - s->var_values[VAR_S2R_MAIN_N] = link->frame_count_out; + s->var_values[VAR_S2R_MAIN_N] = inl->frame_count_out; s->var_values[VAR_S2R_MAIN_T] = TS2T(in->pts, link->time_base); #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS @@ -842,7 +848,7 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif } else { - s->var_values[VAR_N] = link->frame_count_out; + s->var_values[VAR_N] = inl->frame_count_out; s->var_values[VAR_T] = TS2T(in->pts, link->time_base); #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS @@ -899,7 +905,8 @@ static int nppscale_filter_frame(AVFilterLink *link, AVFrame *in) AVFilterContext *ctx = link->dst; NPPScaleContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)outlink->hw_frames_ctx->data; + FilterLink *l = ff_filter_link(outlink); + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)l->hw_frames_ctx->data; AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; AVFrame *out = NULL; @@ -940,6 +947,7 @@ fail: static int nppscale_filter_frame_ref(AVFilterLink *link, AVFrame *in) { + FilterLink *inl = ff_filter_link(link); NPPScaleContext *scale = link->dst->priv; AVFilterLink *outlink = link->dst->outputs[1]; int frame_changed; @@ -961,7 +969,7 @@ static int nppscale_filter_frame_ref(AVFilterLink *link, AVFrame *in) } if (scale->eval_mode == EVAL_MODE_FRAME) { - scale->var_values[VAR_N] = link->frame_count_out; + scale->var_values[VAR_N] = inl->frame_count_out; scale->var_values[VAR_T] = TS2T(in->pts, link->time_base); #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c index 5f20b8a43..41f119bb5 100644 --- a/libavfilter/vf_scale_vaapi.c +++ b/libavfilter/vf_scale_vaapi.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "scale_eval.h" #include "video.h" #include "vaapi_vpp.h" diff --git a/libavfilter/vf_scale_vt.c b/libavfilter/vf_scale_vt.c index af4a8b32c..05f4e7b79 100644 --- a/libavfilter/vf_scale_vt.c +++ b/libavfilter/vf_scale_vt.c @@ -24,7 +24,8 @@ #include "libavutil/hwcontext_videotoolbox.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "internal.h" + +#include "filters.h" #include "scale_eval.h" #include "video.h" @@ -174,9 +175,11 @@ fail: static int scale_vt_config_output(AVFilterLink *outlink) { int err; + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; ScaleVtContext *s = avctx->priv; AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); AVHWFramesContext *hw_frame_ctx_in; AVHWFramesContext *hw_frame_ctx_out; @@ -196,21 +199,22 @@ static int scale_vt_config_output(AVFilterLink *outlink) outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; } - hw_frame_ctx_in = (AVHWFramesContext *)inlink->hw_frames_ctx->data; + hw_frame_ctx_in = (AVHWFramesContext *)inl->hw_frames_ctx->data; - av_buffer_unref(&outlink->hw_frames_ctx); - outlink->hw_frames_ctx = av_hwframe_ctx_alloc(hw_frame_ctx_in->device_ref); - hw_frame_ctx_out = (AVHWFramesContext *)outlink->hw_frames_ctx->data; + av_buffer_unref(&outl->hw_frames_ctx); + outl->hw_frames_ctx = av_hwframe_ctx_alloc(hw_frame_ctx_in->device_ref); + hw_frame_ctx_out = (AVHWFramesContext *)outl->hw_frames_ctx->data; hw_frame_ctx_out->format = AV_PIX_FMT_VIDEOTOOLBOX; hw_frame_ctx_out->sw_format = hw_frame_ctx_in->sw_format; hw_frame_ctx_out->width = outlink->w; hw_frame_ctx_out->height = outlink->h; + ((AVVTFramesContext *)hw_frame_ctx_out->hwctx)->color_range = ((AVVTFramesContext *)hw_frame_ctx_in->hwctx)->color_range; err = ff_filter_init_hw_frames(avctx, outlink, 1); if (err < 0) return err; - err = av_hwframe_ctx_init(outlink->hw_frames_ctx); + err = av_hwframe_ctx_init(outl->hw_frames_ctx); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to init videotoolbox frame context, %s\n", diff --git a/libavfilter/vf_scale_vulkan.c b/libavfilter/vf_scale_vulkan.c index 7210509de..6a32ebbd5 100644 --- a/libavfilter/vf_scale_vulkan.c +++ b/libavfilter/vf_scale_vulkan.c @@ -23,7 +23,7 @@ #include "vulkan_filter.h" #include "vulkan_spirv.h" #include "scale_eval.h" -#include "internal.h" +#include "filters.h" #include "colorspace.h" #include "video.h" diff --git a/libavfilter/vf_scdet.c b/libavfilter/vf_scdet.c index 15399cfeb..705bdf977 100644 --- a/libavfilter/vf_scdet.c +++ b/libavfilter/vf_scdet.c @@ -53,8 +53,8 @@ typedef struct SCDetContext { static const AVOption scdet_options[] = { { "threshold", "set scene change detect threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 10.}, 0, 100., V|F }, { "t", "set scene change detect threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 10.}, 0, 100., V|F }, - { "sc_pass", "Set the flag to pass scene change frames", OFFSET(sc_pass), AV_OPT_TYPE_BOOL, {.dbl = 0 }, 0, 1, V|F }, - { "s", "Set the flag to pass scene change frames", OFFSET(sc_pass), AV_OPT_TYPE_BOOL, {.dbl = 0 }, 0, 1, V|F }, + { "sc_pass", "Set the flag to pass scene change frames", OFFSET(sc_pass), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, V|F }, + { "s", "Set the flag to pass scene change frames", OFFSET(sc_pass), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, V|F }, {NULL} }; diff --git a/libavfilter/vf_scroll.c b/libavfilter/vf_scroll.c index eebf12e90..c5646264f 100644 --- a/libavfilter/vf_scroll.c +++ b/libavfilter/vf_scroll.c @@ -22,7 +22,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ScrollContext { diff --git a/libavfilter/vf_selectivecolor.c b/libavfilter/vf_selectivecolor.c index eea79b781..fce9f67ac 100644 --- a/libavfilter/vf_selectivecolor.c +++ b/libavfilter/vf_selectivecolor.c @@ -32,7 +32,7 @@ #include "libavcodec/mathops.h" // for mid_pred(), which is a macro so no link dependency #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define R 0 diff --git a/libavfilter/vf_separatefields.c b/libavfilter/vf_separatefields.c index b7ddb2637..54c112bf6 100644 --- a/libavfilter/vf_separatefields.c +++ b/libavfilter/vf_separatefields.c @@ -21,7 +21,6 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" typedef struct SeparateFieldsContext { @@ -34,6 +33,8 @@ static int config_props_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; SeparateFieldsContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); s->nb_planes = av_pix_fmt_count_planes(inlink->format); @@ -44,8 +45,8 @@ static int config_props_output(AVFilterLink *outlink) outlink->time_base.num = inlink->time_base.num; outlink->time_base.den = inlink->time_base.den * 2; - outlink->frame_rate.num = inlink->frame_rate.num * 2; - outlink->frame_rate.den = inlink->frame_rate.den; + ol->frame_rate.num = il->frame_rate.num * 2; + ol->frame_rate.den = il->frame_rate.den; outlink->w = inlink->w; outlink->h = inlink->h / 2; diff --git a/libavfilter/vf_setparams.c b/libavfilter/vf_setparams.c index c96f4d314..14a16477c 100644 --- a/libavfilter/vf_setparams.c +++ b/libavfilter/vf_setparams.c @@ -23,8 +23,8 @@ #include "libavutil/pixfmt.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" enum SetFieldMode { @@ -41,6 +41,7 @@ typedef struct SetParamsContext { int color_primaries; int color_trc; int colorspace; + int chroma_location; } SetParamsContext; #define OFFSET(x) offsetof(SetParamsContext, x) @@ -48,10 +49,10 @@ typedef struct SetParamsContext { static const AVOption setparams_options[] = { {"field_mode", "select interlace mode", OFFSET(field_mode), AV_OPT_TYPE_INT, {.i64=MODE_AUTO}, -1, MODE_PROG, FLAGS, .unit = "mode"}, - {"auto", "keep the same input field", 0, AV_OPT_TYPE_CONST, {.i64=MODE_AUTO}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, - {"bff", "mark as bottom-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_BFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, - {"tff", "mark as top-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_TFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, - {"prog", "mark as progressive", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PROG}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, + {"auto", "keep the same input field", 0, AV_OPT_TYPE_CONST, {.i64=MODE_AUTO}, 0, 0, FLAGS, .unit = "mode"}, + {"bff", "mark as bottom-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_BFF}, 0, 0, FLAGS, .unit = "mode"}, + {"tff", "mark as top-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_TFF}, 0, 0, FLAGS, .unit = "mode"}, + {"prog", "mark as progressive", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PROG}, 0, 0, FLAGS, .unit = "mode"}, {"range", "select color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64=-1},-1, AVCOL_RANGE_NB-1, FLAGS, .unit = "range"}, {"auto", "keep the same color range", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, .unit = "range"}, @@ -65,57 +66,71 @@ static const AVOption setparams_options[] = { {"jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range"}, {"color_primaries", "select color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_PRI_NB-1, FLAGS, .unit = "color_primaries"}, - {"auto", "keep the same color primaries", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_UNSPECIFIED}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470M}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470BG}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE170M}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE240M}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"film", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_FILM}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"bt2020", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT2020}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE428}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"smpte431", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE431}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"smpte432", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE432}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"jedec-p22", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_JEDEC_P22}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, - {"ebu3213", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_EBU3213}, INT_MIN, INT_MAX, FLAGS, .unit = "color_primaries"}, + {"auto", "keep the same color primaries", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_UNSPECIFIED}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470M}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470BG}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE170M}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE240M}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"film", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_FILM}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"bt2020", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT2020}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE428}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"smpte431", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE431}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"smpte432", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE432}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"jedec-p22", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_JEDEC_P22}, 0, 0, FLAGS, .unit = "color_primaries"}, + {"ebu3213", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_EBU3213}, 0, 0, FLAGS, .unit = "color_primaries"}, {"color_trc", "select color transfer", OFFSET(color_trc), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_TRC_NB-1, FLAGS, .unit = "color_trc"}, - {"auto", "keep the same color transfer", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_UNSPECIFIED}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA22}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA28}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE170M}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE240M}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LINEAR}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"log100", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LOG}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"log316", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LOG_SQRT}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"iec61966-2-4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_4}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"bt1361e", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT1361_ECG}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"iec61966-2-1", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_1}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"bt2020-10", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_10}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"bt2020-12", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_12}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"smpte2084", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE2084}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE428}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, - {"arib-std-b67", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_ARIB_STD_B67}, INT_MIN, INT_MAX, FLAGS, .unit = "color_trc"}, + {"auto", "keep the same color transfer", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, .unit = "color_trc"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709}, 0, 0, FLAGS, .unit = "color_trc"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "color_trc"}, + {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA22}, 0, 0, FLAGS, .unit = "color_trc"}, + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA28}, 0, 0, FLAGS, .unit = "color_trc"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE170M}, 0, 0, FLAGS, .unit = "color_trc"}, + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE240M}, 0, 0, FLAGS, .unit = "color_trc"}, + {"linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LINEAR}, 0, 0, FLAGS, .unit = "color_trc"}, + {"log100", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LOG}, 0, 0, FLAGS, .unit = "color_trc"}, + {"log316", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LOG_SQRT}, 0, 0, FLAGS, .unit = "color_trc"}, + {"iec61966-2-4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_4}, 0, 0, FLAGS, .unit = "color_trc"}, + {"bt1361e", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT1361_ECG}, 0, 0, FLAGS, .unit = "color_trc"}, + {"iec61966-2-1", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_1}, 0, 0, FLAGS, .unit = "color_trc"}, + {"bt2020-10", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_10}, 0, 0, FLAGS, .unit = "color_trc"}, + {"bt2020-12", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_12}, 0, 0, FLAGS, .unit = "color_trc"}, + {"smpte2084", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE2084}, 0, 0, FLAGS, .unit = "color_trc"}, + {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE428}, 0, 0, FLAGS, .unit = "color_trc"}, + {"arib-std-b67", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_ARIB_STD_B67}, 0, 0, FLAGS, .unit = "color_trc"}, {"colorspace", "select colorspace", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_SPC_NB-1, FLAGS, .unit = "colorspace"}, - {"auto", "keep the same colorspace", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"gbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_RGB}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT709}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_UNSPECIFIED}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"fcc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_FCC}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT470BG}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE170M}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE240M}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"ycgco", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"bt2020nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"bt2020c", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_CL}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"smpte2085", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE2085}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"chroma-derived-nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_NCL},INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"chroma-derived-c", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_CL}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, - {"ictcp", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_ICTCP}, INT_MIN, INT_MAX, FLAGS, .unit = "colorspace"}, + {"auto", "keep the same colorspace", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, .unit = "colorspace"}, + {"gbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_RGB}, 0, 0, FLAGS, .unit = "colorspace"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT709}, 0, 0, FLAGS, .unit = "colorspace"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "colorspace"}, + {"fcc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_FCC}, 0, 0, FLAGS, .unit = "colorspace"}, + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT470BG}, 0, 0, FLAGS, .unit = "colorspace"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE170M}, 0, 0, FLAGS, .unit = "colorspace"}, + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE240M}, 0, 0, FLAGS, .unit = "colorspace"}, + {"ycgco", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO}, 0, 0, FLAGS, .unit = "colorspace"}, + {"ycgco-re", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO_RE}, 0, 0, FLAGS, .unit = "colorspace"}, + {"ycgco-ro", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO_RO}, 0, 0, FLAGS, .unit = "colorspace"}, + {"bt2020nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL}, 0, 0, FLAGS, .unit = "colorspace"}, + {"bt2020c", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_CL}, 0, 0, FLAGS, .unit = "colorspace"}, + {"smpte2085", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE2085}, 0, 0, FLAGS, .unit = "colorspace"}, + {"chroma-derived-nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_NCL},0, 0, FLAGS, .unit = "colorspace"}, + {"chroma-derived-c", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_CL}, 0, 0, FLAGS, .unit = "colorspace"}, + {"ictcp", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_ICTCP}, 0, 0, FLAGS, .unit = "colorspace"}, + {"ipt-c2", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_IPT_C2}, 0, 0, FLAGS, .unit = "colorspace"}, + + {"chroma_location", "select chroma sample location", OFFSET(chroma_location), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCHROMA_LOC_NB-1, FLAGS, .unit = "chroma_location"}, + {"auto", "keep the same chroma location", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, .unit = "chroma_location"}, + {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_location"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_location"}, + {"left", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_LEFT}, 0, 0, FLAGS, .unit = "chroma_location"}, + {"center", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_CENTER}, 0, 0, FLAGS, .unit = "chroma_location"}, + {"topleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOPLEFT}, 0, 0, FLAGS, .unit = "chroma_location"}, + {"top", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOP}, 0, 0, FLAGS, .unit = "chroma_location"}, + {"bottomleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOMLEFT}, 0, 0, FLAGS, .unit = "chroma_location"}, + {"bottom", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOM}, 0, 0, FLAGS, .unit = "chroma_location"}, {NULL} }; @@ -171,17 +186,18 @@ FF_ENABLE_DEPRECATION_WARNINGS frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST; } - /* set range */ + /* set straightforward parameters */ if (s->color_range >= 0) frame->color_range = s->color_range; - - /* set color prim, trc, space */ if (s->color_primaries >= 0) frame->color_primaries = s->color_primaries; if (s->color_trc >= 0) frame->color_trc = s->color_trc; if (s->colorspace >= 0) frame->colorspace = s->colorspace; + if (s->chroma_location >= 0) + frame->chroma_location = s->chroma_location; + return ff_filter_frame(ctx->outputs[0], frame); } @@ -249,10 +265,10 @@ const AVFilter ff_vf_setrange = { #if CONFIG_SETFIELD_FILTER static const AVOption setfield_options[] = { {"mode", "select interlace mode", OFFSET(field_mode), AV_OPT_TYPE_INT, {.i64=MODE_AUTO}, -1, MODE_PROG, FLAGS, .unit = "mode"}, - {"auto", "keep the same input field", 0, AV_OPT_TYPE_CONST, {.i64=MODE_AUTO}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, - {"bff", "mark as bottom-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_BFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, - {"tff", "mark as top-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_TFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, - {"prog", "mark as progressive", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PROG}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, + {"auto", "keep the same input field", 0, AV_OPT_TYPE_CONST, {.i64=MODE_AUTO}, 0, 0, FLAGS, .unit = "mode"}, + {"bff", "mark as bottom-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_BFF}, 0, 0, FLAGS, .unit = "mode"}, + {"tff", "mark as top-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_TFF}, 0, 0, FLAGS, .unit = "mode"}, + {"prog", "mark as progressive", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PROG}, 0, 0, FLAGS, .unit = "mode"}, {NULL} }; diff --git a/libavfilter/vf_sharpen_npp.c b/libavfilter/vf_sharpen_npp.c index 73c77dd5d..4989126ed 100644 --- a/libavfilter/vf_sharpen_npp.c +++ b/libavfilter/vf_sharpen_npp.c @@ -24,13 +24,14 @@ #include #include -#include "internal.h" +#include "filters.h" #include "libavutil/pixdesc.h" #include "libavutil/cuda_check.h" #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" #include "libavutil/opt.h" + #define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, device_hwctx->internal->cuda_dl, x) static const enum AVPixelFormat supported_formats[] = { @@ -70,16 +71,18 @@ fail: static int nppsharpen_config(AVFilterContext* ctx, int width, int height) { + FilterLink *inl = ff_filter_link(ctx->inputs[0]); + FilterLink *outl = ff_filter_link(ctx->outputs[0]); NPPSharpenContext* s = ctx->priv; AVHWFramesContext *out_ctx, *in_ctx; int i, ret, supported_format = 0; - if (!ctx->inputs[0]->hw_frames_ctx) { + if (!inl->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n"); goto fail; } - in_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; + in_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; s->frames_ctx = av_hwframe_ctx_alloc(in_ctx->device_ref); if (!s->frames_ctx) @@ -111,8 +114,8 @@ static int nppsharpen_config(AVFilterContext* ctx, int width, int height) if (ret < 0) goto fail; - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx); - if (!ctx->outputs[0]->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(s->frames_ctx); + if (!outl->hw_frames_ctx) goto fail; return 0; @@ -152,8 +155,8 @@ static int nppsharpen_config_props(AVFilterLink* outlink) static int nppsharpen_sharpen(AVFilterContext* ctx, AVFrame* out, AVFrame* in) { - AVHWFramesContext* in_ctx = - (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; + FilterLink *inl = ff_filter_link(ctx->inputs[0]); + AVHWFramesContext* in_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; NPPSharpenContext* s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(in_ctx->sw_format); @@ -179,8 +182,9 @@ static int nppsharpen_filter_frame(AVFilterLink* link, AVFrame* in) AVFilterContext* ctx = link->dst; NPPSharpenContext* s = ctx->priv; AVFilterLink* outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); AVHWFramesContext* frames_ctx = - (AVHWFramesContext*)outlink->hw_frames_ctx->data; + (AVHWFramesContext*)outl->hw_frames_ctx->data; AVCUDADeviceContext* device_hwctx = frames_ctx->device_ctx->hwctx; AVFrame* out = NULL; diff --git a/libavfilter/vf_shear.c b/libavfilter/vf_shear.c index 5008db3f4..067d38286 100644 --- a/libavfilter/vf_shear.c +++ b/libavfilter/vf_shear.c @@ -26,7 +26,7 @@ #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c index 28d8ea76e..1c9cf6c6a 100644 --- a/libavfilter/vf_showinfo.c +++ b/libavfilter/vf_showinfo.c @@ -47,7 +47,7 @@ #include "libavutil/uuid.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ShowInfoContext { @@ -73,27 +73,15 @@ static void dump_spherical(AVFilterContext *ctx, AVFrame *frame, const AVFrameSi const AVSphericalMapping *spherical = (const AVSphericalMapping *)sd->data; double yaw, pitch, roll; - if (sd->size < sizeof(*spherical)) { - av_log(ctx, AV_LOG_ERROR, "invalid data\n"); - return; - } + av_log(ctx, AV_LOG_INFO, "%s ", av_spherical_projection_name(spherical->projection)); - if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR) - av_log(ctx, AV_LOG_INFO, "equirectangular "); - else if (spherical->projection == AV_SPHERICAL_CUBEMAP) - av_log(ctx, AV_LOG_INFO, "cubemap "); - else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) - av_log(ctx, AV_LOG_INFO, "tiled equirectangular "); - else { - av_log(ctx, AV_LOG_WARNING, "unknown\n"); - return; + if (spherical->yaw || spherical->pitch || spherical->roll) { + yaw = ((double)spherical->yaw) / (1 << 16); + pitch = ((double)spherical->pitch) / (1 << 16); + roll = ((double)spherical->roll) / (1 << 16); + av_log(ctx, AV_LOG_INFO, "(%f/%f/%f) ", yaw, pitch, roll); } - yaw = ((double)spherical->yaw) / (1 << 16); - pitch = ((double)spherical->pitch) / (1 << 16); - roll = ((double)spherical->roll) / (1 << 16); - av_log(ctx, AV_LOG_INFO, "(%f/%f/%f) ", yaw, pitch, roll); - if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) { size_t l, t, r, b; av_spherical_tile_bounds(spherical, frame->width, frame->height, @@ -108,23 +96,27 @@ static void dump_spherical(AVFilterContext *ctx, AVFrame *frame, const AVFrameSi static void dump_stereo3d(AVFilterContext *ctx, const AVFrameSideData *sd) { - const AVStereo3D *stereo; - - if (sd->size < sizeof(*stereo)) { - av_log(ctx, AV_LOG_ERROR, "invalid data\n"); - return; - } - - stereo = (const AVStereo3D *)sd->data; + const AVStereo3D *stereo = (const AVStereo3D *)sd->data; av_log(ctx, AV_LOG_INFO, "type - %s", av_stereo3d_type_name(stereo->type)); if (stereo->flags & AV_STEREO3D_FLAG_INVERT) av_log(ctx, AV_LOG_INFO, " (inverted)"); + + av_log(ctx, AV_LOG_INFO, ", view - %s, primary_eye - %s", av_stereo3d_view_name(stereo->view), + av_stereo3d_primary_eye_name(stereo->primary_eye)); + if (stereo->baseline) + av_log(ctx, AV_LOG_INFO, ", baseline: %"PRIu32"", stereo->baseline); + if (stereo->horizontal_disparity_adjustment.num && stereo->horizontal_disparity_adjustment.den) + av_log(ctx, AV_LOG_INFO, ", horizontal_disparity_adjustment: %0.4f", + av_q2d(stereo->horizontal_disparity_adjustment)); + if (stereo->horizontal_field_of_view.num && stereo->horizontal_field_of_view.den) + av_log(ctx, AV_LOG_INFO, ", horizontal_field_of_view: %0.3f", av_q2d(stereo->horizontal_field_of_view)); } -static void dump_s12m_timecode(AVFilterContext *ctx, AVRational frame_rate, const AVFrameSideData *sd) +static void dump_s12m_timecode(AVFilterContext *ctx, AVFilterLink *inlink, const AVFrameSideData *sd) { + FilterLink *l = ff_filter_link(inlink); const uint32_t *tc = (const uint32_t *)sd->data; if ((sd->size != sizeof(uint32_t) * 4) || (tc[0] > 3)) { @@ -134,7 +126,7 @@ static void dump_s12m_timecode(AVFilterContext *ctx, AVRational frame_rate, cons for (int j = 1; j <= tc[0]; j++) { char tcbuf[AV_TIMECODE_STR_SIZE]; - av_timecode_make_smpte_tc_string2(tcbuf, frame_rate, tc[j], 0, 0); + av_timecode_make_smpte_tc_string2(tcbuf, l->frame_rate, tc[j], 0, 0); av_log(ctx, AV_LOG_INFO, "timecode - %s%s", tcbuf, j != tc[0] ? ", " : ""); } } @@ -735,6 +727,7 @@ static void update_sample_stats(int depth, int be, const uint8_t *src, int len, static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; ShowInfoContext *s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); @@ -768,7 +761,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) "n:%4"PRId64" pts:%7s pts_time:%-7s duration:%7"PRId64 " duration_time:%-7s " "fmt:%s cl:%s sar:%d/%d s:%dx%d i:%c iskey:%d type:%c ", - inlink->frame_count_out, + inl->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base), frame->duration, av_ts2timestr(frame->duration, &inlink->time_base), desc->name, av_chroma_location_name(frame->chroma_location), @@ -815,7 +808,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) dump_stereo3d(ctx, sd); break; case AV_FRAME_DATA_S12M_TIMECODE: { - dump_s12m_timecode(ctx, inlink->frame_rate, sd); + dump_s12m_timecode(ctx, inlink, sd); break; } case AV_FRAME_DATA_DISPLAYMATRIX: @@ -864,6 +857,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) case AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT: dump_ambient_viewing_environment(ctx, sd); break; + case AV_FRAME_DATA_VIEW_ID: + av_log(ctx, AV_LOG_INFO, "view id: %d\n", *(int*)sd->data); + break; default: if (name) av_log(ctx, AV_LOG_INFO, @@ -884,11 +880,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) static int config_props(AVFilterContext *ctx, AVFilterLink *link, int is_out) { + FilterLink *l = ff_filter_link(link); av_log(ctx, AV_LOG_INFO, "config %s time_base: %d/%d, frame_rate: %d/%d\n", is_out ? "out" : "in", link->time_base.num, link->time_base.den, - link->frame_rate.num, link->frame_rate.den); + l->frame_rate.num, l->frame_rate.den); return 0; } diff --git a/libavfilter/vf_showpalette.c b/libavfilter/vf_showpalette.c index 0405bdb94..e887d0709 100644 --- a/libavfilter/vf_showpalette.c +++ b/libavfilter/vf_showpalette.c @@ -23,8 +23,8 @@ #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct ShowPaletteContext { diff --git a/libavfilter/vf_shuffleframes.c b/libavfilter/vf_shuffleframes.c index cf8f197e2..77ce6d975 100644 --- a/libavfilter/vf_shuffleframes.c +++ b/libavfilter/vf_shuffleframes.c @@ -21,10 +21,11 @@ #include "libavutil/avstring.h" #include "libavutil/common.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ShuffleFramesContext { diff --git a/libavfilter/vf_shufflepixels.c b/libavfilter/vf_shufflepixels.c index d3e1af087..875601a98 100644 --- a/libavfilter/vf_shufflepixels.c +++ b/libavfilter/vf_shufflepixels.c @@ -19,17 +19,17 @@ */ #include "libavutil/avassert.h" -#include "libavutil/avstring.h" #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/imgutils.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/random_seed.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct ShufflePixelsContext { diff --git a/libavfilter/vf_shuffleplanes.c b/libavfilter/vf_shuffleplanes.c index fb2f85cf5..c9cbd472e 100644 --- a/libavfilter/vf_shuffleplanes.c +++ b/libavfilter/vf_shuffleplanes.c @@ -24,8 +24,8 @@ #include "libavutil/pixfmt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct ShufflePlanesContext { diff --git a/libavfilter/vf_signalstats.c b/libavfilter/vf_signalstats.c index 49bd9aa50..8dca3cb44 100644 --- a/libavfilter/vf_signalstats.c +++ b/libavfilter/vf_signalstats.c @@ -21,10 +21,10 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "filters.h" -#include "internal.h" enum FilterMode { FILTER_NONE = -1, @@ -537,244 +537,12 @@ static unsigned compute_bit_depth(uint16_t mask) return av_popcount(mask); } -static int filter_frame8(AVFilterLink *link, AVFrame *in) +static int filter_frame(AVFilterLink *link, AVFrame *in) { AVFilterContext *ctx = link->dst; SignalstatsContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out = in; - int i, j; - int w = 0, cw = 0, // in - pw = 0, cpw = 0; // prev - int fil; - char metabuf[128]; - unsigned int *histy = s->histy, - *histu = s->histu, - *histv = s->histv, - histhue[360] = {0}, - *histsat = s->histsat; - int miny = -1, minu = -1, minv = -1; - int maxy = -1, maxu = -1, maxv = -1; - int lowy = -1, lowu = -1, lowv = -1; - int highy = -1, highu = -1, highv = -1; - int minsat = -1, maxsat = -1, lowsat = -1, highsat = -1; - int lowp, highp, clowp, chighp; - int accy, accu, accv; - int accsat, acchue = 0; - int medhue, maxhue; - int toty = 0, totu = 0, totv = 0, totsat=0; - int tothue = 0; - int dify = 0, difu = 0, difv = 0; - uint16_t masky = 0, masku = 0, maskv = 0; - int ret; - int filtot[FILT_NUMB] = {0}; - AVFrame *prev; - - AVFrame *sat = s->frame_sat; - AVFrame *hue = s->frame_hue; - const uint8_t *p_sat = sat->data[0]; - const uint8_t *p_hue = hue->data[0]; - const int lsz_sat = sat->linesize[0]; - const int lsz_hue = hue->linesize[0]; - ThreadDataHueSatMetrics td_huesat = { - .src = in, - .dst_sat = sat, - .dst_hue = hue, - }; - - if (!s->frame_prev) - s->frame_prev = av_frame_clone(in); - - prev = s->frame_prev; - - if (s->outfilter != FILTER_NONE) { - out = av_frame_clone(in); - if (!out) { - av_frame_free(&in); - return AVERROR(ENOMEM); - } - ret = ff_inlink_make_frame_writable(link, &out); - if (ret < 0) { - av_frame_free(&out); - av_frame_free(&in); - return ret; - } - } - - ff_filter_execute(ctx, compute_sat_hue_metrics8, &td_huesat, - NULL, FFMIN(s->chromah, ff_filter_get_nb_threads(ctx))); - - // Calculate luma histogram and difference with previous frame or field. - memset(s->histy, 0, s->maxsize * sizeof(*s->histy)); - for (j = 0; j < link->h; j++) { - for (i = 0; i < link->w; i++) { - const int yuv = in->data[0][w + i]; - - masky |= yuv; - histy[yuv]++; - dify += abs(yuv - prev->data[0][pw + i]); - } - w += in->linesize[0]; - pw += prev->linesize[0]; - } - - // Calculate chroma histogram and difference with previous frame or field. - memset(s->histu, 0, s->maxsize * sizeof(*s->histu)); - memset(s->histv, 0, s->maxsize * sizeof(*s->histv)); - memset(s->histsat, 0, s->maxsize * sizeof(*s->histsat)); - for (j = 0; j < s->chromah; j++) { - for (i = 0; i < s->chromaw; i++) { - const int yuvu = in->data[1][cw+i]; - const int yuvv = in->data[2][cw+i]; - - masku |= yuvu; - maskv |= yuvv; - histu[yuvu]++; - difu += abs(yuvu - prev->data[1][cpw+i]); - histv[yuvv]++; - difv += abs(yuvv - prev->data[2][cpw+i]); - - histsat[p_sat[i]]++; - histhue[((int16_t*)p_hue)[i]]++; - } - cw += in->linesize[1]; - cpw += prev->linesize[1]; - p_sat += lsz_sat; - p_hue += lsz_hue; - } - - for (fil = 0; fil < FILT_NUMB; fil ++) { - if (s->filters & 1<outfilter == fil ? out : NULL, - }; - memset(s->jobs_rets, 0, s->nb_jobs * sizeof(*s->jobs_rets)); - ff_filter_execute(ctx, filters_def[fil].process8, - &td, s->jobs_rets, s->nb_jobs); - for (i = 0; i < s->nb_jobs; i++) - filtot[fil] += s->jobs_rets[i]; - } - } - - // find low / high based on histogram percentile - // these only need to be calculated once. - - lowp = lrint(s->fs * 10 / 100.); - highp = lrint(s->fs * 90 / 100.); - clowp = lrint(s->cfs * 10 / 100.); - chighp = lrint(s->cfs * 90 / 100.); - - accy = accu = accv = accsat = 0; - for (fil = 0; fil < s->maxsize; fil++) { - if (miny < 0 && histy[fil]) miny = fil; - if (minu < 0 && histu[fil]) minu = fil; - if (minv < 0 && histv[fil]) minv = fil; - if (minsat < 0 && histsat[fil]) minsat = fil; - - if (histy[fil]) maxy = fil; - if (histu[fil]) maxu = fil; - if (histv[fil]) maxv = fil; - if (histsat[fil]) maxsat = fil; - - toty += histy[fil] * fil; - totu += histu[fil] * fil; - totv += histv[fil] * fil; - totsat += histsat[fil] * fil; - - accy += histy[fil]; - accu += histu[fil]; - accv += histv[fil]; - accsat += histsat[fil]; - - if (lowy == -1 && accy >= lowp) lowy = fil; - if (lowu == -1 && accu >= clowp) lowu = fil; - if (lowv == -1 && accv >= clowp) lowv = fil; - if (lowsat == -1 && accsat >= clowp) lowsat = fil; - - if (highy == -1 && accy >= highp) highy = fil; - if (highu == -1 && accu >= chighp) highu = fil; - if (highv == -1 && accv >= chighp) highv = fil; - if (highsat == -1 && accsat >= chighp) highsat = fil; - } - - maxhue = histhue[0]; - medhue = -1; - for (fil = 0; fil < 360; fil++) { - tothue += histhue[fil] * fil; - acchue += histhue[fil]; - - if (medhue == -1 && acchue > s->cfs / 2) - medhue = fil; - if (histhue[fil] > maxhue) { - maxhue = histhue[fil]; - } - } - - av_frame_free(&s->frame_prev); - s->frame_prev = av_frame_clone(in); - -#define SET_META(key, fmt, val) do { \ - snprintf(metabuf, sizeof(metabuf), fmt, val); \ - av_dict_set(&out->metadata, "lavfi.signalstats." key, metabuf, 0); \ -} while (0) - - SET_META("YMIN", "%d", miny); - SET_META("YLOW", "%d", lowy); - SET_META("YAVG", "%g", 1.0 * toty / s->fs); - SET_META("YHIGH", "%d", highy); - SET_META("YMAX", "%d", maxy); - - SET_META("UMIN", "%d", minu); - SET_META("ULOW", "%d", lowu); - SET_META("UAVG", "%g", 1.0 * totu / s->cfs); - SET_META("UHIGH", "%d", highu); - SET_META("UMAX", "%d", maxu); - - SET_META("VMIN", "%d", minv); - SET_META("VLOW", "%d", lowv); - SET_META("VAVG", "%g", 1.0 * totv / s->cfs); - SET_META("VHIGH", "%d", highv); - SET_META("VMAX", "%d", maxv); - - SET_META("SATMIN", "%d", minsat); - SET_META("SATLOW", "%d", lowsat); - SET_META("SATAVG", "%g", 1.0 * totsat / s->cfs); - SET_META("SATHIGH", "%d", highsat); - SET_META("SATMAX", "%d", maxsat); - - SET_META("HUEMED", "%d", medhue); - SET_META("HUEAVG", "%g", 1.0 * tothue / s->cfs); - - SET_META("YDIF", "%g", 1.0 * dify / s->fs); - SET_META("UDIF", "%g", 1.0 * difu / s->cfs); - SET_META("VDIF", "%g", 1.0 * difv / s->cfs); - - SET_META("YBITDEPTH", "%d", compute_bit_depth(masky)); - SET_META("UBITDEPTH", "%d", compute_bit_depth(masku)); - SET_META("VBITDEPTH", "%d", compute_bit_depth(maskv)); - - for (fil = 0; fil < FILT_NUMB; fil ++) { - if (s->filters & 1<fs); - snprintf(metaname, sizeof(metaname), "lavfi.signalstats.%s", filters_def[fil].name); - av_dict_set(&out->metadata, metaname, metabuf, 0); - } - } - - if (in != out) - av_frame_free(&in); - return ff_filter_frame(outlink, out); -} - -static int filter_frame16(AVFilterLink *link, AVFrame *in) -{ - AVFilterContext *ctx = link->dst; - SignalstatsContext *s = ctx->priv; - AVFilterLink *outlink = ctx->outputs[0]; - AVFrame *out = in; - int i, j; int w = 0, cw = 0, // in pw = 0, cpw = 0; // prev int fil; @@ -803,10 +571,7 @@ static int filter_frame16(AVFilterLink *link, AVFrame *in) int ret; AVFrame *sat = s->frame_sat; AVFrame *hue = s->frame_hue; - const uint16_t *p_sat = (uint16_t *)sat->data[0]; - const uint16_t *p_hue = (uint16_t *)hue->data[0]; - const int lsz_sat = sat->linesize[0] / 2; - const int lsz_hue = hue->linesize[0] / 2; + const int hbd = s->depth > 8; ThreadDataHueSatMetrics td_huesat = { .src = in, .dst_sat = sat, @@ -832,46 +597,93 @@ static int filter_frame16(AVFilterLink *link, AVFrame *in) } } - ff_filter_execute(ctx, compute_sat_hue_metrics16, &td_huesat, + ff_filter_execute(ctx, hbd ? compute_sat_hue_metrics16 + : compute_sat_hue_metrics8, &td_huesat, NULL, FFMIN(s->chromah, ff_filter_get_nb_threads(ctx))); - // Calculate luma histogram and difference with previous frame or field. memset(s->histy, 0, s->maxsize * sizeof(*s->histy)); - for (j = 0; j < link->h; j++) { - for (i = 0; i < link->w; i++) { - const int yuv = AV_RN16(in->data[0] + w + i * 2); - - masky |= yuv; - histy[yuv]++; - dify += abs(yuv - (int)AV_RN16(prev->data[0] + pw + i * 2)); - } - w += in->linesize[0]; - pw += prev->linesize[0]; - } - - // Calculate chroma histogram and difference with previous frame or field. memset(s->histu, 0, s->maxsize * sizeof(*s->histu)); memset(s->histv, 0, s->maxsize * sizeof(*s->histv)); memset(s->histsat, 0, s->maxsize * sizeof(*s->histsat)); - for (j = 0; j < s->chromah; j++) { - for (i = 0; i < s->chromaw; i++) { - const int yuvu = AV_RN16(in->data[1] + cw + i * 2); - const int yuvv = AV_RN16(in->data[2] + cw + i * 2); - masku |= yuvu; - maskv |= yuvv; - histu[yuvu]++; - difu += abs(yuvu - (int)AV_RN16(prev->data[1] + cpw + i * 2)); - histv[yuvv]++; - difv += abs(yuvv - (int)AV_RN16(prev->data[2] + cpw + i * 2)); + if (hbd) { + const uint16_t *p_sat = (uint16_t *)sat->data[0]; + const uint16_t *p_hue = (uint16_t *)hue->data[0]; + const int lsz_sat = sat->linesize[0] / 2; + const int lsz_hue = hue->linesize[0] / 2; + // Calculate luma histogram and difference with previous frame or field. + for (int j = 0; j < link->h; j++) { + for (int i = 0; i < link->w; i++) { + const int yuv = AV_RN16(in->data[0] + w + i * 2); - histsat[p_sat[i]]++; - histhue[((int16_t*)p_hue)[i]]++; + masky |= yuv; + histy[yuv]++; + dify += abs(yuv - (int)AV_RN16(prev->data[0] + pw + i * 2)); + } + w += in->linesize[0]; + pw += prev->linesize[0]; + } + + // Calculate chroma histogram and difference with previous frame or field. + for (int j = 0; j < s->chromah; j++) { + for (int i = 0; i < s->chromaw; i++) { + const int yuvu = AV_RN16(in->data[1] + cw + i * 2); + const int yuvv = AV_RN16(in->data[2] + cw + i * 2); + + masku |= yuvu; + maskv |= yuvv; + histu[yuvu]++; + difu += abs(yuvu - (int)AV_RN16(prev->data[1] + cpw + i * 2)); + histv[yuvv]++; + difv += abs(yuvv - (int)AV_RN16(prev->data[2] + cpw + i * 2)); + + histsat[p_sat[i]]++; + histhue[((int16_t*)p_hue)[i]]++; + } + cw += in->linesize[1]; + cpw += prev->linesize[1]; + p_sat += lsz_sat; + p_hue += lsz_hue; + } + } else { + const uint8_t *p_sat = sat->data[0]; + const uint8_t *p_hue = hue->data[0]; + const int lsz_sat = sat->linesize[0]; + const int lsz_hue = hue->linesize[0]; + // Calculate luma histogram and difference with previous frame or field. + for (int j = 0; j < link->h; j++) { + for (int i = 0; i < link->w; i++) { + const int yuv = in->data[0][w + i]; + + masky |= yuv; + histy[yuv]++; + dify += abs(yuv - prev->data[0][pw + i]); + } + w += in->linesize[0]; + pw += prev->linesize[0]; + } + + // Calculate chroma histogram and difference with previous frame or field. + for (int j = 0; j < s->chromah; j++) { + for (int i = 0; i < s->chromaw; i++) { + const int yuvu = in->data[1][cw+i]; + const int yuvv = in->data[2][cw+i]; + + masku |= yuvu; + maskv |= yuvv; + histu[yuvu]++; + difu += abs(yuvu - prev->data[1][cpw+i]); + histv[yuvv]++; + difv += abs(yuvv - prev->data[2][cpw+i]); + + histsat[p_sat[i]]++; + histhue[((int16_t*)p_hue)[i]]++; + } + cw += in->linesize[1]; + cpw += prev->linesize[1]; + p_sat += lsz_sat; + p_hue += lsz_hue; } - cw += in->linesize[1]; - cpw += prev->linesize[1]; - p_sat += lsz_sat; - p_hue += lsz_hue; } for (fil = 0; fil < FILT_NUMB; fil ++) { @@ -881,9 +693,9 @@ static int filter_frame16(AVFilterLink *link, AVFrame *in) .out = out != in && s->outfilter == fil ? out : NULL, }; memset(s->jobs_rets, 0, s->nb_jobs * sizeof(*s->jobs_rets)); - ff_filter_execute(ctx, filters_def[fil].process16, + ff_filter_execute(ctx, hbd ? filters_def[fil].process16 : filters_def[fil].process8, &td, s->jobs_rets, s->nb_jobs); - for (i = 0; i < s->nb_jobs; i++) + for (int i = 0; i < s->nb_jobs; i++) filtot[fil] += s->jobs_rets[i]; } } @@ -908,10 +720,10 @@ static int filter_frame16(AVFilterLink *link, AVFrame *in) if (histv[fil]) maxv = fil; if (histsat[fil]) maxsat = fil; - toty += histy[fil] * fil; - totu += histu[fil] * fil; - totv += histv[fil] * fil; - totsat += histsat[fil] * fil; + toty += (uint64_t)histy[fil] * fil; + totu += (uint64_t)histu[fil] * fil; + totv += (uint64_t)histv[fil] * fil; + totsat += (uint64_t)histsat[fil] * fil; accy += histy[fil]; accu += histu[fil]; @@ -932,7 +744,7 @@ static int filter_frame16(AVFilterLink *link, AVFrame *in) maxhue = histhue[0]; medhue = -1; for (fil = 0; fil < 360; fil++) { - tothue += histhue[fil] * fil; + tothue += (uint64_t)histhue[fil] * fil; acchue += histhue[fil]; if (medhue == -1 && acchue > s->cfs / 2) @@ -945,40 +757,45 @@ static int filter_frame16(AVFilterLink *link, AVFrame *in) av_frame_free(&s->frame_prev); s->frame_prev = av_frame_clone(in); - SET_META("YMIN", "%d", miny); - SET_META("YLOW", "%d", lowy); +#define SET_META(key, fmt, val) do { \ + snprintf(metabuf, sizeof(metabuf), fmt, val); \ + av_dict_set(&out->metadata, "lavfi.signalstats." key, metabuf, 0); \ +} while (0) + + av_dict_set_int(&out->metadata, "lavfi.signalstats.YMIN", miny, 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.YLOW", lowy, 0); SET_META("YAVG", "%g", 1.0 * toty / s->fs); - SET_META("YHIGH", "%d", highy); - SET_META("YMAX", "%d", maxy); + av_dict_set_int(&out->metadata, "lavfi.signalstats.YHIGH", highy, 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.YMAX", maxy, 0); - SET_META("UMIN", "%d", minu); - SET_META("ULOW", "%d", lowu); + av_dict_set_int(&out->metadata, "lavfi.signalstats.UMIN", minu, 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.ULOW", lowu, 0); SET_META("UAVG", "%g", 1.0 * totu / s->cfs); - SET_META("UHIGH", "%d", highu); - SET_META("UMAX", "%d", maxu); + av_dict_set_int(&out->metadata, "lavfi.signalstats.UHIGH", highu, 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.UMAX", maxu, 0); - SET_META("VMIN", "%d", minv); - SET_META("VLOW", "%d", lowv); + av_dict_set_int(&out->metadata, "lavfi.signalstats.VMIN", minv, 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.VLOW", lowv, 0); SET_META("VAVG", "%g", 1.0 * totv / s->cfs); - SET_META("VHIGH", "%d", highv); - SET_META("VMAX", "%d", maxv); + av_dict_set_int(&out->metadata, "lavfi.signalstats.VHIGH", highv, 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.VMAX", maxv, 0); - SET_META("SATMIN", "%d", minsat); - SET_META("SATLOW", "%d", lowsat); + av_dict_set_int(&out->metadata, "lavfi.signalstats.SATMIN", minsat, 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.SATLOW", lowsat, 0); SET_META("SATAVG", "%g", 1.0 * totsat / s->cfs); - SET_META("SATHIGH", "%d", highsat); - SET_META("SATMAX", "%d", maxsat); + av_dict_set_int(&out->metadata, "lavfi.signalstats.SATHIGH", highsat, 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.SATMAX", maxsat, 0); - SET_META("HUEMED", "%d", medhue); + av_dict_set_int(&out->metadata, "lavfi.signalstats.HUEMED", medhue, 0); SET_META("HUEAVG", "%g", 1.0 * tothue / s->cfs); SET_META("YDIF", "%g", 1.0 * dify / s->fs); SET_META("UDIF", "%g", 1.0 * difu / s->cfs); SET_META("VDIF", "%g", 1.0 * difv / s->cfs); - SET_META("YBITDEPTH", "%d", compute_bit_depth(masky)); - SET_META("UBITDEPTH", "%d", compute_bit_depth(masku)); - SET_META("VBITDEPTH", "%d", compute_bit_depth(maskv)); + av_dict_set_int(&out->metadata, "lavfi.signalstats.YBITDEPTH", compute_bit_depth(masky), 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.UBITDEPTH", compute_bit_depth(masku), 0); + av_dict_set_int(&out->metadata, "lavfi.signalstats.VBITDEPTH", compute_bit_depth(maskv), 0); for (fil = 0; fil < FILT_NUMB; fil ++) { if (s->filters & 1<dst; - SignalstatsContext *s = ctx->priv; - - if (s->depth > 8) - return filter_frame16(link, in); - else - return filter_frame8(link, in); -} - static const AVFilterPad signalstats_inputs[] = { { .name = "default", diff --git a/libavfilter/vf_signature.c b/libavfilter/vf_signature.c index 3858fe307..f419522ac 100644 --- a/libavfilter/vf_signature.c +++ b/libavfilter/vf_signature.c @@ -26,11 +26,12 @@ #include "libavcodec/put_bits.h" #include "libavformat/avformat.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/avstring.h" #include "libavutil/file_open.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "signature.h" #include "signature_lookup.c" @@ -385,9 +386,7 @@ static int xml_export(AVFilterContext *ctx, StreamContext *sc, const char* filen f = avpriv_fopen_utf8(filename, "w"); if (!f) { int err = AVERROR(EINVAL); - char buf[128]; - av_strerror(err, buf, sizeof(buf)); - av_log(ctx, AV_LOG_ERROR, "cannot open xml file %s: %s\n", filename, buf); + av_log(ctx, AV_LOG_ERROR, "cannot open xml file %s: %s\n", filename, av_err2str(err)); return err; } @@ -499,9 +498,7 @@ static int binary_export(AVFilterContext *ctx, StreamContext *sc, const char* fi f = avpriv_fopen_utf8(filename, "wb"); if (!f) { int err = AVERROR(EINVAL); - char buf[128]; - av_strerror(err, buf, sizeof(buf)); - av_log(ctx, AV_LOG_ERROR, "cannot open file %s: %s\n", filename, buf); + av_log(ctx, AV_LOG_ERROR, "cannot open file %s: %s\n", filename, av_err2str(err)); av_freep(&buffer); return err; } @@ -725,9 +722,11 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); outlink->time_base = inlink->time_base; - outlink->frame_rate = inlink->frame_rate; + ol->frame_rate = il->frame_rate; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->w = inlink->w; outlink->h = inlink->h; diff --git a/libavfilter/vf_siti.c b/libavfilter/vf_siti.c index 1b6ff32d6..3c563ac8b 100644 --- a/libavfilter/vf_siti.c +++ b/libavfilter/vf_siti.c @@ -28,10 +28,11 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" static const int X_FILTER[9] = { diff --git a/libavfilter/vf_smartblur.c b/libavfilter/vf_smartblur.c index ae0ec05b2..fe1b591a4 100644 --- a/libavfilter/vf_smartblur.c +++ b/libavfilter/vf_smartblur.c @@ -30,7 +30,7 @@ #include "libswscale/swscale.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define RADIUS_MIN 0.1 @@ -54,6 +54,7 @@ typedef struct SmartblurContext { const AVClass *class; FilterParam luma; FilterParam chroma; + FilterParam alpha; int hsub; int vsub; unsigned int sws_flags; @@ -77,6 +78,13 @@ static const AVOption smartblur_options[] = { { "chroma_threshold", "set chroma threshold", OFFSET(chroma.threshold), AV_OPT_TYPE_INT, {.i64=THRESHOLD_MIN-1}, THRESHOLD_MIN-1, THRESHOLD_MAX, .flags=FLAGS }, { "ct", "set chroma threshold", OFFSET(chroma.threshold), AV_OPT_TYPE_INT, {.i64=THRESHOLD_MIN-1}, THRESHOLD_MIN-1, THRESHOLD_MAX, .flags=FLAGS }, + { "alpha_radius", "set alpha radius", OFFSET(alpha.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS }, + { "ar" , "set alpha radius", OFFSET(alpha.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS }, + { "alpha_strength", "set alpha strength", OFFSET(alpha.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS }, + { "as", "set alpha strength", OFFSET(alpha.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS }, + { "alpha_threshold", "set alpha threshold", OFFSET(alpha.threshold), AV_OPT_TYPE_INT, {.i64=THRESHOLD_MIN-1}, THRESHOLD_MIN-1, THRESHOLD_MAX, .flags=FLAGS }, + { "at", "set alpha threshold", OFFSET(alpha.threshold), AV_OPT_TYPE_INT, {.i64=THRESHOLD_MIN-1}, THRESHOLD_MIN-1, THRESHOLD_MAX, .flags=FLAGS }, + { NULL } }; @@ -94,15 +102,24 @@ static av_cold int init(AVFilterContext *ctx) if (s->chroma.threshold < THRESHOLD_MIN) s->chroma.threshold = s->luma.threshold; - s->luma.quality = s->chroma.quality = 3.0; + /* make alpha default to luma values, if not explicitly set */ + if (s->alpha.radius < RADIUS_MIN) + s->alpha.radius = s->luma.radius; + if (s->alpha.strength < STRENGTH_MIN) + s->alpha.strength = s->luma.strength; + if (s->alpha.threshold < THRESHOLD_MIN) + s->alpha.threshold = s->luma.threshold; + + s->luma.quality = s->chroma.quality = s->alpha.quality = 3.0; s->sws_flags = SWS_BICUBIC; av_log(ctx, AV_LOG_VERBOSE, "luma_radius:%f luma_strength:%f luma_threshold:%d " - "chroma_radius:%f chroma_strength:%f chroma_threshold:%d\n", + "chroma_radius:%f chroma_strength:%f chroma_threshold:%d " + "alpha_radius:%f alpha_strength:%f alpha_threshold:%d\n", s->luma.radius, s->luma.strength, s->luma.threshold, - s->chroma.radius, s->chroma.strength, s->chroma.threshold); - + s->chroma.radius, s->chroma.strength, s->chroma.threshold, + s->alpha.radius, s->alpha.strength, s->alpha.threshold); return 0; } @@ -112,13 +129,15 @@ static av_cold void uninit(AVFilterContext *ctx) sws_freeContext(s->luma.filter_context); sws_freeContext(s->chroma.filter_context); + sws_freeContext(s->alpha.filter_context); } static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, - AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, - AV_PIX_FMT_GRAY8, + AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, + AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUV440P, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; @@ -162,6 +181,7 @@ static int config_props(AVFilterLink *inlink) AV_CEIL_RSHIFT(inlink->w, s->hsub), AV_CEIL_RSHIFT(inlink->h, s->vsub), s->sws_flags); + alloc_sws_context(&s->alpha, inlink->w, inlink->h, s->sws_flags); return 0; } @@ -261,6 +281,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic) s->chroma.filter_context); } + if (inpic->data[3]) { + blur(outpic->data[3], outpic->linesize[3], + inpic->data[3], inpic->linesize[3], + inlink->w, inlink->h, s->alpha.threshold, + s->alpha.filter_context); + } + av_frame_free(&inpic); return ff_filter_frame(outlink, outpic); } diff --git a/libavfilter/vf_spp.c b/libavfilter/vf_spp.c index 5c6495612..0c33c263b 100644 --- a/libavfilter/vf_spp.c +++ b/libavfilter/vf_spp.c @@ -33,10 +33,12 @@ #include "libavutil/emms.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "internal.h" + +#include "filters.h" #include "qp_table.h" #include "vf_spp.h" #include "video.h" @@ -171,7 +173,7 @@ static void store_slice_c(uint8_t *dst, const int16_t *src, int y, x; #define STORE(pos) do { \ - temp = ((src[x + y*src_linesize + pos] << log2_scale) + d[pos]) >> 6; \ + temp = (src[x + y*src_linesize + pos] * (1 << log2_scale) + d[pos]) >> 6;\ if (temp & 0x100) \ temp = ~(temp >> 31); \ dst[x + y*dst_linesize + pos] = temp; \ @@ -202,7 +204,7 @@ static void store_slice16_c(uint16_t *dst, const int16_t *src, unsigned int mask = -1<>1)) >> 5; \ + temp = (src[x + y*src_linesize + pos] * (1 << log2_scale) + (d[pos]>>1)) >> 5; \ if (temp & mask ) \ temp = ~(temp >> 31); \ dst[x + y*dst_linesize + pos] = temp; \ diff --git a/libavfilter/vf_sr.c b/libavfilter/vf_sr.c index 60683b520..6c3320330 100644 --- a/libavfilter/vf_sr.c +++ b/libavfilter/vf_sr.c @@ -26,7 +26,7 @@ */ #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -50,13 +50,10 @@ static const AVOption sr_options[] = { { "tensorflow", "tensorflow backend flag", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, .unit = "backend" }, #endif { "scale_factor", "scale factor for SRCNN model", OFFSET(scale_factor), AV_OPT_TYPE_INT, { .i64 = 2 }, 2, 4, FLAGS }, - { "model", "path to model file specifying network architecture and its parameters", OFFSET(dnnctx.model_filename), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, - { "input", "input name of the model", OFFSET(dnnctx.model_inputname), AV_OPT_TYPE_STRING, { .str = "x" }, 0, 0, FLAGS }, - { "output", "output name of the model", OFFSET(dnnctx.model_outputnames_string), AV_OPT_TYPE_STRING, { .str = "y" }, 0, 0, FLAGS }, { NULL } }; -AVFILTER_DEFINE_CLASS(sr); +AVFILTER_DNN_DEFINE_CLASS(sr, DNN_TF); static av_cold int init(AVFilterContext *context) { @@ -192,6 +189,7 @@ const AVFilter ff_vf_sr = { .name = "sr", .description = NULL_IF_CONFIG_SMALL("Apply DNN-based image super resolution to the input."), .priv_size = sizeof(SRContext), + .preinit = ff_dnn_filter_init_child_class, .init = init, .uninit = uninit, FILTER_INPUTS(sr_inputs), diff --git a/libavfilter/vf_ssim.c b/libavfilter/vf_ssim.c index 53eb72fe6..52b22a687 100644 --- a/libavfilter/vf_ssim.c +++ b/libavfilter/vf_ssim.c @@ -36,12 +36,13 @@ #include "libavutil/avstring.h" #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "ssim.h" typedef struct SSIMContext { @@ -193,9 +194,8 @@ static float ssim_end1(int s1, int s2, int ss, int s12) static float ssim_endn_16bit(const int64_t (*sum0)[4], const int64_t (*sum1)[4], int width, int max) { float ssim = 0.0; - int i; - for (i = 0; i < width; i++) + for (int i = 0; i < width; i++) ssim += ssim_end1x(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0], sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1], sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2], @@ -207,9 +207,8 @@ static float ssim_endn_16bit(const int64_t (*sum0)[4], const int64_t (*sum1)[4], static double ssim_endn_8bit(const int (*sum0)[4], const int (*sum1)[4], int width) { double ssim = 0.0; - int i; - for (i = 0; i < width; i++) + for (int i = 0; i < width; i++) ssim += ssim_end1(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0], sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1], sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2], @@ -413,10 +412,8 @@ static av_cold int init(AVFilterContext *ctx) s->stats_file = avpriv_fopen_utf8(s->stats_file_str, "w"); if (!s->stats_file) { int err = AVERROR(errno); - char buf[128]; - av_strerror(err, buf, sizeof(buf)); av_log(ctx, AV_LOG_ERROR, "Could not open stats file %s: %s\n", - s->stats_file_str, buf); + s->stats_file_str, av_err2str(err)); return err; } } @@ -444,7 +441,7 @@ static int config_input_ref(AVFilterLink *inlink) const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); AVFilterContext *ctx = inlink->dst; SSIMContext *s = ctx->priv; - int sum = 0, i; + int sum = 0; s->nb_threads = ff_filter_get_nb_threads(ctx); s->nb_components = desc->nb_components; @@ -465,9 +462,9 @@ static int config_input_ref(AVFilterLink *inlink) s->planeheight[0] = s->planeheight[3] = inlink->h; s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); s->planewidth[0] = s->planewidth[3] = inlink->w; - for (i = 0; i < s->nb_components; i++) + for (int i = 0; i < s->nb_components; i++) sum += s->planeheight[i] * s->planewidth[i]; - for (i = 0; i < s->nb_components; i++) + for (int i = 0; i < s->nb_components; i++) s->coefs[i] = (double) s->planeheight[i] * s->planewidth[i] / sum; s->temp = av_calloc(s->nb_threads, sizeof(*s->temp)); @@ -506,6 +503,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; SSIMContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(mainlink); + FilterLink *ol = ff_filter_link(outlink); int ret; ret = ff_framesync_init_dualinput(&s->fs, ctx); @@ -515,7 +514,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_configure(&s->fs)) < 0) return ret; @@ -543,9 +542,8 @@ static av_cold void uninit(AVFilterContext *ctx) if (s->nb_frames > 0) { char buf[256]; - int i; buf[0] = 0; - for (i = 0; i < s->nb_components; i++) { + for (int i = 0; i < s->nb_components; i++) { int c = s->is_rgb ? s->rgba_map[i] : i; av_strlcatf(buf, sizeof(buf), " %c:%f (%f)", s->comps[i], s->ssim[c] / s->nb_frames, ssim_db(s->ssim[c], s->nb_frames)); diff --git a/libavfilter/vf_ssim360.c b/libavfilter/vf_ssim360.c index 0f5b11c72..42632bcd8 100644 --- a/libavfilter/vf_ssim360.c +++ b/libavfilter/vf_ssim360.c @@ -45,12 +45,13 @@ #include "libavutil/avstring.h" #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "framesync.h" #define RIGHT 0 @@ -1131,7 +1132,7 @@ static int do_ssim360(FFFrameSync *fs) AVFrame *master, *ref; AVDictionary **metadata; double c[4], ssim360v = 0.0, ssim360p50 = 0.0; - int i, ret; + int ret; int need_frame_skip = s->nb_net_frames % (s->frame_skip_ratio + 1); HeatmapList* h_ptr = NULL; @@ -1152,7 +1153,7 @@ static int do_ssim360(FFFrameSync *fs) return ret; } - for (i = 0; i < s->nb_components; i++) { + for (int i = 0; i < s->nb_components; i++) { if (s->use_tape) { c[i] = ssim360_tape(master->data[i], s->main_tape_map[i][0], ref->data[i], s->ref_tape_map [i][0], @@ -1190,16 +1191,16 @@ static int do_ssim360(FFFrameSync *fs) // Record percentiles from histogram and attach metadata when using tape if (s->use_tape) { - int i, p, hist_indices[4]; + int hist_indices[4]; double hist_weight[4]; - for (i = 0; i < s->nb_components; i++) { + for (int i = 0; i < s->nb_components; i++) { hist_indices[i] = SSIM360_HIST_SIZE - 1; hist_weight[i] = 0; } - for (p = 0; PERCENTILE_LIST[p] >= 0.0; p ++) { - for (i = 0; i < s->nb_components; i++) { + for (int p = 0; PERCENTILE_LIST[p] >= 0.0; p ++) { + for (int i = 0; i < s->nb_components; i++) { double target_weight, ssim360p; // Target weight = total number of samples above the specified percentile @@ -1217,12 +1218,12 @@ static int do_ssim360(FFFrameSync *fs) } } - for (i = 0; i < s->nb_components; i++) { + for (int i = 0; i < s->nb_components; i++) { memset(s->ssim360_hist[i], 0, SSIM360_HIST_SIZE * sizeof(double)); s->ssim360_hist_net[i] = 0; } - for (i = 0; i < s->nb_components; i++) { + for (int i = 0; i < s->nb_components; i++) { int cidx = s->is_rgb ? s->rgba_map[i] : i; set_meta(metadata, "lavfi.ssim360.", s->comps[i], c[cidx]); } @@ -1234,7 +1235,7 @@ static int do_ssim360(FFFrameSync *fs) if (s->stats_file) { fprintf(s->stats_file, "n:%"PRId64" ", s->nb_ssim_frames); - for (i = 0; i < s->nb_components; i++) { + for (int i = 0; i < s->nb_components; i++) { int cidx = s->is_rgb ? s->rgba_map[i] : i; fprintf(s->stats_file, "%c:%f ", s->comps[i], c[cidx]); } @@ -1319,12 +1320,9 @@ static av_cold int init(AVFilterContext *ctx) } else { s->stats_file = avpriv_fopen_utf8(s->stats_file_str, "w"); if (!s->stats_file) { - char buf[128]; - err = AVERROR(errno); - av_strerror(err, buf, sizeof(buf)); av_log(ctx, AV_LOG_ERROR, "Could not open stats file %s: %s\n", - s->stats_file_str, buf); + s->stats_file_str, av_err2str(err)); return err; } } @@ -1593,6 +1591,8 @@ static int config_output(AVFilterLink *outlink) SSIM360Context *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; AVFilterLink *reflink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(mainlink); + FilterLink *ol = ff_filter_link(outlink); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); int ret; @@ -1642,7 +1642,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + ol->frame_rate = il->frame_rate; s->fs.opt_shortest = 1; s->fs.opt_repeatlast = 1; diff --git a/libavfilter/vf_stack.c b/libavfilter/vf_stack.c index 2bb3d9b1d..832804864 100644 --- a/libavfilter/vf_stack.c +++ b/libavfilter/vf_stack.c @@ -22,14 +22,15 @@ #include "libavutil/avstring.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "framesync.h" #include "video.h" @@ -195,7 +196,9 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; StackContext *s = ctx->priv; - AVRational frame_rate = ctx->inputs[0]->frame_rate; + FilterLink *il = ff_filter_link(ctx->inputs[0]); + FilterLink *ol = ff_filter_link(outlink); + AVRational frame_rate = il->frame_rate; AVRational sar = ctx->inputs[0]->sample_aspect_ratio; int height = ctx->inputs[0]->h; int width = ctx->inputs[0]->w; @@ -382,16 +385,16 @@ static int config_output(AVFilterLink *outlink) outlink->w = width; outlink->h = height; - outlink->frame_rate = frame_rate; + ol->frame_rate = frame_rate; outlink->sample_aspect_ratio = sar; for (i = 1; i < s->nb_inputs; i++) { - AVFilterLink *inlink = ctx->inputs[i]; - if (outlink->frame_rate.num != inlink->frame_rate.num || - outlink->frame_rate.den != inlink->frame_rate.den) { + il = ff_filter_link(ctx->inputs[i]); + if (ol->frame_rate.num != il->frame_rate.num || + ol->frame_rate.den != il->frame_rate.den) { av_log(ctx, AV_LOG_VERBOSE, "Video inputs have different frame rates, output will be VFR\n"); - outlink->frame_rate = av_make_q(1, 0); + ol->frame_rate = av_make_q(1, 0); break; } } diff --git a/libavfilter/vf_stack_qsv.c b/libavfilter/vf_stack_qsv.c index 3e6aefe44..9c4ca4abd 100644 --- a/libavfilter/vf_stack_qsv.c +++ b/libavfilter/vf_stack_qsv.c @@ -23,6 +23,7 @@ #include "config_components.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/common.h" #include "libavutil/pixdesc.h" @@ -34,7 +35,6 @@ #include "libavutil/mathematics.h" #include "libavutil/parseutils.h" -#include "internal.h" #include "filters.h" #include "formats.h" #include "video.h" @@ -70,13 +70,16 @@ static int process_frame(FFFrameSync *fs) { AVFilterContext *ctx = fs->parent; QSVVPPContext *qsv = fs->opaque; - AVFrame *frame = NULL; + AVFrame *frame = NULL, *propref = NULL; int ret = 0; for (int i = 0; i < ctx->nb_inputs; i++) { ret = ff_framesync_get_frame(fs, i, &frame, 0); - if (ret == 0) - ret = ff_qsvvpp_filter_frame(qsv, ctx->inputs[i], frame); + if (ret == 0) { + if (i == 0) + propref = frame; + ret = ff_qsvvpp_filter_frame(qsv, ctx->inputs[i], frame, propref); + } if (ret < 0 && ret != AVERROR(EAGAIN)) break; } @@ -96,15 +99,16 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; StackQSVContext *sctx = ctx->priv; AVFilterLink *inlink0 = ctx->inputs[0]; + FilterLink *inl0 = ff_filter_link(inlink0); enum AVPixelFormat in_format; int depth = 8, ret; mfxVPPCompInputStream *is = sctx->comp_conf.InputStream; if (inlink0->format == AV_PIX_FMT_QSV) { - if (!inlink0->hw_frames_ctx || !inlink0->hw_frames_ctx->data) + if (!inl0->hw_frames_ctx || !inl0->hw_frames_ctx->data) return AVERROR(EINVAL); - in_format = ((AVHWFramesContext*)inlink0->hw_frames_ctx->data)->sw_format; + in_format = ((AVHWFramesContext*)inl0->hw_frames_ctx->data)->sw_format; } else in_format = inlink0->format; @@ -112,10 +116,11 @@ static int config_output(AVFilterLink *outlink) for (int i = 1; i < sctx->base.nb_inputs; i++) { AVFilterLink *inlink = ctx->inputs[i]; + FilterLink *inl = ff_filter_link(inlink); if (inlink0->format == AV_PIX_FMT_QSV) { - AVHWFramesContext *hwfc0 = (AVHWFramesContext *)inlink0->hw_frames_ctx->data; - AVHWFramesContext *hwfc = (AVHWFramesContext *)inlink->hw_frames_ctx->data; + AVHWFramesContext *hwfc0 = (AVHWFramesContext *)inl0->hw_frames_ctx->data; + AVHWFramesContext *hwfc = (AVHWFramesContext *)inl->hw_frames_ctx->data; if (inlink0->format != inlink->format) { av_log(ctx, AV_LOG_ERROR, "Mixing hardware and software pixel formats is not supported.\n"); diff --git a/libavfilter/vf_stack_vaapi.c b/libavfilter/vf_stack_vaapi.c index 8e9471e6d..602a7825a 100644 --- a/libavfilter/vf_stack_vaapi.c +++ b/libavfilter/vf_stack_vaapi.c @@ -35,7 +35,6 @@ #include "libavutil/parseutils.h" #include "libavutil/mem.h" -#include "internal.h" #include "filters.h" #include "formats.h" #include "video.h" @@ -137,26 +136,28 @@ static int config_output(AVFilterLink *outlink) StackVAAPIContext *sctx = avctx->priv; VAAPIVPPContext *vppctx = avctx->priv; AVFilterLink *inlink0 = avctx->inputs[0]; + FilterLink *inl0 = ff_filter_link(inlink0); AVHWFramesContext *hwfc0 = NULL; int ret; - if (inlink0->format != AV_PIX_FMT_VAAPI || !inlink0->hw_frames_ctx || !inlink0->hw_frames_ctx->data) { + if (inlink0->format != AV_PIX_FMT_VAAPI || !inl0->hw_frames_ctx || !inl0->hw_frames_ctx->data) { av_log(avctx, AV_LOG_ERROR, "Software pixel format is not supported.\n"); return AVERROR(EINVAL); } - hwfc0 = (AVHWFramesContext *)inlink0->hw_frames_ctx->data; + hwfc0 = (AVHWFramesContext *)inl0->hw_frames_ctx->data; for (int i = 1; i < sctx->base.nb_inputs; i++) { AVFilterLink *inlink = avctx->inputs[i]; + FilterLink *inl = ff_filter_link(inlink); AVHWFramesContext *hwfc = NULL; - if (inlink->format != AV_PIX_FMT_VAAPI || !inlink->hw_frames_ctx || !inlink->hw_frames_ctx->data) { + if (inlink->format != AV_PIX_FMT_VAAPI || !inl->hw_frames_ctx || !inl->hw_frames_ctx->data) { av_log(avctx, AV_LOG_ERROR, "Software pixel format is not supported.\n"); return AVERROR(EINVAL); } - hwfc = (AVHWFramesContext *)inlink->hw_frames_ctx->data; + hwfc = (AVHWFramesContext *)inl->hw_frames_ctx->data; if (hwfc0->sw_format != hwfc->sw_format) { av_log(avctx, AV_LOG_ERROR, "All inputs should have the same underlying software pixel format.\n"); diff --git a/libavfilter/vf_stereo3d.c b/libavfilter/vf_stereo3d.c index 6bd4158f6..dc9cc3355 100644 --- a/libavfilter/vf_stereo3d.c +++ b/libavfilter/vf_stereo3d.c @@ -27,8 +27,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "stereo3d.h" @@ -364,7 +364,9 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; Stereo3DContext *s = ctx->priv; - AVRational fps = inlink->frame_rate; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); + AVRational fps = il->frame_rate; AVRational tb = inlink->time_base; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); int ret; @@ -577,7 +579,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = s->out.width; outlink->h = s->out.height; - outlink->frame_rate = fps; + ol->frame_rate = fps; outlink->time_base = tb; outlink->sample_aspect_ratio = s->aspect; diff --git a/libavfilter/vf_subtitles.c b/libavfilter/vf_subtitles.c index a6338f3da..de1cfa7d9 100644 --- a/libavfilter/vf_subtitles.c +++ b/libavfilter/vf_subtitles.c @@ -29,7 +29,6 @@ #include -#include "config.h" #include "config_components.h" #if CONFIG_SUBTITLES_FILTER # include "libavcodec/avcodec.h" @@ -37,12 +36,12 @@ # include "libavformat/avformat.h" #endif #include "libavutil/avstring.h" -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" + +#include "filters.h" #include "drawutils.h" #include "avfilter.h" -#include "internal.h" #include "formats.h" #include "video.h" diff --git a/libavfilter/vf_super2xsai.c b/libavfilter/vf_super2xsai.c index 65144cbf1..8f3fd8478 100644 --- a/libavfilter/vf_super2xsai.c +++ b/libavfilter/vf_super2xsai.c @@ -29,7 +29,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/intreadwrite.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct Super2xSaIContext { diff --git a/libavfilter/vf_swaprect.c b/libavfilter/vf_swaprect.c index 119fd692f..71869cf53 100644 --- a/libavfilter/vf_swaprect.c +++ b/libavfilter/vf_swaprect.c @@ -19,14 +19,14 @@ */ #include "libavutil/avassert.h" -#include "libavutil/avstring.h" #include "libavutil/eval.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct SwapRectContext { @@ -78,6 +78,7 @@ enum { VAR_W, VAR_H, VAR_A, VAR_N, VAR_T, static int filter_frame(AVFilterLink *inlink, AVFrame *in) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; SwapRectContext *s = ctx->priv; @@ -97,7 +98,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) var_values[VAR_A] = (float) inlink->w / inlink->h; var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1; var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR]; - var_values[VAR_N] = inlink->frame_count_out; + var_values[VAR_N] = inl->frame_count_out; var_values[VAR_T] = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base); #if FF_API_FRAME_PKT FF_DISABLE_DEPRECATION_WARNINGS diff --git a/libavfilter/vf_swapuv.c b/libavfilter/vf_swapuv.c index df04631d2..5c7c69494 100644 --- a/libavfilter/vf_swapuv.c +++ b/libavfilter/vf_swapuv.c @@ -23,23 +23,12 @@ * swap UV filter */ -#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" -typedef struct SwapUVContext { - const AVClass *class; -} SwapUVContext; - -static const AVOption swapuv_options[] = { - { NULL } -}; - -AVFILTER_DEFINE_CLASS(swapuv); - static void do_swap(AVFrame *frame) { FFSWAP(uint8_t*, frame->data[1], frame->data[2]); @@ -104,8 +93,6 @@ static const AVFilterPad swapuv_inputs[] = { const AVFilter ff_vf_swapuv = { .name = "swapuv", .description = NULL_IF_CONFIG_SMALL("Swap U and V components."), - .priv_size = sizeof(SwapUVContext), - .priv_class = &swapuv_class, FILTER_INPUTS(swapuv_inputs), FILTER_OUTPUTS(ff_video_default_filterpad), FILTER_QUERY_FUNC(query_formats), diff --git a/libavfilter/vf_telecine.c b/libavfilter/vf_telecine.c index 44ef2b74d..77f62f3e8 100644 --- a/libavfilter/vf_telecine.c +++ b/libavfilter/vf_telecine.c @@ -31,7 +31,6 @@ #include "avfilter.h" #include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct TelecineContext { @@ -139,8 +138,10 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; TelecineContext *s = ctx->priv; - const AVFilterLink *inlink = ctx->inputs[0]; - AVRational fps = inlink->frame_rate; + AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); + AVRational fps = il->frame_rate; if (!fps.num || !fps.den) { av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; " @@ -149,9 +150,9 @@ static int config_output(AVFilterLink *outlink) } fps = av_mul_q(fps, av_inv_q(s->pts)); av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n", - inlink->frame_rate.num, inlink->frame_rate.den, fps.num, fps.den); + il->frame_rate.num, il->frame_rate.den, fps.num, fps.den); - outlink->frame_rate = fps; + ol->frame_rate = fps; outlink->time_base = av_mul_q(inlink->time_base, s->pts); av_log(ctx, AV_LOG_VERBOSE, "TB: %d/%d -> %d/%d\n", inlink->time_base.num, inlink->time_base.den, outlink->time_base.num, outlink->time_base.den); @@ -165,6 +166,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); TelecineContext *s = ctx->priv; int i, len, ret = 0, nout = 0; @@ -279,7 +281,7 @@ FF_ENABLE_DEPRECATION_WARNINGS else frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST; frame->pts = ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time) + - av_rescale(outlink->frame_count_in, s->ts_unit.num, + av_rescale(outl->frame_count_in, s->ts_unit.num, s->ts_unit.den); ret = ff_filter_frame(outlink, frame); } diff --git a/libavfilter/vf_threshold.c b/libavfilter/vf_threshold.c index dc73c277d..b8e794f0b 100644 --- a/libavfilter/vf_threshold.c +++ b/libavfilter/vf_threshold.c @@ -28,8 +28,8 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "video.h" #include "threshold.h" #include "vf_threshold_init.h" @@ -181,6 +181,8 @@ static int config_output(AVFilterLink *outlink) AVFilterLink *threshold = ctx->inputs[1]; AVFilterLink *min = ctx->inputs[2]; AVFilterLink *max = ctx->inputs[3]; + FilterLink *il = ff_filter_link(base); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -205,7 +207,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = base->w; outlink->h = base->h; outlink->sample_aspect_ratio = base->sample_aspect_ratio; - outlink->frame_rate = base->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_init(&s->fs, ctx, 4)) < 0) return ret; diff --git a/libavfilter/vf_thumbnail.c b/libavfilter/vf_thumbnail.c index 0b335c2a7..6cf791b65 100644 --- a/libavfilter/vf_thumbnail.c +++ b/libavfilter/vf_thumbnail.c @@ -27,10 +27,11 @@ * @see http://notbrainsurgery.livejournal.com/29773.html */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #define HIST_SIZE (3*256) diff --git a/libavfilter/vf_thumbnail_cuda.c b/libavfilter/vf_thumbnail_cuda.c index 40a3b75dd..d70df03f1 100644 --- a/libavfilter/vf_thumbnail_cuda.c +++ b/libavfilter/vf_thumbnail_cuda.c @@ -23,11 +23,12 @@ #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" #include "libavutil/cuda_check.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "cuda/load_helper.h" @@ -357,8 +358,10 @@ static int format_is_supported(enum AVPixelFormat fmt) static int config_props(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; + FilterLink *inl = ff_filter_link(inlink); + FilterLink *outl = ff_filter_link(ctx->outputs[0]); ThumbnailCudaContext *s = ctx->priv; - AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; + AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; AVCUDADeviceContext *device_hwctx = hw_frames_ctx->device_ctx->hwctx; CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx; CudaFunctions *cu = device_hwctx->internal->cuda_dl; @@ -400,10 +403,10 @@ static int config_props(AVFilterLink *inlink) CHECK_CU(cu->cuCtxPopCurrent(&dummy)); - s->hw_frames_ctx = ctx->inputs[0]->hw_frames_ctx; + s->hw_frames_ctx = inl->hw_frames_ctx; - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->hw_frames_ctx); - if (!ctx->outputs[0]->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(s->hw_frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); s->tb = inlink->time_base; diff --git a/libavfilter/vf_tile.c b/libavfilter/vf_tile.c index b45e739bb..2af97fee7 100644 --- a/libavfilter/vf_tile.c +++ b/libavfilter/vf_tile.c @@ -28,9 +28,9 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "formats.h" #include "video.h" -#include "internal.h" typedef struct TileContext { const AVClass *class; @@ -121,6 +121,8 @@ static int config_props(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; TileContext *tile = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); const unsigned total_margin_w = (tile->w - 1) * tile->padding + 2*tile->margin; const unsigned total_margin_h = (tile->h - 1) * tile->padding + 2*tile->margin; @@ -137,8 +139,7 @@ static int config_props(AVFilterLink *outlink) outlink->w = tile->w * inlink->w + total_margin_w; outlink->h = tile->h * inlink->h + total_margin_h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; - outlink->frame_rate = av_mul_q(inlink->frame_rate, - av_make_q(1, tile->nb_frames - tile->overlap)); + ol->frame_rate = av_mul_q(il->frame_rate, av_make_q(1, tile->nb_frames - tile->overlap)); ff_draw_init2(&tile->draw, inlink->format, inlink->colorspace, inlink->color_range, 0); ff_draw_color(&tile->draw, &tile->blank, tile->rgba_color); diff --git a/libavfilter/vf_tiltandshift.c b/libavfilter/vf_tiltandshift.c index 0149cd44d..72475bbaa 100644 --- a/libavfilter/vf_tiltandshift.c +++ b/libavfilter/vf_tiltandshift.c @@ -25,15 +25,13 @@ #include -#include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "libavutil/rational.h" #include "avfilter.h" -#include "formats.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum PaddingOption { diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c index c916e5837..3e2111d9a 100644 --- a/libavfilter/vf_tinterlace.c +++ b/libavfilter/vf_tinterlace.c @@ -26,11 +26,12 @@ * temporal field interlace filter, ported from MPlayer/libmpcodecs */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/imgutils.h" #include "libavutil/avassert.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "tinterlace.h" #include "video.h" @@ -211,6 +212,8 @@ static int config_out_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); TInterlaceContext *tinterlace = ctx->priv; int ret, i; @@ -255,13 +258,13 @@ static int config_out_props(AVFilterLink *outlink) tinterlace->preout_time_base = inlink->time_base; if (tinterlace->mode == MODE_INTERLACEX2) { tinterlace->preout_time_base.den *= 2; - outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1}); + ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){2,1}); outlink->time_base = av_mul_q(inlink->time_base , (AVRational){1,2}); } else if (tinterlace->mode == MODE_MERGEX2) { - outlink->frame_rate = inlink->frame_rate; + ol->frame_rate = il->frame_rate; outlink->time_base = inlink->time_base; } else if (tinterlace->mode != MODE_PAD) { - outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2}); + ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){1,2}); outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1}); } @@ -292,7 +295,7 @@ static int config_out_props(AVFilterLink *outlink) #endif } - ret = ff_ccfifo_init(&tinterlace->cc_fifo, outlink->frame_rate, ctx); + ret = ff_ccfifo_init(&tinterlace->cc_fifo, ol->frame_rate, ctx); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n"); return ret; @@ -372,8 +375,10 @@ void copy_picture_field(TInterlaceContext *tinterlace, static int filter_frame(AVFilterLink *inlink, AVFrame *picref) { + FilterLink *inl = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *l = ff_filter_link(outlink); TInterlaceContext *tinterlace = ctx->priv; AVFrame *cur, *next, *out; int field, tff, full, ret; @@ -413,12 +418,12 @@ FF_ENABLE_DEPRECATION_WARNINGS copy_picture_field(tinterlace, out->data, out->linesize, (const uint8_t **)cur->data, cur->linesize, inlink->format, inlink->w, inlink->h, - FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inlink->frame_count_out) & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags); + FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inl->frame_count_out) & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags); /* write even frame lines into the lower field of the new frame */ copy_picture_field(tinterlace, out->data, out->linesize, (const uint8_t **)next->data, next->linesize, inlink->format, inlink->w, inlink->h, - FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inlink->frame_count_out) & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags); + FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? (1 + inl->frame_count_out) & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags); if (tinterlace->mode != MODE_MERGEX2) av_frame_free(&tinterlace->next); break; @@ -440,7 +445,7 @@ FF_ENABLE_DEPRECATION_WARNINGS out->height = outlink->h; out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1)); - field = (1 + outlink->frame_count_in) & 1 ? FIELD_UPPER : FIELD_LOWER; + field = (1 + l->frame_count_in) & 1 ? FIELD_UPPER : FIELD_LOWER; full = out->color_range == AVCOL_RANGE_JPEG || ff_fmt_is_in(out->format, full_scale_yuvj_pix_fmts); /* copy upper and lower fields */ copy_picture_field(tinterlace, out->data, out->linesize, @@ -559,7 +564,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); - out->duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + out->duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base); ff_ccfifo_inject(&tinterlace->cc_fifo, out); ret = ff_filter_frame(outlink, out); diff --git a/libavfilter/vf_tmidequalizer.c b/libavfilter/vf_tmidequalizer.c index 650aa3663..f17b2090c 100644 --- a/libavfilter/vf_tmidequalizer.c +++ b/libavfilter/vf_tmidequalizer.c @@ -19,10 +19,11 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct TMidEqualizerContext { diff --git a/libavfilter/vf_tonemap.c b/libavfilter/vf_tonemap.c index 8029f6966..d8322f45b 100644 --- a/libavfilter/vf_tonemap.c +++ b/libavfilter/vf_tonemap.c @@ -35,7 +35,7 @@ #include "avfilter.h" #include "colorspace.h" -#include "internal.h" +#include "filters.h" #include "video.h" enum TonemapAlgorithm { diff --git a/libavfilter/vf_tonemap_opencl.c b/libavfilter/vf_tonemap_opencl.c index a2a27307b..2f2eeac33 100644 --- a/libavfilter/vf_tonemap_opencl.c +++ b/libavfilter/vf_tonemap_opencl.c @@ -24,7 +24,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" @@ -343,8 +343,7 @@ static int tonemap_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) int err; double peak = ctx->peak; - AVHWFramesContext *input_frames_ctx = - (AVHWFramesContext*)input->hw_frames_ctx->data; + AVHWFramesContext *input_frames_ctx; av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", av_get_pix_fmt_name(input->format), @@ -352,6 +351,7 @@ static int tonemap_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) if (!input->hw_frames_ctx) return AVERROR(EINVAL); + input_frames_ctx = (AVHWFramesContext*)input->hw_frames_ctx->data; output = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!output) { diff --git a/libavfilter/vf_tonemap_vaapi.c b/libavfilter/vf_tonemap_vaapi.c index 0b767202d..b1cc03709 100644 --- a/libavfilter/vf_tonemap_vaapi.c +++ b/libavfilter/vf_tonemap_vaapi.c @@ -22,7 +22,7 @@ #include "libavutil/mastering_display_metadata.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "vaapi_vpp.h" #include "video.h" @@ -39,7 +39,11 @@ typedef struct HDRVAAPIContext { enum AVColorTransferCharacteristic color_transfer; enum AVColorSpace color_matrix; + char *mastering_display; + char *content_light; + VAHdrMetaDataHDR10 in_metadata; + VAHdrMetaDataHDR10 out_metadata; AVFrameSideData *src_display; AVFrameSideData *src_light; @@ -146,6 +150,87 @@ static int tonemap_vaapi_save_metadata(AVFilterContext *avctx, AVFrame *input_fr return 0; } +static int tonemap_vaapi_update_sidedata(AVFilterContext *avctx, AVFrame *output_frame) +{ + HDRVAAPIContext *ctx = avctx->priv; + AVFrameSideData *metadata; + AVMasteringDisplayMetadata *hdr_meta; + AVFrameSideData *metadata_lt; + AVContentLightMetadata *hdr_meta_lt; + int i; + const int mapping[3] = {1, 2, 0}; //green, blue, red + const int chroma_den = 50000; + const int luma_den = 10000; + + metadata = av_frame_new_side_data(output_frame, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA, + sizeof(AVMasteringDisplayMetadata)); + if (!metadata) + return AVERROR(ENOMEM); + + hdr_meta = (AVMasteringDisplayMetadata *)metadata->data; + + for (i = 0; i < 3; i++) { + const int j = mapping[i]; + hdr_meta->display_primaries[j][0].num = ctx->out_metadata.display_primaries_x[i]; + hdr_meta->display_primaries[j][0].den = chroma_den; + + hdr_meta->display_primaries[j][1].num = ctx->out_metadata.display_primaries_y[i]; + hdr_meta->display_primaries[j][1].den = chroma_den; + } + + hdr_meta->white_point[0].num = ctx->out_metadata.white_point_x; + hdr_meta->white_point[0].den = chroma_den; + + hdr_meta->white_point[1].num = ctx->out_metadata.white_point_y; + hdr_meta->white_point[1].den = chroma_den; + hdr_meta->has_primaries = 1; + + hdr_meta->max_luminance.num = ctx->out_metadata.max_display_mastering_luminance; + hdr_meta->max_luminance.den = luma_den; + + hdr_meta->min_luminance.num = ctx->out_metadata.min_display_mastering_luminance; + hdr_meta->min_luminance.den = luma_den; + hdr_meta->has_luminance = 1; + + av_log(avctx, AV_LOG_DEBUG, + "Mastering display colour volume(out):\n"); + av_log(avctx, AV_LOG_DEBUG, + "G(%u,%u) B(%u,%u) R(%u,%u) WP(%u,%u)\n", + ctx->out_metadata.display_primaries_x[0], + ctx->out_metadata.display_primaries_y[0], + ctx->out_metadata.display_primaries_x[1], + ctx->out_metadata.display_primaries_y[1], + ctx->out_metadata.display_primaries_x[2], + ctx->out_metadata.display_primaries_y[2], + ctx->out_metadata.white_point_x, + ctx->out_metadata.white_point_y); + av_log(avctx, AV_LOG_DEBUG, + "max_display_mastering_luminance=%u, min_display_mastering_luminance=%u\n", + ctx->out_metadata.max_display_mastering_luminance, + ctx->out_metadata.min_display_mastering_luminance); + + metadata_lt = av_frame_new_side_data(output_frame, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + sizeof(AVContentLightMetadata)); + if (!metadata_lt) + return AVERROR(ENOMEM); + + hdr_meta_lt = (AVContentLightMetadata *)metadata_lt->data; + + hdr_meta_lt->MaxCLL = FFMIN(ctx->out_metadata.max_content_light_level, 65535); + hdr_meta_lt->MaxFALL = FFMIN(ctx->out_metadata.max_pic_average_light_level, 65535); + + av_log(avctx, AV_LOG_DEBUG, + "Content light level information(out):\n"); + av_log(avctx, AV_LOG_DEBUG, + "MaxCLL(%u) MaxFALL(%u)\n", + ctx->out_metadata.max_content_light_level, + ctx->out_metadata.max_pic_average_light_level); + + return 0; +} + static int tonemap_vaapi_set_filter_params(AVFilterContext *avctx, AVFrame *input_frame) { VAAPIVPPContext *vpp_ctx = avctx->priv; @@ -208,15 +293,26 @@ static int tonemap_vaapi_build_filter_params(AVFilterContext *avctx) return AVERROR(EINVAL); } - for (i = 0; i < num_query_caps; i++) { - if (VA_TONE_MAPPING_HDR_TO_SDR & hdr_cap[i].caps_flag) - break; - } - - if (i >= num_query_caps) { - av_log(avctx, AV_LOG_ERROR, - "VAAPI driver doesn't support HDR to SDR\n"); - return AVERROR(EINVAL); + if (ctx->mastering_display) { + for (i = 0; i < num_query_caps; i++) { + if (VA_TONE_MAPPING_HDR_TO_HDR & hdr_cap[i].caps_flag) + break; + } + if (i >= num_query_caps) { + av_log(avctx, AV_LOG_ERROR, + "VAAPI driver doesn't support HDR to HDR\n"); + return AVERROR(EINVAL); + } + } else { + for (i = 0; i < num_query_caps; i++) { + if (VA_TONE_MAPPING_HDR_TO_SDR & hdr_cap[i].caps_flag) + break; + } + if (i >= num_query_caps) { + av_log(avctx, AV_LOG_ERROR, + "VAAPI driver doesn't support HDR to SDR\n"); + return AVERROR(EINVAL); + } } hdrtm_param.type = VAProcFilterHighDynamicRangeToneMapping; @@ -241,6 +337,8 @@ static int tonemap_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame VAProcPipelineParameterBuffer params; int err; + VAHdrMetaData out_hdr_metadata; + av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", av_get_pix_fmt_name(input_frame->format), input_frame->width, input_frame->height, input_frame->pts); @@ -278,22 +376,43 @@ static int tonemap_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame if (err < 0) goto fail; + av_frame_remove_side_data(output_frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + av_frame_remove_side_data(output_frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + + if (!ctx->mastering_display) { + /* Use BT709 by default for HDR to SDR output frame */ + output_frame->color_primaries = AVCOL_PRI_BT709; + output_frame->color_trc = AVCOL_TRC_BT709; + output_frame->colorspace = AVCOL_SPC_BT709; + } + if (ctx->color_primaries != AVCOL_PRI_UNSPECIFIED) output_frame->color_primaries = ctx->color_primaries; if (ctx->color_transfer != AVCOL_TRC_UNSPECIFIED) output_frame->color_trc = ctx->color_transfer; - else - output_frame->color_trc = AVCOL_TRC_BT709; if (ctx->color_matrix != AVCOL_SPC_UNSPECIFIED) output_frame->colorspace = ctx->color_matrix; + if (ctx->mastering_display) { + err = tonemap_vaapi_update_sidedata(avctx, output_frame); + if (err < 0) + goto fail; + } + err = ff_vaapi_vpp_init_params(avctx, ¶ms, input_frame, output_frame); if (err < 0) goto fail; + if (ctx->mastering_display) { + out_hdr_metadata.metadata_type = VAProcHighDynamicRangeMetadataHDR10; + out_hdr_metadata.metadata = &ctx->out_metadata; + out_hdr_metadata.metadata_size = sizeof(VAHdrMetaDataHDR10); + params.output_hdr_metadata = &out_hdr_metadata; + } + if (vpp_ctx->nb_filter_buffers) { params.filters = &vpp_ctx->filter_buffers[0]; params.num_filters = vpp_ctx->nb_filter_buffers; @@ -309,9 +428,6 @@ static int tonemap_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame av_get_pix_fmt_name(output_frame->format), output_frame->width, output_frame->height, output_frame->pts); - av_frame_remove_side_data(output_frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); - av_frame_remove_side_data(output_frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); - return ff_filter_frame(outlink, output_frame); fail: @@ -332,8 +448,13 @@ static av_cold int tonemap_vaapi_init(AVFilterContext *avctx) if (ctx->output_format_string) { vpp_ctx->output_format = av_get_pix_fmt(ctx->output_format_string); } else { - vpp_ctx->output_format = AV_PIX_FMT_NV12; - av_log(avctx, AV_LOG_WARNING, "Output format not set, use default format NV12\n"); + if (ctx->mastering_display) { + vpp_ctx->output_format = AV_PIX_FMT_P010; + av_log(avctx, AV_LOG_VERBOSE, "Output format not set, use default format P010 for HDR to HDR tone mapping.\n"); + } else { + vpp_ctx->output_format = AV_PIX_FMT_NV12; + av_log(avctx, AV_LOG_VERBOSE, "Output format not set, use default format NV12 for HDR to SDR tone mapping.\n"); + } } #define STRING_OPTION(var_name, func_name, default_value) do { \ @@ -353,6 +474,37 @@ static av_cold int tonemap_vaapi_init(AVFilterContext *avctx) STRING_OPTION(color_transfer, color_transfer, AVCOL_TRC_UNSPECIFIED); STRING_OPTION(color_matrix, color_space, AVCOL_SPC_UNSPECIFIED); + if (ctx->mastering_display) { + if (10 != sscanf(ctx->mastering_display, + "%hu %hu|%hu %hu|%hu %hu|%hu %hu|%u %u", + &ctx->out_metadata.display_primaries_x[0], + &ctx->out_metadata.display_primaries_y[0], + &ctx->out_metadata.display_primaries_x[1], + &ctx->out_metadata.display_primaries_y[1], + &ctx->out_metadata.display_primaries_x[2], + &ctx->out_metadata.display_primaries_y[2], + &ctx->out_metadata.white_point_x, + &ctx->out_metadata.white_point_y, + &ctx->out_metadata.min_display_mastering_luminance, + &ctx->out_metadata.max_display_mastering_luminance)) { + av_log(avctx, AV_LOG_ERROR, + "Option mastering-display input invalid\n"); + return AVERROR(EINVAL); + } + + if (!ctx->content_light) { + ctx->out_metadata.max_content_light_level = 0; + ctx->out_metadata.max_pic_average_light_level = 0; + } else if (2 != sscanf(ctx->content_light, + "%hu %hu", + &ctx->out_metadata.max_content_light_level, + &ctx->out_metadata.max_pic_average_light_level)) { + av_log(avctx, AV_LOG_ERROR, + "Option content-light input invalid\n"); + return AVERROR(EINVAL); + } + } + return 0; } @@ -378,6 +530,12 @@ static const AVOption tonemap_vaapi_options[] = { { "t", "Output color transfer characteristics set", OFFSET(color_transfer_string), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS, .unit = "transfer" }, + { "display", "set mastering display colour volume", + OFFSET(mastering_display), AV_OPT_TYPE_STRING, + { .str = NULL }, .flags = FLAGS }, + { "light", "set content light level information", + OFFSET(content_light), AV_OPT_TYPE_STRING, + { .str = NULL }, .flags = FLAGS }, { NULL } }; diff --git a/libavfilter/vf_tpad.c b/libavfilter/vf_tpad.c index 72d0bf338..0b156772c 100644 --- a/libavfilter/vf_tpad.c +++ b/libavfilter/vf_tpad.c @@ -23,7 +23,6 @@ #include "avfilter.h" #include "audio.h" #include "filters.h" -#include "internal.h" #include "formats.h" #include "drawutils.h" #include "video.h" @@ -90,6 +89,7 @@ static int activate(AVFilterContext *ctx) { AVFilterLink *inlink = ctx->inputs[0]; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *l = ff_filter_link(outlink); TPadContext *s = ctx->priv; AVFrame *frame = NULL; int ret, status; @@ -116,7 +116,7 @@ static int activate(AVFilterContext *ctx) ff_fill_rectangle(&s->draw, &s->color, frame->data, frame->linesize, 0, 0, frame->width, frame->height); - duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base); frame->pts = s->pts; frame->duration = duration; s->pts += duration; @@ -136,7 +136,7 @@ static int activate(AVFilterContext *ctx) frame = av_frame_clone(s->cache_start); if (!frame) return AVERROR(ENOMEM); - duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base); frame->pts = s->pts; frame->duration = duration; s->pts += duration; @@ -182,7 +182,7 @@ static int activate(AVFilterContext *ctx) if (!frame) return AVERROR(ENOMEM); } - duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + duration = av_rescale_q(1, av_inv_q(l->frame_rate), outlink->time_base); frame->pts = s->pts; frame->duration = duration; s->pts += duration; @@ -200,6 +200,7 @@ static int activate(AVFilterContext *ctx) static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; + FilterLink *l = ff_filter_link(inlink); TPadContext *s = ctx->priv; if (needs_drawing(s)) { @@ -208,9 +209,9 @@ static int config_input(AVFilterLink *inlink) } if (s->start_duration) - s->pad_start = av_rescale_q(s->start_duration, inlink->frame_rate, av_inv_q(AV_TIME_BASE_Q)); + s->pad_start = av_rescale_q(s->start_duration, l->frame_rate, av_inv_q(AV_TIME_BASE_Q)); if (s->stop_duration) - s->pad_stop = av_rescale_q(s->stop_duration, inlink->frame_rate, av_inv_q(AV_TIME_BASE_Q)); + s->pad_stop = av_rescale_q(s->stop_duration, l->frame_rate, av_inv_q(AV_TIME_BASE_Q)); return 0; } diff --git a/libavfilter/vf_transpose.c b/libavfilter/vf_transpose.c index bfd6f45fb..d2836246b 100644 --- a/libavfilter/vf_transpose.c +++ b/libavfilter/vf_transpose.c @@ -35,8 +35,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "transpose.h" diff --git a/libavfilter/vf_transpose_npp.c b/libavfilter/vf_transpose_npp.c index 96c008cda..1706267b1 100644 --- a/libavfilter/vf_transpose_npp.c +++ b/libavfilter/vf_transpose_npp.c @@ -29,8 +29,8 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, device_hwctx->internal->cuda_dl, x) @@ -178,6 +178,8 @@ static int format_is_supported(enum AVPixelFormat fmt) static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_height, int out_width, int out_height) { + FilterLink *inl = ff_filter_link(ctx->inputs[0]); + FilterLink *outl = ff_filter_link(ctx->outputs[0]); NPPTransposeContext *s = ctx->priv; AVHWFramesContext *in_frames_ctx; enum AVPixelFormat format; @@ -185,12 +187,12 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig int rot_width = out_width, rot_height = out_height; /* check that we have a hw context */ - if (!ctx->inputs[0]->hw_frames_ctx) { + if (!inl->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n"); return AVERROR(EINVAL); } - in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; + in_frames_ctx = (AVHWFramesContext*)inl->hw_frames_ctx->data; format = in_frames_ctx->sw_format; if (!format_is_supported(format)) { @@ -235,13 +237,13 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig } if (last_stage >= 0) { - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx); + outl->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx); } else { - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(ctx->inputs[0]->hw_frames_ctx); + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); s->passthrough = 1; } - if (!ctx->outputs[0]->hw_frames_ctx) + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); return 0; @@ -249,17 +251,19 @@ static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_heig static int npptranspose_config_props(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); NPPTransposeContext *s = ctx->priv; int ret; if ((inlink->w >= inlink->h && s->passthrough == NPP_TRANSPOSE_PT_TYPE_LANDSCAPE) || (inlink->w <= inlink->h && s->passthrough == NPP_TRANSPOSE_PT_TYPE_PORTRAIT)) { - if (inlink->hw_frames_ctx) { - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); - if (!outlink->hw_frames_ctx) + if (inl->hw_frames_ctx) { + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); } @@ -387,7 +391,8 @@ static int npptranspose_filter_frame(AVFilterLink *link, AVFrame *in) AVFilterContext *ctx = link->dst; NPPTransposeContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)outlink->hw_frames_ctx->data; + FilterLink *outl = ff_filter_link(outlink); + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)outl->hw_frames_ctx->data; AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; AVFrame *out = NULL; CUcontext dummy; diff --git a/libavfilter/vf_transpose_opencl.c b/libavfilter/vf_transpose_opencl.c index 262dec0a8..063c5b3cf 100644 --- a/libavfilter/vf_transpose_opencl.c +++ b/libavfilter/vf_transpose_opencl.c @@ -23,7 +23,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" @@ -71,9 +71,11 @@ fail: static int transpose_opencl_config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; TransposeOpenCLContext *s = avctx->priv; AVFilterLink *inlink = avctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); const AVPixFmtDescriptor *desc_in = av_pix_fmt_desc_get(inlink->format); int ret; @@ -81,9 +83,9 @@ static int transpose_opencl_config_output(AVFilterLink *outlink) s->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) || (inlink->w <= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) { - if (inlink->hw_frames_ctx) { - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); - if (!outlink->hw_frames_ctx) + if (inl->hw_frames_ctx) { + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); } av_log(avctx, AV_LOG_VERBOSE, diff --git a/libavfilter/vf_transpose_vaapi.c b/libavfilter/vf_transpose_vaapi.c index 165a97de3..4976958be 100644 --- a/libavfilter/vf_transpose_vaapi.c +++ b/libavfilter/vf_transpose_vaapi.c @@ -21,7 +21,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "transpose.h" #include "vaapi_vpp.h" #include "video.h" @@ -185,15 +185,17 @@ static av_cold int transpose_vaapi_init(AVFilterContext *avctx) static int transpose_vaapi_vpp_config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; VAAPIVPPContext *vpp_ctx = avctx->priv; TransposeVAAPIContext *ctx = avctx->priv; AVFilterLink *inlink = avctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); if ((inlink->w >= inlink->h && ctx->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) || (inlink->w <= inlink->h && ctx->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) { - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); - if (!outlink->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); + if (!outl->hw_frames_ctx) return AVERROR(ENOMEM); av_log(avctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d (passthrough mode)\n", diff --git a/libavfilter/vf_transpose_vt.c b/libavfilter/vf_transpose_vt.c index e0f35fdb5..819334086 100644 --- a/libavfilter/vf_transpose_vt.c +++ b/libavfilter/vf_transpose_vt.c @@ -24,7 +24,8 @@ #include "libavutil/hwcontext_videotoolbox.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "internal.h" + +#include "filters.h" #include "transpose.h" #include "video.h" @@ -105,27 +106,30 @@ fail: static int transpose_vt_recreate_hw_ctx(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); AVHWFramesContext *hw_frame_ctx_in; AVHWFramesContext *hw_frame_ctx_out; int err; - av_buffer_unref(&outlink->hw_frames_ctx); + av_buffer_unref(&outl->hw_frames_ctx); - hw_frame_ctx_in = (AVHWFramesContext *)inlink->hw_frames_ctx->data; - outlink->hw_frames_ctx = av_hwframe_ctx_alloc(hw_frame_ctx_in->device_ref); - hw_frame_ctx_out = (AVHWFramesContext *)outlink->hw_frames_ctx->data; + hw_frame_ctx_in = (AVHWFramesContext *)inl->hw_frames_ctx->data; + outl->hw_frames_ctx = av_hwframe_ctx_alloc(hw_frame_ctx_in->device_ref); + hw_frame_ctx_out = (AVHWFramesContext *)outl->hw_frames_ctx->data; hw_frame_ctx_out->format = AV_PIX_FMT_VIDEOTOOLBOX; hw_frame_ctx_out->sw_format = hw_frame_ctx_in->sw_format; hw_frame_ctx_out->width = outlink->w; hw_frame_ctx_out->height = outlink->h; + ((AVVTFramesContext *)hw_frame_ctx_out->hwctx)->color_range = ((AVVTFramesContext *)hw_frame_ctx_in->hwctx)->color_range; err = ff_filter_init_hw_frames(avctx, outlink, 1); if (err < 0) return err; - err = av_hwframe_ctx_init(outlink->hw_frames_ctx); + err = av_hwframe_ctx_init(outl->hw_frames_ctx); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to init videotoolbox frame context, %s\n", @@ -139,16 +143,18 @@ static int transpose_vt_recreate_hw_ctx(AVFilterLink *outlink) static int transpose_vt_config_output(AVFilterLink *outlink) { int err; + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; TransposeVtContext *s = avctx->priv; AVFilterLink *inlink = outlink->src->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); CFStringRef rotation = kVTRotation_0; CFBooleanRef vflip = kCFBooleanFalse; CFBooleanRef hflip = kCFBooleanFalse; int swap_w_h = 0; - av_buffer_unref(&outlink->hw_frames_ctx); - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); + av_buffer_unref(&outl->hw_frames_ctx); + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); if ((inlink->w >= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) || (inlink->w <= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) { diff --git a/libavfilter/vf_transpose_vulkan.c b/libavfilter/vf_transpose_vulkan.c index 263a934dc..72ea142e5 100644 --- a/libavfilter/vf_transpose_vulkan.c +++ b/libavfilter/vf_transpose_vulkan.c @@ -23,7 +23,8 @@ #include "libavutil/opt.h" #include "vulkan_filter.h" #include "vulkan_spirv.h" -#include "internal.h" + +#include "filters.h" #include "transpose.h" #include "video.h" @@ -193,18 +194,20 @@ static av_cold void transpose_vulkan_uninit(AVFilterContext *avctx) static int config_props_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; TransposeVulkanContext *s = avctx->priv; FFVulkanContext *vkctx = &s->vkctx; AVFilterLink *inlink = avctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); if ((inlink->w >= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) || (inlink->w <= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) { av_log(avctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d (passthrough mode)\n", inlink->w, inlink->h, inlink->w, inlink->h); - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); - return outlink->hw_frames_ctx ? 0 : AVERROR(ENOMEM); + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); + return outl->hw_frames_ctx ? 0 : AVERROR(ENOMEM); } else { s->passthrough = TRANSPOSE_PT_TYPE_NONE; } diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c index 2705ac527..b5dd468b6 100644 --- a/libavfilter/vf_unsharp.c +++ b/libavfilter/vf_unsharp.c @@ -37,14 +37,45 @@ */ #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "libavutil/common.h" #include "libavutil/imgutils.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "unsharp.h" + +#define MIN_MATRIX_SIZE 3 +#define MAX_MATRIX_SIZE 63 + +typedef struct UnsharpFilterParam { + int msize_x; ///< matrix width + int msize_y; ///< matrix height + int amount; ///< effect amount + int steps_x; ///< horizontal step count + int steps_y; ///< vertical step count + int scalebits; ///< bits to shift pixel + int32_t halfscale; ///< amount to add to pixel + uint32_t *sr; ///< finite state machine storage within a row + uint32_t **sc; ///< finite state machine storage across rows +} UnsharpFilterParam; + +typedef struct UnsharpContext { + const AVClass *class; + int lmsize_x, lmsize_y, cmsize_x, cmsize_y; + int amsize_x, amsize_y; + float lamount, camount; + float aamount; + UnsharpFilterParam luma; ///< luma parameters (width, height, amount) + UnsharpFilterParam chroma; ///< chroma parameters (width, height, amount) + UnsharpFilterParam alpha; ///< alpha parameters (width, height, amount) + int hsub, vsub; + int nb_planes; + int bitdepth; + int bps; + int nb_threads; + int (* unsharp_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); +} UnsharpContext; typedef struct TheadData { UnsharpFilterParam *fp; @@ -141,7 +172,7 @@ static int name##_##nbits(AVFilterContext *ctx, void *arg, int jobnr, int nb_job DEF_UNSHARP_SLICE_FUNC(unsharp_slice, 16) DEF_UNSHARP_SLICE_FUNC(unsharp_slice, 8) -static int apply_unsharp_c(AVFilterContext *ctx, AVFrame *in, AVFrame *out) +static int apply_unsharp(AVFilterContext *ctx, AVFrame *in, AVFrame *out) { AVFilterLink *inlink = ctx->inputs[0]; UnsharpContext *s = ctx->priv; @@ -208,7 +239,6 @@ static av_cold int init(AVFilterContext *ctx) SET_FILTER_PARAM(chroma, c); SET_FILTER_PARAM(alpha, a); - s->apply_unsharp = apply_unsharp_c; return 0; } @@ -305,7 +335,6 @@ static av_cold void uninit(AVFilterContext *ctx) static int filter_frame(AVFilterLink *link, AVFrame *in) { - UnsharpContext *s = link->dst->priv; AVFilterLink *outlink = link->dst->outputs[0]; AVFrame *out; int ret = 0; @@ -317,7 +346,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) } av_frame_copy_props(out, in); - ret = s->apply_unsharp(link->dst, in, out); + ret = apply_unsharp(link->dst, in, out); av_frame_free(&in); diff --git a/libavfilter/vf_unsharp_opencl.c b/libavfilter/vf_unsharp_opencl.c index 09398464c..c36997f69 100644 --- a/libavfilter/vf_unsharp_opencl.c +++ b/libavfilter/vf_unsharp_opencl.c @@ -23,7 +23,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" @@ -59,7 +59,7 @@ typedef struct UnsharpOpenCLContext { cl_int size_y; cl_float amount; cl_float threshold; - } plane[4]; + } plane[AV_VIDEO_MAX_PLANES]; } UnsharpOpenCLContext; diff --git a/libavfilter/vf_untile.c b/libavfilter/vf_untile.c index f32f3e186..486cce31e 100644 --- a/libavfilter/vf_untile.c +++ b/libavfilter/vf_untile.c @@ -75,6 +75,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; UntileContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); AVRational dt; s->desc = av_pix_fmt_desc_get(outlink->format); @@ -88,9 +90,9 @@ static int config_output(AVFilterLink *outlink) outlink->w = inlink->w / s->w; outlink->h = inlink->h / s->h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; - outlink->frame_rate = av_mul_q(inlink->frame_rate, av_make_q(s->nb_frames, 1)); - if (outlink->frame_rate.num) - dt = av_inv_q(outlink->frame_rate); + ol->frame_rate = av_mul_q(il->frame_rate, av_make_q(s->nb_frames, 1)); + if (ol->frame_rate.num) + dt = av_inv_q(ol->frame_rate); else dt = av_mul_q(inlink->time_base, av_make_q(1, s->nb_frames)); outlink->time_base = av_gcd_q(inlink->time_base, dt, AV_TIME_BASE / 2, AV_TIME_BASE_Q); diff --git a/libavfilter/vf_uspp.c b/libavfilter/vf_uspp.c index 10c8aaeb6..f8e506aa2 100644 --- a/libavfilter/vf_uspp.c +++ b/libavfilter/vf_uspp.c @@ -29,12 +29,14 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/video_enc_params.h" #include "libavcodec/avcodec.h" -#include "internal.h" + +#include "filters.h" #include "qp_table.h" #include "avfilter.h" #include "video.h" diff --git a/libavfilter/vf_v360.c b/libavfilter/vf_v360.c index 942b47d7a..4ba389e33 100644 --- a/libavfilter/vf_v360.c +++ b/libavfilter/vf_v360.c @@ -36,12 +36,12 @@ #include #include "libavutil/avassert.h" -#include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "v360.h" @@ -286,6 +286,8 @@ static int remap##ws##_##bits##bit_slice(AVFilterContext *ctx, void *arg, int jo const AVFrame *in = td->in; \ AVFrame *out = td->out; \ \ + av_assert1(s->nb_planes <= AV_VIDEO_MAX_PLANES); \ + \ for (int stereo = 0; stereo < 1 + s->out_stereo > STEREO_2D; stereo++) { \ for (int plane = 0; plane < s->nb_planes; plane++) { \ const unsigned map = s->map[plane]; \ @@ -3787,6 +3789,8 @@ static int barrelsplit_to_xyz(const V360Context *s, case 3: // back bottom vf = (y * 2.f - 1.5f) / scaleh + 3.f - facef; break; + default: + av_assert0(0); } l_x = (0.5f - uf) / scalew; l_y = 0.5f * dir_vert; @@ -4251,8 +4255,8 @@ static int v360_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) int16_t *u = r->u[p] + ((j - slice_start) * uv_linesize + i) * elements; int16_t *v = r->v[p] + ((j - slice_start) * uv_linesize + i) * elements; int16_t *ker = r->ker[p] + ((j - slice_start) * uv_linesize + i) * elements; - uint8_t *mask8 = p ? NULL : r->mask + ((j - slice_start) * s->pr_width[0] + i); - uint16_t *mask16 = p ? NULL : (uint16_t *)r->mask + ((j - slice_start) * s->pr_width[0] + i); + uint8_t *mask8 = (p || !r->mask) ? NULL : r->mask + ((j - slice_start) * s->pr_width[0] + i); + uint16_t *mask16 = (p || !r->mask) ? NULL : (uint16_t *)r->mask + ((j - slice_start) * s->pr_width[0] + i); int in_mask, out_mask; if (s->out_transpose) diff --git a/libavfilter/vf_vaguedenoiser.c b/libavfilter/vf_vaguedenoiser.c index 19deaa25e..932135685 100644 --- a/libavfilter/vf_vaguedenoiser.c +++ b/libavfilter/vf_vaguedenoiser.c @@ -23,11 +23,12 @@ #include "libavutil/imgutils.h" #include "libavutil/attributes.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct VagueDenoiserContext { diff --git a/libavfilter/vf_varblur.c b/libavfilter/vf_varblur.c index 6ebb9c066..8c5aebdcf 100644 --- a/libavfilter/vf_varblur.c +++ b/libavfilter/vf_varblur.c @@ -19,11 +19,12 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #include "video.h" typedef struct VarBlurContext { @@ -319,6 +320,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; AVFilterLink *radiuslink = ctx->inputs[1]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); VarBlurContext *s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); int ret; @@ -336,7 +339,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = inlink->h; outlink->time_base = inlink->time_base; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; - outlink->frame_rate = inlink->frame_rate; + ol->frame_rate = il->frame_rate; s->depth = desc->comp[0].depth; s->blur_plane = s->depth <= 8 ? blur_plane8 : s->depth <= 16 ? blur_plane16 : blur_plane32; diff --git a/libavfilter/vf_vectorscope.c b/libavfilter/vf_vectorscope.c index 735cf35a8..efaf7d927 100644 --- a/libavfilter/vf_vectorscope.c +++ b/libavfilter/vf_vectorscope.c @@ -20,13 +20,13 @@ #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavutil/xga_font_data.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" enum GraticuleType { diff --git a/libavfilter/vf_vflip.c b/libavfilter/vf_vflip.c index 8d6724ed3..1b7e1e4d7 100644 --- a/libavfilter/vf_vflip.c +++ b/libavfilter/vf_vflip.c @@ -24,24 +24,16 @@ */ #include "libavutil/internal.h" -#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct FlipContext { - const AVClass *class; int vsub; ///< vertical chroma subsampling int bayer; } FlipContext; -static const AVOption vflip_options[] = { - { NULL } -}; - -AVFILTER_DEFINE_CLASS(vflip); - static int config_input(AVFilterLink *link) { FlipContext *flip = link->dst->priv; @@ -139,7 +131,6 @@ const AVFilter ff_vf_vflip = { .name = "vflip", .description = NULL_IF_CONFIG_SMALL("Flip the input video vertically."), .priv_size = sizeof(FlipContext), - .priv_class = &vflip_class, FILTER_INPUTS(avfilter_vf_vflip_inputs), FILTER_OUTPUTS(ff_video_default_filterpad), .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, diff --git a/libavfilter/vf_vfrdet.c b/libavfilter/vf_vfrdet.c index 8d641dd36..049e87b3e 100644 --- a/libavfilter/vf_vfrdet.c +++ b/libavfilter/vf_vfrdet.c @@ -20,7 +20,8 @@ #include "libavutil/common.h" #include "libavutil/opt.h" -#include "internal.h" + +#include "filters.h" #include "video.h" typedef struct VFRDETContext { diff --git a/libavfilter/vf_vibrance.c b/libavfilter/vf_vibrance.c index e1d6e64ae..3be620e69 100644 --- a/libavfilter/vf_vibrance.c +++ b/libavfilter/vf_vibrance.c @@ -22,7 +22,7 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define R 0 diff --git a/libavfilter/vf_vidstabdetect.c b/libavfilter/vf_vidstabdetect.c index 1e1946a45..7b52f36dd 100644 --- a/libavfilter/vf_vidstabdetect.c +++ b/libavfilter/vf_vidstabdetect.c @@ -28,7 +28,6 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" #include "vidstabutils.h" diff --git a/libavfilter/vf_vidstabtransform.c b/libavfilter/vf_vidstabtransform.c index dd86c4d81..d2b771591 100644 --- a/libavfilter/vf_vidstabtransform.c +++ b/libavfilter/vf_vidstabtransform.c @@ -27,7 +27,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "vidstabutils.h" diff --git a/libavfilter/vf_vif.c b/libavfilter/vf_vif.c index a927abaf6..ee62723ae 100644 --- a/libavfilter/vf_vif.c +++ b/libavfilter/vf_vif.c @@ -27,11 +27,12 @@ #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "framesync.h" -#include "internal.h" #define NUM_DATA_BUFS 13 @@ -549,6 +550,8 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; VIFContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(mainlink); + FilterLink *ol = ff_filter_link(outlink); FFFrameSyncIn *in; int ret; @@ -556,7 +559,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = mainlink->h; outlink->time_base = mainlink->time_base; outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; - outlink->frame_rate = mainlink->frame_rate; + ol->frame_rate = il->frame_rate; if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0) return ret; diff --git a/libavfilter/vf_vignette.c b/libavfilter/vf_vignette.c index b329c510a..5b4b9c738 100644 --- a/libavfilter/vf_vignette.c +++ b/libavfilter/vf_vignette.c @@ -20,11 +20,12 @@ #include /* DBL_MAX */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/eval.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" static const char *const var_names[] = { @@ -148,12 +149,13 @@ static double get_natural_factor(const VignetteContext *s, int x, int y) static void update_context(VignetteContext *s, AVFilterLink *inlink, AVFrame *frame) { + FilterLink *inl = ff_filter_link(inlink); int x, y; float *dst = s->fmap; int dst_linesize = s->fmap_linesize; if (frame) { - s->var_values[VAR_N] = inlink->frame_count_out; + s->var_values[VAR_N] = inl->frame_count_out; s->var_values[VAR_T] = TS2T(frame->pts, inlink->time_base); s->var_values[VAR_PTS] = TS2D(frame->pts); } else { @@ -282,14 +284,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) static int config_props(AVFilterLink *inlink) { VignetteContext *s = inlink->dst->priv; + FilterLink *l = ff_filter_link(inlink); AVRational sar = inlink->sample_aspect_ratio; s->desc = av_pix_fmt_desc_get(inlink->format); s->var_values[VAR_W] = inlink->w; s->var_values[VAR_H] = inlink->h; s->var_values[VAR_TB] = av_q2d(inlink->time_base); - s->var_values[VAR_R] = inlink->frame_rate.num == 0 || inlink->frame_rate.den == 0 ? - NAN : av_q2d(inlink->frame_rate); + s->var_values[VAR_R] = l->frame_rate.num == 0 || l->frame_rate.den == 0 ? + NAN : av_q2d(l->frame_rate); if (!sar.num || !sar.den) sar.num = sar.den = 1; diff --git a/libavfilter/vf_vmafmotion.c b/libavfilter/vf_vmafmotion.c index 022816e89..a8adc6701 100644 --- a/libavfilter/vf_vmafmotion.c +++ b/libavfilter/vf_vmafmotion.c @@ -25,11 +25,12 @@ */ #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" #include "vmaf_motion.h" @@ -89,11 +90,10 @@ static void convolution_x(const uint16_t *filter, int filt_w, const uint16_t *sr int borders_left = radius; int borders_right = w - (filt_w - radius); int i, j, k; - int sum = 0; for (i = 0; i < h; i++) { for (j = 0; j < borders_left; j++) { - sum = 0; + int sum = 0; for (k = 0; k < filt_w; k++) { int j_tap = FFABS(j - radius + k); if (j_tap >= w) { @@ -113,7 +113,7 @@ static void convolution_x(const uint16_t *filter, int filt_w, const uint16_t *sr } for (j = borders_right; j < w; j++) { - sum = 0; + int sum = 0; for (k = 0; k < filt_w; k++) { int j_tap = FFABS(j - radius + k); if (j_tap >= w) { @@ -317,10 +317,8 @@ static av_cold int init(AVFilterContext *ctx) s->stats_file = avpriv_fopen_utf8(s->stats_file_str, "w"); if (!s->stats_file) { int err = AVERROR(errno); - char buf[128]; - av_strerror(err, buf, sizeof(buf)); av_log(ctx, AV_LOG_ERROR, "Could not open stats file %s: %s\n", - s->stats_file_str, buf); + s->stats_file_str, av_err2str(err)); return err; } } diff --git a/libavfilter/vf_vpp_qsv.c b/libavfilter/vf_vpp_qsv.c index 598c85be0..7f05f1fab 100644 --- a/libavfilter/vf_vpp_qsv.c +++ b/libavfilter/vf_vpp_qsv.c @@ -34,7 +34,6 @@ #include "libavutil/mastering_display_metadata.h" #include "formats.h" -#include "internal.h" #include "avfilter.h" #include "filters.h" @@ -297,18 +296,19 @@ static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; VPPContext *vpp = ctx->priv; + FilterLink *inl = ff_filter_link(inlink); int ret; int64_t ow, oh; if (vpp->framerate.den == 0 || vpp->framerate.num == 0) { - vpp->framerate = inlink->frame_rate; + vpp->framerate = inl->frame_rate; if (vpp->deinterlace && vpp->field_rate) - vpp->framerate = av_mul_q(inlink->frame_rate, + vpp->framerate = av_mul_q(inl->frame_rate, (AVRational){ 2, 1 }); } - if (av_cmp_q(vpp->framerate, inlink->frame_rate)) + if (av_cmp_q(vpp->framerate, inl->frame_rate)) vpp->use_frc = 1; ret = eval_expr(ctx); @@ -364,13 +364,13 @@ static int config_input(AVFilterLink *inlink) static mfxStatus get_mfx_version(const AVFilterContext *ctx, mfxVersion *mfx_version) { - const AVFilterLink *inlink = ctx->inputs[0]; + const FilterLink *l = ff_filter_link(ctx->inputs[0]); AVBufferRef *device_ref; AVHWDeviceContext *device_ctx; AVQSVDeviceContext *device_hwctx; - if (inlink->hw_frames_ctx) { - AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data; + if (l->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)l->hw_frames_ctx->data; device_ref = frames_ctx->device_ref; } else if (ctx->hw_device_ctx) { device_ref = ctx->hw_device_ctx; @@ -524,6 +524,7 @@ static int vpp_set_frame_ext_params(AVFilterContext *ctx, const AVFrame *in, AVF static int config_output(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); AVFilterContext *ctx = outlink->src; VPPContext *vpp = ctx->priv; QSVVPPParam param = { NULL }; @@ -531,11 +532,13 @@ static int config_output(AVFilterLink *outlink) mfxExtBuffer *ext_buf[ENH_FILTERS_COUNT]; mfxVersion mfx_version; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); enum AVPixelFormat in_format; outlink->w = vpp->out_width; outlink->h = vpp->out_height; - outlink->frame_rate = vpp->framerate; + ol->frame_rate = vpp->framerate; if (vpp->framerate.num == 0 || vpp->framerate.den == 0) outlink->time_base = inlink->time_base; else @@ -552,10 +555,10 @@ static int config_output(AVFilterLink *outlink) } if (inlink->format == AV_PIX_FMT_QSV) { - if (!inlink->hw_frames_ctx || !inlink->hw_frames_ctx->data) + if (!inl->hw_frames_ctx || !inl->hw_frames_ctx->data) return AVERROR(EINVAL); else - in_format = ((AVHWFramesContext*)inlink->hw_frames_ctx->data)->sw_format; + in_format = ((AVHWFramesContext*)inl->hw_frames_ctx->data)->sw_format; } else in_format = inlink->format; @@ -716,8 +719,8 @@ static int config_output(AVFilterLink *outlink) else { /* No MFX session is created in this case */ av_log(ctx, AV_LOG_VERBOSE, "qsv vpp pass through mode.\n"); - if (inlink->hw_frames_ctx) - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); + if (inl->hw_frames_ctx) + outl->hw_frames_ctx = av_buffer_ref(inl->hw_frames_ctx); } return 0; @@ -748,7 +751,7 @@ static int activate(AVFilterContext *ctx) if (qsv->session) { if (in || qsv->eof) { - ret = ff_qsvvpp_filter_frame(qsv, inlink, in); + ret = ff_qsvvpp_filter_frame(qsv, inlink, in, in); av_frame_free(&in); if (ret == AVERROR(EAGAIN)) goto not_ready; @@ -766,11 +769,12 @@ static int activate(AVFilterContext *ctx) } else { /* No MFX session is created in pass-through mode */ if (in) { + FilterLink *ol = ff_filter_link(outlink); if (in->pts != AV_NOPTS_VALUE) in->pts = av_rescale_q(in->pts, inlink->time_base, outlink->time_base); - if (outlink->frame_rate.num && outlink->frame_rate.den) - in->duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + if (ol->frame_rate.num && ol->frame_rate.den) + in->duration = av_rescale_q(1, av_inv_q(ol->frame_rate), outlink->time_base); else in->duration = 0; diff --git a/libavfilter/vf_w3fdif.c b/libavfilter/vf_w3fdif.c index 6814905a4..33ebc4d6c 100644 --- a/libavfilter/vf_w3fdif.c +++ b/libavfilter/vf_w3fdif.c @@ -23,10 +23,11 @@ #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "w3fdif.h" @@ -327,11 +328,13 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); W3FDIFContext *s = ctx->priv; outlink->time_base = av_mul_q(inlink->time_base, (AVRational){1, 2}); if (s->mode) - outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2, 1}); + ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){2, 1}); return 0; } diff --git a/libavfilter/vf_waveform.c b/libavfilter/vf_waveform.c index e004ea84f..8b54e12e3 100644 --- a/libavfilter/vf_waveform.c +++ b/libavfilter/vf_waveform.c @@ -19,13 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavutil/xga_font_data.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct ThreadData { diff --git a/libavfilter/vf_weave.c b/libavfilter/vf_weave.c index f0e8b0927..598779d1c 100644 --- a/libavfilter/vf_weave.c +++ b/libavfilter/vf_weave.c @@ -22,8 +22,8 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct WeaveContext { @@ -68,10 +68,12 @@ static int config_props_output(AVFilterLink *outlink) int ret; if (!s->double_weave) { + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); outlink->time_base.num = inlink->time_base.num * 2; outlink->time_base.den = inlink->time_base.den; - outlink->frame_rate.num = inlink->frame_rate.num; - outlink->frame_rate.den = inlink->frame_rate.den * 2; + ol->frame_rate.num = il->frame_rate.num; + ol->frame_rate.den = il->frame_rate.den * 2; } outlink->w = inlink->w; outlink->h = inlink->h * 2; @@ -97,12 +99,13 @@ typedef struct ThreadData { static int weave_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); WeaveContext *s = ctx->priv; ThreadData *td = arg; AVFrame *in = td->in; AVFrame *out = td->out; - const int weave = (s->double_weave && !(inlink->frame_count_out & 1)); + const int weave = (s->double_weave && !(inl->frame_count_out & 1)); const int field1 = weave ? s->first_field : (!s->first_field); const int field2 = weave ? (!s->first_field) : s->first_field; diff --git a/libavfilter/vf_xbr.c b/libavfilter/vf_xbr.c index 1750da043..47d11be44 100644 --- a/libavfilter/vf_xbr.c +++ b/libavfilter/vf_xbr.c @@ -30,7 +30,8 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "internal.h" + +#include "filters.h" #include "video.h" #define LB_MASK 0x00FEFEFE diff --git a/libavfilter/vf_xfade.c b/libavfilter/vf_xfade.c index f61c7083d..639904cab 100644 --- a/libavfilter/vf_xfade.c +++ b/libavfilter/vf_xfade.c @@ -23,7 +23,6 @@ #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" #include "avfilter.h" -#include "internal.h" #include "filters.h" #include "video.h" @@ -956,7 +955,7 @@ static void vertopen##name##_transition(AVFilterContext *ctx, { \ XFadeContext *s = ctx->priv; \ const int width = out->width; \ - const float w2 = out->width / 2; \ + const float w2 = out->width / 2.0; \ \ for (int y = slice_start; y < slice_end; y++) { \ for (int x = 0; x < width; x++) { \ @@ -984,7 +983,7 @@ static void vertclose##name##_transition(AVFilterContext *ctx, XFadeContext *s = ctx->priv; \ const int nb_planes = s->nb_planes; \ const int width = out->width; \ - const float w2 = out->width / 2; \ + const float w2 = out->width / 2.0; \ \ for (int y = slice_start; y < slice_end; y++) { \ for (int x = 0; x < width; x++) { \ @@ -1012,7 +1011,7 @@ static void horzopen##name##_transition(AVFilterContext *ctx, XFadeContext *s = ctx->priv; \ const int nb_planes = s->nb_planes; \ const int width = out->width; \ - const float h2 = out->height / 2; \ + const float h2 = out->height / 2.0; \ \ for (int y = slice_start; y < slice_end; y++) { \ const float smooth = 2.f - fabsf((y - h2) / h2) - progress * 2.f; \ @@ -1040,7 +1039,7 @@ static void horzclose##name##_transition(AVFilterContext *ctx, XFadeContext *s = ctx->priv; \ const int nb_planes = s->nb_planes; \ const int width = out->width; \ - const float h2 = out->height / 2; \ + const float h2 = out->height / 2.0; \ \ for (int y = slice_start; y < slice_end; y++) { \ const float smooth = 1.f + fabsf((y - h2) / h2) - progress * 2.f; \ @@ -2041,6 +2040,9 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; AVFilterLink *inlink0 = ctx->inputs[0]; AVFilterLink *inlink1 = ctx->inputs[1]; + FilterLink *inl0 = ff_filter_link(inlink0); + FilterLink *inl1 = ff_filter_link(inlink1); + FilterLink *ol = ff_filter_link(outlink); XFadeContext *s = ctx->priv; const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink0->format); @@ -2063,19 +2065,19 @@ static int config_output(AVFilterLink *outlink) return AVERROR(EINVAL); } - if (!inlink0->frame_rate.num || !inlink0->frame_rate.den) { + if (!inl0->frame_rate.num || !inl0->frame_rate.den) { av_log(ctx, AV_LOG_ERROR, "The inputs needs to be a constant frame rate; " - "current rate of %d/%d is invalid\n", inlink0->frame_rate.num, inlink0->frame_rate.den); + "current rate of %d/%d is invalid\n", inl0->frame_rate.num, inl0->frame_rate.den); return AVERROR(EINVAL); } - if (inlink0->frame_rate.num != inlink1->frame_rate.num || - inlink0->frame_rate.den != inlink1->frame_rate.den) { + if (inl0->frame_rate.num != inl1->frame_rate.num || + inl0->frame_rate.den != inl1->frame_rate.den) { av_log(ctx, AV_LOG_ERROR, "First input link %s frame rate " "(%d/%d) do not match the corresponding " "second input link %s frame rate (%d/%d)\n", - ctx->input_pads[0].name, inlink0->frame_rate.num, inlink0->frame_rate.den, - ctx->input_pads[1].name, inlink1->frame_rate.num, inlink1->frame_rate.den); + ctx->input_pads[0].name, inl0->frame_rate.num, inl0->frame_rate.den, + ctx->input_pads[1].name, inl1->frame_rate.num, inl1->frame_rate.den); return AVERROR(EINVAL); } @@ -2083,7 +2085,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = inlink0->h; outlink->time_base = inlink0->time_base; outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio; - outlink->frame_rate = inlink0->frame_rate; + ol->frame_rate = inl0->frame_rate; s->depth = pix_desc->comp[0].depth; s->is_rgb = !!(pix_desc->flags & AV_PIX_FMT_FLAG_RGB); diff --git a/libavfilter/vf_xfade_opencl.c b/libavfilter/vf_xfade_opencl.c index 2368c046b..856a300c3 100644 --- a/libavfilter/vf_xfade_opencl.c +++ b/libavfilter/vf_xfade_opencl.c @@ -22,7 +22,6 @@ #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" @@ -216,6 +215,8 @@ static int xfade_opencl_config_output(AVFilterLink *outlink) XFadeOpenCLContext *ctx = avctx->priv; AVFilterLink *inlink0 = avctx->inputs[0]; AVFilterLink *inlink1 = avctx->inputs[1]; + FilterLink *il = ff_filter_link(inlink0); + FilterLink *ol = ff_filter_link(outlink); int err; err = ff_opencl_filter_config_output(outlink); @@ -245,7 +246,7 @@ static int xfade_opencl_config_output(AVFilterLink *outlink) outlink->time_base = inlink0->time_base; outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio; - outlink->frame_rate = inlink0->frame_rate; + ol->frame_rate = il->frame_rate; if (ctx->duration) ctx->duration_pts = av_rescale_q(ctx->duration, AV_TIME_BASE_Q, outlink->time_base); @@ -293,7 +294,9 @@ static int xfade_opencl_activate(AVFilterContext *avctx) if (ctx->first_pts + ctx->offset_pts > ctx->xf[0]->pts) { ctx->xf[0] = NULL; ctx->need_second = 0; - ff_inlink_consume_frame(avctx->inputs[0], &in); + ret = ff_inlink_consume_frame(avctx->inputs[0], &in); + if (ret < 0) + return ret; return ff_filter_frame(outlink, in); } @@ -302,8 +305,14 @@ static int xfade_opencl_activate(AVFilterContext *avctx) } if (ctx->xf[0] && ff_inlink_queued_frames(avctx->inputs[1]) > 0) { - ff_inlink_consume_frame(avctx->inputs[0], &ctx->xf[0]); - ff_inlink_consume_frame(avctx->inputs[1], &ctx->xf[1]); + ret = ff_inlink_consume_frame(avctx->inputs[0], &ctx->xf[0]); + if (ret < 0) + return ret; + ret = ff_inlink_consume_frame(avctx->inputs[1], &ctx->xf[1]); + if (ret < 0) { + av_frame_free(&ctx->xf[0]); + return ret; + } ctx->last_pts = ctx->xf[1]->pts; ctx->pts = ctx->xf[0]->pts; diff --git a/libavfilter/vf_xfade_vulkan.c b/libavfilter/vf_xfade_vulkan.c index be041eaef..94acc5258 100644 --- a/libavfilter/vf_xfade_vulkan.c +++ b/libavfilter/vf_xfade_vulkan.c @@ -22,7 +22,6 @@ #include "vulkan_filter.h" #include "vulkan_spirv.h" #include "filters.h" -#include "internal.h" #include "video.h" #define IN_A 0 @@ -460,6 +459,8 @@ static int config_props_output(AVFilterLink *outlink) XFadeVulkanContext *s = avctx->priv; AVFilterLink *inlink_a = avctx->inputs[IN_A]; AVFilterLink *inlink_b = avctx->inputs[IN_B]; + FilterLink *il = ff_filter_link(inlink_a); + FilterLink *ol = ff_filter_link(outlink); if (inlink_a->w != inlink_b->w || inlink_a->h != inlink_b->h) { av_log(avctx, AV_LOG_ERROR, "First input link %s parameters " @@ -483,7 +484,7 @@ static int config_props_output(AVFilterLink *outlink) s->start_pts = s->inputs_offset_pts = AV_NOPTS_VALUE; outlink->time_base = inlink_a->time_base; - outlink->frame_rate = inlink_a->frame_rate; + ol->frame_rate = il->frame_rate; outlink->sample_aspect_ratio = inlink_a->sample_aspect_ratio; if (s->duration) diff --git a/libavfilter/vf_xmedian.c b/libavfilter/vf_xmedian.c index ebcbea97e..492fd0fe5 100644 --- a/libavfilter/vf_xmedian.c +++ b/libavfilter/vf_xmedian.c @@ -22,12 +22,13 @@ #include "libavutil/avstring.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/qsort.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "framesync.h" #include "video.h" @@ -59,6 +60,10 @@ typedef struct XMedianContext { int (*median_frames)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } XMedianContext; +#define OFFSET(x) offsetof(XMedianContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM +#define TFLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM + static const enum AVPixelFormat pixel_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, @@ -234,9 +239,11 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; XMedianContext *s = ctx->priv; - AVRational frame_rate = ctx->inputs[0]->frame_rate; - AVRational sar = ctx->inputs[0]->sample_aspect_ratio; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(inlink); + FilterLink *ol = ff_filter_link(outlink); + AVRational frame_rate = il->frame_rate; + AVRational sar = ctx->inputs[0]->sample_aspect_ratio; int height = ctx->inputs[0]->h; int width = ctx->inputs[0]->w; FFFrameSyncIn *in; @@ -283,7 +290,7 @@ static int config_output(AVFilterLink *outlink) outlink->w = width; outlink->h = height; - outlink->frame_rate = frame_rate; + ol->frame_rate = frame_rate; outlink->sample_aspect_ratio = sar; if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0) @@ -360,10 +367,6 @@ static av_cold int xmedian_init(AVFilterContext *ctx) return init(ctx); } -#define OFFSET(x) offsetof(XMedianContext, x) -#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM -#define TFLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM - static const AVOption xmedian_options[] = { { "inputs", "set number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64=3}, 3, 255, .flags = FLAGS }, { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, .flags =TFLAGS }, diff --git a/libavfilter/vf_xpsnr.c b/libavfilter/vf_xpsnr.c new file mode 100644 index 000000000..097258bf4 --- /dev/null +++ b/libavfilter/vf_xpsnr.c @@ -0,0 +1,759 @@ +/* + * 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 + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * Calculate the extended perceptually weighted PSNR (XPSNR) between two input videos. + * + * Authors: Christian Helmrich, Lehmann, and Stoffers, Fraunhofer HHI, Berlin, Germany + */ + +#include "libavutil/avstring.h" +#include "libavutil/file_open.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avfilter.h" +#include "drawutils.h" +#include "filters.h" +#include "framesync.h" +#include "xpsnr.h" + +/* XPSNR structure definition */ + +typedef struct XPSNRContext { + /* required basic variables */ + const AVClass *class; + int bpp; /* unpacked */ + int depth; /* packed */ + char comps[4]; + int num_comps; + uint64_t num_frames_64; + unsigned frame_rate; + FFFrameSync fs; + int line_sizes[4]; + int plane_height[4]; + int plane_width[4]; + uint8_t rgba_map[4]; + FILE *stats_file; + char *stats_file_str; + /* XPSNR specific variables */ + double *sse_luma; + double *weights; + AVBufferRef *buf_org [3]; + AVBufferRef *buf_org_m1[3]; + AVBufferRef *buf_org_m2[3]; + AVBufferRef *buf_rec [3]; + uint64_t max_error_64; + double sum_wdist [3]; + double sum_xpsnr [3]; + int and_is_inf[3]; + int is_rgb; + PSNRDSPContext dsp; +} XPSNRContext; + +/* required macro definitions */ + +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM +#define OFFSET(x) offsetof(XPSNRContext, x) +#define XPSNR_GAMMA 2 + +static const AVOption xpsnr_options[] = { + {"stats_file", "Set file where to store per-frame XPSNR information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, + {"f", "Set file where to store per-frame XPSNR information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS}, + { NULL } +}; + +FRAMESYNC_DEFINE_CLASS(xpsnr, XPSNRContext, fs); + +/* XPSNR function definitions */ + +static uint64_t highds(const int x_act, const int y_act, const int w_act, const int h_act, const int16_t *o_m0, const int o) +{ + uint64_t sa_act = 0; + + for (int y = y_act; y < h_act; y += 2) { + for (int x = x_act; x < w_act; x += 2) { + const int f = 12 * ((int)o_m0[ y *o + x ] + (int)o_m0[ y *o + x+1] + (int)o_m0[(y+1)*o + x ] + (int)o_m0[(y+1)*o + x+1]) + - 3 * ((int)o_m0[(y-1)*o + x ] + (int)o_m0[(y-1)*o + x+1] + (int)o_m0[(y+2)*o + x ] + (int)o_m0[(y+2)*o + x+1]) + - 3 * ((int)o_m0[ y *o + x-1] + (int)o_m0[ y *o + x+2] + (int)o_m0[(y+1)*o + x-1] + (int)o_m0[(y+1)*o + x+2]) + - 2 * ((int)o_m0[(y-1)*o + x-1] + (int)o_m0[(y-1)*o + x+2] + (int)o_m0[(y+2)*o + x-1] + (int)o_m0[(y+2)*o + x+2]) + - ((int)o_m0[(y-2)*o + x-1] + (int)o_m0[(y-2)*o + x ] + (int)o_m0[(y-2)*o + x+1] + (int)o_m0[(y-2)*o + x+2] + + (int)o_m0[(y+3)*o + x-1] + (int)o_m0[(y+3)*o + x ] + (int)o_m0[(y+3)*o + x+1] + (int)o_m0[(y+3)*o + x+2] + + (int)o_m0[(y-1)*o + x-2] + (int)o_m0[ y *o + x-2] + (int)o_m0[(y+1)*o + x-2] + (int)o_m0[(y+2)*o + x-2] + + (int)o_m0[(y-1)*o + x+3] + (int)o_m0[ y *o + x+3] + (int)o_m0[(y+1)*o + x+3] + (int)o_m0[(y+2)*o + x+3]); + sa_act += (uint64_t) abs(f); + } + } + return sa_act; +} + +static uint64_t diff1st(const uint32_t w_act, const uint32_t h_act, const int16_t *o_m0, int16_t *o_m1, const int o) +{ + uint64_t ta_act = 0; + + for (uint32_t y = 0; y < h_act; y += 2) { + for (uint32_t x = 0; x < w_act; x += 2) { + const int t = (int)o_m0[y*o + x] + (int)o_m0[y*o + x+1] + (int)o_m0[(y+1)*o + x] + (int)o_m0[(y+1)*o + x+1] + - ((int)o_m1[y*o + x] + (int)o_m1[y*o + x+1] + (int)o_m1[(y+1)*o + x] + (int)o_m1[(y+1)*o + x+1]); + ta_act += (uint64_t) abs(t); + o_m1[y*o + x ] = o_m0[y*o + x ]; o_m1[(y+1)*o + x ] = o_m0[(y+1)*o + x ]; + o_m1[y*o + x+1] = o_m0[y*o + x+1]; o_m1[(y+1)*o + x+1] = o_m0[(y+1)*o + x+1]; + } + } + return (ta_act * XPSNR_GAMMA); +} + +static uint64_t diff2nd(const uint32_t w_act, const uint32_t h_act, const int16_t *o_m0, int16_t *o_m1, int16_t *o_m2, const int o) +{ + uint64_t ta_act = 0; + + for (uint32_t y = 0; y < h_act; y += 2) { + for (uint32_t x = 0; x < w_act; x += 2) { + const int t = (int)o_m0[y*o + x] + (int)o_m0[y*o + x+1] + (int)o_m0[(y+1)*o + x] + (int)o_m0[(y+1)*o + x+1] + - 2 * ((int)o_m1[y*o + x] + (int)o_m1[y*o + x+1] + (int)o_m1[(y+1)*o + x] + (int)o_m1[(y+1)*o + x+1]) + + (int)o_m2[y*o + x] + (int)o_m2[y*o + x+1] + (int)o_m2[(y+1)*o + x] + (int)o_m2[(y+1)*o + x+1]; + ta_act += (uint64_t) abs(t); + o_m2[y*o + x ] = o_m1[y*o + x ]; o_m2[(y+1)*o + x ] = o_m1[(y+1)*o + x ]; + o_m2[y*o + x+1] = o_m1[y*o + x+1]; o_m2[(y+1)*o + x+1] = o_m1[(y+1)*o + x+1]; + o_m1[y*o + x ] = o_m0[y*o + x ]; o_m1[(y+1)*o + x ] = o_m0[(y+1)*o + x ]; + o_m1[y*o + x+1] = o_m0[y*o + x+1]; o_m1[(y+1)*o + x+1] = o_m0[(y+1)*o + x+1]; + } + } + return (ta_act * XPSNR_GAMMA); +} + +static uint64_t sse_line_16bit(const uint8_t *blk_org8, const uint8_t *blk_rec8, int block_width) +{ + const uint16_t *blk_org = (const uint16_t *) blk_org8; + const uint16_t *blk_rec = (const uint16_t *) blk_rec8; + uint64_t sse = 0; /* sum for one pixel line */ + + for (int x = 0; x < block_width; x++) { + const int64_t error = (int64_t) blk_org[x] - (int64_t) blk_rec[x]; + + sse += error * error; + } + + /* sum of squared errors for the pixel line */ + return sse; +} + +static inline uint64_t calc_squared_error(XPSNRContext const *s, + const int16_t *blk_org, const uint32_t stride_org, + const int16_t *blk_rec, const uint32_t stride_rec, + const uint32_t block_width, const uint32_t block_height) +{ + uint64_t sse = 0; /* sum of squared errors */ + + for (uint32_t y = 0; y < block_height; y++) { + sse += s->dsp.sse_line((const uint8_t *) blk_org, (const uint8_t *) blk_rec, (int) block_width); + blk_org += stride_org; + blk_rec += stride_rec; + } + + /* return nonweighted sum of squared errors */ + return sse; +} + +static inline double calc_squared_error_and_weight (XPSNRContext const *s, + const int16_t *pic_org, const uint32_t stride_org, + int16_t *pic_org_m1, int16_t *pic_org_m2, + const int16_t *pic_rec, const uint32_t stride_rec, + const uint32_t offset_x, const uint32_t offset_y, + const uint32_t block_width, const uint32_t block_height, + const uint32_t bit_depth, const uint32_t int_frame_rate, double *ms_act) +{ + const int o = (int) stride_org; + const int r = (int) stride_rec; + const int16_t *o_m0 = pic_org + offset_y * o + offset_x; + int16_t *o_m1 = pic_org_m1 + offset_y * o + offset_x; + int16_t *o_m2 = pic_org_m2 + offset_y * o + offset_x; + const int16_t *r_m0 = pic_rec + offset_y * r + offset_x; + const int b_val = (s->plane_width[0] * s->plane_height[0] > 2048 * 1152 ? 2 : 1); /* threshold is a bit more than HD resolution */ + const int x_act = (offset_x > 0 ? 0 : b_val); + const int y_act = (offset_y > 0 ? 0 : b_val); + const int w_act = (offset_x + block_width < (uint32_t) s->plane_width [0] ? (int) block_width : (int) block_width - b_val); + const int h_act = (offset_y + block_height < (uint32_t) s->plane_height[0] ? (int) block_height : (int) block_height - b_val); + + const double sse = (double) calc_squared_error (s, o_m0, stride_org, + r_m0, stride_rec, + block_width, block_height); + uint64_t sa_act = 0; /* spatial abs. activity */ + uint64_t ta_act = 0; /* temporal abs. activity */ + + if (w_act <= x_act || h_act <= y_act) /* small */ + return sse; + + if (b_val > 1) { /* highpass with downsampling */ + if (w_act > 12) + sa_act = s->dsp.highds_func(x_act, y_act, w_act, h_act, o_m0, o); + else + highds(x_act, y_act, w_act, h_act, o_m0, o); + } else { /* <=HD highpass without downsampling */ + for (int y = y_act; y < h_act; y++) { + for (int x = x_act; x < w_act; x++) { + const int f = 12 * (int)o_m0[y*o + x] - 2 * ((int)o_m0[y*o + x-1] + (int)o_m0[y*o + x+1] + (int)o_m0[(y-1)*o + x] + (int)o_m0[(y+1)*o + x]) + - ((int)o_m0[(y-1)*o + x-1] + (int)o_m0[(y-1)*o + x+1] + (int)o_m0[(y+1)*o + x-1] + (int)o_m0[(y+1)*o + x+1]); + sa_act += (uint64_t) abs(f); + } + } + } + + /* calculate weight (average squared activity) */ + *ms_act = (double) sa_act / ((double) (w_act - x_act) * (double) (h_act - y_act)); + + if (b_val > 1) { /* highpass with downsampling */ + if (int_frame_rate < 32) /* 1st-order diff */ + ta_act = s->dsp.diff1st_func(block_width, block_height, o_m0, o_m1, o); + else /* 2nd-order diff (diff of two diffs) */ + ta_act = s->dsp.diff2nd_func(block_width, block_height, o_m0, o_m1, o_m2, o); + } else { /* <=HD highpass without downsampling */ + if (int_frame_rate < 32) { /* 1st-order diff */ + for (uint32_t y = 0; y < block_height; y++) { + for (uint32_t x = 0; x < block_width; x++) { + const int t = (int)o_m0[y * o + x] - (int)o_m1[y * o + x]; + + ta_act += XPSNR_GAMMA * (uint64_t) abs(t); + o_m1[y * o + x] = o_m0[y * o + x]; + } + } + } else { /* 2nd-order diff (diff of 2 diffs) */ + for (uint32_t y = 0; y < block_height; y++) { + for (uint32_t x = 0; x < block_width; x++) { + const int t = (int)o_m0[y * o + x] - 2 * (int)o_m1[y * o + x] + (int)o_m2[y * o + x]; + + ta_act += XPSNR_GAMMA * (uint64_t) abs(t); + o_m2[y * o + x] = o_m1[y * o + x]; + o_m1[y * o + x] = o_m0[y * o + x]; + } + } + } + } + + /* weight += mean squared temporal activity */ + *ms_act += (double) ta_act / ((double) block_width * (double) block_height); + + /* lower limit, accounts for high-pass gain */ + if (*ms_act < (double) (1 << (bit_depth - 6))) + *ms_act = (double) (1 << (bit_depth - 6)); + + *ms_act *= *ms_act; /* since SSE is squared */ + + /* return nonweighted sum of squared errors */ + return sse; +} + +static inline double get_avg_xpsnr (const double sqrt_wsse_val, const double sum_xpsnr_val, + const uint32_t image_width, const uint32_t image_height, + const uint64_t max_error_64, const uint64_t num_frames_64) +{ + if (num_frames_64 == 0) + return INFINITY; + + if (sqrt_wsse_val >= (double) num_frames_64) { /* square-mean-root average */ + const double avg_dist = sqrt_wsse_val / (double) num_frames_64; + const uint64_t num64 = (uint64_t) image_width * (uint64_t) image_height * max_error_64; + + return 10.0 * log10((double) num64 / ((double) avg_dist * (double) avg_dist)); + } + + return sum_xpsnr_val / (double) num_frames_64; /* older log-domain average */ +} + +static int get_wsse(AVFilterContext *ctx, int16_t **org, int16_t **org_m1, int16_t **org_m2, int16_t **rec, + uint64_t *const wsse64) +{ + XPSNRContext *const s = ctx->priv; + const uint32_t w = s->plane_width [0]; /* luma image width in pixels */ + const uint32_t h = s->plane_height[0];/* luma image height in pixels */ + const double r = (double)(w * h) / (3840.0 * 2160.0); /* UHD ratio */ + const uint32_t b = FFMAX(0, 4 * (int32_t) (32.0 * sqrt(r) + + 0.5)); /* block size, integer multiple of 4 for SIMD */ + const uint32_t w_blk = (w + b - 1) / b; /* luma width in units of blocks */ + const double avg_act = sqrt(16.0 * (double) (1 << (2 * s->depth - 9)) / sqrt(FFMAX(0.00001, + r))); /* the sqrt(a_pic) */ + const int *stride_org = (s->bpp == 1 ? s->plane_width : s->line_sizes); + uint32_t x, y, idx_blk = 0; /* the "16.0" above is due to fixed-point code */ + double *const sse_luma = s->sse_luma; + double *const weights = s->weights; + int c; + + if (!wsse64 || (s->depth < 6) || (s->depth > 16) || (s->num_comps <= 0) || + (s->num_comps > 3) || (w == 0) || (h == 0)) { + av_log(ctx, AV_LOG_ERROR, "Error in XPSNR routine: invalid argument(s).\n"); + return AVERROR(EINVAL); + } + if (!weights || (b >= 4 && !sse_luma)) { + av_log(ctx, AV_LOG_ERROR, "Failed to allocate temporary block memory.\n"); + return AVERROR(ENOMEM); + } + + if (b >= 4) { + const int16_t *p_org = org[0]; + const uint32_t s_org = stride_org[0] / s->bpp; + const int16_t *p_rec = rec[0]; + const uint32_t s_rec = s->plane_width[0]; + int16_t *p_org_m1 = org_m1[0]; /* pixel */ + int16_t *p_org_m2 = org_m2[0]; /* memory */ + double wsse_luma = 0.0; + + for (y = 0; y < h; y += b) { /* calculate block SSE and perceptual weights */ + const uint32_t block_height = (y + b > h ? h - y : b); + + for (x = 0; x < w; x += b, idx_blk++) { + const uint32_t block_width = (x + b > w ? w - x : b); + double ms_act = 1.0, ms_act_prev = 0.0; + + sse_luma[idx_blk] = calc_squared_error_and_weight(s, p_org, s_org, + p_org_m1, p_org_m2, + p_rec, s_rec, + x, y, + block_width, block_height, + s->depth, s->frame_rate, &ms_act); + weights[idx_blk] = 1.0 / sqrt(ms_act); + + if (w * h <= 640 * 480) { /* in-line "min-smoothing" as in paper */ + if (x == 0) /* first column */ + ms_act_prev = (idx_blk > 1 ? weights[idx_blk - 2] : 0); + else /* after first column */ + ms_act_prev = (x > b ? FFMAX(weights[idx_blk - 2], weights[idx_blk]) : weights[idx_blk]); + + if (idx_blk > w_blk) /* after the first row and first column */ + ms_act_prev = FFMAX(ms_act_prev, weights[idx_blk - 1 - w_blk]); /* min (L, T) */ + if ((idx_blk > 0) && (weights[idx_blk - 1] > ms_act_prev)) + weights[idx_blk - 1] = ms_act_prev; + + if ((x + b >= w) && (y + b >= h) && (idx_blk > w_blk)) { /* last block in picture */ + ms_act_prev = FFMAX(weights[idx_blk - 1], weights[idx_blk - w_blk]); + if (weights[idx_blk] > ms_act_prev) + weights[idx_blk] = ms_act_prev; + } + } + } /* for x */ + } /* for y */ + + for (y = idx_blk = 0; y < h; y += b) { /* calculate sum for luma (Y) XPSNR */ + for (x = 0; x < w; x += b, idx_blk++) { + wsse_luma += sse_luma[idx_blk] * weights[idx_blk]; + } + } + wsse64[0] = (wsse_luma <= 0.0 ? 0 : (uint64_t) (wsse_luma * avg_act + 0.5)); + } /* b >= 4 */ + + for (c = 0; c < s->num_comps; c++) { /* finalize WSSE value for each component */ + const int16_t *p_org = org[c]; + const uint32_t s_org = stride_org[c] / s->bpp; + const int16_t *p_rec = rec[c]; + const uint32_t s_rec = s->plane_width[c]; + const uint32_t w_pln = s->plane_width[c]; + const uint32_t h_pln = s->plane_height[c]; + + if (b < 4) /* picture is too small for XPSNR, calculate nonweighted PSNR */ + wsse64[c] = calc_squared_error (s, p_org, s_org, + p_rec, s_rec, + w_pln, h_pln); + else if (c > 0) { /* b >= 4 so Y XPSNR has already been calculated above */ + const uint32_t bx = (b * w_pln) / w; + const uint32_t by = (b * h_pln) / h; /* up to chroma downsampling by 4 */ + double wsse_chroma = 0.0; + + for (y = idx_blk = 0; y < h_pln; y += by) { /* calc chroma (Cb/Cr) XPSNR */ + const uint32_t block_height = (y + by > h_pln ? h_pln - y : by); + + for (x = 0; x < w_pln; x += bx, idx_blk++) { + const uint32_t block_width = (x + bx > w_pln ? w_pln - x : bx); + + wsse_chroma += (double) calc_squared_error (s, p_org + y * s_org + x, s_org, + p_rec + y * s_rec + x, s_rec, + block_width, block_height) * weights[idx_blk]; + } + } + wsse64[c] = (wsse_chroma <= 0.0 ? 0 : (uint64_t) (wsse_chroma * avg_act + 0.5)); + } + } /* for c */ + + return 0; +} + +static void set_meta(AVDictionary **metadata, const char *key, char comp, float d) +{ + char value[128]; + snprintf(value, sizeof(value), "%f", d); + if (comp) { + char key2[128]; + snprintf(key2, sizeof(key2), "%s%c", key, comp); + av_dict_set(metadata, key2, value, 0); + } else { + av_dict_set(metadata, key, value, 0); + } +} + +static int do_xpsnr(FFFrameSync *fs) +{ + AVFilterContext *ctx = fs->parent; + XPSNRContext *const s = ctx->priv; + const uint32_t w = s->plane_width [0]; /* luma image width in pixels */ + const uint32_t h = s->plane_height[0]; /* luma image height in pixels */ + const uint32_t b = FFMAX(0, 4 * (int32_t) (32.0 * sqrt((double) (w * h) / (3840.0 * 2160.0)) + 0.5)); /* block size */ + const uint32_t w_blk = (w + b - 1) / b; /* luma width in units of blocks */ + const uint32_t h_blk = (h + b - 1) / b; /* luma height in units of blocks */ + AVFrame *master, *ref = NULL; + int16_t *porg [3]; + int16_t *porg_m1[3]; + int16_t *porg_m2[3]; + int16_t *prec [3]; + uint64_t wsse64 [3] = {0, 0, 0}; + double cur_xpsnr[3] = {INFINITY, INFINITY, INFINITY}; + int c, ret_value; + AVDictionary **metadata; + + if ((ret_value = ff_framesync_dualinput_get(fs, &master, &ref)) < 0) + return ret_value; + if (ctx->is_disabled || !ref) + return ff_filter_frame(ctx->outputs[0], master); + metadata = &master->metadata; + + /* prepare XPSNR calculations: allocate temporary picture and block memory */ + if (!s->sse_luma) + s->sse_luma = av_malloc_array(w_blk * h_blk, sizeof(double)); + if (!s->weights) + s->weights = av_malloc_array(w_blk * h_blk, sizeof(double)); + + for (c = 0; c < s->num_comps; c++) { /* create temporal org buffer memory */ + s->line_sizes[c] = master->linesize[c]; + + if (c == 0) { /* luma ch. */ + const int stride_org_bpp = (s->bpp == 1 ? s->plane_width[c] : s->line_sizes[c] / s->bpp); + + if (!s->buf_org_m1[c]) + s->buf_org_m1[c] = av_buffer_allocz(stride_org_bpp * s->plane_height[c] * sizeof(int16_t)); + if (!s->buf_org_m2[c]) + s->buf_org_m2[c] = av_buffer_allocz(stride_org_bpp * s->plane_height[c] * sizeof(int16_t)); + + porg_m1[c] = (int16_t *) s->buf_org_m1[c]->data; + porg_m2[c] = (int16_t *) s->buf_org_m2[c]->data; + } + } + + if (s->bpp == 1) { /* 8 bit */ + for (c = 0; c < s->num_comps; c++) { /* allocate org/rec buffer memory */ + const int m = s->line_sizes[c]; /* master stride */ + const int r = ref->linesize[c]; /* ref/c stride */ + const int o = s->plane_width[c]; /* XPSNR stride */ + + if (!s->buf_org[c]) + s->buf_org[c] = av_buffer_allocz(s->plane_width[c] * s->plane_height[c] * sizeof(int16_t)); + if (!s->buf_rec[c]) + s->buf_rec[c] = av_buffer_allocz(s->plane_width[c] * s->plane_height[c] * sizeof(int16_t)); + + porg[c] = (int16_t *) s->buf_org[c]->data; + prec[c] = (int16_t *) s->buf_rec[c]->data; + + for (int y = 0; y < s->plane_height[c]; y++) { + for (int x = 0; x < s->plane_width[c]; x++) { + porg[c][y * o + x] = (int16_t) master->data[c][y * m + x]; + prec[c][y * o + x] = (int16_t) ref->data[c][y * r + x]; + } + } + } + } else { /* 10, 12, 14 bit */ + for (c = 0; c < s->num_comps; c++) { + porg[c] = (int16_t *) master->data[c]; + prec[c] = (int16_t *) ref->data[c]; + } + } + + /* extended perceptually weighted peak signal-to-noise ratio (XPSNR) value */ + ret_value = get_wsse(ctx, (int16_t **) &porg, (int16_t **) &porg_m1, (int16_t **) &porg_m2, + (int16_t **) &prec, wsse64); + if ( ret_value < 0 ) + return ret_value; /* an error here means something went wrong earlier! */ + + for (c = 0; c < s->num_comps; c++) { + const double sqrt_wsse = sqrt((double) wsse64[c]); + + cur_xpsnr[c] = get_avg_xpsnr (sqrt_wsse, INFINITY, + s->plane_width[c], s->plane_height[c], + s->max_error_64, 1 /* single frame */); + s->sum_wdist[c] += sqrt_wsse; + s->sum_xpsnr[c] += cur_xpsnr[c]; + s->and_is_inf[c] &= isinf(cur_xpsnr[c]); + } + s->num_frames_64++; + + for (int j = 0; j < s->num_comps; j++) { + int c = s->is_rgb ? s->rgba_map[j] : j; + set_meta(metadata, "lavfi.xpsnr.xpsnr.", s->comps[j], cur_xpsnr[c]); + } + + if (s->stats_file) { /* print out frame- and component-wise XPSNR averages */ + fprintf(s->stats_file, "n: %4"PRId64"", s->num_frames_64); + + for (c = 0; c < s->num_comps; c++) + fprintf(s->stats_file, " XPSNR %c: %3.4f", s->comps[c], cur_xpsnr[c]); + fprintf(s->stats_file, "\n"); + } + + return ff_filter_frame(ctx->outputs[0], master); +} + +static av_cold int init(AVFilterContext *ctx) +{ + XPSNRContext *const s = ctx->priv; + int c; + + if (s->stats_file_str) { + if (!strcmp(s->stats_file_str, "-")) /* no stats file, so use stdout */ + s->stats_file = stdout; + else { + s->stats_file = avpriv_fopen_utf8(s->stats_file_str, "w"); + + if (!s->stats_file) { + const int err = AVERROR(errno); + char buf[128]; + + av_strerror(err, buf, sizeof(buf)); + av_log(ctx, AV_LOG_ERROR, "Could not open statistics file %s: %s\n", s->stats_file_str, buf); + return err; + } + } + } + + s->sse_luma = NULL; + s->weights = NULL; + + for (c = 0; c < 3; c++) { /* initialize XPSNR data of each color component */ + s->buf_org [c] = NULL; + s->buf_org_m1[c] = NULL; + s->buf_org_m2[c] = NULL; + s->buf_rec [c] = NULL; + s->sum_wdist [c] = 0.0; + s->sum_xpsnr [c] = 0.0; + s->and_is_inf[c] = 1; + } + + s->fs.on_event = do_xpsnr; + + return 0; +} + +static const enum AVPixelFormat xpsnr_formats[] = { + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, +#define PF_NOALPHA(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf +#define PF_ALPHA(suf) AV_PIX_FMT_YUVA420##suf, AV_PIX_FMT_YUVA422##suf, AV_PIX_FMT_YUVA444##suf +#define PF(suf) PF_NOALPHA(suf), PF_ALPHA(suf) + PF(P), PF(P9), PF(P10), PF_NOALPHA(P12), PF_NOALPHA(P14), PF(P16), + AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_NONE +}; + +static int config_input_ref(AVFilterLink *inlink) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + AVFilterContext *ctx = inlink->dst; + XPSNRContext *const s = ctx->priv; + FilterLink *il = ff_filter_link(inlink); + + if ((ctx->inputs[0]->w != ctx->inputs[1]->w) || + (ctx->inputs[0]->h != ctx->inputs[1]->h)) { + av_log(ctx, AV_LOG_ERROR, "Width and height of the input videos must match.\n"); + return AVERROR(EINVAL); + } + if (ctx->inputs[0]->format != ctx->inputs[1]->format) { + av_log(ctx, AV_LOG_ERROR, "The input videos must be of the same pixel format.\n"); + return AVERROR(EINVAL); + } + + s->bpp = (desc->comp[0].depth <= 8 ? 1 : 2); + s->depth = desc->comp[0].depth; + s->max_error_64 = (1 << s->depth) - 1; /* conventional limit */ + s->max_error_64 *= s->max_error_64; + + s->frame_rate = il->frame_rate.num / il->frame_rate.den; + + s->num_comps = (desc->nb_components > 3 ? 3 : desc->nb_components); + + s->is_rgb = (ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0); + s->comps[0] = (s->is_rgb ? 'r' : 'y'); + s->comps[1] = (s->is_rgb ? 'g' : 'u'); + s->comps[2] = (s->is_rgb ? 'b' : 'v'); + s->comps[3] = 'a'; + + s->plane_width [1] = s->plane_width [2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->plane_width [0] = s->plane_width [3] = inlink->w; + s->plane_height[1] = s->plane_height[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->plane_height[0] = s->plane_height[3] = inlink->h; + + s->dsp.sse_line = sse_line_16bit; + s->dsp.highds_func = highds; /* initialize filtering methods */ + s->dsp.diff1st_func = diff1st; + s->dsp.diff2nd_func = diff2nd; +#if ARCH_X86 + ff_xpsnr_init_x86(&s->dsp, 15); /* initialize x86 SSE method */ +#endif + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + XPSNRContext *s = ctx->priv; + AVFilterLink *mainlink = ctx->inputs[0]; + FilterLink *il = ff_filter_link(mainlink); + FilterLink *ol = ff_filter_link(outlink); + int ret; + + if ((ret = ff_framesync_init_dualinput(&s->fs, ctx)) < 0) + return ret; + + outlink->w = mainlink->w; + outlink->h = mainlink->h; + outlink->time_base = mainlink->time_base; + outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio; + ol->frame_rate = il->frame_rate; + + if ((ret = ff_framesync_configure(&s->fs)) < 0) + return ret; + + outlink->time_base = s->fs.time_base; + + if (av_cmp_q(mainlink->time_base, outlink->time_base) || + av_cmp_q(ctx->inputs[1]->time_base, outlink->time_base)) + av_log(ctx, AV_LOG_WARNING, "not matching timebases found between first input: %d/%d and second input %d/%d, results may be incorrect!\n", + mainlink->time_base.num, mainlink->time_base.den, + ctx->inputs[1]->time_base.num, ctx->inputs[1]->time_base.den); + + return 0; +} + +static int activate(AVFilterContext *ctx) +{ + XPSNRContext *s = ctx->priv; + + return ff_framesync_activate(&s->fs); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + XPSNRContext *const s = ctx->priv; + int c; + + if (s->num_frames_64 > 0) { /* print out overall component-wise mean XPSNR */ + const double xpsnr_luma = get_avg_xpsnr(s->sum_wdist[0], s->sum_xpsnr[0], + s->plane_width[0], s->plane_height[0], + s->max_error_64, s->num_frames_64); + double xpsnr_min = xpsnr_luma; + + /* luma */ + av_log(ctx, AV_LOG_INFO, "XPSNR %c: %3.4f", s->comps[0], xpsnr_luma); + if (s->stats_file) { + fprintf(s->stats_file, "\nXPSNR average, %"PRId64" frames", s->num_frames_64); + fprintf(s->stats_file, " %c: %3.4f", s->comps[0], xpsnr_luma); + } + /* chroma */ + for (c = 1; c < s->num_comps; c++) { + const double xpsnr_chroma = get_avg_xpsnr(s->sum_wdist[c], s->sum_xpsnr[c], + s->plane_width[c], s->plane_height[c], + s->max_error_64, s->num_frames_64); + if (xpsnr_min > xpsnr_chroma) + xpsnr_min = xpsnr_chroma; + + av_log(ctx, AV_LOG_INFO, " %c: %3.4f", s->comps[c], xpsnr_chroma); + if (s->stats_file && s->stats_file != stdout) + fprintf(s->stats_file, " %c: %3.4f", s->comps[c], xpsnr_chroma); + } + /* print out line break, and minimum XPSNR across the color components */ + if (s->num_comps > 1) { + av_log(ctx, AV_LOG_INFO, " (minimum: %3.4f)\n", xpsnr_min); + if (s->stats_file && s->stats_file != stdout) + fprintf(s->stats_file, " (minimum: %3.4f)\n", xpsnr_min); + } else { + av_log(ctx, AV_LOG_INFO, "\n"); + if (s->stats_file && s->stats_file != stdout) + fprintf(s->stats_file, "\n"); + } + } + + ff_framesync_uninit(&s->fs); /* free temporary picture or block buf memory */ + + if (s->stats_file && s->stats_file != stdout) + fclose(s->stats_file); + + av_freep(&s->sse_luma); + av_freep(&s->weights ); + + for (c = 0; c < s->num_comps; c++) { /* free extra temporal org buf memory */ + if(s->buf_org_m1[c]) + av_freep(s->buf_org_m1[c]); + if(s->buf_org_m2[c]) + av_freep(s->buf_org_m2[c]); + } + if (s->bpp == 1) { /* 8 bit */ + for (c = 0; c < s->num_comps; c++) { /* and org/rec picture buf memory */ + if(s->buf_org_m2[c]) + av_freep(s->buf_org[c]); + if(s->buf_rec[c]) + av_freep(s->buf_rec[c]); + } + } +} + +static const AVFilterPad xpsnr_inputs[] = { + { + .name = "main", + .type = AVMEDIA_TYPE_VIDEO, + }, { + .name = "reference", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input_ref, + } +}; + +static const AVFilterPad xpsnr_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + } +}; + +const AVFilter ff_vf_xpsnr = { + .name = "xpsnr", + .description = NULL_IF_CONFIG_SMALL("Calculate the extended perceptually weighted peak signal-to-noise ratio (XPSNR) between two video streams."), + .preinit = xpsnr_framesync_preinit, + .init = init, + .uninit = uninit, + .activate = activate, + .priv_size = sizeof(XPSNRContext), + .priv_class = &xpsnr_class, + FILTER_INPUTS (xpsnr_inputs), + FILTER_OUTPUTS(xpsnr_outputs), + FILTER_PIXFMTS_ARRAY(xpsnr_formats), + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_METADATA_ONLY +}; diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c index aa5ca4a88..2bf58aa48 100644 --- a/libavfilter/vf_yadif.c +++ b/libavfilter/vf_yadif.c @@ -22,7 +22,7 @@ #include "libavutil/common.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "yadif.h" typedef struct ThreadData { diff --git a/libavfilter/vf_yadif_cuda.c b/libavfilter/vf_yadif_cuda.c index 79080e71c..257523788 100644 --- a/libavfilter/vf_yadif_cuda.c +++ b/libavfilter/vf_yadif_cuda.c @@ -22,7 +22,8 @@ #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" #include "libavutil/cuda_check.h" -#include "internal.h" + +#include "filters.h" #include "yadif.h" #include "cuda/load_helper.h" @@ -209,16 +210,17 @@ static av_cold void deint_cuda_uninit(AVFilterContext *ctx) static int config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; DeintCUDAContext *s = ctx->priv; - if (!inlink->hw_frames_ctx) { + if (!l->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "A hardware frames reference is " "required to associate the processing device.\n"); return AVERROR(EINVAL); } - s->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx); + s->input_frames_ref = av_buffer_ref(l->hw_frames_ctx); if (!s->input_frames_ref) { av_log(ctx, AV_LOG_ERROR, "A input frames reference create " "failed.\n"); @@ -231,6 +233,7 @@ static int config_input(AVFilterLink *inlink) static int config_output(AVFilterLink *link) { + FilterLink *l = ff_filter_link(link); AVHWFramesContext *output_frames; AVFilterContext *ctx = link->src; DeintCUDAContext *s = ctx->priv; @@ -249,15 +252,15 @@ static int config_output(AVFilterLink *link) s->hwctx = ((AVHWDeviceContext*)s->device_ref->data)->hwctx; cu = s->hwctx->internal->cuda_dl; - link->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref); - if (!link->hw_frames_ctx) { + l->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref); + if (!l->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context " "for output.\n"); ret = AVERROR(ENOMEM); goto exit; } - output_frames = (AVHWFramesContext*)link->hw_frames_ctx->data; + output_frames = (AVHWFramesContext*)l->hw_frames_ctx->data; output_frames->format = AV_PIX_FMT_CUDA; output_frames->sw_format = s->input_frames->sw_format; @@ -270,7 +273,7 @@ static int config_output(AVFilterLink *link) if (ret < 0) goto exit; - ret = av_hwframe_ctx_init(link->hw_frames_ctx); + ret = av_hwframe_ctx_init(l->hw_frames_ctx); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Failed to initialise CUDA frame " "context for output: %d\n", ret); diff --git a/libavfilter/vf_yadif_videotoolbox.m b/libavfilter/vf_yadif_videotoolbox.m index c47d3edfb..09520db35 100644 --- a/libavfilter/vf_yadif_videotoolbox.m +++ b/libavfilter/vf_yadif_videotoolbox.m @@ -19,11 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "internal.h" +#include "filters.h" #include "metal/utils.h" #include "yadif.h" #include "libavutil/avassert.h" #include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_videotoolbox.h" #include "libavutil/objc.h" #include @@ -288,16 +289,17 @@ static av_cold int yadif_videotoolbox_init(AVFilterContext *ctx) static int do_config_input(AVFilterLink *inlink) API_AVAILABLE(macos(10.11), ios(8.0)) { + FilterLink *l = ff_filter_link(inlink); AVFilterContext *ctx = inlink->dst; YADIFVTContext *s = ctx->priv; - if (!inlink->hw_frames_ctx) { + if (!l->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "A hardware frames reference is " "required to associate the processing device.\n"); return AVERROR(EINVAL); } - s->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx); + s->input_frames_ref = av_buffer_ref(l->hw_frames_ctx); if (!s->input_frames_ref) { av_log(ctx, AV_LOG_ERROR, "A input frames reference create " "failed.\n"); @@ -321,7 +323,9 @@ static int config_input(AVFilterLink *inlink) static int do_config_output(AVFilterLink *link) API_AVAILABLE(macos(10.11), ios(8.0)) { - AVHWFramesContext *output_frames; + FilterLink *l = ff_filter_link(link); + FilterLink *il = ff_filter_link(link->src->inputs[0]); + AVHWFramesContext *output_frames, *input_frames; AVFilterContext *ctx = link->src; YADIFVTContext *s = ctx->priv; YADIFContext *y = &s->yadif; @@ -335,26 +339,28 @@ static int do_config_output(AVFilterLink *link) API_AVAILABLE(macos(10.11), ios( return AVERROR(ENOMEM); } - link->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref); - if (!link->hw_frames_ctx) { + l->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref); + if (!l->hw_frames_ctx) { av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context " "for output.\n"); ret = AVERROR(ENOMEM); goto exit; } - output_frames = (AVHWFramesContext*)link->hw_frames_ctx->data; + input_frames = (AVHWFramesContext*)il->hw_frames_ctx->data; + output_frames = (AVHWFramesContext*)l->hw_frames_ctx->data; output_frames->format = AV_PIX_FMT_VIDEOTOOLBOX; output_frames->sw_format = s->input_frames->sw_format; output_frames->width = ctx->inputs[0]->w; output_frames->height = ctx->inputs[0]->h; + ((AVVTFramesContext *)output_frames->hwctx)->color_range = ((AVVTFramesContext *)input_frames->hwctx)->color_range; ret = ff_filter_init_hw_frames(ctx, link, 10); if (ret < 0) goto exit; - ret = av_hwframe_ctx_init(link->hw_frames_ctx); + ret = av_hwframe_ctx_init(l->hw_frames_ctx); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Failed to initialise VideoToolbox frame " "context for output: %d\n", ret); diff --git a/libavfilter/vf_yaepblur.c b/libavfilter/vf_yaepblur.c index b39738b57..513404734 100644 --- a/libavfilter/vf_yaepblur.c +++ b/libavfilter/vf_yaepblur.c @@ -27,10 +27,11 @@ * Anal. Mach. Intell. PAMI-2, 1980." */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/imgutils.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct YAEPContext { diff --git a/libavfilter/vf_zoompan.c b/libavfilter/vf_zoompan.c index e729bda56..8a4d57b7a 100644 --- a/libavfilter/vf_zoompan.c +++ b/libavfilter/vf_zoompan.c @@ -23,7 +23,6 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "filters.h" -#include "internal.h" #include "video.h" #include "libswscale/swscale.h" @@ -125,13 +124,14 @@ static av_cold int init(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; + FilterLink *l = ff_filter_link(outlink); ZPContext *s = ctx->priv; int ret; outlink->w = s->w; outlink->h = s->h; outlink->time_base = av_inv_q(s->framerate); - outlink->frame_rate = s->framerate; + l->frame_rate = s->framerate; s->desc = av_pix_fmt_desc_get(outlink->format); s->finished = 1; @@ -155,6 +155,7 @@ static int output_single_frame(AVFilterContext *ctx, AVFrame *in, double *var_va { ZPContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); AVFilterLink *inlink = ctx->inputs[0]; int64_t pts = s->frame_count; int k, x, y, w, h, ret = 0; @@ -171,7 +172,7 @@ static int output_single_frame(AVFilterContext *ctx, AVFrame *in, double *var_va var_values[VAR_OUT_TIME] = pts * av_q2d(outlink->time_base); var_values[VAR_TIME] = var_values[VAR_OT] = var_values[VAR_OUT_TIME]; var_values[VAR_FRAME] = i; - var_values[VAR_ON] = outlink->frame_count_in; + var_values[VAR_ON] = outl->frame_count_in; *zoom = av_expr_eval(s->zoom_expr, var_values, NULL); @@ -259,7 +260,9 @@ static int activate(AVFilterContext *ctx) { ZPContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; + FilterLink *inl = ff_filter_link(inlink); AVFilterLink *outlink = ctx->outputs[0]; + FilterLink *outl = ff_filter_link(outlink); int status, ret = 0; int64_t pts; @@ -282,8 +285,8 @@ static int activate(AVFilterContext *ctx) s->var_values[VAR_IN_H] = s->var_values[VAR_IH] = s->in->height; s->var_values[VAR_OUT_W] = s->var_values[VAR_OW] = s->w; s->var_values[VAR_OUT_H] = s->var_values[VAR_OH] = s->h; - s->var_values[VAR_IN] = inlink->frame_count_out - 1; - s->var_values[VAR_ON] = outlink->frame_count_in; + s->var_values[VAR_IN] = inl->frame_count_out - 1; + s->var_values[VAR_ON] = outl->frame_count_in; s->var_values[VAR_PX] = s->x; s->var_values[VAR_PY] = s->y; s->var_values[VAR_X] = 0; diff --git a/libavfilter/vf_zscale.c b/libavfilter/vf_zscale.c index ad8fdb6eb..afd22ce6c 100644 --- a/libavfilter/vf_zscale.c +++ b/libavfilter/vf_zscale.c @@ -31,18 +31,17 @@ #include #include "avfilter.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" -#include "libavutil/avstring.h" #include "libavutil/eval.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" -#include "libavutil/imgutils.h" #define ZIMG_ALIGNMENT 64 #define MIN_TILESIZE 64 @@ -109,11 +108,6 @@ typedef struct ZScaleContext { char *w_expr; ///< width expression string char *h_expr; ///< height expression string - int out_h_chr_pos; - int out_v_chr_pos; - int in_h_chr_pos; - int in_v_chr_pos; - int first_time; int force_original_aspect_ratio; @@ -632,9 +626,12 @@ static int graphs_build(AVFrame *in, AVFrame *out, const AVPixFmtDescriptor *des if (ret) return print_zimg_error(ctx); + if (size > (SIZE_MAX - ZIMG_ALIGNMENT)) + return AVERROR(ENOMEM); + if (s->tmp[job_nr]) av_freep(&s->tmp[job_nr]); - s->tmp[job_nr] = av_calloc(size, 1); + s->tmp[job_nr] = av_mallocz(size + ZIMG_ALIGNMENT); if (!s->tmp[job_nr]) return AVERROR(ENOMEM); @@ -661,27 +658,19 @@ static int graphs_build(AVFrame *in, AVFrame *out, const AVPixFmtDescriptor *des return 0; } -static int realign_frame(const AVPixFmtDescriptor *desc, AVFrame **frame, int needs_copy) +static int realign_frame(AVFilterLink *link, const AVPixFmtDescriptor *desc, AVFrame **frame, int needs_copy) { AVFrame *aligned = NULL; int ret = 0, plane, planes; /* Realign any unaligned input frame. */ - planes = av_pix_fmt_count_planes(desc->nb_components); + planes = av_pix_fmt_count_planes((*frame)->format); for (plane = 0; plane < planes; plane++) { int p = desc->comp[plane].plane; if ((uintptr_t)(*frame)->data[p] % ZIMG_ALIGNMENT || (*frame)->linesize[p] % ZIMG_ALIGNMENT) { - if (!(aligned = av_frame_alloc())) { - ret = AVERROR(ENOMEM); - goto fail; - } - - aligned->format = (*frame)->format; - aligned->width = (*frame)->width; - aligned->height = (*frame)->height; - - if ((ret = av_frame_get_buffer(aligned, ZIMG_ALIGNMENT)) < 0) - goto fail; + aligned = ff_default_get_video_buffer2(link, (*frame)->width, (*frame)->height, ZIMG_ALIGNMENT); + if (!aligned) + return AVERROR(ENOMEM); if (needs_copy && (ret = av_frame_copy(aligned, *frame)) < 0) goto fail; @@ -754,7 +743,9 @@ static int filter_slice(AVFilterContext *ctx, void *data, int job_nr, int n_jobs } if (!s->graph[job_nr]) return AVERROR(EINVAL); - ret = zimg_filter_graph_process(s->graph[job_nr], &src_buf, &dst_buf, s->tmp[job_nr], 0, 0, 0, 0); + ret = zimg_filter_graph_process(s->graph[job_nr], &src_buf, &dst_buf, + (uint8_t *)FFALIGN((uintptr_t)s->tmp[job_nr], ZIMG_ALIGNMENT), + 0, 0, 0, 0); if (ret) return print_zimg_error(ctx); @@ -769,7 +760,9 @@ static int filter_slice(AVFilterContext *ctx, void *data, int job_nr, int n_jobs if (!s->alpha_graph[job_nr]) return AVERROR(EINVAL); - ret = zimg_filter_graph_process(s->alpha_graph[job_nr], &src_buf, &dst_buf, s->tmp[job_nr], 0, 0, 0, 0); + ret = zimg_filter_graph_process(s->alpha_graph[job_nr], &src_buf, &dst_buf, + (uint8_t *)FFALIGN((uintptr_t)s->tmp[job_nr], ZIMG_ALIGNMENT), + 0, 0, 0, 0); if (ret) return print_zimg_error(ctx); } @@ -806,20 +799,17 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) (s->src_format.pixel_type !=s->dst_format.pixel_type) || (s->src_format.transfer_characteristics !=s->dst_format.transfer_characteristics) ){ - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + out = ff_default_get_video_buffer2(outlink, outlink->w, outlink->h, ZIMG_ALIGNMENT); if (!out) { ret = AVERROR(ENOMEM); goto fail; } - if ((ret = realign_frame(odesc, &out, 0)) < 0) - goto fail; - av_frame_copy_props(out, in); out->colorspace = outlink->colorspace; out->color_range = outlink->color_range; - if ((ret = realign_frame(desc, &in, 1)) < 0) + if ((ret = realign_frame(link, desc, &in, 1)) < 0) goto fail; snprintf(buf, sizeof(buf)-1, "%d", outlink->w); diff --git a/libavfilter/video.c b/libavfilter/video.c index bbd119383..1de7f2ef5 100644 --- a/libavfilter/video.c +++ b/libavfilter/video.c @@ -26,12 +26,12 @@ #include "libavutil/buffer.h" #include "libavutil/cpu.h" #include "libavutil/hwcontext.h" -#include "libavutil/imgutils.h" +#include "libavutil/pixfmt.h" #include "avfilter.h" #include "avfilter_internal.h" +#include "filters.h" #include "framepool.h" -#include "internal.h" #include "video.h" const AVFilterPad ff_video_default_filterpad[1] = { @@ -55,15 +55,15 @@ AVFrame *ff_default_get_video_buffer2(AVFilterLink *link, int w, int h, int alig int pool_align = 0; enum AVPixelFormat pool_format = AV_PIX_FMT_NONE; - if (link->hw_frames_ctx && - ((AVHWFramesContext*)link->hw_frames_ctx->data)->format == link->format) { + if (li->l.hw_frames_ctx && + ((AVHWFramesContext*)li->l.hw_frames_ctx->data)->format == link->format) { int ret; frame = av_frame_alloc(); if (!frame) return NULL; - ret = av_hwframe_get_buffer(link->hw_frames_ctx, frame, 0); + ret = av_hwframe_get_buffer(li->l.hw_frames_ctx, frame, 0); if (ret < 0) av_frame_free(&frame); @@ -71,8 +71,10 @@ AVFrame *ff_default_get_video_buffer2(AVFilterLink *link, int w, int h, int alig } if (!li->frame_pool) { - li->frame_pool = ff_frame_pool_video_init(av_buffer_allocz, w, h, - link->format, align); + li->frame_pool = ff_frame_pool_video_init(CONFIG_MEMORY_POISONING + ? NULL + : av_buffer_allocz, + w, h, link->format, align); if (!li->frame_pool) return NULL; } else { @@ -86,8 +88,10 @@ AVFrame *ff_default_get_video_buffer2(AVFilterLink *link, int w, int h, int alig pool_format != link->format || pool_align != align) { ff_frame_pool_uninit(&li->frame_pool); - li->frame_pool = ff_frame_pool_video_init(av_buffer_allocz, w, h, - link->format, align); + li->frame_pool = ff_frame_pool_video_init(CONFIG_MEMORY_POISONING + ? NULL + : av_buffer_allocz, + w, h, link->format, align); if (!li->frame_pool) return NULL; } diff --git a/libavfilter/video.h b/libavfilter/video.h index 81331c319..f44d3445d 100644 --- a/libavfilter/video.h +++ b/libavfilter/video.h @@ -22,7 +22,7 @@ #define AVFILTER_VIDEO_H #include "avfilter.h" -#include "internal.h" +#include "filters.h" /** * An AVFilterPad array whose only entry has name "default" @@ -45,4 +45,15 @@ AVFrame *ff_null_get_video_buffer(AVFilterLink *link, int w, int h); */ AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h); +/** + * Returns true if a pixel format is "regular YUV", which includes all pixel + * formats that are affected by YUV colorspace negotiation. + */ +int ff_fmt_is_regular_yuv(enum AVPixelFormat fmt); + +/** + * Returns true if a YUV pixel format is forced full range (i.e. YUVJ). + */ +int ff_fmt_is_forced_full_range(enum AVPixelFormat fmt); + #endif /* AVFILTER_VIDEO_H */ diff --git a/libavfilter/vidstabutils.c b/libavfilter/vidstabutils.c index 56fbdbdb8..a0c1fc990 100644 --- a/libavfilter/vidstabutils.c +++ b/libavfilter/vidstabutils.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "vidstabutils.h" const enum AVPixelFormat ff_vidstab_pix_fmts[] = { diff --git a/libavfilter/vsink_nullsink.c b/libavfilter/vsink_nullsink.c index f21299c6f..cc8cf1a13 100644 --- a/libavfilter/vsink_nullsink.c +++ b/libavfilter/vsink_nullsink.c @@ -17,7 +17,7 @@ */ #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "libavutil/internal.h" static int filter_frame(AVFilterLink *link, AVFrame *frame) diff --git a/libavfilter/vsrc_cellauto.c b/libavfilter/vsrc_cellauto.c index b469f1bf2..c831072df 100644 --- a/libavfilter/vsrc_cellauto.c +++ b/libavfilter/vsrc_cellauto.c @@ -28,11 +28,12 @@ #include "libavutil/file.h" #include "libavutil/internal.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/random_seed.h" #include "libavutil/avstring.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" typedef struct CellAutoContext { @@ -216,11 +217,12 @@ static av_cold void uninit(AVFilterContext *ctx) static int config_props(AVFilterLink *outlink) { CellAutoContext *s = outlink->src->priv; + FilterLink *l = ff_filter_link(outlink); outlink->w = s->w; outlink->h = s->h; outlink->time_base = av_inv_q(s->frame_rate); - outlink->frame_rate = s->frame_rate; + l->frame_rate = s->frame_rate; return 0; } diff --git a/libavfilter/vsrc_ddagrab.c b/libavfilter/vsrc_ddagrab.c index 018f46ed9..302c558d9 100644 --- a/libavfilter/vsrc_ddagrab.c +++ b/libavfilter/vsrc_ddagrab.c @@ -34,6 +34,7 @@ #include #endif +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time.h" #include "libavutil/avstring.h" @@ -42,7 +43,7 @@ #include "libavutil/hwcontext_d3d11va.h" #include "compat/w32dlfcn.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "vsrc_ddagrab_shaders.h" @@ -853,6 +854,7 @@ fail: static int ddagrab_config_props(AVFilterLink *outlink) { + FilterLink *l = ff_filter_link(outlink); AVFilterContext *avctx = outlink->src; DdagrabContext *dda = avctx->priv; int ret; @@ -914,14 +916,14 @@ static int ddagrab_config_props(AVFilterLink *outlink) if (ret < 0) return ret; - outlink->hw_frames_ctx = av_buffer_ref(dda->frames_ref); - if (!outlink->hw_frames_ctx) + l->hw_frames_ctx = av_buffer_ref(dda->frames_ref); + if (!l->hw_frames_ctx) return AVERROR(ENOMEM); outlink->w = dda->width; outlink->h = dda->height; outlink->time_base = (AVRational){1, TIMER_RES}; - outlink->frame_rate = dda->framerate; + l->frame_rate = dda->framerate; return 0; } diff --git a/libavfilter/vsrc_gradients.c b/libavfilter/vsrc_gradients.c index 567a4a311..201ca8f86 100644 --- a/libavfilter/vsrc_gradients.c +++ b/libavfilter/vsrc_gradients.c @@ -21,7 +21,6 @@ #include "avfilter.h" #include "filters.h" #include "video.h" -#include "internal.h" #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/lfg.h" @@ -334,6 +333,7 @@ static int draw_gradients_slice32_planar(AVFilterContext *ctx, void *arg, int jo static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; + FilterLink *l = ff_filter_link(outlink); GradientsContext *s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); @@ -344,7 +344,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = s->h; outlink->time_base = av_inv_q(s->frame_rate); outlink->sample_aspect_ratio = (AVRational) {1, 1}; - outlink->frame_rate = s->frame_rate; + l->frame_rate = s->frame_rate; if (s->seed == -1) s->seed = av_get_random_seed(); av_lfg_init(&s->lfg, s->seed); diff --git a/libavfilter/vsrc_life.c b/libavfilter/vsrc_life.c index 9f83ca5e1..a624dbb63 100644 --- a/libavfilter/vsrc_life.c +++ b/libavfilter/vsrc_life.c @@ -29,12 +29,12 @@ #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "libavutil/random_seed.h" #include "libavutil/avstring.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "formats.h" #include "video.h" @@ -280,11 +280,12 @@ static av_cold void uninit(AVFilterContext *ctx) static int config_props(AVFilterLink *outlink) { LifeContext *life = outlink->src->priv; + FilterLink *l = ff_filter_link(outlink); outlink->w = life->w; outlink->h = life->h; outlink->time_base = av_inv_q(life->frame_rate); - outlink->frame_rate = life->frame_rate; + l->frame_rate = life->frame_rate; return 0; } diff --git a/libavfilter/vsrc_mandelbrot.c b/libavfilter/vsrc_mandelbrot.c index 8eede7737..46b6854bf 100644 --- a/libavfilter/vsrc_mandelbrot.c +++ b/libavfilter/vsrc_mandelbrot.c @@ -27,9 +27,10 @@ */ #include "avfilter.h" +#include "filters.h" #include "video.h" -#include "internal.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include #include @@ -150,6 +151,7 @@ static av_cold void uninit(AVFilterContext *ctx) static int config_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; + FilterLink *l = ff_filter_link(outlink); MBContext *s = ctx->priv; if (av_image_check_size(s->w, s->h, 0, ctx) < 0) @@ -158,7 +160,7 @@ static int config_props(AVFilterLink *outlink) outlink->w = s->w; outlink->h = s->h; outlink->time_base = av_inv_q(s->frame_rate); - outlink->frame_rate = s->frame_rate; + l->frame_rate = s->frame_rate; return 0; } diff --git a/libavfilter/vsrc_mptestsrc.c b/libavfilter/vsrc_mptestsrc.c index 0395af35e..b431656f6 100644 --- a/libavfilter/vsrc_mptestsrc.c +++ b/libavfilter/vsrc_mptestsrc.c @@ -26,7 +26,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "internal.h" +#include "filters.h" #include "video.h" #define WIDTH 512 @@ -274,6 +274,7 @@ static av_cold int init(AVFilterContext *ctx) static int config_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; + FilterLink *l = ff_filter_link(outlink); MPTestContext *test = ctx->priv; const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(outlink->format); @@ -283,19 +284,20 @@ static int config_props(AVFilterLink *outlink) outlink->w = WIDTH; outlink->h = HEIGHT; outlink->time_base = av_inv_q(test->frame_rate); - outlink->frame_rate = test->frame_rate; + l->frame_rate = test->frame_rate; return 0; } static int request_frame(AVFilterLink *outlink) { + FilterLink *outl = ff_filter_link(outlink); MPTestContext *test = outlink->src->priv; AVFrame *picref; int w = WIDTH, h = HEIGHT, cw = AV_CEIL_RSHIFT(w, test->hsub), ch = AV_CEIL_RSHIFT(h, test->vsub); - uint64_t frame = outlink->frame_count_in / test->max_frames; - uint64_t mod = outlink->frame_count_in % test->max_frames; + uint64_t frame = outl->frame_count_in / test->max_frames; + uint64_t mod = outl->frame_count_in % test->max_frames; enum test_type tt = test->test; int i; diff --git a/libavfilter/vsrc_perlin.c b/libavfilter/vsrc_perlin.c new file mode 100644 index 000000000..f736d2b97 --- /dev/null +++ b/libavfilter/vsrc_perlin.c @@ -0,0 +1,170 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * Perlin noise generator + */ + +#include + +#include "perlin.h" +#include "libavutil/lfg.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "filters.h" +#include "formats.h" +#include "video.h" + +typedef struct PerlinContext { + const AVClass *class; + + int w, h; + AVRational frame_rate; + + FFPerlin perlin; + int octaves; + double persistence; + unsigned int random_seed; + enum FFPerlinRandomMode random_mode; + + double xscale, yscale, tscale; + uint64_t pts; +} PerlinContext; + +#define OFFSET(x) offsetof(PerlinContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption perlin_options[] = { + { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="320x240"}, 0, 0, FLAGS }, + { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="320x240"}, 0, 0, FLAGS }, + { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS }, + { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS }, + { "octaves", "set the number of components to use to generate the noise", OFFSET(octaves), AV_OPT_TYPE_INT, {.i64=1}, 1, INT_MAX, FLAGS }, + { "persistence", "set the octaves persistence", OFFSET(persistence), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0, DBL_MAX, FLAGS }, + + { "xscale", "set x-scale factor", OFFSET(xscale), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0, DBL_MAX, FLAGS }, + { "yscale", "set y-scale factor", OFFSET(yscale), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0, DBL_MAX, FLAGS }, + { "tscale", "set t-scale factor", OFFSET(tscale), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0, DBL_MAX, FLAGS }, + + { "random_mode", "set random mode used to compute initial pattern", OFFSET(random_mode), AV_OPT_TYPE_INT, {.i64=FF_PERLIN_RANDOM_MODE_RANDOM}, 0, FF_PERLIN_RANDOM_MODE_NB-1, FLAGS, .unit = "random_mode" }, + { "random", "compute and use random seed", 0, AV_OPT_TYPE_CONST, {.i64=FF_PERLIN_RANDOM_MODE_RANDOM}, 0, 0, FLAGS, .unit = "random_mode" }, + { "ken", "use the predefined initial pattern defined by Ken Perlin in the original article", 0, AV_OPT_TYPE_CONST, {.i64=FF_PERLIN_RANDOM_MODE_KEN}, 0, 0, FLAGS, .unit = "random_mode" }, + { "seed", "use the value specified by random_seed", 0, AV_OPT_TYPE_CONST, {.i64=FF_PERLIN_RANDOM_MODE_SEED}, 0, 0, FLAGS, .unit="random_mode" }, + + { "random_seed", "set the seed for filling the initial pattern", OFFSET(random_seed), AV_OPT_TYPE_UINT, {.i64=0}, 0, UINT_MAX, FLAGS }, + { "seed", "set the seed for filling the initial pattern", OFFSET(random_seed), AV_OPT_TYPE_UINT, {.i64=0}, 0, UINT_MAX, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(perlin); + +static av_cold int init(AVFilterContext *ctx) +{ + PerlinContext *perlin = ctx->priv; + int ret; + + if (ret = ff_perlin_init(&perlin->perlin, -1, perlin->octaves, perlin->persistence, + perlin->random_mode, perlin->random_seed)) { + return ret; + } + + av_log(ctx, AV_LOG_VERBOSE, + "s:%dx%d r:%d/%d octaves:%d persistence:%f xscale:%f yscale:%f tscale:%f\n", + perlin->w, perlin->h, perlin->frame_rate.num, perlin->frame_rate.den, + perlin->octaves, perlin->persistence, + perlin->xscale, perlin->yscale, perlin->tscale); + return 0; +} + +static int config_props(AVFilterLink *outlink) +{ + PerlinContext *perlin = outlink->src->priv; + FilterLink *l = ff_filter_link(outlink); + + outlink->w = perlin->w; + outlink->h = perlin->h; + outlink->time_base = av_inv_q(perlin->frame_rate); + l->frame_rate = perlin->frame_rate; + + return 0; +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + PerlinContext *perlin = ctx->priv; + AVFrame *picref = ff_get_video_buffer(outlink, perlin->w, perlin->h); + int i, j; + uint8_t *data0, *data; + double x, y, t; + + if (!picref) + return AVERROR(ENOMEM); + + picref->sample_aspect_ratio = (AVRational) {1, 1}; + picref->pts = perlin->pts++; + picref->duration = 1; + + t = perlin->tscale * (perlin->pts * av_q2d(outlink->time_base)); + data0 = picref->data[0]; + + for (i = 0; i < perlin->h; i++) { + y = perlin->yscale * (double)i / perlin->h; + + data = data0; + + for (j = 0; j < perlin->w; j++) { + double res; + x = perlin->xscale * (double)j / perlin->w; + res = ff_perlin_get(&perlin->perlin, x, y, t); + av_log(ctx, AV_LOG_DEBUG, "x:%f y:%f t:%f => %f\n", x, y, t, res); + *data++ = res * 255; + } + data0 += picref->linesize[0]; + } + + return ff_filter_frame(outlink, picref); +} + +static int query_formats(AVFilterContext *ctx) +{ + enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; + + return ff_set_common_formats_from_list(ctx, pix_fmts); +} + +static const AVFilterPad perlin_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .request_frame = request_frame, + .config_props = config_props, + }, +}; + +const AVFilter ff_vsrc_perlin = { + .name = "perlin", + .description = NULL_IF_CONFIG_SMALL("Generate Perlin noise"), + .priv_size = sizeof(PerlinContext), + .priv_class = &perlin_class, + .init = init, + .inputs = NULL, + FILTER_OUTPUTS(perlin_outputs), + FILTER_QUERY_FUNC(query_formats), +}; diff --git a/libavfilter/vsrc_sierpinski.c b/libavfilter/vsrc_sierpinski.c index 2f3108190..8cc6142a1 100644 --- a/libavfilter/vsrc_sierpinski.c +++ b/libavfilter/vsrc_sierpinski.c @@ -24,8 +24,8 @@ */ #include "avfilter.h" +#include "filters.h" #include "video.h" -#include "internal.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" @@ -138,6 +138,7 @@ static int draw_carpet_slice(AVFilterContext *ctx, void *arg, int job, int nb_jo static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; + FilterLink *l = ff_filter_link(outlink); SierpinskiContext *s = ctx->priv; if (av_image_check_size(s->w, s->h, 0, ctx) < 0) @@ -147,7 +148,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = s->h; outlink->time_base = av_inv_q(s->frame_rate); outlink->sample_aspect_ratio = (AVRational) {1, 1}; - outlink->frame_rate = s->frame_rate; + l->frame_rate = s->frame_rate; if (s->seed == -1) s->seed = av_get_random_seed(); av_lfg_init(&s->lfg, s->seed); diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c index 55c7e30ed..f14e36a95 100644 --- a/libavfilter/vsrc_testsrc.c +++ b/libavfilter/vsrc_testsrc.c @@ -35,21 +35,19 @@ #include "config_components.h" -#include - #include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/ffmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" -#include "libavutil/parseutils.h" #include "libavutil/xga_font_data.h" #include "avfilter.h" #include "drawutils.h" #include "filters.h" +#include "filters.h" #include "formats.h" -#include "internal.h" #include "video.h" typedef struct TestSourceContext { @@ -150,11 +148,12 @@ static av_cold void uninit(AVFilterContext *ctx) static int config_props(AVFilterLink *outlink) { TestSourceContext *test = outlink->src->priv; + FilterLink *l = ff_filter_link(outlink); outlink->w = test->w; outlink->h = test->h; outlink->sample_aspect_ratio = test->sar; - outlink->frame_rate = test->frame_rate; + l->frame_rate = test->frame_rate; outlink->time_base = test->time_base; return 0; @@ -262,8 +261,6 @@ static int color_config_props(AVFilterLink *inlink) inlink->color_range, 0); ff_draw_color(&test->draw, &test->color, test->color_rgba); - test->w = ff_draw_round_to_sub(&test->draw, 0, -1, test->w); - test->h = ff_draw_round_to_sub(&test->draw, 1, -1, test->h); if (av_image_check_size(test->w, test->h, 0, ctx) < 0) return AVERROR(EINVAL); @@ -699,6 +696,15 @@ const AVFilter ff_vsrc_testsrc = { #endif /* CONFIG_TESTSRC_FILTER */ +static void av_unused set_color(TestSourceContext *s, FFDrawColor *color, uint32_t argb) +{ + uint8_t rgba[4] = { (argb >> 16) & 0xFF, + (argb >> 8) & 0xFF, + (argb >> 0) & 0xFF, + (argb >> 24) & 0xFF, }; + ff_draw_color(&s->draw, color, rgba); +} + #if CONFIG_TESTSRC2_FILTER static const AVOption testsrc2_options[] = { @@ -709,15 +715,6 @@ static const AVOption testsrc2_options[] = { AVFILTER_DEFINE_CLASS(testsrc2); -static void set_color(TestSourceContext *s, FFDrawColor *color, uint32_t argb) -{ - uint8_t rgba[4] = { (argb >> 16) & 0xFF, - (argb >> 8) & 0xFF, - (argb >> 0) & 0xFF, - (argb >> 24) & 0xFF, }; - ff_draw_color(&s->draw, color, rgba); -} - static uint32_t color_gradient(unsigned index) { unsigned si = index & 0xFF, sd = 0xFF - si; diff --git a/libavfilter/vsrc_testsrc_vulkan.c b/libavfilter/vsrc_testsrc_vulkan.c index 480b23ac9..77fa9a0ba 100644 --- a/libavfilter/vsrc_testsrc_vulkan.c +++ b/libavfilter/vsrc_testsrc_vulkan.c @@ -23,7 +23,6 @@ #include "libavutil/opt.h" #include "vulkan_filter.h" #include "vulkan_spirv.h" -#include "internal.h" #include "filters.h" #include "colorspace.h" #include "video.h" @@ -266,6 +265,7 @@ static int testsrc_vulkan_activate(AVFilterContext *ctx) static int testsrc_vulkan_config_props(AVFilterLink *outlink) { int err; + FilterLink *l = ff_filter_link(outlink); TestSrcVulkanContext *s = outlink->src->priv; FFVulkanContext *vkctx = &s->vkctx; @@ -284,8 +284,8 @@ static int testsrc_vulkan_config_props(AVFilterLink *outlink) if (err < 0) return err; - outlink->hw_frames_ctx = av_buffer_ref(vkctx->frames_ref); - if (!outlink->hw_frames_ctx) + l->hw_frames_ctx = av_buffer_ref(vkctx->frames_ref); + if (!l->hw_frames_ctx) return AVERROR(ENOMEM); s->time_base = av_inv_q(s->frame_rate); @@ -297,7 +297,7 @@ static int testsrc_vulkan_config_props(AVFilterLink *outlink) outlink->w = s->w; outlink->h = s->h; outlink->sample_aspect_ratio = s->sar; - outlink->frame_rate = s->frame_rate; + l->frame_rate = s->frame_rate; outlink->time_base = s->time_base; return 0; diff --git a/libavfilter/vulkan_filter.c b/libavfilter/vulkan_filter.c index cef42eeb4..2c6ab7284 100644 --- a/libavfilter/vulkan_filter.c +++ b/libavfilter/vulkan_filter.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "filters.h" #include "vulkan_filter.h" #include "libavutil/vulkan_loader.h" @@ -36,6 +37,7 @@ int ff_vk_filter_init_context(AVFilterContext *avctx, FFVulkanContext *s, if (frames_ref) { int no_storage = 0; FFVulkanFunctions *vk; + VkImageUsageFlagBits usage_req; const VkFormat *sub = av_vkfmt_from_pixfmt(sw_format); frames_ctx = (AVHWFramesContext *)frames_ref->data; @@ -52,22 +54,45 @@ int ff_vk_filter_init_context(AVFilterContext *avctx, FFVulkanContext *s, if (sw_format != frames_ctx->sw_format) goto skip; - /* Unusual tiling mismatch. Don't let linear through either. */ - if (vk_frames->tiling != VK_IMAGE_TILING_OPTIMAL) - goto skip; - - /* Usage mismatch */ - if ((vk_frames->usage & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT)) != - (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT)) + /* Don't let linear through. */ + if (vk_frames->tiling == VK_IMAGE_TILING_LINEAR) goto skip; s->extensions = ff_vk_extensions_to_mask(vk_dev->enabled_dev_extensions, vk_dev->nb_enabled_dev_extensions); + + /* More advanced format checks */ err = ff_vk_load_functions(device_ctx, &s->vkfn, s->extensions, 1, 1); if (err < 0) return err; vk = &s->vkfn; + /* Usage mismatch */ + usage_req = VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_STORAGE_BIT; + + /* If format supports hardware encoding, make sure + * the context includes it. */ + if (vk_frames->format[1] == VK_FORMAT_UNDEFINED && + (s->extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE | + FF_VK_EXT_VIDEO_MAINTENANCE_1))) { + VkFormatProperties3 fprops = { + .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3, + }; + VkFormatProperties2 prop = { + .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, + .pNext = &fprops, + }; + vk->GetPhysicalDeviceFormatProperties2(vk_dev->phys_dev, + vk_frames->format[0], + &prop); + if (fprops.optimalTilingFeatures & VK_FORMAT_FEATURE_2_VIDEO_ENCODE_INPUT_BIT_KHR) + usage_req |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR; + } + + if ((vk_frames->usage & usage_req) != usage_req) + goto skip; + /* Check if the subformats can do storage */ for (int i = 0; sub[i] != VK_FORMAT_UNDEFINED; i++) { VkFormatProperties2 prop = { @@ -75,22 +100,18 @@ int ff_vk_filter_init_context(AVFilterContext *avctx, FFVulkanContext *s, }; vk->GetPhysicalDeviceFormatProperties2(vk_dev->phys_dev, sub[i], &prop); - - if (vk_frames->tiling == VK_IMAGE_TILING_LINEAR) { - no_storage |= !(prop.formatProperties.linearTilingFeatures & - VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT); - } else { - no_storage |= !(prop.formatProperties.optimalTilingFeatures & - VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT); - } + no_storage |= !(prop.formatProperties.optimalTilingFeatures & + VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT); } /* Check if it's usable */ if (no_storage) { skip: + av_log(avctx, AV_LOG_VERBOSE, "Cannot reuse context, creating a new one\n"); device_ref = frames_ctx->device_ref; frames_ref = NULL; } else { + av_log(avctx, AV_LOG_VERBOSE, "Reusing existing frames context\n"); frames_ref = av_buffer_ref(frames_ref); if (!frames_ref) return AVERROR(ENOMEM); @@ -116,8 +137,7 @@ skip: vk_frames->tiling = VK_IMAGE_TILING_OPTIMAL; vk_frames->usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT; + VK_IMAGE_USAGE_TRANSFER_SRC_BIT; err = av_hwframe_ctx_init(frames_ref); if (err < 0) { @@ -132,18 +152,6 @@ skip: s->extensions = ff_vk_extensions_to_mask(vk_dev->enabled_dev_extensions, vk_dev->nb_enabled_dev_extensions); - /** - * libplacebo does not use descriptor buffers. - */ - if (!(s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) && - strcmp(avctx->filter->name, "libplacebo")) { - av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires that " - "the %s extension is supported!\n", - VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME); - av_buffer_unref(&frames_ref); - return AVERROR(EINVAL); - } - err = ff_vk_load_functions(device_ctx, &s->vkfn, s->extensions, 1, 1); if (err < 0) { av_buffer_unref(&frames_ref); @@ -165,17 +173,18 @@ skip: int ff_vk_filter_config_input(AVFilterLink *inlink) { + FilterLink *l = ff_filter_link(inlink); AVHWFramesContext *input_frames; AVFilterContext *avctx = inlink->dst; FFVulkanContext *s = inlink->dst->priv; - if (!inlink->hw_frames_ctx) { + if (!l->hw_frames_ctx) { av_log(inlink->dst, AV_LOG_ERROR, "Vulkan filtering requires a " "hardware frames context on the input.\n"); return AVERROR(EINVAL); } - input_frames = (AVHWFramesContext *)inlink->hw_frames_ctx->data; + input_frames = (AVHWFramesContext *)l->hw_frames_ctx->data; if (input_frames->format != AV_PIX_FMT_VULKAN) return AVERROR(EINVAL); @@ -184,7 +193,7 @@ int ff_vk_filter_config_input(AVFilterLink *inlink) return 0; /* Save the ref, without reffing it */ - s->input_frames_ref = inlink->hw_frames_ctx; + s->input_frames_ref = l->hw_frames_ctx; /* Defaults */ s->input_format = input_frames->sw_format; @@ -198,9 +207,10 @@ int ff_vk_filter_config_input(AVFilterLink *inlink) int ff_vk_filter_config_output(AVFilterLink *outlink) { int err; + FilterLink *l = ff_filter_link(outlink); FFVulkanContext *s = outlink->src->priv; - av_buffer_unref(&outlink->hw_frames_ctx); + av_buffer_unref(&l->hw_frames_ctx); err = ff_vk_filter_init_context(outlink->src, s, s->input_frames_ref, s->output_width, s->output_height, @@ -208,8 +218,8 @@ int ff_vk_filter_config_output(AVFilterLink *outlink) if (err < 0) return err; - outlink->hw_frames_ctx = av_buffer_ref(s->frames_ref); - if (!outlink->hw_frames_ctx) + l->hw_frames_ctx = av_buffer_ref(s->frames_ref); + if (!l->hw_frames_ctx) return AVERROR(ENOMEM); outlink->w = s->output_width; @@ -242,12 +252,13 @@ int ff_vk_filter_process_simple(FFVulkanContext *vkctx, FFVkExecPool *e, FFVkExecContext *exec = ff_vk_exec_get(e); ff_vk_exec_start(vkctx, exec); - ff_vk_exec_bind_pipeline(vkctx, exec, pl); - - if (push_src) - ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT, - 0, push_size, push_src); - + RET(ff_vk_exec_add_dep_frame(vkctx, exec, out_f, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + RET(ff_vk_create_imageviews(vkctx, exec, out_views, out_f)); + ff_vk_update_descriptor_img_array(vkctx, pl, exec, out_f, out_views, 0, !!in_f, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); if (in_f) { RET(ff_vk_exec_add_dep_frame(vkctx, exec, in_f, VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, @@ -256,27 +267,28 @@ int ff_vk_filter_process_simple(FFVulkanContext *vkctx, FFVkExecPool *e, ff_vk_update_descriptor_img_array(vkctx, pl, exec, in_f, in_views, 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, sampler); - ff_vk_frame_barrier(vkctx, exec, in_f, 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_SHADER_READ_ONLY_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED); } - RET(ff_vk_exec_add_dep_frame(vkctx, exec, out_f, - VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); - RET(ff_vk_create_imageviews(vkctx, exec, out_views, out_f)); - ff_vk_update_descriptor_img_array(vkctx, pl, exec, out_f, out_views, 0, !!in_f, - VK_IMAGE_LAYOUT_GENERAL, - VK_NULL_HANDLE); + /* Bind pipeline, update push data */ + ff_vk_exec_bind_pipeline(vkctx, exec, pl); + if (push_src) + ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT, + 0, push_size, push_src); + + /* Add data sync barriers */ ff_vk_frame_barrier(vkctx, exec, out_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, VK_IMAGE_LAYOUT_GENERAL, VK_QUEUE_FAMILY_IGNORED); + if (in_f) + ff_vk_frame_barrier(vkctx, exec, in_f, 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_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED); vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, @@ -358,12 +370,6 @@ int ff_vk_filter_process_2pass(FFVulkanContext *vkctx, FFVkExecPool *e, VkImageView *src_views = !i ? in_views : tmp_views; VkImageView *dst_views = !i ? tmp_views : out_views; - ff_vk_exec_bind_pipeline(vkctx, exec, pl); - - if (push_src) - ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT, - 0, push_size, push_src); - ff_vk_update_descriptor_img_array(vkctx, pl, exec, src_f, src_views, 0, 0, !i ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL, @@ -372,6 +378,12 @@ int ff_vk_filter_process_2pass(FFVulkanContext *vkctx, FFVkExecPool *e, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE); + /* Bind pipeline, update push data */ + ff_vk_exec_bind_pipeline(vkctx, exec, pl); + if (push_src) + ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT, + 0, push_size, push_src); + vk->CmdDispatch(exec->buf, FFALIGN(vkctx->output_width, pl->wg_size[0])/pl->wg_size[0], FFALIGN(vkctx->output_height, pl->wg_size[1])/pl->wg_size[1], @@ -400,32 +412,47 @@ int ff_vk_filter_process_Nin(FFVulkanContext *vkctx, FFVkExecPool *e, FFVkExecContext *exec = ff_vk_exec_get(e); ff_vk_exec_start(vkctx, exec); - /* Inputs */ + /* Add deps and create temporary imageviews */ + RET(ff_vk_exec_add_dep_frame(vkctx, exec, out, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); + RET(ff_vk_create_imageviews(vkctx, exec, out_views, out)); for (int i = 0; i < nb_in; i++) { RET(ff_vk_exec_add_dep_frame(vkctx, exec, in[i], VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); RET(ff_vk_create_imageviews(vkctx, exec, in_views[i], in[i])); - - ff_vk_frame_barrier(vkctx, exec, in[i], 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_SHADER_READ_ONLY_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED); } - /* Output */ - RET(ff_vk_exec_add_dep_frame(vkctx, exec, out, - VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT)); - RET(ff_vk_create_imageviews(vkctx, exec, out_views, out)); + /* Update descriptor sets */ + ff_vk_update_descriptor_img_array(vkctx, pl, exec, out, out_views, 0, nb_in, + VK_IMAGE_LAYOUT_GENERAL, + VK_NULL_HANDLE); + for (int i = 0; i < nb_in; i++) + ff_vk_update_descriptor_img_array(vkctx, pl, exec, in[i], in_views[i], 0, i, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + sampler); + + /* Bind pipeline, update push data */ + ff_vk_exec_bind_pipeline(vkctx, exec, pl); + if (push_src) + ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT, + 0, push_size, push_src); + + /* Add data sync barriers */ ff_vk_frame_barrier(vkctx, exec, out, img_bar, &nb_img_bar, VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_QUEUE_FAMILY_IGNORED); + for (int i = 0; i < nb_in; i++) + ff_vk_frame_barrier(vkctx, exec, in[i], 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_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED); vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) { .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, @@ -433,21 +460,6 @@ int ff_vk_filter_process_Nin(FFVulkanContext *vkctx, FFVkExecPool *e, .imageMemoryBarrierCount = nb_img_bar, }); - ff_vk_exec_bind_pipeline(vkctx, exec, pl); - - if (push_src) - ff_vk_update_push_exec(vkctx, exec, pl, VK_SHADER_STAGE_COMPUTE_BIT, - 0, push_size, push_src); - - for (int i = 0; i < nb_in; i++) - ff_vk_update_descriptor_img_array(vkctx, pl, exec, in[i], in_views[i], 0, i, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - sampler); - - ff_vk_update_descriptor_img_array(vkctx, pl, exec, out, out_views, 0, nb_in, - VK_IMAGE_LAYOUT_GENERAL, - VK_NULL_HANDLE); - vk->CmdDispatch(exec->buf, FFALIGN(vkctx->output_width, pl->wg_size[0])/pl->wg_size[0], FFALIGN(vkctx->output_height, pl->wg_size[1])/pl->wg_size[1], diff --git a/libavfilter/vulkan_shaderc.c b/libavfilter/vulkan_shaderc.c index 38be1030a..9e8a3d17a 100644 --- a/libavfilter/vulkan_shaderc.c +++ b/libavfilter/vulkan_shaderc.c @@ -51,6 +51,7 @@ static int shdc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx, shaderc_compile_options_set_target_env(opts, shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); shaderc_compile_options_set_target_spirv(opts, shaderc_spirv_version_1_5); + shaderc_compile_options_set_generate_debug_info(opts); shaderc_compile_options_set_optimization_level(opts, shaderc_optimization_level_performance); @@ -65,6 +66,9 @@ static int shdc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx, warn = shaderc_result_get_num_warnings(res); message = shaderc_result_get_error_message(res); + if (ret != shaderc_compilation_status_success && !err) + err = 1; + loglevel = err ? AV_LOG_ERROR : warn ? AV_LOG_WARNING : AV_LOG_VERBOSE; ff_vk_shader_print(avctx, shd, loglevel); diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile index e87481bd7..40d5b790a 100644 --- a/libavfilter/x86/Makefile +++ b/libavfilter/x86/Makefile @@ -12,6 +12,7 @@ OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp_init.o OBJS-$(CONFIG_GBLUR_FILTER) += x86/vf_gblur_init.o OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun_init.o OBJS-$(CONFIG_FRAMERATE_FILTER) += x86/vf_framerate_init.o +OBJS-$(CONFIG_HALDCLUT_FILTER) += x86/vf_lut3d_init.o OBJS-$(CONFIG_HFLIP_FILTER) += x86/vf_hflip_init.o OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d_init.o OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet_init.o @@ -28,6 +29,7 @@ OBJS-$(CONFIG_PSNR_FILTER) += x86/vf_psnr_init.o OBJS-$(CONFIG_PULLUP_FILTER) += x86/vf_pullup_init.o OBJS-$(CONFIG_REMOVEGRAIN_FILTER) += x86/vf_removegrain_init.o OBJS-$(CONFIG_SHOWCQT_FILTER) += x86/avf_showcqt_init.o +OBJS-$(CONFIG_SOBEL_FILTER) += x86/vf_convolution_init.o OBJS-$(CONFIG_SPP_FILTER) += x86/vf_spp.o OBJS-$(CONFIG_SSIM_FILTER) += x86/vf_ssim_init.o OBJS-$(CONFIG_STEREO3D_FILTER) += x86/vf_stereo3d_init.o @@ -38,6 +40,7 @@ OBJS-$(CONFIG_TRANSPOSE_FILTER) += x86/vf_transpose_init.o OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume_init.o OBJS-$(CONFIG_V360_FILTER) += x86/vf_v360_init.o OBJS-$(CONFIG_W3FDIF_FILTER) += x86/vf_w3fdif_init.o +OBJS-$(CONFIG_XPSNR_FILTER) += x86/vf_xpsnr_init.o OBJS-$(CONFIG_YADIF_FILTER) += x86/vf_yadif_init.o X86ASM-OBJS-$(CONFIG_SCENE_SAD) += x86/scene_sad.o @@ -54,6 +57,7 @@ X86ASM-OBJS-$(CONFIG_FRAMERATE_FILTER) += x86/vf_framerate.o X86ASM-OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp.o X86ASM-OBJS-$(CONFIG_GBLUR_FILTER) += x86/vf_gblur.o X86ASM-OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun.o +X86ASM-OBJS-$(CONFIG_HALDCLUT_FILTER) += x86/vf_lut3d.o X86ASM-OBJS-$(CONFIG_HFLIP_FILTER) += x86/vf_hflip.o X86ASM-OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d.o X86ASM-OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet.o @@ -71,6 +75,7 @@ ifdef CONFIG_GPL X86ASM-OBJS-$(CONFIG_REMOVEGRAIN_FILTER) += x86/vf_removegrain.o endif X86ASM-OBJS-$(CONFIG_SHOWCQT_FILTER) += x86/avf_showcqt.o +X86ASM-OBJS-$(CONFIG_SOBEL_FILTER) += x86/vf_convolution.o X86ASM-OBJS-$(CONFIG_SSIM_FILTER) += x86/vf_ssim.o X86ASM-OBJS-$(CONFIG_STEREO3D_FILTER) += x86/vf_stereo3d.o X86ASM-OBJS-$(CONFIG_TBLEND_FILTER) += x86/vf_blend.o diff --git a/libavfilter/x86/vf_blend_init.c b/libavfilter/x86/vf_blend_init.c index c326c4336..f4e097ee3 100644 --- a/libavfilter/x86/vf_blend_init.c +++ b/libavfilter/x86/vf_blend_init.c @@ -28,7 +28,7 @@ void ff_blend_##name##_##opt(const uint8_t *top, ptrdiff_t top_linesize, \ const uint8_t *bottom, ptrdiff_t bottom_linesize, \ uint8_t *dst, ptrdiff_t dst_linesize, \ ptrdiff_t width, ptrdiff_t height, \ - struct FilterParams *param, double *values, int starty); + FilterParams *param, SliceParams *sliceparam); BLEND_FUNC(addition, sse2) BLEND_FUNC(addition, avx2) diff --git a/libavfilter/x86/vf_gblur_init.c b/libavfilter/x86/vf_gblur_init.c index b47f6fbff..6aabfb410 100644 --- a/libavfilter/x86/vf_gblur_init.c +++ b/libavfilter/x86/vf_gblur_init.c @@ -21,6 +21,7 @@ #include "libavutil/attributes.h" #include "libavutil/cpu.h" +#include "libavutil/mem.h" #include "libavutil/x86/cpu.h" #include "libavfilter/gblur.h" diff --git a/libavfilter/x86/vf_xpsnr_init.c b/libavfilter/x86/vf_xpsnr_init.c new file mode 100644 index 000000000..d33657dcd --- /dev/null +++ b/libavfilter/x86/vf_xpsnr_init.c @@ -0,0 +1,43 @@ +/* + * 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 + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * SIMD initialization for calculation of extended perceptually weighted PSNR (XPSNR). + * + * Authors: Christian Helmrich, Lehmann, and Stoffers, Fraunhofer HHI, Berlin, Germany + */ + +#include "libavutil/x86/cpu.h" +#include "libavfilter/xpsnr.h" + +uint64_t ff_sse_line_16bit_sse2(const uint8_t *buf, const uint8_t *ref, const int w); + +void ff_xpsnr_init_x86(PSNRDSPContext *dsp, const int bpp) +{ + if (bpp <= 15) { /* XPSNR always operates with 16-bit internal precision */ + const int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) + dsp->sse_line = ff_sse_line_16bit_sse2; + } +} diff --git a/libavfilter/xpsnr.h b/libavfilter/xpsnr.h new file mode 100644 index 000000000..eb14e1606 --- /dev/null +++ b/libavfilter/xpsnr.h @@ -0,0 +1,48 @@ +/* + * 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 + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Public declaration of DSP context structure of XPSNR measurement filter for FFmpeg. + * + * Authors: Christian Helmrich, Lehmann, and Stoffers, Fraunhofer HHI, Berlin, Germany + */ + +#ifndef AVFILTER_XPSNR_H +#define AVFILTER_XPSNR_H + +#include +#include +#include "libavutil/x86/cpu.h" + +/* public XPSNR DSP structure definition */ + +typedef struct XPSNRDSPContext { + uint64_t (*sse_line) (const uint8_t *buf, const uint8_t *ref, const int w); + uint64_t (*highds_func) (const int x_act, const int y_act, const int w_act, const int h_act, const int16_t *o_m0, const int o); + uint64_t (*diff1st_func)(const uint32_t w_act, const uint32_t h_act, const int16_t *o_m0, int16_t *o_m1, const int o); + uint64_t (*diff2nd_func)(const uint32_t w_act, const uint32_t h_act, const int16_t *o_m0, int16_t *o_m1, int16_t *o_m2, const int o); +} PSNRDSPContext; + +void ff_xpsnr_init_x86(PSNRDSPContext *dsp, const int bpp); + +#endif /* AVFILTER_XPSNR_H */ diff --git a/libavfilter/yadif_common.c b/libavfilter/yadif_common.c index 35be87e8d..059b44ba2 100644 --- a/libavfilter/yadif_common.c +++ b/libavfilter/yadif_common.c @@ -21,7 +21,7 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" -#include "internal.h" +#include "filters.h" #include "video.h" #include "yadif.h" @@ -218,6 +218,8 @@ int ff_yadif_request_frame(AVFilterLink *link) int ff_yadif_config_output_common(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; + FilterLink *il = ff_filter_link(ctx->inputs[0]); + FilterLink *ol = ff_filter_link(outlink); YADIFContext *yadif = ctx->priv; AVRational tb = ctx->inputs[0]->time_base; int ret; @@ -239,12 +241,12 @@ int ff_yadif_config_output_common(AVFilterLink *outlink) } if(yadif->mode & 1) - outlink->frame_rate = av_mul_q(ctx->inputs[0]->frame_rate, + ol->frame_rate = av_mul_q(il->frame_rate, (AVRational){2, 1}); else - outlink->frame_rate = ctx->inputs[0]->frame_rate; + ol->frame_rate = il->frame_rate; - ret = ff_ccfifo_init(&yadif->cc_fifo, outlink->frame_rate, ctx); + ret = ff_ccfifo_init(&yadif->cc_fifo, ol->frame_rate, ctx); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Failure to setup CC FIFO queue\n"); return ret; diff --git a/libavformat/4xm.c b/libavformat/4xm.c index 516c7866b..218ea837c 100644 --- a/libavformat/4xm.c +++ b/libavformat/4xm.c @@ -29,6 +29,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" +#include "libavutil/mem.h" #include "libavcodec/internal.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/Makefile b/libavformat/Makefile index ae86954e7..7ca68a703 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -35,6 +35,7 @@ OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o # subsystems OBJS-$(CONFIG_ISO_MEDIA) += isom.o +OBJS-$(CONFIG_ISO_WRITER) += av1.o avc.o hevc.o nal.o vvc.o vpcc.o OBJS-$(CONFIG_IAMFDEC) += iamf_reader.o iamf_parse.o iamf.o OBJS-$(CONFIG_IAMFENC) += iamf_writer.o iamf.o OBJS-$(CONFIG_NETWORK) += network.o @@ -127,7 +128,8 @@ OBJS-$(CONFIG_ASF_DEMUXER) += asfdec_f.o asf.o asfcrypt.o \ asf_tags.o avlanguage.o OBJS-$(CONFIG_ASF_O_DEMUXER) += asfdec_o.o asf.o asfcrypt.o \ asf_tags.o avlanguage.o -OBJS-$(CONFIG_ASF_MUXER) += asfenc.o asf.o avlanguage.o +OBJS-$(CONFIG_ASF_MUXER) += asfenc.o asf.o asf_tags.o \ + avlanguage.o OBJS-$(CONFIG_ASS_DEMUXER) += assdec.o subtitles.o OBJS-$(CONFIG_ASS_MUXER) += assenc.o OBJS-$(CONFIG_AST_DEMUXER) += ast.o astdec.o @@ -219,7 +221,7 @@ OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \ OBJS-$(CONFIG_FLIC_DEMUXER) += flic.o OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o OBJS-$(CONFIG_LIVE_FLV_DEMUXER) += flvdec.o -OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o hevc.o av1.o vpcc.o +OBJS-$(CONFIG_FLV_MUXER) += flvenc.o OBJS-$(CONFIG_FOURXM_DEMUXER) += 4xm.o OBJS-$(CONFIG_FRAMECRC_MUXER) += framecrcenc.o framehash.o OBJS-$(CONFIG_FRAMEHASH_MUXER) += hashenc.o framehash.o @@ -259,7 +261,7 @@ OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o OBJS-$(CONFIG_EVC_DEMUXER) += evcdec.o rawdec.o OBJS-$(CONFIG_EVC_MUXER) += rawenc.o OBJS-$(CONFIG_HLS_DEMUXER) += hls.o hls_sample_encryption.o -OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o hlsplaylist.o avc.o +OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o hlsplaylist.o OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o OBJS-$(CONFIG_IAMF_DEMUXER) += iamfdec.o OBJS-$(CONFIG_IAMF_MUXER) += iamfenc.o @@ -332,6 +334,8 @@ OBJS-$(CONFIG_KVAG_DEMUXER) += kvag.o OBJS-$(CONFIG_KVAG_MUXER) += kvag.o rawenc.o OBJS-$(CONFIG_LAF_DEMUXER) += lafdec.o OBJS-$(CONFIG_LATM_MUXER) += latmenc.o rawenc.o +OBJS-$(CONFIG_LC3_DEMUXER) += lc3.o +OBJS-$(CONFIG_LC3_MUXER) += lc3.o OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o OBJS-$(CONFIG_LOAS_DEMUXER) += loasdec.o rawdec.o OBJS-$(CONFIG_LUODAT_DEMUXER) += luodatdec.o @@ -346,7 +350,6 @@ OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o \ oggparsevorbis.o vorbiscomment.o \ qtpalette.o replaygain.o dovi_isom.o OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \ - av1.o avc.o hevc.o vvc.o\ flacenc_header.o avlanguage.o \ vorbiscomment.o wv.o dovi_isom.o OBJS-$(CONFIG_MCA_DEMUXER) += mca.o @@ -368,7 +371,7 @@ OBJS-$(CONFIG_MODS_DEMUXER) += mods.o OBJS-$(CONFIG_MOFLEX_DEMUXER) += moflex.o OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o mov_esds.o \ qtpalette.o replaygain.o dovi_isom.o -OBJS-$(CONFIG_MOV_MUXER) += movenc.o av1.o avc.o hevc.o vvc.o vpcc.o \ +OBJS-$(CONFIG_MOV_MUXER) += movenc.o \ movenchint.o mov_chan.o rtp.o \ movenccenc.o movenc_ttml.o rawutils.o \ dovi_isom.o evc.o @@ -401,7 +404,7 @@ OBJS-$(CONFIG_MUSX_DEMUXER) += musx.o OBJS-$(CONFIG_MV_DEMUXER) += mvdec.o OBJS-$(CONFIG_MVI_DEMUXER) += mvi.o OBJS-$(CONFIG_MXF_DEMUXER) += mxfdec.o mxf.o avlanguage.o -OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o avc.o +OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o OBJS-$(CONFIG_NC_DEMUXER) += ncdec.o OBJS-$(CONFIG_NISTSPHERE_DEMUXER) += nistspheredec.o pcm.o @@ -493,6 +496,7 @@ OBJS-$(CONFIG_QOA_DEMUXER) += qoadec.o OBJS-$(CONFIG_R3D_DEMUXER) += r3d.o OBJS-$(CONFIG_RAWVIDEO_DEMUXER) += rawvideodec.o OBJS-$(CONFIG_RAWVIDEO_MUXER) += rawenc.o +OBJS-$(CONFIG_RCWT_DEMUXER) += rcwtdec.o subtitles.o OBJS-$(CONFIG_RCWT_MUXER) += rcwtenc.o subtitles.o OBJS-$(CONFIG_REALTEXT_DEMUXER) += realtextdec.o subtitles.o OBJS-$(CONFIG_REDSPARK_DEMUXER) += redspark.o @@ -522,8 +526,7 @@ OBJS-$(CONFIG_RTP_MUXER) += rtp.o \ rtpenc_vc2hq.o \ rtpenc_vp8.o \ rtpenc_vp9.o \ - rtpenc_xiph.o \ - avc.o hevc.o vvc.o + rtpenc_xiph.o OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o rtspdec.o httpauth.o \ urldecode.o OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o httpauth.o \ @@ -723,7 +726,7 @@ OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o OBJS-$(CONFIG_LIBZMQ_PROTOCOL) += libzmq.o # Objects duplicated from other libraries for shared builds -SHLIBOBJS += log2_tab.o to_upper4.o bitstream.o +SHLIBOBJS += log2_tab.o to_upper4.o SHLIBOBJS-$(CONFIG_ISO_MEDIA) += mpegaudiotabs.o SHLIBOBJS-$(CONFIG_FLV_MUXER) += mpeg4audio_sample_rates.o SHLIBOBJS-$(CONFIG_HLS_DEMUXER) += ac3_channel_layout_tab.o diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c index e267886e1..0b4bd69dd 100644 --- a/libavformat/aacdec.c +++ b/libavformat/aacdec.c @@ -119,7 +119,7 @@ static int adts_aac_read_header(AVFormatContext *s) ff_id3v1_read(s); if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && - !av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) { + !av_dict_count(s->metadata)) { int64_t cur = avio_tell(s->pb); ff_ape_parse_tag(s); avio_seek(s->pb, cur, SEEK_SET); @@ -143,9 +143,8 @@ static int handle_id3(AVFormatContext *s, AVPacket *pkt) int ret; ret = av_append_packet(s->pb, pkt, ff_id3v2_tag_len(pkt->data) - pkt->size); - if (ret < 0) { + if (ret < 0) return ret; - } ffio_init_read_context(&pb, pkt->data, pkt->size); ff_id3v2_read_dict(&pb.pub, &metadata, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); @@ -175,9 +174,8 @@ retry: if (ret < 0) return ret; - if (ret < ADTS_HEADER_SIZE) { + if (ret < ADTS_HEADER_SIZE) return AVERROR(EIO); - } if ((AV_RB16(pkt->data) >> 4) != 0xfff) { // Parse all the ID3 headers between frames @@ -185,9 +183,8 @@ retry: av_assert2(append > 0); ret = av_append_packet(s->pb, pkt, append); - if (ret != append) { + if (ret != append) return AVERROR(EIO); - } if (!ff_id3v2_match(pkt->data, ID3v2_DEFAULT_MAGIC)) { av_packet_unref(pkt); ret = adts_aac_resync(s); @@ -200,9 +197,8 @@ retry: } fsize = (AV_RB32(pkt->data + 3) >> 13) & 0x1FFF; - if (fsize < ADTS_HEADER_SIZE) { + if (fsize < ADTS_HEADER_SIZE) return AVERROR_INVALIDDATA; - } ret = av_append_packet(s->pb, pkt, fsize - pkt->size); diff --git a/libavformat/aadec.c b/libavformat/aadec.c index c39fb51a8..e9b0a6a97 100644 --- a/libavformat/aadec.c +++ b/libavformat/aadec.c @@ -29,6 +29,7 @@ #include "libavutil/avstring.h" #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/tea.h" #include "libavutil/opt.h" diff --git a/libavformat/aaxdec.c b/libavformat/aaxdec.c index 830ae5d89..40a088a35 100644 --- a/libavformat/aaxdec.c +++ b/libavformat/aaxdec.c @@ -20,6 +20,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "demux.h" diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c index fc01ffcbf..bd5bd2e4b 100644 --- a/libavformat/aiffdec.c +++ b/libavformat/aiffdec.c @@ -21,6 +21,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/allformats.c b/libavformat/allformats.c index e15d0fa6d..305fa4653 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -252,6 +252,8 @@ extern const FFInputFormat ff_kvag_demuxer; extern const FFOutputFormat ff_kvag_muxer; extern const FFInputFormat ff_laf_demuxer; extern const FFOutputFormat ff_latm_muxer; +extern const FFInputFormat ff_lc3_demuxer; +extern const FFOutputFormat ff_lc3_muxer; extern const FFInputFormat ff_lmlm4_demuxer; extern const FFInputFormat ff_loas_demuxer; extern const FFInputFormat ff_luodat_demuxer; @@ -391,6 +393,7 @@ extern const FFInputFormat ff_qoa_demuxer; extern const FFInputFormat ff_r3d_demuxer; extern const FFInputFormat ff_rawvideo_demuxer; extern const FFOutputFormat ff_rawvideo_muxer; +extern const FFInputFormat ff_rcwt_demuxer; extern const FFOutputFormat ff_rcwt_muxer; extern const FFInputFormat ff_realtext_demuxer; extern const FFInputFormat ff_redspark_demuxer; @@ -576,8 +579,8 @@ extern const FFInputFormat ff_vapoursynth_demuxer; #include "libavformat/muxer_list.c" #include "libavformat/demuxer_list.c" -static atomic_uintptr_t indev_list_intptr = ATOMIC_VAR_INIT(0); -static atomic_uintptr_t outdev_list_intptr = ATOMIC_VAR_INIT(0); +static atomic_uintptr_t indev_list_intptr = 0; +static atomic_uintptr_t outdev_list_intptr = 0; const AVOutputFormat *av_muxer_iterate(void **opaque) { diff --git a/libavformat/ape.c b/libavformat/ape.c index c664cd60f..f86ca5e89 100644 --- a/libavformat/ape.c +++ b/libavformat/ape.c @@ -23,6 +23,7 @@ #include #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/apetag.c b/libavformat/apetag.c index f2794c46f..0989fcb09 100644 --- a/libavformat/apetag.c +++ b/libavformat/apetag.c @@ -23,6 +23,7 @@ #include #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "apetag.h" @@ -120,7 +121,8 @@ int64_t ff_ape_parse_tag(AVFormatContext *s) avio_seek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET); - avio_read(pb, buf, 8); /* APETAGEX */ + if(avio_read(pb, buf, 8) != 8) /* APETAGEX */ + return 0; if (strncmp(buf, APE_TAG_PREAMBLE, 8)) { return 0; } diff --git a/libavformat/apngdec.c b/libavformat/apngdec.c index 469028333..d0005046c 100644 --- a/libavformat/apngdec.c +++ b/libavformat/apngdec.c @@ -32,6 +32,7 @@ #include "internal.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/apng.h" #include "libavcodec/png.h" diff --git a/libavformat/apngenc.c b/libavformat/apngenc.c index 4d0438f82..0d56d784f 100644 --- a/libavformat/apngenc.c +++ b/libavformat/apngenc.c @@ -27,6 +27,7 @@ #include "libavutil/crc.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/apng.h" #include "libavcodec/png.h" diff --git a/libavformat/argo_brp.c b/libavformat/argo_brp.c index f88def373..94b404b5d 100644 --- a/libavformat/argo_brp.c +++ b/libavformat/argo_brp.c @@ -380,8 +380,8 @@ static int argo_brp_read_packet(AVFormatContext *s, AVPacket *pkt) if (blk.size < ASF_CHUNK_HEADER_SIZE) return AVERROR_INVALIDDATA; - if ((ret = avio_read(s->pb, buf, ASF_CHUNK_HEADER_SIZE)) < 0) - return ret; + if (avio_read(s->pb, buf, ASF_CHUNK_HEADER_SIZE) != ASF_CHUNK_HEADER_SIZE) + return AVERROR_INVALIDDATA; ff_argo_asf_parse_chunk_header(&ckhdr, buf); diff --git a/libavformat/asf.c b/libavformat/asf.c index 128506222..5c118d2db 100644 --- a/libavformat/asf.c +++ b/libavformat/asf.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "asf.h" #include "demux.h" #include "id3v2.h" @@ -89,8 +90,8 @@ static int asf_read_picture(AVFormatContext *s, int len) return 0; } - if (picsize >= len) { - av_log(s, AV_LOG_ERROR, "Invalid attached picture data size: %d >= %d.\n", + if (picsize >= len || ((int64_t)len - picsize) * 2 + 1 > INT_MAX) { + av_log(s, AV_LOG_ERROR, "Invalid attached picture data size: %d (len = %d).\n", picsize, len); return AVERROR_INVALIDDATA; } diff --git a/libavformat/asfdec_f.c b/libavformat/asfdec_f.c index 8daae216a..2441cadb4 100644 --- a/libavformat/asfdec_f.c +++ b/libavformat/asfdec_f.c @@ -29,6 +29,7 @@ #include "libavutil/dict.h" #include "libavutil/internal.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avformat.h" #include "avio_internal.h" diff --git a/libavformat/asfdec_o.c b/libavformat/asfdec_o.c index 8ec1c8094..dd187e600 100644 --- a/libavformat/asfdec_o.c +++ b/libavformat/asfdec_o.c @@ -26,6 +26,7 @@ #include "libavutil/dict.h" #include "libavutil/internal.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/time_internal.h" #include "avformat.h" diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c index 2f2d9b1ba..75285b065 100644 --- a/libavformat/asfenc.c +++ b/libavformat/asfenc.c @@ -24,6 +24,7 @@ #include "libavutil/avassert.h" #include "libavutil/dict.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/codec_desc.h" #include "avformat.h" diff --git a/libavformat/assenc.c b/libavformat/assenc.c index 7b474a600..75c19afd0 100644 --- a/libavformat/assenc.c +++ b/libavformat/assenc.c @@ -20,6 +20,7 @@ */ #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "internal.h" diff --git a/libavformat/async.c b/libavformat/async.c index e096b0bc6..e0329e23e 100644 --- a/libavformat/async.c +++ b/libavformat/async.c @@ -53,7 +53,7 @@ typedef struct RingBuffer int read_pos; } RingBuffer; -typedef struct Context { +typedef struct AsyncContext { AVClass *class; URLContext *inner; @@ -78,7 +78,7 @@ typedef struct Context { int abort_request; AVIOInterruptCB interrupt_callback; -} Context; +} AsyncContext; static int ring_init(RingBuffer *ring, unsigned int capacity, int read_back_capacity) { @@ -132,7 +132,7 @@ static int ring_read(RingBuffer *ring, void *dest, int buf_size) static int wrapped_url_read(void *src, void *dst, size_t *size) { URLContext *h = src; - Context *c = h->priv_data; + AsyncContext *c = h->priv_data; int ret; ret = ffurl_read(c->inner, dst, *size); @@ -170,7 +170,7 @@ static int ring_drain(RingBuffer *ring, int offset) static int async_check_interrupt(void *arg) { URLContext *h = arg; - Context *c = h->priv_data; + AsyncContext *c = h->priv_data; if (c->abort_request) return 1; @@ -184,7 +184,7 @@ static int async_check_interrupt(void *arg) static void *async_buffer_task(void *arg) { URLContext *h = arg; - Context *c = h->priv_data; + AsyncContext *c = h->priv_data; RingBuffer *ring = &c->ring; int ret = 0; int64_t seek_ret; @@ -249,7 +249,7 @@ static void *async_buffer_task(void *arg) static int async_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { - Context *c = h->priv_data; + AsyncContext *c = h->priv_data; int ret; AVIOInterruptCB interrupt_callback = {.callback = async_check_interrupt, .opaque = h}; @@ -316,7 +316,7 @@ fifo_fail: static int async_close(URLContext *h) { - Context *c = h->priv_data; + AsyncContext *c = h->priv_data; int ret; pthread_mutex_lock(&c->mutex); @@ -339,7 +339,7 @@ static int async_close(URLContext *h) static int async_read_internal(URLContext *h, void *dest, int size) { - Context *c = h->priv_data; + AsyncContext *c = h->priv_data; RingBuffer *ring = &c->ring; int read_complete = !dest; int to_read = size; @@ -391,7 +391,7 @@ static int async_read(URLContext *h, unsigned char *buf, int size) static int64_t async_seek(URLContext *h, int64_t pos, int whence) { - Context *c = h->priv_data; + AsyncContext *c = h->priv_data; RingBuffer *ring = &c->ring; int64_t ret; int64_t new_logical_pos; @@ -472,7 +472,7 @@ static int64_t async_seek(URLContext *h, int64_t pos, int whence) return ret; } -#define OFFSET(x) offsetof(Context, x) +#define OFFSET(x) offsetof(AsyncContext, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { @@ -495,7 +495,7 @@ const URLProtocol ff_async_protocol = { .url_read = async_read, .url_seek = async_seek, .url_close = async_close, - .priv_data_size = sizeof(Context), + .priv_data_size = sizeof(AsyncContext), .priv_data_class = &async_context_class, }; diff --git a/libavformat/au.c b/libavformat/au.c index 98f1a5b50..224499582 100644 --- a/libavformat/au.c +++ b/libavformat/au.c @@ -31,6 +31,7 @@ #include "libavutil/bprint.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/av1.c b/libavformat/av1.c index cb86e66d0..35c23dd0b 100644 --- a/libavformat/av1.c +++ b/libavformat/av1.c @@ -21,6 +21,7 @@ #include "libavutil/avassert.h" #include "libavutil/mem.h" +#include "libavutil/pixfmt.h" #include "libavcodec/av1.h" #include "libavcodec/av1_parse.h" #include "libavcodec/defs.h" diff --git a/libavformat/av1dec.c b/libavformat/av1dec.c index 3363003b1..8c0b8fe97 100644 --- a/libavformat/av1dec.c +++ b/libavformat/av1dec.c @@ -379,6 +379,7 @@ static int obu_get_packet(AVFormatContext *s, AVPacket *pkt) if (size < 0) return size; + memset(header + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); len = read_obu_with_size(header, size, &obu_size, &type); if (len < 0) { av_log(c, AV_LOG_ERROR, "Failed to read obu\n"); diff --git a/libavformat/avc.c b/libavformat/avc.c index b0ceb1d2d..e4040928c 100644 --- a/libavformat/avc.c +++ b/libavformat/avc.c @@ -20,124 +20,13 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/h264.h" #include "libavcodec/get_bits.h" -#include "avformat.h" #include "avio.h" #include "avc.h" #include "avio_internal.h" - -static const uint8_t *avc_find_startcode_internal(const uint8_t *p, const uint8_t *end) -{ - const uint8_t *a = p + 4 - ((intptr_t)p & 3); - - for (end -= 3; p < a && p < end; p++) { - if (p[0] == 0 && p[1] == 0 && p[2] == 1) - return p; - } - - for (end -= 3; p < end; p += 4) { - uint32_t x = *(const uint32_t*)p; -// if ((x - 0x01000100) & (~x) & 0x80008000) // little endian -// if ((x - 0x00010001) & (~x) & 0x00800080) // big endian - if ((x - 0x01010101) & (~x) & 0x80808080) { // generic - if (p[1] == 0) { - if (p[0] == 0 && p[2] == 1) - return p; - if (p[2] == 0 && p[3] == 1) - return p+1; - } - if (p[3] == 0) { - if (p[2] == 0 && p[4] == 1) - return p+2; - if (p[4] == 0 && p[5] == 1) - return p+3; - } - } - } - - for (end += 3; p < end; p++) { - if (p[0] == 0 && p[1] == 0 && p[2] == 1) - return p; - } - - return end + 3; -} - -const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end){ - const uint8_t *out = avc_find_startcode_internal(p, end); - if(pnalus); - while (nal_start < end && !*(nal_start++)); - if (nal_start == end) - break; - - nal_end = ff_avc_find_startcode(nal_start, end); - if (pb) { - avio_wb32(pb, nal_end - nal_start); - avio_write(pb, nal_start, nal_end - nal_start); - } else if (list->nb_nalus >= nalu_limit) { - return AVERROR(ERANGE); - } else { - NALU *tmp = av_fast_realloc(list->nalus, &list->nalus_array_size, - (list->nb_nalus + 1) * sizeof(*list->nalus)); - if (!tmp) - return AVERROR(ENOMEM); - list->nalus = tmp; - tmp[list->nb_nalus++] = (NALU){ .offset = nal_start - p, - .size = nal_end - nal_start }; - } - size += 4 + nal_end - nal_start; - nal_start = nal_end; - } - return size; -} - -int ff_avc_parse_nal_units(AVIOContext *pb, const uint8_t *buf_in, int size) -{ - return avc_parse_nal_units(pb, NULL, buf_in, size); -} - -int ff_nal_units_create_list(NALUList *list, const uint8_t *buf, int size) -{ - list->nb_nalus = 0; - return avc_parse_nal_units(NULL, list, buf, size); -} - -void ff_nal_units_write_list(const NALUList *list, AVIOContext *pb, - const uint8_t *buf) -{ - for (unsigned i = 0; i < list->nb_nalus; i++) { - avio_wb32(pb, list->nalus[i].size); - avio_write(pb, buf + list->nalus[i].offset, list->nalus[i].size); - } -} - -int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) -{ - AVIOContext *pb; - int ret = avio_open_dyn_buf(&pb); - if(ret < 0) - return ret; - - ff_avc_parse_nal_units(pb, buf_in, *size); - - *size = avio_close_dyn_buf(pb, buf); - return 0; -} +#include "nal.h" int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len) { @@ -157,7 +46,7 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len) return 0; } - ret = ff_avc_parse_nal_units_buf(data, &buf, &len); + ret = ff_nal_parse_units_buf(data, &buf, &len); if (ret < 0) return ret; start = buf; @@ -283,55 +172,6 @@ int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size) return 0; } -const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start, - const uint8_t *end, - int nal_length_size) -{ - unsigned int res = 0; - - if (end - start < nal_length_size) - return NULL; - while (nal_length_size--) - res = (res << 8) | *start++; - - if (res > end - start) - return NULL; - - return start + res; -} - -uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, - uint32_t *dst_len, int header_len) -{ - uint8_t *dst; - uint32_t i, len; - - dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE); - if (!dst) - return NULL; - - /* NAL unit header */ - i = len = 0; - while (i < header_len && i < src_len) - dst[len++] = src[i++]; - - while (i + 2 < src_len) - if (!src[i] && !src[i + 1] && src[i + 2] == 3) { - dst[len++] = src[i++]; - dst[len++] = src[i++]; - i++; // remove emulation_prevention_three_byte - } else - dst[len++] = src[i++]; - - while (i < src_len) - dst[len++] = src[i++]; - - memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); - - *dst_len = len; - return dst; -} - static const AVRational avc_sample_aspect_ratio[17] = { { 0, 1 }, { 1, 1 }, diff --git a/libavformat/avc.h b/libavformat/avc.h index 0ce95c194..e36108afc 100644 --- a/libavformat/avc.h +++ b/libavformat/avc.h @@ -26,45 +26,8 @@ #include "libavutil/rational.h" #include "avio.h" -typedef struct NALU { - int offset; - uint32_t size; -} NALU; - -typedef struct NALUList { - NALU *nalus; - unsigned nalus_array_size; - unsigned nb_nalus; ///< valid entries in nalus -} NALUList; - -/* This function will parse the given annex B buffer and create - * a NALUList from it. This list can be passed to ff_nal_units_write_list() - * to write the access unit reformatted to mp4. - * - * @param list A NALUList. The list->nalus and list->nalus_array_size - * must be valid when calling this function and may be updated. - * nb_nalus is set by this function on success. - * @param buf buffer containing annex B H.264 or H.265. Must be padded. - * @param size size of buf, excluding padding. - * @return < 0 on error, the size of the mp4-style packet on success. - */ -int ff_nal_units_create_list(NALUList *list, const uint8_t *buf, int size); - -/* Writes a NALUList to the specified AVIOContext. The list must originate - * from ff_nal_units_create_list() with the same buf. */ -void ff_nal_units_write_list(const NALUList *list, AVIOContext *pb, - const uint8_t *buf); - -int ff_avc_parse_nal_units(AVIOContext *s, const uint8_t *buf, int size); -int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size); int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len); -const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end); int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size); -const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start, - const uint8_t *end, - int nal_length_size); -uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, - uint32_t *dst_len, int header_len); typedef struct { uint8_t id; diff --git a/libavformat/avformat.c b/libavformat/avformat.c index 140fb5b6a..06dcde056 100644 --- a/libavformat/avformat.c +++ b/libavformat/avformat.c @@ -104,6 +104,10 @@ void ff_free_stream_group(AVStreamGroup **pstg) av_freep(&stg->params.tile_grid->offsets); av_freep(&stg->params.tile_grid); break; + case AV_STREAM_GROUP_PARAMS_LCEVC: + av_opt_free(stg->params.lcevc); + av_freep(&stg->params.lcevc); + break; default: break; } @@ -327,6 +331,7 @@ const char *avformat_stream_group_name(enum AVStreamGroupParamsType type) case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: return "IAMF Audio Element"; case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: return "IAMF Mix Presentation"; case AV_STREAM_GROUP_PARAMS_TILE_GRID: return "Tile Grid"; + case AV_STREAM_GROUP_PARAMS_LCEVC: return "LCEVC (Split video and enhancement)"; } return NULL; } @@ -770,6 +775,7 @@ AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *f return fr; } +#if FF_API_INTERNAL_TIMING int avformat_transfer_internal_stream_timing_info(const AVOutputFormat *ofmt, AVStream *ost, const AVStream *ist, enum AVTimebaseSource copy_tb) @@ -849,6 +855,7 @@ AVRational av_stream_get_codec_timebase(const AVStream *st) { return cffstream(st)->avctx ? cffstream(st)->avctx->time_base : cffstream(st)->transferred_mux_tb; } +#endif void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index de4039767..56c1c8028 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -713,6 +713,11 @@ typedef struct AVIndexEntry { * The video stream contains still images. */ #define AV_DISPOSITION_STILL_IMAGE (1 << 20) +/** + * The video stream contains multiple layers, e.g. stereoscopic views (cf. H.264 + * Annex G/H, or HEVC Annex F). + */ +#define AV_DISPOSITION_MULTILAYER (1 << 21) /** * @return The AV_DISPOSITION_* flag corresponding to disp or a negative error @@ -1079,11 +1084,37 @@ typedef struct AVStreamGroupTileGrid { int height; } AVStreamGroupTileGrid; +/** + * AVStreamGroupLCEVC is meant to define the relation between video streams + * and a data stream containing LCEVC enhancement layer NALUs. + * + * No more than one stream of @ref AVCodecParameters.codec_type "codec_type" + * AVMEDIA_TYPE_DATA shall be present, and it must be of + * @ref AVCodecParameters.codec_id "codec_id" AV_CODEC_ID_LCEVC. + */ +typedef struct AVStreamGroupLCEVC { + const AVClass *av_class; + + /** + * Index of the LCEVC data stream in AVStreamGroup. + */ + unsigned int lcevc_index; + /** + * Width of the final stream for presentation. + */ + int width; + /** + * Height of the final image for presentation. + */ + int height; +} AVStreamGroupLCEVC; + enum AVStreamGroupParamsType { AV_STREAM_GROUP_PARAMS_NONE, AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT, AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION, AV_STREAM_GROUP_PARAMS_TILE_GRID, + AV_STREAM_GROUP_PARAMS_LCEVC, }; struct AVIAMFAudioElement; @@ -1125,6 +1156,7 @@ typedef struct AVStreamGroup { struct AVIAMFAudioElement *iamf_audio_element; struct AVIAMFMixPresentation *iamf_mix_presentation; struct AVStreamGroupTileGrid *tile_grid; + struct AVStreamGroupLCEVC *lcevc; } params; /** @@ -1439,7 +1471,7 @@ typedef struct AVFormatContext { * * @note this is \e not used for determining the \ref AVInputFormat * "input format" - * @sa format_probesize + * @see format_probesize */ int64_t probesize; @@ -1667,6 +1699,8 @@ typedef struct AVFormatContext { * Skip duration calcuation in estimate_timings_from_pts. * - encoding: unused * - decoding: set by user + * + * @see duration_probesize */ int skip_estimate_duration_from_pts; @@ -1729,7 +1763,7 @@ typedef struct AVFormatContext { * * Demuxing only, set by the caller before avformat_open_input(). * - * @sa probesize + * @see probesize */ int format_probesize; @@ -1870,6 +1904,16 @@ typedef struct AVFormatContext { * @return 0 on success, a negative AVERROR code on failure */ int (*io_close2)(struct AVFormatContext *s, AVIOContext *pb); + + /** + * Maximum number of bytes read from input in order to determine stream durations + * when using estimate_timings_from_pts in avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info(). + * Can be set to 0 to let avformat choose using a heuristic. + * + * @see skip_estimate_duration_from_pts + */ + int64_t duration_probesize; } AVFormatContext; /** @@ -3030,6 +3074,7 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, int avformat_queue_attached_pictures(AVFormatContext *s); +#if FF_API_INTERNAL_TIMING enum AVTimebaseSource { AVFMT_TBCF_AUTO = -1, AVFMT_TBCF_DECODER, @@ -3040,25 +3085,20 @@ enum AVTimebaseSource { }; /** - * Transfer internal timing information from one stream to another. - * - * This function is useful when doing stream copy. - * - * @param ofmt target output format for ost - * @param ost output stream which needs timings copy and adjustments - * @param ist reference input stream to copy timings from - * @param copy_tb define from where the stream codec timebase needs to be imported + * @deprecated do not call this function */ +attribute_deprecated int avformat_transfer_internal_stream_timing_info(const AVOutputFormat *ofmt, AVStream *ost, const AVStream *ist, enum AVTimebaseSource copy_tb); /** - * Get the internal codec timebase from a stream. - * - * @param st input stream to extract the timebase from + * @deprecated do not call this function */ +attribute_deprecated AVRational av_stream_get_codec_timebase(const AVStream *st); +#endif + /** * @} diff --git a/libavformat/avidec.c b/libavformat/avidec.c index 2c99dbb88..1ae09efc1 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -25,6 +25,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/dict.h" #include "libavutil/integer.h" diff --git a/libavformat/avienc.c b/libavformat/avienc.c index a61e5c310..2a3cff121 100644 --- a/libavformat/avienc.c +++ b/libavformat/avienc.c @@ -25,7 +25,6 @@ #include "internal.h" #include "avi.h" #include "avio_internal.h" -#include "config_components.h" #include "riff.h" #include "mpegts.h" #include "mux.h" @@ -36,6 +35,7 @@ #include "libavutil/internal.h" #include "libavutil/dict.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/timestamp.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" diff --git a/libavformat/avio.c b/libavformat/avio.c index 0503b2278..d109f3adf 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -21,6 +21,7 @@ #include "libavutil/avstring.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time.h" #include "libavutil/avassert.h" diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index 360996090..6a74c1ce6 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -24,6 +24,7 @@ #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/avassert.h" #include "libavcodec/defs.h" diff --git a/libavformat/avisynth.c b/libavformat/avisynth.c index e85b9ae48..cb2be1092 100644 --- a/libavformat/avisynth.c +++ b/libavformat/avisynth.c @@ -21,9 +21,9 @@ #include "libavutil/attributes.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" - -#include "libavcodec/internal.h" +#include "libavutil/thread.h" #include "avformat.h" #include "demux.h" @@ -115,42 +115,19 @@ typedef struct AviSynthContext { int error; uint32_t flags; - - /* Linked list pointers. */ - struct AviSynthContext *next; + struct AviSynthLibrary avs_library; } AviSynthContext; -static const int avs_planes_packed[1] = { 0 }; -static const int avs_planes_grey[1] = { AVS_PLANAR_Y }; -static const int avs_planes_yuv[3] = { AVS_PLANAR_Y, AVS_PLANAR_U, - AVS_PLANAR_V }; -static const int avs_planes_rgb[3] = { AVS_PLANAR_G, AVS_PLANAR_B, - AVS_PLANAR_R }; -static const int avs_planes_yuva[4] = { AVS_PLANAR_Y, AVS_PLANAR_U, - AVS_PLANAR_V, AVS_PLANAR_A }; -static const int avs_planes_rgba[4] = { AVS_PLANAR_G, AVS_PLANAR_B, - AVS_PLANAR_R, AVS_PLANAR_A }; - -/* A conflict between C++ global objects, atexit, and dynamic loading requires - * us to register our own atexit handler to prevent double freeing. */ -static AviSynthLibrary avs_library; -static int avs_atexit_called = 0; - -/* Linked list of AviSynthContexts. An atexit handler destroys this list. */ -static AviSynthContext *avs_ctx_list = NULL; - -static av_cold void avisynth_atexit_handler(void); - -static av_cold int avisynth_load_library(void) +static av_cold int avisynth_load_library(AviSynthContext *avs) { - avs_library.library = dlopen(AVISYNTH_LIB, RTLD_NOW | RTLD_LOCAL); - if (!avs_library.library) + avs->avs_library.library = dlopen(AVISYNTH_LIB, RTLD_NOW | RTLD_LOCAL); + if (!avs->avs_library.library) return AVERROR_UNKNOWN; #define LOAD_AVS_FUNC(name, continue_on_fail) \ - avs_library.name = (name ## _func) \ - dlsym(avs_library.library, #name); \ - if (!continue_on_fail && !avs_library.name) \ + avs->avs_library.name = (name ## _func) \ + dlsym(avs->avs_library.library, #name); \ + if (!continue_on_fail && !avs->avs_library.name) \ goto fail; LOAD_AVS_FUNC(avs_bit_blt, 0); @@ -183,11 +160,10 @@ static av_cold int avisynth_load_library(void) LOAD_AVS_FUNC(avs_get_env_property, 1); #undef LOAD_AVS_FUNC - atexit(avisynth_atexit_handler); return 0; fail: - dlclose(avs_library.library); + dlclose(avs->avs_library.library); return AVERROR_UNKNOWN; } @@ -199,67 +175,34 @@ static av_cold int avisynth_context_create(AVFormatContext *s) AviSynthContext *avs = s->priv_data; int ret; - if (!avs_library.library) - if (ret = avisynth_load_library()) + if (!avs->avs_library.library) + if (ret = avisynth_load_library(avs)) return ret; - avs->env = avs_library.avs_create_script_environment(3); - if (avs_library.avs_get_error) { - const char *error = avs_library.avs_get_error(avs->env); + avs->env = avs->avs_library.avs_create_script_environment(3); + if (avs->avs_library.avs_get_error) { + const char *error = avs->avs_library.avs_get_error(avs->env); if (error) { av_log(s, AV_LOG_ERROR, "%s\n", error); return AVERROR_UNKNOWN; } } - if (!avs_ctx_list) { - avs_ctx_list = avs; - } else { - avs->next = avs_ctx_list; - avs_ctx_list = avs; - } - return 0; } static av_cold void avisynth_context_destroy(AviSynthContext *avs) { - if (avs_atexit_called) - return; - - if (avs == avs_ctx_list) { - avs_ctx_list = avs->next; - } else { - AviSynthContext *prev = avs_ctx_list; - while (prev->next != avs) - prev = prev->next; - prev->next = avs->next; - } - if (avs->clip) { - avs_library.avs_release_clip(avs->clip); + avs->avs_library.avs_release_clip(avs->clip); avs->clip = NULL; } if (avs->env) { - avs_library.avs_delete_script_environment(avs->env); + avs->avs_library.avs_delete_script_environment(avs->env); avs->env = NULL; } } -static av_cold void avisynth_atexit_handler(void) -{ - AviSynthContext *avs = avs_ctx_list; - - while (avs) { - AviSynthContext *next = avs->next; - avisynth_context_destroy(avs); - avs = next; - } - dlclose(avs_library.library); - - avs_atexit_called = 1; -} - /* Create AVStream from audio and video data. */ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) { @@ -271,6 +214,17 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) int sar_num = 1; int sar_den = 1; + static const int avs_planes_packed[1] = { 0 }; + static const int avs_planes_grey[1] = { AVS_PLANAR_Y }; + static const int avs_planes_yuv[3] = { AVS_PLANAR_Y, AVS_PLANAR_U, + AVS_PLANAR_V }; + static const int avs_planes_rgb[3] = { AVS_PLANAR_G, AVS_PLANAR_B, + AVS_PLANAR_R }; + static const int avs_planes_yuva[4] = { AVS_PLANAR_Y, AVS_PLANAR_U, + AVS_PLANAR_V, AVS_PLANAR_A }; + static const int avs_planes_rgba[4] = { AVS_PLANAR_G, AVS_PLANAR_B, + AVS_PLANAR_R, AVS_PLANAR_A }; + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; st->codecpar->width = avs->vi->width; @@ -529,17 +483,17 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) * version 9 at the minimum. Technically, 8.1 works, but the time * distance between 8.1 and 9 is very small, so just restrict it to 9. */ - if (avs_library.avs_get_version(avs->clip) >= 9) { + if (avs->avs_library.avs_get_version(avs->clip) >= 9) { - frame = avs_library.avs_get_frame(avs->clip, 0); - avsmap = avs_library.avs_get_frame_props_ro(avs->env, frame); + frame = avs->avs_library.avs_get_frame(avs->clip, 0); + avsmap = avs->avs_library.avs_get_frame_props_ro(avs->env, frame); /* Field order */ if(avs->flags & AVISYNTH_FRAMEPROP_FIELD_ORDER) { - if(avs_library.avs_prop_get_type(avs->env, avsmap, "_FieldBased") == AVS_PROPTYPE_UNSET) { + if(avs->avs_library.avs_prop_get_type(avs->env, avsmap, "_FieldBased") == AVS_PROPTYPE_UNSET) { st->codecpar->field_order = AV_FIELD_UNKNOWN; } else { - switch (avs_library.avs_prop_get_int(avs->env, avsmap, "_FieldBased", 0, &error)) { + switch (avs->avs_library.avs_prop_get_int(avs->env, avsmap, "_FieldBased", 0, &error)) { case 0: st->codecpar->field_order = AV_FIELD_PROGRESSIVE; break; @@ -557,10 +511,10 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) /* Color Range */ if(avs->flags & AVISYNTH_FRAMEPROP_RANGE) { - if(avs_library.avs_prop_get_type(avs->env, avsmap, "_ColorRange") == AVS_PROPTYPE_UNSET) { + if(avs->avs_library.avs_prop_get_type(avs->env, avsmap, "_ColorRange") == AVS_PROPTYPE_UNSET) { st->codecpar->color_range = AVCOL_RANGE_UNSPECIFIED; } else { - switch (avs_library.avs_prop_get_int(avs->env, avsmap, "_ColorRange", 0, &error)) { + switch (avs->avs_library.avs_prop_get_int(avs->env, avsmap, "_ColorRange", 0, &error)) { case 0: st->codecpar->color_range = AVCOL_RANGE_JPEG; break; @@ -575,7 +529,7 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) /* Color Primaries */ if(avs->flags & AVISYNTH_FRAMEPROP_PRIMARIES) { - switch (avs_library.avs_prop_get_int(avs->env, avsmap, "_Primaries", 0, &error)) { + switch (avs->avs_library.avs_prop_get_int(avs->env, avsmap, "_Primaries", 0, &error)) { case 1: st->codecpar->color_primaries = AVCOL_PRI_BT709; break; @@ -619,7 +573,7 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) /* Color Transfer Characteristics */ if(avs->flags & AVISYNTH_FRAMEPROP_TRANSFER) { - switch (avs_library.avs_prop_get_int(avs->env, avsmap, "_Transfer", 0, &error)) { + switch (avs->avs_library.avs_prop_get_int(avs->env, avsmap, "_Transfer", 0, &error)) { case 1: st->codecpar->color_trc = AVCOL_TRC_BT709; break; @@ -678,10 +632,10 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) /* Matrix coefficients */ if(avs->flags & AVISYNTH_FRAMEPROP_MATRIX) { - if(avs_library.avs_prop_get_type(avs->env, avsmap, "_Matrix") == AVS_PROPTYPE_UNSET) { + if(avs->avs_library.avs_prop_get_type(avs->env, avsmap, "_Matrix") == AVS_PROPTYPE_UNSET) { st->codecpar->color_space = AVCOL_SPC_UNSPECIFIED; } else { - switch (avs_library.avs_prop_get_int(avs->env, avsmap, "_Matrix", 0, &error)) { + switch (avs->avs_library.avs_prop_get_int(avs->env, avsmap, "_Matrix", 0, &error)) { case 0: st->codecpar->color_space = AVCOL_SPC_RGB; break; @@ -732,10 +686,10 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) /* Chroma Location */ if(avs->flags & AVISYNTH_FRAMEPROP_CHROMA_LOCATION) { - if(avs_library.avs_prop_get_type(avs->env, avsmap, "_ChromaLocation") == AVS_PROPTYPE_UNSET) { + if(avs->avs_library.avs_prop_get_type(avs->env, avsmap, "_ChromaLocation") == AVS_PROPTYPE_UNSET) { st->codecpar->chroma_location = AVCHROMA_LOC_UNSPECIFIED; } else { - switch (avs_library.avs_prop_get_int(avs->env, avsmap, "_ChromaLocation", 0, &error)) { + switch (avs->avs_library.avs_prop_get_int(avs->env, avsmap, "_ChromaLocation", 0, &error)) { case 0: st->codecpar->chroma_location = AVCHROMA_LOC_LEFT; break; @@ -762,12 +716,12 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) /* Sample aspect ratio */ if(avs->flags & AVISYNTH_FRAMEPROP_SAR) { - sar_num = avs_library.avs_prop_get_int(avs->env, avsmap, "_SARNum", 0, &error); - sar_den = avs_library.avs_prop_get_int(avs->env, avsmap, "_SARDen", 0, &error); + sar_num = avs->avs_library.avs_prop_get_int(avs->env, avsmap, "_SARNum", 0, &error); + sar_den = avs->avs_library.avs_prop_get_int(avs->env, avsmap, "_SARDen", 0, &error); st->sample_aspect_ratio = (AVRational){ sar_num, sar_den }; } - avs_library.avs_release_video_frame(frame); + avs->avs_library.avs_release_video_frame(frame); } else { st->codecpar->field_order = AV_FIELD_UNKNOWN; /* AviSynth works with frame-based video, detecting field order can @@ -796,9 +750,9 @@ static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) st->duration = avs->vi->num_audio_samples; avpriv_set_pts_info(st, 64, 1, avs->vi->audio_samples_per_second); - if (avs_library.avs_get_version(avs->clip) >= 10) + if (avs->avs_library.avs_get_version(avs->clip) >= 10) av_channel_layout_from_mask(&st->codecpar->ch_layout, - avs_library.avs_get_channel_mask(avs->vi)); + avs->avs_library.avs_get_channel_mask(avs->vi)); switch (avs->vi->sample_type) { case AVS_SAMPLE_INT8: @@ -860,13 +814,13 @@ static int avisynth_open_file(AVFormatContext *s) if (ret = avisynth_context_create(s)) return ret; - if (!avs_library.avs_check_version(avs->env, 7)) { + if (!avs->avs_library.avs_check_version(avs->env, 7)) { AVS_Value args[] = { avs_new_value_string(s->url), avs_new_value_bool(1) // filename is in UTF-8 }; - val = avs_library.avs_invoke(avs->env, "Import", - avs_new_value_array(args, 2), 0); + val = avs->avs_library.avs_invoke(avs->env, "Import", + avs_new_value_array(args, 2), 0); } else { AVS_Value arg; #ifdef _WIN32 @@ -880,7 +834,7 @@ static int avisynth_open_file(AVFormatContext *s) #else arg = avs_new_value_string(s->url); #endif - val = avs_library.avs_invoke(avs->env, "Import", arg, 0); + val = avs->avs_library.avs_invoke(avs->env, "Import", arg, 0); #ifdef _WIN32 av_free(filename_ansi); #endif @@ -897,14 +851,14 @@ static int avisynth_open_file(AVFormatContext *s) goto fail; } - avs->clip = avs_library.avs_take_clip(val, avs->env); - avs->vi = avs_library.avs_get_video_info(avs->clip); + avs->clip = avs->avs_library.avs_take_clip(val, avs->env); + avs->vi = avs->avs_library.avs_get_video_info(avs->clip); /* On Windows, FFmpeg supports AviSynth interface version 6 or higher. * This includes AviSynth 2.6 RC1 or higher, and AviSynth+ r1718 or higher, * and excludes 2.5 and the 2.6 alphas. */ - if (avs_library.avs_get_version(avs->clip) < 6) { + if (avs->avs_library.avs_get_version(avs->clip) < 6) { av_log(s, AV_LOG_ERROR, "AviSynth version is too old. Please upgrade to either AviSynth 2.6 >= RC1 or AviSynth+ >= r1718.\n"); ret = AVERROR_UNKNOWN; @@ -912,7 +866,7 @@ static int avisynth_open_file(AVFormatContext *s) } /* Release the AVS_Value as it will go out of scope. */ - avs_library.avs_release_value(val); + avs->avs_library.avs_release_value(val); if (ret = avisynth_create_stream(s)) goto fail; @@ -960,7 +914,7 @@ static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, if (discard) return 0; - bits = avs_library.avs_bits_per_pixel(avs->vi); + bits = avs->avs_library.avs_bits_per_pixel(avs->vi); /* Without the cast to int64_t, calculation overflows at about 9k x 9k * resolution. */ @@ -977,8 +931,8 @@ static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, pkt->duration = 1; pkt->stream_index = avs->curr_stream; - frame = avs_library.avs_get_frame(avs->clip, n); - error = avs_library.avs_clip_get_error(avs->clip); + frame = avs->avs_library.avs_get_frame(avs->clip, n); + error = avs->avs_library.avs_clip_get_error(avs->clip); if (error) { av_log(s, AV_LOG_ERROR, "%s\n", error); avs->error = 1; @@ -989,26 +943,26 @@ static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, dst_p = pkt->data; for (i = 0; i < avs->n_planes; i++) { plane = avs->planes[i]; - src_p = avs_library.avs_get_read_ptr_p(frame, plane); - pitch = avs_library.avs_get_pitch_p(frame, plane); + src_p = avs->avs_library.avs_get_read_ptr_p(frame, plane); + pitch = avs->avs_library.avs_get_pitch_p(frame, plane); - rowsize = avs_library.avs_get_row_size_p(frame, plane); - planeheight = avs_library.avs_get_height_p(frame, plane); + rowsize = avs->avs_library.avs_get_row_size_p(frame, plane); + planeheight = avs->avs_library.avs_get_height_p(frame, plane); /* Flip RGB video. */ - if (avs_library.avs_is_color_space(avs->vi, AVS_CS_BGR) || - avs_library.avs_is_color_space(avs->vi, AVS_CS_BGR48) || - avs_library.avs_is_color_space(avs->vi, AVS_CS_BGR64)) { + if (avs->avs_library.avs_is_color_space(avs->vi, AVS_CS_BGR) || + avs->avs_library.avs_is_color_space(avs->vi, AVS_CS_BGR48) || + avs->avs_library.avs_is_color_space(avs->vi, AVS_CS_BGR64)) { src_p = src_p + (planeheight - 1) * pitch; pitch = -pitch; } - avs_library.avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch, - rowsize, planeheight); + avs->avs_library.avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch, + rowsize, planeheight); dst_p += rowsize * planeheight; } - avs_library.avs_release_video_frame(frame); + avs->avs_library.avs_release_video_frame(frame); return 0; } @@ -1068,8 +1022,8 @@ static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, pkt->duration = samples; pkt->stream_index = avs->curr_stream; - avs_library.avs_get_audio(avs->clip, pkt->data, n, samples); - error = avs_library.avs_clip_get_error(avs->clip); + avs->avs_library.avs_get_audio(avs->clip, pkt->data, n, samples); + error = avs->avs_library.avs_clip_get_error(avs->clip); if (error) { av_log(s, AV_LOG_ERROR, "%s\n", error); avs->error = 1; @@ -1083,16 +1037,9 @@ static av_cold int avisynth_read_header(AVFormatContext *s) { int ret; - // Calling library must implement a lock for thread-safe opens. - if (ret = ff_lock_avformat()) + if (ret = avisynth_open_file(s)) return ret; - if (ret = avisynth_open_file(s)) { - ff_unlock_avformat(); - return ret; - } - - ff_unlock_avformat(); return 0; } @@ -1128,11 +1075,13 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) static av_cold int avisynth_read_close(AVFormatContext *s) { - if (ff_lock_avformat()) - return AVERROR_UNKNOWN; + AviSynthContext *avs = s->priv_data; + + if (avs->avs_library.library) { + avisynth_context_destroy(s->priv_data); + dlclose(avs->avs_library.library); + } - avisynth_context_destroy(s->priv_data); - ff_unlock_avformat(); return 0; } diff --git a/libavformat/bethsoftvid.c b/libavformat/bethsoftvid.c index bdf1bdc6c..e3c4758f3 100644 --- a/libavformat/bethsoftvid.c +++ b/libavformat/bethsoftvid.c @@ -30,6 +30,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/bitstream.c b/libavformat/bitstream.c deleted file mode 100644 index 2afda37c3..000000000 --- a/libavformat/bitstream.c +++ /dev/null @@ -1 +0,0 @@ -#include "libavcodec/bitstream.c" diff --git a/libavformat/bmv.c b/libavformat/bmv.c index b2980cf58..84ab2aac5 100644 --- a/libavformat/bmv.c +++ b/libavformat/bmv.c @@ -20,6 +20,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/brstm.c b/libavformat/brstm.c index 8b0ba3af6..d29004155 100644 --- a/libavformat/brstm.c +++ b/libavformat/brstm.c @@ -20,6 +20,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/bytestream.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/cache.c b/libavformat/cache.c index 115c2c249..5d71e56f3 100644 --- a/libavformat/cache.c +++ b/libavformat/cache.c @@ -30,6 +30,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/file_open.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/tree.h" #include "avio.h" @@ -51,7 +52,7 @@ typedef struct CacheEntry { int size; } CacheEntry; -typedef struct Context { +typedef struct CacheContext { AVClass *class; int fd; char *filename; @@ -64,7 +65,7 @@ typedef struct Context { URLContext *inner; int64_t cache_hit, cache_miss; int read_ahead_limit; -} Context; +} CacheContext; static int cmp(const void *key, const void *node) { @@ -73,9 +74,9 @@ static int cmp(const void *key, const void *node) static int cache_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { + CacheContext *c = h->priv_data; int ret; char *buffername; - Context *c= h->priv_data; av_strstart(arg, "cache:", &arg); @@ -98,7 +99,7 @@ static int cache_open(URLContext *h, const char *arg, int flags, AVDictionary ** static int add_entry(URLContext *h, const unsigned char *buf, int size) { - Context *c= h->priv_data; + CacheContext *c = h->priv_data; int64_t pos = -1; int ret; CacheEntry *entry = NULL, *next[2] = {NULL, NULL}; @@ -161,7 +162,7 @@ fail: static int cache_read(URLContext *h, unsigned char *buf, int size) { - Context *c= h->priv_data; + CacheContext *c = h->priv_data; CacheEntry *entry, *next[2] = {NULL, NULL}; int64_t r; @@ -226,7 +227,7 @@ static int cache_read(URLContext *h, unsigned char *buf, int size) static int64_t cache_seek(URLContext *h, int64_t pos, int whence) { - Context *c= h->priv_data; + CacheContext *c = h->priv_data; int64_t ret; if (whence == AVSEEK_SIZE) { @@ -297,7 +298,7 @@ static int enu_free(void *opaque, void *elem) static int cache_close(URLContext *h) { - Context *c= h->priv_data; + CacheContext *c = h->priv_data; int ret; av_log(h, AV_LOG_INFO, "Statistics, cache hits:%"PRId64" cache misses:%"PRId64"\n", @@ -317,7 +318,7 @@ static int cache_close(URLContext *h) return 0; } -#define OFFSET(x) offsetof(Context, x) +#define OFFSET(x) offsetof(CacheContext, x) #define D AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { @@ -338,6 +339,6 @@ const URLProtocol ff_cache_protocol = { .url_read = cache_read, .url_seek = cache_seek, .url_close = cache_close, - .priv_data_size = sizeof(Context), + .priv_data_size = sizeof(CacheContext), .priv_data_class = &cache_context_class, }; diff --git a/libavformat/cafdec.c b/libavformat/cafdec.c index 07a2939a7..5d7dbe8f4 100644 --- a/libavformat/cafdec.c +++ b/libavformat/cafdec.c @@ -36,6 +36,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "caf.h" typedef struct CafContext { diff --git a/libavformat/cafenc.c b/libavformat/cafenc.c index 426bc0520..89ecb51e5 100644 --- a/libavformat/cafenc.c +++ b/libavformat/cafenc.c @@ -26,6 +26,7 @@ #include "mux.h" #include "libavutil/intfloat.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #define FRAME_SIZE_OFFSET 40 diff --git a/libavformat/chromaprint.c b/libavformat/chromaprint.c index 1cdca47ea..eae233a65 100644 --- a/libavformat/chromaprint.c +++ b/libavformat/chromaprint.c @@ -20,15 +20,17 @@ */ #include "avformat.h" -#include "internal.h" #include "mux.h" #include "libavutil/opt.h" +#include "libavutil/thread.h" #include #define CPR_VERSION_INT AV_VERSION_INT(CHROMAPRINT_VERSION_MAJOR, \ CHROMAPRINT_VERSION_MINOR, \ CHROMAPRINT_VERSION_PATCH) +static AVMutex chromaprint_mutex = AV_MUTEX_INITIALIZER; + typedef enum FingerprintFormat { FINGERPRINT_RAW, FINGERPRINT_COMPRESSED, @@ -52,9 +54,9 @@ static void deinit(AVFormatContext *s) ChromaprintMuxContext *const cpr = s->priv_data; if (cpr->ctx) { - ff_lock_avformat(); + ff_mutex_lock(&chromaprint_mutex); chromaprint_free(cpr->ctx); - ff_unlock_avformat(); + ff_mutex_unlock(&chromaprint_mutex); } } @@ -63,9 +65,9 @@ static av_cold int init(AVFormatContext *s) ChromaprintMuxContext *cpr = s->priv_data; AVStream *st; - ff_lock_avformat(); + ff_mutex_lock(&chromaprint_mutex); cpr->ctx = chromaprint_new(cpr->algorithm); - ff_unlock_avformat(); + ff_mutex_unlock(&chromaprint_mutex); if (!cpr->ctx) { av_log(s, AV_LOG_ERROR, "Failed to create chromaprint context.\n"); diff --git a/libavformat/cinedec.c b/libavformat/cinedec.c index 9ddfc90b4..e0bcca4ce 100644 --- a/libavformat/cinedec.c +++ b/libavformat/cinedec.c @@ -26,6 +26,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/bmp.h" #include "libavutil/intfloat.h" #include "avformat.h" diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c index 93cab01ce..fe65d0c76 100644 --- a/libavformat/concatdec.c +++ b/libavformat/concatdec.c @@ -22,6 +22,7 @@ #include "libavutil/avassert.h" #include "libavutil/bprint.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/timestamp.h" diff --git a/libavformat/crypto.c b/libavformat/crypto.c index 4393fb639..868f6ddc2 100644 --- a/libavformat/crypto.c +++ b/libavformat/crypto.c @@ -21,6 +21,7 @@ #include "libavutil/aes.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "url.h" @@ -61,7 +62,7 @@ typedef struct CryptoContext { #define OFFSET(x) offsetof(CryptoContext, x) #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM -static const AVOption options[] = { +static const AVOption crypto_options[] = { {"key", "AES encryption/decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, .flags = D|E }, {"iv", "AES encryption/decryption initialization vector", OFFSET(iv), AV_OPT_TYPE_BINARY, .flags = D|E }, {"decryption_key", "AES decryption key", OFFSET(decrypt_key), AV_OPT_TYPE_BINARY, .flags = D }, @@ -74,7 +75,7 @@ static const AVOption options[] = { static const AVClass crypto_class = { .class_name = "crypto", .item_name = av_default_item_name, - .option = options, + .option = crypto_options, .version = LIBAVUTIL_VERSION_INT, }; diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c index 63070b77b..71d79067a 100644 --- a/libavformat/dashdec.c +++ b/libavformat/dashdec.c @@ -22,6 +22,7 @@ #include #include #include "libavutil/bprint.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time.h" #include "libavutil/parseutils.h" @@ -445,7 +446,7 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, av_freep(pb); av_dict_copy(&tmp, *opts, 0); av_dict_copy(&tmp, opts2, 0); - ret = avio_open2(pb, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); + ret = ffio_open_whitelist(pb, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp, s->protocol_whitelist, s->protocol_blacklist); if (ret >= 0) { // update cookies on http response with setcookies. char *new_cookies = NULL; @@ -1224,7 +1225,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) close_in = 1; av_dict_copy(&opts, c->avio_opts, 0); - ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); + ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist); av_dict_free(&opts); if (ret < 0) return ret; @@ -1931,25 +1932,27 @@ static int open_demux_for_component(AVFormatContext *s, struct representation *p int i; pls->parent = s; - pls->cur_seq_no = calc_cur_seg_no(s, pls); + pls->cur_seq_no = calc_cur_seg_no(s, pls); - if (!pls->last_seq_no) { + if (!pls->last_seq_no) pls->last_seq_no = calc_max_seg_no(pls, s->priv_data); - } ret = reopen_demux_for_component(s, pls); - if (ret < 0) { - goto fail; - } + if (ret < 0) + return ret; + for (i = 0; i < pls->ctx->nb_streams; i++) { AVStream *st = avformat_new_stream(s, NULL); AVStream *ist = pls->ctx->streams[i]; - if (!st) { - ret = AVERROR(ENOMEM); - goto fail; - } + if (!st) + return AVERROR(ENOMEM); + st->id = i; - avcodec_parameters_copy(st->codecpar, ist->codecpar); + + ret = avcodec_parameters_copy(st->codecpar, ist->codecpar); + if (ret < 0) + return ret; + avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); // copy disposition @@ -1957,8 +1960,6 @@ static int open_demux_for_component(AVFormatContext *s, struct representation *p } return 0; -fail: - return ret; } static int is_common_init_section_exist(struct representation **pls, int n_pls) @@ -2207,9 +2208,9 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt) if (cur->is_restart_needed) { cur->cur_seg_offset = 0; cur->init_sec_buf_read_offset = 0; + cur->is_restart_needed = 0; ff_format_io_close(cur->parent, &cur->input); ret = reopen_demux_for_component(s, cur); - cur->is_restart_needed = 0; } } return AVERROR_EOF; diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 5cb38c4c3..d4a6fe030 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -33,6 +33,7 @@ #include "libavutil/bprint.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/rational.h" @@ -1321,7 +1322,7 @@ static int write_manifest(AVFormatContext *s, int final) av_strlcat(codec_str, audio_codec_str, sizeof(codec_str)); } get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); - ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, + ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, 0, playlist_file, agroup, codec_str, NULL, NULL); } @@ -1347,7 +1348,7 @@ static int write_manifest(AVFormatContext *s, int final) continue; av_strlcpy(codec_str, os->codec_str, sizeof(codec_str)); get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); - ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, + ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, 0, playlist_file, NULL, codec_str, NULL, NULL); } diff --git a/libavformat/data_uri.c b/libavformat/data_uri.c index 28eb2b9e0..3868a1963 100644 --- a/libavformat/data_uri.c +++ b/libavformat/data_uri.c @@ -22,6 +22,7 @@ #include "libavutil/avstring.h" #include "libavutil/avutil.h" #include "libavutil/base64.h" +#include "libavutil/mem.h" #include "url.h" typedef struct { diff --git a/libavformat/demux.c b/libavformat/demux.c index 5027b8420..4fd22c493 100644 --- a/libavformat/demux.c +++ b/libavformat/demux.c @@ -29,6 +29,7 @@ #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixfmt.h" #include "libavutil/time.h" @@ -1318,6 +1319,8 @@ fail: return ret; } +static int extract_extradata(FFFormatContext *si, AVStream *st, const AVPacket *pkt); + static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) { FFFormatContext *const si = ffformatcontext(s); @@ -1372,6 +1375,16 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) return ret; } + if (!sti->avctx->extradata) { + sti->extract_extradata.inited = 0; + + ret = extract_extradata(si, st, pkt); + if (ret < 0) { + av_packet_unref(pkt); + return ret; + } + } + sti->codec_desc = avcodec_descriptor_get(sti->avctx->codec_id); sti->need_context_update = 0; @@ -1803,8 +1816,9 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic) "Estimating duration from bitrate, this may be inaccurate\n"); } -#define DURATION_MAX_READ_SIZE 250000LL -#define DURATION_MAX_RETRY 6 +#define DURATION_DEFAULT_MAX_READ_SIZE 250000LL +#define DURATION_DEFAULT_MAX_RETRY 6 +#define DURATION_MAX_RETRY 1 /* only usable for MPEG-PS streams */ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) @@ -1812,6 +1826,8 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) FFFormatContext *const si = ffformatcontext(ic); AVPacket *const pkt = si->pkt; int num, den, read_size, ret; + int64_t duration_max_read_size = ic->duration_probesize ? ic->duration_probesize >> DURATION_MAX_RETRY : DURATION_DEFAULT_MAX_READ_SIZE; + int duration_max_retry = ic->duration_probesize ? DURATION_MAX_RETRY : DURATION_DEFAULT_MAX_RETRY; int found_duration = 0; int is_end; int64_t filesize, offset, duration; @@ -1847,7 +1863,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) filesize = ic->pb ? avio_size(ic->pb) : 0; do { is_end = found_duration; - offset = filesize - (DURATION_MAX_READ_SIZE << retry); + offset = filesize - (duration_max_read_size << retry); if (offset < 0) offset = 0; @@ -1856,7 +1872,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) for (;;) { AVStream *st; FFStream *sti; - if (read_size >= DURATION_MAX_READ_SIZE << (FFMAX(retry - 1, 0))) + if (read_size >= duration_max_read_size << (FFMAX(retry - 1, 0))) break; do { @@ -1910,7 +1926,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) } } while (!is_end && offset && - ++retry <= DURATION_MAX_RETRY); + ++retry <= duration_max_retry); av_opt_set_int(ic, "skip_changes", 0, AV_OPT_SEARCH_CHILDREN); @@ -2423,6 +2439,7 @@ static int extract_extradata_init(AVStream *st) if (!ret) goto finish; + av_bsf_free(&sti->extract_extradata.bsf); ret = av_bsf_alloc(f, &sti->extract_extradata.bsf); if (ret < 0) return ret; @@ -3085,9 +3102,12 @@ find_stream_info_err: av_freep(&sti->info); } - err = codec_close(sti); - if (err < 0 && ret >= 0) - ret = err; + if (avcodec_is_open(sti->avctx)) { + err = codec_close(sti); + if (err < 0 && ret >= 0) + ret = err; + } + av_bsf_free(&sti->extract_extradata.bsf); } if (ic->pb) { diff --git a/libavformat/demux_utils.c b/libavformat/demux_utils.c index 171a07107..86f551245 100644 --- a/libavformat/demux_utils.c +++ b/libavformat/demux_utils.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/version.h" +#include "libavutil/mem.h" #include "libavutil/avassert.h" #include "libavcodec/bytestream.h" diff --git a/libavformat/dhav.c b/libavformat/dhav.c index 997875eff..b2ead9960 100644 --- a/libavformat/dhav.c +++ b/libavformat/dhav.c @@ -22,6 +22,7 @@ #include +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "avio_internal.h" #include "avformat.h" @@ -272,9 +273,14 @@ static int dhav_read_header(AVFormatContext *s) { DHAVContext *dhav = s->priv_data; uint8_t signature[5]; + int ret = ffio_ensure_seekback(s->pb, 5); - ffio_ensure_seekback(s->pb, 5); - avio_read(s->pb, signature, sizeof(signature)); + if (ret < 0) + return ret; + + ret = ffio_read_size(s->pb, signature, sizeof(signature)); + if (ret < 0) + return ret; if (!memcmp(signature, "DAHUA", 5)) { avio_skip(s->pb, 0x400 - 5); dhav->last_good_pos = avio_tell(s->pb); diff --git a/libavformat/dovi_isom.c b/libavformat/dovi_isom.c index ef7ab1b6d..269374cff 100644 --- a/libavformat/dovi_isom.c +++ b/libavformat/dovi_isom.c @@ -22,6 +22,7 @@ */ #include "libavutil/dovi_meta.h" +#include "libavutil/mem.h" #include "libavcodec/put_bits.h" @@ -56,11 +57,14 @@ int ff_isom_parse_dvcc_dvvc(void *logctx, AVStream *st, // Has enough remaining data if (size >= 5) { - dovi->dv_bl_signal_compatibility_id = ((*buf_ptr++) >> 4) & 0x0f; // 4 bits + uint8_t buf = *buf_ptr++; + dovi->dv_bl_signal_compatibility_id = (buf >> 4) & 0x0f; // 4 bits + dovi->dv_md_compression = (buf >> 2) & 0x03; // 2 bits } else { // 0 stands for None // Dolby Vision V1.2.93 profiles and levels dovi->dv_bl_signal_compatibility_id = 0; + dovi->dv_md_compression = AV_DOVI_COMPRESSION_NONE; } if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data, @@ -70,13 +74,14 @@ int ff_isom_parse_dvcc_dvvc(void *logctx, AVStream *st, } av_log(logctx, AV_LOG_TRACE, "DOVI in dvcC/dvvC/dvwC box, version: %d.%d, profile: %d, level: %d, " - "rpu flag: %d, el flag: %d, bl flag: %d, compatibility id: %d\n", + "rpu flag: %d, el flag: %d, bl flag: %d, compatibility id: %d, compression: %d\n", dovi->dv_version_major, dovi->dv_version_minor, dovi->dv_profile, dovi->dv_level, dovi->rpu_present_flag, dovi->el_present_flag, dovi->bl_present_flag, - dovi->dv_bl_signal_compatibility_id); + dovi->dv_bl_signal_compatibility_id, + dovi->dv_md_compression); return 0; } @@ -96,8 +101,9 @@ void ff_isom_put_dvcc_dvvc(void *logctx, uint8_t out[ISOM_DVCC_DVVC_SIZE], put_bits(&pb, 1, !!dovi->el_present_flag); put_bits(&pb, 1, !!dovi->bl_present_flag); put_bits(&pb, 4, dovi->dv_bl_signal_compatibility_id & 0x0f); + put_bits(&pb, 2, dovi->dv_md_compression & 0x03); - put_bits(&pb, 28, 0); /* reserved */ + put_bits(&pb, 26, 0); /* reserved */ put_bits32(&pb, 0); /* reserved */ put_bits32(&pb, 0); /* reserved */ put_bits32(&pb, 0); /* reserved */ @@ -107,12 +113,14 @@ void ff_isom_put_dvcc_dvvc(void *logctx, uint8_t out[ISOM_DVCC_DVVC_SIZE], av_log(logctx, AV_LOG_DEBUG, "DOVI in %s box, version: %d.%d, profile: %d, level: %d, " - "rpu flag: %d, el flag: %d, bl flag: %d, compatibility id: %d\n", + "rpu flag: %d, el flag: %d, bl flag: %d, compatibility id: %d, " + "compression: %d\n", dovi->dv_profile > 10 ? "dvwC" : (dovi->dv_profile > 7 ? "dvvC" : "dvcC"), dovi->dv_version_major, dovi->dv_version_minor, dovi->dv_profile, dovi->dv_level, dovi->rpu_present_flag, dovi->el_present_flag, dovi->bl_present_flag, - dovi->dv_bl_signal_compatibility_id); + dovi->dv_bl_signal_compatibility_id, + dovi->dv_md_compression); } diff --git a/libavformat/dss.c b/libavformat/dss.c index 510b1bd60..47c8f49d6 100644 --- a/libavformat/dss.c +++ b/libavformat/dss.c @@ -21,6 +21,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/dtshddec.c b/libavformat/dtshddec.c index 9939724ac..28d3aeb47 100644 --- a/libavformat/dtshddec.c +++ b/libavformat/dtshddec.c @@ -21,6 +21,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "libavcodec/dca.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/dump.c b/libavformat/dump.c index ca47d733f..f20c2c495 100644 --- a/libavformat/dump.c +++ b/libavformat/dump.c @@ -32,6 +32,7 @@ #include "libavutil/ambient_viewing_environment.h" #include "libavutil/dovi_meta.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/replaygain.h" #include "libavutil/spherical.h" @@ -258,7 +259,16 @@ static void dump_stereo3d(void *ctx, const AVPacketSideData *sd, int log_level) stereo = (const AVStereo3D *)sd->data; - av_log(ctx, log_level, "%s", av_stereo3d_type_name(stereo->type)); + av_log(ctx, log_level, "%s, view: %s, primary eye: %s", + av_stereo3d_type_name(stereo->type), av_stereo3d_view_name(stereo->view), + av_stereo3d_primary_eye_name(stereo->primary_eye)); + if (stereo->baseline) + av_log(ctx, log_level, ", baseline: %"PRIu32"", stereo->baseline); + if (stereo->horizontal_disparity_adjustment.num && stereo->horizontal_disparity_adjustment.den) + av_log(ctx, log_level, ", horizontal_disparity_adjustment: %0.4f", + av_q2d(stereo->horizontal_disparity_adjustment)); + if (stereo->horizontal_field_of_view.num && stereo->horizontal_field_of_view.den) + av_log(ctx, log_level, ", horizontal_field_of_view: %0.3f", av_q2d(stereo->horizontal_field_of_view)); if (stereo->flags & AV_STEREO3D_FLAG_INVERT) av_log(ctx, log_level, " (inverted)"); @@ -380,10 +390,12 @@ static void dump_spherical(void *ctx, const AVCodecParameters *par, av_log(ctx, log_level, "%s ", av_spherical_projection_name(spherical->projection)); - yaw = ((double)spherical->yaw) / (1 << 16); - pitch = ((double)spherical->pitch) / (1 << 16); - roll = ((double)spherical->roll) / (1 << 16); - av_log(ctx, log_level, "(%f/%f/%f) ", yaw, pitch, roll); + if (spherical->yaw || spherical->pitch || spherical->roll) { + yaw = ((double)spherical->yaw) / (1 << 16); + pitch = ((double)spherical->pitch) / (1 << 16); + roll = ((double)spherical->roll) / (1 << 16); + av_log(ctx, log_level, "(%f/%f/%f) ", yaw, pitch, roll); + } if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) { size_t l, t, r, b; @@ -404,13 +416,15 @@ static void dump_dovi_conf(void *ctx, const AVPacketSideData *sd, (const AVDOVIDecoderConfigurationRecord *)sd->data; av_log(ctx, log_level, "version: %d.%d, profile: %d, level: %d, " - "rpu flag: %d, el flag: %d, bl flag: %d, compatibility id: %d", + "rpu flag: %d, el flag: %d, bl flag: %d, compatibility id: %d, " + "compression: %d", dovi->dv_version_major, dovi->dv_version_minor, dovi->dv_profile, dovi->dv_level, dovi->rpu_present_flag, dovi->el_present_flag, dovi->bl_present_flag, - dovi->dv_bl_signal_compatibility_id); + dovi->dv_bl_signal_compatibility_id, + dovi->dv_md_compression); } static void dump_s12m_timecode(void *ctx, const AVStream *st, const AVPacketSideData *sd, @@ -430,6 +444,23 @@ static void dump_s12m_timecode(void *ctx, const AVStream *st, const AVPacketSide } } +static void dump_cropping(void *ctx, const AVPacketSideData *sd) +{ + uint32_t top, bottom, left, right; + + if (sd->size < sizeof(uint32_t) * 4) { + av_log(ctx, AV_LOG_ERROR, "invalid data\n"); + return; + } + + top = AV_RL32(sd->data + 0); + bottom = AV_RL32(sd->data + 4); + left = AV_RL32(sd->data + 8); + right = AV_RL32(sd->data + 12); + + av_log(ctx, AV_LOG_INFO, "%d/%d/%d/%d", left, right, top, bottom); +} + static void dump_sidedata(void *ctx, const AVStream *st, const char *indent, int log_level) { @@ -504,6 +535,10 @@ static void dump_sidedata(void *ctx, const AVStream *st, const char *indent, case AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT: dump_ambient_viewing_environment_metadata(ctx, sd); break; + case AV_PKT_DATA_FRAME_CROPPING: + av_log(ctx, AV_LOG_INFO, "Frame cropping: "); + dump_cropping(ctx, sd); + break; default: av_log(ctx, log_level, "unknown side data type %d " "(%"SIZE_SPECIFIER" bytes)", sd->type, sd->size); @@ -552,6 +587,8 @@ static void dump_disposition(int disposition, int log_level) av_log(NULL, log_level, " (still image)"); if (disposition & AV_DISPOSITION_NON_DIEGETIC) av_log(NULL, log_level, " (non-diegetic)"); + if (disposition & AV_DISPOSITION_MULTILAYER) + av_log(NULL, log_level, " (multilayer)"); } /* "user interface" functions */ @@ -752,6 +789,33 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed, } break; } + case AV_STREAM_GROUP_PARAMS_LCEVC: { + const AVStreamGroupLCEVC *lcevc = stg->params.lcevc; + AVCodecContext *avctx = avcodec_alloc_context3(NULL); + const char *ptr = NULL; + av_log(NULL, AV_LOG_INFO, " LCEVC:"); + if (avctx && stg->nb_streams && !avcodec_parameters_to_context(avctx, stg->streams[0]->codecpar)) { + avctx->width = lcevc->width; + avctx->height = lcevc->height; + avctx->coded_width = lcevc->width; + avctx->coded_height = lcevc->height; + if (ic->dump_separator) + av_opt_set(avctx, "dump_separator", ic->dump_separator, 0); + buf[0] = 0; + avcodec_string(buf, sizeof(buf), avctx, is_output); + ptr = av_stristr(buf, " "); + } + avcodec_free_context(&avctx); + if (ptr) + av_log(NULL, AV_LOG_INFO, "%s", ptr); + av_log(NULL, AV_LOG_INFO, "\n"); + for (int i = 0; i < stg->nb_streams; i++) { + const AVStream *st = stg->streams[i]; + dump_stream_format(ic, st->index, i, index, is_output, AV_LOG_VERBOSE); + printed[st->index] = 1; + } + break; + } default: break; } diff --git a/libavformat/dv.c b/libavformat/dv.c index c0d3343e3..8af0d5a65 100644 --- a/libavformat/dv.c +++ b/libavformat/dv.c @@ -40,6 +40,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/timecode.h" #include "dv.h" #include "libavutil/avassert.h" diff --git a/libavformat/dvdvideodec.c b/libavformat/dvdvideodec.c index c94e7f7fe..f92c5ae54 100644 --- a/libavformat/dvdvideodec.c +++ b/libavformat/dvdvideodec.c @@ -38,14 +38,13 @@ #include #include +#include "libavcodec/ac3_parser.h" #include "libavutil/avstring.h" #include "libavutil/avutil.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" -#include "libavutil/time.h" -#include "libavutil/timestamp.h" #include "avformat.h" #include "avio_internal.h" @@ -58,7 +57,7 @@ #define DVDVIDEO_MAX_PS_SEARCH_BLOCKS 128 #define DVDVIDEO_BLOCK_SIZE 2048 #define DVDVIDEO_TIME_BASE_Q (AVRational) { 1, 90000 } -#define DVDVIDEO_PTS_WRAP_BITS 64 /* VOBUs use 32 (PES allows 33) */ +#define DVDVIDEO_PTS_WRAP_BITS 32 /* VOBUs use 32 (PES allows 33) */ #define DVDVIDEO_LIBDVDX_LOG_BUFFER_SIZE 1024 #define PCI_START_BYTE 45 /* complement dvdread's DSI_START_BYTE */ @@ -110,15 +109,16 @@ typedef struct DVDVideoPlaybackState { int in_pgc; /* if our navigator is in the PGC */ int in_ps; /* if our navigator is in the program stream */ int in_vts; /* if our navigator is in the VTS */ + int is_seeking; /* relax navigation path while seeking */ int64_t nav_pts; /* PTS according to IFO, not frame-accurate */ - int nb_cells_played; /* number of cells played back so far */ uint64_t pgc_duration_est; /* estimated duration as reported by IFO */ uint64_t pgc_elapsed; /* the elapsed time of the PGC, cell-relative */ int pgc_nb_pg_est; /* number of PGs as reported by IFOs */ int pgcn; /* ID of the PGC we are playing */ int pgn; /* ID of the PG we are in now */ + int ptm_discont; /* signal that a PTM discontinuity occurred */ + int64_t ptm_offset; /* PTM discontinuity offset (as NAV value) */ int ptt; /* ID of the chapter we are in now */ - int64_t ts_offset; /* PTS discontinuity offset (ex. VOB change) */ uint32_t vobu_duration; /* duration of the current VOBU */ uint32_t vobu_e_ptm; /* end PTM of the current VOBU */ int vtsn; /* ID of the active VTS (video title set) */ @@ -165,10 +165,12 @@ typedef struct DVDVideoDemuxContext { /* playback control */ int64_t first_pts; /* the PTS of the first video keyframe */ - int play_end; /* signal EOF to the parent demuxer */ - DVDVideoPlaybackState play_state; /* the active playback state */ int play_started; /* signal that playback has started */ - int segment_started; /* signal that subdemuxer is on a segment */ + DVDVideoPlaybackState play_state; /* the active playback state */ + int64_t *prev_pts; /* track the previous PTS emitted per stream */ + int64_t pts_offset; /* PTS discontinuity offset (ex. VOB change) */ + int seek_warned; /* signal that we warned about seeking limits */ + int subdemux_reset; /* signal that subdemuxer should be reset */ } DVDVideoDemuxContext; static void dvdvideo_libdvdread_log(void *opaque, dvd_logger_level_t level, @@ -345,7 +347,7 @@ static int dvdvideo_menu_open(AVFormatContext *s, DVDVideoPlaybackState *state) } /* make sure the PGC is valid */ - state->pgcn = c->opt_pgc - 1; + state->pgcn = c->opt_pgc; state->pgc = pgci_ut->lu[c->opt_menu_lu - 1].pgcit->pgci_srp[c->opt_pgc - 1].pgc; if (!state->pgc || !state->pgc->program_map || !state->pgc->cell_playback) { av_log(s, AV_LOG_ERROR, "Invalid PGC structure for menu [LU %d, PGC %d]\n", @@ -391,14 +393,16 @@ static int dvdvideo_menu_open(AVFormatContext *s, DVDVideoPlaybackState *state) } static int dvdvideo_menu_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState *state, - uint8_t *buf, int buf_size, - void (*flush_cb)(AVFormatContext *s)) + uint8_t *buf, int buf_size, int *p_is_nav_packet) { int64_t blocks_read = 0; uint8_t read_buf[DVDVIDEO_BLOCK_SIZE] = {0}; pci_t pci = (pci_t) {0}; dsi_t dsi = (dsi_t) {0}; + (*p_is_nav_packet) = 0; + state->ptm_discont = 0; + if (buf_size != DVDVIDEO_BLOCK_SIZE) { av_log(s, AV_LOG_ERROR, "Invalid buffer size (expected=%d actual=%d)\n", DVDVIDEO_BLOCK_SIZE, buf_size); @@ -464,10 +468,8 @@ static int dvdvideo_menu_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState if (state->in_pgc) { if (state->vobu_e_ptm != pci.pci_gi.vobu_s_ptm) { - if (flush_cb) - flush_cb(s); - - state->ts_offset += state->vobu_e_ptm - pci.pci_gi.vobu_s_ptm; + state->ptm_discont = 1; + state->ptm_offset += state->vobu_e_ptm - pci.pci_gi.vobu_s_ptm; } } else { state->in_pgc = 1; @@ -475,13 +477,17 @@ static int dvdvideo_menu_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState } state->vobu_e_ptm = pci.pci_gi.vobu_e_ptm; + state->vobu_duration = pci.pci_gi.vobu_e_ptm - pci.pci_gi.vobu_s_ptm; av_log(s, AV_LOG_DEBUG, "NAV packet: sector=%d " - "vobu_s_ptm=%d vobu_e_ptm=%d ts_offset=%" PRId64 "\n", + "vobu_s_ptm=%d vobu_e_ptm=%d ptm_offset=%" PRId64 "\n", dsi.dsi_gi.nv_pck_lbn, - pci.pci_gi.vobu_s_ptm, pci.pci_gi.vobu_e_ptm, state->ts_offset); + pci.pci_gi.vobu_s_ptm, pci.pci_gi.vobu_e_ptm, state->ptm_offset); - return FFERROR_REDO; + + (*p_is_nav_packet) = 1; + + return 0; } /* we are in the middle of a VOBU, so pass on the PS packet */ @@ -537,7 +543,7 @@ static int dvdvideo_play_open(AVFormatContext *s, DVDVideoPlaybackState *state) goto end_dvdnav_error; } - if (c->opt_pgc > 0 && c->opt_pg > 0) { + if (c->opt_pgc > 0) { if (dvdnav_program_play(state->dvdnav, c->opt_title, c->opt_pgc, c->opt_pg) != DVDNAV_STATUS_OK) { av_log(s, AV_LOG_ERROR, "Unable to start playback at title %d, PGC %d, PG %d\n", c->opt_title, c->opt_pgc, c->opt_pg); @@ -611,9 +617,7 @@ end_dvdnav_error: } static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState *state, - uint8_t *buf, int buf_size, - int *p_nav_event, - void (*flush_cb)(AVFormatContext *s)) + uint8_t *buf, int buf_size, int *p_is_nav_packet) { DVDVideoDemuxContext *c = s->priv_data; @@ -624,10 +628,12 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState dvdnav_vts_change_event_t *e_vts; dvdnav_cell_change_event_t *e_cell; int cur_title, cur_pgcn, cur_pgn, cur_angle, cur_title_unused, cur_ptt, cur_nb_angles; - int is_cell_promising = 0; pci_t *e_pci; dsi_t *e_dsi; + (*p_is_nav_packet) = 0; + state->ptm_discont = 0; + if (buf_size != DVDVIDEO_BLOCK_SIZE) { av_log(s, AV_LOG_ERROR, "Invalid buffer size (expected=%d actual=%d)\n", DVDVIDEO_BLOCK_SIZE, buf_size); @@ -706,42 +712,43 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState continue; e_cell = (dvdnav_cell_change_event_t *) nav_buf; - is_cell_promising = !c->opt_trim || dvdvideo_is_cell_promising(s, state->pgc, e_cell->cellN); - av_log(s, AV_LOG_DEBUG, "new cell: prev=%d new=%d promising=%d\n", - state->celln, e_cell->cellN, is_cell_promising); + av_log(s, AV_LOG_DEBUG, "new cell: prev=%d new=%d\n", state->celln, e_cell->cellN); if (!state->in_ps && !state->in_pgc) { if (cur_title == c->opt_title && (c->opt_pgc || cur_ptt == c->opt_chapter_start) && cur_pgcn == state->pgcn && - cur_pgn == state->entry_pgn && - is_cell_promising) { + cur_pgn == state->entry_pgn) { state->in_pgc = 1; } - - if (c->opt_trim && !is_cell_promising) - av_log(s, AV_LOG_INFO, "Skipping padding cell #%d\n", e_cell->cellN); - } else if (state->celln >= e_cell->cellN || state->pgn > cur_pgn) { + } else if (!state->is_seeking && + (state->celln >= e_cell->cellN || state->pgn > cur_pgn)) { return AVERROR_EOF; } state->celln = e_cell->cellN; state->ptt = cur_ptt; state->pgn = cur_pgn; - state->nb_cells_played++; continue; case DVDNAV_NAV_PACKET: if (!state->in_pgc) continue; - if ((state->ptt > 0 && state->ptt > cur_ptt) || + if ((!state->is_seeking && state->ptt > 0 && state->ptt > cur_ptt) || (c->opt_chapter_end > 0 && cur_ptt > c->opt_chapter_end)) { return AVERROR_EOF; } + if (nav_len != DVDVIDEO_BLOCK_SIZE) { + av_log(s, AV_LOG_ERROR, "Invalid NAV packet size (expected=%d actual=%d)\n", + DVDVIDEO_BLOCK_SIZE, nav_len); + + return AVERROR_INVALIDDATA; + } + e_pci = dvdnav_get_current_nav_pci(state->dvdnav); e_dsi = dvdnav_get_current_nav_dsi(state->dvdnav); @@ -766,23 +773,28 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState e_pci->pci_gi.nv_pck_lbn, state->vobu_duration, state->nav_pts); if (!state->in_ps) { + if (c->opt_trim && !dvdvideo_is_cell_promising(s, state->pgc, state->celln)) { + av_log(s, AV_LOG_INFO, "Skipping padding cell #%d\n", state->celln); + + i = 0; + continue; + } + av_log(s, AV_LOG_DEBUG, "navigation: locked to program stream\n"); state->in_ps = 1; } else { if (state->vobu_e_ptm != e_pci->pci_gi.vobu_s_ptm) { - if (flush_cb) - flush_cb(s); - - state->ts_offset += state->vobu_e_ptm - e_pci->pci_gi.vobu_s_ptm; + state->ptm_discont = 1; + state->ptm_offset += state->vobu_e_ptm - e_pci->pci_gi.vobu_s_ptm; } } state->vobu_e_ptm = e_pci->pci_gi.vobu_e_ptm; - (*p_nav_event) = nav_event; + (*p_is_nav_packet) = 1; - return nav_len; + return 0; case DVDNAV_BLOCK_OK: if (!state->in_ps) { if (state->in_pgc) @@ -804,18 +816,25 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState return AVERROR_INPUT_CHANGED; } - memcpy(buf, &nav_buf, nav_len); - if (state->pgn != cur_pgn) av_log(s, AV_LOG_WARNING, "Unexpected PG change (expected=%d actual=%d); " "this could be due to a missed NAV packet\n", state->pgn, cur_pgn); - (*p_nav_event) = nav_event; + memcpy(buf, &nav_buf, nav_len); + + state->is_seeking = 0; return nav_len; - case DVDNAV_STILL_FRAME: case DVDNAV_WAIT: + if (dvdnav_wait_skip(state->dvdnav) != DVDNAV_STATUS_OK) { + av_log(s, AV_LOG_ERROR, "Unable to skip WAIT event\n"); + + goto end_dvdnav_error; + } + + continue; + case DVDNAV_STILL_FRAME: case DVDNAV_HOP_CHANNEL: case DVDNAV_HIGHLIGHT: if (state->in_ps) @@ -829,14 +848,6 @@ static int dvdvideo_play_next_ps_block(AVFormatContext *s, DVDVideoPlaybackState } } - if (nav_event == DVDNAV_WAIT) { - if (dvdnav_wait_skip(state->dvdnav) != DVDNAV_STATUS_OK) { - av_log(s, AV_LOG_ERROR, "Unable to skip WAIT event\n"); - - goto end_dvdnav_error; - } - } - continue; default: continue; @@ -863,11 +874,10 @@ static int dvdvideo_chapters_setup_simple(AVFormatContext *s) int64_t total_duration = 0; int chapter_start = c->opt_chapter_start; - int chapter_end = c->opt_chapter_end > 0 ? c->opt_chapter_end : c->play_state.pgc_nb_pg_est - 1; + int chapter_end = c->opt_chapter_end > 0 ? c->opt_chapter_end : c->play_state.pgc_nb_pg_est; /* dvdnav_describe_title_chapters() describes PGs rather than PTTs, so validate our range */ - if (chapter_start == chapter_end || - c->play_state.pgc_nb_pg_est == 1 || + if (c->play_state.pgc_nb_pg_est == 1 || chapter_start > c->play_state.pgc_nb_pg_est || chapter_end > c->play_state.pgc_nb_pg_est) { @@ -879,8 +889,14 @@ static int dvdvideo_chapters_setup_simple(AVFormatContext *s) for (int i = chapter_start - 1; i < chapter_end; i++) { uint64_t time_effective = c->play_state.pgc_pg_times_est[i] - c->play_state.nav_pts; - if (!avpriv_new_chapter(s, i, DVDVIDEO_TIME_BASE_Q, time_prev, time_effective, NULL)) + if (time_effective - time_prev == 0) + continue; + + if (chapter_start != chapter_end && + !avpriv_new_chapter(s, i, DVDVIDEO_TIME_BASE_Q, time_prev, time_effective, NULL)) { + return AVERROR(ENOMEM); + } time_prev = time_effective; total_duration = time_effective; @@ -900,19 +916,26 @@ static int dvdvideo_chapters_setup_preindex(AVFormatContext *s) { DVDVideoDemuxContext *c = s->priv_data; - int ret = 0, interrupt = 0; - int nb_chapters = 0, last_ptt = c->opt_chapter_start; + int ret, partn, last_partn; + int interrupt = 0, nb_chapters = 0; uint64_t cur_chapter_offset = 0, cur_chapter_duration = 0; DVDVideoPlaybackState state = {0}; uint8_t nav_buf[DVDVIDEO_BLOCK_SIZE]; - int nav_event; + int is_nav_packet; if (c->opt_chapter_start == c->opt_chapter_end) - return ret; + return 0; - if ((ret = dvdvideo_play_open(s, &state)) < 0) - return ret; + if (c->opt_menu) { + if ((ret = dvdvideo_menu_open(s, &state)) < 0) + return ret; + last_partn = state.celln; + } else { + if ((ret = dvdvideo_play_open(s, &state)) < 0) + return ret; + last_partn = c->opt_chapter_start; + } if (state.pgc->nr_of_programs == 1) goto end_close; @@ -921,31 +944,39 @@ static int dvdvideo_chapters_setup_preindex(AVFormatContext *s) "Indexing chapter markers, this will take a long time. Please wait...\n"); while (!(interrupt = ff_check_interrupt(&s->interrupt_callback))) { - ret = dvdvideo_play_next_ps_block(s, &state, nav_buf, DVDVIDEO_BLOCK_SIZE, - &nav_event, NULL); + if (c->opt_menu) + ret = dvdvideo_menu_next_ps_block(s, &state, nav_buf, DVDVIDEO_BLOCK_SIZE, &is_nav_packet); + else + ret = dvdvideo_play_next_ps_block(s, &state, nav_buf, DVDVIDEO_BLOCK_SIZE, &is_nav_packet); + if (ret < 0 && ret != AVERROR_EOF) goto end_close; - if (nav_event != DVDNAV_NAV_PACKET && ret != AVERROR_EOF) + if (!is_nav_packet && ret != AVERROR_EOF) continue; - if (state.ptt == last_ptt) { + partn = c->opt_menu ? state.celln : state.ptt; + + if (partn == last_partn) { cur_chapter_duration += state.vobu_duration; /* ensure we add the last chapter */ if (ret != AVERROR_EOF) continue; } - if (!avpriv_new_chapter(s, nb_chapters, DVDVIDEO_TIME_BASE_Q, cur_chapter_offset, - cur_chapter_offset + cur_chapter_duration, NULL)) { - ret = AVERROR(ENOMEM); - goto end_close; + if (cur_chapter_duration > 0) { + if (!avpriv_new_chapter(s, nb_chapters, DVDVIDEO_TIME_BASE_Q, cur_chapter_offset, + cur_chapter_offset + cur_chapter_duration, NULL)) { + ret = AVERROR(ENOMEM); + goto end_close; + } + + nb_chapters++; } - nb_chapters++; cur_chapter_offset += cur_chapter_duration; cur_chapter_duration = state.vobu_duration; - last_ptt = state.ptt; + last_partn = partn; if (ret == AVERROR_EOF) break; @@ -965,7 +996,10 @@ static int dvdvideo_chapters_setup_preindex(AVFormatContext *s) ret = 0; end_close: - dvdvideo_play_close(s, &state); + if (c->opt_menu) + dvdvideo_menu_close(s, &state); + else + dvdvideo_play_close(s, &state); return ret; } @@ -1019,9 +1053,7 @@ static int dvdvideo_video_stream_analyze(AVFormatContext *s, video_attr_t video_ return 0; } -static int dvdvideo_video_stream_add(AVFormatContext *s, - DVDVideoVTSVideoStreamEntry *entry, - enum AVStreamParseType need_parsing) +static int dvdvideo_video_stream_add(AVFormatContext *s, DVDVideoVTSVideoStreamEntry *entry) { AVStream *st; FFStream *sti; @@ -1045,7 +1077,7 @@ static int dvdvideo_video_stream_add(AVFormatContext *s, sti = ffstream(st); sti->request_probe = 0; - sti->need_parsing = need_parsing; + sti->need_parsing = AVSTREAM_PARSE_HEADERS; sti->display_aspect_ratio = entry->dar; avpriv_set_pts_info(st, DVDVIDEO_PTS_WRAP_BITS, @@ -1058,7 +1090,7 @@ static int dvdvideo_video_stream_setup(AVFormatContext *s) { DVDVideoDemuxContext *c = s->priv_data; - int ret = 0; + int ret; DVDVideoVTSVideoStreamEntry entry = {0}; video_attr_t video_attr; @@ -1069,7 +1101,7 @@ static int dvdvideo_video_stream_setup(AVFormatContext *s) video_attr = c->vts_ifo->vtsi_mat->vts_video_attr; if ((ret = dvdvideo_video_stream_analyze(s, video_attr, &entry)) < 0 || - (ret = dvdvideo_video_stream_add(s, &entry, AVSTREAM_PARSE_HEADERS)) < 0) { + (ret = dvdvideo_video_stream_add(s, &entry)) < 0) { av_log(s, AV_LOG_ERROR, "Unable to add video stream\n"); return ret; @@ -1181,8 +1213,7 @@ static int dvdvideo_audio_stream_analyze(AVFormatContext *s, audio_attr_t audio_ return 0; } -static int dvdvideo_audio_stream_add(AVFormatContext *s, DVDVideoPGCAudioStreamEntry *entry, - enum AVStreamParseType need_parsing) +static int dvdvideo_audio_stream_add(AVFormatContext *s, DVDVideoPGCAudioStreamEntry *entry) { AVStream *st; FFStream *sti; @@ -1207,7 +1238,7 @@ static int dvdvideo_audio_stream_add(AVFormatContext *s, DVDVideoPGCAudioStreamE sti = ffstream(st); sti->request_probe = 0; - sti->need_parsing = need_parsing; + sti->need_parsing = AVSTREAM_PARSE_HEADERS; avpriv_set_pts_info(st, DVDVIDEO_PTS_WRAP_BITS, DVDVIDEO_TIME_BASE_Q.num, DVDVIDEO_TIME_BASE_Q.den); @@ -1219,7 +1250,7 @@ static int dvdvideo_audio_stream_add_all(AVFormatContext *s) { DVDVideoDemuxContext *c = s->priv_data; - int ret = 0; + int ret; int nb_streams; if (c->opt_menu) @@ -1250,7 +1281,7 @@ static int dvdvideo_audio_stream_add_all(AVFormatContext *s) if (s->streams[j]->id == entry.startcode) continue; - if ((ret = dvdvideo_audio_stream_add(s, &entry, AVSTREAM_PARSE_HEADERS)) < 0) + if ((ret = dvdvideo_audio_stream_add(s, &entry)) < 0) goto break_error; continue; @@ -1268,6 +1299,7 @@ static int dvdvideo_subp_stream_analyze(AVFormatContext *s, uint32_t offset, sub { DVDVideoDemuxContext *c = s->priv_data; + int ret; char lang_dvd[3] = {0}; entry->startcode = 0x20 + (offset & 0x1F); @@ -1279,7 +1311,9 @@ static int dvdvideo_subp_stream_analyze(AVFormatContext *s, uint32_t offset, sub /* dvdsub palettes currently have no colorspace tagging and all muxers only support RGB */ /* this is not a lossless conversion, but no use cases are supported for the original YUV */ - ff_dvdclut_yuv_to_rgb(entry->clut, FF_DVDCLUT_CLUT_SIZE); + ret = ff_dvdclut_yuv_to_rgb(entry->clut, FF_DVDCLUT_CLUT_SIZE); + if (ret < 0) + return ret; AV_WB16(lang_dvd, subp_attr.lang_code); entry->lang_iso = ff_convert_lang_to(lang_dvd, AV_LANG_ISO639_2_BIBL); @@ -1287,8 +1321,7 @@ static int dvdvideo_subp_stream_analyze(AVFormatContext *s, uint32_t offset, sub return 0; } -static int dvdvideo_subp_stream_add(AVFormatContext *s, DVDVideoPGCSubtitleStreamEntry *entry, - enum AVStreamParseType need_parsing) +static int dvdvideo_subp_stream_add(AVFormatContext *s, DVDVideoPGCSubtitleStreamEntry *entry) { AVStream *st; FFStream *sti; @@ -1314,7 +1347,7 @@ static int dvdvideo_subp_stream_add(AVFormatContext *s, DVDVideoPGCSubtitleStrea sti = ffstream(st); sti->request_probe = 0; - sti->need_parsing = need_parsing; + sti->need_parsing = AVSTREAM_PARSE_HEADERS; avpriv_set_pts_info(st, DVDVIDEO_PTS_WRAP_BITS, DVDVIDEO_TIME_BASE_Q.num, DVDVIDEO_TIME_BASE_Q.den); @@ -1326,7 +1359,7 @@ static int dvdvideo_subp_stream_add_internal(AVFormatContext *s, uint32_t offset subp_attr_t subp_attr, enum DVDVideoSubpictureViewport viewport) { - int ret = 0; + int ret; DVDVideoPGCSubtitleStreamEntry entry = {0}; entry.viewport = viewport; @@ -1339,7 +1372,7 @@ static int dvdvideo_subp_stream_add_internal(AVFormatContext *s, uint32_t offset if (s->streams[i]->id == entry.startcode) return 0; - if ((ret = dvdvideo_subp_stream_add(s, &entry, AVSTREAM_PARSE_HEADERS)) < 0) + if ((ret = dvdvideo_subp_stream_add(s, &entry)) < 0) goto end_error; return 0; @@ -1363,7 +1396,7 @@ static int dvdvideo_subp_stream_add_all(AVFormatContext *s) for (int i = 0; i < nb_streams; i++) { - int ret = 0; + int ret; uint32_t subp_control; subp_attr_t subp_attr; video_attr_t video_attr; @@ -1415,46 +1448,40 @@ static int dvdvideo_subp_stream_add_all(AVFormatContext *s) return 0; } -static void dvdvideo_subdemux_flush(AVFormatContext *s) -{ - DVDVideoDemuxContext *c = s->priv_data; - - if (!c->segment_started) - return; - - av_log(s, AV_LOG_DEBUG, "flushing sub-demuxer\n"); - avio_flush(&c->mpeg_pb.pub); - ff_read_frame_flush(c->mpeg_ctx); - c->segment_started = 0; -} - static int dvdvideo_subdemux_read_data(void *opaque, uint8_t *buf, int buf_size) { AVFormatContext *s = opaque; DVDVideoDemuxContext *c = s->priv_data; - int ret = 0; - int nav_event; - - if (c->play_end) - return AVERROR_EOF; + int ret; + int is_nav_packet; if (c->opt_menu) - ret = dvdvideo_menu_next_ps_block(s, &c->play_state, buf, buf_size, - dvdvideo_subdemux_flush); + ret = dvdvideo_menu_next_ps_block(s, &c->play_state, buf, buf_size, &is_nav_packet); else - ret = dvdvideo_play_next_ps_block(opaque, &c->play_state, buf, buf_size, - &nav_event, dvdvideo_subdemux_flush); + ret = dvdvideo_play_next_ps_block(s, &c->play_state, buf, buf_size, &is_nav_packet); - if (ret == AVERROR_EOF) { - c->mpeg_pb.pub.eof_reached = 1; - c->play_end = 1; + if (ret < 0) + goto subdemux_eof; - return AVERROR_EOF; + if (is_nav_packet) { + if (c->play_state.ptm_discont) { + c->subdemux_reset = 1; + + ret = AVERROR_EOF; + goto subdemux_eof; + } + + return FFERROR_REDO; } - if (ret >= 0 && nav_event == DVDNAV_NAV_PACKET) - return FFERROR_REDO; + return ret; + +subdemux_eof: + c->mpeg_pb.pub.eof_reached = 1; + c->mpeg_pb.pub.error = ret; + c->mpeg_pb.pub.read_packet = NULL; + c->mpeg_pb.pub.buf_end = c->mpeg_pb.pub.buf_ptr = c->mpeg_pb.pub.buffer; return ret; } @@ -1471,7 +1498,7 @@ static int dvdvideo_subdemux_open(AVFormatContext *s) { DVDVideoDemuxContext *c = s->priv_data; extern const FFInputFormat ff_mpegps_demuxer; - int ret = 0; + int ret; if (!(c->mpeg_buf = av_mallocz(DVDVIDEO_BLOCK_SIZE))) return AVERROR(ENOMEM); @@ -1496,26 +1523,37 @@ static int dvdvideo_subdemux_open(AVFormatContext *s) c->mpeg_ctx->max_analyze_duration = 0; c->mpeg_ctx->interrupt_callback = s->interrupt_callback; c->mpeg_ctx->pb = &c->mpeg_pb.pub; - c->mpeg_ctx->correct_ts_overflow = 0; c->mpeg_ctx->io_open = NULL; return avformat_open_input(&c->mpeg_ctx, "", &ff_mpegps_demuxer.p, NULL); } +static int dvdvideo_subdemux_reset(AVFormatContext *s) +{ + int ret; + + av_log(s, AV_LOG_VERBOSE, "Resetting sub-demuxer\n"); + + dvdvideo_subdemux_close(s); + if ((ret = dvdvideo_subdemux_open(s)) < 0) + return ret; + + return 0; +} + static int dvdvideo_read_header(AVFormatContext *s) { DVDVideoDemuxContext *c = s->priv_data; - int ret = 0; + int ret; if (c->opt_menu) { if (c->opt_region || c->opt_title > 1 || - c->opt_preindex || c->opt_chapter_start > 1 || c->opt_chapter_end > 0) { av_log(s, AV_LOG_ERROR, "-menu is not compatible with the -region, -title, " - "-preindex, or -chapter_start/-chapter_end options\n"); + "or -chapter_start/-chapter_end options\n"); return AVERROR(EINVAL); } @@ -1525,28 +1563,28 @@ static int dvdvideo_read_header(AVFormatContext *s) return AVERROR(EINVAL); } - if (!c->opt_menu_lu) { - av_log(s, AV_LOG_INFO, "Defaulting to menu language unit #1. " - "This is not always desirable, validation suggested.\n"); - - c->opt_menu_lu = 1; - } - - if (!c->opt_pg) { - av_log(s, AV_LOG_INFO, "Defaulting to menu PG #1. " - "This is not always desirable, validation suggested.\n"); - - c->opt_pg = 1; - } - - if ((ret = dvdvideo_ifo_open(s)) < 0 || - (ret = dvdvideo_menu_open(s, &c->play_state)) < 0 || - (ret = dvdvideo_subdemux_open(s)) < 0 || - (ret = dvdvideo_video_stream_setup(s)) < 0 || - (ret = dvdvideo_audio_stream_add_all(s)) < 0) + if ((ret = dvdvideo_ifo_open(s)) < 0 || + (c->opt_preindex && (ret = dvdvideo_chapters_setup_preindex(s)) < 0) || + (ret = dvdvideo_menu_open(s, &c->play_state)) < 0 || + (ret = dvdvideo_video_stream_setup(s)) < 0 || + (ret = dvdvideo_audio_stream_add_all(s)) < 0 || + (ret = dvdvideo_subdemux_open(s)) < 0) return ret; - return 0; + goto end_ready; + } + + if (c->opt_pgc && (c->opt_chapter_start > 1 || c->opt_chapter_end > 0 || c->opt_preindex)) { + av_log(s, AV_LOG_ERROR, "PGC extraction not compatible with chapter or preindex options\n"); + + return AVERROR(EINVAL); + } + + if (!c->opt_pgc && (c->opt_chapter_end != 0 && c->opt_chapter_start > c->opt_chapter_end)) { + av_log(s, AV_LOG_ERROR, "Chapter (PTT) range [%d, %d] is invalid\n", + c->opt_chapter_start, c->opt_chapter_end); + + return AVERROR(EINVAL); } if (c->opt_title == 0) { @@ -1556,33 +1594,27 @@ static int dvdvideo_read_header(AVFormatContext *s) c->opt_title = 1; } - if (c->opt_pgc) { - if (c->opt_pg == 0) { - av_log(s, AV_LOG_ERROR, "Invalid coordinates. If -pgc is set, -pg must be set too.\n"); - - return AVERROR(EINVAL); - } else if (c->opt_chapter_start > 1 || c->opt_chapter_end > 0 || c->opt_preindex) { - av_log(s, AV_LOG_ERROR, "-pgc is not compatible with the -preindex or " - "-chapter_start/-chapter_end options\n"); - return AVERROR(EINVAL); - } - } - if ((ret = dvdvideo_ifo_open(s)) < 0) return ret; if (!c->opt_pgc && c->opt_preindex && (ret = dvdvideo_chapters_setup_preindex(s)) < 0) return ret; - if ((ret = dvdvideo_play_open(s, &c->play_state)) < 0 || - (ret = dvdvideo_subdemux_open(s)) < 0 || - (ret = dvdvideo_video_stream_setup(s)) < 0 || - (ret = dvdvideo_audio_stream_add_all(s)) < 0 || - (ret = dvdvideo_subp_stream_add_all(s)) < 0) + if ((ret = dvdvideo_play_open(s, &c->play_state)) < 0 || + (!c->opt_pgc && !c->opt_preindex && (ret = dvdvideo_chapters_setup_simple(s)) < 0) || + (ret = dvdvideo_video_stream_setup(s)) < 0 || + (ret = dvdvideo_audio_stream_add_all(s)) < 0 || + (ret = dvdvideo_subp_stream_add_all(s)) < 0 || + (ret = dvdvideo_subdemux_open(s)) < 0) return ret; - if (!c->opt_pgc && !c->opt_preindex) - return dvdvideo_chapters_setup_simple(s); +end_ready: + c->prev_pts = av_malloc(s->nb_streams * sizeof(int64_t)); + if (!c->prev_pts) + return AVERROR(ENOMEM); + + for (int i = 0; i < s->nb_streams; i++) + c->prev_pts[i] = AV_NOPTS_VALUE; return 0; } @@ -1592,72 +1624,90 @@ static int dvdvideo_read_packet(AVFormatContext *s, AVPacket *pkt) DVDVideoDemuxContext *c = s->priv_data; int ret; - enum AVMediaType st_type; - int found_stream = 0; - - if (c->play_end) - return AVERROR_EOF; + int is_key = 0; + int st_mapped = 0; + AVStream *st_subdemux; + uint8_t ac3_bitstream_id; + uint16_t ac3_frame_size; ret = av_read_frame(c->mpeg_ctx, pkt); + if (ret < 0) { + if (c->subdemux_reset && ret == AVERROR_EOF) { + c->subdemux_reset = 0; + c->pts_offset = c->play_state.ptm_offset; + + if ((ret = dvdvideo_subdemux_reset(s)) < 0) + return ret; + + return FFERROR_REDO; + } - if (ret < 0) return ret; + } - if (!c->segment_started) - c->segment_started = 1; - - st_type = c->mpeg_ctx->streams[pkt->stream_index]->codecpar->codec_type; + st_subdemux = c->mpeg_ctx->streams[pkt->stream_index]; + is_key = pkt->flags & AV_PKT_FLAG_KEY; /* map the subdemuxer stream to the parent demuxer's stream (by startcode) */ for (int i = 0; i < s->nb_streams; i++) { - if (s->streams[i]->id == c->mpeg_ctx->streams[pkt->stream_index]->id) { + if (s->streams[i]->id == st_subdemux->id) { pkt->stream_index = s->streams[i]->index; - found_stream = 1; + st_mapped = 1; + break; } } - if (!found_stream) { - av_log(s, AV_LOG_DEBUG, "discarding frame with stream that was not in IFO headers " - "(stream id=%d)\n", c->mpeg_ctx->streams[pkt->stream_index]->id); + if (!st_mapped || pkt->pts == AV_NOPTS_VALUE || pkt->dts == AV_NOPTS_VALUE) + goto discard; - return FFERROR_REDO; + if (!c->play_started) { + /* try to start at the beginning of a GOP */ + if (st_subdemux->codecpar->codec_type != AVMEDIA_TYPE_VIDEO || !is_key) + goto discard; + + c->first_pts = pkt->pts; + c->play_started = 1; } - if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE) { - if (!c->play_started) { - /* try to start at the beginning of a GOP */ - if (st_type != AVMEDIA_TYPE_VIDEO || !(pkt->flags & AV_PKT_FLAG_KEY)) { - av_log(s, AV_LOG_VERBOSE, "Discarding packet which is not a video keyframe or " - "with unset PTS/DTS at start\n"); - return FFERROR_REDO; - } + pkt->pts += c->pts_offset - c->first_pts; + pkt->dts += c->pts_offset - c->first_pts; - c->first_pts = pkt->pts; - c->play_started = 1; - } + if (pkt->pts < 0) + goto discard; - pkt->pts += c->play_state.ts_offset - c->first_pts; - pkt->dts += c->play_state.ts_offset - c->first_pts; + /* clean up after DVD muxers which end seamless PGs on duplicate or partial AC3 samples */ + if (st_subdemux->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && + st_subdemux->codecpar->codec_id == AV_CODEC_ID_AC3) { - if (pkt->pts < 0) { - av_log(s, AV_LOG_VERBOSE, "Discarding packet with negative PTS (st=%d pts=%" PRId64 "), " - "this is OK at start of playback\n", - pkt->stream_index, pkt->pts); + if (pkt->pts <= c->prev_pts[pkt->stream_index]) + goto discard; - return FFERROR_REDO; - } - } else { - av_log(s, AV_LOG_WARNING, "Unset PTS or DTS @ st=%d pts=%" PRId64 " dts=%" PRId64 "\n", - pkt->stream_index, pkt->pts, pkt->dts); + ret = av_ac3_parse_header(pkt->buf->data, pkt->size, + &ac3_bitstream_id, &ac3_frame_size); + + if (ret < 0 || pkt->size != ac3_frame_size) + goto discard; } av_log(s, AV_LOG_TRACE, "st=%d pts=%" PRId64 " dts=%" PRId64 " " - "ts_offset=%" PRId64 " first_pts=%" PRId64 "\n", + "pts_offset=%" PRId64 " first_pts=%" PRId64 "\n", pkt->stream_index, pkt->pts, pkt->dts, - c->play_state.ts_offset, c->first_pts); + c->pts_offset, c->first_pts); - return c->play_end ? AVERROR_EOF : 0; + c->prev_pts[pkt->stream_index] = pkt->pts; + + return 0; + +discard: + av_log(s, st_mapped ? AV_LOG_VERBOSE : AV_LOG_DEBUG, + "Discarding frame @ st=%d pts=%" PRId64 " dts=%" PRId64 " is_key=%d st_mapped=%d\n", + st_mapped ? pkt->stream_index : -1, pkt->pts, pkt->dts, is_key, st_mapped); + + if (st_mapped) + c->prev_pts[pkt->stream_index] = pkt->pts; + + return FFERROR_REDO; } static int dvdvideo_close(AVFormatContext *s) @@ -1673,6 +1723,75 @@ static int dvdvideo_close(AVFormatContext *s) dvdvideo_ifo_close(s); + if (c->prev_pts) + av_freep(&c->prev_pts); + + return 0; +} + +static int dvdvideo_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) +{ + DVDVideoDemuxContext *c = s->priv_data; + int ret; + int64_t new_nav_pts; + pci_t* new_nav_pci; + dsi_t* new_nav_dsi; + + if (c->opt_menu || c->opt_chapter_start > 1) { + av_log(s, AV_LOG_ERROR, "Seeking is not compatible with menus or chapter extraction\n"); + + return AVERROR_PATCHWELCOME; + } + + if ((flags & AVSEEK_FLAG_BYTE)) + return AVERROR(ENOSYS); + + if (timestamp < 0 || timestamp > s->duration) + return AVERROR(EINVAL); + + if (!c->seek_warned) { + av_log(s, AV_LOG_WARNING, "Seeking is inherently unreliable and will result " + "in imprecise timecodes from this point\n"); + c->seek_warned = 1; + } + + /* XXX(PATCHWELCOME): use dvdnav_jump_to_sector_by_time(c->play_state.dvdnav, timestamp, 0) + * when it is available in a released version of libdvdnav; it is more accurate */ + if (dvdnav_time_search(c->play_state.dvdnav, timestamp) != DVDNAV_STATUS_OK) { + av_log(s, AV_LOG_ERROR, "libdvdnav: seeking to %" PRId64 " failed\n", timestamp); + + return AVERROR_EXTERNAL; + } + + new_nav_pts = dvdnav_get_current_time (c->play_state.dvdnav); + new_nav_pci = dvdnav_get_current_nav_pci(c->play_state.dvdnav); + new_nav_dsi = dvdnav_get_current_nav_dsi(c->play_state.dvdnav); + + if (new_nav_pci == NULL || new_nav_dsi == NULL) { + av_log(s, AV_LOG_ERROR, "Invalid NAV packet after seeking\n"); + + return AVERROR_INVALIDDATA; + } + + c->play_state.in_pgc = 1; + c->play_state.in_ps = 0; + c->play_state.is_seeking = 1; + c->play_state.nav_pts = timestamp; + c->play_state.ptm_offset = timestamp; + c->play_state.ptm_discont = 0; + c->play_state.vobu_e_ptm = new_nav_pci->pci_gi.vobu_s_ptm; + + c->first_pts = 0; + c->play_started = 0; + c->pts_offset = timestamp; + c->subdemux_reset = 0; + + if ((ret = dvdvideo_subdemux_reset(s)) < 0) + return ret; + + av_log(s, AV_LOG_DEBUG, "seeking: requested_nav_pts=%" PRId64 " new_nav_pts=%" PRId64 "\n", + timestamp, new_nav_pts); + return 0; } @@ -1682,9 +1801,9 @@ static const AVOption dvdvideo_options[] = { {"chapter_end", "exit chapter (PTT) number (0=end)", OFFSET(opt_chapter_end), AV_OPT_TYPE_INT, { .i64=0 }, 0, 99, AV_OPT_FLAG_DECODING_PARAM }, {"chapter_start", "entry chapter (PTT) number", OFFSET(opt_chapter_start), AV_OPT_TYPE_INT, { .i64=1 }, 1, 99, AV_OPT_FLAG_DECODING_PARAM }, {"menu", "demux menu domain", OFFSET(opt_menu), AV_OPT_TYPE_BOOL, { .i64=0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, - {"menu_lu", "menu language unit (0=auto)", OFFSET(opt_menu_lu), AV_OPT_TYPE_INT, { .i64=0 }, 0, 99, AV_OPT_FLAG_DECODING_PARAM }, - {"menu_vts", "menu VTS (0=VMG main menu)", OFFSET(opt_menu_vts), AV_OPT_TYPE_INT, { .i64=0 }, 0, 99, AV_OPT_FLAG_DECODING_PARAM }, - {"pg", "entry PG number (0=auto)", OFFSET(opt_pg), AV_OPT_TYPE_INT, { .i64=0 }, 0, 255, AV_OPT_FLAG_DECODING_PARAM }, + {"menu_lu", "menu language unit", OFFSET(opt_menu_lu), AV_OPT_TYPE_INT, { .i64=1 }, 1, 99, AV_OPT_FLAG_DECODING_PARAM }, + {"menu_vts", "menu VTS (0=VMG root menu)", OFFSET(opt_menu_vts), AV_OPT_TYPE_INT, { .i64=1 }, 0, 99, AV_OPT_FLAG_DECODING_PARAM }, + {"pg", "entry PG number (when paired with PGC number)", OFFSET(opt_pg), AV_OPT_TYPE_INT, { .i64=1 }, 1, 255, AV_OPT_FLAG_DECODING_PARAM }, {"pgc", "entry PGC number (0=auto)", OFFSET(opt_pgc), AV_OPT_TYPE_INT, { .i64=0 }, 0, 999, AV_OPT_FLAG_DECODING_PARAM }, {"preindex", "enable for accurate chapter markers, slow (2-pass read)", OFFSET(opt_preindex), AV_OPT_TYPE_BOOL, { .i64=0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, {"region", "playback region number (0=free)", OFFSET(opt_region), AV_OPT_TYPE_INT, { .i64=0 }, 0, 8, AV_OPT_FLAG_DECODING_PARAM }, @@ -1704,11 +1823,12 @@ const FFInputFormat ff_dvdvideo_demuxer = { .p.name = "dvdvideo", .p.long_name = NULL_IF_CONFIG_SMALL("DVD-Video"), .p.priv_class = &dvdvideo_class, - .p.flags = AVFMT_NOFILE | AVFMT_SHOW_IDS | AVFMT_TS_DISCONT | - AVFMT_NO_BYTE_SEEK | AVFMT_NOGENSEARCH | AVFMT_NOBINSEARCH, + .p.flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT | AVFMT_SEEK_TO_PTS | + AVFMT_NOFILE | AVFMT_NO_BYTE_SEEK | AVFMT_NOGENSEARCH | AVFMT_NOBINSEARCH, .priv_data_size = sizeof(DVDVideoDemuxContext), .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP, .read_close = dvdvideo_close, .read_header = dvdvideo_read_header, - .read_packet = dvdvideo_read_packet + .read_packet = dvdvideo_read_packet, + .read_seek = dvdvideo_read_seek }; diff --git a/libavformat/dxa.c b/libavformat/dxa.c index 813e665a2..56b19a7fc 100644 --- a/libavformat/dxa.c +++ b/libavformat/dxa.c @@ -120,6 +120,8 @@ static int dxa_read_header(AVFormatContext *s) avio_skip(pb, fsize); } c->bpc = (fsize + (int64_t)c->frames - 1) / c->frames; + if (c->bpc < 0) + return AVERROR_INVALIDDATA; if(ast->codecpar->block_align) { if (c->bpc > INT_MAX - ast->codecpar->block_align + 1) return AVERROR_INVALIDDATA; diff --git a/libavformat/electronicarts.c b/libavformat/electronicarts.c index f7f6fd4ca..04acf3a40 100644 --- a/libavformat/electronicarts.c +++ b/libavformat/electronicarts.c @@ -198,6 +198,10 @@ static int process_audio_header_elements(AVFormatContext *s) av_log(s, AV_LOG_DEBUG, "end of header block reached\n"); in_header = 0; break; + case 0x1B: + ea->video.time_base = (AVRational) {1, read_arbitrary(pb)}; + av_log(s, AV_LOG_DEBUG, "Setting framerate to %u\n", ea->video.time_base.den); + break; default: av_log(s, AV_LOG_DEBUG, "header element 0x%02x set to 0x%08"PRIx32"\n", @@ -325,7 +329,8 @@ static void process_video_header_mdec(AVFormatContext *s, VideoProperties *video avio_skip(pb, 4); video->width = avio_rl16(pb); video->height = avio_rl16(pb); - video->time_base = (AVRational) { 1, 15 }; + if (!video->time_base.num) + video->time_base = (AVRational) { 1, 15 }; video->codec = AV_CODEC_ID_MDEC; } @@ -427,12 +432,14 @@ static int process_ea_header(AVFormatContext *s) case pQGT_TAG: case TGQs_TAG: ea->video.codec = AV_CODEC_ID_TGQ; - ea->video.time_base = (AVRational) { 1, 15 }; + if (!ea->video.time_base.num) + ea->video.time_base = (AVRational) { 1, 15 }; break; case pIQT_TAG: ea->video.codec = AV_CODEC_ID_TQI; - ea->video.time_base = (AVRational) { 1, 15 }; + if (!ea->video.time_base.num) + ea->video.time_base = (AVRational) { 1, 15 }; break; case MADk_TAG: diff --git a/libavformat/evc.c b/libavformat/evc.c index 95f07266b..6a63630b0 100644 --- a/libavformat/evc.c +++ b/libavformat/evc.c @@ -19,14 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/get_bits.h" #include "libavcodec/golomb.h" #include "libavcodec/evc.h" -#include "avformat.h" #include "avio.h" #include "evc.h" -#include "avio_internal.h" // @see ISO/IEC 14496-15:2021 Coding of audio-visual objects - Part 15: section 12.3.3.1 enum { @@ -62,7 +60,6 @@ typedef struct EVCDecoderConfigurationRecord { uint8_t bit_depth_chroma_minus8; // 3 bits uint16_t pic_width_in_luma_samples; // 16 bits uint16_t pic_height_in_luma_samples; // 16 bits - uint8_t reserved; // 6 bits '000000'b uint8_t lengthSizeMinusOne; // 2 bits uint8_t num_of_arrays; // 8 bits EVCNALUnitArray arrays[NB_ARRAYS]; @@ -210,15 +207,15 @@ static int evcc_write(AVIOContext *pb, EVCDecoderConfigurationRecord *evcc) if(array->numNalus == 0) continue; - av_log(NULL, AV_LOG_TRACE, "array_completeness[%"PRIu8"]: %"PRIu8"\n", + av_log(NULL, AV_LOG_TRACE, "array_completeness[%u]: %"PRIu8"\n", i, array->array_completeness); - av_log(NULL, AV_LOG_TRACE, "NAL_unit_type[%"PRIu8"]: %"PRIu8"\n", + av_log(NULL, AV_LOG_TRACE, "NAL_unit_type[%u]: %"PRIu8"\n", i, array->NAL_unit_type); - av_log(NULL, AV_LOG_TRACE, "numNalus[%"PRIu8"]: %"PRIu16"\n", + av_log(NULL, AV_LOG_TRACE, "numNalus[%u]: %"PRIu16"\n", i, array->numNalus); for ( unsigned j = 0; j < array->numNalus; j++) av_log(NULL, AV_LOG_TRACE, - "nalUnitLength[%"PRIu8"][%"PRIu16"]: %"PRIu16"\n", + "nalUnitLength[%u][%u]: %"PRIu16"\n", i, j, array->nalUnitLength[j]); } @@ -235,7 +232,7 @@ static int evcc_write(AVIOContext *pb, EVCDecoderConfigurationRecord *evcc) /* unsigned int(8) profile_idc */ avio_w8(pb, evcc->profile_idc); - /* unsigned int(8) profile_idc */ + /* unsigned int(8) level_idc */ avio_w8(pb, evcc->level_idc); /* unsigned int(32) toolset_idc_h */ @@ -256,14 +253,14 @@ static int evcc_write(AVIOContext *pb, EVCDecoderConfigurationRecord *evcc) /* unsigned int(16) pic_width_in_luma_samples; */ avio_wb16(pb, evcc->pic_width_in_luma_samples); - /* unsigned int(16) pic_width_in_luma_samples; */ + /* unsigned int(16) pic_height_in_luma_samples; */ avio_wb16(pb, evcc->pic_height_in_luma_samples); /* - * bit(6) reserved = '111111'b; - * unsigned int(2) chromaFormat; + * unsigned int(6) reserved = '000000'b; + * unsigned int(2) lengthSizeMinusOne; */ - avio_w8(pb, evcc->lengthSizeMinusOne | 0xfc); + avio_w8(pb, evcc->lengthSizeMinusOne & 0x3); /* unsigned int(8) numOfArrays; */ avio_w8(pb, evcc->num_of_arrays); diff --git a/libavformat/ffmetadec.c b/libavformat/ffmetadec.c index ab62b7006..bfda7d0bd 100644 --- a/libavformat/ffmetadec.c +++ b/libavformat/ffmetadec.c @@ -21,6 +21,7 @@ #include "libavutil/bprint.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "ffmeta.h" diff --git a/libavformat/file.c b/libavformat/file.c index 1f853e0e1..6a66040b6 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -24,6 +24,7 @@ #include "libavutil/avstring.h" #include "libavutil/file_open.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avio.h" #if HAVE_DIRENT_H @@ -98,7 +99,6 @@ typedef struct FileContext { #if HAVE_DIRENT_H DIR *dir; #endif - int64_t initial_pos; } FileContext; static const AVOption file_options[] = { @@ -193,6 +193,7 @@ static int file_check(URLContext *h, int mask) return ret; } +#if CONFIG_FD_PROTOCOL || CONFIG_PIPE_PROTOCOL static int fd_dup(URLContext *h, int oldfd) { int newfd; @@ -215,16 +216,12 @@ static int fd_dup(URLContext *h, int oldfd) #endif return newfd; } +#endif static int file_close(URLContext *h) { FileContext *c = h->priv_data; - int ret; - - if (c->initial_pos >= 0 && !h->is_streamed) - lseek(c->fd, c->initial_pos, SEEK_SET); - - ret = close(c->fd); + int ret = close(c->fd); return (ret == -1) ? AVERROR(errno) : 0; } @@ -292,7 +289,6 @@ static int file_open(URLContext *h, const char *filename, int flags) av_strstart(filename, "file:", &filename); - c->initial_pos = -1; if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) { access = O_CREAT | O_RDWR; if (c->trunc) @@ -441,13 +437,16 @@ static int pipe_open(URLContext *h, const char *filename, int flags) if (c->fd < 0) { av_strstart(filename, "pipe:", &filename); - fd = strtol(filename, &final, 10); - if((filename == final) || *final ) {/* No digits found, or something like 10ab */ + if (!*filename) { if (flags & AVIO_FLAG_WRITE) { fd = 1; } else { fd = 0; } + } else { + fd = strtol(filename, &final, 10); + if (*final) /* No digits found, or something like 10ab */ + return AVERROR(EINVAL); } c->fd = fd; } @@ -501,11 +500,6 @@ static int fd_open(URLContext *h, const char *filename, int flags) if (c->fd == -1) return AVERROR(errno); - if (h->is_streamed) - c->initial_pos = -1; - else - c->initial_pos = lseek(c->fd, 0, SEEK_CUR); - return 0; } diff --git a/libavformat/fitsenc.c b/libavformat/fitsenc.c index a8efe93d3..69da4319d 100644 --- a/libavformat/fitsenc.c +++ b/libavformat/fitsenc.c @@ -24,8 +24,8 @@ * FITS muxer. */ +#include "avformat.h" #include "avio_internal.h" -#include "internal.h" #include "mux.h" typedef struct FITSContext { diff --git a/libavformat/flac_picture.c b/libavformat/flac_picture.c index b33fee75b..c9f3f11ed 100644 --- a/libavformat/flac_picture.c +++ b/libavformat/flac_picture.c @@ -89,10 +89,8 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t **bufp, int buf_size, mime++; } if (id == AV_CODEC_ID_NONE) { - av_log(s, AV_LOG_ERROR, "Unknown attached picture mimetype: %s.\n", + av_log(s, AV_LOG_WARNING, "Unknown attached picture mimetype: %s.\n", mimetype); - if (s->error_recognition & AV_EF_EXPLODE) - return AVERROR_INVALIDDATA; return 0; } diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c index 5fe835cd0..3c317acae 100644 --- a/libavformat/flacdec.c +++ b/libavformat/flacdec.c @@ -20,6 +20,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavcodec/avcodec.h" #include "libavcodec/bytestream.h" #include "libavcodec/flac.h" diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index 892371fcd..1fb3e0cd3 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -29,12 +29,12 @@ #include "libavutil/channel_layout.h" #include "libavutil/dict.h" #include "libavutil/dict_internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/internal.h" #include "libavutil/intfloat.h" #include "libavutil/intreadwrite.h" #include "libavutil/mastering_display_metadata.h" -#include "libavutil/mathematics.h" #include "avformat.h" #include "demux.h" #include "internal.h" @@ -1111,6 +1111,7 @@ static int flv_parse_video_color_info(AVFormatContext *s, AVStream *st, int64_t return TYPE_UNKNOWN; } + av_free(flv->metaVideoColor); if (!(flv->metaVideoColor = av_mallocz(sizeof(FLVMetaVideoColor)))) { return AVERROR(ENOMEM); } diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c index a7d4fa46a..f34df61c0 100644 --- a/libavformat/flvenc.c +++ b/libavformat/flvenc.c @@ -25,6 +25,7 @@ #include "libavutil/avassert.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavcodec/codec_desc.h" #include "libavcodec/mpeg4audio.h" #include "avio.h" @@ -35,6 +36,7 @@ #include "avformat.h" #include "flv.h" #include "internal.h" +#include "nal.h" #include "mux.h" #include "libavutil/opt.h" #include "libavcodec/put_bits.h" @@ -1075,7 +1077,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) { /* check if extradata looks like mp4 formatted */ if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1) - if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0) + if ((ret = ff_nal_parse_units_buf(pkt->data, &data, &size)) < 0) return ret; } else if (par->codec_id == AV_CODEC_ID_HEVC) { if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1) diff --git a/libavformat/format.c b/libavformat/format.c index 0cdfd85c2..e65a6fc05 100644 --- a/libavformat/format.c +++ b/libavformat/format.c @@ -22,9 +22,8 @@ #include "config_components.h" #include "libavutil/avstring.h" -#include "libavutil/bprint.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/thread.h" #include "avio_internal.h" #include "avformat.h" diff --git a/libavformat/ftp.c b/libavformat/ftp.c index f9b069a59..fba32715e 100644 --- a/libavformat/ftp.c +++ b/libavformat/ftp.c @@ -23,6 +23,7 @@ #include "libavutil/avstring.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "avformat.h" #include "internal.h" diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c index 294007682..d5f06adc6 100644 --- a/libavformat/gifdec.c +++ b/libavformat/gifdec.c @@ -85,7 +85,10 @@ static int gif_probe(const AVProbeData *p) static int resync(AVIOContext *pb) { - ffio_ensure_seekback(pb, 13); + int ret = ffio_ensure_seekback(pb, 13); + if (ret < 0) + return ret; + for (int i = 0; i < 6; i++) { int b = avio_r8(pb); if (b != gif87a_sig[i] && b != gif89a_sig[i]) diff --git a/libavformat/gxfenc.c b/libavformat/gxfenc.c index 0aea7bd7c..43ffa9d45 100644 --- a/libavformat/gxfenc.c +++ b/libavformat/gxfenc.c @@ -22,6 +22,7 @@ #include "libavutil/avassert.h" #include "libavutil/intfloat.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "internal.h" diff --git a/libavformat/hashenc.c b/libavformat/hashenc.c index 17ee2f7e9..e4e324424 100644 --- a/libavformat/hashenc.c +++ b/libavformat/hashenc.c @@ -24,6 +24,7 @@ #include "libavutil/avstring.h" #include "libavutil/hash.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avformat.h" #include "internal.h" diff --git a/libavformat/hdsenc.c b/libavformat/hdsenc.c index 17fa0c807..01efa1f8d 100644 --- a/libavformat/hdsenc.c +++ b/libavformat/hdsenc.c @@ -33,6 +33,7 @@ #include "libavutil/base64.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" typedef struct Fragment { diff --git a/libavformat/hevc.c b/libavformat/hevc.c index ca5187a92..7cf0b0ffb 100644 --- a/libavformat/hevc.c +++ b/libavformat/hevc.c @@ -20,12 +20,14 @@ #include "libavcodec/get_bits.h" #include "libavcodec/golomb.h" -#include "libavcodec/hevc.h" +#include "libavcodec/hevc/hevc.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avc.h" #include "avio.h" #include "avio_internal.h" #include "hevc.h" +#include "nal.h" #define MAX_SPATIAL_SEGMENTATION 4096 // max. value of u(12) field @@ -38,12 +40,26 @@ enum { NB_ARRAYS }; + +#define FLAG_ARRAY_COMPLETENESS (1 << 0) +#define FLAG_IS_NALFF (1 << 1) +#define FLAG_IS_LHVC (1 << 2) + +typedef struct HVCCNALUnit { + uint8_t nuh_layer_id; + uint8_t parameter_set_id; + uint16_t nalUnitLength; + const uint8_t *nalUnit; + + // VPS + uint8_t vps_max_sub_layers_minus1; +} HVCCNALUnit; + typedef struct HVCCNALUnitArray { uint8_t array_completeness; uint8_t NAL_unit_type; uint16_t numNalus; - uint16_t *nalUnitLength; - uint8_t **nalUnit; + HVCCNALUnit *nal; } HVCCNALUnitArray; typedef struct HEVCDecoderConfigurationRecord { @@ -368,19 +384,17 @@ static void skip_sub_layer_ordering_info(GetBitContext *gb) get_ue_golomb_long(gb); // max_latency_increase_plus1 } -static int hvcc_parse_vps(GetBitContext *gb, +static int hvcc_parse_vps(GetBitContext *gb, HVCCNALUnit *nal, HEVCDecoderConfigurationRecord *hvcc) { - unsigned int vps_max_sub_layers_minus1; - + nal->parameter_set_id = get_bits(gb, 4); /* - * vps_video_parameter_set_id u(4) * vps_reserved_three_2bits u(2) * vps_max_layers_minus1 u(6) */ - skip_bits(gb, 12); + skip_bits(gb, 8); - vps_max_sub_layers_minus1 = get_bits(gb, 3); + nal->vps_max_sub_layers_minus1 = get_bits(gb, 3); /* * numTemporalLayers greater than 1 indicates that the stream to which this @@ -391,7 +405,7 @@ static int hvcc_parse_vps(GetBitContext *gb, * that it is unknown whether the stream is temporally scalable. */ hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers, - vps_max_sub_layers_minus1 + 1); + nal->vps_max_sub_layers_minus1 + 1); /* * vps_temporal_id_nesting_flag u(1) @@ -399,7 +413,7 @@ static int hvcc_parse_vps(GetBitContext *gb, */ skip_bits(gb, 17); - hvcc_parse_ptl(gb, hvcc, vps_max_sub_layers_minus1); + hvcc_parse_ptl(gb, hvcc, nal->vps_max_sub_layers_minus1); /* nothing useful for hvcC past this point */ return 0; @@ -491,15 +505,38 @@ static int parse_rps(GetBitContext *gb, unsigned int rps_idx, return 0; } -static int hvcc_parse_sps(GetBitContext *gb, +static int hvcc_parse_sps(GetBitContext *gb, HVCCNALUnit *nal, HEVCDecoderConfigurationRecord *hvcc) { unsigned int i, sps_max_sub_layers_minus1, log2_max_pic_order_cnt_lsb_minus4; unsigned int num_short_term_ref_pic_sets, num_delta_pocs[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; + unsigned int sps_ext_or_max_sub_layers_minus1, multi_layer_ext_sps_flag; - skip_bits(gb, 4); // sps_video_parameter_set_id + unsigned int sps_video_parameter_set_id = get_bits(gb, 4); - sps_max_sub_layers_minus1 = get_bits (gb, 3); + if (nal->nuh_layer_id == 0) { + sps_ext_or_max_sub_layers_minus1 = 0; + sps_max_sub_layers_minus1 = get_bits(gb, 3); + } else { + sps_ext_or_max_sub_layers_minus1 = get_bits(gb, 3); + if (sps_ext_or_max_sub_layers_minus1 == 7) { + const HVCCNALUnitArray *array = &hvcc->arrays[VPS_INDEX]; + const HVCCNALUnit *vps = NULL; + + for (i = 0; i < array->numNalus; i++) + if (sps_video_parameter_set_id == array->nal[i].parameter_set_id) { + vps = &array->nal[i]; + break; + } + if (!vps) + return AVERROR_INVALIDDATA; + + sps_max_sub_layers_minus1 = vps->vps_max_sub_layers_minus1; + } else + sps_max_sub_layers_minus1 = sps_ext_or_max_sub_layers_minus1; + } + multi_layer_ext_sps_flag = nal->nuh_layer_id && + sps_ext_or_max_sub_layers_minus1 == 7; /* * numTemporalLayers greater than 1 indicates that the stream to which this @@ -512,35 +549,43 @@ static int hvcc_parse_sps(GetBitContext *gb, hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers, sps_max_sub_layers_minus1 + 1); - hvcc->temporalIdNested = get_bits1(gb); - - hvcc_parse_ptl(gb, hvcc, sps_max_sub_layers_minus1); - - get_ue_golomb_long(gb); // sps_seq_parameter_set_id - - hvcc->chromaFormat = get_ue_golomb_long(gb); - - if (hvcc->chromaFormat == 3) - skip_bits1(gb); // separate_colour_plane_flag - - get_ue_golomb_long(gb); // pic_width_in_luma_samples - get_ue_golomb_long(gb); // pic_height_in_luma_samples - - if (get_bits1(gb)) { // conformance_window_flag - get_ue_golomb_long(gb); // conf_win_left_offset - get_ue_golomb_long(gb); // conf_win_right_offset - get_ue_golomb_long(gb); // conf_win_top_offset - get_ue_golomb_long(gb); // conf_win_bottom_offset + if (!multi_layer_ext_sps_flag) { + hvcc->temporalIdNested = get_bits1(gb); + hvcc_parse_ptl(gb, hvcc, sps_max_sub_layers_minus1); } - hvcc->bitDepthLumaMinus8 = get_ue_golomb_long(gb); - hvcc->bitDepthChromaMinus8 = get_ue_golomb_long(gb); + nal->parameter_set_id = get_ue_golomb_long(gb); + + if (multi_layer_ext_sps_flag) { + if (get_bits1(gb)) // update_rep_format_flag + skip_bits(gb, 8); // sps_rep_format_idx + } else { + hvcc->chromaFormat = get_ue_golomb_long(gb); + + if (hvcc->chromaFormat == 3) + skip_bits1(gb); // separate_colour_plane_flag + + get_ue_golomb_long(gb); // pic_width_in_luma_samples + get_ue_golomb_long(gb); // pic_height_in_luma_samples + + if (get_bits1(gb)) { // conformance_window_flag + get_ue_golomb_long(gb); // conf_win_left_offset + get_ue_golomb_long(gb); // conf_win_right_offset + get_ue_golomb_long(gb); // conf_win_top_offset + get_ue_golomb_long(gb); // conf_win_bottom_offset + } + + hvcc->bitDepthLumaMinus8 = get_ue_golomb_long(gb); + hvcc->bitDepthChromaMinus8 = get_ue_golomb_long(gb); + } log2_max_pic_order_cnt_lsb_minus4 = get_ue_golomb_long(gb); - /* sps_sub_layer_ordering_info_present_flag */ - i = get_bits1(gb) ? 0 : sps_max_sub_layers_minus1; - for (; i <= sps_max_sub_layers_minus1; i++) - skip_sub_layer_ordering_info(gb); + if (!multi_layer_ext_sps_flag) { + /* sps_sub_layer_ordering_info_present_flag */ + i = get_bits1(gb) ? 0 : sps_max_sub_layers_minus1; + for (; i <= sps_max_sub_layers_minus1; i++) + skip_sub_layer_ordering_info(gb); + } get_ue_golomb_long(gb); // log2_min_luma_coding_block_size_minus3 get_ue_golomb_long(gb); // log2_diff_max_min_luma_coding_block_size @@ -549,9 +594,15 @@ static int hvcc_parse_sps(GetBitContext *gb, get_ue_golomb_long(gb); // max_transform_hierarchy_depth_inter get_ue_golomb_long(gb); // max_transform_hierarchy_depth_intra - if (get_bits1(gb) && // scaling_list_enabled_flag - get_bits1(gb)) // sps_scaling_list_data_present_flag - skip_scaling_list_data(gb); + if (get_bits1(gb)) { // scaling_list_enabled_flag + int sps_infer_scaling_list_flag = 0; + if (multi_layer_ext_sps_flag) + sps_infer_scaling_list_flag = get_bits1(gb); + if (sps_infer_scaling_list_flag) + skip_bits(gb, 6); // sps_scaling_list_ref_layer_id + else if (get_bits1(gb)) // sps_scaling_list_data_present_flag + skip_scaling_list_data(gb); + } skip_bits1(gb); // amp_enabled_flag skip_bits1(gb); // sample_adaptive_offset_enabled_flag @@ -595,12 +646,12 @@ static int hvcc_parse_sps(GetBitContext *gb, return 0; } -static int hvcc_parse_pps(GetBitContext *gb, +static int hvcc_parse_pps(GetBitContext *gb, HVCCNALUnit *nal, HEVCDecoderConfigurationRecord *hvcc) { uint8_t tiles_enabled_flag, entropy_coding_sync_enabled_flag; - get_ue_golomb_long(gb); // pps_pic_parameter_set_id + nal->parameter_set_id = get_ue_golomb_long(gb); // pps_pic_parameter_set_id get_ue_golomb_long(gb); // pps_seq_parameter_set_id /* @@ -652,59 +703,51 @@ static int hvcc_parse_pps(GetBitContext *gb, return 0; } -static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type) +static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type, + uint8_t *nuh_layer_id) { skip_bits1(gb); // forbidden_zero_bit *nal_type = get_bits(gb, 6); + *nuh_layer_id = get_bits(gb, 6); /* - * nuh_layer_id u(6) * nuh_temporal_id_plus1 u(3) */ - skip_bits(gb, 9); + skip_bits(gb, 3); } -static int hvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, - uint8_t nal_type, int ps_array_completeness, +static int hvcc_array_add_nal_unit(const uint8_t *nal_buf, uint32_t nal_size, HVCCNALUnitArray *array) { + HVCCNALUnit *nal; int ret; uint16_t numNalus = array->numNalus; - ret = av_reallocp_array(&array->nalUnit, numNalus + 1, sizeof(uint8_t*)); + ret = av_reallocp_array(&array->nal, numNalus + 1, sizeof(*array->nal)); if (ret < 0) return ret; - ret = av_reallocp_array(&array->nalUnitLength, numNalus + 1, sizeof(uint16_t)); - if (ret < 0) - return ret; - - array->nalUnit [numNalus] = nal_buf; - array->nalUnitLength[numNalus] = nal_size; - array->NAL_unit_type = nal_type; + nal = &array->nal[numNalus]; + nal->nalUnit = nal_buf; + nal->nalUnitLength = nal_size; array->numNalus++; - /* - * When the sample entry name is ‘hvc1’, the default and mandatory value of - * array_completeness is 1 for arrays of all types of parameter sets, and 0 - * for all other arrays. When the sample entry name is ‘hev1’, the default - * value of array_completeness is 0 for all arrays. - */ - if (nal_type == HEVC_NAL_VPS || nal_type == HEVC_NAL_SPS || nal_type == HEVC_NAL_PPS) - array->array_completeness = ps_array_completeness; - return 0; } -static int hvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, - int ps_array_completeness, +static int hvcc_add_nal_unit(const uint8_t *nal_buf, uint32_t nal_size, HEVCDecoderConfigurationRecord *hvcc, - unsigned array_idx) + int flags, unsigned array_idx) { int ret = 0; + int is_nalff = !!(flags & FLAG_IS_NALFF); + int is_lhvc = !!(flags & FLAG_IS_LHVC); + int ps_array_completeness = !!(flags & FLAG_ARRAY_COMPLETENESS); + HVCCNALUnitArray *const array = &hvcc->arrays[array_idx]; + HVCCNALUnit *nal; GetBitContext gbc; - uint8_t nal_type; + uint8_t nal_type, nuh_layer_id; uint8_t *rbsp_buf; uint32_t rbsp_size; @@ -718,26 +761,46 @@ static int hvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, if (ret < 0) goto end; - nal_unit_parse_header(&gbc, &nal_type); + nal_unit_parse_header(&gbc, &nal_type, &nuh_layer_id); + if (!is_lhvc && nuh_layer_id > 0) + goto end; /* * Note: only 'declarative' SEI messages are allowed in * hvcC. Perhaps the SEI playload type should be checked * and non-declarative SEI messages discarded? */ - ret = hvcc_array_add_nal_unit(nal_buf, nal_size, nal_type, - ps_array_completeness, - &hvcc->arrays[array_idx]); + ret = hvcc_array_add_nal_unit(nal_buf, nal_size, array); if (ret < 0) goto end; - if (hvcc->arrays[array_idx].numNalus == 1) + if (array->numNalus == 1) { hvcc->numOfArrays++; + array->NAL_unit_type = nal_type; + + /* + * When the sample entry name is ‘hvc1’, the default and mandatory value of + * array_completeness is 1 for arrays of all types of parameter sets, and 0 + * for all other arrays. When the sample entry name is ‘hev1’, the default + * value of array_completeness is 0 for all arrays. + */ + if (nal_type == HEVC_NAL_VPS || nal_type == HEVC_NAL_SPS || + nal_type == HEVC_NAL_PPS) + array->array_completeness = ps_array_completeness; + } + + nal = &array->nal[array->numNalus-1]; + nal->nuh_layer_id = nuh_layer_id; + + /* Don't parse parameter sets. We already have the needed information*/ + if (is_nalff) + goto end; + if (nal_type == HEVC_NAL_VPS) - ret = hvcc_parse_vps(&gbc, hvcc); + ret = hvcc_parse_vps(&gbc, nal, hvcc); else if (nal_type == HEVC_NAL_SPS) - ret = hvcc_parse_sps(&gbc, hvcc); + ret = hvcc_parse_sps(&gbc, nal, hvcc); else if (nal_type == HEVC_NAL_PPS) - ret = hvcc_parse_pps(&gbc, hvcc); + ret = hvcc_parse_pps(&gbc, nal, hvcc); if (ret < 0) goto end; @@ -771,14 +834,16 @@ static void hvcc_close(HEVCDecoderConfigurationRecord *hvcc) for (unsigned i = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) { HVCCNALUnitArray *const array = &hvcc->arrays[i]; array->numNalus = 0; - av_freep(&array->nalUnit); - av_freep(&array->nalUnitLength); + av_freep(&array->nal); } } -static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) +static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc, + int flags) { - uint16_t vps_count, sps_count, pps_count; + uint16_t numNalus[NB_ARRAYS] = { 0 }; + int is_lhvc = !!(flags & FLAG_IS_LHVC); + int numOfArrays = 0; /* * We only support writing HEVCDecoderConfigurationRecord version 1. @@ -804,36 +869,61 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) * let's always set them to values meaning 'unspecified'. */ hvcc->avgFrameRate = 0; - hvcc->constantFrameRate = 0; + /* + * lhvC doesn't store this field. It instead reserves the bits, setting them + * to '11'b. + */ + hvcc->constantFrameRate = is_lhvc * 0x3; + /* + * Skip all NALUs with nuh_layer_id == 0 if writing lhvC. We do it here and + * not before parsing them as some parameter sets with nuh_layer_id > 0 + * may reference base layer parameters sets. + */ + for (unsigned i = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) { + const HVCCNALUnitArray *const array = &hvcc->arrays[i]; + + if (array->numNalus == 0) + continue; + + for (unsigned j = 0; j < array->numNalus; j++) + numNalus[i] += !is_lhvc || (array->nal[j].nuh_layer_id != 0); + numOfArrays += (numNalus[i] > 0); + } + + av_log(NULL, AV_LOG_TRACE, "%s\n", is_lhvc ? "lhvC" : "hvcC"); av_log(NULL, AV_LOG_TRACE, "configurationVersion: %"PRIu8"\n", hvcc->configurationVersion); - av_log(NULL, AV_LOG_TRACE, "general_profile_space: %"PRIu8"\n", - hvcc->general_profile_space); - av_log(NULL, AV_LOG_TRACE, "general_tier_flag: %"PRIu8"\n", - hvcc->general_tier_flag); - av_log(NULL, AV_LOG_TRACE, "general_profile_idc: %"PRIu8"\n", - hvcc->general_profile_idc); - av_log(NULL, AV_LOG_TRACE, "general_profile_compatibility_flags: 0x%08"PRIx32"\n", - hvcc->general_profile_compatibility_flags); - av_log(NULL, AV_LOG_TRACE, "general_constraint_indicator_flags: 0x%012"PRIx64"\n", - hvcc->general_constraint_indicator_flags); - av_log(NULL, AV_LOG_TRACE, "general_level_idc: %"PRIu8"\n", - hvcc->general_level_idc); + if (!is_lhvc) { + av_log(NULL, AV_LOG_TRACE, "general_profile_space: %"PRIu8"\n", + hvcc->general_profile_space); + av_log(NULL, AV_LOG_TRACE, "general_tier_flag: %"PRIu8"\n", + hvcc->general_tier_flag); + av_log(NULL, AV_LOG_TRACE, "general_profile_idc: %"PRIu8"\n", + hvcc->general_profile_idc); + av_log(NULL, AV_LOG_TRACE, "general_profile_compatibility_flags: 0x%08"PRIx32"\n", + hvcc->general_profile_compatibility_flags); + av_log(NULL, AV_LOG_TRACE, "general_constraint_indicator_flags: 0x%012"PRIx64"\n", + hvcc->general_constraint_indicator_flags); + av_log(NULL, AV_LOG_TRACE, "general_level_idc: %"PRIu8"\n", + hvcc->general_level_idc); + } av_log(NULL, AV_LOG_TRACE, "min_spatial_segmentation_idc: %"PRIu16"\n", hvcc->min_spatial_segmentation_idc); av_log(NULL, AV_LOG_TRACE, "parallelismType: %"PRIu8"\n", hvcc->parallelismType); - av_log(NULL, AV_LOG_TRACE, "chromaFormat: %"PRIu8"\n", - hvcc->chromaFormat); - av_log(NULL, AV_LOG_TRACE, "bitDepthLumaMinus8: %"PRIu8"\n", - hvcc->bitDepthLumaMinus8); - av_log(NULL, AV_LOG_TRACE, "bitDepthChromaMinus8: %"PRIu8"\n", - hvcc->bitDepthChromaMinus8); - av_log(NULL, AV_LOG_TRACE, "avgFrameRate: %"PRIu16"\n", - hvcc->avgFrameRate); - av_log(NULL, AV_LOG_TRACE, "constantFrameRate: %"PRIu8"\n", - hvcc->constantFrameRate); + if (!is_lhvc) { + av_log(NULL, AV_LOG_TRACE, "chromaFormat: %"PRIu8"\n", + hvcc->chromaFormat); + av_log(NULL, AV_LOG_TRACE, "bitDepthLumaMinus8: %"PRIu8"\n", + hvcc->bitDepthLumaMinus8); + av_log(NULL, AV_LOG_TRACE, "bitDepthChromaMinus8: %"PRIu8"\n", + hvcc->bitDepthChromaMinus8); + av_log(NULL, AV_LOG_TRACE, "avgFrameRate: %"PRIu16"\n", + hvcc->avgFrameRate); + av_log(NULL, AV_LOG_TRACE, "constantFrameRate: %"PRIu8"\n", + hvcc->constantFrameRate); + } av_log(NULL, AV_LOG_TRACE, "numTemporalLayers: %"PRIu8"\n", hvcc->numTemporalLayers); av_log(NULL, AV_LOG_TRACE, "temporalIdNested: %"PRIu8"\n", @@ -841,11 +931,11 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) av_log(NULL, AV_LOG_TRACE, "lengthSizeMinusOne: %"PRIu8"\n", hvcc->lengthSizeMinusOne); av_log(NULL, AV_LOG_TRACE, "numOfArrays: %"PRIu8"\n", - hvcc->numOfArrays); + numOfArrays); for (unsigned i = 0, j = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) { const HVCCNALUnitArray *const array = &hvcc->arrays[i]; - if (array->numNalus == 0) + if (numNalus[i] == 0) continue; av_log(NULL, AV_LOG_TRACE, "array_completeness[%u]: %"PRIu8"\n", @@ -853,46 +943,52 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) av_log(NULL, AV_LOG_TRACE, "NAL_unit_type[%u]: %"PRIu8"\n", j, array->NAL_unit_type); av_log(NULL, AV_LOG_TRACE, "numNalus[%u]: %"PRIu16"\n", - j, array->numNalus); - for (unsigned k = 0; k < array->numNalus; k++) + j, numNalus[i]); + for (unsigned k = 0; k < array->numNalus; k++) { + if (is_lhvc && array->nal[k].nuh_layer_id == 0) + continue; + av_log(NULL, AV_LOG_TRACE, "nalUnitLength[%u][%u]: %"PRIu16"\n", - j, k, array->nalUnitLength[k]); + j, k, array->nal[k].nalUnitLength); + } j++; } /* * We need at least one of each: VPS, SPS and PPS. */ - vps_count = hvcc->arrays[VPS_INDEX].numNalus; - sps_count = hvcc->arrays[SPS_INDEX].numNalus; - pps_count = hvcc->arrays[PPS_INDEX].numNalus; - if (!vps_count || vps_count > HEVC_MAX_VPS_COUNT || - !sps_count || sps_count > HEVC_MAX_SPS_COUNT || - !pps_count || pps_count > HEVC_MAX_PPS_COUNT) + if ((flags & FLAG_ARRAY_COMPLETENESS) && + (!numNalus[VPS_INDEX] || numNalus[VPS_INDEX] > HEVC_MAX_VPS_COUNT) && !is_lhvc) + return AVERROR_INVALIDDATA; + if ((flags & FLAG_ARRAY_COMPLETENESS) && + (!numNalus[SPS_INDEX] || numNalus[SPS_INDEX] > HEVC_MAX_SPS_COUNT || + !numNalus[PPS_INDEX] || numNalus[PPS_INDEX] > HEVC_MAX_PPS_COUNT)) return AVERROR_INVALIDDATA; /* unsigned int(8) configurationVersion = 1; */ avio_w8(pb, hvcc->configurationVersion); - /* - * unsigned int(2) general_profile_space; - * unsigned int(1) general_tier_flag; - * unsigned int(5) general_profile_idc; - */ - avio_w8(pb, hvcc->general_profile_space << 6 | - hvcc->general_tier_flag << 5 | - hvcc->general_profile_idc); + if (!is_lhvc) { + /* + * unsigned int(2) general_profile_space; + * unsigned int(1) general_tier_flag; + * unsigned int(5) general_profile_idc; + */ + avio_w8(pb, hvcc->general_profile_space << 6 | + hvcc->general_tier_flag << 5 | + hvcc->general_profile_idc); - /* unsigned int(32) general_profile_compatibility_flags; */ - avio_wb32(pb, hvcc->general_profile_compatibility_flags); + /* unsigned int(32) general_profile_compatibility_flags; */ + avio_wb32(pb, hvcc->general_profile_compatibility_flags); - /* unsigned int(48) general_constraint_indicator_flags; */ - avio_wb32(pb, hvcc->general_constraint_indicator_flags >> 16); - avio_wb16(pb, hvcc->general_constraint_indicator_flags); + /* unsigned int(48) general_constraint_indicator_flags; */ + avio_wb32(pb, hvcc->general_constraint_indicator_flags >> 16); + avio_wb16(pb, hvcc->general_constraint_indicator_flags); - /* unsigned int(8) general_level_idc; */ - avio_w8(pb, hvcc->general_level_idc); + /* unsigned int(8) general_level_idc; */ + avio_w8(pb, hvcc->general_level_idc); + } /* * bit(4) reserved = '1111'b; @@ -906,29 +1002,34 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) */ avio_w8(pb, hvcc->parallelismType | 0xfc); - /* - * bit(6) reserved = '111111'b; - * unsigned int(2) chromaFormat; - */ - avio_w8(pb, hvcc->chromaFormat | 0xfc); + if (!is_lhvc) { + /* + * bit(6) reserved = '111111'b; + * unsigned int(2) chromaFormat; + */ + avio_w8(pb, hvcc->chromaFormat | 0xfc); + + /* + * bit(5) reserved = '11111'b; + * unsigned int(3) bitDepthLumaMinus8; + */ + avio_w8(pb, hvcc->bitDepthLumaMinus8 | 0xf8); + + /* + * bit(5) reserved = '11111'b; + * unsigned int(3) bitDepthChromaMinus8; + */ + avio_w8(pb, hvcc->bitDepthChromaMinus8 | 0xf8); + + /* bit(16) avgFrameRate; */ + avio_wb16(pb, hvcc->avgFrameRate); + } /* - * bit(5) reserved = '11111'b; - * unsigned int(3) bitDepthLumaMinus8; - */ - avio_w8(pb, hvcc->bitDepthLumaMinus8 | 0xf8); - - /* - * bit(5) reserved = '11111'b; - * unsigned int(3) bitDepthChromaMinus8; - */ - avio_w8(pb, hvcc->bitDepthChromaMinus8 | 0xf8); - - /* bit(16) avgFrameRate; */ - avio_wb16(pb, hvcc->avgFrameRate); - - /* - * bit(2) constantFrameRate; + * if (!is_lhvc) + * bit(2) constantFrameRate; + * else + * bit(2) reserved = '11'b; * bit(3) numTemporalLayers; * bit(1) temporalIdNested; * unsigned int(2) lengthSizeMinusOne; @@ -939,12 +1040,12 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) hvcc->lengthSizeMinusOne); /* unsigned int(8) numOfArrays; */ - avio_w8(pb, hvcc->numOfArrays); + avio_w8(pb, numOfArrays); for (unsigned i = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) { const HVCCNALUnitArray *const array = &hvcc->arrays[i]; - if (!array->numNalus) + if (!numNalus[i]) continue; /* * bit(1) array_completeness; @@ -955,15 +1056,19 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) array->NAL_unit_type & 0x3f); /* unsigned int(16) numNalus; */ - avio_wb16(pb, array->numNalus); + avio_wb16(pb, numNalus[i]); for (unsigned j = 0; j < array->numNalus; j++) { + HVCCNALUnit *nal = &array->nal[j]; + + if (is_lhvc && nal->nuh_layer_id == 0) + continue; + /* unsigned int(16) nalUnitLength; */ - avio_wb16(pb, array->nalUnitLength[j]); + avio_wb16(pb, nal->nalUnitLength); /* bit(8*nalUnitLength) nalUnit; */ - avio_write(pb, array->nalUnit[j], - array->nalUnitLength[j]); + avio_write(pb, nal->nalUnit, nal->nalUnitLength); } } @@ -977,11 +1082,11 @@ int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in, uint8_t *buf, *end, *start = NULL; if (!filter_ps) { - ret = ff_avc_parse_nal_units(pb, buf_in, size); + ret = ff_nal_parse_units(pb, buf_in, size); goto end; } - ret = ff_avc_parse_nal_units_buf(buf_in, &start, &size); + ret = ff_nal_parse_units_buf(buf_in, &start, &size); if (ret < 0) goto end; @@ -1039,26 +1144,105 @@ int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, return 0; } -int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, - int size, int ps_array_completeness) +static int hvcc_parse_nal_unit(const uint8_t *buf, uint32_t len, int type, + HEVCDecoderConfigurationRecord *hvcc, + int flags) +{ + for (unsigned i = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) { + static const uint8_t array_idx_to_type[] = + { HEVC_NAL_VPS, HEVC_NAL_SPS, HEVC_NAL_PPS, + HEVC_NAL_SEI_PREFIX, HEVC_NAL_SEI_SUFFIX }; + + if (type == array_idx_to_type[i]) { + int ret = hvcc_add_nal_unit(buf, len, hvcc, flags, i); + if (ret < 0) + return ret; + break; + } + } + + return 0; +} + +static int write_configuration_record(AVIOContext *pb, const uint8_t *data, + int size, int flags) { HEVCDecoderConfigurationRecord hvcc; - uint8_t *buf, *end, *start; + uint8_t *buf, *end, *start = NULL; int ret; if (size < 6) { /* We can't write a valid hvcC from the provided data */ return AVERROR_INVALIDDATA; } else if (*data == 1) { - /* Data is already hvcC-formatted */ - avio_write(pb, data, size); - return 0; + /* Data is already hvcC-formatted. Parse the arrays to skip any NALU + with nuh_layer_id > 0 */ + GetBitContext gbc; + int num_arrays; + + if (size < 23) + return AVERROR_INVALIDDATA; + + ret = init_get_bits8(&gbc, data, size); + if (ret < 0) + return ret; + + hvcc_init(&hvcc); + skip_bits(&gbc, 8); // hvcc.configurationVersion + hvcc.general_profile_space = get_bits(&gbc, 2); + hvcc.general_tier_flag = get_bits1(&gbc); + hvcc.general_profile_idc = get_bits(&gbc, 5); + hvcc.general_profile_compatibility_flags = get_bits_long(&gbc, 32); + hvcc.general_constraint_indicator_flags = get_bits64(&gbc, 48); + hvcc.general_level_idc = get_bits(&gbc, 8); + skip_bits(&gbc, 4); // reserved + hvcc.min_spatial_segmentation_idc = get_bits(&gbc, 12); + skip_bits(&gbc, 6); // reserved + hvcc.parallelismType = get_bits(&gbc, 2); + skip_bits(&gbc, 6); // reserved + hvcc.chromaFormat = get_bits(&gbc, 2); + skip_bits(&gbc, 5); // reserved + hvcc.bitDepthLumaMinus8 = get_bits(&gbc, 3); + skip_bits(&gbc, 5); // reserved + hvcc.bitDepthChromaMinus8 = get_bits(&gbc, 3); + hvcc.avgFrameRate = get_bits(&gbc, 16); + hvcc.constantFrameRate = get_bits(&gbc, 2); + hvcc.numTemporalLayers = get_bits(&gbc, 3); + hvcc.temporalIdNested = get_bits1(&gbc); + hvcc.lengthSizeMinusOne = get_bits(&gbc, 2); + + flags |= FLAG_IS_NALFF; + + num_arrays = get_bits(&gbc, 8); + for (int i = 0; i < num_arrays; i++) { + int type, num_nalus; + + skip_bits(&gbc, 2); + type = get_bits(&gbc, 6); + num_nalus = get_bits(&gbc, 16); + for (int j = 0; j < num_nalus; j++) { + int len = get_bits(&gbc, 16); + + if (len > (get_bits_left(&gbc) / 8)) + goto end; + + ret = hvcc_parse_nal_unit(data + get_bits_count(&gbc) / 8, + len, type, &hvcc, flags); + if (ret < 0) + goto end; + + skip_bits_long(&gbc, len * 8); + } + } + + ret = hvcc_write(pb, &hvcc, flags); + goto end; } else if (!(AV_RB24(data) == 1 || AV_RB32(data) == 1)) { /* Not a valid Annex B start code prefix */ return AVERROR_INVALIDDATA; } - ret = ff_avc_parse_nal_units_buf(data, &start, &size); + ret = ff_nal_parse_units_buf(data, &start, &size); if (ret < 0) return ret; @@ -1073,27 +1257,31 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, buf += 4; - for (unsigned i = 0; i < FF_ARRAY_ELEMS(hvcc.arrays); i++) { - static const uint8_t array_idx_to_type[] = - { HEVC_NAL_VPS, HEVC_NAL_SPS, HEVC_NAL_PPS, - HEVC_NAL_SEI_PREFIX, HEVC_NAL_SEI_SUFFIX }; - - if (type == array_idx_to_type[i]) { - ret = hvcc_add_nal_unit(buf, len, ps_array_completeness, - &hvcc, i); - if (ret < 0) - goto end; - break; - } - } + ret = hvcc_parse_nal_unit(buf, len, type, &hvcc, flags); + if (ret < 0) + goto end; buf += len; } - ret = hvcc_write(pb, &hvcc); + ret = hvcc_write(pb, &hvcc, flags); end: hvcc_close(&hvcc); av_free(start); return ret; } + +int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, + int size, int ps_array_completeness) +{ + return write_configuration_record(pb, data, size, + !!ps_array_completeness * FLAG_ARRAY_COMPLETENESS); +} + +int ff_isom_write_lhvc(AVIOContext *pb, const uint8_t *data, + int size, int ps_array_completeness) +{ + return write_configuration_record(pb, data, size, + (!!ps_array_completeness * FLAG_ARRAY_COMPLETENESS) | FLAG_IS_LHVC); +} diff --git a/libavformat/hevc.h b/libavformat/hevc.h index 0f56325c1..12000b25a 100644 --- a/libavformat/hevc.h +++ b/libavformat/hevc.h @@ -79,7 +79,8 @@ int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, int *size, int filter_ps, int *ps_count); /** - * Writes HEVC extradata (parameter sets, declarative SEI NAL units) to the + * Writes HEVC extradata (parameter sets and declarative SEI NAL units with + * nuh_layer_id == 0, as a HEVCDecoderConfigurationRecord) to the * provided AVIOContext. * * If the extradata is Annex B format, it gets converted to hvcC format before @@ -96,4 +97,21 @@ int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, int size, int ps_array_completeness); +/** + * Writes L-HEVC extradata (parameter sets with nuh_layer_id > 0, as a + * LHEVCDecoderConfigurationRecord) to the provided AVIOContext. + * + * If the extradata is Annex B format, it gets converted to lhvC format before + * writing. Otherwise, hvcC formated extradata is expected, not lhvC. + * + * @param pb address of the AVIOContext where the lhvC shall be written + * @param data address of the buffer holding the data needed to write the lhvC + * @param size size (in bytes) of the data buffer + * @param ps_array_completeness whether all parameter sets are in the lhvC (1) + * or there may be additional parameter sets in the bitstream (0) + * @return >=0 in case of success, a negative value corresponding to an AVERROR + * code in case of failure + */ +int ff_isom_write_lhvc(AVIOContext *pb, const uint8_t *data, + int size, int ps_array_completeness); #endif /* AVFORMAT_HEVC_H */ diff --git a/libavformat/hevcdec.c b/libavformat/hevcdec.c index 255f03bc4..4fc4068cd 100644 --- a/libavformat/hevcdec.c +++ b/libavformat/hevcdec.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavcodec/hevc.h" +#include "libavcodec/hevc/hevc.h" #include "avformat.h" #include "rawdec.h" diff --git a/libavformat/hls.c b/libavformat/hls.c index 8702113e9..b96c5ab9d 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -35,6 +35,7 @@ #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/dict.h" #include "libavutil/time.h" @@ -222,6 +223,7 @@ typedef struct HLSContext { AVDictionary *avio_opts; AVDictionary *seg_format_opts; char *allowed_extensions; + int extension_picky; int max_reload; int http_persistent; int http_multiple; @@ -730,6 +732,46 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, return ret; } +static int test_segment(AVFormatContext *s, const AVInputFormat *in_fmt, struct playlist *pls, struct segment *seg) +{ + HLSContext *c = s->priv_data; + int matchA = 3; + int matchF = 0; + + if (!c->extension_picky) + return 0; + + if (strcmp(c->allowed_extensions, "ALL")) + matchA = av_match_ext (seg->url, c->allowed_extensions) + + 2*(ff_match_url_ext(seg->url, c->allowed_extensions) > 0); + + if (!matchA) { + av_log(s, AV_LOG_ERROR, "URL %s is not in allowed_extensions\n", seg->url); + return AVERROR_INVALIDDATA; + } + + if (in_fmt) { + if (in_fmt->extensions) { + matchF = av_match_ext( seg->url, in_fmt->extensions) + + 2*(ff_match_url_ext(seg->url, in_fmt->extensions) > 0); + if(av_match_name("mp4", in_fmt->name)) { + matchF |= av_match_ext( seg->url, "ts,m2t,m2ts,mts,mpg,m4s,mpeg,mpegts") + + 2*(ff_match_url_ext(seg->url, "ts,m2t,m2ts,mts,mpg,m4s,mpeg,mpegts") > 0); + } + } else if (!strcmp(in_fmt->name, "mpegts")) { + matchF = av_match_ext( seg->url, "ts,m2t,m2ts,mts,mpg,m4s,mpeg,mpegts") + + 2*(ff_match_url_ext(seg->url, "ts,m2t,m2ts,mts,mpg,m4s,mpeg,mpegts") > 0); + } + + if (!(matchA & matchF)) { + av_log(s, AV_LOG_ERROR, "detected format %s extension %s mismatches allowed extensions in url %s\n", in_fmt->name, in_fmt->extensions ? in_fmt->extensions : "none", seg->url); + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + static int parse_playlist(HLSContext *c, const char *url, struct playlist *pls, AVIOContext *in) { @@ -988,6 +1030,14 @@ static int parse_playlist(HLSContext *c, const char *url, goto fail; } + ret = test_segment(c->ctx, pls->ctx ? pls->ctx->iformat : NULL, pls, seg); + if (ret < 0) { + av_free(seg->url); + av_free(seg->key); + av_free(seg); + goto fail; + } + if (duration < 0.001 * AV_TIME_BASE) { av_log(c->ctx, AV_LOG_WARNING, "Cannot get correct #EXTINF value of segment %s," " set to default value to 1ms.\n", seg->url); @@ -2098,6 +2148,7 @@ static int hls_read_header(AVFormatContext *s) * If encryption scheme is SAMPLE-AES and audio setup information is present in external audio track, * use that information to find the media format, otherwise probe input data */ + seg = current_segment(pls); if (seg && seg->key_type == KEY_SAMPLE_AES && pls->is_id3_timestamped && pls->audio_setup_info.codec_id != AV_CODEC_ID_NONE) { av_assert1(pls->audio_setup_info.codec_id == AV_CODEC_ID_AAC || @@ -2112,6 +2163,11 @@ static int hls_read_header(AVFormatContext *s) pls->ctx->interrupt_callback = s->interrupt_callback; url = av_strdup(pls->segments[0]->url); ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, url, NULL, 0, 0); + + for (int n = 0; n < pls->n_segments; n++) + if (ret >= 0) + ret = test_segment(s, in_fmt, pls, pls->segments[n]); + if (ret < 0) { /* Free the ctx - it isn't initialized properly at this point, * so avformat_close_input shouldn't be called. If @@ -2126,6 +2182,7 @@ static int hls_read_header(AVFormatContext *s) av_free(url); } + seg = current_segment(pls); if (seg && seg->key_type == KEY_SAMPLE_AES) { if (strstr(in_fmt->name, "mov")) { char key[33]; @@ -2172,6 +2229,7 @@ static int hls_read_header(AVFormatContext *s) * on us if they want to. */ if (pls->is_id3_timestamped || (pls->n_renditions > 0 && pls->renditions[0]->type == AVMEDIA_TYPE_AUDIO)) { + seg = current_segment(pls); if (seg && seg->key_type == KEY_SAMPLE_AES && pls->audio_setup_info.setup_data_length > 0 && pls->ctx->nb_streams == 1) ret = ff_hls_senc_parse_audio_setup_info(pls->ctx->streams[0], &pls->audio_setup_info); @@ -2572,8 +2630,10 @@ static const AVOption hls_options[] = { OFFSET(allowed_extensions), AV_OPT_TYPE_STRING, {.str = "3gp,aac,avi,ac3,eac3,flac,mkv,m3u8,m4a,m4s,m4v,mpg,mov,mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,wav"}, INT_MIN, INT_MAX, FLAGS}, + {"extension_picky", "Be picky with all extensions matching", + OFFSET(extension_picky), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS}, {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded", - OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 3}, 0, INT_MAX, FLAGS}, + OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 100}, 0, INT_MAX, FLAGS}, {"m3u8_hold_counters", "The maximum number of times to load m3u8 when it refreshes without new segments", OFFSET(m3u8_hold_counters), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, FLAGS}, {"http_persistent", "Use persistent HTTP connections", diff --git a/libavformat/hls_sample_encryption.c b/libavformat/hls_sample_encryption.c index f412836d4..f9f410f3d 100644 --- a/libavformat/hls_sample_encryption.c +++ b/libavformat/hls_sample_encryption.c @@ -28,6 +28,7 @@ #include "libavutil/aes.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "hls_sample_encryption.h" diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 1ec4d5048..081d91f7d 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -33,6 +33,7 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/log.h" #include "libavutil/random_seed.h" @@ -49,6 +50,7 @@ #endif #include "hlsplaylist.h" #include "internal.h" +#include "nal.h" #include "mux.h" #include "os_support.h" #include "url.h" @@ -148,6 +150,11 @@ typedef struct VariantStream { int discontinuity; int reference_stream_index; + int64_t total_size; + double total_duration; + int64_t avg_bitrate; + int64_t max_bitrate; + HLSSegment *segments; HLSSegment *last_segment; HLSSegment *old_segments; @@ -569,12 +576,6 @@ static void reflush_dynbuf(VariantStream *vs, int *range_length) avio_write(vs->out, vs->temp_buffer, *range_length); } -#if HAVE_DOS_PATHS -#define SEPARATOR '\\' -#else -#define SEPARATOR '/' -#endif - static int hls_delete_file(HLSContext *hls, AVFormatContext *avf, char *path, const char *proto) { @@ -667,7 +668,7 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n", segment->filename); if (!hls->use_localtime_mkdir) // segment->filename contains basename only - av_bprintf(&path, "%s%c", dirname, SEPARATOR); + av_bprintf(&path, "%s/", dirname); av_bprintf(&path, "%s", segment->filename); if (!av_bprint_is_complete(&path)) { @@ -684,8 +685,7 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, vtt_dirname = av_dirname(vtt_dirname_r); av_bprint_clear(&path); - av_bprintf(&path, "%s%c%s", vtt_dirname, SEPARATOR, - segment->sub_filename); + av_bprintf(&path, "%s/%s", vtt_dirname, segment->sub_filename); av_freep(&vtt_dirname_r); if (!av_bprint_is_complete(&path)) { @@ -887,7 +887,9 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs) if (!(st = avformat_new_stream(loc, NULL))) return AVERROR(ENOMEM); - avcodec_parameters_copy(st->codecpar, vs->streams[i]->codecpar); + ret = avcodec_parameters_copy(st->codecpar, vs->streams[i]->codecpar); + if (ret < 0) + return ret; if (!oc->oformat->codec_tag || av_codec_get_id (oc->oformat->codec_tag, vs->streams[i]->codecpar->codec_tag) == st->codecpar->codec_id || av_codec_get_tag(oc->oformat->codec_tag, vs->streams[i]->codecpar->codec_id) <= 0) { @@ -1113,6 +1115,18 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, if (!en) return AVERROR(ENOMEM); + vs->total_size += size; + vs->total_duration += duration; + if (duration > 0.5) { + // Don't include the final, possibly very short segment in the + // calculation of the max bitrate. + int cur_bitrate = (int)(8 * size / duration); + if (cur_bitrate > vs->max_bitrate) + vs->max_bitrate = cur_bitrate; + } + if (vs->total_duration > 0) + vs->avg_bitrate = (int)(8 * vs->total_size / vs->total_duration); + en->var_stream_idx = vs->var_stream_idx; ret = sls_flags_filename_process(s, hls, vs, en, duration, pos, size); if (ret < 0) { @@ -1367,14 +1381,15 @@ static int64_t get_stream_bit_rate(AVStream *stream) } static int create_master_playlist(AVFormatContext *s, - VariantStream * const input_vs) + VariantStream * const input_vs, + int final) { HLSContext *hls = s->priv_data; VariantStream *vs, *temp_vs; AVStream *vid_st, *aud_st; AVDictionary *options = NULL; unsigned int i, j; - int ret, bandwidth; + int ret, bandwidth, avg_bandwidth; const char *m3u8_rel_name = NULL; const char *vtt_m3u8_rel_name = NULL; const char *ccgroup; @@ -1394,8 +1409,8 @@ static int create_master_playlist(AVFormatContext *s, return 0; } else { /* Keep publishing the master playlist at the configured rate */ - if (&hls->var_streams[0] != input_vs || !hls->master_publish_rate || - input_vs->number % hls->master_publish_rate) + if ((&hls->var_streams[0] != input_vs || !hls->master_publish_rate || + input_vs->number % hls->master_publish_rate) && !final) return 0; } @@ -1485,12 +1500,17 @@ static int create_master_playlist(AVFormatContext *s, } } - bandwidth = 0; - if (vid_st) - bandwidth += get_stream_bit_rate(vid_st); - if (aud_st) - bandwidth += get_stream_bit_rate(aud_st); - bandwidth += bandwidth / 10; + if (final) { + bandwidth = vs->max_bitrate; + avg_bandwidth = vs->avg_bitrate; + } else { + bandwidth = 0; + if (vid_st) + bandwidth += get_stream_bit_rate(vid_st); + if (aud_st) + bandwidth += get_stream_bit_rate(aud_st); + bandwidth += bandwidth / 10; + } ccgroup = NULL; if (vid_st && vs->ccgroup) { @@ -1519,11 +1539,11 @@ static int create_master_playlist(AVFormatContext *s, } if (!hls->has_default_key || !hls->has_video_m3u8) { - ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name, + ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, avg_bandwidth, m3u8_rel_name, aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup, sgroup); } else { if (vid_st) { - ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name, + ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, avg_bandwidth, m3u8_rel_name, aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup, sgroup); } } @@ -1588,8 +1608,6 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) ret = hlsenc_io_open(s, byterange_mode ? &hls->m3u8_out : &vs->out, temp_filename, &options); av_dict_free(&options); if (ret < 0) { - if (hls->ignore_io_errors) - ret = 0; goto fail; } @@ -1647,8 +1665,6 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) ret = hlsenc_io_open(s, &hls->sub_m3u8_out, temp_vtt_filename, &options); av_dict_free(&options); if (ret < 0) { - if (hls->ignore_io_errors) - ret = 0; goto fail; } ff_hls_write_playlist_header(hls->sub_m3u8_out, hls->version, hls->allowcache, @@ -1680,7 +1696,7 @@ fail: ff_rename(temp_vtt_filename, vs->vtt_m3u8_name, s); } if (ret >= 0 && hls->master_pl_name) - if (create_master_playlist(s, vs) < 0) + if (create_master_playlist(s, vs, last) < 0) av_log(s, AV_LOG_WARNING, "Master playlist creation failed\n"); return ret; @@ -2389,7 +2405,7 @@ static int hls_init_file_resend(AVFormatContext *s, VariantStream *vs) static int64_t append_single_file(AVFormatContext *s, VariantStream *vs) { - int ret = 0; + int64_t ret = 0; int64_t read_byte = 0; int64_t total_size = 0; char *filename = NULL; @@ -2427,7 +2443,6 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) int is_ref_pkt = 1; int ret = 0, can_split = 1, i, j; int stream_index = 0; - int subtitle_streams = 0; int range_length = 0; const char *proto = NULL; int use_temp_file = 0; @@ -2435,6 +2450,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) char *old_filename = NULL; for (i = 0; i < hls->nb_varstreams; i++) { + int subtitle_streams = 0; vs = &hls->var_streams[i]; for (j = 0; j < vs->nb_streams; j++) { if (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { @@ -2513,6 +2529,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) end_pts, AV_TIME_BASE_Q) >= 0) { int64_t new_start_pos; int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); + double cur_duration; av_write_frame(oc, NULL); /* Flush any buffered data */ new_start_pos = avio_tell(oc->pb); @@ -2595,6 +2612,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) av_dict_free(&options); return ret; } + vs->size = range_length; ret = hlsenc_io_close(s, &vs->out, filename); if (ret < 0) { av_log(s, AV_LOG_WARNING, "upload segment failed," @@ -2623,15 +2641,13 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR(ENOMEM); } - if (vs->start_pos || hls->segment_type != SEGMENT_TYPE_FMP4) { - double cur_duration = (double)(pkt->pts - vs->end_pts) * st->time_base.num / st->time_base.den; - ret = hls_append_segment(s, hls, vs, cur_duration, vs->start_pos, vs->size); - vs->end_pts = pkt->pts; - vs->duration = 0; - if (ret < 0) { - av_freep(&old_filename); - return ret; - } + cur_duration = (double)(pkt->pts - vs->end_pts) * st->time_base.num / st->time_base.den; + ret = hls_append_segment(s, hls, vs, cur_duration, vs->start_pos, vs->size); + vs->end_pts = pkt->pts; + vs->duration = 0; + if (ret < 0) { + av_freep(&old_filename); + return ret; } // if we're building a VOD playlist, skip writing the manifest multiple times, and just wait until the end @@ -2673,7 +2689,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) vs->start_pos = new_start_pos; } } else { - vs->start_pos = new_start_pos; + vs->start_pos = 0; sls_flag_file_rename(hls, vs, old_filename); ret = hls_start(s, vs); } @@ -2768,6 +2784,7 @@ static int hls_write_trailer(struct AVFormatContext *s) filename = av_asprintf("%s", oc->url); } if (!filename) { + av_dict_free(&options); av_freep(&old_filename); return AVERROR(ENOMEM); } diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c index 4f35d0388..f8a697770 100644 --- a/libavformat/hlsplaylist.c +++ b/libavformat/hlsplaylist.c @@ -71,6 +71,7 @@ void ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup, } void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, + int avg_bandwidth, const char *filename, const char *agroup, const char *codecs, const char *ccgroup, const char *sgroup) @@ -85,6 +86,8 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, } avio_printf(out, "#EXT-X-STREAM-INF:BANDWIDTH=%d", bandwidth); + if (avg_bandwidth) + avio_printf(out, ",AVERAGE-BANDWIDTH=%d", avg_bandwidth); if (st && st->codecpar->width > 0 && st->codecpar->height > 0) avio_printf(out, ",RESOLUTION=%dx%d", st->codecpar->width, st->codecpar->height); diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h index c2744c227..d7aa44d8d 100644 --- a/libavformat/hlsplaylist.h +++ b/libavformat/hlsplaylist.h @@ -43,6 +43,7 @@ void ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup, const char *filename, const char *language, int name_id, int is_default); void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, + int avg_bandwidth, const char *filename, const char *agroup, const char *codecs, const char *ccgroup, const char *sgroup); diff --git a/libavformat/hlsproto.c b/libavformat/hlsproto.c index 4db61dee3..02f695c1d 100644 --- a/libavformat/hlsproto.c +++ b/libavformat/hlsproto.c @@ -26,6 +26,7 @@ */ #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/time.h" #include "avio_internal.h" #include "internal.h" diff --git a/libavformat/http.c b/libavformat/http.c index 9e933b18b..ec60bc0b1 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -31,6 +31,8 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/getenv_utf8.h" +#include "libavutil/macros.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time.h" #include "libavutil/parseutils.h" @@ -55,7 +57,7 @@ #define MAX_CACHED_REDIRECTS 32 #define HTTP_SINGLE 1 #define HTTP_MUTLI 2 -#define MAX_EXPIRY 19 +#define MAX_DATE_LEN 19 #define WHITESPACES " \n\t\r" typedef enum { LOWER_PROTO, @@ -137,6 +139,10 @@ typedef struct HTTPContext { char *new_location; AVDictionary *redirect_cache; uint64_t filesize_from_content_range; + int respect_retry_after; + unsigned int retry_after; + int reconnect_max_retries; + int reconnect_delay_total_max; } HTTPContext; #define OFFSET(x) offsetof(HTTPContext, x) @@ -175,6 +181,9 @@ static const AVOption options[] = { { "reconnect_on_http_error", "list of http status codes to reconnect on", OFFSET(reconnect_on_http_error), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D }, { "reconnect_streamed", "auto reconnect streamed / non seekable streams", OFFSET(reconnect_streamed), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D }, { "reconnect_delay_max", "max reconnect delay in seconds after which to give up", OFFSET(reconnect_delay_max), AV_OPT_TYPE_INT, { .i64 = 120 }, 0, UINT_MAX/1000/1000, D }, + { "reconnect_max_retries", "the max number of times to retry a connection", OFFSET(reconnect_max_retries), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, D }, + { "reconnect_delay_total_max", "max total reconnect delay in seconds after which to give up", OFFSET(reconnect_delay_total_max), AV_OPT_TYPE_INT, { .i64 = 256 }, 0, UINT_MAX/1000/1000, D }, + { "respect_retry_after", "respect the Retry-After header when retrying connections", OFFSET(respect_retry_after), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D }, { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E }, { "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, { "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E}, @@ -285,6 +294,7 @@ static int http_should_reconnect(HTTPContext *s, int err) case AVERROR_HTTP_UNAUTHORIZED: case AVERROR_HTTP_FORBIDDEN: case AVERROR_HTTP_NOT_FOUND: + case AVERROR_HTTP_TOO_MANY_REQUESTS: case AVERROR_HTTP_OTHER_4XX: status_group = "4xx"; break; @@ -354,8 +364,9 @@ static int http_open_cnx(URLContext *h, AVDictionary **options) { HTTPAuthType cur_auth_type, cur_proxy_auth_type; HTTPContext *s = h->priv_data; - int ret, attempts = 0, redirects = 0; + int ret, conn_attempts = 1, auth_attempts = 0, redirects = 0; int reconnect_delay = 0; + int reconnect_delay_total = 0; uint64_t off; char *cached; @@ -381,14 +392,26 @@ redo: ret = http_open_cnx_internal(h, options); if (ret < 0) { if (!http_should_reconnect(s, ret) || - reconnect_delay > s->reconnect_delay_max) + reconnect_delay > s->reconnect_delay_max || + (s->reconnect_max_retries >= 0 && conn_attempts > s->reconnect_max_retries) || + reconnect_delay_total > s->reconnect_delay_total_max) goto fail; + /* Both fields here are in seconds. */ + if (s->respect_retry_after && s->retry_after > 0) { + reconnect_delay = s->retry_after; + if (reconnect_delay > s->reconnect_delay_max) + goto fail; + s->retry_after = 0; + } + av_log(h, AV_LOG_WARNING, "Will reconnect at %"PRIu64" in %d second(s).\n", off, reconnect_delay); ret = ff_network_sleep_interruptible(1000U * 1000 * reconnect_delay, &h->interrupt_callback); if (ret != AVERROR(ETIMEDOUT)) goto fail; + reconnect_delay_total += reconnect_delay; reconnect_delay = 1 + 2 * reconnect_delay; + conn_attempts++; /* restore the offset (http_connect resets it) */ s->off = off; @@ -397,10 +420,10 @@ redo: goto redo; } - attempts++; + auth_attempts++; if (s->http_code == 401) { if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) && - s->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) { + s->auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 4) { ffurl_closep(&s->hd); goto redo; } else @@ -408,7 +431,7 @@ redo: } if (s->http_code == 407) { if ((cur_proxy_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) && - s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) { + s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 4) { ffurl_closep(&s->hd); goto redo; } else @@ -437,7 +460,7 @@ redo: /* Restart the authentication process with the new target, which * might use a different auth mechanism. */ memset(&s->auth_state, 0, sizeof(s->auth_state)); - attempts = 0; + auth_attempts = 0; goto redo; } return 0; @@ -521,6 +544,7 @@ int ff_http_averror(int status_code, int default_averror) case 401: return AVERROR_HTTP_UNAUTHORIZED; case 403: return AVERROR_HTTP_FORBIDDEN; case 404: return AVERROR_HTTP_NOT_FOUND; + case 429: return AVERROR_HTTP_TOO_MANY_REQUESTS; default: break; } if (status_code >= 400 && status_code <= 499) @@ -557,6 +581,11 @@ static int http_write_reply(URLContext* h, int status_code) reply_code = 404; reply_text = "Not Found"; break; + case AVERROR_HTTP_TOO_MANY_REQUESTS: + case 429: + reply_code = 429; + reply_text = "Too Many Requests"; + break; case 200: reply_code = 200; reply_text = "OK"; @@ -896,29 +925,29 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p) return 0; } -static int parse_set_cookie_expiry_time(const char *exp_str, struct tm *buf) +static int parse_http_date(const char *date_str, struct tm *buf) { - char exp_buf[MAX_EXPIRY]; - int i, j, exp_buf_len = MAX_EXPIRY-1; - char *expiry; + char date_buf[MAX_DATE_LEN]; + int i, j, date_buf_len = MAX_DATE_LEN-1; + char *date; // strip off any punctuation or whitespace - for (i = 0, j = 0; exp_str[i] != '\0' && j < exp_buf_len; i++) { - if ((exp_str[i] >= '0' && exp_str[i] <= '9') || - (exp_str[i] >= 'A' && exp_str[i] <= 'Z') || - (exp_str[i] >= 'a' && exp_str[i] <= 'z')) { - exp_buf[j] = exp_str[i]; + for (i = 0, j = 0; date_str[i] != '\0' && j < date_buf_len; i++) { + if ((date_str[i] >= '0' && date_str[i] <= '9') || + (date_str[i] >= 'A' && date_str[i] <= 'Z') || + (date_str[i] >= 'a' && date_str[i] <= 'z')) { + date_buf[j] = date_str[i]; j++; } } - exp_buf[j] = '\0'; - expiry = exp_buf; + date_buf[j] = '\0'; + date = date_buf; // move the string beyond the day of week - while ((*expiry < '0' || *expiry > '9') && *expiry != '\0') - expiry++; + while ((*date < '0' || *date > '9') && *date != '\0') + date++; - return av_small_strptime(expiry, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL); + return av_small_strptime(date, "%d%b%Y%H%M%S", buf) ? 0 : AVERROR(EINVAL); } static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) @@ -961,7 +990,7 @@ static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) { AVDictionary *new_params = NULL; - AVDictionaryEntry *e, *cookie_entry; + const AVDictionaryEntry *e, *cookie_entry; char *eql, *name; // ensure the cookie is parsable @@ -969,7 +998,7 @@ static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) return -1; // if there is no cookie value there is nothing to parse - cookie_entry = av_dict_get(new_params, "", NULL, AV_DICT_IGNORE_SUFFIX); + cookie_entry = av_dict_iterate(new_params, NULL); if (!cookie_entry || !cookie_entry->value) { av_dict_free(&new_params); return -1; @@ -978,7 +1007,7 @@ static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) // ensure the cookie is not expired or older than an existing value if ((e = av_dict_get(new_params, "expires", NULL, 0)) && e->value) { struct tm new_tm = {0}; - if (!parse_set_cookie_expiry_time(e->value, &new_tm)) { + if (!parse_http_date(e->value, &new_tm)) { AVDictionaryEntry *e2; // if the cookie has already expired ignore it @@ -995,7 +1024,7 @@ static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) e2 = av_dict_get(old_params, "expires", NULL, 0); if (e2 && e2->value) { struct tm old_tm = {0}; - if (!parse_set_cookie_expiry_time(e->value, &old_tm)) { + if (!parse_http_date(e->value, &old_tm)) { if (av_timegm(&new_tm) < av_timegm(&old_tm)) { av_dict_free(&new_params); av_dict_free(&old_params); @@ -1047,7 +1076,7 @@ static void parse_expires(HTTPContext *s, const char *p) { struct tm tm; - if (!parse_set_cookie_expiry_time(p, &tm)) { + if (!parse_http_date(p, &tm)) { s->expires = av_timegm(&tm); } } @@ -1079,7 +1108,7 @@ static void parse_cache_control(HTTPContext *s, const char *p) } } -static int process_line(URLContext *h, char *line, int line_count) +static int process_line(URLContext *h, char *line, int line_count, int *parsed_http_code) { HTTPContext *s = h->priv_data; const char *auto_method = h->flags & AVIO_FLAG_READ ? "POST" : "GET"; @@ -1159,6 +1188,8 @@ static int process_line(URLContext *h, char *line, int line_count) av_log(h, AV_LOG_TRACE, "http_code=%d\n", s->http_code); + *parsed_http_code = 1; + if ((ret = check_http_code(h, s->http_code, end)) < 0) return ret; } @@ -1222,6 +1253,18 @@ static int process_line(URLContext *h, char *line, int line_count) parse_expires(s, p); } else if (!av_strcasecmp(tag, "Cache-Control")) { parse_cache_control(s, p); + } else if (!av_strcasecmp(tag, "Retry-After")) { + /* The header can be either an integer that represents seconds, or a date. */ + struct tm tm; + int date_ret = parse_http_date(p, &tm); + if (!date_ret) { + time_t retry = av_timegm(&tm); + int64_t now = av_gettime() / 1000000; + int64_t diff = ((int64_t) retry) - now; + s->retry_after = (unsigned int) FFMAX(0, diff); + } else { + s->retry_after = strtoul(p, NULL, 10); + } } } return 1; @@ -1257,7 +1300,7 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, *cookies = NULL; while ((cookie = av_strtok(next, "\n", &saveptr)) && !ret) { AVDictionary *cookie_params = NULL; - AVDictionaryEntry *cookie_entry, *e; + const AVDictionaryEntry *cookie_entry, *e; next = NULL; // store the cookie in a dict in case it is updated in the response @@ -1269,14 +1312,14 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, goto skip_cookie; // if the cookie has no value, skip it - cookie_entry = av_dict_get(cookie_params, "", NULL, AV_DICT_IGNORE_SUFFIX); + cookie_entry = av_dict_iterate(cookie_params, NULL); if (!cookie_entry || !cookie_entry->value) goto skip_cookie; // if the cookie has expired, don't add it if ((e = av_dict_get(cookie_params, "expires", NULL, 0)) && e->value) { struct tm tm_buf = {0}; - if (!parse_set_cookie_expiry_time(e->value, &tm_buf)) { + if (!parse_http_date(e->value, &tm_buf)) { if (av_timegm(&tm_buf) < av_gettime() / 1000000) goto skip_cookie; } @@ -1331,7 +1374,7 @@ static int http_read_header(URLContext *h) { HTTPContext *s = h->priv_data; char line[MAX_URL_SIZE]; - int err = 0; + int err = 0, http_err = 0; av_freep(&s->new_location); s->expires = 0; @@ -1339,18 +1382,31 @@ static int http_read_header(URLContext *h) s->filesize_from_content_range = UINT64_MAX; for (;;) { + int parsed_http_code = 0; + if ((err = http_get_line(s, line, sizeof(line))) < 0) return err; av_log(h, AV_LOG_TRACE, "header='%s'\n", line); - err = process_line(h, line, s->line_count); - if (err < 0) - return err; + err = process_line(h, line, s->line_count, &parsed_http_code); + if (err < 0) { + if (parsed_http_code) { + http_err = err; + } else { + /* Prefer to return HTTP code error if we've already seen one. */ + if (http_err) + return http_err; + else + return err; + } + } if (err == 0) break; s->line_count++; } + if (http_err) + return http_err; // filesize from Content-Range can always be used, even if using chunked Transfer-Encoding if (s->filesize_from_content_range != UINT64_MAX) @@ -1672,6 +1728,8 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size) int err, read_ret; int64_t seek_ret; int reconnect_delay = 0; + int reconnect_delay_total = 0; + int conn_attempts = 1; if (!s->hd) return AVERROR_EOF; @@ -1700,14 +1758,17 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size) !(s->reconnect_at_eof && read_ret == AVERROR_EOF)) break; - if (reconnect_delay > s->reconnect_delay_max) + if (reconnect_delay > s->reconnect_delay_max || (s->reconnect_max_retries >= 0 && conn_attempts > s->reconnect_max_retries) || + reconnect_delay_total > s->reconnect_delay_total_max) return AVERROR(EIO); av_log(h, AV_LOG_WARNING, "Will reconnect at %"PRIu64" in %d second(s), error=%s.\n", s->off, reconnect_delay, av_err2str(read_ret)); err = ff_network_sleep_interruptible(1000U*1000*reconnect_delay, &h->interrupt_callback); if (err != AVERROR(ETIMEDOUT)) return err; + reconnect_delay_total += reconnect_delay; reconnect_delay = 1 + 2*reconnect_delay; + conn_attempts++; seek_ret = http_seek_internal(h, target, SEEK_SET, 1); if (seek_ret >= 0 && seek_ret != target) { av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target); @@ -2048,7 +2109,7 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags) char hostname[1024], hoststr[1024]; char auth[1024], pathbuf[1024], *path; char lower_url[100]; - int port, ret = 0, attempts = 0; + int port, ret = 0, auth_attempts = 0; HTTPAuthType cur_auth_type; char *authstr; @@ -2108,10 +2169,10 @@ redo: if (ret < 0) goto fail; - attempts++; + auth_attempts++; if (s->http_code == 407 && (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) && - s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) { + s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && auth_attempts < 2) { ffurl_closep(&s->hd); goto redo; } diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c index 978092835..904836250 100644 --- a/libavformat/httpauth.c +++ b/libavformat/httpauth.c @@ -22,6 +22,7 @@ #include "httpauth.h" #include "libavutil/base64.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "internal.h" #include "libavutil/random_seed.h" #include "libavutil/md5.h" diff --git a/libavformat/iamf_parse.c b/libavformat/iamf_parse.c index a222a46c8..7b3b1e87f 100644 --- a/libavformat/iamf_parse.c +++ b/libavformat/iamf_parse.c @@ -20,10 +20,10 @@ */ #include "libavutil/avassert.h" -#include "libavutil/common.h" #include "libavutil/iamf.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavcodec/get_bits.h" #include "libavcodec/flac.h" #include "libavcodec/leb.h" @@ -36,7 +36,7 @@ static int opus_decoder_config(IAMFCodecConfig *codec_config, AVIOContext *pb, int len) { - int left = len - avio_tell(pb); + int ret, left = len - avio_tell(pb); if (left < 11 || codec_config->audio_roll_distance >= 0) return AVERROR_INVALIDDATA; @@ -45,13 +45,13 @@ static int opus_decoder_config(IAMFCodecConfig *codec_config, if (!codec_config->extradata) return AVERROR(ENOMEM); - AV_WB32(codec_config->extradata, MKBETAG('O','p','u','s')); - AV_WB32(codec_config->extradata + 4, MKBETAG('H','e','a','d')); - codec_config->extradata_size = avio_read(pb, codec_config->extradata + 8, left); - if (codec_config->extradata_size < left) - return AVERROR_INVALIDDATA; + AV_WB32A(codec_config->extradata, MKBETAG('O','p','u','s')); + AV_WB32A(codec_config->extradata + 4, MKBETAG('H','e','a','d')); + ret = ffio_read_size(pb, codec_config->extradata + 8, left); + if (ret < 0) + return ret; - codec_config->extradata_size += 8; + codec_config->extradata_size = left + 8; codec_config->sample_rate = 48000; return 0; @@ -67,7 +67,7 @@ static int aac_decoder_config(IAMFCodecConfig *codec_config, if (codec_config->audio_roll_distance >= 0) return AVERROR_INVALIDDATA; - tag = avio_r8(pb); + ff_mp4_read_descr(logctx, pb, &tag); if (tag != MP4DecConfigDescrTag) return AVERROR_INVALIDDATA; @@ -87,12 +87,9 @@ static int aac_decoder_config(IAMFCodecConfig *codec_config, if (codec_id && codec_id != codec_config->codec_id) return AVERROR_INVALIDDATA; - tag = avio_r8(pb); - if (tag != MP4DecSpecificDescrTag) - return AVERROR_INVALIDDATA; - - left = len - avio_tell(pb); - if (left <= 0) + left = ff_mp4_read_descr(logctx, pb, &tag); + if (tag != MP4DecSpecificDescrTag || + !left || left > (len - avio_tell(pb))) return AVERROR_INVALIDDATA; // We pad extradata here because avpriv_mpeg4audio_get_config2() needs it. @@ -100,9 +97,10 @@ static int aac_decoder_config(IAMFCodecConfig *codec_config, if (!codec_config->extradata) return AVERROR(ENOMEM); - codec_config->extradata_size = avio_read(pb, codec_config->extradata, left); - if (codec_config->extradata_size < left) - return AVERROR_INVALIDDATA; + ret = ffio_read_size(pb, codec_config->extradata, left); + if (ret < 0) + return ret; + codec_config->extradata_size = left; memset(codec_config->extradata + codec_config->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); @@ -119,7 +117,7 @@ static int aac_decoder_config(IAMFCodecConfig *codec_config, static int flac_decoder_config(IAMFCodecConfig *codec_config, AVIOContext *pb, int len) { - int left; + int ret, left; if (codec_config->audio_roll_distance) return AVERROR_INVALIDDATA; @@ -134,10 +132,11 @@ static int flac_decoder_config(IAMFCodecConfig *codec_config, if (!codec_config->extradata) return AVERROR(ENOMEM); - codec_config->extradata_size = avio_read(pb, codec_config->extradata, left); - if (codec_config->extradata_size < left) - return AVERROR_INVALIDDATA; + ret = ffio_read_size(pb, codec_config->extradata, left); + if (ret < 0) + return ret; + codec_config->extradata_size = left; codec_config->sample_rate = AV_RB24(codec_config->extradata + 10) >> 4; return 0; @@ -179,12 +178,9 @@ static int codec_config_obu(void *s, IAMFContext *c, AVIOContext *pb, int len) if (!buf) return AVERROR(ENOMEM); - ret = avio_read(pb, buf, len); - if (ret != len) { - if (ret >= 0) - ret = AVERROR_INVALIDDATA; + ret = ffio_read_size(pb, buf, len); + if (ret < 0) goto fail; - } ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); pbc = &b.pub; @@ -283,10 +279,10 @@ static int update_extradata(AVCodecParameters *codecpar) switch(codecpar->codec_id) { case AV_CODEC_ID_OPUS: - AV_WB8(codecpar->extradata + 9, codecpar->ch_layout.nb_channels); - AV_WL16(codecpar->extradata + 10, AV_RB16(codecpar->extradata + 10)); // Byte swap pre-skip - AV_WL32(codecpar->extradata + 12, AV_RB32(codecpar->extradata + 12)); // Byte swap sample rate - AV_WL16(codecpar->extradata + 16, AV_RB16(codecpar->extradata + 16)); // Byte swap Output Gain + AV_WB8(codecpar->extradata + 9, codecpar->ch_layout.nb_channels); + AV_WL16A(codecpar->extradata + 10, AV_RB16A(codecpar->extradata + 10)); // Byte swap pre-skip + AV_WL32A(codecpar->extradata + 12, AV_RB32A(codecpar->extradata + 12)); // Byte swap sample rate + AV_WL16A(codecpar->extradata + 16, AV_RB16A(codecpar->extradata + 16)); // Byte swap Output Gain break; case AV_CODEC_ID_AAC: { uint8_t buf[5]; @@ -308,10 +304,10 @@ static int update_extradata(AVCodecParameters *codecpar) skip_bits(&gb, 4); put_bits(&pb, 4, codecpar->ch_layout.nb_channels); // set channel config ret = put_bits_left(&pb); - put_bits(&pb, ret, get_bits(&gb, ret)); + put_bits(&pb, ret, get_bits_long(&gb, ret)); flush_put_bits(&pb); - memcpy(codecpar->extradata, buf, sizeof(buf)); + memcpy(codecpar->extradata, buf, put_bytes_output(&pb)); break; } case AV_CODEC_ID_FLAC: { @@ -417,11 +413,11 @@ static int ambisonics_config(void *s, AVIOContext *pb, ambisonics_mode = ffio_read_leb(pb); if (ambisonics_mode > 1) - return 0; + return AVERROR_INVALIDDATA; output_channel_count = avio_r8(pb); // C substream_count = avio_r8(pb); // N - if (audio_element->nb_substreams != substream_count) + if (audio_element->nb_substreams != substream_count || output_channel_count == 0) return AVERROR_INVALIDDATA; order = floor(sqrt(output_channel_count - 1)); @@ -500,6 +496,7 @@ static int param_parse(void *s, IAMFContext *c, AVIOContext *pb, AVIAMFParamDefinition *param; unsigned int parameter_id, parameter_rate, mode; unsigned int duration = 0, constant_subblock_duration = 0, nb_subblocks = 0; + unsigned int total_duration = 0; size_t param_size; parameter_id = ffio_read_leb(pb); @@ -520,8 +517,10 @@ static int param_parse(void *s, IAMFContext *c, AVIOContext *pb, constant_subblock_duration = ffio_read_leb(pb); if (constant_subblock_duration == 0) nb_subblocks = ffio_read_leb(pb); - else + else { nb_subblocks = duration / constant_subblock_duration; + total_duration = duration; + } } param = av_iamf_param_definition_alloc(type, nb_subblocks, ¶m_size); @@ -532,8 +531,11 @@ static int param_parse(void *s, IAMFContext *c, AVIOContext *pb, void *subblock = av_iamf_param_definition_get_subblock(param, i); unsigned int subblock_duration = constant_subblock_duration; - if (constant_subblock_duration == 0) + if (constant_subblock_duration == 0) { subblock_duration = ffio_read_leb(pb); + total_duration += subblock_duration; + } else if (i == nb_subblocks - 1) + subblock_duration = duration - i * constant_subblock_duration; switch (type) { case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { @@ -561,6 +563,12 @@ static int param_parse(void *s, IAMFContext *c, AVIOContext *pb, } } + if (!mode && !constant_subblock_duration && total_duration != duration) { + av_log(s, AV_LOG_ERROR, "Invalid subblock durations in parameter_id %u\n", parameter_id); + av_free(param); + return AVERROR_INVALIDDATA; + } + param->parameter_id = parameter_id; param->parameter_rate = parameter_rate; param->duration = duration; @@ -616,12 +624,9 @@ static int audio_element_obu(void *s, IAMFContext *c, AVIOContext *pb, int len) if (!buf) return AVERROR(ENOMEM); - ret = avio_read(pb, buf, len); - if (ret != len) { - if (ret >= 0) - ret = AVERROR_INVALIDDATA; + ret = ffio_read_size(pb, buf, len); + if (ret < 0) goto fail; - } ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); pbc = &b.pub; @@ -636,6 +641,12 @@ static int audio_element_obu(void *s, IAMFContext *c, AVIOContext *pb, int len) } audio_element_type = avio_r8(pbc) >> 5; + if (audio_element_type > AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE) { + av_log(s, AV_LOG_DEBUG, "Unknown audio_element_type referenced in an audio element. Ignoring\n"); + ret = 0; + goto fail; + } + codec_config_id = ffio_read_leb(pbc); codec_config = ff_iamf_get_codec_config(c, codec_config_id); @@ -717,6 +728,12 @@ static int audio_element_obu(void *s, IAMFContext *c, AVIOContext *pb, int len) } num_parameters = ffio_read_leb(pbc); + if (num_parameters > 2 && audio_element_type == 0) { + av_log(s, AV_LOG_ERROR, "Audio Element parameter count %u is invalid" + " for Channel representations\n", num_parameters); + ret = AVERROR_INVALIDDATA; + goto fail; + } if (num_parameters && audio_element_type != 0) { av_log(s, AV_LOG_ERROR, "Audio Element parameter count %u is invalid" " for Scene representations\n", num_parameters); @@ -730,11 +747,19 @@ static int audio_element_obu(void *s, IAMFContext *c, AVIOContext *pb, int len) type = ffio_read_leb(pbc); if (type == AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN) ret = AVERROR_INVALIDDATA; - else if (type == AV_IAMF_PARAMETER_DEFINITION_DEMIXING) + else if (type == AV_IAMF_PARAMETER_DEFINITION_DEMIXING) { + if (element->demixing_info) { + ret = AVERROR_INVALIDDATA; + goto fail; + } ret = param_parse(s, c, pbc, type, audio_element, &element->demixing_info); - else if (type == AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN) + } else if (type == AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN) { + if (element->recon_gain_info) { + ret = AVERROR_INVALIDDATA; + goto fail; + } ret = param_parse(s, c, pbc, type, audio_element, &element->recon_gain_info); - else { + } else { unsigned param_definition_size = ffio_read_leb(pbc); avio_skip(pbc, param_definition_size); } @@ -751,8 +776,7 @@ static int audio_element_obu(void *s, IAMFContext *c, AVIOContext *pb, int len) if (ret < 0) goto fail; } else { - unsigned audio_element_config_size = ffio_read_leb(pbc); - avio_skip(pbc, audio_element_config_size); + av_assert0(0); } c->audio_elements[c->nb_audio_elements++] = audio_element; @@ -800,12 +824,9 @@ static int mix_presentation_obu(void *s, IAMFContext *c, AVIOContext *pb, int le if (!buf) return AVERROR(ENOMEM); - ret = avio_read(pb, buf, len); - if (ret != len) { - if (ret >= 0) - ret = AVERROR_INVALIDDATA; + ret = ffio_read_size(pb, buf, len); + if (ret < 0) goto fail; - } ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); pbc = &b.pub; @@ -844,6 +865,7 @@ static int mix_presentation_obu(void *s, IAMFContext *c, AVIOContext *pb, int le mix_presentation->language_label = av_calloc(mix_presentation->count_label, sizeof(*mix_presentation->language_label)); if (!mix_presentation->language_label) { + mix_presentation->count_label = 0; ret = AVERROR(ENOMEM); goto fail; } @@ -1075,6 +1097,7 @@ int ff_iamfdec_read_descriptors(IAMFContext *c, AVIOContext *pb, size = avio_read(pb, header, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); if (size < 0) return size; + memset(header + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); len = ff_iamf_parse_obu_header(header, size, &obu_size, &start_pos, &type, NULL, NULL); if (len < 0 || obu_size > max_size) { diff --git a/libavformat/iamf_reader.c b/libavformat/iamf_reader.c index f3ff4170c..d331e1315 100644 --- a/libavformat/iamf_reader.c +++ b/libavformat/iamf_reader.c @@ -22,6 +22,7 @@ #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavcodec/mathops.h" #include "libavcodec/packet.h" #include "avformat.h" @@ -72,8 +73,8 @@ static int audio_frame_obu(AVFormatContext *s, const IAMFDemuxContext *c, uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); if (!side_data) return AVERROR(ENOMEM); - AV_WL32(side_data, skip_samples); - AV_WL32(side_data + 4, discard_padding); + AV_WL32A(side_data, skip_samples); + AV_WL32A(side_data + 4, discard_padding); } if (c->mix) { uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_MIX_GAIN_PARAM, c->mix_size); @@ -108,6 +109,7 @@ static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c, AVIOContext *pb; uint8_t *buf; unsigned int duration, constant_subblock_duration; + unsigned int total_duration = 0; unsigned int nb_subblocks; unsigned int parameter_id; size_t out_param_size; @@ -146,8 +148,10 @@ static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c, constant_subblock_duration = ffio_read_leb(pb); if (constant_subblock_duration == 0) nb_subblocks = ffio_read_leb(pb); - else + else { nb_subblocks = duration / constant_subblock_duration; + total_duration = duration; + } } else { duration = param->duration; constant_subblock_duration = param->constant_subblock_duration; @@ -171,8 +175,11 @@ static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c, void *subblock = av_iamf_param_definition_get_subblock(out_param, i); unsigned int subblock_duration = constant_subblock_duration; - if (!param_definition->mode && !constant_subblock_duration) + if (!param_definition->mode && !constant_subblock_duration) { subblock_duration = ffio_read_leb(pb); + total_duration += subblock_duration; + } else if (i == nb_subblocks - 1) + subblock_duration = duration - i * constant_subblock_duration; switch (param->type) { case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { @@ -234,6 +241,12 @@ static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c, av_log(s, level, "Underread in parameter_block_obu. %d bytes left at the end\n", len); } + if (!param_definition->mode && !constant_subblock_duration && total_duration != duration) { + av_log(s, AV_LOG_ERROR, "Invalid duration in parameter block\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + switch (param->type) { case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: av_free(c->mix); @@ -269,17 +282,20 @@ int ff_iamf_read_packet(AVFormatContext *s, IAMFDemuxContext *c, int read = 0; while (1) { - uint8_t header[MAX_IAMF_OBU_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; + uint8_t header[MAX_IAMF_OBU_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE] = {0}; enum IAMF_OBU_Type type; unsigned obu_size; unsigned skip_samples, discard_padding; int ret, len, size, start_pos; - if ((ret = ffio_ensure_seekback(pb, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size))) < 0) + ret = ffio_ensure_seekback(pb, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); + if (ret < 0) return ret; size = avio_read(pb, header, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); if (size < 0) return size; + if (size != FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)) + return AVERROR_INVALIDDATA; len = ff_iamf_parse_obu_header(header, size, &obu_size, &start_pos, &type, &skip_samples, &discard_padding); diff --git a/libavformat/iamf_writer.c b/libavformat/iamf_writer.c index 5e8d8f768..27926f859 100644 --- a/libavformat/iamf_writer.c +++ b/libavformat/iamf_writer.c @@ -42,12 +42,12 @@ static int update_extradata(IAMFCodecConfig *codec_config) if (codec_config->extradata_size != 19) return AVERROR_INVALIDDATA; codec_config->extradata_size -= 8; - AV_WB8(codec_config->extradata + 0, AV_RL8(codec_config->extradata + 8)); // version - AV_WB8(codec_config->extradata + 1, 2); // set channels to stereo - AV_WB16(codec_config->extradata + 2, AV_RL16(codec_config->extradata + 10)); // Byte swap pre-skip - AV_WB32(codec_config->extradata + 4, AV_RL32(codec_config->extradata + 12)); // Byte swap sample rate - AV_WB16(codec_config->extradata + 8, 0); // set Output Gain to 0 - AV_WB8(codec_config->extradata + 10, AV_RL8(codec_config->extradata + 18)); // Mapping family + AV_WB8(codec_config->extradata + 0, AV_RL8(codec_config->extradata + 8)); // version + AV_WB8(codec_config->extradata + 1, 2); // set channels to stereo + AV_WB16A(codec_config->extradata + 2, AV_RL16A(codec_config->extradata + 10)); // Byte swap pre-skip + AV_WB32A(codec_config->extradata + 4, AV_RL32A(codec_config->extradata + 12)); // Byte swap sample rate + AV_WB16A(codec_config->extradata + 8, 0); // set Output Gain to 0 + AV_WB8(codec_config->extradata + 10, AV_RL8(codec_config->extradata + 18)); // Mapping family break; case AV_CODEC_ID_FLAC: { uint8_t buf[13]; @@ -112,9 +112,17 @@ static int fill_codec_config(IAMFContext *iamf, const AVStreamGroup *stg, int j, ret = 0; codec_config->codec_id = st->codecpar->codec_id; - codec_config->sample_rate = st->codecpar->sample_rate; codec_config->codec_tag = st->codecpar->codec_tag; - codec_config->nb_samples = st->codecpar->frame_size; + switch (codec_config->codec_id) { + case AV_CODEC_ID_OPUS: + codec_config->sample_rate = 48000; + codec_config->nb_samples = av_rescale(st->codecpar->frame_size, 48000, st->codecpar->sample_rate); + break; + default: + codec_config->sample_rate = st->codecpar->sample_rate; + codec_config->nb_samples = st->codecpar->frame_size; + break; + } populate_audio_roll_distance(codec_config); if (st->codecpar->extradata_size) { codec_config->extradata = av_memdup(st->codecpar->extradata, st->codecpar->extradata_size); @@ -183,9 +191,9 @@ static int add_param_definition(IAMFContext *iamf, AVIAMFParamDefinition *param, } if (codec_config) { if (!param->duration) - param->duration = codec_config->nb_samples; + param->duration = av_rescale(codec_config->nb_samples, param->parameter_rate, codec_config->sample_rate); if (!param->constant_subblock_duration) - param->constant_subblock_duration = codec_config->nb_samples; + param->constant_subblock_duration = av_rescale(codec_config->nb_samples, param->parameter_rate, codec_config->sample_rate); } param_definition = av_mallocz(sizeof(*param_definition)); @@ -209,6 +217,10 @@ int ff_iamf_add_audio_element(IAMFContext *iamf, const AVStreamGroup *stg, void if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT) return AVERROR(EINVAL); + if (!stg->nb_streams) { + av_log(log_ctx, AV_LOG_ERROR, "Audio Element id %"PRId64" has no streams\n", stg->id); + return AVERROR(EINVAL); + } iamf_audio_element = stg->params.iamf_audio_element; if (iamf_audio_element->audio_element_type == AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE) { @@ -373,6 +385,10 @@ int ff_iamf_add_mix_presentation(IAMFContext *iamf, const AVStreamGroup *stg, vo if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) return AVERROR(EINVAL); + if (!stg->nb_streams) { + av_log(log_ctx, AV_LOG_ERROR, "Mix Presentation id %"PRId64" has no streams\n", stg->id); + return AVERROR(EINVAL); + } for (int i = 0; i < iamf->nb_mix_presentations; i++) { if (stg->id == iamf->mix_presentations[i]->mix_presentation_id) { diff --git a/libavformat/icecast.c b/libavformat/icecast.c index b06c53cab..3146d7f38 100644 --- a/libavformat/icecast.c +++ b/libavformat/icecast.c @@ -20,8 +20,8 @@ */ -#include "libavutil/avstring.h" #include "libavutil/bprint.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avformat.h" diff --git a/libavformat/icodec.c b/libavformat/icodec.c index 808c7ab79..b09d0060a 100644 --- a/libavformat/icodec.c +++ b/libavformat/icodec.c @@ -25,6 +25,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/bytestream.h" #include "libavcodec/png.h" #include "avformat.h" @@ -197,7 +198,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) AV_WL32(buf + 32, image->nb_pal); } - if (image->nb_pal > INT_MAX / 4 - 14 - 40) + if (image->nb_pal > INT_MAX / 4 - 14 - 40U) return AVERROR_INVALIDDATA; AV_WL32(buf - 4, 14 + 40 + image->nb_pal * 4); diff --git a/libavformat/icoenc.c b/libavformat/icoenc.c index caa3ba496..7a7d839d8 100644 --- a/libavformat/icoenc.c +++ b/libavformat/icoenc.c @@ -25,7 +25,7 @@ */ #include "libavutil/intreadwrite.h" -#include "libavutil/pixdesc.h" +#include "libavutil/mem.h" #include "libavcodec/codec_id.h" diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index e0a7e3f3e..350788570 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -36,6 +36,7 @@ #include "libavutil/bprint.h" #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/png.h" #include "avio_internal.h" #include "demux.h" diff --git a/libavformat/iff.c b/libavformat/iff.c index 0cbe12533..6b4503fdb 100644 --- a/libavformat/iff.c +++ b/libavformat/iff.c @@ -34,6 +34,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "libavcodec/bytestream.h" #include "avformat.h" #include "demux.h" @@ -359,6 +360,9 @@ static int read_dst_frame(AVFormatContext *s, AVPacket *pkt) uint64_t chunk_pos, data_pos, data_size; int ret = AVERROR_EOF; + if (s->nb_streams < 1) + return AVERROR_INVALIDDATA; + while (!avio_feof(pb)) { chunk_pos = avio_tell(pb); if (chunk_pos >= iff->body_end) diff --git a/libavformat/ilbc.c b/libavformat/ilbc.c index a24aa3da9..6c441c21b 100644 --- a/libavformat/ilbc.c +++ b/libavformat/ilbc.c @@ -61,7 +61,8 @@ static int ilbc_read_header(AVFormatContext *s) AVStream *st; uint8_t header[9]; - avio_read(pb, header, 9); + if (avio_read(pb, header, 9) != 9) + return AVERROR_INVALIDDATA; st = avformat_new_stream(s, NULL); if (!st) diff --git a/libavformat/imf_cpl.c b/libavformat/imf_cpl.c index 5f1a67443..137cff2a6 100644 --- a/libavformat/imf_cpl.c +++ b/libavformat/imf_cpl.c @@ -51,9 +51,9 @@ */ #include "imf.h" -#include "libavformat/mxf.h" #include "libavutil/bprint.h" #include "libavutil/error.h" +#include "libavutil/mem.h" #include xmlNodePtr ff_imf_xml_get_child_element_by_name(xmlNodePtr parent, const char *name_utf8) diff --git a/libavformat/imfdec.c b/libavformat/imfdec.c index bf56c7826..a86b4763f 100644 --- a/libavformat/imfdec.c +++ b/libavformat/imfdec.c @@ -70,8 +70,8 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "mxf.h" #include #include diff --git a/libavformat/img2.c b/libavformat/img2.c index 06e48549a..9981867f8 100644 --- a/libavformat/img2.c +++ b/libavformat/img2.c @@ -20,80 +20,90 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/avstring.h" #include "internal.h" #include "img2.h" +#define IMG_TAGS(TAG) \ + TAG(MJPEG, jpeg ) \ + TAG(MJPEG, jpg ) \ + TAG(MJPEG, jps ) \ + TAG(MJPEG, mpo ) \ + TAG(LJPEG, ljpg ) \ + TAG(JPEGLS, jls ) \ + TAG(PNG, png ) \ + TAG(PNG, pns ) \ + TAG(PNG, mng ) \ + TAG(PPM, ppm ) \ + TAG(PPM, pnm ) \ + TAG(PGM, pgm ) \ + TAG(PGMYUV, pgmyuv ) \ + TAG(PBM, pbm ) \ + TAG(PAM, pam ) \ + TAG(PFM, pfm ) \ + TAG(PHM, phm ) \ + TAG(CRI, cri ) \ + TAG(ALIAS_PIX, pix ) \ + TAG(DDS, dds ) \ + TAG(MPEG1VIDEO, mpg1-img ) \ + TAG(MPEG2VIDEO, mpg2-img ) \ + TAG(MPEG4, mpg4-img ) \ + TAG(RAWVIDEO, y ) \ + TAG(RAWVIDEO, raw ) \ + TAG(BMP, bmp ) \ + TAG(TARGA, tga ) \ + TAG(TIFF, tiff ) \ + TAG(TIFF, tif ) \ + TAG(TIFF, dng ) \ + TAG(SGI, sgi ) \ + TAG(PTX, ptx ) \ + TAG(PHOTOCD, pcd ) \ + TAG(PCX, pcx ) \ + TAG(QDRAW, pic ) \ + TAG(QDRAW, pct ) \ + TAG(QDRAW, pict ) \ + TAG(SUNRAST, sun ) \ + TAG(SUNRAST, ras ) \ + TAG(SUNRAST, rs ) \ + TAG(SUNRAST, im1 ) \ + TAG(SUNRAST, im8 ) \ + TAG(SUNRAST, im24 ) \ + TAG(SUNRAST, im32 ) \ + TAG(SUNRAST, sunras ) \ + TAG(SVG, svg ) \ + TAG(SVG, svgz ) \ + TAG(JPEG2000, j2c ) \ + TAG(JPEG2000, jp2 ) \ + TAG(JPEG2000, jpc ) \ + TAG(JPEG2000, j2k ) \ + TAG(DPX, dpx ) \ + TAG(EXR, exr ) \ + TAG(PICTOR, pic ) \ + TAG(V210X, yuv10 ) \ + TAG(WEBP, webp ) \ + TAG(XBM, xbm ) \ + TAG(XPM, xpm ) \ + TAG(XFACE, xface ) \ + TAG(XWD, xwd ) \ + TAG(GEM, img ) \ + TAG(GEM, ximg ) \ + TAG(GEM, timg ) \ + TAG(VBN, vbn ) \ + TAG(JPEGXL, jxl ) \ + TAG(QOI, qoi ) \ + TAG(RADIANCE_HDR, hdr ) \ + TAG(WBMP, wbmp ) \ + TAG(NONE, ) + +#define LENGTH_CHECK(CODECID, STR) \ + static_assert(sizeof(#STR) <= sizeof(ff_img_tags->str), #STR " does not fit into IdStrMap.str\n"); +IMG_TAGS(LENGTH_CHECK) + const IdStrMap ff_img_tags[] = { - { AV_CODEC_ID_MJPEG, "jpeg" }, - { AV_CODEC_ID_MJPEG, "jpg" }, - { AV_CODEC_ID_MJPEG, "jps" }, - { AV_CODEC_ID_MJPEG, "mpo" }, - { AV_CODEC_ID_LJPEG, "ljpg" }, - { AV_CODEC_ID_JPEGLS, "jls" }, - { AV_CODEC_ID_PNG, "png" }, - { AV_CODEC_ID_PNG, "pns" }, - { AV_CODEC_ID_PNG, "mng" }, - { AV_CODEC_ID_PPM, "ppm" }, - { AV_CODEC_ID_PPM, "pnm" }, - { AV_CODEC_ID_PGM, "pgm" }, - { AV_CODEC_ID_PGMYUV, "pgmyuv" }, - { AV_CODEC_ID_PBM, "pbm" }, - { AV_CODEC_ID_PAM, "pam" }, - { AV_CODEC_ID_PFM, "pfm" }, - { AV_CODEC_ID_PHM, "phm" }, - { AV_CODEC_ID_CRI, "cri" }, - { AV_CODEC_ID_ALIAS_PIX, "pix" }, - { AV_CODEC_ID_DDS, "dds" }, - { AV_CODEC_ID_MPEG1VIDEO, "mpg1-img" }, - { AV_CODEC_ID_MPEG2VIDEO, "mpg2-img" }, - { AV_CODEC_ID_MPEG4, "mpg4-img" }, - { AV_CODEC_ID_RAWVIDEO, "y" }, - { AV_CODEC_ID_RAWVIDEO, "raw" }, - { AV_CODEC_ID_BMP, "bmp" }, - { AV_CODEC_ID_TARGA, "tga" }, - { AV_CODEC_ID_TIFF, "tiff" }, - { AV_CODEC_ID_TIFF, "tif" }, - { AV_CODEC_ID_TIFF, "dng" }, - { AV_CODEC_ID_SGI, "sgi" }, - { AV_CODEC_ID_PTX, "ptx" }, - { AV_CODEC_ID_PHOTOCD, "pcd" }, - { AV_CODEC_ID_PCX, "pcx" }, - { AV_CODEC_ID_QDRAW, "pic" }, - { AV_CODEC_ID_QDRAW, "pct" }, - { AV_CODEC_ID_QDRAW, "pict" }, - { AV_CODEC_ID_SUNRAST, "sun" }, - { AV_CODEC_ID_SUNRAST, "ras" }, - { AV_CODEC_ID_SUNRAST, "rs" }, - { AV_CODEC_ID_SUNRAST, "im1" }, - { AV_CODEC_ID_SUNRAST, "im8" }, - { AV_CODEC_ID_SUNRAST, "im24" }, - { AV_CODEC_ID_SUNRAST, "im32" }, - { AV_CODEC_ID_SUNRAST, "sunras" }, - { AV_CODEC_ID_SVG, "svg" }, - { AV_CODEC_ID_SVG, "svgz" }, - { AV_CODEC_ID_JPEG2000, "j2c" }, - { AV_CODEC_ID_JPEG2000, "jp2" }, - { AV_CODEC_ID_JPEG2000, "jpc" }, - { AV_CODEC_ID_JPEG2000, "j2k" }, - { AV_CODEC_ID_DPX, "dpx" }, - { AV_CODEC_ID_EXR, "exr" }, - { AV_CODEC_ID_PICTOR, "pic" }, - { AV_CODEC_ID_V210X, "yuv10" }, - { AV_CODEC_ID_WEBP, "webp" }, - { AV_CODEC_ID_XBM, "xbm" }, - { AV_CODEC_ID_XPM, "xpm" }, - { AV_CODEC_ID_XFACE, "xface" }, - { AV_CODEC_ID_XWD, "xwd" }, - { AV_CODEC_ID_GEM, "img" }, - { AV_CODEC_ID_GEM, "ximg" }, - { AV_CODEC_ID_GEM, "timg" }, - { AV_CODEC_ID_VBN, "vbn" }, - { AV_CODEC_ID_JPEGXL, "jxl" }, - { AV_CODEC_ID_QOI, "qoi" }, - { AV_CODEC_ID_RADIANCE_HDR, "hdr" }, - { AV_CODEC_ID_WBMP, "wbmp" }, - { AV_CODEC_ID_NONE, NULL } +#define TAG(CODECID, STR) { AV_CODEC_ID_ ## CODECID, #STR }, +IMG_TAGS(TAG) }; static enum AVCodecID str2id(const IdStrMap *tags, const char *str) diff --git a/libavformat/img2.h b/libavformat/img2.h index 5fd8ff77f..e98902c96 100644 --- a/libavformat/img2.h +++ b/libavformat/img2.h @@ -66,7 +66,7 @@ typedef struct VideoDemuxData { typedef struct IdStrMap { enum AVCodecID id; - const char *str; + char str[12]; } IdStrMap; extern const IdStrMap ff_img_tags[]; diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c index 69cce36be..3389fa818 100644 --- a/libavformat/img2dec.c +++ b/libavformat/img2dec.c @@ -28,9 +28,9 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "libavutil/parseutils.h" #include "libavutil/intreadwrite.h" #include "libavcodec/gif.h" #include "avformat.h" @@ -563,6 +563,7 @@ int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt) } goto fail; } else { + memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE); s->img_count++; s->img_number++; s->pts++; diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c index 526a11e5e..41638d92b 100644 --- a/libavformat/img2enc.c +++ b/libavformat/img2enc.c @@ -160,13 +160,13 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR(EINVAL); } } else if (img->frame_pts) { - if (av_get_frame_filename2(filename, sizeof(filename), s->url, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { + if (ff_get_frame_filename(filename, sizeof(filename), s->url, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { av_log(s, AV_LOG_ERROR, "Cannot write filename by pts of the frames."); return AVERROR(EINVAL); } - } else if (av_get_frame_filename2(filename, sizeof(filename), s->url, - img->img_number, - AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { + } else if (ff_get_frame_filename(filename, sizeof(filename), s->url, + img->img_number, + AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { if (img->img_number == img->start_img_number) { av_log(s, AV_LOG_WARNING, "The specified filename '%s' does not contain an image sequence pattern or a pattern is invalid.\n", s->url); av_log(s, AV_LOG_WARNING, diff --git a/libavformat/internal.h b/libavformat/internal.h index 7f3d1c008..6c026f08a 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -411,7 +411,9 @@ typedef struct FFStream { const struct AVCodecDescriptor *codec_desc; +#if FF_API_INTERNAL_TIMING AVRational transferred_mux_tb; +#endif } FFStream; static av_always_inline FFStream *ffstream(AVStream *st) @@ -727,9 +729,6 @@ struct AVBPrint; */ int ff_bprint_to_codecpar_extradata(AVCodecParameters *par, struct AVBPrint *buf); -int ff_lock_avformat(void); -int ff_unlock_avformat(void); - /** * Set AVFormatContext url field to the provided pointer. The pointer must * point to a valid string. The existing url field is freed if necessary. Also @@ -746,6 +745,22 @@ void ff_format_set_url(AVFormatContext *s, char *url); */ int ff_match_url_ext(const char *url, const char *extensions); +/** + * Return in 'buf' the path with '%d' replaced by a number. + * + * Also handles the '%0nd' format where 'n' is the total number + * of digits and '%%'. + * + * @param buf destination buffer + * @param buf_size destination buffer size + * @param path path with substitution template + * @param number the number to substitute + * @param flags AV_FRAME_FILENAME_FLAGS_* + * @return 0 if OK, -1 on format error + */ +int ff_get_frame_filename(char *buf, int buf_size, const char *path, + int64_t number, int flags); + struct FFOutputFormat; struct FFInputFormat; void avpriv_register_devices(const struct FFOutputFormat * const o[], diff --git a/libavformat/ipfsgateway.c b/libavformat/ipfsgateway.c index 9c0d46109..9a15bcf93 100644 --- a/libavformat/ipfsgateway.c +++ b/libavformat/ipfsgateway.c @@ -22,6 +22,7 @@ #include "libavutil/avstring.h" #include "libavutil/file_open.h" #include "libavutil/getenv_utf8.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include #include "os_support.h" diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c index 5d1748953..3701be276 100644 --- a/libavformat/ipmovie.c +++ b/libavformat/ipmovie.c @@ -614,7 +614,8 @@ static int ipmovie_read_header(AVFormatContext *s) ipmovie->avf = s; - avio_read(pb, signature_buffer, sizeof(signature_buffer)); + if (avio_read(pb, signature_buffer, sizeof(signature_buffer)) != sizeof(signature_buffer)) + return AVERROR_INVALIDDATA; while (memcmp(signature_buffer, signature, sizeof(signature))) { memmove(signature_buffer, signature_buffer + 1, sizeof(signature_buffer) - 1); signature_buffer[sizeof(signature_buffer) - 1] = avio_r8(pb); diff --git a/libavformat/isom.c b/libavformat/isom.c index c5930bd4d..01f9126d3 100644 --- a/libavformat/isom.c +++ b/libavformat/isom.c @@ -292,12 +292,12 @@ int ff_mp4_read_descr_len(AVIOContext *pb) return len; } -int ff_mp4_read_descr(AVFormatContext *fc, AVIOContext *pb, int *tag) +int ff_mp4_read_descr(void *logctx, AVIOContext *pb, int *tag) { int len; *tag = avio_r8(pb); len = ff_mp4_read_descr_len(pb); - av_log(fc, AV_LOG_TRACE, "MPEG-4 description: tag=0x%02x len=%d\n", *tag, len); + av_log(logctx, AV_LOG_TRACE, "MPEG-4 description: tag=0x%02x len=%d\n", *tag, len); return len; } @@ -326,7 +326,7 @@ static const AVCodecTag mp4_audio_types[] = { { AV_CODEC_ID_NONE, AOT_NULL }, }; -int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext *pb) +int ff_mp4_read_dec_config_descr(void *logctx, AVStream *st, AVIOContext *pb) { enum AVCodecID codec_id; int len, tag; @@ -341,34 +341,36 @@ int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id); if (codec_id) st->codecpar->codec_id = codec_id; - av_log(fc, AV_LOG_TRACE, "esds object type id 0x%02x\n", object_type_id); - len = ff_mp4_read_descr(fc, pb, &tag); + av_log(logctx, AV_LOG_TRACE, "esds object type id 0x%02x\n", object_type_id); + len = ff_mp4_read_descr(logctx, pb, &tag); if (tag == MP4DecSpecificDescrTag) { - av_log(fc, AV_LOG_TRACE, "Specific MPEG-4 header len=%d\n", len); + av_log(logctx, AV_LOG_TRACE, "Specific MPEG-4 header len=%d\n", len); /* As per 14496-3:2009 9.D.2.2, No decSpecificInfo is defined for MPEG-1 Audio or MPEG-2 Audio; MPEG-2 AAC excluded. */ if (object_type_id == 0x69 || object_type_id == 0x6b) return 0; if (!len || (uint64_t)len > (1<<30)) return AVERROR_INVALIDDATA; - if ((ret = ff_get_extradata(fc, st->codecpar, pb, len)) < 0) + if ((ret = ff_get_extradata(logctx, st->codecpar, pb, len)) < 0) return ret; if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { MPEG4AudioConfig cfg = {0}; ret = avpriv_mpeg4audio_get_config2(&cfg, st->codecpar->extradata, - st->codecpar->extradata_size, 1, fc); + st->codecpar->extradata_size, 1, logctx); if (ret < 0) return ret; - av_channel_layout_uninit(&st->codecpar->ch_layout); - st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; - st->codecpar->ch_layout.nb_channels = cfg.channels; + if (cfg.channels != st->codecpar->ch_layout.nb_channels) { + av_channel_layout_uninit(&st->codecpar->ch_layout); + st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; + st->codecpar->ch_layout.nb_channels = cfg.channels; + } if (cfg.object_type == 29 && cfg.sampling_index < 3) // old mp3on4 st->codecpar->sample_rate = ff_mpa_freq_tab[cfg.sampling_index]; else if (cfg.ext_sample_rate) st->codecpar->sample_rate = cfg.ext_sample_rate; else st->codecpar->sample_rate = cfg.sample_rate; - av_log(fc, AV_LOG_TRACE, "mp4a config channels %d obj %d ext obj %d " + av_log(logctx, AV_LOG_TRACE, "mp4a config channels %d obj %d ext obj %d " "sample rate %d ext sample rate %d\n", cfg.channels, cfg.object_type, cfg.ext_object_type, cfg.sample_rate, cfg.ext_sample_rate); diff --git a/libavformat/isom.h b/libavformat/isom.h index c0a5788e0..ffabc01a2 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -212,9 +212,13 @@ typedef struct MOVStreamContext { unsigned drefs_count; MOVDref *drefs; int dref_id; + unsigned tref_flags; + int tref_id; int timecode_track; int width; ///< tkhd width int height; ///< tkhd height + int h_spacing; ///< pasp hSpacing + int v_spacing; ///< pasp vSpacing int dts_shift; ///< dts shift when ctts is negative uint32_t palette[256]; int has_palette; @@ -247,9 +251,11 @@ typedef struct MOVStreamContext { int32_t *display_matrix; AVStereo3D *stereo3d; + size_t stereo3d_size; AVSphericalMapping *spherical; size_t spherical_size; AVMasteringDisplayMetadata *mastering; + size_t mastering_size; AVContentLightMetadata *coll; size_t coll_size; AVAmbientViewingEnvironment *ambient; @@ -349,7 +355,7 @@ typedef struct MOVContext { uint32_t max_stts_delta; int primary_item_id; int cur_item_id; - HEIFItem *heif_item; + HEIFItem **heif_item; int nb_heif_item; HEIFGrid *heif_grid; int nb_heif_grid; @@ -359,8 +365,8 @@ typedef struct MOVContext { } MOVContext; int ff_mp4_read_descr_len(AVIOContext *pb); -int ff_mp4_read_descr(AVFormatContext *fc, AVIOContext *pb, int *tag); -int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext *pb); +int ff_mp4_read_descr(void *logctx, AVIOContext *pb, int *tag); +int ff_mp4_read_dec_config_descr(void *logctx, AVStream *st, AVIOContext *pb); void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id); #define MP4ODescrTag 0x01 @@ -404,6 +410,7 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id); #define MOV_SAMPLE_DEPENDENCY_YES 0x1 #define MOV_SAMPLE_DEPENDENCY_NO 0x2 +#define MOV_TREF_FLAG_ENHANCEMENT 0x1 #define TAG_IS_AVCI(tag) \ ((tag) == MKTAG('a', 'i', '5', 'p') || \ diff --git a/libavformat/isom_tags.c b/libavformat/isom_tags.c index 058f0f2a5..5dd72d570 100644 --- a/libavformat/isom_tags.c +++ b/libavformat/isom_tags.c @@ -290,6 +290,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_CFHD, MKTAG('C', 'F', 'H', 'D') }, + { AV_CODEC_ID_LCEVC, MKTAG('l', 'v', 'c', '1') }, /* LCEVC raw payload */ + { AV_CODEC_ID_NONE, 0 }, }; diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c index 09782eecd..9feaea351 100644 --- a/libavformat/ivfenc.c +++ b/libavformat/ivfenc.c @@ -24,7 +24,7 @@ typedef struct IVFEncContext { unsigned frame_cnt; - uint64_t last_pts, sum_delta_pts, last_pkt_duration; + uint64_t last_pts, last_pkt_duration; } IVFEncContext; static int ivf_init(AVFormatContext *s) @@ -80,8 +80,6 @@ static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt) avio_wl32(pb, pkt->size); avio_wl64(pb, pkt->pts); avio_write(pb, pkt->data, pkt->size); - if (ctx->frame_cnt) - ctx->sum_delta_pts += pkt->pts - ctx->last_pts; ctx->last_pkt_duration = pkt->duration; ctx->frame_cnt++; ctx->last_pts = pkt->pts; diff --git a/libavformat/jpegxl_anim_dec.c b/libavformat/jpegxl_anim_dec.c index ac95d3b96..7798f3dab 100644 --- a/libavformat/jpegxl_anim_dec.c +++ b/libavformat/jpegxl_anim_dec.c @@ -43,7 +43,7 @@ typedef struct JXLAnimDemuxContext { static int jpegxl_anim_probe(const AVProbeData *p) { - uint8_t buffer[4096 + AV_INPUT_BUFFER_PADDING_SIZE]; + uint8_t buffer[4096 + AV_INPUT_BUFFER_PADDING_SIZE] = {0}; int copied = 0, ret; FFJXLMetadata meta = { 0 }; @@ -124,6 +124,8 @@ static int jpegxl_anim_read_header(AVFormatContext *s) } } + memset(head + headsize, 0, AV_INPUT_BUFFER_PADDING_SIZE); + /* offset in bits of the animation header */ ret = ff_jpegxl_parse_codestream_header(head, headsize, &meta, 0); if (ret < 0 || meta.animation_offset <= 0) diff --git a/libavformat/jvdec.c b/libavformat/jvdec.c index 41dad2392..c4580b6a0 100644 --- a/libavformat/jvdec.c +++ b/libavformat/jvdec.c @@ -27,6 +27,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/lafdec.c b/libavformat/lafdec.c index 4ce4449c4..7cd109a55 100644 --- a/libavformat/lafdec.c +++ b/libavformat/lafdec.c @@ -20,6 +20,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "demux.h" diff --git a/libavformat/lc3.c b/libavformat/lc3.c new file mode 100644 index 000000000..16c12a98d --- /dev/null +++ b/libavformat/lc3.c @@ -0,0 +1,244 @@ +/* + * LC3 muxer and demuxer + * Copyright (C) 2024 Antoine Soulier + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * Based on the file format specified by : + * + * - Bluetooth SIG - Low Complexity Communication Codec Test Suite + * https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=502301 + * 3.2.8.2 Reference LC3 Codec Bitstream Format + * + * - ETSI TI 103 634 V1.4.1 - Low Complexity Communication Codec plus + * https://www.etsi.org/deliver/etsi_ts/103600_103699/103634/01.04.01_60/ts_103634v010401p.pdf + * LC3plus conformance script package + */ + +#include "config_components.h" + +#include "libavcodec/packet.h" +#include "libavutil/intreadwrite.h" + +#include "avformat.h" +#include "avio.h" +#include "demux.h" +#include "internal.h" +#include "mux.h" + +static int check_frame_length(void *avcl, int srate_hz, int frame_us) +{ + if (srate_hz != 8000 && srate_hz != 16000 && srate_hz != 24000 && + srate_hz != 32000 && srate_hz != 48000 && srate_hz != 96000) { + if (avcl) + av_log(avcl, AV_LOG_ERROR, + "Invalid LC3 sample rate: %d Hz.\n", srate_hz); + return -1; + } + + if (frame_us != 2500 && frame_us != 5000 && + frame_us != 7500 && frame_us != 10000) { + if (avcl) + av_log(avcl, AV_LOG_ERROR, + "Invalid LC3 frame duration: %.1f ms.\n", frame_us / 1000.f); + return -1; + } + + return 0; +} + +#if CONFIG_LC3_DEMUXER + +typedef struct LC3DemuxContext { + int frame_samples; + int64_t end_dts; +} LC3DemuxContext; + +static int lc3_read_probe(const AVProbeData *p) +{ + int frame_us, srate_hz; + + if (p->buf_size < 12) + return 0; + + if (AV_RB16(p->buf + 0) != 0x1ccc || + AV_RL16(p->buf + 2) < 9 * sizeof(uint16_t)) + return 0; + + srate_hz = AV_RL16(p->buf + 4) * 100; + frame_us = AV_RL16(p->buf + 10) * 10; + if (check_frame_length(NULL, srate_hz, frame_us) < 0) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static int lc3_read_header(AVFormatContext *s) +{ + LC3DemuxContext *lc3 = s->priv_data; + AVStream *st = NULL; + uint16_t tag, hdr_size; + uint32_t length; + int srate_hz, frame_us, channels, bit_rate; + int ep_mode, hr_mode; + int num_extra_params; + int delay, ret; + + tag = avio_rb16(s->pb); + hdr_size = avio_rl16(s->pb); + + if (tag != 0x1ccc || hdr_size < 9 * sizeof(uint16_t)) + return AVERROR_INVALIDDATA; + + num_extra_params = hdr_size / sizeof(uint16_t) - 9; + + srate_hz = avio_rl16(s->pb) * 100; + bit_rate = avio_rl16(s->pb) * 100; + channels = avio_rl16(s->pb); + frame_us = avio_rl16(s->pb) * 10; + ep_mode = avio_rl16(s->pb) != 0; + length = avio_rl32(s->pb); + hr_mode = num_extra_params >= 1 && avio_rl16(s->pb); + + if (check_frame_length(s, srate_hz, frame_us) < 0) + return AVERROR_INVALIDDATA; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + avpriv_set_pts_info(st, 64, 1, srate_hz); + avpriv_update_cur_dts(s, st, 0); + st->duration = length; + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = AV_CODEC_ID_LC3; + st->codecpar->sample_rate = srate_hz; + st->codecpar->bit_rate = bit_rate; + st->codecpar->ch_layout.nb_channels = channels; + + if ((ret = ff_alloc_extradata(st->codecpar, 6)) < 0) + return ret; + + AV_WL16(st->codecpar->extradata + 0, frame_us / 10); + AV_WL16(st->codecpar->extradata + 2, ep_mode); + AV_WL16(st->codecpar->extradata + 4, hr_mode); + + lc3->frame_samples = av_rescale(frame_us, srate_hz, 1000*1000); + + delay = av_rescale(frame_us == 7500 ? 4000 : 2500, srate_hz, 1000*1000); + lc3->end_dts = length ? length + delay : -1; + + return 0; +} + +static int lc3_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + LC3DemuxContext *lc3 = s->priv_data; + AVStream *st = s->streams[0]; + AVIOContext *pb = s->pb; + int64_t pos = avio_tell(pb); + int64_t remaining_samples; + int ret; + + ret = av_get_packet(s->pb, pkt, avio_rl16(pb)); + if (ret < 0) + return ret; + + pkt->pos = pos; + + remaining_samples = lc3->end_dts < 0 ? lc3->frame_samples : + FFMAX(lc3->end_dts - ffstream(st)->cur_dts, 0); + pkt->duration = FFMIN(lc3->frame_samples, remaining_samples); + + return 0; +} + +const FFInputFormat ff_lc3_demuxer = { + .p.name = "lc3", + .p.long_name = NULL_IF_CONFIG_SMALL("LC3 (Low Complexity Communication Codec)"), + .p.extensions = "lc3", + .p.flags = AVFMT_GENERIC_INDEX, + .priv_data_size = sizeof(LC3DemuxContext), + .read_probe = lc3_read_probe, + .read_header = lc3_read_header, + .read_packet = lc3_read_packet, +}; + +#endif /* CONFIG_LC3_DEMUXER */ + +#if CONFIG_LC3_MUXER + +static int lc3_write_header(AVFormatContext *s) +{ + AVStream *st = s->streams[0]; + int channels = st->codecpar->ch_layout.nb_channels; + int srate_hz = st->codecpar->sample_rate; + int bit_rate = st->codecpar->bit_rate; + int frame_us, ep_mode, hr_mode; + uint32_t nb_samples = av_rescale_q( + st->duration, st->time_base, (AVRational){ 1, srate_hz }); + + if (st->codecpar->extradata_size < 6) + return AVERROR_INVALIDDATA; + + frame_us = AV_RL16(st->codecpar->extradata + 0) * 10; + ep_mode = AV_RL16(st->codecpar->extradata + 2) != 0; + hr_mode = AV_RL16(st->codecpar->extradata + 4) != 0; + + if (check_frame_length(s, srate_hz, frame_us) < 0) + return AVERROR_INVALIDDATA; + + avio_wb16(s->pb, 0x1ccc); + avio_wl16(s->pb, (9 + hr_mode) * sizeof(uint16_t)); + avio_wl16(s->pb, srate_hz / 100); + avio_wl16(s->pb, bit_rate / 100); + avio_wl16(s->pb, channels); + avio_wl16(s->pb, frame_us / 10); + avio_wl16(s->pb, ep_mode); + avio_wl32(s->pb, nb_samples); + if (hr_mode) + avio_wl16(s->pb, hr_mode); + + return 0; +} + +static int lc3_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + avio_wl16(s->pb, pkt->size); + avio_write(s->pb, pkt->data, pkt->size); + return 0; +} + +const FFOutputFormat ff_lc3_muxer = { + .p.name = "lc3", + .p.long_name = NULL_IF_CONFIG_SMALL("LC3 (Low Complexity Communication Codec)"), + .p.extensions = "lc3", + .p.audio_codec = AV_CODEC_ID_LC3, + .p.video_codec = AV_CODEC_ID_NONE, + .p.subtitle_codec = AV_CODEC_ID_NONE, + .p.flags = AVFMT_NOTIMESTAMPS, + .flags_internal = FF_OFMT_FLAG_MAX_ONE_OF_EACH | + FF_OFMT_FLAG_ONLY_DEFAULT_CODECS, + .write_header = lc3_write_header, + .write_packet = lc3_write_packet, +}; + +#endif /* CONFIG_LC3_MUXER */ diff --git a/libavformat/libamqp.c b/libavformat/libamqp.c index 27851e1b2..3cc6bc0e9 100644 --- a/libavformat/libamqp.c +++ b/libavformat/libamqp.c @@ -23,9 +23,8 @@ #include #include #include "avformat.h" -#include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/time.h" #include "network.h" #include "url.h" #include "urldecode.h" diff --git a/libavformat/libgme.c b/libavformat/libgme.c index 26d079c27..fbcdc2804 100644 --- a/libavformat/libgme.c +++ b/libavformat/libgme.c @@ -22,8 +22,7 @@ */ #include -#include "libavutil/avstring.h" -#include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/libmodplug.c b/libavformat/libmodplug.c index 8c6569f77..680a5fe9b 100644 --- a/libavformat/libmodplug.c +++ b/libavformat/libmodplug.c @@ -26,6 +26,7 @@ #include #include "libavutil/avstring.h" #include "libavutil/eval.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/libopenmpt.c b/libavformat/libopenmpt.c index c270a60cb..736af7caf 100644 --- a/libavformat/libopenmpt.c +++ b/libavformat/libopenmpt.c @@ -30,8 +30,8 @@ #define OPENMPT_API_VERSION_AT_LEAST(major, minor, patch) (OPENMPT_API_VERSION >= OPENMPT_API_VERSION_MAKE((major), (minor), (patch))) #endif -#include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/libsmbclient.c b/libavformat/libsmbclient.c index f81fff2df..28de2daa9 100644 --- a/libavformat/libsmbclient.c +++ b/libavformat/libsmbclient.c @@ -20,6 +20,7 @@ #include #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "url.h" diff --git a/libavformat/libsrt.c b/libavformat/libsrt.c index a7aafea53..9e860abcc 100644 --- a/libavformat/libsrt.c +++ b/libavformat/libsrt.c @@ -23,6 +23,7 @@ #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/time.h" diff --git a/libavformat/libssh.c b/libavformat/libssh.c index 127faaabd..523b79bef 100644 --- a/libavformat/libssh.c +++ b/libavformat/libssh.c @@ -22,6 +22,7 @@ #define LIBSSH_STATIC #include #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/attributes.h" #include "libavformat/avio.h" @@ -189,13 +190,13 @@ static av_cold int libssh_close(URLContext *h) static av_cold int libssh_connect(URLContext *h, const char *url, char *path, size_t path_size) { LIBSSHContext *libssh = h->priv_data; - char proto[10], hostname[1024], credencials[1024]; + char proto[10], hostname[1024], credentials[1024]; int port = 22, ret; const char *user = NULL, *pass = NULL; char *end = NULL; av_url_split(proto, sizeof(proto), - credencials, sizeof(credencials), + credentials, sizeof(credentials), hostname, sizeof(hostname), &port, path, path_size, @@ -211,7 +212,7 @@ static av_cold int libssh_connect(URLContext *h, const char *url, char *path, si if ((ret = libssh_create_ssh_session(libssh, hostname, port)) < 0) return ret; - user = av_strtok(credencials, ":", &end); + user = av_strtok(credentials, ":", &end); pass = av_strtok(end, ":", &end); if ((ret = libssh_authentication(libssh, user, pass)) < 0) diff --git a/libavformat/libzmq.c b/libavformat/libzmq.c index f4bb849e4..da84efee7 100644 --- a/libavformat/libzmq.c +++ b/libavformat/libzmq.c @@ -94,7 +94,7 @@ static int zmq_proto_open(URLContext *h, const char *uri, int flags) return AVERROR_EXTERNAL; } - if (av_strstart(uri, "zmq:", &uri)) { + if (!av_strstart(uri, "zmq:", &uri)) { av_log(h, AV_LOG_ERROR, "URL %s lacks prefix\n", uri); return AVERROR(EINVAL); } diff --git a/libavformat/lmlm4.c b/libavformat/lmlm4.c index 209b544cc..cec2f7ca0 100644 --- a/libavformat/lmlm4.c +++ b/libavformat/lmlm4.c @@ -91,19 +91,19 @@ static int lmlm4_read_packet(AVFormatContext *s, AVPacket *pkt) frame_type = avio_rb16(pb); packet_size = avio_rb32(pb); padding = -packet_size & 511; - frame_size = packet_size - 8; if (frame_type > LMLM4_MPEG1L2 || frame_type == LMLM4_INVALID) { av_log(s, AV_LOG_ERROR, "invalid or unsupported frame_type\n"); - return AVERROR(EIO); + return AVERROR_INVALIDDATA; } if (packet_size > LMLM4_MAX_PACKET_SIZE || packet_size<=8) { av_log(s, AV_LOG_ERROR, "packet size %d is invalid\n", packet_size); - return AVERROR(EIO); + return AVERROR_INVALIDDATA; } + frame_size = packet_size - 8; if ((ret = av_get_packet(pb, pkt, frame_size)) <= 0) - return AVERROR(EIO); + return ret < 0 ? ret : AVERROR(EIO); avio_skip(pb, padding); diff --git a/libavformat/lrc.c b/libavformat/lrc.c index 139c6506e..6c78a91d6 100644 --- a/libavformat/lrc.c +++ b/libavformat/lrc.c @@ -1,5 +1,5 @@ /* - * LRC lyrics file format decoder + * LRC lyrics file format common structs * Copyright (c) 2014 StarBrilliant * * This file is part of FFmpeg. diff --git a/libavformat/lrcdec.c b/libavformat/lrcdec.c index 5435a65b1..68c44bce9 100644 --- a/libavformat/lrcdec.c +++ b/libavformat/lrcdec.c @@ -1,5 +1,5 @@ /* - * LRC lyrics file format decoder + * LRC lyrics file format demuxer * Copyright (c) 2014 StarBrilliant * * This file is part of FFmpeg. diff --git a/libavformat/lrcenc.c b/libavformat/lrcenc.c index 15c31d33b..7570529c2 100644 --- a/libavformat/lrcenc.c +++ b/libavformat/lrcenc.c @@ -1,5 +1,5 @@ /* - * LRC lyrics file format decoder + * LRC lyrics file format muxer * Copyright (c) 2014 StarBrilliant * * This file is part of FFmpeg. diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index ae3565b0c..efa3e44c8 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -46,6 +46,7 @@ #include "libavutil/lzo.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/time_internal.h" @@ -212,7 +213,13 @@ typedef struct MatroskaTrackVideo { uint64_t display_height; uint64_t pixel_width; uint64_t pixel_height; + uint64_t cropped_width; + uint64_t cropped_height; EbmlBin color_space; + uint64_t pixel_cropt; + uint64_t pixel_cropl; + uint64_t pixel_cropb; + uint64_t pixel_cropr; uint64_t display_unit; uint64_t interlaced; uint64_t field_order; @@ -526,10 +533,10 @@ static EbmlSyntax matroska_track_video[] = { { MATROSKA_ID_VIDEOALPHAMODE, EBML_UINT, 0, 0, offsetof(MatroskaTrackVideo, alpha_mode), { .u = 0 } }, { MATROSKA_ID_VIDEOCOLOR, EBML_NEST, 0, sizeof(MatroskaTrackVideoColor), offsetof(MatroskaTrackVideo, color), { .n = matroska_track_video_color } }, { MATROSKA_ID_VIDEOPROJECTION, EBML_NEST, 0, 0, offsetof(MatroskaTrackVideo, projection), { .n = matroska_track_video_projection } }, - { MATROSKA_ID_VIDEOPIXELCROPB, EBML_NONE }, - { MATROSKA_ID_VIDEOPIXELCROPT, EBML_NONE }, - { MATROSKA_ID_VIDEOPIXELCROPL, EBML_NONE }, - { MATROSKA_ID_VIDEOPIXELCROPR, EBML_NONE }, + { MATROSKA_ID_VIDEOPIXELCROPB, EBML_UINT, 0, 0, offsetof(MatroskaTrackVideo, pixel_cropb), {.u = 0 } }, + { MATROSKA_ID_VIDEOPIXELCROPT, EBML_UINT, 0, 0, offsetof(MatroskaTrackVideo, pixel_cropt), {.u = 0 } }, + { MATROSKA_ID_VIDEOPIXELCROPL, EBML_UINT, 0, 0, offsetof(MatroskaTrackVideo, pixel_cropl), {.u = 0 } }, + { MATROSKA_ID_VIDEOPIXELCROPR, EBML_UINT, 0, 0, offsetof(MatroskaTrackVideo, pixel_cropr), {.u = 0 } }, { MATROSKA_ID_VIDEODISPLAYUNIT, EBML_UINT, 0, 0, offsetof(MatroskaTrackVideo, display_unit), { .u= MATROSKA_VIDEO_DISPLAYUNIT_PIXELS } }, { MATROSKA_ID_VIDEOFLAGINTERLACED, EBML_UINT, 0, 0, offsetof(MatroskaTrackVideo, interlaced), { .u = MATROSKA_VIDEO_INTERLACE_FLAG_UNDETERMINED } }, { MATROSKA_ID_VIDEOFIELDORDER, EBML_UINT, 0, 0, offsetof(MatroskaTrackVideo, field_order), { .u = MATROSKA_VIDEO_FIELDORDER_UNDETERMINED } }, @@ -1314,6 +1321,8 @@ static int ebml_parse(MatroskaDemuxContext *matroska, matroska->num_levels--; return LEVEL_ENDED; } + // We have not encountered a known element; syntax is a sentinel. + av_assert1(syntax->type == EBML_NONE); }; } @@ -2250,8 +2259,9 @@ static int mkv_stereo3d_conv(AVStream *st, MatroskaVideoStereoModeType stereo_mo STEREOMODE_STEREO3D_MAPPING(STEREO_MODE_CONV, NOTHING) }; AVStereo3D *stereo; + size_t size; - stereo = av_stereo3d_alloc(); + stereo = av_stereo3d_alloc_size(&size); if (!stereo) return AVERROR(ENOMEM); @@ -2259,7 +2269,7 @@ static int mkv_stereo3d_conv(AVStream *st, MatroskaVideoStereoModeType stereo_mo stereo->flags = stereo_mode_conv[stereo_mode].flags; if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data, - AV_PKT_DATA_STEREO3D, stereo, sizeof(*stereo), 0)) { + AV_PKT_DATA_STEREO3D, stereo, size, 0)) { av_freep(&stereo); return AVERROR(ENOMEM); } @@ -2321,15 +2331,15 @@ static int mkv_parse_video_color(AVStream *st, const MatroskaTrack *track) { } if (has_mastering_primaries || has_mastering_luminance) { - AVMasteringDisplayMetadata *metadata; - AVPacketSideData *sd = av_packet_side_data_new(&st->codecpar->coded_side_data, - &st->codecpar->nb_coded_side_data, - AV_PKT_DATA_MASTERING_DISPLAY_METADATA, - sizeof(AVMasteringDisplayMetadata), 0); - if (!sd) + size_t size = 0; + AVMasteringDisplayMetadata *metadata = av_mastering_display_metadata_alloc_size(&size); + if (!metadata) return AVERROR(ENOMEM); - metadata = (AVMasteringDisplayMetadata*)sd->data; - memset(metadata, 0, sizeof(AVMasteringDisplayMetadata)); + if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data, + AV_PKT_DATA_MASTERING_DISPLAY_METADATA, metadata, size, 0)) { + av_freep(&metadata); + return AVERROR(ENOMEM); + } if (has_mastering_primaries) { metadata->display_primaries[0][0] = av_d2q(mastering_meta->r_x, INT_MAX); metadata->display_primaries[0][1] = av_d2q(mastering_meta->r_y, INT_MAX); @@ -2961,15 +2971,32 @@ static int mkv_parse_video(MatroskaTrack *track, AVStream *st, &display_width_mul, &display_height_mul); if (track->video.display_unit < MATROSKA_VIDEO_DISPLAYUNIT_UNKNOWN) { - if (track->video.display_width && track->video.display_height && - par->height < INT64_MAX / track->video.display_width / display_width_mul && - par->width < INT64_MAX / track->video.display_height / display_height_mul) + if (track->video.display_width && track->video.display_height && + track->video.display_width != -1 && track->video.display_height != -1 && + track->video.cropped_height < INT64_MAX / track->video.display_width / display_width_mul && + track->video.cropped_width < INT64_MAX / track->video.display_height / display_height_mul) av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, - par->height * track->video.display_width * display_width_mul, - par->width * track->video.display_height * display_height_mul, + track->video.cropped_height * track->video.display_width * display_width_mul, + track->video.cropped_width * track->video.display_height * display_height_mul, INT_MAX); } + if (track->video.cropped_width != track->video.pixel_width || + track->video.cropped_height != track->video.pixel_height) { + uint8_t *cropping; + AVPacketSideData *sd = av_packet_side_data_new(&st->codecpar->coded_side_data, + &st->codecpar->nb_coded_side_data, + AV_PKT_DATA_FRAME_CROPPING, + sizeof(uint32_t) * 4, 0); + if (!sd) + return AVERROR(ENOMEM); + + cropping = sd->data; + bytestream_put_le32(&cropping, track->video.pixel_cropt); + bytestream_put_le32(&cropping, track->video.pixel_cropb); + bytestream_put_le32(&cropping, track->video.pixel_cropl); + bytestream_put_le32(&cropping, track->video.pixel_cropr); + } if (par->codec_id != AV_CODEC_ID_HEVC) sti->need_parsing = AVSTREAM_PARSE_HEADERS; @@ -3135,10 +3162,21 @@ static int matroska_parse_tracks(AVFormatContext *s) track->default_duration = default_duration; } } - if (track->video.display_width == -1) - track->video.display_width = track->video.pixel_width; - if (track->video.display_height == -1) - track->video.display_height = track->video.pixel_height; + if (track->video.pixel_cropl >= INT_MAX - track->video.pixel_cropr || + track->video.pixel_cropt >= INT_MAX - track->video.pixel_cropb || + (track->video.pixel_cropl + track->video.pixel_cropr) >= track->video.pixel_width || + (track->video.pixel_cropt + track->video.pixel_cropb) >= track->video.pixel_height) + return AVERROR_INVALIDDATA; + track->video.cropped_width = track->video.pixel_width - + track->video.pixel_cropl - track->video.pixel_cropr; + track->video.cropped_height = track->video.pixel_height - + track->video.pixel_cropt - track->video.pixel_cropb; + if (track->video.display_unit == MATROSKA_VIDEO_DISPLAYUNIT_PIXELS) { + if (track->video.display_width == -1) + track->video.display_width = track->video.cropped_width; + if (track->video.display_height == -1) + track->video.display_height = track->video.cropped_height; + } } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { if (!track->audio.out_samplerate) track->audio.out_samplerate = track->audio.samplerate; @@ -4021,9 +4059,9 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, (AVRational){1, 1000000000}, (AVRational){1, st->codecpar->sample_rate}); if (discard_padding > 0) { - AV_WL32(side_data + 4, discard_padding); + AV_WL32A(side_data + 4, discard_padding); } else { - AV_WL32(side_data, -discard_padding); + AV_WL32A(side_data, -discard_padding); } } @@ -4186,7 +4224,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf } else { res = matroska_parse_frame(matroska, track, st, buf, out_data, out_size, timecode, lace_duration, - pos, !n ? is_keyframe : 0, + pos, is_keyframe, blockmore, nb_blockmore, discard_padding); if (res) @@ -4580,9 +4618,10 @@ static int64_t webm_dash_manifest_compute_bandwidth(AVFormatContext *s, int64_t // The prebuffer ends in the last Cue. Estimate how much data was // prebuffered. pre_bytes = desc_end.end_offset - desc_end.start_offset; - pre_ns = desc_end.end_time_ns - desc_end.start_time_ns; - if (pre_ns <= 0) + if (desc_end.end_time_ns <= desc_end.start_time_ns || + desc_end.end_time_ns - (uint64_t)desc_end.start_time_ns > INT64_MAX) return -1; + pre_ns = desc_end.end_time_ns - desc_end.start_time_ns; pre_sec = pre_ns / nano_seconds_per_second; prebuffer_bytes += pre_bytes * ((temp_prebuffer_ns / nano_seconds_per_second) / pre_sec); @@ -4595,7 +4634,7 @@ static int64_t webm_dash_manifest_compute_bandwidth(AVFormatContext *s, int64_t int64_t desc_bytes = desc_end.end_offset - desc_beg.start_offset; int64_t desc_ns = desc_end.end_time_ns - desc_beg.start_time_ns; double desc_sec, calc_bits_per_second, percent, mod_bits_per_second; - if (desc_bytes <= 0) + if (desc_bytes <= 0 || desc_bytes > INT64_MAX/8) return -1; desc_sec = desc_ns / nano_seconds_per_second; diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 0de4ec1dc..60c896e96 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -33,6 +33,7 @@ #include "flacenc.h" #include "internal.h" #include "isom.h" +#include "nal.h" #include "matroska.h" #include "mux.h" #include "riff.h" @@ -50,6 +51,7 @@ #include "libavutil/lfg.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" @@ -1249,7 +1251,9 @@ static int mkv_assemble_codecprivate(AVFormatContext *s, AVIOContext *dyn_cp, par->codec_tag = tag; /* Same comment as for ff_put_bmp_header applies here. */ - ff_put_wav_header(s, dyn_cp, par, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX); + ret = ff_put_wav_header(s, dyn_cp, par, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX); + if (ret < 0) + return ret; #endif } @@ -1365,7 +1369,7 @@ static void mkv_write_video_color(EbmlWriter *writer, const AVStream *st, (ypos >> 7) + 1); } - side_data = av_packet_side_data_get(st->codecpar->coded_side_data, st->codecpar->nb_coded_side_data, + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data, AV_PKT_DATA_CONTENT_LIGHT_LEVEL); if (side_data) { const AVContentLightMetadata *metadata = (AVContentLightMetadata *)side_data->data; @@ -1375,7 +1379,7 @@ static void mkv_write_video_color(EbmlWriter *writer, const AVStream *st, metadata->MaxFALL); } - side_data = av_packet_side_data_get(st->codecpar->coded_side_data, st->codecpar->nb_coded_side_data, + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data, AV_PKT_DATA_MASTERING_DISPLAY_METADATA); if (side_data) { const AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)side_data->data; @@ -1411,12 +1415,12 @@ static void mkv_write_video_color(EbmlWriter *writer, const AVStream *st, } #define MAX_VIDEO_PROJECTION_ELEMS 6 -static void mkv_handle_rotation(void *logctx, const AVStream *st, +static void mkv_handle_rotation(void *logctx, const AVCodecParameters *par, double *yaw, double *roll) { const int32_t *matrix; const AVPacketSideData *side_data = - av_packet_side_data_get(st->codecpar->coded_side_data, st->codecpar->nb_coded_side_data, + av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data, AV_PKT_DATA_DISPLAYMATRIX); if (!side_data) @@ -1467,11 +1471,11 @@ ignore: } static int mkv_handle_spherical(void *logctx, EbmlWriter *writer, - const AVStream *st, uint8_t private[], + const AVCodecParameters *par, uint8_t private[], double *yaw, double *pitch, double *roll) { - const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data, - st->codecpar->nb_coded_side_data, + const AVPacketSideData *sd = av_packet_side_data_get(par->coded_side_data, + par->nb_coded_side_data, AV_PKT_DATA_SPHERICAL); const AVSphericalMapping *spherical; @@ -1527,16 +1531,17 @@ static int mkv_handle_spherical(void *logctx, EbmlWriter *writer, } static void mkv_write_video_projection(void *logctx, EbmlWriter *wr, - const AVStream *st, uint8_t private[]) + const AVCodecParameters *par, + uint8_t private[]) { double yaw = 0, pitch = 0, roll = 0; int ret; ebml_writer_open_master(wr, MATROSKA_ID_VIDEOPROJECTION); - ret = mkv_handle_spherical(logctx, wr, st, private, &yaw, &pitch, &roll); + ret = mkv_handle_spherical(logctx, wr, par, private, &yaw, &pitch, &roll); if (!ret) - mkv_handle_rotation(logctx, st, &yaw, &roll); + mkv_handle_rotation(logctx, par, &yaw, &roll); if (yaw) ebml_writer_add_float(wr, MATROSKA_ID_VIDEOPROJECTIONPOSEYAW, yaw); @@ -1590,6 +1595,7 @@ static void mkv_write_field_order(EbmlWriter *writer, int is_webm, #define MAX_STEREO_MODE_ELEMS 1 static int mkv_write_stereo_mode(AVFormatContext *s, EbmlWriter *writer, + const AVCodecParameters *par, const AVStream *st, int is_webm, int *h_width, int *h_height) { @@ -1650,7 +1656,7 @@ static int mkv_write_stereo_mode(AVFormatContext *s, EbmlWriter *writer, }; int fmt; - sd = av_packet_side_data_get(st->codecpar->coded_side_data, st->codecpar->nb_coded_side_data, + sd = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data, AV_PKT_DATA_STEREO3D); if (!sd) return 0; @@ -1711,7 +1717,7 @@ static void mkv_write_blockadditionmapping(AVFormatContext *s, const MatroskaMux } } - sd = av_packet_side_data_get(st->codecpar->coded_side_data, st->codecpar->nb_coded_side_data, + sd = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data, AV_PKT_DATA_DOVI_CONF); if (!sd) @@ -1752,8 +1758,10 @@ static int mkv_write_track_video(AVFormatContext *s, MatroskaMuxContext *mkv, const AVDictionaryEntry *tag; int display_width_div = 1, display_height_div = 1; uint8_t color_space[4], projection_private[20]; + const AVPacketSideData *sd; EBML_WRITER(MAX_FIELD_ORDER_ELEMS + MAX_STEREO_MODE_ELEMS + - MAX_VIDEO_COLOR_ELEMS + MAX_VIDEO_PROJECTION_ELEMS + 8); + MAX_VIDEO_COLOR_ELEMS + MAX_VIDEO_PROJECTION_ELEMS + 12); + int cropped_width = par->width, cropped_height = par->height; int ret; ebml_writer_open_master(&writer, MATROSKA_ID_TRACKVIDEO); @@ -1765,7 +1773,7 @@ static int mkv_write_track_video(AVFormatContext *s, MatroskaMuxContext *mkv, // check both side data and metadata for stereo information, // write the result to the bitstream if any is found - ret = mkv_write_stereo_mode(s, &writer, st, IS_WEBM(mkv), + ret = mkv_write_stereo_mode(s, &writer, par, st, IS_WEBM(mkv), &display_width_div, &display_height_div); if (ret < 0) @@ -1776,25 +1784,55 @@ static int mkv_write_track_video(AVFormatContext *s, MatroskaMuxContext *mkv, (tag = av_dict_get( s->metadata, "alpha_mode", NULL, 0))) && strtol(tag->value, NULL, 0)) ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEOALPHAMODE, 1); + sd = av_packet_side_data_get(par->coded_side_data, + par->nb_coded_side_data, + AV_PKT_DATA_FRAME_CROPPING); + if (sd && sd->size == sizeof(uint32_t) * 4) { + uint64_t top, bottom, left, right; + + top = AV_RL32(sd->data + 0); + bottom = AV_RL32(sd->data + 4); + left = AV_RL32(sd->data + 8); + right = AV_RL32(sd->data + 12); + + if ((left + right) >= par->width || + (top + bottom) >= par->height) { + av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n"); + return AVERROR(EINVAL); + } + + if (bottom) + ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEOPIXELCROPB, bottom); + if (top) + ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEOPIXELCROPT, top); + if (left) + ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEOPIXELCROPL, left); + if (right) + ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEOPIXELCROPR, right); + + cropped_width -= left + right; + cropped_height -= top + bottom; + } + // write DisplayWidth and DisplayHeight, they contain the size of // a single source view and/or the display aspect ratio if (st->sample_aspect_ratio.num) { - int64_t d_width = av_rescale(par->width, st->sample_aspect_ratio.num, st->sample_aspect_ratio.den); + int64_t d_width = av_rescale(cropped_width, st->sample_aspect_ratio.num, st->sample_aspect_ratio.den); if (d_width > INT_MAX) { av_log(s, AV_LOG_ERROR, "Overflow in display width\n"); return AVERROR(EINVAL); } - if (d_width != par->width || display_width_div != 1 || display_height_div != 1) { + if (d_width != cropped_width || display_width_div != 1 || display_height_div != 1) { if (IS_WEBM(mkv) || display_width_div != 1 || display_height_div != 1) { ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEODISPLAYWIDTH, d_width / display_width_div); ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEODISPLAYHEIGHT, - par->height / display_height_div); + cropped_height / display_height_div); } else { AVRational display_aspect_ratio; av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den, - par->width * (int64_t)st->sample_aspect_ratio.num, - par->height * (int64_t)st->sample_aspect_ratio.den, + cropped_width * (int64_t)st->sample_aspect_ratio.num, + cropped_height * (int64_t)st->sample_aspect_ratio.den, 1024 * 1024); ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEODISPLAYWIDTH, display_aspect_ratio.num); @@ -1806,9 +1844,9 @@ static int mkv_write_track_video(AVFormatContext *s, MatroskaMuxContext *mkv, } } else if (display_width_div != 1 || display_height_div != 1) { ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEODISPLAYWIDTH, - par->width / display_width_div); + cropped_width / display_width_div); ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEODISPLAYHEIGHT, - par->height / display_height_div); + cropped_height / display_height_div); } else if (!IS_WEBM(mkv)) ebml_writer_add_uint(&writer, MATROSKA_ID_VIDEODISPLAYUNIT, MATROSKA_VIDEO_DISPLAYUNIT_UNKNOWN); @@ -1819,7 +1857,7 @@ static int mkv_write_track_video(AVFormatContext *s, MatroskaMuxContext *mkv, color_space, sizeof(color_space)); } mkv_write_video_color(&writer, st, par); - mkv_write_video_projection(s, &writer, st, projection_private); + mkv_write_video_projection(s, &writer, par, projection_private); return ebml_writer_write(&writer, pb); } @@ -3499,20 +3537,20 @@ static const AVCodecTag additional_subtitle_tags[] = { #define OFFSET(x) offsetof(MatroskaMuxContext, x) #define FLAGS AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "reserve_index_space", "Reserve a given amount of space (in bytes) at the beginning of the file for the index (cues).", OFFSET(reserve_cues_space), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, - { "cues_to_front", "Move Cues (the index) to the front by shifting data if necessary", OFFSET(move_cues_to_front), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS }, - { "cluster_size_limit", "Store at most the provided amount of bytes in a cluster. ", OFFSET(cluster_size_limit), AV_OPT_TYPE_INT , { .i64 = -1 }, -1, INT_MAX, FLAGS }, - { "cluster_time_limit", "Store at most the provided number of milliseconds in a cluster.", OFFSET(cluster_time_limit), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, - { "dash", "Create a WebM file conforming to WebM DASH specification", OFFSET(is_dash), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, - { "dash_track_number", "Track number for the DASH stream", OFFSET(dash_track_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS }, - { "live", "Write files assuming it is a live stream.", OFFSET(is_live), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, - { "allow_raw_vfw", "allow RAW VFW mode", OFFSET(allow_raw_vfw), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, - { "flipped_raw_rgb", "Raw RGB bitmaps in VFW mode are stored bottom-up", OFFSET(flipped_raw_rgb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { "reserve_index_space", "reserve a given amount of space (in bytes) at the beginning of the file for the index (cues)", OFFSET(reserve_cues_space), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, + { "cues_to_front", "move Cues (the index) to the front by shifting data if necessary", OFFSET(move_cues_to_front), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS }, + { "cluster_size_limit", "store at most the provided amount of bytes in a cluster", OFFSET(cluster_size_limit), AV_OPT_TYPE_INT , { .i64 = -1 }, -1, INT_MAX, FLAGS }, + { "cluster_time_limit", "store at most the provided number of milliseconds in a cluster", OFFSET(cluster_time_limit), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, + { "dash", "create a WebM file conforming to WebM DASH specification", OFFSET(is_dash), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { "dash_track_number", "track number for the DASH stream", OFFSET(dash_track_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS }, + { "live", "write files assuming it is a live stream", OFFSET(is_live), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { "allow_raw_vfw", "allow raw VFW mode", OFFSET(allow_raw_vfw), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { "flipped_raw_rgb", "store raw RGB bitmaps in VFW mode in bottom-up mode", OFFSET(flipped_raw_rgb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, { "write_crc32", "write a CRC32 element inside every Level 1 element", OFFSET(write_crc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, - { "default_mode", "Controls how a track's FlagDefault is inferred", OFFSET(default_mode), AV_OPT_TYPE_INT, { .i64 = DEFAULT_MODE_PASSTHROUGH }, DEFAULT_MODE_INFER, DEFAULT_MODE_PASSTHROUGH, FLAGS, .unit = "default_mode" }, - { "infer", "For each track type, mark each track of disposition default as default; if none exists, mark the first track as default.", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_INFER }, 0, 0, FLAGS, .unit = "default_mode" }, - { "infer_no_subs", "For each track type, mark each track of disposition default as default; for audio and video: if none exists, mark the first track as default.", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_INFER_NO_SUBS }, 0, 0, FLAGS, .unit = "default_mode" }, - { "passthrough", "Use the disposition flag as-is", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_PASSTHROUGH }, 0, 0, FLAGS, .unit = "default_mode" }, + { "default_mode", "control how a track's FlagDefault is inferred", OFFSET(default_mode), AV_OPT_TYPE_INT, { .i64 = DEFAULT_MODE_PASSTHROUGH }, DEFAULT_MODE_INFER, DEFAULT_MODE_PASSTHROUGH, FLAGS, .unit = "default_mode" }, + { "infer", "for each track type, mark each track of disposition default as default; if none exists, mark the first track as default", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_INFER }, 0, 0, FLAGS, .unit = "default_mode" }, + { "infer_no_subs", "for each track type, mark each track of disposition default as default; for audio and video: if none exists, mark the first track as default", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_INFER_NO_SUBS }, 0, 0, FLAGS, .unit = "default_mode" }, + { "passthrough", "use the disposition flag as-is", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_PASSTHROUGH }, 0, 0, FLAGS, .unit = "default_mode" }, { NULL }, }; diff --git a/libavformat/mccdec.c b/libavformat/mccdec.c index 85bf93cd3..8c0ea09b6 100644 --- a/libavformat/mccdec.c +++ b/libavformat/mccdec.c @@ -93,7 +93,7 @@ static int mcc_read_header(AVFormatContext *s) { MCCContext *mcc = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); - AVRational rate; + AVRational rate = {0}; int64_t ts, pos; uint8_t out[4096]; char line[4096]; @@ -139,7 +139,7 @@ static int mcc_read_header(AVFormatContext *s) continue; } - if (av_sscanf(line, "%d:%d:%d:%d", &hh, &mm, &ss, &fs) != 4) + if (av_sscanf(line, "%d:%d:%d:%d", &hh, &mm, &ss, &fs) != 4 || rate.den <= 0) continue; ts = av_sat_add64(av_rescale(hh * 3600LL + mm * 60LL + ss, rate.num, rate.den), fs); diff --git a/libavformat/mlvdec.c b/libavformat/mlvdec.c index e3165e381..20a6f3629 100644 --- a/libavformat/mlvdec.c +++ b/libavformat/mlvdec.c @@ -28,6 +28,7 @@ #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/rational.h" #include "avformat.h" #include "demux.h" @@ -81,13 +82,15 @@ static int check_file_header(AVIOContext *pb, uint64_t guid) static void read_string(AVFormatContext *avctx, AVIOContext *pb, const char *tag, unsigned size) { char * value = av_malloc(size + 1); + int ret; + if (!value) { avio_skip(pb, size); return; } - avio_read(pb, value, size); - if (!value[0]) { + ret = avio_read(pb, value, size); + if (ret != size || !value[0]) { av_free(value); return; } @@ -434,19 +437,25 @@ static int read_packet(AVFormatContext *avctx, AVPacket *pkt) if (size < 16) return AVERROR_INVALIDDATA; avio_skip(pb, 12); //timestamp, frameNumber - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + size -= 12; + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (size < 8) + return AVERROR_INVALIDDATA; avio_skip(pb, 8); // cropPosX, cropPosY, panPosX, panPosY + size -= 8; + } space = avio_rl32(pb); + if (size < space + 4LL) + return AVERROR_INVALIDDATA; avio_skip(pb, space); + size -= space; if ((mlv->class[st->id] & (MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA))) { ret = AVERROR_PATCHWELCOME; } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { ret = av_get_packet(pb, pkt, (st->codecpar->width * st->codecpar->height * st->codecpar->bits_per_coded_sample + 7) >> 3); } else { // AVMEDIA_TYPE_AUDIO - if (space > UINT_MAX - 24 || size < (24 + space)) - return AVERROR_INVALIDDATA; - ret = av_get_packet(pb, pkt, size - (24 + space)); + ret = av_get_packet(pb, pkt, size - 4); } if (ret < 0) diff --git a/libavformat/mms.c b/libavformat/mms.c index 16babc095..95414a2fb 100644 --- a/libavformat/mms.c +++ b/libavformat/mms.c @@ -23,6 +23,7 @@ #include "mms.h" #include "asf.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #define MMS_MAX_STREAMS 256 /**< arbitrary sanity check value */ diff --git a/libavformat/mmsh.c b/libavformat/mmsh.c index 60113d61d..aeadb12da 100644 --- a/libavformat/mmsh.c +++ b/libavformat/mmsh.c @@ -28,8 +28,9 @@ #include #include "libavutil/intreadwrite.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "internal.h" +#include "avformat.h" #include "mms.h" #include "http.h" #include "url.h" diff --git a/libavformat/mmst.c b/libavformat/mmst.c index d7f71304e..e68606086 100644 --- a/libavformat/mmst.c +++ b/libavformat/mmst.c @@ -30,9 +30,9 @@ #include "avformat.h" #include "mms.h" -#include "internal.h" #include "avio_internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/bytestream.h" #include "network.h" #include "url.h" diff --git a/libavformat/mov.c b/libavformat/mov.c index 0f7b910a7..41ca280c8 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -40,6 +40,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/aes.h" #include "libavutil/aes_ctr.h" @@ -51,7 +52,7 @@ #include "libavutil/uuid.h" #include "libavcodec/ac3tab.h" #include "libavcodec/flac.h" -#include "libavcodec/hevc.h" +#include "libavcodec/hevc/hevc.h" #include "libavcodec/mpegaudiodecheader.h" #include "libavcodec/mlp_parse.h" #include "avformat.h" @@ -187,26 +188,42 @@ static int mov_read_mac_string(MOVContext *c, AVIOContext *pb, int len, return p - dst; } +/** + * Get the current item in the parsing process. + */ +static HEIFItem *heif_cur_item(MOVContext *c) +{ + HEIFItem *item = NULL; + + for (int i = 0; i < c->nb_heif_item; i++) { + if (!c->heif_item[i] || c->heif_item[i]->item_id != c->cur_item_id) + continue; + + item = c->heif_item[i]; + break; + } + + return item; +} + +/** + * Get the current stream in the parsing process. This can either be the + * latest stream added to the context, or the stream referenced by an item. + */ static AVStream *get_curr_st(MOVContext *c) { AVStream *st = NULL; + HEIFItem *item; if (c->fc->nb_streams < 1) return NULL; - for (int i = 0; i < c->nb_heif_item; i++) { - HEIFItem *item = &c->heif_item[i]; - - if (!item->st) - continue; - if (item->st->id != c->cur_item_id) - continue; + if (c->cur_item_id == -1) + return c->fc->streams[c->fc->nb_streams-1]; + item = heif_cur_item(c); + if (item) st = item->st; - break; - } - if (!st) - st = c->fc->streams[c->fc->nb_streams-1]; return st; } @@ -864,6 +881,7 @@ static int mov_read_dac3(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +#if CONFIG_IAMFDEC static int mov_read_iacb(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -1048,6 +1066,7 @@ fail: return ret; } +#endif static int mov_read_dec3(MOVContext *c, AVIOContext *pb, MOVAtom atom) { @@ -1211,20 +1230,100 @@ static int mov_read_wfex(MOVContext *c, AVIOContext *pb, MOVAtom atom) return ret; } +static int mov_read_clap(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + AVPacketSideData *sd; + AVRational aperture_width, aperture_height, horiz_off, vert_off; + AVRational pc_x, pc_y; + uint64_t top, bottom, left, right; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + + aperture_width.num = avio_rb32(pb); + aperture_width.den = avio_rb32(pb); + aperture_height.num = avio_rb32(pb); + aperture_height.den = avio_rb32(pb); + + horiz_off.num = avio_rb32(pb); + horiz_off.den = avio_rb32(pb); + vert_off.num = avio_rb32(pb); + vert_off.den = avio_rb32(pb); + + if (aperture_width.num < 0 || aperture_width.den < 0 || + aperture_height.num < 0 || aperture_height.den < 0 || + horiz_off.den < 0 || vert_off.den < 0) + return AVERROR_INVALIDDATA; + + av_log(c->fc, AV_LOG_TRACE, "clap: apertureWidth %d/%d, apertureHeight %d/%d " + "horizOff %d/%d vertOff %d/%d\n", + aperture_width.num, aperture_width.den, aperture_height.num, aperture_height.den, + horiz_off.num, horiz_off.den, vert_off.num, vert_off.den); + + pc_x = av_mul_q((AVRational) { st->codecpar->width - 1, 1 }, (AVRational) { 1, 2 }); + pc_x = av_add_q(pc_x, horiz_off); + pc_y = av_mul_q((AVRational) { st->codecpar->height - 1, 1 }, (AVRational) { 1, 2 }); + pc_y = av_add_q(pc_y, vert_off); + + aperture_width = av_sub_q(aperture_width, (AVRational) { 1, 1 }); + aperture_width = av_mul_q(aperture_width, (AVRational) { 1, 2 }); + aperture_height = av_sub_q(aperture_height, (AVRational) { 1, 1 }); + aperture_height = av_mul_q(aperture_height, (AVRational) { 1, 2 }); + + left = av_q2d(av_sub_q(pc_x, aperture_width)); + right = av_q2d(av_add_q(pc_x, aperture_width)); + top = av_q2d(av_sub_q(pc_y, aperture_height)); + bottom = av_q2d(av_add_q(pc_y, aperture_height)); + + if (bottom > (st->codecpar->height - 1) || + right > (st->codecpar->width - 1)) + return AVERROR_INVALIDDATA; + + bottom = st->codecpar->height - 1 - bottom; + right = st->codecpar->width - 1 - right; + + if (!(left | right | top | bottom)) + return 0; + + if ((left + right) >= st->codecpar->width || + (top + bottom) >= st->codecpar->height) + return AVERROR_INVALIDDATA; + + sd = av_packet_side_data_new(&st->codecpar->coded_side_data, + &st->codecpar->nb_coded_side_data, + AV_PKT_DATA_FRAME_CROPPING, + sizeof(uint32_t) * 4, 0); + if (!sd) + return AVERROR(ENOMEM); + + AV_WL32A(sd->data, top); + AV_WL32A(sd->data + 4, bottom); + AV_WL32A(sd->data + 8, left); + AV_WL32A(sd->data + 12, right); + + return 0; +} + /* This atom overrides any previously set aspect ratio */ static int mov_read_pasp(MOVContext *c, AVIOContext *pb, MOVAtom atom) { const int num = avio_rb32(pb); const int den = avio_rb32(pb); AVStream *st; + MOVStreamContext *sc; if (c->fc->nb_streams < 1) return 0; st = c->fc->streams[c->fc->nb_streams-1]; + sc = st->priv_data; + + av_log(c->fc, AV_LOG_TRACE, "pasp: hSpacing %d, vSpacing %d\n", num, den); if (den != 0) { - av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, - num, den, 32767); + sc->h_spacing = num; + sc->v_spacing = den; } return 0; } @@ -1545,6 +1644,8 @@ static int64_t get_frag_time(AVFormatContext *s, AVStream *dst_st, // to fragments that referenced this stream in the sidx if (sc->has_sidx) { frag_stream_info = get_frag_stream_info(frag_index, index, sc->id); + if (!frag_stream_info) + return AV_NOPTS_VALUE; if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) return frag_stream_info->sidx_pts; if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE) @@ -2351,6 +2452,30 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_sbas(MOVContext* c, AVIOContext* pb, MOVAtom atom) +{ + AVStream* st; + MOVStreamContext* sc; + + if (c->fc->nb_streams < 1) + return 0; + + /* For SBAS this should be fine - though beware if someone implements a + * tref atom processor that doesn't drop down to default then this may + * be lost. */ + if (atom.size > 4) { + av_log(c->fc, AV_LOG_ERROR, "Only a single tref of type sbas is supported\n"); + return AVERROR_PATCHWELCOME; + } + + st = c->fc->streams[c->fc->nb_streams - 1]; + sc = st->priv_data; + sc->tref_id = avio_rb32(pb); + sc->tref_flags |= MOV_TREF_FLAG_ENHANCEMENT; + + return 0; +} + /** * An strf atom is a BITMAPINFOHEADER struct. This struct is 40 bytes itself, * but can have extradata appended at the end after the 40 bytes belonging @@ -3414,13 +3539,13 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->stts_data[i].duration = 1; corrected_dts += (delta_magnitude < 0 ? (int64_t)delta_magnitude : 1) * sample_count; } else { - corrected_dts += sample_duration * (int64_t)sample_count; + corrected_dts += sample_duration * (uint64_t)sample_count; } - current_dts += sc->stts_data[i].duration * (int64_t)sample_count; + current_dts += sc->stts_data[i].duration * (uint64_t)sample_count; if (current_dts > corrected_dts) { - int64_t drift = (current_dts - corrected_dts)/FFMAX(sample_count, 1); + int64_t drift = av_sat_sub64(current_dts, corrected_dts) / FFMAX(sample_count, 1); uint32_t correction = (sc->stts_data[i].duration > drift) ? drift : sc->stts_data[i].duration - 1; current_dts -= correction * (uint64_t)sample_count; sc->stts_data[i].duration -= correction; @@ -4850,6 +4975,7 @@ static void fix_timescale(MOVContext *c, MOVStreamContext *sc) } } +#if CONFIG_IAMFDEC static int mov_update_iamf_streams(MOVContext *c, const AVStream *st) { const MOVStreamContext *sc = st->priv_data; @@ -4893,6 +5019,25 @@ static int mov_update_iamf_streams(MOVContext *c, const AVStream *st) return 0; } +#endif + +static int sanity_checks(void *log_obj, MOVStreamContext *sc, int index) +{ + if ((sc->chunk_count && (!sc->stts_count || !sc->stsc_count || + (!sc->sample_size && !sc->sample_count))) || + (!sc->chunk_count && sc->sample_count)) { + av_log(log_obj, AV_LOG_ERROR, "stream %d, missing mandatory atoms, broken header\n", + index); + return 1; + } + + if (sc->stsc_count && sc->stsc_data[ sc->stsc_count - 1 ].first > sc->chunk_count) { + av_log(log_obj, AV_LOG_ERROR, "stream %d, contradictionary STSC and STCO\n", + index); + return 2; + } + return 0; +} static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) { @@ -4910,6 +5055,8 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->codecpar->codec_type = AVMEDIA_TYPE_DATA; sc->ffindex = st->index; c->trak_index = st->index; + sc->tref_flags = 0; + sc->tref_id = -1; sc->refcount = 1; if ((ret = mov_read_default(c, pb, atom)) < 0) @@ -4924,19 +5071,9 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_freep(&sc->stsc_data); } - /* sanity checks */ - if ((sc->chunk_count && (!sc->stts_count || !sc->stsc_count || - (!sc->sample_size && !sc->sample_count))) || - (!sc->chunk_count && sc->sample_count)) { - av_log(c->fc, AV_LOG_ERROR, "stream %d, missing mandatory atoms, broken header\n", - st->index); - return 0; - } - if (sc->stsc_count && sc->stsc_data[ sc->stsc_count - 1 ].first > sc->chunk_count) { - av_log(c->fc, AV_LOG_ERROR, "stream %d, contradictionary STSC and STCO\n", - st->index); - return AVERROR_INVALIDDATA; - } + ret = sanity_checks(c->fc, sc, st->index); + if (ret) + return ret > 1 ? AVERROR_INVALIDDATA : 0; fix_timescale(c, sc); @@ -4957,11 +5094,13 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) mov_build_index(c, st); +#if CONFIG_IAMFDEC if (sc->iamf) { ret = mov_update_iamf_streams(c, st); if (ret < 0) return ret; } +#endif if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) { MOVDref *dref = &sc->drefs[sc->dref_id - 1]; @@ -4987,11 +5126,15 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) } if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (sc->h_spacing && sc->v_spacing) + av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, + sc->h_spacing, sc->v_spacing, INT_MAX); if (!st->sample_aspect_ratio.num && st->codecpar->width && st->codecpar->height && sc->height && sc->width && (st->codecpar->width != sc->width || st->codecpar->height != sc->height)) { - st->sample_aspect_ratio = av_d2q(((double)st->codecpar->height * sc->width) / - ((double)st->codecpar->width * sc->height), INT_MAX); + av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, + (int64_t)st->codecpar->height * sc->width, + (int64_t)st->codecpar->width * sc->height, INT_MAX); } #if FF_API_R_FRAME_RATE @@ -5065,7 +5208,7 @@ static int mov_read_keys(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_skip(pb, 4); count = avio_rb32(pb); atom.size -= 8; - if (count > UINT_MAX / sizeof(*c->meta_keys) - 1) { + if (count >= UINT_MAX / sizeof(*c->meta_keys)) { av_log(c->fc, AV_LOG_ERROR, "The 'keys' atom with the invalid key count: %"PRIu32"\n", count); return AVERROR_INVALIDDATA; @@ -5710,10 +5853,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) pts = AV_NOPTS_VALUE; } - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) - keyframe = 1; - else - keyframe = + keyframe = !(sample_flags & (MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC | MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES)); if (keyframe) { @@ -6171,7 +6311,7 @@ static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_skip(pb, 3); /* flags */ - sc->mastering = av_mastering_display_metadata_alloc(); + sc->mastering = av_mastering_display_metadata_alloc_size(&sc->mastering_size); if (!sc->mastering) return AVERROR(ENOMEM); @@ -6214,7 +6354,7 @@ static int mov_read_mdcv(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } - sc->mastering = av_mastering_display_metadata_alloc(); + sc->mastering = av_mastering_display_metadata_alloc_size(&sc->mastering_size); if (!sc->mastering) return AVERROR(ENOMEM); @@ -6365,7 +6505,7 @@ static int mov_read_st3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } - sc->stereo3d = av_stereo3d_alloc(); + sc->stereo3d = av_stereo3d_alloc_size(&sc->stereo3d_size); if (!sc->stereo3d) return AVERROR(ENOMEM); @@ -6510,6 +6650,325 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_vexu_proj(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + MOVStreamContext *sc; + int size; + uint32_t tag; + enum AVSphericalProjection projection; + + if (c->fc->nb_streams < 1) + return 0; + + st = c->fc->streams[c->fc->nb_streams - 1]; + sc = st->priv_data; + + if (atom.size != 16) { + av_log(c->fc, AV_LOG_ERROR, "Invalid size for proj box: %"PRIu64"\n", atom.size); + return AVERROR_INVALIDDATA; + } + + size = avio_rb32(pb); + if (size != 16) { + av_log(c->fc, AV_LOG_ERROR, "Invalid size for prji box: %d\n", size); + return AVERROR_INVALIDDATA; + } + + tag = avio_rl32(pb); + if (tag != MKTAG('p','r','j','i')) { + av_log(c->fc, AV_LOG_ERROR, "Invalid child box of proj box: 0x%08X\n", tag); + return AVERROR_INVALIDDATA; + } + + avio_skip(pb, 1); // version + avio_skip(pb, 3); // flags + + tag = avio_rl32(pb); + switch (tag) { + case MKTAG('r','e','c','t'): + projection = AV_SPHERICAL_RECTILINEAR; + break; + case MKTAG('e','q','u','i'): + projection = AV_SPHERICAL_EQUIRECTANGULAR; + break; + case MKTAG('h','e','q','u'): + projection = AV_SPHERICAL_HALF_EQUIRECTANGULAR; + break; + case MKTAG('f','i','s','h'): + projection = AV_SPHERICAL_FISHEYE; + break; + default: + av_log(c->fc, AV_LOG_ERROR, "Invalid projection type in prji box: 0x%08X\n", tag); + return AVERROR_INVALIDDATA; + } + + sc->spherical = av_spherical_alloc(&sc->spherical_size); + if (!sc->spherical) + return AVERROR(ENOMEM); + + sc->spherical->projection = projection; + + return 0; +} + +static int mov_read_eyes(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + MOVStreamContext *sc; + int size, flags = 0; + int64_t remaining; + uint32_t tag, baseline = 0; + enum AVStereo3DView view = AV_STEREO3D_VIEW_UNSPEC; + enum AVStereo3DType type = AV_STEREO3D_2D; + enum AVStereo3DPrimaryEye primary_eye = AV_PRIMARY_EYE_NONE; + AVRational horizontal_disparity_adjustment = { 0, 1 }; + + if (c->fc->nb_streams < 1) + return 0; + + st = c->fc->streams[c->fc->nb_streams - 1]; + sc = st->priv_data; + + remaining = atom.size; + while (remaining > 0) { + size = avio_rb32(pb); + if (size < 8 || size > remaining ) { + av_log(c->fc, AV_LOG_ERROR, "Invalid child size in eyes box\n"); + return AVERROR_INVALIDDATA; + } + + tag = avio_rl32(pb); + switch (tag) { + case MKTAG('s','t','r','i'): { + int has_right, has_left; + uint8_t tmp; + if (size != 13) { + av_log(c->fc, AV_LOG_ERROR, "Invalid size of stri box: %d\n", size); + return AVERROR_INVALIDDATA; + } + avio_skip(pb, 1); // version + avio_skip(pb, 3); // flags + + tmp = avio_r8(pb); + + // eye_views_reversed + if (tmp & 8) { + flags |= AV_STEREO3D_FLAG_INVERT; + } + // has_additional_views + if (tmp & 4) { + // skip... + } + + has_right = tmp & 2; // has_right_eye_view + has_left = tmp & 1; // has_left_eye_view + + if (has_left && has_right) + view = AV_STEREO3D_VIEW_PACKED; + else if (has_left) + view = AV_STEREO3D_VIEW_LEFT; + else if (has_right) + view = AV_STEREO3D_VIEW_RIGHT; + if (has_left || has_right) + type = AV_STEREO3D_UNSPEC; + + break; + } + case MKTAG('h','e','r','o'): { + int tmp; + if (size != 13) { + av_log(c->fc, AV_LOG_ERROR, "Invalid size of hero box: %d\n", size); + return AVERROR_INVALIDDATA; + } + avio_skip(pb, 1); // version + avio_skip(pb, 3); // flags + + tmp = avio_r8(pb); + if (tmp == 0) + primary_eye = AV_PRIMARY_EYE_NONE; + else if (tmp == 1) + primary_eye = AV_PRIMARY_EYE_LEFT; + else if (tmp == 2) + primary_eye = AV_PRIMARY_EYE_RIGHT; + else + av_log(c->fc, AV_LOG_WARNING, "Unknown hero eye type: %d\n", tmp); + + break; + } + case MKTAG('c','a','m','s'): { + uint32_t subtag; + int subsize; + if (size != 24) { + av_log(c->fc, AV_LOG_ERROR, "Invalid size of cams box: %d\n", size); + return AVERROR_INVALIDDATA; + } + + subsize = avio_rb32(pb); + if (subsize != 16) { + av_log(c->fc, AV_LOG_ERROR, "Invalid size of blin box: %d\n", size); + return AVERROR_INVALIDDATA; + } + + subtag = avio_rl32(pb); + if (subtag != MKTAG('b','l','i','n')) { + av_log(c->fc, AV_LOG_ERROR, "Expected blin box, got 0x%08X\n", subtag); + return AVERROR_INVALIDDATA; + } + + avio_skip(pb, 1); // version + avio_skip(pb, 3); // flags + + baseline = avio_rb32(pb); + + break; + } + case MKTAG('c','m','f','y'): { + uint32_t subtag; + int subsize; + int32_t adjustment; + if (size != 24) { + av_log(c->fc, AV_LOG_ERROR, "Invalid size of cmfy box: %d\n", size); + return AVERROR_INVALIDDATA; + } + + subsize = avio_rb32(pb); + if (subsize != 16) { + av_log(c->fc, AV_LOG_ERROR, "Invalid size of dadj box: %d\n", size); + return AVERROR_INVALIDDATA; + } + + subtag = avio_rl32(pb); + if (subtag != MKTAG('d','a','d','j')) { + av_log(c->fc, AV_LOG_ERROR, "Expected dadj box, got 0x%08X\n", subtag); + return AVERROR_INVALIDDATA; + } + + avio_skip(pb, 1); // version + avio_skip(pb, 3); // flags + + adjustment = (int32_t) avio_rb32(pb); + + horizontal_disparity_adjustment.num = (int) adjustment; + horizontal_disparity_adjustment.den = 10000; + + break; + } + default: + av_log(c->fc, AV_LOG_WARNING, "Unknown tag in eyes: 0x%08X\n", tag); + avio_skip(pb, size - 8); + break; + } + remaining -= size; + } + + if (remaining != 0) { + av_log(c->fc, AV_LOG_ERROR, "Broken eyes box\n"); + return AVERROR_INVALIDDATA; + } + + if (type == AV_STEREO3D_2D) + return 0; + + if (!sc->stereo3d) { + sc->stereo3d = av_stereo3d_alloc_size(&sc->stereo3d_size); + if (!sc->stereo3d) + return AVERROR(ENOMEM); + } + + sc->stereo3d->flags = flags; + sc->stereo3d->type = type; + sc->stereo3d->view = view; + sc->stereo3d->primary_eye = primary_eye; + sc->stereo3d->baseline = baseline; + sc->stereo3d->horizontal_disparity_adjustment = horizontal_disparity_adjustment; + + return 0; +} + +static int mov_read_vexu(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + int size; + int64_t remaining; + uint32_t tag; + + if (c->fc->nb_streams < 1) + return 0; + + if (atom.size < 8) { + av_log(c->fc, AV_LOG_ERROR, "Empty video extension usage box\n"); + return AVERROR_INVALIDDATA; + } + + remaining = atom.size; + while (remaining > 0) { + size = avio_rb32(pb); + if (size < 8 || size > remaining ) { + av_log(c->fc, AV_LOG_ERROR, "Invalid child size in vexu box\n"); + return AVERROR_INVALIDDATA; + } + + tag = avio_rl32(pb); + switch (tag) { + case MKTAG('p','r','o','j'): { + MOVAtom proj = { tag, size - 8 }; + int ret = mov_read_vexu_proj(c, pb, proj); + if (ret < 0) + return ret; + break; + } + case MKTAG('e','y','e','s'): { + MOVAtom eyes = { tag, size - 8 }; + int ret = mov_read_eyes(c, pb, eyes); + if (ret < 0) + return ret; + break; + } + default: + av_log(c->fc, AV_LOG_WARNING, "Unknown tag in vexu: 0x%08X\n", tag); + avio_skip(pb, size - 8); + break; + } + remaining -= size; + } + + if (remaining != 0) { + av_log(c->fc, AV_LOG_ERROR, "Broken vexu box\n"); + return AVERROR_INVALIDDATA; + } + + return 0; +} + +static int mov_read_hfov(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + MOVStreamContext *sc; + + if (c->fc->nb_streams < 1) + return 0; + + st = c->fc->streams[c->fc->nb_streams - 1]; + sc = st->priv_data; + + if (atom.size != 4) { + av_log(c->fc, AV_LOG_ERROR, "Invalid size of hfov box: %"PRIu64"\n", atom.size); + return AVERROR_INVALIDDATA; + } + + + if (!sc->stereo3d) { + sc->stereo3d = av_stereo3d_alloc_size(&sc->stereo3d_size); + if (!sc->stereo3d) + return AVERROR(ENOMEM); + } + + sc->stereo3d->horizontal_field_of_view.num = avio_rb32(pb); + sc->stereo3d->horizontal_field_of_view.den = 1000; // thousands of a degree + + return 0; +} + static int mov_parse_uuid_spherical(MOVStreamContext *sc, AVIOContext *pb, size_t len) { int ret = 0; @@ -6549,7 +7008,7 @@ static int mov_parse_uuid_spherical(MOVStreamContext *sc, AVIOContext *pb, size_ else mode = AV_STEREO3D_2D; - sc->stereo3d = av_stereo3d_alloc(); + sc->stereo3d = av_stereo3d_alloc_size(&sc->stereo3d_size); if (!sc->stereo3d) goto out; @@ -6686,7 +7145,7 @@ static int mov_read_free(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (atom.size < 8) return 0; - ret = avio_read(pb, content, FFMIN(sizeof(content), atom.size)); + ret = ffio_read_size(pb, content, FFMIN(sizeof(content), atom.size)); if (ret < 0) return ret; @@ -7733,15 +8192,19 @@ static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPa return AVERROR_INVALIDDATA; } + encrypted_sample = NULL; if (!encryption_index->nb_encrypted_samples) { // Full-sample encryption with default settings. encrypted_sample = sc->cenc.default_encrypted_sample; } else if (encrypted_index >= 0 && encrypted_index < encryption_index->nb_encrypted_samples) { // Per-sample setting override. encrypted_sample = encryption_index->encrypted_samples[encrypted_index]; - if (!encrypted_sample) + if (!encrypted_sample) { encrypted_sample = sc->cenc.default_encrypted_sample; - } else { + } + } + + if (!encrypted_sample) { av_log(mov->fc, AV_LOG_ERROR, "Incorrect number of samples in encryption info\n"); return AVERROR_INVALIDDATA; } @@ -7790,8 +8253,8 @@ static int mov_read_dops(MOVContext *c, AVIOContext *pb, MOVAtom atom) if ((ret = ff_alloc_extradata(st->codecpar, size)) < 0) return ret; - AV_WL32(st->codecpar->extradata, MKTAG('O','p','u','s')); - AV_WL32(st->codecpar->extradata + 4, MKTAG('H','e','a','d')); + AV_WL32A(st->codecpar->extradata, MKTAG('O','p','u','s')); + AV_WL32A(st->codecpar->extradata + 4, MKTAG('H','e','a','d')); AV_WB8(st->codecpar->extradata + 8, 1); /* OpusHead version */ avio_read(pb, st->codecpar->extradata + 9, size - 9); @@ -7799,10 +8262,10 @@ static int mov_read_dops(MOVContext *c, AVIOContext *pb, MOVAtom atom) little-endian; aside from the preceeding magic and version they're otherwise currently identical. Data after output gain at offset 16 doesn't need to be bytewapped. */ - pre_skip = AV_RB16(st->codecpar->extradata + 10); - AV_WL16(st->codecpar->extradata + 10, pre_skip); - AV_WL32(st->codecpar->extradata + 12, AV_RB32(st->codecpar->extradata + 12)); - AV_WL16(st->codecpar->extradata + 16, AV_RB16(st->codecpar->extradata + 16)); + pre_skip = AV_RB16A(st->codecpar->extradata + 10); + AV_WL16A(st->codecpar->extradata + 10, pre_skip); + AV_WL32A(st->codecpar->extradata + 12, AV_RB32A(st->codecpar->extradata + 12)); + AV_WL16A(st->codecpar->extradata + 16, AV_RB16A(st->codecpar->extradata + 16)); st->codecpar->initial_padding = pre_skip; st->codecpar->seek_preroll = av_rescale_q(OPUS_SEEK_PREROLL_MS, @@ -7867,6 +8330,55 @@ static int mov_read_dvcc_dvvc(MOVContext *c, AVIOContext *pb, MOVAtom atom) return ff_isom_parse_dvcc_dvvc(c->fc, st, buf, read_size); } +static int mov_read_lhvc(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + uint8_t *buf; + int ret, old_size, num_arrays; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + + if (!st->codecpar->extradata_size) + // TODO: handle lhvC when present before hvcC + return 0; + + if (atom.size < 6 || st->codecpar->extradata_size < 23) + return AVERROR_INVALIDDATA; + + buf = av_malloc(atom.size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!buf) + return AVERROR(ENOMEM); + memset(buf + atom.size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + ret = ffio_read_size(pb, buf, atom.size); + if (ret < 0) { + av_free(buf); + av_log(c->fc, AV_LOG_WARNING, "lhvC atom truncated\n"); + return 0; + } + + num_arrays = buf[5]; + old_size = st->codecpar->extradata_size; + atom.size -= 8 /* account for mov_realloc_extradata offseting */ + + 6 /* lhvC bytes before the arrays*/; + + ret = mov_realloc_extradata(st->codecpar, atom); + if (ret < 0) { + av_free(buf); + return ret; + } + + st->codecpar->extradata[22] += num_arrays; + memcpy(st->codecpar->extradata + old_size, buf + 6, atom.size + 8); + + st->disposition |= AV_DISPOSITION_MULTILAYER; + + av_free(buf); + return 0; +} + static int mov_read_kind(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVFormatContext *ctx = c->fc; @@ -7959,8 +8471,10 @@ cleanup: static int mov_read_SA3D(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; - int i, version, type; + AVChannelLayout ch_layout = { 0 }; + int ret, i, version, type; int ambisonic_order, channel_order, normalization, channel_count; + int ambi_channels, non_diegetic_channels; if (c->fc->nb_streams < 1) return 0; @@ -7979,11 +8493,12 @@ static int mov_read_SA3D(MOVContext *c, AVIOContext *pb, MOVAtom atom) } type = avio_r8(pb); - if (type) { + if (type & 0x7f) { av_log(c->fc, AV_LOG_WARNING, - "Unsupported ambisonic type %d\n", type); + "Unsupported ambisonic type %d\n", type & 0x7f); return 0; } + non_diegetic_channels = (type >> 7) * 2; // head_locked_stereo ambisonic_order = avio_rb32(pb); @@ -8002,24 +8517,43 @@ static int mov_read_SA3D(MOVContext *c, AVIOContext *pb, MOVAtom atom) } channel_count = avio_rb32(pb); - if (ambisonic_order < 0 || channel_count != (ambisonic_order + 1LL) * (ambisonic_order + 1LL)) { + if (ambisonic_order < 0 || ambisonic_order > 31 || + channel_count != ((ambisonic_order + 1LL) * (ambisonic_order + 1LL) + + non_diegetic_channels)) { av_log(c->fc, AV_LOG_ERROR, "Invalid number of channels (%d / %d)\n", channel_count, ambisonic_order); return 0; } + ambi_channels = channel_count - non_diegetic_channels; + + ret = av_channel_layout_custom_init(&ch_layout, channel_count); + if (ret < 0) + return 0; for (i = 0; i < channel_count; i++) { - if (i != avio_rb32(pb)) { - av_log(c->fc, AV_LOG_WARNING, - "Ambisonic channel reordering is not supported\n"); + unsigned channel = avio_rb32(pb); + + if (channel >= channel_count) { + av_log(c->fc, AV_LOG_ERROR, "Invalid channel index (%d / %d)\n", + channel, ambisonic_order); + av_channel_layout_uninit(&ch_layout); return 0; } + if (channel >= ambi_channels) + ch_layout.u.map[i].id = channel - ambi_channels; + else + ch_layout.u.map[i].id = AV_CHAN_AMBISONIC_BASE + channel; + } + + ret = av_channel_layout_retype(&ch_layout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL); + if (ret < 0) { + av_channel_layout_uninit(&ch_layout); + return 0; } av_channel_layout_uninit(&st->codecpar->ch_layout); - st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_AMBISONIC; - st->codecpar->ch_layout.nb_channels = channel_count; + st->codecpar->ch_layout = ch_layout; return 0; } @@ -8085,7 +8619,7 @@ static int mov_read_idat(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - HEIFItem *heif_item; + HEIFItem **heif_item; int version, offset_size, length_size, base_offset_size, index_size; int item_count, extent_count; int64_t base_offset, extent_offset, extent_length; @@ -8116,12 +8650,13 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR(ENOMEM); c->heif_item = heif_item; if (item_count > c->nb_heif_item) - memset(c->heif_item + c->nb_heif_item, 0, + memset(&c->heif_item[c->nb_heif_item], 0, sizeof(*c->heif_item) * (item_count - c->nb_heif_item)); c->nb_heif_item = FFMAX(c->nb_heif_item, item_count); av_log(c->fc, AV_LOG_TRACE, "iloc: item_count %d\n", item_count); for (int i = 0; i < item_count; i++) { + HEIFItem *item = c->heif_item[i]; int item_id = (version < 2) ? avio_rb16(pb) : avio_rb32(pb); int offset_type = (version > 0) ? avio_rb16(pb) & 0xf : 0; @@ -8131,7 +8666,6 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) avpriv_report_missing_feature(c->fc, "iloc offset type %d", offset_type); return AVERROR_PATCHWELCOME; } - c->heif_item[i].item_id = item_id; avio_rb16(pb); // data_reference_index. if (rb_size(pb, &base_offset, base_offset_size) < 0) @@ -8142,19 +8676,26 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) avpriv_report_missing_feature(c->fc, "iloc: extent_count > 1"); return AVERROR_PATCHWELCOME; } - for (int j = 0; j < extent_count; j++) { - if (rb_size(pb, &extent_offset, offset_size) < 0 || - rb_size(pb, &extent_length, length_size) < 0 || - base_offset > INT64_MAX - extent_offset) - return AVERROR_INVALIDDATA; - if (offset_type == 1) - c->heif_item[i].is_idat_relative = 1; - c->heif_item[i].extent_length = extent_length; - c->heif_item[i].extent_offset = base_offset + extent_offset; - av_log(c->fc, AV_LOG_TRACE, "iloc: item_idx %d, offset_type %d, " - "extent_offset %"PRId64", extent_length %"PRId64"\n", - i, offset_type, c->heif_item[i].extent_offset, c->heif_item[i].extent_length); - } + + if (rb_size(pb, &extent_offset, offset_size) < 0 || + rb_size(pb, &extent_length, length_size) < 0 || + base_offset > INT64_MAX - extent_offset) + return AVERROR_INVALIDDATA; + + if (!item) + item = c->heif_item[i] = av_mallocz(sizeof(*item)); + if (!item) + return AVERROR(ENOMEM); + + item->item_id = item_id; + + if (offset_type == 1) + item->is_idat_relative = 1; + item->extent_length = extent_length; + item->extent_offset = base_offset + extent_offset; + av_log(c->fc, AV_LOG_TRACE, "iloc: item_idx %d, offset_type %d, " + "extent_offset %"PRId64", extent_length %"PRId64"\n", + i, offset_type, item->extent_offset, item->extent_length); } c->found_iloc = 1; @@ -8163,6 +8704,7 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx) { + HEIFItem *item; AVBPrint item_name; int64_t size = atom.size; uint32_t item_type; @@ -8202,15 +8744,21 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx) if (size > 0) avio_skip(pb, size); + item = c->heif_item[idx]; + if (!item) + item = c->heif_item[idx] = av_mallocz(sizeof(*item)); + if (!item) + return AVERROR(ENOMEM); + if (ret) - av_bprint_finalize(&item_name, &c->heif_item[idx].name); - c->heif_item[idx].item_id = item_id; - c->heif_item[idx].type = item_type; + av_bprint_finalize(&item_name, &c->heif_item[idx]->name); + c->heif_item[idx]->item_id = item_id; + c->heif_item[idx]->type = item_type; switch (item_type) { case MKTAG('a','v','0','1'): case MKTAG('h','v','c','1'): - ret = heif_add_stream(c, &c->heif_item[idx]); + ret = heif_add_stream(c, c->heif_item[idx]); if (ret < 0) return ret; break; @@ -8221,7 +8769,7 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx) static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - HEIFItem *heif_item; + HEIFItem **heif_item; int entry_count; int version, got_stream = 0, ret, i; @@ -8239,15 +8787,17 @@ static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR(ENOMEM); c->heif_item = heif_item; if (entry_count > c->nb_heif_item) - memset(c->heif_item + c->nb_heif_item, 0, + memset(&c->heif_item[c->nb_heif_item], 0, sizeof(*c->heif_item) * (entry_count - c->nb_heif_item)); c->nb_heif_item = FFMAX(c->nb_heif_item, entry_count); for (i = 0; i < entry_count; i++) { MOVAtom infe; - if (avio_feof(pb)) - return AVERROR_INVALIDDATA; + if (avio_feof(pb)) { + ret = AVERROR_INVALIDDATA; + goto fail; + } infe.size = avio_rb32(pb) - 8; infe.type = avio_rl32(pb); ret = mov_read_infe(c, pb, infe, i); @@ -8261,7 +8811,10 @@ static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; fail: for (; i >= 0; i--) { - HEIFItem *item = &c->heif_item[i]; + HEIFItem *item = c->heif_item[i]; + + if (!item) + continue; av_freep(&item->name); if (!item->st) @@ -8289,9 +8842,9 @@ static int mov_read_iref_dimg(MOVContext *c, AVIOContext *pb, int version) } } for (int i = 0; i < c->nb_heif_item; i++) { - if (c->heif_item[i].item_id != from_item_id) + if (!c->heif_item[i] || c->heif_item[i]->item_id != from_item_id) continue; - item = &c->heif_item[i]; + item = c->heif_item[i]; switch (item->type) { case MKTAG('g','r','i','d'): @@ -8397,6 +8950,7 @@ static int mov_read_iref(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_ispe(MOVContext *c, AVIOContext *pb, MOVAtom atom) { + HEIFItem *item; uint32_t width, height; avio_r8(pb); /* version */ @@ -8407,12 +8961,10 @@ static int mov_read_ispe(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "ispe: item_id %d, width %u, height %u\n", c->cur_item_id, width, height); - for (int i = 0; i < c->nb_heif_item; i++) { - if (c->heif_item[i].item_id == c->cur_item_id) { - c->heif_item[i].width = width; - c->heif_item[i].height = height; - break; - } + item = heif_cur_item(c); + if (item) { + item->width = width; + item->height = height; } return 0; @@ -8566,6 +9118,8 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('a','l','a','c'), mov_read_alac }, /* alac specific atom */ { MKTAG('a','v','c','C'), mov_read_glbl }, { MKTAG('p','a','s','p'), mov_read_pasp }, +{ MKTAG('c','l','a','p'), mov_read_clap }, +{ MKTAG('s','b','a','s'), mov_read_sbas }, { MKTAG('s','i','d','x'), mov_read_sidx }, { MKTAG('s','t','b','l'), mov_read_default }, { MKTAG('s','t','c','o'), mov_read_stco }, @@ -8620,6 +9174,8 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('d','f','L','a'), mov_read_dfla }, { MKTAG('s','t','3','d'), mov_read_st3d }, /* stereoscopic 3D video box */ { MKTAG('s','v','3','d'), mov_read_sv3d }, /* spherical video box */ +{ MKTAG('v','e','x','u'), mov_read_vexu }, /* video extension usage */ +{ MKTAG('h','f','o','v'), mov_read_hfov }, { MKTAG('d','O','p','s'), mov_read_dops }, { MKTAG('d','m','l','p'), mov_read_dmlp }, { MKTAG('S','m','D','m'), mov_read_smdm }, @@ -8643,7 +9199,11 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('i','p','r','p'), mov_read_iprp }, { MKTAG('i','i','n','f'), mov_read_iinf }, { MKTAG('a','m','v','e'), mov_read_amve }, /* ambient viewing environment box */ +{ MKTAG('l','h','v','C'), mov_read_lhvc }, +{ MKTAG('l','v','c','C'), mov_read_glbl }, +#if CONFIG_IAMFDEC { MKTAG('i','a','c','b'), mov_read_iacb }, +#endif { 0, NULL } }; @@ -9115,8 +9675,10 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st) av_freep(&sc->coll); av_freep(&sc->ambient); +#if CONFIG_IAMFDEC if (sc->iamf) ff_iamf_read_deinit(sc->iamf); +#endif av_freep(&sc->iamf); } @@ -9156,8 +9718,12 @@ static int mov_read_close(AVFormatContext *s) av_freep(&mov->aes_decrypt); av_freep(&mov->chapter_tracks); - for (i = 0; i < mov->nb_heif_item; i++) - av_freep(&mov->heif_item[i].name); + for (i = 0; i < mov->nb_heif_item; i++) { + if (!mov->heif_item[i]) + continue; + av_freep(&mov->heif_item[i]->name); + av_freep(&mov->heif_item[i]); + } av_freep(&mov->heif_item); for (i = 0; i < mov->nb_heif_grid; i++) { av_freep(&mov->heif_grid[i].tile_id_list); @@ -9473,11 +10039,12 @@ static int mov_parse_tiles(AVFormatContext *s) int k; for (k = 0; k < mov->nb_heif_item; k++) { - HEIFItem *item = &mov->heif_item[k]; - AVStream *st = item->st; + HEIFItem *item = mov->heif_item[k]; + AVStream *st; - if (item->item_id != tile_id) + if (!item || item->item_id != tile_id) continue; + st = item->st; if (!st) { av_log(s, AV_LOG_WARNING, "HEIF item id %d from grid id %d doesn't " "reference a stream\n", @@ -9536,6 +10103,76 @@ static int mov_parse_tiles(AVFormatContext *s) return 0; } +static int mov_parse_heif_items(AVFormatContext *s) +{ + MOVContext *mov = s->priv_data; + int err; + + for (int i = 0; i < mov->nb_heif_item; i++) { + HEIFItem *item = mov->heif_item[i]; + MOVStreamContext *sc; + AVStream *st; + int64_t offset = 0; + + if (!item) + continue; + if (!item->st) { + if (item->item_id == mov->thmb_item_id) { + av_log(s, AV_LOG_ERROR, "HEIF thumbnail doesn't reference a stream\n"); + return AVERROR_INVALIDDATA; + } + continue; + } + if (item->is_idat_relative) { + if (!mov->idat_offset) { + av_log(s, AV_LOG_ERROR, "Missing idat box for item %d\n", item->item_id); + return AVERROR_INVALIDDATA; + } + offset = mov->idat_offset; + } + + st = item->st; + sc = st->priv_data; + st->codecpar->width = item->width; + st->codecpar->height = item->height; + + err = sanity_checks(s, sc, item->item_id); + if (err) + return AVERROR_INVALIDDATA; + + sc->sample_sizes[0] = item->extent_length; + sc->chunk_offsets[0] = item->extent_offset + offset; + + if (item->item_id == mov->primary_item_id) + st->disposition |= AV_DISPOSITION_DEFAULT; + + mov_build_index(mov, st); + } + + if (mov->nb_heif_grid) { + err = mov_parse_tiles(s); + if (err < 0) + return err; + } + + return 0; +} + +static AVStream *mov_find_reference_track(AVFormatContext *s, AVStream *st, + int first_index) +{ + MOVStreamContext *sc = st->priv_data; + + if (sc->tref_id < 0) + return NULL; + + for (int i = first_index; i < s->nb_streams; i++) + if (s->streams[i]->id == sc->tref_id) + return s->streams[i]; + + return NULL; +} + static int mov_read_header(AVFormatContext *s) { MOVContext *mov = s->priv_data; @@ -9578,49 +10215,9 @@ static int mov_read_header(AVFormatContext *s) av_log(mov->fc, AV_LOG_TRACE, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); if (mov->found_iloc && mov->found_iinf) { - for (i = 0; i < mov->nb_heif_item; i++) { - HEIFItem *item = &mov->heif_item[i]; - MOVStreamContext *sc; - AVStream *st; - int64_t offset = 0; - - if (!item->st) { - if (item->item_id == mov->thmb_item_id) { - av_log(s, AV_LOG_ERROR, "HEIF thumbnail doesn't reference a stream\n"); - return AVERROR_INVALIDDATA; - } - continue; - } - if (item->is_idat_relative) { - if (!mov->idat_offset) { - av_log(s, AV_LOG_ERROR, "Missing idat box for item %d\n", item->item_id); - return AVERROR_INVALIDDATA; - } - offset = mov->idat_offset; - } - - st = item->st; - sc = st->priv_data; - st->codecpar->width = item->width; - st->codecpar->height = item->height; - - if (sc->sample_count != 1 || sc->chunk_count != 1) - return AVERROR_INVALIDDATA; - - sc->sample_sizes[0] = item->extent_length; - sc->chunk_offsets[0] = item->extent_offset + offset; - - if (item->item_id == mov->primary_item_id) - st->disposition |= AV_DISPOSITION_DEFAULT; - - mov_build_index(mov, st); - } - - if (mov->nb_heif_grid) { - err = mov_parse_tiles(s); - if (err < 0) - return err; - } + err = mov_parse_heif_items(s); + if (err < 0) + return err; } // prevent iloc and iinf boxes from being parsed while reading packets. // this is needed because an iinf box may have been parsed but ignored @@ -9661,6 +10258,50 @@ static int mov_read_header(AVFormatContext *s) } export_orphan_timecode(s); + /* Create LCEVC stream groups. */ + for (i = 0; i < s->nb_streams; i++) { + AVStreamGroup *stg; + AVStream *st = s->streams[i]; + AVStream *st_base; + MOVStreamContext *sc = st->priv_data; + + /* Find an enhancement stream. */ + if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC || + !(sc->tref_flags & MOV_TREF_FLAG_ENHANCEMENT)) + continue; + + st->codecpar->codec_type = AVMEDIA_TYPE_DATA; + + stg = avformat_stream_group_create(s, AV_STREAM_GROUP_PARAMS_LCEVC, NULL); + if (!stg) + return AVERROR(ENOMEM); + + stg->id = st->id; + stg->params.lcevc->width = st->codecpar->width; + stg->params.lcevc->height = st->codecpar->height; + st->codecpar->width = 0; + st->codecpar->height = 0; + + j = 0; + while (st_base = mov_find_reference_track(s, st, j)) { + err = avformat_stream_group_add_stream(stg, st_base); + if (err < 0) + return err; + + j = st_base->index + 1; + } + if (!j) { + av_log(s, AV_LOG_ERROR, "Failed to find base stream for enhancement stream\n"); + return AVERROR_INVALIDDATA; + } + + err = avformat_stream_group_add_stream(stg, st); + if (err < 0) + return err; + + stg->params.lcevc->lcevc_index = stg->nb_streams - 1; + } + for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; FFStream *const sti = ffstream(st); @@ -9691,25 +10332,7 @@ static int mov_read_header(AVFormatContext *s) } } - if (mov->trex_data) { - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - MOVStreamContext *sc = st->priv_data; - if (st->duration > 0) { - /* Akin to sc->data_size * 8 * sc->time_scale / st->duration but accounting for overflows. */ - st->codecpar->bit_rate = av_rescale(sc->data_size, ((int64_t) sc->time_scale) * 8, st->duration); - if (st->codecpar->bit_rate == INT64_MIN) { - av_log(s, AV_LOG_WARNING, "Overflow during bit rate calculation %"PRId64" * 8 * %d\n", - sc->data_size, sc->time_scale); - st->codecpar->bit_rate = 0; - if (s->error_recognition & AV_EF_EXPLODE) - return AVERROR_INVALIDDATA; - } - } - } - } - - if (mov->use_mfra_for > 0) { + if (mov->trex_data || mov->use_mfra_for > 0) { for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; MOVStreamContext *sc = st->priv_data; @@ -9757,7 +10380,7 @@ static int mov_read_header(AVFormatContext *s) if (sc->stereo3d) { if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data, AV_PKT_DATA_STEREO3D, - (uint8_t *)sc->stereo3d, sizeof(*sc->stereo3d), 0)) + (uint8_t *)sc->stereo3d, sc->stereo3d_size, 0)) return AVERROR(ENOMEM); sc->stereo3d = NULL; @@ -9773,7 +10396,7 @@ static int mov_read_header(AVFormatContext *s) if (sc->mastering) { if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, - (uint8_t *)sc->mastering, sizeof(*sc->mastering), 0)) + (uint8_t *)sc->mastering, sc->mastering_size, 0)) return AVERROR(ENOMEM); sc->mastering = NULL; @@ -9903,25 +10526,73 @@ static int mov_change_extradata(AVStream *st, AVPacket *pkt) return 0; } -static int get_eia608_packet(AVIOContext *pb, AVPacket *pkt, int size) +static int get_eia608_packet(AVIOContext *pb, AVPacket *pkt, int src_size) { - int new_size, ret; + /* We can't make assumptions about the structure of the payload, + because it may include multiple cdat and cdt2 samples. */ + const uint32_t cdat = AV_RB32("cdat"); + const uint32_t cdt2 = AV_RB32("cdt2"); + int ret, out_size = 0; - if (size <= 8) + /* a valid payload must have size, 4cc, and at least 1 byte pair: */ + if (src_size < 10) return AVERROR_INVALIDDATA; - new_size = ((size - 8) / 2) * 3; - ret = av_new_packet(pkt, new_size); + + /* avoid an int overflow: */ + if ((src_size - 8) / 2 >= INT_MAX / 3) + return AVERROR_INVALIDDATA; + + ret = av_new_packet(pkt, ((src_size - 8) / 2) * 3); if (ret < 0) return ret; - avio_skip(pb, 8); - for (int j = 0; j < new_size; j += 3) { - pkt->data[j] = 0xFC; - pkt->data[j+1] = avio_r8(pb); - pkt->data[j+2] = avio_r8(pb); + /* parse and re-format the c608 payload in one pass. */ + while (src_size >= 10) { + const uint32_t atom_size = avio_rb32(pb); + const uint32_t atom_type = avio_rb32(pb); + const uint32_t data_size = atom_size - 8; + const uint8_t cc_field = + atom_type == cdat ? 1 : + atom_type == cdt2 ? 2 : + 0; + + /* account for bytes consumed for atom size and type. */ + src_size -= 8; + + /* make sure the data size stays within the buffer boundaries. */ + if (data_size < 2 || data_size > src_size) { + ret = AVERROR_INVALIDDATA; + break; + } + + /* make sure the data size is consistent with N byte pairs. */ + if (data_size % 2 != 0) { + ret = AVERROR_INVALIDDATA; + break; + } + + if (!cc_field) { + /* neither cdat or cdt2 ... skip it */ + avio_skip(pb, data_size); + src_size -= data_size; + continue; + } + + for (uint32_t i = 0; i < data_size; i += 2) { + pkt->data[out_size] = (0x1F << 3) | (1 << 2) | (cc_field - 1); + pkt->data[out_size + 1] = avio_r8(pb); + pkt->data[out_size + 2] = avio_r8(pb); + out_size += 3; + src_size -= 2; + } } - return 0; + if (src_size > 0) + /* skip any remaining unread portion of the input payload */ + avio_skip(pb, src_size); + + av_shrink_packet(pkt, out_size); + return ret; } static int mov_finalize_packet(AVFormatContext *s, AVStream *st, AVIndexEntry *sample, @@ -10030,6 +10701,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) if (st->codecpar->codec_id == AV_CODEC_ID_EIA_608 && sample->size > 8) ret = get_eia608_packet(sc->pb, pkt, sample->size); +#if CONFIG_IAMFDEC else if (sc->iamf) { int64_t pts, dts, pos, duration; int flags, size = sample->size; @@ -10052,7 +10724,9 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) } if (!ret) return FFERROR_REDO; - } else + } +#endif + else ret = av_get_packet(sc->pb, pkt, sample->size); if (ret < 0) { if (should_retry(sc->pb, ret)) { @@ -10172,7 +10846,7 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, { MOVStreamContext *sc = st->priv_data; FFStream *const sti = ffstream(st); - int sample, time_sample, ret; + int sample, time_sample, ret, next_ts, requested_sample; unsigned int i; // Here we consider timestamp to be PTS, hence try to offset it so that we @@ -10193,7 +10867,17 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, if (!sample || can_seek_to_key_sample(st, sample, timestamp)) break; - timestamp -= FFMAX(sc->min_sample_duration, 1); + + next_ts = timestamp - FFMAX(sc->min_sample_duration, 1); + requested_sample = av_index_search_timestamp(st, next_ts, flags); + + // If we've reached a different sample trying to find a good pts to + // seek to, give up searching because we'll end up seeking back to + // sample 0 on every seek. + if (sample != requested_sample && !can_seek_to_key_sample(st, requested_sample, next_ts)) + break; + + timestamp = next_ts; } mov_current_sample_set(sc, sample); diff --git a/libavformat/mov_chan.c b/libavformat/mov_chan.c index 287059d65..4484a22a1 100644 --- a/libavformat/mov_chan.c +++ b/libavformat/mov_chan.c @@ -23,10 +23,12 @@ * @author Justin Ruggles */ +#include #include #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavcodec/codec_id.h" #include "mov_chan.h" @@ -73,6 +75,44 @@ enum { c_Haptic = AV_CHAN_NONE, }; +enum { + iso_L = AV_CHAN_FRONT_LEFT, + iso_R = AV_CHAN_FRONT_RIGHT, + iso_C = AV_CHAN_FRONT_CENTER, + iso_LFE = AV_CHAN_LOW_FREQUENCY, + iso_Lsr = AV_CHAN_BACK_LEFT, + iso_Rsr = AV_CHAN_BACK_RIGHT, + iso_Lc = AV_CHAN_FRONT_LEFT_OF_CENTER, + iso_Rc = AV_CHAN_FRONT_RIGHT_OF_CENTER, + iso_Cs = AV_CHAN_BACK_CENTER, + iso_Ls = AV_CHAN_SIDE_LEFT, + iso_Rs = AV_CHAN_SIDE_RIGHT, + iso_Ts = AV_CHAN_TOP_CENTER, + iso_Lv = AV_CHAN_TOP_FRONT_LEFT, + iso_Cv = AV_CHAN_TOP_FRONT_CENTER, + iso_Rv = AV_CHAN_TOP_FRONT_RIGHT, + iso_Lvr = AV_CHAN_TOP_BACK_LEFT, + iso_Cvr = AV_CHAN_TOP_BACK_CENTER, + iso_Rvr = AV_CHAN_TOP_BACK_RIGHT, + // = AV_CHAN_STEREO_LEFT, + // = AV_CHAN_STEREO_RIGHT, + iso_Lw = AV_CHAN_WIDE_LEFT, + iso_Rw = AV_CHAN_WIDE_RIGHT, + iso_Lsd = AV_CHAN_SURROUND_DIRECT_LEFT, + iso_Rsd = AV_CHAN_SURROUND_DIRECT_RIGHT, + iso_LFE2 = AV_CHAN_LOW_FREQUENCY_2, + iso_Lvss = AV_CHAN_TOP_SIDE_LEFT, + iso_Rvss = AV_CHAN_TOP_SIDE_RIGHT, + iso_Cb = AV_CHAN_BOTTOM_FRONT_CENTER, + iso_Lb = AV_CHAN_BOTTOM_FRONT_LEFT, + iso_Rb = AV_CHAN_BOTTOM_FRONT_RIGHT, + iso_Lss = AV_CHAN_SIDE_SURROUND_LEFT, + iso_Rss = AV_CHAN_SIDE_SURROUND_RIGHT, + /* The following have no exact counterparts */ + iso_Lvs = AV_CHAN_NONE, + iso_Rvs = AV_CHAN_NONE, +}; + struct MovChannelLayoutMap { union { uint32_t tag; @@ -80,108 +120,142 @@ struct MovChannelLayoutMap { }; }; -#define TAG(_0) {.tag = _0} -#define ID(_0) {.id = c_##_0} -#define CHLIST(_0, ...) TAG(_0), __VA_ARGS__ -#define CHLIST01(_0, _1) CHLIST(_0, ID(_1)) -#define CHLIST02(_0, _1, _2) CHLIST(_0, ID(_1), ID(_2)) -#define CHLIST03(_0, _1, _2, _3) CHLIST(_0, ID(_1), ID(_2), ID(_3)) -#define CHLIST04(_0, _1, _2, _3, _4) CHLIST(_0, ID(_1), ID(_2), ID(_3), ID(_4)) -#define CHLIST05(_0, _1, _2, _3, _4, _5) CHLIST(_0, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5)) -#define CHLIST06(_0, _1, _2, _3, _4, _5, _6) CHLIST(_0, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6)) -#define CHLIST07(_0, _1, _2, _3, _4, _5, _6, _7) CHLIST(_0, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7)) -#define CHLIST08(_0, _1, _2, _3, _4, _5, _6, _7, _8) CHLIST(_0, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8)) -#define CHLIST09(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) CHLIST(_0, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9)) -#define CHLIST16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ - CHLIST(_0, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9), ID(_10), \ - ID(_11), ID(_12), ID(_13), ID(_14), ID(_15), ID(_16)) -#define CHLIST21(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21) \ - CHLIST(_0, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9), ID(_10), \ - ID(_11), ID(_12), ID(_13), ID(_14), ID(_15), ID(_16), ID(_17), ID(_18), ID(_19), ID(_20), ID(_21)) +#define TAG(_tag, _cnt) {.tag = _tag} +#define ID(_0) {.id = c_##_0} +#define CHLIST01(_tag, _1) CHLIST(_tag, 1, ID(_1)) +#define CHLIST02(_tag, _1, _2) CHLIST(_tag, 2, ID(_1), ID(_2)) +#define CHLIST03(_tag, _1, _2, _3) CHLIST(_tag, 3, ID(_1), ID(_2), ID(_3)) +#define CHLIST04(_tag, _1, _2, _3, _4) CHLIST(_tag, 4, ID(_1), ID(_2), ID(_3), ID(_4)) +#define CHLIST05(_tag, _1, _2, _3, _4, _5) CHLIST(_tag, 5, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5)) +#define CHLIST06(_tag, _1, _2, _3, _4, _5, _6) CHLIST(_tag, 6, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6)) +#define CHLIST07(_tag, _1, _2, _3, _4, _5, _6, _7) CHLIST(_tag, 7, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7)) +#define CHLIST08(_tag, _1, _2, _3, _4, _5, _6, _7, _8) CHLIST(_tag, 8, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8)) +#define CHLIST09(_tag, _1, _2, _3, _4, _5, _6, _7, _8, _9) CHLIST(_tag, 9, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9)) +#define CHLIST16(_tag, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ + CHLIST(_tag, 16, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9), ID(_10), \ + ID(_11), ID(_12), ID(_13), ID(_14), ID(_15), ID(_16)) +#define CHLIST21(_tag, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21) \ + CHLIST(_tag, 21, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9), ID(_10), \ + ID(_11), ID(_12), ID(_13), ID(_14), ID(_15), ID(_16), ID(_17), ID(_18), ID(_19), ID(_20), ID(_21)) +#define CHLIST24(_tag, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24) \ + CHLIST(_tag, 24, ID(_1), ID(_2), ID(_3), ID(_4), ID(_5), ID(_6), ID(_7), ID(_8), ID(_9), ID(_10), \ + ID(_11), ID(_12), ID(_13), ID(_14), ID(_15), ID(_16), ID(_17), ID(_18), ID(_19), ID(_20), \ + ID(_21), ID(_22), ID(_23), ID(_24)) +#define MOV_CH_LAYOUT_MAP \ + CHLIST01( MOV_CH_LAYOUT_MONO, C )\ + CHLIST02( MOV_CH_LAYOUT_STEREO, L, R )\ + CHLIST02( MOV_CH_LAYOUT_STEREOHEADPHONES, L, R )\ + CHLIST02( MOV_CH_LAYOUT_BINAURAL, L, R )\ + CHLIST02( MOV_CH_LAYOUT_MIDSIDE, L, R )\ + CHLIST02( MOV_CH_LAYOUT_XY, L, R )\ + CHLIST02( MOV_CH_LAYOUT_MATRIXSTEREO, Lt, Rt )\ + CHLIST02( MOV_CH_LAYOUT_AC3_1_0_1, C, LFE )\ + CHLIST03( MOV_CH_LAYOUT_MPEG_3_0_A, L, R, C )\ + CHLIST03( MOV_CH_LAYOUT_MPEG_3_0_B, C, L, R )\ + CHLIST03( MOV_CH_LAYOUT_AC3_3_0, L, C, R )\ + CHLIST03( MOV_CH_LAYOUT_ITU_2_1, L, R, Cs )\ + CHLIST03( MOV_CH_LAYOUT_DVD_4, L, R, LFE )\ + CHLIST04( MOV_CH_LAYOUT_AMBISONIC_B_FORMAT, W, X, Y, Z )\ + CHLIST04( MOV_CH_LAYOUT_QUADRAPHONIC, L, R, Rls, Rrs )\ + CHLIST04( MOV_CH_LAYOUT_MPEG_4_0_A, L, R, C, Cs )\ + CHLIST04( MOV_CH_LAYOUT_MPEG_4_0_B, C, L, R, Cs )\ + CHLIST04( MOV_CH_LAYOUT_AC3_3_1, L, C, R, Cs )\ + CHLIST04( MOV_CH_LAYOUT_ITU_2_2, L, R, Ls, Rs )\ + CHLIST04( MOV_CH_LAYOUT_DVD_5, L, R, LFE, Cs )\ + CHLIST04( MOV_CH_LAYOUT_AC3_2_1_1, L, R, Cs, LFE )\ + CHLIST04( MOV_CH_LAYOUT_DVD_10, L, R, C, LFE )\ + CHLIST04( MOV_CH_LAYOUT_AC3_3_0_1, L, C, R, LFE )\ + CHLIST04( MOV_CH_LAYOUT_DTS_3_1, C, L, R, LFE )\ + CHLIST05( MOV_CH_LAYOUT_PENTAGONAL, L, R, Rls, Rrs, C )\ + CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_A, L, R, C, Ls, Rs )\ + CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_B, L, R, Ls, Rs, C )\ + CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_C, L, C, R, Ls, Rs )\ + CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_D, C, L, R, Ls, Rs )\ + CHLIST05( MOV_CH_LAYOUT_DVD_6, L, R, LFE, Ls, Rs )\ + CHLIST05( MOV_CH_LAYOUT_DVD_18, L, R, Ls, Rs, LFE )\ + CHLIST05( MOV_CH_LAYOUT_DVD_11, L, R, C, LFE, Cs )\ + CHLIST05( MOV_CH_LAYOUT_AC3_3_1_1, L, C, R, Cs, LFE )\ + CHLIST05( MOV_CH_LAYOUT_DTS_4_1, C, L, R, Cs, LFE )\ + CHLIST06( MOV_CH_LAYOUT_HEXAGONAL, L, R, Rls, Rrs, C, Cs )\ + CHLIST06( MOV_CH_LAYOUT_DTS_6_0_C, C, Cs, L, R, Rls, Rrs )\ + CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_A, L, R, C, LFE, Ls, Rs )\ + CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_B, L, R, Ls, Rs, C, LFE )\ + CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_C, L, C, R, Ls, Rs, LFE )\ + CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_D, C, L, R, Ls, Rs, LFE )\ + CHLIST06( MOV_CH_LAYOUT_AUDIOUNIT_6_0, L, R, Ls, Rs, C, Cs )\ + CHLIST06( MOV_CH_LAYOUT_AAC_6_0, C, L, R, Ls, Rs, Cs )\ + CHLIST06( MOV_CH_LAYOUT_EAC3_6_0_A, L, C, R, Ls, Rs, Cs )\ + CHLIST06( MOV_CH_LAYOUT_DTS_6_0_A, Lc, Rc, L, R, Ls, Rs )\ + CHLIST06( MOV_CH_LAYOUT_DTS_6_0_B, C, L, R, Rls, Rrs, Ts )\ + CHLIST07( MOV_CH_LAYOUT_MPEG_6_1_A, L, R, C, LFE, Ls, Rs, Cs )\ + CHLIST07( MOV_CH_LAYOUT_AAC_6_1, C, L, R, Ls, Rs, Cs, LFE )\ + CHLIST07( MOV_CH_LAYOUT_EAC3_6_1_A, L, C, R, Ls, Rs, LFE, Cs )\ + CHLIST07( MOV_CH_LAYOUT_DTS_6_1_D, C, L, R, Ls, Rs, LFE, Cs )\ + CHLIST07( MOV_CH_LAYOUT_AUDIOUNIT_7_0, L, R, Ls, Rs, C, Rls, Rrs )\ + CHLIST07( MOV_CH_LAYOUT_AAC_7_0, C, L, R, Ls, Rs, Rls, Rrs )\ + CHLIST07( MOV_CH_LAYOUT_EAC3_7_0_A, L, C, R, Ls, Rs, Rls, Rrs )\ + CHLIST07( MOV_CH_LAYOUT_AUDIOUNIT_7_0_FRONT, L, R, Ls, Rs, C, Lc, Rc )\ + CHLIST07( MOV_CH_LAYOUT_DTS_7_0, Lc, C, Rc, L, R, Ls, Rs )\ + CHLIST07( MOV_CH_LAYOUT_EAC3_6_1_B, L, C, R, Ls, Rs, LFE, Ts )\ + CHLIST07( MOV_CH_LAYOUT_EAC3_6_1_C, L, C, R, Ls, Rs, LFE, Vhc )\ + CHLIST07( MOV_CH_LAYOUT_DTS_6_1_A, Lc, Rc, L, R, Ls, Rs, LFE )\ + CHLIST07( MOV_CH_LAYOUT_DTS_6_1_B, C, L, R, Rls, Rrs, Ts, LFE )\ + CHLIST07( MOV_CH_LAYOUT_DTS_6_1_C, C, Cs, L, R, Rls, Rrs, LFE )\ + CHLIST08( MOV_CH_LAYOUT_OCTAGONAL, L, R, Rls, Rrs, C, Cs, Ls, Rs )\ + CHLIST08( MOV_CH_LAYOUT_AAC_OCTAGONAL, C, L, R, Ls, Rs, Rls, Rrs, Cs )\ + CHLIST08( MOV_CH_LAYOUT_CUBE, L, R, Rls, Rrs, Vhl, Vhr, Rlt, Rrt )\ + CHLIST08( MOV_CH_LAYOUT_MPEG_7_1_A, L, R, C, LFE, Ls, Rs, Lc, Rc )\ + CHLIST08( MOV_CH_LAYOUT_MPEG_7_1_B, C, Lc, Rc, L, R, Ls, Rs, LFE )\ + CHLIST08( MOV_CH_LAYOUT_EMAGIC_DEFAULT_7_1, L, R, Ls, Rs, C, LFE, Lc, Rc )\ + CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_B, L, C, R, Ls, Rs, LFE, Lc, Rc )\ + CHLIST08( MOV_CH_LAYOUT_DTS_7_1, Lc, C, Rc, L, R, Ls, Rs, LFE )\ + CHLIST08( MOV_CH_LAYOUT_MPEG_7_1_C, L, R, C, LFE, Ls, Rs, Rls, Rrs )\ + CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_A, L, C, R, Ls, Rs, LFE, Rls, Rrs )\ + CHLIST08( MOV_CH_LAYOUT_SMPTE_DTV, L, R, C, LFE, Ls, Rs, Lt, Rt )\ + CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_C, L, C, R, Ls, Rs, LFE, Lsd, Rsd )\ + CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_D, L, C, R, Ls, Rs, LFE, Lw, Rw )\ + CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_E, L, C, R, Ls, Rs, LFE, Vhl, Vhr )\ + CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_F, L, C, R, Ls, Rs, LFE, Cs, Ts )\ + CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_G, L, C, R, Ls, Rs, LFE, Cs, Vhc )\ + CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_H, L, C, R, Ls, Rs, LFE, Ts, Vhc )\ + CHLIST08( MOV_CH_LAYOUT_DTS_8_0_A, Lc, Rc, L, R, Ls, Rs, Rls, Rrs )\ + CHLIST08( MOV_CH_LAYOUT_DTS_8_0_B, Lc, C, Rc, L, R, Ls, Cs, Rs )\ + CHLIST09( MOV_CH_LAYOUT_DTS_8_1_A, Lc, Rc, L, R, Ls, Rs, Rls, Rrs, LFE )\ + CHLIST09( MOV_CH_LAYOUT_DTS_8_1_B, Lc, C, Rc, L, R, Ls, Cs, Rs, LFE )\ + CHLIST16( MOV_CH_LAYOUT_TMH_10_2_STD, L, R, C, Vhc, Lsd, Rsd, Ls, Rs, Vhl, Vhr, Lw, Rw, Csd, Cs, LFE1, LFE2 )\ + CHLIST21( MOV_CH_LAYOUT_TMH_10_2_FULL, L, R, C, Vhc, Lsd, Rsd, Ls, Rs, Vhl, Vhr, Lw, Rw, Csd, Cs, LFE1, LFE2, Lc, Rc, HI, VI, Haptic )\ + +#define CHLIST(_tag, _cnt, ...) static_assert((_tag & 0xffff) == _cnt, "Channel count of " #_tag " is not " #_cnt); +MOV_CH_LAYOUT_MAP +#undef CHLIST +#define CHLIST(_tag, _cnt, ...) TAG(_tag, _cnt), __VA_ARGS__, static const struct MovChannelLayoutMap mov_ch_layout_map[] = { - CHLIST01( MOV_CH_LAYOUT_MONO, C ), - CHLIST02( MOV_CH_LAYOUT_STEREO, L, R ), - CHLIST02( MOV_CH_LAYOUT_STEREOHEADPHONES, L, R ), - CHLIST02( MOV_CH_LAYOUT_BINAURAL, L, R ), - CHLIST02( MOV_CH_LAYOUT_MIDSIDE, L, R ), //C, sides - CHLIST02( MOV_CH_LAYOUT_XY, L, R ), //X (left ), Y (right ) - CHLIST02( MOV_CH_LAYOUT_MATRIXSTEREO, Lt, Rt ), - CHLIST02( MOV_CH_LAYOUT_AC3_1_0_1, C, LFE ), - CHLIST03( MOV_CH_LAYOUT_MPEG_3_0_A, L, R, C ), - CHLIST03( MOV_CH_LAYOUT_MPEG_3_0_B, C, L, R ), - CHLIST03( MOV_CH_LAYOUT_AC3_3_0, L, C, R ), - CHLIST03( MOV_CH_LAYOUT_ITU_2_1, L, R, Cs ), - CHLIST03( MOV_CH_LAYOUT_DVD_4, L, R, LFE ), - CHLIST04( MOV_CH_LAYOUT_AMBISONIC_B_FORMAT, W, X, Y, Z ), - CHLIST04( MOV_CH_LAYOUT_QUADRAPHONIC, L, R, Rls, Rrs ), - CHLIST04( MOV_CH_LAYOUT_MPEG_4_0_A, L, R, C, Cs ), - CHLIST04( MOV_CH_LAYOUT_MPEG_4_0_B, C, L, R, Cs ), - CHLIST04( MOV_CH_LAYOUT_AC3_3_1, L, C, R, Cs ), - CHLIST04( MOV_CH_LAYOUT_ITU_2_2, L, R, Ls, Rs ), - CHLIST04( MOV_CH_LAYOUT_DVD_5, L, R, LFE, Cs ), - CHLIST04( MOV_CH_LAYOUT_AC3_2_1_1, L, R, Cs, LFE ), - CHLIST04( MOV_CH_LAYOUT_DVD_10, L, R, C, LFE ), - CHLIST04( MOV_CH_LAYOUT_AC3_3_0_1, L, C, R, LFE ), - CHLIST04( MOV_CH_LAYOUT_DTS_3_1, C, L, R, LFE ), - CHLIST05( MOV_CH_LAYOUT_PENTAGONAL, L, R, Rls, Rrs, C ), - CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_A, L, R, C, Ls, Rs ), - CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_B, L, R, Ls, Rs, C ), - CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_C, L, C, R, Ls, Rs ), - CHLIST05( MOV_CH_LAYOUT_MPEG_5_0_D, C, L, R, Ls, Rs ), - CHLIST05( MOV_CH_LAYOUT_DVD_6, L, R, LFE, Ls, Rs ), - CHLIST05( MOV_CH_LAYOUT_DVD_18, L, R, Ls, Rs, LFE ), - CHLIST05( MOV_CH_LAYOUT_DVD_11, L, R, C, LFE, Cs ), - CHLIST05( MOV_CH_LAYOUT_AC3_3_1_1, L, C, R, Cs, LFE ), - CHLIST05( MOV_CH_LAYOUT_DTS_4_1, C, L, R, Cs, LFE ), - CHLIST06( MOV_CH_LAYOUT_HEXAGONAL, L, R, Rls, Rrs, C, Cs ), - CHLIST06( MOV_CH_LAYOUT_DTS_6_0_C, C, Cs, L, R, Rls, Rrs ), - CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_A, L, R, C, LFE, Ls, Rs ), - CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_B, L, R, Ls, Rs, C, LFE ), - CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_C, L, C, R, Ls, Rs, LFE ), - CHLIST06( MOV_CH_LAYOUT_MPEG_5_1_D, C, L, R, Ls, Rs, LFE ), - CHLIST06( MOV_CH_LAYOUT_AUDIOUNIT_6_0, L, R, Ls, Rs, C, Cs ), - CHLIST06( MOV_CH_LAYOUT_AAC_6_0, C, L, R, Ls, Rs, Cs ), - CHLIST06( MOV_CH_LAYOUT_EAC3_6_0_A, L, C, R, Ls, Rs, Cs ), - CHLIST06( MOV_CH_LAYOUT_DTS_6_0_A, Lc, Rc, L, R, Ls, Rs ), - CHLIST06( MOV_CH_LAYOUT_DTS_6_0_B, C, L, R, Rls, Rrs, Ts ), - CHLIST07( MOV_CH_LAYOUT_MPEG_6_1_A, L, R, C, LFE, Ls, Rs, Cs ), - CHLIST07( MOV_CH_LAYOUT_AAC_6_1, C, L, R, Ls, Rs, Cs, LFE ), - CHLIST07( MOV_CH_LAYOUT_EAC3_6_1_A, L, C, R, Ls, Rs, LFE, Cs ), - CHLIST07( MOV_CH_LAYOUT_DTS_6_1_D, C, L, R, Ls, Rs, LFE, Cs ), - CHLIST07( MOV_CH_LAYOUT_AUDIOUNIT_7_0, L, R, Ls, Rs, C, Rls, Rrs ), - CHLIST07( MOV_CH_LAYOUT_AAC_7_0, C, L, R, Ls, Rs, Rls, Rrs ), - CHLIST07( MOV_CH_LAYOUT_EAC3_7_0_A, L, C, R, Ls, Rs, Rls, Rrs ), - CHLIST07( MOV_CH_LAYOUT_AUDIOUNIT_7_0_FRONT, L, R, Ls, Rs, C, Lc, Rc ), - CHLIST07( MOV_CH_LAYOUT_DTS_7_0, Lc, C, Rc, L, R, Ls, Rs ), - CHLIST07( MOV_CH_LAYOUT_EAC3_6_1_B, L, C, R, Ls, Rs, LFE, Ts ), - CHLIST07( MOV_CH_LAYOUT_EAC3_6_1_C, L, C, R, Ls, Rs, LFE, Vhc ), - CHLIST07( MOV_CH_LAYOUT_DTS_6_1_A, Lc, Rc, L, R, Ls, Rs, LFE ), - CHLIST07( MOV_CH_LAYOUT_DTS_6_1_B, C, L, R, Rls, Rrs, Ts, LFE ), - CHLIST07( MOV_CH_LAYOUT_DTS_6_1_C, C, Cs, L, R, Rls, Rrs, LFE ), - CHLIST08( MOV_CH_LAYOUT_OCTAGONAL, L, R, Rls, Rrs, C, Cs, Ls, Rs ), - CHLIST08( MOV_CH_LAYOUT_AAC_OCTAGONAL, C, L, R, Ls, Rs, Rls, Rrs, Cs ), - CHLIST08( MOV_CH_LAYOUT_CUBE, L, R, Rls, Rrs, Vhl, Vhr, Rlt, Rrt ), - CHLIST08( MOV_CH_LAYOUT_MPEG_7_1_A, L, R, C, LFE, Ls, Rs, Lc, Rc ), - CHLIST08( MOV_CH_LAYOUT_MPEG_7_1_B, C, Lc, Rc, L, R, Ls, Rs, LFE ), - CHLIST08( MOV_CH_LAYOUT_EMAGIC_DEFAULT_7_1, L, R, Ls, Rs, C, LFE, Lc, Rc ), - CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_B, L, C, R, Ls, Rs, LFE, Lc, Rc ), - CHLIST08( MOV_CH_LAYOUT_DTS_7_1, Lc, C, Rc, L, R, Ls, Rs, LFE ), - CHLIST08( MOV_CH_LAYOUT_MPEG_7_1_C, L, R, C, LFE, Ls, Rs, Rls, Rrs ), - CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_A, L, C, R, Ls, Rs, LFE, Rls, Rrs ), - CHLIST08( MOV_CH_LAYOUT_SMPTE_DTV, L, R, C, LFE, Ls, Rs, Lt, Rt ), - CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_C, L, C, R, Ls, Rs, LFE, Lsd, Rsd ), - CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_D, L, C, R, Ls, Rs, LFE, Lw, Rw ), - CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_E, L, C, R, Ls, Rs, LFE, Vhl, Vhr ), - CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_F, L, C, R, Ls, Rs, LFE, Cs, Ts ), - CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_G, L, C, R, Ls, Rs, LFE, Cs, Vhc ), - CHLIST08( MOV_CH_LAYOUT_EAC3_7_1_H, L, C, R, Ls, Rs, LFE, Ts, Vhc ), - CHLIST08( MOV_CH_LAYOUT_DTS_8_0_A, Lc, Rc, L, R, Ls, Rs, Rls, Rrs ), - CHLIST08( MOV_CH_LAYOUT_DTS_8_0_B, Lc, C, Rc, L, R, Ls, Cs, Rs ), - CHLIST09( MOV_CH_LAYOUT_DTS_8_1_A, Lc, Rc, L, R, Ls, Rs, Rls, Rrs, LFE ), - CHLIST09( MOV_CH_LAYOUT_DTS_8_1_B, Lc, C, Rc, L, R, Ls, Cs, Rs, LFE ), - CHLIST16( MOV_CH_LAYOUT_TMH_10_2_STD, L, R, C, Vhc, Lsd, Rsd, Ls, Rs, Vhl, Vhr, Lw, Rw, Csd, Cs, LFE1, LFE2), - CHLIST21( MOV_CH_LAYOUT_TMH_10_2_FULL, L, R, C, Vhc, Lsd, Rsd, Ls, Rs, Vhl, Vhr, Lw, Rw, Csd, Cs, LFE1, LFE2, Lc, Rc, HI, VI, Haptic), + MOV_CH_LAYOUT_MAP + { {0} }, +}; + +#undef ID +#undef TAG +#define ID(_0) {.id = iso_##_0} +#define TAG(_tag, _cnt) {.tag = (_tag << 16) | _cnt} + +/* ISO/IEC 23001-8 */ +static const struct MovChannelLayoutMap iso_ch_layout_map[] = { + CHLIST01( 1, C ) + CHLIST02( 2, L, R ) + CHLIST03( 3, C, L, R ) + CHLIST04( 4, C, L, R, Cs ) + CHLIST05( 5, C, L, R, Ls, Rs ) + CHLIST06( 6, C, L, R, Ls, Rs, LFE ) + CHLIST08( 7, C, Lc, Rc, L, R, Ls, Rs, LFE ) + CHLIST03( 9, L, R, Cs ) + CHLIST04( 10, L, R, Ls, Rs ) + CHLIST07( 11, C, L, R, Ls, Rs, Cs, LFE ) + CHLIST08( 12, C, L, R, Ls, Rs, Lsr, Rsr, LFE ) + CHLIST24( 13, C, Lc, Rc, L, R, Lss, Rss, Lsr, Rsr, Cs, LFE, LFE2, Cv, Lv, Rv, Lvss, Rvss, Ts, Lvr, Rvr, Cvr, Cb, Lb, Rb) + CHLIST08( 14, C, L, R, Ls, Rs, LFE, Lv, Rv) + { {0} }, }; static const enum MovChannelLayoutTag mov_ch_layouts_aac[] = { @@ -278,19 +352,11 @@ static const struct { { AV_CODEC_ID_NONE, NULL }, }; -static const struct MovChannelLayoutMap* find_layout_map(uint32_t tag) +static const struct MovChannelLayoutMap* find_layout_map(uint32_t tag, const struct MovChannelLayoutMap *map) { -#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 - { - int i; - for (i = 0; i < FF_ARRAY_ELEMS(mov_ch_layout_map); i += 1 + (mov_ch_layout_map[i].tag & 0xffff)) - av_assert2(mov_ch_layout_map[i].tag & 0xffff0000); - av_assert2(i == FF_ARRAY_ELEMS(mov_ch_layout_map)); - } -#endif - for (int i = 0; i < FF_ARRAY_ELEMS(mov_ch_layout_map); i += 1 + (mov_ch_layout_map[i].tag & 0xffff)) - if (mov_ch_layout_map[i].tag == tag) - return &mov_ch_layout_map[i + 1]; + for (int i = 0; map[i].tag & 0xffff; i += 1 + (map[i].tag & 0xffff)) + if (map[i].tag == tag) + return &map[i + 1]; return NULL; } @@ -302,25 +368,33 @@ static const struct MovChannelLayoutMap* find_layout_map(uint32_t tag) * @param[in] tag channel layout tag * @return <0 on error */ -static int mov_get_channel_layout(AVChannelLayout *ch_layout, uint32_t tag) +static int mov_get_channel_layout(AVChannelLayout *ch_layout, uint32_t tag, uint64_t omitted_channel_map, const struct MovChannelLayoutMap *map) { - int i, channels; const struct MovChannelLayoutMap *layout_map; - channels = tag & 0xFFFF; - /* find the channel layout for the specified layout tag */ - layout_map = find_layout_map(tag); + layout_map = find_layout_map(tag, map); if (layout_map) { int ret; + int map_layout_nb_channels = tag & 0xFFFF; + int nb_channels = ch_layout->nb_channels; + + /* Omitted channel bits must not exceed number of channels in map */ + if (omitted_channel_map >> map_layout_nb_channels) + return AVERROR_INVALIDDATA; + av_channel_layout_uninit(ch_layout); - ret = av_channel_layout_custom_init(ch_layout, channels); + ret = av_channel_layout_custom_init(ch_layout, nb_channels); if (ret < 0) return ret; - for (i = 0; i < channels; i++) { - enum AVChannel id = layout_map[i].id; - ch_layout->u.map[i].id = (id != AV_CHAN_NONE ? id : AV_CHAN_UNKNOWN); + + for (int i = 0, idx = 0; i < map_layout_nb_channels && idx < nb_channels; i++, omitted_channel_map >>= 1) { + if (!(omitted_channel_map & 1)) { + enum AVChannel id = layout_map[i].id; + ch_layout->u.map[idx++].id = (id != AV_CHAN_NONE ? id : AV_CHAN_UNKNOWN); + } } + return av_channel_layout_retype(ch_layout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL); } return 0; @@ -364,12 +438,34 @@ static uint32_t mov_get_channel_label(enum AVChannel channel) return 0; } +static int is_layout_valid_for_tag(const AVChannelLayout *ch_layout, uint32_t tag, const struct MovChannelLayoutMap *map) +{ + const struct MovChannelLayoutMap *layout_map; + int channels = ch_layout->nb_channels; + + /* get the layout map based on the channel count */ + if ((tag & 0xFFFF) != channels) + return 0; + + layout_map = find_layout_map(tag, map); + if (layout_map) { + int i; + for (i = 0; i < channels; i++) { + if (av_channel_layout_channel_from_index(ch_layout, i) != layout_map[i].id) + break; + } + if (i == channels) + return 1; + } + return 0; +} + int ff_mov_get_channel_layout_tag(const AVCodecParameters *par, uint32_t *layout, uint32_t *bitmap, uint32_t **pchannel_desc) { - int i, j; + int i; uint32_t tag = 0; const enum MovChannelLayoutTag *layouts = NULL; @@ -382,26 +478,11 @@ int ff_mov_get_channel_layout_tag(const AVCodecParameters *par, layouts = mov_codec_ch_layouts[i].layouts; if (layouts) { - int channels; - const struct MovChannelLayoutMap *layout_map; - - /* get the layout map based on the channel count */ - channels = par->ch_layout.nb_channels; - /* find the layout tag for the specified channel layout */ - for (i = 0; layouts[i] != 0; i++) { - if ((layouts[i] & 0xFFFF) != channels) - continue; - layout_map = find_layout_map(layouts[i]); - if (layout_map) { - for (j = 0; j < channels; j++) { - if (av_channel_layout_channel_from_index(&par->ch_layout, j) != layout_map[j].id) - break; - } - if (j == channels) - break; - } - } + for (i = 0; layouts[i] != 0; i++) + if (is_layout_valid_for_tag(&par->ch_layout, layouts[i], mov_ch_layout_map)) + break; + tag = layouts[i]; } @@ -462,10 +543,22 @@ int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st, return 0; if (layout_tag == MOV_CH_LAYOUT_USE_DESCRIPTIONS) { - int nb_channels = ch_layout->nb_channels ? ch_layout->nb_channels : num_descr; - if (num_descr > nb_channels) { - av_log(s, AV_LOG_WARNING, "got %d channel descriptions, capping to the number of channels %d\n", + int nb_channels = ch_layout->nb_channels; + + if (!num_descr || num_descr < nb_channels) { + av_log(s, AV_LOG_ERROR, "got %d channel descriptions when at least %d were needed\n", num_descr, nb_channels); + return AVERROR_INVALIDDATA; + } + + if (num_descr > nb_channels) { + int strict = s->strict_std_compliance >= FF_COMPLIANCE_STRICT; + av_log(s, strict ? AV_LOG_ERROR : AV_LOG_WARNING, + "got %d channel descriptions when number of channels is %d\n", + num_descr, nb_channels); + if (strict) + return AVERROR_INVALIDDATA; + av_log(s, AV_LOG_WARNING, "capping channel descriptions to the number of channels\n"); num_descr = nb_channels; } @@ -508,7 +601,7 @@ int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st, if (!ch_layout->nb_channels) ch_layout->nb_channels = nb_channels; if (nb_channels == ch_layout->nb_channels) { - ret = mov_get_channel_layout(ch_layout, layout_tag); + ret = mov_get_channel_layout(ch_layout, layout_tag, 0, mov_ch_layout_map); if (ret < 0) return ret; } else { @@ -524,185 +617,53 @@ out: return ret; } -/* ISO/IEC 23001-8, 8.2 */ -static const AVChannelLayout iso_channel_configuration[] = { - // 0: any setup - {0}, - - // 1: centre front - AV_CHANNEL_LAYOUT_MONO, - - // 2: left front, right front - AV_CHANNEL_LAYOUT_STEREO, - - // 3: centre front, left front, right front - AV_CHANNEL_LAYOUT_SURROUND, - - // 4: centre front, left front, right front, rear centre - AV_CHANNEL_LAYOUT_4POINT0, - - // 5: centre front, left front, right front, left surround, right surround - AV_CHANNEL_LAYOUT_5POINT0, - - // 6: 5 + LFE - AV_CHANNEL_LAYOUT_5POINT1, - - // 7: centre front, left front centre, right front centre, - // left front, right front, left surround, right surround, LFE - AV_CHANNEL_LAYOUT_7POINT1_WIDE, - - // 8: channel1, channel2 - AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, - - // 9: left front, right front, rear centre - AV_CHANNEL_LAYOUT_2_1, - - // 10: left front, right front, left surround, right surround - AV_CHANNEL_LAYOUT_2_2, - - // 11: centre front, left front, right front, left surround, right surround, rear centre, LFE - AV_CHANNEL_LAYOUT_6POINT1, - - // 12: centre front, left front, right front - // left surround, right surround - // rear surround left, rear surround right - // LFE - AV_CHANNEL_LAYOUT_7POINT1, - - // 13: - AV_CHANNEL_LAYOUT_22POINT2, - - // 14: - AV_CHANNEL_LAYOUT_7POINT1_TOP_BACK, - - // TODO: 15 - 20 -}; - /* ISO/IEC 23001-8, table 8 */ static const enum AVChannel iso_channel_position[] = { - // 0: left front - AV_CHAN_FRONT_LEFT, + [0] = AV_CHAN_FRONT_LEFT, // left front + [1] = AV_CHAN_FRONT_RIGHT, // right front + [2] = AV_CHAN_FRONT_CENTER, // centre front + [3] = AV_CHAN_LOW_FREQUENCY, // low frequency enhancement + [4] = AV_CHAN_SIDE_LEFT, // left surround + [5] = AV_CHAN_SIDE_RIGHT, // right surround + [6] = AV_CHAN_FRONT_LEFT_OF_CENTER, // left front centre + [7] = AV_CHAN_FRONT_RIGHT_OF_CENTER, // right front centre + [8] = AV_CHAN_BACK_LEFT, // rear surround left + [9] = AV_CHAN_BACK_RIGHT, // rear surround right + [10] = AV_CHAN_BACK_CENTER, // rear centre + [11] = AV_CHAN_SURROUND_DIRECT_LEFT, // left surround direct + [12] = AV_CHAN_SURROUND_DIRECT_RIGHT, // right surround direct + [13] = AV_CHAN_SIDE_SURROUND_LEFT, // left side surround + [14] = AV_CHAN_SIDE_SURROUND_RIGHT, // right side surround + [15] = AV_CHAN_WIDE_LEFT, // left wide front + [16] = AV_CHAN_WIDE_RIGHT, // right wide front + [17] = AV_CHAN_TOP_FRONT_LEFT, // left front vertical height + [18] = AV_CHAN_TOP_FRONT_RIGHT, // right front vertical height + [19] = AV_CHAN_TOP_FRONT_CENTER, // centre front vertical height + [20] = AV_CHAN_TOP_BACK_LEFT, // left surround vertical height rear + [21] = AV_CHAN_TOP_BACK_RIGHT, // right surround vertical height rear + [22] = AV_CHAN_TOP_BACK_CENTER, // centre vertical height rear + [23] = AV_CHAN_TOP_SIDE_LEFT, // left vertical height side surround + [24] = AV_CHAN_TOP_SIDE_RIGHT, // right vertical height side surround + [25] = AV_CHAN_TOP_CENTER, // top centre surround + [26] = AV_CHAN_LOW_FREQUENCY_2, // low frequency enhancement 2 + [27] = AV_CHAN_BOTTOM_FRONT_LEFT, // left front vertical bottom + [28] = AV_CHAN_BOTTOM_FRONT_RIGHT, // right front vertical bottom + [29] = AV_CHAN_BOTTOM_FRONT_CENTER, // centre front vertical bottom + [30] = AV_CHAN_TOP_SURROUND_LEFT, // left vertical height surround + [31] = AV_CHAN_TOP_SURROUND_RIGHT, // right vertical height surround - // 1: right front - AV_CHAN_FRONT_RIGHT, + [32] = AV_CHAN_NONE, // reserved + [33] = AV_CHAN_NONE, // reserved + [34] = AV_CHAN_NONE, // reserved + [35] = AV_CHAN_NONE, // reserved - // 2: centre front - AV_CHAN_FRONT_CENTER, - - // 3: low frequence enhancement - AV_CHAN_LOW_FREQUENCY, - - // 4: left surround - // TODO - AV_CHAN_NONE, - - // 5: right surround - // TODO - AV_CHAN_NONE, - - // 6: left front centre - AV_CHAN_FRONT_LEFT_OF_CENTER, - - // 7: right front centre - AV_CHAN_FRONT_RIGHT_OF_CENTER, - - // 8: rear surround left - AV_CHAN_BACK_LEFT, - - // 9: rear surround right - AV_CHAN_BACK_RIGHT, - - // 10: rear centre - AV_CHAN_BACK_CENTER, - - // 11: left surround direct - AV_CHAN_SURROUND_DIRECT_LEFT, - - // 12: right surround direct - AV_CHAN_SURROUND_DIRECT_RIGHT, - - // 13: left side surround - AV_CHAN_SIDE_LEFT, - - // 14: right side surround - AV_CHAN_SIDE_RIGHT, - - // 15: left wide front - AV_CHAN_WIDE_LEFT, - - // 16: right wide front - AV_CHAN_WIDE_RIGHT, - - // 17: left front vertical height - AV_CHAN_TOP_FRONT_LEFT, - - // 18: right front vertical height - AV_CHAN_TOP_FRONT_RIGHT, - - // 19: centre front vertical height - AV_CHAN_TOP_FRONT_CENTER, - - // 20: left surround vertical height rear - AV_CHAN_TOP_BACK_LEFT, - - // 21: right surround vertical height rear - AV_CHAN_TOP_BACK_RIGHT, - - // 22: centre vertical height rear - AV_CHAN_TOP_BACK_CENTER, - - // 23: left vertical height side surround - AV_CHAN_TOP_SIDE_LEFT, - - // 24: right vertical height side surround - AV_CHAN_TOP_SIDE_RIGHT, - - // 25: top centre surround - AV_CHAN_TOP_CENTER, - - // 26: low frequency enhancement 2 - AV_CHAN_LOW_FREQUENCY_2, - - // 27: left front vertical bottom - AV_CHAN_BOTTOM_FRONT_LEFT, - - // 28: right front vertical bottom - AV_CHAN_BOTTOM_FRONT_RIGHT, - - // 29: centre front vertical bottom - AV_CHAN_BOTTOM_FRONT_CENTER, - - // 30: left vertical height surround - // TODO - AV_CHAN_NONE, - - // 31: right vertical height surround - // TODO - AV_CHAN_NONE, - - // 32, 33, 34, 35, reserved - AV_CHAN_NONE, - AV_CHAN_NONE, - AV_CHAN_NONE, - AV_CHAN_NONE, - - // 36: low frequency enhancement 3 - AV_CHAN_NONE, - - // 37: left edge of screen - AV_CHAN_NONE, - // 38: right edge of screen - AV_CHAN_NONE, - // 39: half-way between centre of screen and left edge of screen - AV_CHAN_NONE, - // 40: half-way between centre of screen and right edge of screen - AV_CHAN_NONE, - - // 41: left back surround - AV_CHAN_NONE, - - // 42: right back surround - AV_CHAN_NONE, + [36] = AV_CHAN_NONE, // low frequency enhancement 3 + [37] = AV_CHAN_NONE, // left edge of screen + [38] = AV_CHAN_NONE, // right edge of screen + [39] = AV_CHAN_NONE, // half-way between centre of screen and left edge of screen + [40] = AV_CHAN_NONE, // half-way between centre of screen and right edge of screen + [41] = AV_CHAN_NONE, // left back surround + [42] = AV_CHAN_NONE, // right back surround // 43 - 125: reserved // 126: explicit position @@ -713,9 +674,9 @@ int ff_mov_get_channel_config_from_layout(const AVChannelLayout *layout, int *co { // Set default value which means any setup in 23001-8 *config = 0; - for (int i = 0; i < FF_ARRAY_ELEMS(iso_channel_configuration); i++) { - if (!av_channel_layout_compare(layout, iso_channel_configuration + i)) { - *config = i; + for (int i = 0; iso_ch_layout_map[i].tag & 0xffff; i += 1 + (iso_ch_layout_map[i].tag & 0xffff)) { + if (is_layout_valid_for_tag(layout, iso_ch_layout_map[i].tag, &iso_ch_layout_map[i])) { + *config = iso_ch_layout_map[i].tag >> 16; break; } } @@ -723,14 +684,19 @@ int ff_mov_get_channel_config_from_layout(const AVChannelLayout *layout, int *co return 0; } -int ff_mov_get_channel_layout_from_config(int config, AVChannelLayout *layout) +int ff_mov_get_channel_layout_from_config(int config, AVChannelLayout *layout, uint64_t omitted_channel_map) { - if (config > 0 && config < FF_ARRAY_ELEMS(iso_channel_configuration)) { - av_channel_layout_copy(layout, &iso_channel_configuration[config]); - return 0; - } + if (config > 0) { + uint32_t layout_tag; + int nb_omitted_channels = av_popcount64(omitted_channel_map); - return -1; + if (layout->nb_channels <= 0 || layout->nb_channels > UINT16_MAX - nb_omitted_channels) + return AVERROR_INVALIDDATA; + + layout_tag = (config << 16) | (layout->nb_channels + nb_omitted_channels); + return mov_get_channel_layout(layout, layout_tag, omitted_channel_map, iso_ch_layout_map); + } + return 1; } int ff_mov_get_channel_positions_from_layout(const AVChannelLayout *layout, @@ -804,13 +770,9 @@ int ff_mov_read_chnl(AVFormatContext *s, AVIOContext *pb, AVStream *st) return ret; } else { uint64_t omitted_channel_map = avio_rb64(pb); - - if (omitted_channel_map) { - avpriv_request_sample(s, "omitted_channel_map 0x%" PRIx64 " != 0", - omitted_channel_map); - return AVERROR_PATCHWELCOME; - } - ff_mov_get_channel_layout_from_config(layout, &st->codecpar->ch_layout); + ret = ff_mov_get_channel_layout_from_config(layout, &st->codecpar->ch_layout, omitted_channel_map); + if (ret < 0) + return ret; } } diff --git a/libavformat/mov_chan.h b/libavformat/mov_chan.h index e480809c4..ea8be4719 100644 --- a/libavformat/mov_chan.h +++ b/libavformat/mov_chan.h @@ -172,10 +172,11 @@ int ff_mov_get_channel_config_from_layout(const AVChannelLayout *layout, int *co /** * Get AVChannelLayout from ISO/IEC 23001-8 ChannelConfiguration. * - * @return 0 for success, -1 for doesn't match, layout is untouched on failure + * @return 1 if the config was unknown, layout is untouched in this case + * 0 if the config was found + * <0 on error */ - -int ff_mov_get_channel_layout_from_config(int config, AVChannelLayout *layout); +int ff_mov_get_channel_layout_from_config(int config, AVChannelLayout *layout, uint64_t omitted_channel_map); /** * Get ISO/IEC 23001-8 OutputChannelPosition from AVChannelLayout. diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 2d3a4db1d..d6effda6f 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -42,19 +42,18 @@ #include "libavcodec/flac.h" #include "libavcodec/get_bits.h" -#include "libavcodec/bsf.h" #include "libavcodec/internal.h" #include "libavcodec/put_bits.h" #include "libavcodec/vc1_common.h" #include "libavcodec/raw.h" #include "internal.h" #include "libavutil/avstring.h" -#include "libavutil/bprint.h" #include "libavutil/channel_layout.h" #include "libavutil/csp.h" #include "libavutil/intfloat.h" #include "libavutil/mathematics.h" #include "libavutil/libm.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/dict.h" #include "libavutil/pixdesc.h" @@ -64,6 +63,7 @@ #include "libavutil/uuid.h" #include "hevc.h" #include "rtpenc.h" +#include "nal.h" #include "mov_chan.h" #include "movenc_ttml.h" #include "mux.h" @@ -111,6 +111,7 @@ static const AVOption options[] = { { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_USE_MDTA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" }, { "write_colr", "Write colr atom even if the color info is unspecified (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" }, { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" }, + { "hybrid_fragmented", "For recoverability, write a fragmented file that is converted to non-fragmented at the end.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_HYBRID_FRAGMENTED}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" }, { "min_frag_duration", "Minimum fragment duration", offsetof(MOVMuxContext, min_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext, gamma), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM}, { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, @@ -319,6 +320,7 @@ static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track) return update_size(pb, pos); } +#if CONFIG_IAMFENC static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track) { AVIOContext *dyn_bc; @@ -344,6 +346,7 @@ static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra return update_size(pb, pos); } +#endif static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track) { @@ -734,6 +737,9 @@ static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track) // utilize values from properties if we have them available if (props) { + // no avg_bitrate signals that the track is VBR + if (!props->avg_bitrate) + bit_rates.avg_bit_rate = props->avg_bitrate; bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate, props->max_bitrate); bit_rates.buffer_size = props->buffer_size / 8; @@ -915,6 +921,64 @@ static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra return update_size(pb, pos); } +static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track) +{ + const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0); + AVChannelLayout ch_layout = { 0 }; + int64_t pos; + int ambisonic_order, ambi_channels, non_diegetic_channels; + int i, ret; + + if (!str) + return 0; + + ret = av_channel_layout_from_string(&ch_layout, str->value); + if (ret < 0) { + if (ret == AVERROR(EINVAL)) { +invalid: + av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value); + ret = 0; + } + av_channel_layout_uninit(&ch_layout); + return ret; + } + + if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels) + goto invalid; + + ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout); + if (ambisonic_order < 0) + goto invalid; + + ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL); + non_diegetic_channels = ch_layout.nb_channels - ambi_channels; + if (non_diegetic_channels && + (non_diegetic_channels != 2 || + av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO)) + goto invalid; + + av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value); + + pos = avio_tell(pb); + + avio_wb32(pb, 0); // Size + ffio_wfourcc(pb, "SA3D"); + avio_w8(pb, 0); // version + avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type + avio_wb32(pb, ambisonic_order); // ambisonic_order + avio_w8(pb, 0); // ambisonic_channel_ordering + avio_w8(pb, 0); // ambisonic_normalization + avio_wb32(pb, ch_layout.nb_channels); // num_channels + for (i = 0; i < ambi_channels; i++) + avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE); + for (; i < ch_layout.nb_channels; i++) + avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels); + + av_channel_layout_uninit(&ch_layout); + + return update_size(pb, pos); +} + static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track) { uint32_t layout_tag, bitmap, *channel_desc; @@ -1174,8 +1238,6 @@ static int get_samples_per_packet(MOVTrack *track) { int i, first_duration; -// return track->par->frame_size; - /* use 1 for raw PCM */ if (!track->audio_vbr) return 1; @@ -1245,8 +1307,7 @@ static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra if (config) { avio_wb64(pb, 0); } else { - for (int i = 0; i < layout->nb_channels; i++) - avio_w8(pb, speaker_pos[i]); + avio_write(pb, speaker_pos, layout->nb_channels); av_freep(&speaker_pos); } @@ -1392,8 +1453,10 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex ret = mov_write_wave_tag(s, pb, track); else if (track->tag == MKTAG('m','p','4','a')) ret = mov_write_esds_tag(pb, track); +#if CONFIG_IAMFENC else if (track->tag == MKTAG('i','a','m','f')) ret = mov_write_iacb_tag(mov->fc, pb, track); +#endif else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) ret = mov_write_amr_tag(pb, track); else if (track->par->codec_id == AV_CODEC_ID_AC3) @@ -1422,6 +1485,11 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex if (ret < 0) return ret; + if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO + && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) { + return ret; + } + if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) { return ret; @@ -1495,6 +1563,26 @@ static int mov_write_hvcc_tag(AVIOContext *pb, MOVTrack *track) return update_size(pb, pos); } +static int mov_write_lhvc_tag(AVIOContext *pb, MOVTrack *track) +{ + int64_t pos = avio_tell(pb); + int ret; + + avio_wb32(pb, 0); + ffio_wfourcc(pb, "lhvC"); + if (track->tag == MKTAG('h','v','c','1')) + ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 1); + else + ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 0); + + if (ret < 0) { + avio_seek(pb, pos, SEEK_SET); + return ret; + } + + return update_size(pb, pos); +} + static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track) { int64_t pos = avio_tell(pb); @@ -2108,6 +2196,149 @@ static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMa return update_size(pb, sv3d_pos); } +static inline int64_t rescale_rational(AVRational q, int b) +{ + return av_rescale(q.num, b, q.den); +} + +static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb, + const AVStereo3D *stereo3d) +{ + if (!stereo3d->horizontal_field_of_view.num) + return; + + avio_wb32(pb, 12); /* size */ + ffio_wfourcc(pb, "hfov"); + avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000)); +} + +static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb, + const AVSphericalMapping *spherical_mapping) +{ + avio_wb32(pb, 24); /* size */ + ffio_wfourcc(pb, "proj"); + avio_wb32(pb, 16); /* size */ + ffio_wfourcc(pb, "prji"); + avio_wb32(pb, 0); /* version + flags */ + + switch (spherical_mapping->projection) { + case AV_SPHERICAL_RECTILINEAR: + ffio_wfourcc(pb, "rect"); + break; + case AV_SPHERICAL_EQUIRECTANGULAR: + ffio_wfourcc(pb, "equi"); + break; + case AV_SPHERICAL_HALF_EQUIRECTANGULAR: + ffio_wfourcc(pb, "hequ"); + break; + case AV_SPHERICAL_FISHEYE: + ffio_wfourcc(pb, "fish"); + break; + default: + av_assert0(0); + } +} + +static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb, + const AVStereo3D *stereo3d) +{ + int64_t pos = avio_tell(pb); + int view = 0; + + avio_wb32(pb, 0); /* size */ + ffio_wfourcc(pb, "eyes"); + + // stri is mandatory + avio_wb32(pb, 13); /* size */ + ffio_wfourcc(pb, "stri"); + avio_wb32(pb, 0); /* version + flags */ + switch (stereo3d->view) { + case AV_STEREO3D_VIEW_LEFT: + view |= 1 << 0; + break; + case AV_STEREO3D_VIEW_RIGHT: + view |= 1 << 1; + break; + case AV_STEREO3D_VIEW_PACKED: + view |= (1 << 0) | (1 << 1); + break; + } + view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3; + avio_w8(pb, view); + + // hero is optional + if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) { + avio_wb32(pb, 13); /* size */ + ffio_wfourcc(pb, "hero"); + avio_wb32(pb, 0); /* version + flags */ + avio_w8(pb, stereo3d->primary_eye); + } + + // it's not clear if cams is mandatory or optional + if (stereo3d->baseline) { + avio_wb32(pb, 24); /* size */ + ffio_wfourcc(pb, "cams"); + avio_wb32(pb, 16); /* size */ + ffio_wfourcc(pb, "blin"); + avio_wb32(pb, 0); /* version + flags */ + avio_wb32(pb, stereo3d->baseline); + } + + // it's not clear if cmfy is mandatory or optional + if (stereo3d->horizontal_disparity_adjustment.num) { + avio_wb32(pb, 24); /* size */ + ffio_wfourcc(pb, "cmfy"); + avio_wb32(pb, 16); /* size */ + ffio_wfourcc(pb, "dadj"); + avio_wb32(pb, 0); /* version + flags */ + avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000)); + } + + return update_size(pb, pos); +} + +static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb, + const AVStereo3D *stereo3d, + const AVSphericalMapping *spherical_mapping) +{ + int64_t pos; + + if (spherical_mapping && + spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR && + spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR && + spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR && + spherical_mapping->projection != AV_SPHERICAL_FISHEYE) { + av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n", + spherical_mapping->projection); + spherical_mapping = NULL; + } + + if (stereo3d && (stereo3d->type == AV_STEREO3D_2D || + (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) && + stereo3d->view == AV_STEREO3D_VIEW_UNSPEC && + stereo3d->primary_eye == AV_PRIMARY_EYE_NONE && + !stereo3d->baseline && + !stereo3d->horizontal_disparity_adjustment.num))) { + av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n"); + stereo3d = NULL; + } + + if (!spherical_mapping && !stereo3d) + return 0; + + pos = avio_tell(pb); + avio_wb32(pb, 0); /* size */ + ffio_wfourcc(pb, "vexu"); + + if (spherical_mapping) + mov_write_vexu_proj_tag(s, pb, spherical_mapping); + + if (stereo3d) + mov_write_eyes_tag(s, pb, stereo3d); + + return update_size(pb, pos); +} + static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi) { uint8_t buf[ISOM_DVCC_DVVC_SIZE]; @@ -2126,18 +2357,31 @@ static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDe return 32; /* 8 + 24 */ } -static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track) +static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track, + uint32_t top, uint32_t bottom, + uint32_t left, uint32_t right) { + uint32_t cropped_width = track->par->width - left - right; + uint32_t cropped_height = track->height - top - bottom; + AVRational horizOff = + av_sub_q((AVRational) { track->par->width - cropped_width, 2 }, + (AVRational) { left, 1 }); + AVRational vertOff = + av_sub_q((AVRational) { track->height - cropped_height, 2 }, + (AVRational) { top, 1 }); + avio_wb32(pb, 40); ffio_wfourcc(pb, "clap"); - avio_wb32(pb, track->par->width); /* apertureWidth_N */ - avio_wb32(pb, 1); /* apertureWidth_D (= 1) */ - avio_wb32(pb, track->height); /* apertureHeight_N */ - avio_wb32(pb, 1); /* apertureHeight_D (= 1) */ - avio_wb32(pb, 0); /* horizOff_N (= 0) */ - avio_wb32(pb, 1); /* horizOff_D (= 1) */ - avio_wb32(pb, 0); /* vertOff_N (= 0) */ - avio_wb32(pb, 1); /* vertOff_D (= 1) */ + avio_wb32(pb, cropped_width); /* apertureWidthN */ + avio_wb32(pb, 1); /* apertureWidthD */ + avio_wb32(pb, cropped_height); /* apertureHeightN */ + avio_wb32(pb, 1); /* apertureHeightD */ + + avio_wb32(pb, -horizOff.num); + avio_wb32(pb, horizOff.den); + avio_wb32(pb, -vertOff.num); + avio_wb32(pb, vertOff.den); + return 40; } @@ -2244,11 +2488,6 @@ static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track) return 12; } -static inline int64_t rescale_rational(AVRational q, int b) -{ - return av_rescale(q.num, b, q.den); -} - static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track) { const int chroma_den = 50000; @@ -2370,6 +2609,7 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex { int ret = AVERROR_BUG; int64_t pos = avio_tell(pb); + const AVPacketSideData *sd; char compressor_name[32] = { 0 }; int avid = 0; @@ -2461,9 +2701,14 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) { mov_write_avid_tag(pb, track); avid = 1; - } else if (track->par->codec_id == AV_CODEC_ID_HEVC) + } else if (track->par->codec_id == AV_CODEC_ID_HEVC) { mov_write_hvcc_tag(pb, track); - else if (track->par->codec_id == AV_CODEC_ID_VVC) + if (track->st->disposition & AV_DISPOSITION_MULTILAYER) { + ret = mov_write_lhvc_tag(pb, track); + if (ret < 0) + av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n"); + } + } else if (track->par->codec_id == AV_CODEC_ID_VVC) mov_write_vvcc_tag(pb, track); else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) { mov_write_avcc_tag(pb, track); @@ -2530,25 +2775,68 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data, AV_PKT_DATA_SPHERICAL); - const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data, - track->st->codecpar->nb_coded_side_data, - AV_PKT_DATA_DOVI_CONF); - if (stereo_3d) mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data); if (spherical_mapping) mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data); - if (dovi) + } + + if (track->mode == MODE_MOV || (track->mode == MODE_MP4 && + mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) { + const AVStereo3D *stereo3d = NULL; + const AVSphericalMapping *spherical_mapping = NULL; + + sd = av_packet_side_data_get(track->st->codecpar->coded_side_data, + track->st->codecpar->nb_coded_side_data, + AV_PKT_DATA_STEREO3D); + if (sd) + stereo3d = (AVStereo3D *)sd->data; + + sd = av_packet_side_data_get(track->st->codecpar->coded_side_data, + track->st->codecpar->nb_coded_side_data, + AV_PKT_DATA_SPHERICAL); + if (sd) + spherical_mapping = (AVSphericalMapping *)sd->data; + + if (stereo3d || spherical_mapping) + mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping); + if (stereo3d) + mov_write_hfov_tag(s, pb, stereo3d); + } + + if (track->mode == MODE_MP4) { + const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data, + track->st->codecpar->nb_coded_side_data, + AV_PKT_DATA_DOVI_CONF); + if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data); + } else if (dovi) { + av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n"); + } } if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) { mov_write_pasp_tag(pb, track); } - if (uncompressed_ycbcr){ - mov_write_clap_tag(pb, track); - } + sd = av_packet_side_data_get(track->st->codecpar->coded_side_data, + track->st->codecpar->nb_coded_side_data, + AV_PKT_DATA_FRAME_CROPPING); + if (sd && sd->size >= sizeof(uint32_t) * 4) { + uint64_t top = AV_RL32(sd->data + 0); + uint64_t bottom = AV_RL32(sd->data + 4); + uint64_t left = AV_RL32(sd->data + 8); + uint64_t right = AV_RL32(sd->data + 12); + + if ((left + right) >= track->par->width || + (top + bottom) >= track->height) { + av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n"); + return AVERROR(EINVAL); + } + if (top || bottom || left || right) + mov_write_clap_tag(pb, track, top, bottom, left, right); + } else if (uncompressed_ycbcr) + mov_write_clap_tag(pb, track, 0, 0, 0, 0); if (mov->encryption_scheme != MOV_ENC_NONE) { ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid); @@ -2908,6 +3196,7 @@ static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO || track->par->codec_id == AV_CODEC_ID_TRUEHD || track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO || + (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) || track->par->codec_tag == MKTAG('r','t','p',' ')) && track->has_keyframes && track->has_keyframes < track->entry) mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE); @@ -4659,11 +4948,15 @@ static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s) mov->tracks[i].track_id = i >= mov->nb_streams ? ++next_generated_track_id : mov->tracks[i].st->id; } } else { + int last_track_id = 0; for (i = 0; i < mov->nb_tracks; i++) { if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) continue; - mov->tracks[i].track_id = i + 1; + last_track_id = + mov->tracks[i].track_id = (mov->tracks[i].st + ? FFMAX(mov->tracks[i].st->index, last_track_id) + : FFMAX(i, last_track_id)) + 1; } } @@ -5524,9 +5817,10 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) { MOVMuxContext *mov = s->priv_data; int64_t pos = avio_tell(pb); - int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0; + int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0; int has_iamf = 0; +#if CONFIG_IAMFENC for (int i = 0; i < s->nb_stream_groups; i++) { const AVStreamGroup *stg = s->stream_groups[i]; @@ -5536,6 +5830,7 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) break; } } +#endif for (int i = 0; i < mov->nb_streams; i++) { AVStream *st = mov->tracks[i].st; if (is_cover_image(st)) @@ -5553,6 +5848,8 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) st->codecpar->nb_coded_side_data, AV_PKT_DATA_DOVI_CONF)) has_dolby = 1; + if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) + has_id3 = 1; } avio_wb32(pb, 0); /* size */ @@ -5632,6 +5929,9 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) ffio_wfourcc(pb, "dash"); + if (has_id3) + ffio_wfourcc(pb, "aid3"); + return update_size(pb, pos); } @@ -5922,11 +6222,41 @@ static int mov_write_squashed_packets(AVFormatContext *s) return 0; } +static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track, + int64_t ref_pos) +{ + int i; + if (!track->entry) + return 0; + if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) { + for (i = 0; i < track->entry; i++) + track->cluster[i].pos += ref_pos + track->data_offset; + if (track->cluster_written == 0 && !(mov->flags & FF_MOV_FLAG_EMPTY_MOOV)) { + // First flush. If this was a case of not using empty moov, reset chunking. + for (i = 0; i < track->entry; i++) { + track->cluster[i].chunkNum = 0; + track->cluster[i].samples_in_chunk = track->cluster[i].entries; + } + } + if (av_reallocp_array(&track->cluster_written, + track->entry_written + track->entry, + sizeof(*track->cluster))) + return AVERROR(ENOMEM); + memcpy(&track->cluster_written[track->entry_written], + track->cluster, track->entry * sizeof(*track->cluster)); + track->entry_written += track->entry; + } + track->entry = 0; + track->entries_flushed = 0; + track->end_reliable = 0; + return 0; +} + static int mov_flush_fragment(AVFormatContext *s, int force) { MOVMuxContext *mov = s->priv_data; int i, first_track = -1; - int64_t mdat_size = 0; + int64_t mdat_size = 0, mdat_start = 0; int ret; int has_video = 0, starts_with_key = 0, first_video_track = 1; @@ -6031,10 +6361,8 @@ static int mov_flush_fragment(AVFormatContext *s, int force) mov->moov_written = 1; mov->mdat_size = 0; - for (i = 0; i < mov->nb_tracks; i++) { - mov->tracks[i].entry = 0; - mov->tracks[i].end_reliable = 0; - } + for (i = 0; i < mov->nb_tracks; i++) + mov_finish_fragment(mov, &mov->tracks[i], 0); avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT); return 0; } @@ -6103,11 +6431,10 @@ static int mov_flush_fragment(AVFormatContext *s, int force) avio_wb32(s->pb, mdat_size + 8); ffio_wfourcc(s->pb, "mdat"); + mdat_start = avio_tell(s->pb); } - track->entry = 0; - track->entries_flushed = 0; - track->end_reliable = 0; + mov_finish_fragment(mov, &mov->tracks[i], mdat_start); if (!mov->frag_interleave) { if (!track->mdat_buf) continue; @@ -6305,7 +6632,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) /* from x264 or from bytestream H.264 */ /* NAL reformatting needed */ if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) { - ret = ff_avc_parse_nal_units_buf(pkt->data, &reformatted_data, + ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data, &size); if (ret < 0) return ret; @@ -6318,7 +6645,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) goto err; } } else { - size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size); + size = ff_nal_parse_units(pb, pkt->data, pkt->size); } } } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->vos_len > 6 && @@ -6662,8 +6989,10 @@ static int mov_write_subtitle_end_packet(AVFormatContext *s, return ret; } +#if CONFIG_IAMFENC static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt) { + uint8_t *data; int ret; if (pkt->stream_index == trk->first_iamf_idx) { @@ -6677,40 +7006,63 @@ static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pk if (ret < 0) return ret; - if (pkt->stream_index == trk->last_iamf_idx) { - uint8_t *data; + if (pkt->stream_index != trk->last_iamf_idx) + return AVERROR(EAGAIN); - ret = avio_close_dyn_buf(trk->iamf_buf, &data); - trk->iamf_buf = NULL; - - if (!ret) { - if (pkt->size) { - // Either all or none of the packets for a single - // IA Sample may be empty. - av_log(s, AV_LOG_ERROR, "Unexpected packet from " - "stream #%d\n", pkt->stream_index); - ret = AVERROR_INVALIDDATA; - } - av_free(data); - return ret; + ret = avio_close_dyn_buf(trk->iamf_buf, &data); + trk->iamf_buf = NULL; + if (!ret) { + if (pkt->size) { + // Either all or none of the packets for a single + // IA Sample may be empty. + av_log(s, AV_LOG_ERROR, "Unexpected packet from " + "stream #%d\n", pkt->stream_index); + ret = AVERROR_INVALIDDATA; } - av_buffer_unref(&pkt->buf); - pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0); - if (!pkt->buf) { - av_free(data); - return AVERROR(ENOMEM); - } - pkt->data = data; - pkt->size = ret; - pkt->stream_index = trk->first_iamf_idx; + av_free(data); + return ret; + } - ret = avio_open_dyn_buf(&trk->iamf_buf); - if (ret < 0) - return ret; - } else - ret = AVERROR(EAGAIN); + av_buffer_unref(&pkt->buf); + pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0); + if (!pkt->buf) { + av_free(data); + return AVERROR(ENOMEM); + } + pkt->data = data; + pkt->size = ret; + pkt->stream_index = trk->first_iamf_idx; - return ret; + return avio_open_dyn_buf(&trk->iamf_buf); +} +#endif + +static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt) +{ + int64_t pos = avio_tell(pb); + const char *scheme_id_uri = "https://aomedia.org/emsg/ID3"; + const char *value = ""; + + av_assert0(st->time_base.num == 1); + + avio_write_marker(pb, + av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q), + AVIO_DATA_MARKER_BOUNDARY_POINT); + + avio_wb32(pb, 0); /* size */ + ffio_wfourcc(pb, "emsg"); + avio_w8(pb, 1); /* version */ + avio_wb24(pb, 0); + avio_wb32(pb, st->time_base.den); /* timescale */ + avio_wb64(pb, pkt->pts); /* presentation_time */ + avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */ + avio_wb32(pb, 0); /* id */ + /* null terminated UTF8 strings */ + avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1); + avio_write(pb, value, strlen(value) + 1); + avio_write(pb, pkt->data, pkt->size); + + return update_size(pb, pos); } static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) @@ -6723,8 +7075,14 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) return 1; } + if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) { + mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt); + return 0; + } + trk = s->streams[pkt->stream_index]->priv_data; +#if CONFIG_IAMFENC if (trk->iamf) { int ret = mov_build_iamf_packet(s, trk, pkt); if (ret < 0) { @@ -6735,6 +7093,7 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) return ret; } } +#endif if (is_cover_image(trk->st)) { int ret; @@ -7060,6 +7419,7 @@ static void mov_free(AVFormatContext *s) else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) av_freep(&track->par); av_freep(&track->cluster); + av_freep(&track->cluster_written); av_freep(&track->frag_info); av_packet_free(&track->cover_image); @@ -7074,10 +7434,12 @@ static void mov_free(AVFormatContext *s) ff_mov_cenc_free(&track->cenc); ffio_free_dyn_buf(&track->mdat_buf); +#if CONFIG_IAMFENC ffio_free_dyn_buf(&track->iamf_buf); if (track->iamf) ff_iamf_uninit_context(track->iamf); av_freep(&track->iamf); +#endif avpriv_packet_list_free(&track->squashed_packet_queue); } @@ -7152,10 +7514,13 @@ static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track, return 0; } +#if CONFIG_IAMFENC static int mov_init_iamf_track(AVFormatContext *s) { MOVMuxContext *mov = s->priv_data; - MOVTrack *track = &mov->tracks[0]; // IAMF if present is always the first track + MOVTrack *track; + IAMFContext *iamf; + int first_iamf_idx = INT_MAX, last_iamf_idx = 0; int nb_audio_elements = 0, nb_mix_presentations = 0; int ret; @@ -7177,24 +7542,24 @@ static int mov_init_iamf_track(AVFormatContext *s) return AVERROR(EINVAL); } - track->iamf = av_mallocz(sizeof(*track->iamf)); - if (!track->iamf) + iamf = av_mallocz(sizeof(*iamf)); + if (!iamf) return AVERROR(ENOMEM); + for (int i = 0; i < s->nb_stream_groups; i++) { const AVStreamGroup *stg = s->stream_groups[i]; switch(stg->type) { case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: for (int j = 0; j < stg->nb_streams; j++) { - track->first_iamf_idx = FFMIN(stg->streams[j]->index, track->first_iamf_idx); - track->last_iamf_idx = FFMAX(stg->streams[j]->index, track->last_iamf_idx); - stg->streams[j]->priv_data = track; + first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx); + last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx); } - ret = ff_iamf_add_audio_element(track->iamf, stg, s); + ret = ff_iamf_add_audio_element(iamf, stg, s); break; case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: - ret = ff_iamf_add_mix_presentation(track->iamf, stg, s); + ret = ff_iamf_add_mix_presentation(iamf, stg, s); break; default: av_assert0(0); @@ -7203,18 +7568,32 @@ static int mov_init_iamf_track(AVFormatContext *s) return ret; } + track = &mov->tracks[first_iamf_idx]; + track->iamf = iamf; + track->first_iamf_idx = first_iamf_idx; + track->last_iamf_idx = last_iamf_idx; track->tag = MKTAG('i','a','m','f'); + for (int i = 0; i < s->nb_stream_groups; i++) { + AVStreamGroup *stg = s->stream_groups[i]; + if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT) + continue; + for (int j = 0; j < stg->nb_streams; j++) + stg->streams[j]->priv_data = track; + } + ret = avio_open_dyn_buf(&track->iamf_buf); if (ret < 0) return ret; return 0; } +#endif static int mov_init(AVFormatContext *s) { MOVMuxContext *mov = s->priv_data; + int has_iamf = 0; int i, ret; mov->fc = s; @@ -7250,6 +7629,9 @@ static int mov_init(AVFormatContext *s) mov->flags |= FF_MOV_FLAG_FRAGMENT; /* Set other implicit flags immediately */ + if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) + mov->flags |= FF_MOV_FLAG_FRAGMENT; + if (mov->mode == MODE_ISM) mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF | FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS; @@ -7285,19 +7667,11 @@ static int mov_init(AVFormatContext *s) s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) mov->use_editlist = 0; } - if (mov->flags & FF_MOV_FLAG_CMAF) { - // CMAF Track requires negative cts offsets without edit lists - mov->use_editlist = 0; - } } if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist) av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n"); - if (mov->flags & FF_MOV_FLAG_CMAF && mov->use_editlist) { - av_log(s, AV_LOG_WARNING, "Edit list enabled; Assuming writing CMAF Track File\n"); - mov->flags &= ~FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS; - } if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)) s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO; @@ -7349,6 +7723,7 @@ static int mov_init(AVFormatContext *s) s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT; } +#if CONFIG_IAMFENC for (i = 0; i < s->nb_stream_groups; i++) { AVStreamGroup *stg = s->stream_groups[i]; @@ -7365,15 +7740,23 @@ static int mov_init(AVFormatContext *s) } st->priv_data = st; } + has_iamf = 1; if (!mov->nb_tracks) // We support one track for the entire IAMF structure mov->nb_tracks++; } +#endif for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; if (st->priv_data) continue; + // Don't produce a track in the output file for timed ID3 streams. + if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) { + // Leave priv_data set to NULL for these AVStreams that don't + // have a corresponding track. + continue; + } st->priv_data = st; mov->nb_tracks++; } @@ -7454,15 +7837,20 @@ static int mov_init(AVFormatContext *s) } } +#if CONFIG_IAMFENC ret = mov_init_iamf_track(s); if (ret < 0) return ret; +#endif for (int j = 0, i = 0; j < s->nb_streams; j++) { AVStream *st = s->streams[j]; - if (st != st->priv_data) + if (st != st->priv_data) { + if (has_iamf) + i += has_iamf--; continue; + } st->priv_data = &mov->tracks[i++]; } @@ -7471,6 +7859,9 @@ static int mov_init(AVFormatContext *s) MOVTrack *track = st->priv_data; AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0); + if (!track) + continue; + if (!track->st) { track->st = st; track->par = st->codecpar; @@ -7761,6 +8152,11 @@ static int mov_write_header(AVFormatContext *s) FF_MOV_FLAG_FRAG_EVERY_FRAME)) && !mov->max_fragment_duration && !mov->max_fragment_size) mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME; + if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) { + avio_wb32(pb, 8); // placeholder for extended size field (64 bit) + ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free"); + mov->mdat_pos = avio_tell(pb); + } } else if (mov->mode != MODE_AVIF) { if (mov->flags & FF_MOV_FLAG_FASTSTART) mov->reserved_header_pos = avio_tell(pb); @@ -7964,13 +8360,34 @@ static int mov_write_trailer(AVFormatContext *s) } } - if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) { + if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || + mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) { + if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) { + mov_flush_fragment(s, 1); + mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8; + for (i = 0; i < mov->nb_tracks; i++) { + MOVTrack *track = &mov->tracks[i]; + track->data_offset = 0; + av_free(track->cluster); + track->cluster = track->cluster_written; + track->entry = track->entry_written; + track->cluster_written = NULL; + track->entry_written = 0; + track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks + } + // Clear the empty_moov flag, as we do want the moov to include + // all the samples at this point. + mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV; + } + moov_pos = avio_tell(pb); /* Write size of mdat tag */ if (mov->mdat_size + 8 <= UINT32_MAX) { avio_seek(pb, mov->mdat_pos, SEEK_SET); avio_wb32(pb, mov->mdat_size + 8); + if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) + ffio_wfourcc(pb, "mdat"); // overwrite the original moov into a mdat } else { /* overwrite 'wide' placeholder atom */ avio_seek(pb, mov->mdat_pos - 8, SEEK_SET); @@ -8242,11 +8659,11 @@ const FFOutputFormat ff_mov_muxer = { .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, .deinit = mov_free, + .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS #if FF_API_ALLOW_FLUSH - .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, -#else - .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE, + | AVFMT_ALLOW_FLUSH #endif + , .p.codec_tag = (const AVCodecTag* const []){ ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0 }, @@ -8294,11 +8711,11 @@ const FFOutputFormat ff_mp4_muxer = { .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, .deinit = mov_free, + .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS #if FF_API_ALLOW_FLUSH - .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, -#else - .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE, + | AVFMT_ALLOW_FLUSH #endif + , .p.codec_tag = mp4_codec_tags_list, .check_bitstream = mov_check_bitstream, .p.priv_class = &mov_isobmff_muxer_class, diff --git a/libavformat/movenc.h b/libavformat/movenc.h index 08d580594..d73f7f314 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -85,7 +85,7 @@ typedef struct MOVFragmentInfo { typedef struct MOVTrack { int mode; - int entry; + int entry, entry_written; unsigned timescale; uint64_t time; int64_t track_duration; @@ -114,6 +114,7 @@ typedef struct MOVTrack { int vos_len; uint8_t *vos_data; MOVIentry *cluster; + MOVIentry *cluster_written; unsigned cluster_capacity; int audio_vbr; int height; ///< active picture (w/o VBI) height for D-10/IMX @@ -282,6 +283,7 @@ typedef struct MOVMuxContext { #define FF_MOV_FLAG_SKIP_SIDX (1 << 21) #define FF_MOV_FLAG_CMAF (1 << 22) #define FF_MOV_FLAG_PREFER_ICC (1 << 23) +#define FF_MOV_FLAG_HYBRID_FRAGMENTED (1 << 24) int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt); diff --git a/libavformat/movenc_ttml.c b/libavformat/movenc_ttml.c index 6deae4965..413eccfc0 100644 --- a/libavformat/movenc_ttml.c +++ b/libavformat/movenc_ttml.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "isom.h" diff --git a/libavformat/movenccenc.c b/libavformat/movenccenc.c index 74f3c4ccf..1b7a77380 100644 --- a/libavformat/movenccenc.c +++ b/libavformat/movenccenc.c @@ -20,9 +20,11 @@ */ #include "movenccenc.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avio_internal.h" #include "movenc.h" #include "avc.h" +#include "nal.h" static int auxiliary_info_alloc_size(MOVMuxCencContext* ctx, int size) { @@ -203,13 +205,13 @@ int ff_mov_cenc_avc_parse_nal_units(MOVMuxCencContext* ctx, AVIOContext *pb, } size = 0; - nal_start = ff_avc_find_startcode(p, end); + nal_start = ff_nal_find_startcode(p, end); for (;;) { while (nal_start < end && !*(nal_start++)); if (nal_start == end) break; - nal_end = ff_avc_find_startcode(nal_start, end); + nal_end = ff_nal_find_startcode(nal_start, end); avio_wb32(pb, nal_end - nal_start); avio_w8(pb, *nal_start); diff --git a/libavformat/movenchint.c b/libavformat/movenchint.c index 016934118..1fa22fbff 100644 --- a/libavformat/movenchint.c +++ b/libavformat/movenchint.c @@ -21,6 +21,7 @@ #include "movenc.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "mux.h" #include "rtpenc_chain.h" #include "avio_internal.h" diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index 4a02a4506..5695eeec9 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -26,6 +26,7 @@ #include "mux.h" #include "rawenc.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavcodec/mpegaudio.h" #include "libavcodec/mpegaudiodata.h" #include "libavcodec/mpegaudiodecheader.h" diff --git a/libavformat/mpc.c b/libavformat/mpc.c index 89130d5a7..1e0e170c7 100644 --- a/libavformat/mpc.c +++ b/libavformat/mpc.c @@ -20,6 +20,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" @@ -111,7 +112,7 @@ static int mpc_read_header(AVFormatContext *s) if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { int64_t pos = avio_tell(s->pb); ff_ape_parse_tag(s); - if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) + if (av_dict_count(s->metadata) == 0) ff_id3v1_read(s); avio_seek(s->pb, pos, SEEK_SET); } diff --git a/libavformat/mpc8.c b/libavformat/mpc8.c index 42a34a325..6b6db1b28 100644 --- a/libavformat/mpc8.c +++ b/libavformat/mpc8.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavcodec/get_bits.h" #include "libavcodec/unary.h" #include "apetag.h" diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index d48f95c45..2c766a4ee 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -22,6 +22,7 @@ #include "config_components.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "demux.h" @@ -565,7 +566,9 @@ redo: static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 }; unsigned char buf[8]; - avio_read(s->pb, buf, 8); + ret = avio_read(s->pb, buf, 8); + if (ret != 8) + return AVERROR_INVALIDDATA; avio_seek(s->pb, -8, SEEK_CUR); if (!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1)) codec_id = AV_CODEC_ID_CAVS; diff --git a/libavformat/mpegenc.c b/libavformat/mpegenc.c index 14caf9e16..6b6763c30 100644 --- a/libavformat/mpegenc.c +++ b/libavformat/mpegenc.c @@ -27,6 +27,7 @@ #include "libavutil/fifo.h" #include "libavutil/log.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/put_bits.h" diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index 320926248..86b7c8e04 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -22,21 +22,19 @@ #include "config_components.h" #include "libavutil/buffer.h" -#include "libavutil/common.h" #include "libavutil/crc.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/dict.h" -#include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/avassert.h" #include "libavutil/dovi_meta.h" -#include "libavcodec/avcodec.h" #include "libavcodec/bytestream.h" #include "libavcodec/defs.h" #include "libavcodec/get_bits.h" -#include "libavcodec/opus.h" +#include "libavcodec/opus/opus.h" #include "avformat.h" #include "mpegts.h" #include "internal.h" @@ -1674,6 +1672,8 @@ static int mp4_read_iods(AVFormatContext *s, const uint8_t *buf, unsigned size, MP4DescrParseContext d; int ret; + d.predefined_SLConfigDescriptor_seen = 0; + ret = init_MP4DescrParseContext(&d, s, buf, size, descr, max_descr_count); if (ret < 0) return ret; @@ -2191,7 +2191,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type uint32_t buf; AVDOVIDecoderConfigurationRecord *dovi; size_t dovi_size; - int dependency_pid; + int dependency_pid = -1; // Unset if (desc_end - *pp < 4) // (8 + 8 + 7 + 6 + 1 + 1 + 1) / 8 return AVERROR_INVALIDDATA; @@ -2215,10 +2215,12 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type if (desc_end - *pp >= 1) { // 8 bits buf = get8(pp, desc_end); dovi->dv_bl_signal_compatibility_id = (buf >> 4) & 0x0f; // 4 bits + dovi->dv_md_compression = (buf >> 2) & 0x03; // 2 bits } else { // 0 stands for None // Dolby Vision V1.2.93 profiles and levels dovi->dv_bl_signal_compatibility_id = 0; + dovi->dv_md_compression = AV_DOVI_COMPRESSION_NONE; } if (!av_packet_side_data_add(&st->codecpar->coded_side_data, @@ -2230,14 +2232,16 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type } av_log(fc, AV_LOG_TRACE, "DOVI, version: %d.%d, profile: %d, level: %d, " - "rpu flag: %d, el flag: %d, bl flag: %d, dependency_pid: %d, compatibility id: %d\n", + "rpu flag: %d, el flag: %d, bl flag: %d, dependency_pid: %d, " + "compatibility id: %d, compression: %d\n", dovi->dv_version_major, dovi->dv_version_minor, dovi->dv_profile, dovi->dv_level, dovi->rpu_present_flag, dovi->el_present_flag, dovi->bl_present_flag, dependency_pid, - dovi->dv_bl_signal_compatibility_id); + dovi->dv_bl_signal_compatibility_id, + dovi->dv_md_compression); } break; default: diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index d8c148bd3..215783f32 100644 --- a/libavformat/mpegtsenc.c +++ b/libavformat/mpegtsenc.c @@ -25,13 +25,14 @@ #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/ac3_parser_internal.h" #include "libavcodec/bytestream.h" #include "libavcodec/defs.h" #include "libavcodec/h264.h" -#include "libavcodec/hevc.h" +#include "libavcodec/hevc/hevc.h" #include "libavcodec/vvc.h" #include "libavcodec/startcode.h" diff --git a/libavformat/mpjpegdec.c b/libavformat/mpjpegdec.c index e20c61be9..125b17585 100644 --- a/libavformat/mpjpegdec.c +++ b/libavformat/mpjpegdec.c @@ -20,6 +20,7 @@ */ #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avformat.h" diff --git a/libavformat/mtv.c b/libavformat/mtv.c index 9f52cb6c6..01379a18e 100644 --- a/libavformat/mtv.c +++ b/libavformat/mtv.c @@ -24,8 +24,8 @@ * MTV demuxer. */ -#include "libavutil/bswap.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/mux.c b/libavformat/mux.c index 630204a8e..011de51dd 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -27,6 +27,7 @@ #include "libavcodec/codec_desc.h" #include "libavcodec/internal.h" #include "libavcodec/packet_internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/dict.h" #include "libavutil/timestamp.h" diff --git a/libavformat/mvdec.c b/libavformat/mvdec.c index 31640f759..c045d2c7c 100644 --- a/libavformat/mvdec.c +++ b/libavformat/mvdec.c @@ -28,6 +28,7 @@ #include "libavutil/eval.h" #include "libavutil/intfloat.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/rational.h" #include "avformat.h" @@ -255,7 +256,8 @@ static int read_table(AVFormatContext *avctx, AVStream *st, if (avio_feof(pb)) return AVERROR_EOF; - avio_read(pb, name, 16); + if (avio_read(pb, name, 16) != 16) + return AVERROR_INVALIDDATA; name[sizeof(name) - 1] = 0; size = avio_rb32(pb); if (size < 0) { diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 0f9c4fa73..890500820 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -51,6 +51,7 @@ #include "libavutil/avstring.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavcodec/bytestream.h" #include "libavcodec/defs.h" #include "libavcodec/internal.h" @@ -226,6 +227,7 @@ typedef struct MXFDescriptor { UID color_trc_ul; UID color_space_ul; AVMasteringDisplayMetadata *mastering; + size_t mastering_size; AVContentLightMetadata *coll; size_t coll_size; } MXFDescriptor; @@ -326,7 +328,7 @@ typedef int MXFMetadataReadFunc(void *arg, AVIOContext *pb, int tag, int size, U typedef struct MXFMetadataReadTableEntry { const UID key; - MXFMetadataReadFunc *read; + MXFMetadataReadFunc *read; /* if NULL then skip KLV */ int ctx_size; enum MXFMetadataSetType type; } MXFMetadataReadTableEntry; @@ -480,9 +482,7 @@ static int klv_read_packet(MXFContext *mxf, KLVPacket *klv, AVIOContext *pb) static int mxf_get_stream_index(AVFormatContext *s, KLVPacket *klv, int body_sid) { - int i; - - for (i = 0; i < s->nb_streams; i++) { + for (int i = 0; i < s->nb_streams; i++) { MXFTrack *track = s->streams[i]->priv_data; /* SMPTE 379M 7.3 */ if (track && (!body_sid || !track->body_sid || track->body_sid == body_sid) && !memcmp(klv->key + sizeof(mxf_essence_element_key), track->track_number, sizeof(track->track_number))) @@ -521,12 +521,12 @@ static int mxf_get_eia608_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt int cdp_identifier, cdp_length, cdp_footer_id, ccdata_id, cc_count; int line_num, sample_coding, sample_count; int did, sdid, data_length; - int i, ret; + int ret; if (count > 1) av_log(s, AV_LOG_WARNING, "unsupported multiple ANC packets (%d) per KLV packet\n", count); - for (i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { if (length < 6) { av_log(s, AV_LOG_ERROR, "error reading s436m packet %"PRId64"\n", length); return AVERROR_INVALIDDATA; @@ -595,7 +595,6 @@ static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, { const uint8_t *buf_ptr, *end_ptr; uint8_t *data_ptr; - int i; if (length > 61444) /* worst case PAL 1920 samples 8 channels */ return AVERROR_INVALIDDATA; @@ -610,7 +609,7 @@ static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, return AVERROR_INVALIDDATA; for (; end_ptr - buf_ptr >= st->codecpar->ch_layout.nb_channels * 4; ) { - for (i = 0; i < st->codecpar->ch_layout.nb_channels; i++) { + for (int i = 0; i < st->codecpar->ch_layout.nb_channels; i++) { uint32_t sample = bytestream_get_le32(&buf_ptr); if (st->codecpar->bits_per_coded_sample == 24) bytestream_put_le24(&data_ptr, (sample >> 4) & 0xffffff); @@ -672,7 +671,8 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv if (size < 32 || size - 32 < orig_size || (int)orig_size != orig_size) return AVERROR_INVALIDDATA; avio_read(pb, ivec, 16); - avio_read(pb, tmpbuf, 16); + if (avio_read(pb, tmpbuf, 16) != 16) + return AVERROR_INVALIDDATA; if (mxf->aesc) av_aes_crypt(mxf->aesc, tmpbuf, tmpbuf, 1, ivec, 1); if (memcmp(tmpbuf, checkv, 16)) @@ -869,16 +869,16 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size * 2011_DCPTEST_24FPS.V.mxf - two ECs, OP1a * abcdefghiv016f56415e.mxf - zero ECs, OPAtom, output by Avid AirSpeed */ if (nb_essence_containers != 1) { - MXFOP op = nb_essence_containers ? OP1a : OPAtom; + MXFOP mxfop = nb_essence_containers ? OP1a : OPAtom; /* only nag once */ if (!mxf->op) av_log(mxf->fc, AV_LOG_WARNING, "\"OPAtom\" with %"PRIu32" ECs - assuming %s\n", nb_essence_containers, - op == OP1a ? "OP1a" : "OPAtom"); + mxfop == OP1a ? "OP1a" : "OPAtom"); - mxf->op = op; + mxf->op = mxfop; } else mxf->op = OPAtom; } else { @@ -1423,7 +1423,7 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int } if (IS_KLV_KEY(uid, mxf_mastering_display_prefix)) { if (!descriptor->mastering) { - descriptor->mastering = av_mastering_display_metadata_alloc(); + descriptor->mastering = av_mastering_display_metadata_alloc_size(&descriptor->mastering_size); if (!descriptor->mastering) return AVERROR(ENOMEM); } @@ -1531,7 +1531,8 @@ static int mxf_read_indirect_value(void *arg, AVIOContext *pb, int size) if (size <= 17) return 0; - avio_read(pb, key, 17); + if (avio_read(pb, key, 17) != 17) + return AVERROR_INVALIDDATA; /* TODO: handle other types of of indirect values */ if (memcmp(key, mxf_indirect_value_utf16le, 17) == 0) { return mxf_read_utf16le_string(pb, size - 17, &tagged_value->value); @@ -1667,8 +1668,8 @@ static const MXFChannelOrderingUL mxf_channel_ordering[] = { { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x04,0x00,0x00,0x00,0x00 }, AV_CHAN_LOW_FREQUENCY, AV_AUDIO_SERVICE_TYPE_MAIN }, // Low Frequency Effects { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x05,0x00,0x00,0x00,0x00 }, AV_CHAN_SIDE_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Surround { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x06,0x00,0x00,0x00,0x00 }, AV_CHAN_SIDE_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Surround - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x07,0x00,0x00,0x00,0x00 }, AV_CHAN_SIDE_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Side Surround - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x08,0x00,0x00,0x00,0x00 }, AV_CHAN_SIDE_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Side Surround + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x07,0x00,0x00,0x00,0x00 }, AV_CHAN_SIDE_SURROUND_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Side Surround + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x08,0x00,0x00,0x00,0x00 }, AV_CHAN_SIDE_SURROUND_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Side Surround { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x09,0x00,0x00,0x00,0x00 }, AV_CHAN_BACK_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Rear Surround { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0a,0x00,0x00,0x00,0x00 }, AV_CHAN_BACK_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Rear Surround { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x0b,0x00,0x00,0x00,0x00 }, AV_CHAN_FRONT_LEFT_OF_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Center @@ -1681,8 +1682,8 @@ static const MXFChannelOrderingUL mxf_channel_ordering[] = { { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x01,0x00,0x00 }, AV_CHAN_TOP_FRONT_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Height { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x02,0x00,0x00 }, AV_CHAN_TOP_FRONT_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Height { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x03,0x00,0x00 }, AV_CHAN_TOP_FRONT_CENTER, AV_AUDIO_SERVICE_TYPE_MAIN }, // Center Height - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x04,0x00,0x00 }, AV_CHAN_TOP_SIDE_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Surround Height - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x05,0x00,0x00 }, AV_CHAN_TOP_SIDE_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Surround Height + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x04,0x00,0x00 }, AV_CHAN_TOP_SURROUND_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Surround Height + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x05,0x00,0x00 }, AV_CHAN_TOP_SURROUND_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Surround Height { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x06,0x00,0x00 }, AV_CHAN_TOP_SIDE_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Side Surround Height { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x07,0x00,0x00 }, AV_CHAN_TOP_SIDE_RIGHT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Right Side Surround Height { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0d,0x03,0x02,0x01,0x30,0x01,0x08,0x00,0x00 }, AV_CHAN_TOP_BACK_LEFT, AV_AUDIO_SERVICE_TYPE_MAIN }, // Left Rear Surround Height @@ -1922,6 +1923,11 @@ static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_t return mxf_absolute_bodysid_offset(mxf, index_table->body_sid, offset_temp, offset_out, partition_out); } else { /* EditUnitByteCount == 0 for VBR indexes, which is fine since they use explicit StreamOffsets */ + if (s->edit_unit_byte_count && (s->index_duration > INT64_MAX / s->edit_unit_byte_count || + s->edit_unit_byte_count * s->index_duration > INT64_MAX - offset_temp) + ) + return AVERROR_INVALIDDATA; + offset_temp += s->edit_unit_byte_count * s->index_duration; } } @@ -2066,7 +2072,7 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta */ static int mxf_compute_index_tables(MXFContext *mxf) { - int i, j, k, ret, nb_sorted_segments; + int ret, nb_sorted_segments; MXFIndexTableSegment **sorted_segments = NULL; if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)) || @@ -2076,7 +2082,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) } /* sanity check and count unique BodySIDs/IndexSIDs */ - for (i = 0; i < nb_sorted_segments; i++) { + for (int i = 0; i < nb_sorted_segments; i++) { if (i == 0 || sorted_segments[i-1]->index_sid != sorted_segments[i]->index_sid) mxf->nb_index_tables++; else if (sorted_segments[i-1]->body_sid != sorted_segments[i]->body_sid) { @@ -2095,7 +2101,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) } /* distribute sorted segments to index tables */ - for (i = j = 0; i < nb_sorted_segments; i++) { + for (int i = 0, j = 0; i < nb_sorted_segments; i++) { if (i != 0 && sorted_segments[i-1]->index_sid != sorted_segments[i]->index_sid) { /* next IndexSID */ j++; @@ -2104,7 +2110,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) mxf->index_tables[j].nb_segments++; } - for (i = j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) { + for (int i = 0, j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) { MXFIndexTable *t = &mxf->index_tables[j]; MXFTrack *mxf_track = NULL; @@ -2127,7 +2133,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) if ((ret = mxf_compute_ptses_fake_index(mxf, t)) < 0) goto finish_decoding_index; - for (k = 0; k < mxf->fc->nb_streams; k++) { + for (int k = 0; k < mxf->fc->nb_streams; k++) { MXFTrack *track = mxf->fc->streams[k]->priv_data; if (track && track->index_sid == t->index_sid) { mxf_track = track; @@ -2136,7 +2142,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) } /* fix zero IndexDurations */ - for (k = 0; k < t->nb_segments; k++) { + for (int k = 0; k < t->nb_segments; k++) { if (!t->segments[k]->index_edit_rate.num || !t->segments[k]->index_edit_rate.den) { av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i segment %i has invalid IndexEditRate\n", t->index_sid, k); @@ -2389,6 +2395,9 @@ static int mxf_parse_physical_source_package(MXFContext *mxf, MXFTrack *source_t physical_track->edit_rate, source_track->edit_rate); + if (av_sat_add64(start_position, mxf_tc->start_frame) != start_position + (uint64_t)mxf_tc->start_frame) + return AVERROR_INVALIDDATA; + if (av_timecode_init(&tc, mxf_tc->rate, flags, start_position + mxf_tc->start_frame, mxf->fc) == 0) { mxf_add_timecode_metadata(&st->metadata, "timecode", &tc); return 0; @@ -2572,7 +2581,7 @@ static int parse_mca_labels(MXFContext *mxf, MXFTrack *source_track, MXFDescript } if (language && !ambigous_language) { - int ret = set_language(mxf->fc, language, &st->metadata); + ret = set_language(mxf->fc, language, &st->metadata); if (ret < 0) return ret; } @@ -2599,10 +2608,10 @@ static int parse_mca_labels(MXFContext *mxf, MXFTrack *source_track, MXFDescript static int mxf_parse_structural_metadata(MXFContext *mxf) { MXFPackage *material_package = NULL; - int i, j, k, ret; + int k, ret; /* TODO: handle multiple material packages (OP3x) */ - for (i = 0; i < mxf->packages_count; i++) { + for (int i = 0; i < mxf->packages_count; i++) { material_package = mxf_resolve_strong_ref(mxf, &mxf->packages_refs[i], MaterialPackage); if (material_package) break; } @@ -2616,7 +2625,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) av_dict_set(&mxf->fc->metadata, "material_package_name", material_package->name, 0); mxf_parse_package_comments(mxf, &mxf->fc->metadata, material_package); - for (i = 0; i < material_package->tracks_count; i++) { + for (int i = 0; i < material_package->tracks_count; i++) { MXFPackage *source_package = NULL; MXFTrack *material_track = NULL; MXFTrack *source_track = NULL; @@ -2651,7 +2660,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) continue; } - for (j = 0; j < material_track->sequence->structural_components_count; j++) { + for (int j = 0; j < material_track->sequence->structural_components_count; j++) { component = mxf_resolve_strong_ref(mxf, &material_track->sequence->structural_components_refs[j], TimecodeComponent); if (!component) continue; @@ -2669,7 +2678,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) av_log(mxf->fc, AV_LOG_WARNING, "material track %d: has %d components\n", material_track->track_id, material_track->sequence->structural_components_count); - for (j = 0; j < material_track->sequence->structural_components_count; j++) { + for (int j = 0; j < material_track->sequence->structural_components_count; j++) { component = mxf_resolve_sourceclip(mxf, &material_track->sequence->structural_components_refs[j]); if (!component) continue; @@ -2954,7 +2963,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) if (descriptor->mastering) { if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, - (uint8_t *)descriptor->mastering, sizeof(*descriptor->mastering), 0)) { + (uint8_t *)descriptor->mastering, descriptor->mastering_size, 0)) { ret = AVERROR(ENOMEM); goto fail_and_free; } @@ -3233,7 +3242,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext }, { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 }, mxf_read_index_table_segment, sizeof(MXFIndexTableSegment), IndexTableSegment }, { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x23,0x00 }, mxf_read_essence_container_data, sizeof(MXFEssenceContainerData), EssenceContainerData }, - { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL }, + { { 0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x01,0x02,0x10,0x01,0x00,0x00,0x00 } }, /* KLV fill, skip */ }; static int mxf_metadataset_init(MXFMetadataSet *ctx, enum MXFMetadataSetType type, MXFPartition *partition) @@ -3714,7 +3723,7 @@ static int mxf_read_header(AVFormatContext *s) mxf_read_random_index_pack(s); while (!avio_feof(s->pb)) { - const MXFMetadataReadTableEntry *metadata; + size_t x; ret = klv_read_packet(mxf, &klv, s->pb); if (ret < 0 || IS_KLV_KEY(klv.key, ff_mxf_random_index_pack_key)) { @@ -3760,14 +3769,19 @@ static int mxf_read_header(AVFormatContext *s) /* we're still parsing forward. proceed to parsing this partition pack */ } - for (metadata = mxf_metadata_read_table; metadata->read; metadata++) { + for (x = 0; x < FF_ARRAY_ELEMS(mxf_metadata_read_table); x++) { + const MXFMetadataReadTableEntry *metadata = &mxf_metadata_read_table[x]; if (IS_KLV_KEY(klv.key, metadata->key)) { - if ((ret = mxf_parse_klv(mxf, klv, metadata->read, metadata->ctx_size, metadata->type)) < 0) - return ret; + if (metadata->read) { + if ((ret = mxf_parse_klv(mxf, klv, metadata->read, metadata->ctx_size, metadata->type)) < 0) + return ret; + } else { + avio_skip(s->pb, klv.length); + } break; } } - if (!metadata->read) { + if (x >= FF_ARRAY_ELEMS(mxf_metadata_read_table)) { av_log(s, AV_LOG_VERBOSE, "Dark key " PRIxUID "\n", UID_ARG(klv.key)); avio_skip(s->pb, klv.length); @@ -3820,7 +3834,7 @@ static int mxf_get_next_track_edit_unit(MXFContext *mxf, MXFTrack *track, int64_ a = -1; b = track->original_duration; while (b - 1 > a) { - m = (a + b) >> 1; + m = (a + (uint64_t)b) >> 1; if (mxf_edit_unit_absolute_offset(mxf, t, m, track->edit_rate, NULL, &offset, NULL, 0) < 0) return -1; if (offset < current_offset) @@ -3873,7 +3887,7 @@ static int64_t mxf_set_current_edit_unit(MXFContext *mxf, AVStream *st, int64_t int64_t new_edit_unit; MXFIndexTable *t = mxf_find_index_table(mxf, track->index_sid); - if (!t || track->wrapping == UnknownWrapped) + if (!t || track->wrapping == UnknownWrapped || edit_unit > INT64_MAX - track->edit_units_per_packet) return -1; if (mxf_edit_unit_absolute_offset(mxf, t, edit_unit + track->edit_units_per_packet, track->edit_rate, NULL, &next_ofs, NULL, 0) < 0 && @@ -4085,17 +4099,16 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) static int mxf_read_close(AVFormatContext *s) { MXFContext *mxf = s->priv_data; - int i; av_freep(&mxf->packages_refs); av_freep(&mxf->essence_container_data_refs); - for (i = 0; i < s->nb_streams; i++) + for (int i = 0; i < s->nb_streams; i++) s->streams[i]->priv_data = NULL; for (int type = 0; type < FF_ARRAY_ELEMS(mxf->metadata_set_groups); type++) { MXFMetadataSetGroup *mg = &mxf->metadata_set_groups[type]; - for (i = 0; i < mg->metadata_sets_count; i++) + for (int i = 0; i < mg->metadata_sets_count; i++) mxf_free_metadataset(mg->metadata_sets + i, type); mg->metadata_sets_count = 0; av_freep(&mg->metadata_sets); @@ -4105,7 +4118,7 @@ static int mxf_read_close(AVFormatContext *s) av_freep(&mxf->local_tags); if (mxf->index_tables) { - for (i = 0; i < mxf->nb_index_tables; i++) { + for (int i = 0; i < mxf->nb_index_tables; i++) { av_freep(&mxf->index_tables[i].segments); av_freep(&mxf->index_tables[i].ptses); av_freep(&mxf->index_tables[i].fake_index); @@ -4150,7 +4163,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti int64_t seconds; MXFContext* mxf = s->priv_data; int64_t seekpos; - int i, ret; + int ret; MXFIndexTable *t; MXFTrack *source_track = st->priv_data; @@ -4180,6 +4193,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti t = &mxf->index_tables[0]; if (t->index_sid != source_track->index_sid) { + int i; /* If the first index table does not belong to the stream, then find a stream which does belong to the index table */ for (i = 0; i < s->nb_streams; i++) { MXFTrack *new_source_track = s->streams[i]->priv_data; @@ -4241,7 +4255,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti } // Update all tracks sample count - for (i = 0; i < s->nb_streams; i++) { + for (int i = 0; i < s->nb_streams; i++) { AVStream *cur_st = s->streams[i]; MXFTrack *cur_track = cur_st->priv_data; if (cur_track) { @@ -4272,7 +4286,7 @@ static const AVClass demuxer_class = { const FFInputFormat ff_mxf_demuxer = { .p.name = "mxf", .p.long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"), - .p.flags = AVFMT_SEEK_TO_PTS, + .p.flags = AVFMT_SEEK_TO_PTS | AVFMT_NOGENSEARCH, .p.priv_class = &demuxer_class, .priv_data_size = sizeof(MXFContext), .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP, diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index d4fa2bc5b..57be9e6ef 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -40,6 +40,7 @@ #include #include +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/random_seed.h" #include "libavutil/timecode.h" @@ -59,6 +60,7 @@ #include "avio_internal.h" #include "internal.h" #include "avc.h" +#include "nal.h" #include "mux.h" #include "mxf.h" #include "config.h" @@ -2476,7 +2478,7 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, if (mxf->header_written) break; - nal_end = ff_avc_find_startcode(buf, buf_end); + nal_end = ff_nal_find_startcode(buf, buf_end); ret = ff_avc_decode_sps(sps, buf, nal_end - buf); if (ret < 0) { av_log(s, AV_LOG_ERROR, "error parsing sps\n"); @@ -2892,8 +2894,12 @@ static int mxf_init(AVFormatContext *s) if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(st->codecpar->format); - // TODO: should be avg_frame_rate - AVRational tbc = st->time_base; + AVRational tbc = (AVRational){ 0, 0 }; + if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) + tbc = av_inv_q(st->avg_frame_rate); + else if (st->r_frame_rate.num > 0 && st->r_frame_rate.den > 0) + tbc = av_inv_q(st->r_frame_rate); + // Default component depth to 8 sc->component_depth = 8; sc->h_chroma_sub_sample = 2; diff --git a/libavformat/mxg.c b/libavformat/mxg.c index 23d72ad23..6a39873f2 100644 --- a/libavformat/mxg.c +++ b/libavformat/mxg.c @@ -22,6 +22,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/mjpeg.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/nal.c b/libavformat/nal.c new file mode 100644 index 000000000..26dc5fe68 --- /dev/null +++ b/libavformat/nal.c @@ -0,0 +1,190 @@ +/* + * NAL helper functions for muxers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/mem.h" +#include "libavutil/error.h" +#include "libavcodec/defs.h" +#include "avio.h" +#include "avio_internal.h" +#include "nal.h" + +static const uint8_t *nal_find_startcode_internal(const uint8_t *p, const uint8_t *end) +{ + const uint8_t *a = p + 4 - ((intptr_t)p & 3); + + for (end -= 3; p < a && p < end; p++) { + if (p[0] == 0 && p[1] == 0 && p[2] == 1) + return p; + } + + for (end -= 3; p < end; p += 4) { + uint32_t x = *(const uint32_t*)p; +// if ((x - 0x01000100) & (~x) & 0x80008000) // little endian +// if ((x - 0x00010001) & (~x) & 0x00800080) // big endian + if ((x - 0x01010101) & (~x) & 0x80808080) { // generic + if (p[1] == 0) { + if (p[0] == 0 && p[2] == 1) + return p; + if (p[2] == 0 && p[3] == 1) + return p+1; + } + if (p[3] == 0) { + if (p[2] == 0 && p[4] == 1) + return p+2; + if (p[4] == 0 && p[5] == 1) + return p+3; + } + } + } + + for (end += 3; p < end; p++) { + if (p[0] == 0 && p[1] == 0 && p[2] == 1) + return p; + } + + return end + 3; +} + +const uint8_t *ff_nal_find_startcode(const uint8_t *p, const uint8_t *end){ + const uint8_t *out = nal_find_startcode_internal(p, end); + if(pnalus); + while (nal_start < end && !*(nal_start++)); + if (nal_start == end) + break; + + nal_end = ff_nal_find_startcode(nal_start, end); + if (pb) { + avio_wb32(pb, nal_end - nal_start); + avio_write(pb, nal_start, nal_end - nal_start); + } else if (list->nb_nalus >= nalu_limit) { + return AVERROR(ERANGE); + } else { + NALU *tmp = av_fast_realloc(list->nalus, &list->nalus_array_size, + (list->nb_nalus + 1) * sizeof(*list->nalus)); + if (!tmp) + return AVERROR(ENOMEM); + list->nalus = tmp; + tmp[list->nb_nalus++] = (NALU){ .offset = nal_start - p, + .size = nal_end - nal_start }; + } + size += 4 + nal_end - nal_start; + nal_start = nal_end; + } + return size; +} + +int ff_nal_parse_units(AVIOContext *pb, const uint8_t *buf_in, int size) +{ + return nal_parse_units(pb, NULL, buf_in, size); +} + +int ff_nal_units_create_list(NALUList *list, const uint8_t *buf, int size) +{ + list->nb_nalus = 0; + return nal_parse_units(NULL, list, buf, size); +} + +void ff_nal_units_write_list(const NALUList *list, AVIOContext *pb, + const uint8_t *buf) +{ + for (unsigned i = 0; i < list->nb_nalus; i++) { + avio_wb32(pb, list->nalus[i].size); + avio_write(pb, buf + list->nalus[i].offset, list->nalus[i].size); + } +} + +int ff_nal_parse_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) +{ + AVIOContext *pb; + int ret = avio_open_dyn_buf(&pb); + if(ret < 0) + return ret; + + ff_nal_parse_units(pb, buf_in, *size); + + *size = avio_close_dyn_buf(pb, buf); + return 0; +} + +const uint8_t *ff_nal_mp4_find_startcode(const uint8_t *start, + const uint8_t *end, + int nal_length_size) +{ + unsigned int res = 0; + + if (end - start < nal_length_size) + return NULL; + while (nal_length_size--) + res = (res << 8) | *start++; + + if (res > end - start) + return NULL; + + return start + res; +} + +uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, + uint32_t *dst_len, int header_len) +{ + uint8_t *dst; + uint32_t i, len; + + dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE); + if (!dst) + return NULL; + + /* NAL unit header */ + i = len = 0; + while (i < header_len && i < src_len) + dst[len++] = src[i++]; + + while (i + 2 < src_len) + if (!src[i] && !src[i + 1] && src[i + 2] == 3) { + dst[len++] = src[i++]; + dst[len++] = src[i++]; + i++; // remove emulation_prevention_three_byte + } else + dst[len++] = src[i++]; + + while (i < src_len) + dst[len++] = src[i++]; + + memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + *dst_len = len; + return dst; +} diff --git a/libavformat/nal.h b/libavformat/nal.h new file mode 100644 index 000000000..587276da8 --- /dev/null +++ b/libavformat/nal.h @@ -0,0 +1,67 @@ +/* + * NAL helper functions for muxers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 AVFORMAT_NAL_H +#define AVFORMAT_NAL_H + +#include +#include "avio.h" + +typedef struct NALU { + int offset; + uint32_t size; +} NALU; + +typedef struct NALUList { + NALU *nalus; + unsigned nalus_array_size; + unsigned nb_nalus; ///< valid entries in nalus +} NALUList; + +/* This function will parse the given annex B buffer and create + * a NALUList from it. This list can be passed to ff_nal_units_write_list() + * to write the access unit reformatted to mp4. + * + * @param list A NALUList. The list->nalus and list->nalus_array_size + * must be valid when calling this function and may be updated. + * nb_nalus is set by this function on success. + * @param buf buffer containing annex B H.264 or H.265. Must be padded. + * @param size size of buf, excluding padding. + * @return < 0 on error, the size of the mp4-style packet on success. + */ +int ff_nal_units_create_list(NALUList *list, const uint8_t *buf, int size); + +/* Writes a NALUList to the specified AVIOContext. The list must originate + * from ff_nal_units_create_list() with the same buf. */ +void ff_nal_units_write_list(const NALUList *list, AVIOContext *pb, + const uint8_t *buf); + +const uint8_t *ff_nal_find_startcode(const uint8_t *p, const uint8_t *end); +const uint8_t *ff_nal_mp4_find_startcode(const uint8_t *start, + const uint8_t *end, + int nal_length_size); + +int ff_nal_parse_units(AVIOContext *s, const uint8_t *buf, int size); +int ff_nal_parse_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size); + +uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, + uint32_t *dst_len, int header_len); + +#endif /* AVFORMAT_NAL_H */ diff --git a/libavformat/network.c b/libavformat/network.c index f752efc41..2eabd0c16 100644 --- a/libavformat/network.c +++ b/libavformat/network.c @@ -18,8 +18,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" #include "config_components.h" +#if CONFIG_TLS_PROTOCOL && CONFIG_OPENSSL +#include +#endif + #include #include "network.h" #include "tls.h" @@ -31,7 +36,7 @@ int ff_tls_init(void) { #if CONFIG_TLS_PROTOCOL -#if CONFIG_OPENSSL +#if CONFIG_OPENSSL && OPENSSL_VERSION_NUMBER < 0x10100000L int ret; if ((ret = ff_openssl_init()) < 0) return ret; @@ -46,7 +51,7 @@ int ff_tls_init(void) void ff_tls_deinit(void) { #if CONFIG_TLS_PROTOCOL -#if CONFIG_OPENSSL +#if CONFIG_OPENSSL && OPENSSL_VERSION_NUMBER < 0x10100000L ff_openssl_deinit(); #endif #if CONFIG_GNUTLS @@ -282,16 +287,14 @@ int ff_listen_connect(int fd, const struct sockaddr *addr, if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) ret = AVUNERROR(ff_neterrno()); if (ret != 0) { - char errbuf[100]; ret = AVERROR(ret); - av_strerror(ret, errbuf, sizeof(errbuf)); if (will_try_next) av_log(h, AV_LOG_WARNING, "Connection to %s failed (%s), trying next address\n", - h->filename, errbuf); + h->filename, av_err2str(ret)); else av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n", - h->filename, errbuf); + h->filename, av_err2str(ret)); } default: return ret; @@ -416,7 +419,7 @@ int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address, int64_t next_attempt_us = av_gettime_relative(), next_deadline_us; int last_err = AVERROR(EIO); socklen_t optlen; - char errbuf[100], hostbuf[100], portbuf[20]; + char hostbuf[100], portbuf[20]; if (parallel > FF_ARRAY_ELEMS(attempts)) parallel = FF_ARRAY_ELEMS(attempts); @@ -440,9 +443,8 @@ int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address, timeout_ms_per_address, h, customize_fd, customize_ctx); if (last_err < 0) { - av_strerror(last_err, errbuf, sizeof(errbuf)); av_log(h, AV_LOG_VERBOSE, "Connected attempt failed: %s\n", - errbuf); + av_err2str(last_err)); continue; } if (last_err > 0) { @@ -506,9 +508,8 @@ int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address, getnameinfo(attempts[i].addr->ai_addr, attempts[i].addr->ai_addrlen, hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); - av_strerror(last_err, errbuf, sizeof(errbuf)); av_log(h, AV_LOG_VERBOSE, "Connection attempt to %s port %s " - "failed: %s\n", hostbuf, portbuf, errbuf); + "failed: %s\n", hostbuf, portbuf, av_err2str(last_err)); closesocket(attempts[i].fd); memmove(&attempts[i], &attempts[i + 1], (nb_attempts - i - 1) * sizeof(*attempts)); @@ -523,9 +524,8 @@ int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address, if (last_err >= 0) last_err = AVERROR(ECONNREFUSED); if (last_err != AVERROR_EXIT) { - av_strerror(last_err, errbuf, sizeof(errbuf)); av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n", - h->filename, errbuf); + h->filename, av_err2str(last_err)); } return last_err; } @@ -586,7 +586,5 @@ int ff_http_match_no_proxy(const char *no_proxy, const char *hostname) void ff_log_net_error(void *ctx, int level, const char* prefix) { - char errbuf[100]; - av_strerror(ff_neterrno(), errbuf, sizeof(errbuf)); - av_log(ctx, level, "%s: %s\n", prefix, errbuf); + av_log(ctx, level, "%s: %s\n", prefix, av_err2str(ff_neterrno())); } diff --git a/libavformat/nistspheredec.c b/libavformat/nistspheredec.c index 1e6c567e0..e62403614 100644 --- a/libavformat/nistspheredec.c +++ b/libavformat/nistspheredec.c @@ -35,7 +35,7 @@ static int nist_probe(const AVProbeData *p) static int nist_read_header(AVFormatContext *s) { - char buffer[256], coding[32] = "pcm", format[32] = "01"; + char buffer[256]= {0}, coding[32] = "pcm", format[32] = "01"; int bps = 0, be = 0; int32_t header_size = -1; AVStream *st; diff --git a/libavformat/nsvdec.c b/libavformat/nsvdec.c index bb91db837..dd01765d7 100644 --- a/libavformat/nsvdec.c +++ b/libavformat/nsvdec.c @@ -23,6 +23,7 @@ #include "libavutil/attributes.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/nut.c b/libavformat/nut.c index a0bf257c7..9692336ec 100644 --- a/libavformat/nut.c +++ b/libavformat/nut.c @@ -20,6 +20,7 @@ */ #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/tree.h" #include "nut.h" #include "riff.h" diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c index 8c9b19eeb..34b7e3cb9 100644 --- a/libavformat/nutdec.c +++ b/libavformat/nutdec.c @@ -26,6 +26,7 @@ #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/tree.h" #include "libavcodec/bytestream.h" #include "avio_internal.h" @@ -880,8 +881,6 @@ static int read_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int int count = ffio_read_varlen(bc); int skip_start = 0; int skip_end = 0; - int channels = 0; - int64_t channel_layout = 0; int sample_rate = 0; int width = 0; int height = 0; @@ -929,7 +928,7 @@ static int read_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int AV_WB64(dst, v64); dst += 8; } else if (!strcmp(name, "ChannelLayout") && value_len == 8) { - channel_layout = avio_rl64(bc); + // Ignored continue; } else { av_log(s, AV_LOG_WARNING, "Unknown data %s / %s\n", name, type_str); @@ -951,7 +950,7 @@ static int read_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int } else if (!strcmp(name, "SkipEnd")) { skip_end = value; } else if (!strcmp(name, "Channels")) { - channels = value; + // Ignored } else if (!strcmp(name, "SampleRate")) { sample_rate = value; } else if (!strcmp(name, "Width")) { @@ -964,18 +963,14 @@ static int read_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int } } - if (channels || channel_layout || sample_rate || width || height) { - uint8_t *dst = av_packet_new_side_data(pkt, AV_PKT_DATA_PARAM_CHANGE, 28); + if (sample_rate || width || height) { + uint8_t *dst = av_packet_new_side_data(pkt, AV_PKT_DATA_PARAM_CHANGE, 16); if (!dst) return AVERROR(ENOMEM); bytestream_put_le32(&dst, AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE*(!!sample_rate) + AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS*(!!(width|height)) ); - if (channels) - bytestream_put_le32(&dst, channels); - if (channel_layout) - bytestream_put_le64(&dst, channel_layout); if (sample_rate) bytestream_put_le32(&dst, sample_rate); if (width || height){ diff --git a/libavformat/nutenc.c b/libavformat/nutenc.c index 2a33f1581..55efb114c 100644 --- a/libavformat/nutenc.c +++ b/libavformat/nutenc.c @@ -23,6 +23,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/tree.h" #include "libavutil/dict.h" #include "libavutil/avassert.h" diff --git a/libavformat/nuv.c b/libavformat/nuv.c index 507a73b0f..49915ecf1 100644 --- a/libavformat/nuv.c +++ b/libavformat/nuv.c @@ -165,7 +165,9 @@ static int nuv_header(AVFormatContext *s) int is_mythtv, width, height, v_packs, a_packs, ret; AVStream *vst = NULL, *ast = NULL; - avio_read(pb, id_string, 12); + if ((ret = ffio_read_size(pb, id_string, 12)) < 0) + return ret; + is_mythtv = !memcmp(id_string, "MythTVVideo", 12); avio_skip(pb, 5); // version string avio_skip(pb, 3); // padding diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index 6efcadd11..5339fdd32 100644 --- a/libavformat/oggdec.c +++ b/libavformat/oggdec.c @@ -31,6 +31,7 @@ #include #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avio_internal.h" #include "demux.h" #include "oggdec.h" @@ -363,7 +364,9 @@ static int ogg_read_page(AVFormatContext *s, int *sid, int probing) ffio_init_checksum(bc, ff_crc04C11DB7_update, 0x4fa9b05f); /* To rewind if checksum is bad/check magic on switches - this is the max packet size */ - ffio_ensure_seekback(bc, MAX_PAGE_SIZE); + ret = ffio_ensure_seekback(bc, MAX_PAGE_SIZE); + if (ret < 0) + return ret; start_pos = avio_tell(bc); version = avio_r8(bc); diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index bdd19530c..224519a4d 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -25,6 +25,7 @@ #include "libavutil/crc.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/random_seed.h" #include "libavcodec/xiph.h" @@ -431,7 +432,7 @@ static int ogg_build_vp8_headers(AVFormatContext *s, AVStream *st, bytestream_put_be32(&p, st->time_base.num); /* optional second packet: VorbisComment */ - if (av_dict_get(st->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) { + if (av_dict_count(st->metadata)) { p = ogg_write_vorbiscomment(7, bitexact, &oggstream->header_len[1], &st->metadata, 0, NULL, 0); if (!p) return AVERROR(ENOMEM); diff --git a/libavformat/oggparsecelt.c b/libavformat/oggparsecelt.c index e528fd1f4..626e1ab27 100644 --- a/libavformat/oggparsecelt.c +++ b/libavformat/oggparsecelt.c @@ -22,6 +22,7 @@ #include #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "internal.h" #include "oggdec.h" diff --git a/libavformat/oggparsedirac.c b/libavformat/oggparsedirac.c index 74b9ba4f8..c5bd43a75 100644 --- a/libavformat/oggparsedirac.c +++ b/libavformat/oggparsedirac.c @@ -20,6 +20,7 @@ #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/dirac.h" #include "avformat.h" #include "internal.h" diff --git a/libavformat/oggparseopus.c b/libavformat/oggparseopus.c index 54aa725be..218e9df58 100644 --- a/libavformat/oggparseopus.c +++ b/libavformat/oggparseopus.c @@ -22,6 +22,7 @@ #include #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "internal.h" #include "oggdec.h" diff --git a/libavformat/oggparsespeex.c b/libavformat/oggparsespeex.c index d20d14fa4..0a4b32de1 100644 --- a/libavformat/oggparsespeex.c +++ b/libavformat/oggparsespeex.c @@ -24,6 +24,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "internal.h" diff --git a/libavformat/oggparsetheora.c b/libavformat/oggparsetheora.c index 85119352c..6cdd96275 100644 --- a/libavformat/oggparsetheora.c +++ b/libavformat/oggparsetheora.c @@ -23,7 +23,7 @@ **/ #include -#include "libavutil/bswap.h" +#include "libavutil/mem.h" #include "libavcodec/get_bits.h" #include "avformat.h" #include "internal.h" diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index 6fd12560b..9f50ab9ff 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -27,6 +27,7 @@ #include "libavutil/avstring.h" #include "libavutil/base64.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "libavcodec/bytestream.h" #include "libavcodec/vorbis_parser.h" diff --git a/libavformat/omadec.c b/libavformat/omadec.c index 2ca3f45b4..86d3e7202 100644 --- a/libavformat/omadec.c +++ b/libavformat/omadec.c @@ -43,6 +43,7 @@ #include #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/options.c b/libavformat/options.c index 34d2c6e23..039f1eea4 100644 --- a/libavformat/options.c +++ b/libavformat/options.c @@ -29,6 +29,7 @@ #include "libavutil/iamf.h" #include "libavutil/internal.h" #include "libavutil/intmath.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" /** @@ -218,7 +219,8 @@ const AVClass *avformat_get_class(void) { "descriptions", .type = AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, .unit = "disposition" }, \ { "metadata", .type = AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, .unit = "disposition" }, \ { "dependent", .type = AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DEPENDENT }, .unit = "disposition" }, \ - { "still_image", .type = AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_STILL_IMAGE }, .unit = "disposition" } + { "still_image", .type = AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_STILL_IMAGE }, .unit = "disposition" }, \ + { "multilayer", .type = AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_MULTILAYER }, .unit = "disposition" } static const AVOption stream_options[] = { DISPOSITION_OPT(AVStream), @@ -316,7 +318,9 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) sti->pts_buffer[i] = AV_NOPTS_VALUE; st->sample_aspect_ratio = (AVRational) { 0, 1 }; +#if FF_API_INTERNAL_TIMING sti->transferred_mux_tb = (AVRational) { 0, 1 };; +#endif #if FF_API_AVSTREAM_SIDE_DATA sti->inject_global_side_data = si->inject_global_side_data; @@ -344,7 +348,6 @@ static const AVOption tile_grid_options[] = { { "vertical_offset", NULL, OFFSET(vertical_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { NULL }, }; -#undef FLAGS #undef OFFSET static const AVClass tile_grid_class = { @@ -353,6 +356,20 @@ static const AVClass tile_grid_class = { .option = tile_grid_options, }; +#define OFFSET(x) offsetof(AVStreamGroupLCEVC, x) +static const AVOption lcevc_options[] = { + { "video_size", "size of video after LCEVC enhancement has been applied", OFFSET(width), + AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, INT_MAX, FLAGS }, + { NULL }, +}; +#undef OFFSET + +static const AVClass lcevc_class = { + .class_name = "AVStreamGroupLCEVC", + .version = LIBAVUTIL_VERSION_INT, + .option = lcevc_options, +}; + static void *stream_group_child_next(void *obj, void *prev) { AVStreamGroup *stg = obj; @@ -364,6 +381,8 @@ static void *stream_group_child_next(void *obj, void *prev) return stg->params.iamf_mix_presentation; case AV_STREAM_GROUP_PARAMS_TILE_GRID: return stg->params.tile_grid; + case AV_STREAM_GROUP_PARAMS_LCEVC: + return stg->params.lcevc; default: break; } @@ -371,6 +390,8 @@ static void *stream_group_child_next(void *obj, void *prev) return NULL; } +#undef FLAGS + static const AVClass *stream_group_child_iterate(void **opaque) { uintptr_t i = (uintptr_t)*opaque; @@ -389,6 +410,9 @@ static const AVClass *stream_group_child_iterate(void **opaque) case AV_STREAM_GROUP_PARAMS_TILE_GRID: ret = &tile_grid_class; break; + case AV_STREAM_GROUP_PARAMS_LCEVC: + ret = &lcevc_class; + break; default: break; } @@ -458,6 +482,13 @@ AVStreamGroup *avformat_stream_group_create(AVFormatContext *s, stg->params.tile_grid->av_class = &tile_grid_class; av_opt_set_defaults(stg->params.tile_grid); break; + case AV_STREAM_GROUP_PARAMS_LCEVC: + stg->params.lcevc = av_mallocz(sizeof(*stg->params.lcevc)); + if (!stg->params.lcevc) + goto fail; + stg->params.lcevc->av_class = &lcevc_class; + av_opt_set_defaults(stg->params.lcevc); + break; default: goto fail; } diff --git a/libavformat/options_table.h b/libavformat/options_table.h index b9dca147f..311880d24 100644 --- a/libavformat/options_table.h +++ b/libavformat/options_table.h @@ -108,6 +108,7 @@ static const AVOption avformat_options[] = { {"max_streams", "maximum number of streams", OFFSET(max_streams), AV_OPT_TYPE_INT, { .i64 = 1000 }, 0, INT_MAX, D }, {"skip_estimate_duration_from_pts", "skip duration calculation in estimate_timings_from_pts", OFFSET(skip_estimate_duration_from_pts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, D}, {"max_probe_packets", "Maximum number of packets to probe a codec", OFFSET(max_probe_packets), AV_OPT_TYPE_INT, { .i64 = 2500 }, 0, INT_MAX, D }, +{"duration_probesize", "Maximum number of bytes to probe the durations of the streams in estimate_timings_from_pts", OFFSET(duration_probesize), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D}, {NULL}, }; diff --git a/libavformat/os_support.c b/libavformat/os_support.c index 2de6a7c3d..4d6eb8a74 100644 --- a/libavformat/os_support.c +++ b/libavformat/os_support.c @@ -25,6 +25,7 @@ #define _SVID_SOURCE #include "config.h" +#include "libavutil/mem.h" #include "avformat.h" #include "os_support.h" diff --git a/libavformat/os_support.h b/libavformat/os_support.h index f2ff38e23..8479163f7 100644 --- a/libavformat/os_support.h +++ b/libavformat/os_support.h @@ -173,6 +173,7 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout); #ifdef _WIN32 #include #include +#include "libavutil/mem.h" #include "libavutil/wchar_filename.h" #define DEF_FS_FUNCTION(name, wfunc, afunc) \ diff --git a/libavformat/paf.c b/libavformat/paf.c index 056cc6e78..f072f0dc2 100644 --- a/libavformat/paf.c +++ b/libavformat/paf.c @@ -20,6 +20,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavcodec/paf.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/pcmdec.c b/libavformat/pcmdec.c index e9c97f795..2f6508b75 100644 --- a/libavformat/pcmdec.c +++ b/libavformat/pcmdec.c @@ -23,6 +23,7 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/pdvdec.c b/libavformat/pdvdec.c index 8ed4e20e6..76b67dfcf 100644 --- a/libavformat/pdvdec.c +++ b/libavformat/pdvdec.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/pmpdec.c b/libavformat/pmpdec.c index 06ef53d27..28aa746d3 100644 --- a/libavformat/pmpdec.c +++ b/libavformat/pmpdec.c @@ -20,6 +20,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/pp_bnk.c b/libavformat/pp_bnk.c index 34156dd71..5360b7c5d 100644 --- a/libavformat/pp_bnk.c +++ b/libavformat/pp_bnk.c @@ -26,6 +26,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #define PP_BNK_MAX_READ_SIZE 4096 #define PP_BNK_FILE_HEADER_SIZE 20 diff --git a/libavformat/prompeg.c b/libavformat/prompeg.c index 59faa824b..322eb6560 100644 --- a/libavformat/prompeg.c +++ b/libavformat/prompeg.c @@ -80,10 +80,9 @@ */ -#include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" #include "libavutil/random_seed.h" #include "avformat.h" #include "config.h" diff --git a/libavformat/qcp.c b/libavformat/qcp.c index fdf18618d..13a479a11 100644 --- a/libavformat/qcp.c +++ b/libavformat/qcp.c @@ -105,7 +105,8 @@ static int qcp_read_header(AVFormatContext *s) st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; - avio_read(pb, buf, 16); + if (avio_read(pb, buf, 16) != 16) + return AVERROR_INVALIDDATA; if (is_qcelp_13k_guid(buf)) { st->codecpar->codec_id = AV_CODEC_ID_QCELP; } else if (!memcmp(buf, guid_evrc, 16)) { diff --git a/libavformat/qoadec.c b/libavformat/qoadec.c index 9cce5157f..a9632c46c 100644 --- a/libavformat/qoadec.c +++ b/libavformat/qoadec.c @@ -41,6 +41,7 @@ static int qoa_read_header(AVFormatContext *s) { AVIOContext *pb = s->pb; AVStream *st; + int ret; st = avformat_new_stream(s, NULL); if (!st) @@ -52,7 +53,9 @@ static int qoa_read_header(AVFormatContext *s) st->duration = avio_rb32(pb); st->start_time = 0; - ffio_ensure_seekback(pb, 4); + ret = ffio_ensure_seekback(pb, 4); + if (ret < 0) + return ret; st->codecpar->ch_layout.nb_channels = avio_r8(pb); if (st->codecpar->ch_layout.nb_channels == 0) return AVERROR_INVALIDDATA; diff --git a/libavformat/rcwtdec.c b/libavformat/rcwtdec.c new file mode 100644 index 000000000..f6a007cbd --- /dev/null +++ b/libavformat/rcwtdec.c @@ -0,0 +1,122 @@ +/* + * RCWT (Raw Captions With Time) demuxer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * RCWT (Raw Captions With Time) is a format native to ccextractor, a commonly + * used open source tool for processing 608/708 Closed Captions (CC) sources. + * + * This demuxer implements the specification as of March 2024, which has + * been stable and unchanged since April 2014. + * + * A free specification of RCWT can be found here: + * @url{https://github.com/CCExtractor/ccextractor/blob/master/docs/BINARY_FILE_FORMAT.TXT} + */ + +#include "avformat.h" +#include "demux.h" +#include "internal.h" +#include "subtitles.h" +#include "libavutil/intreadwrite.h" + +#define RCWT_HEADER_SIZE 11 + +typedef struct RCWTContext { + FFDemuxSubtitlesQueue q; +} RCWTContext; + +static int rcwt_read_header(AVFormatContext *avf) +{ + RCWTContext *rcwt = avf->priv_data; + + AVStream *st; + uint8_t header[RCWT_HEADER_SIZE]; + int ret; + + /* read header */ + ret = ffio_read_size(avf->pb, header, RCWT_HEADER_SIZE); + if (ret < 0) + return ret; + + if (AV_RB16(header + 6) != 0x0001) { + av_log(avf, AV_LOG_ERROR, "RCWT format version is not compatible " + "(only version 0.001 is known)\n"); + return AVERROR_INVALIDDATA; + } + + av_log(avf, AV_LOG_DEBUG, "RCWT writer application: %02X version: %02x\n", + header[3], header[5]); + + /* setup stream */ + st = avformat_new_stream(avf, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_id = AV_CODEC_ID_EIA_608; + + avpriv_set_pts_info(st, 64, 1, 1000); + + /* demux */ + while (!avio_feof(avf->pb)) { + AVPacket *sub; + int64_t cluster_pos = avio_tell(avf->pb); + int64_t cluster_pts = avio_rl64(avf->pb); + int cluster_nb_blocks = avio_rl16(avf->pb); + + if (cluster_nb_blocks == 0) + continue; + + sub = ff_subtitles_queue_insert(&rcwt->q, NULL, 0, 0); + if (!sub) + return AVERROR(ENOMEM); + + ret = av_get_packet(avf->pb, sub, cluster_nb_blocks * 3); + if (ret < 0) + return ret; + + sub->pos = cluster_pos; + sub->pts = cluster_pts; + } + + ff_subtitles_queue_finalize(avf, &rcwt->q); + + return 0; +} + +static int rcwt_probe(const AVProbeData *p) +{ + return p->buf_size > RCWT_HEADER_SIZE && + AV_RB16(p->buf) == 0xCCCC && + AV_RB8(p->buf + 2) == 0xED && + AV_RB16(p->buf + 6) == 0x0001 ? 50 : 0; +} + +const FFInputFormat ff_rcwt_demuxer = { + .p.name = "rcwt", + .p.long_name = NULL_IF_CONFIG_SMALL("RCWT (Raw Captions With Time)"), + .p.flags = AVFMT_TS_DISCONT, + .priv_data_size = sizeof(RCWTContext), + .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP, + .read_probe = rcwt_probe, + .read_header = rcwt_read_header, + .read_packet = ff_subtitles_read_packet, + .read_seek2 = ff_subtitles_read_seek, + .read_close = ff_subtitles_read_close +}; diff --git a/libavformat/rcwtenc.c b/libavformat/rcwtenc.c index f2459ef1d..270154b70 100644 --- a/libavformat/rcwtenc.c +++ b/libavformat/rcwtenc.c @@ -21,11 +21,6 @@ /* * RCWT (Raw Captions With Time) is a format native to ccextractor, a commonly * used open source tool for processing 608/708 Closed Captions (CC) sources. - * It can be used to archive the original, raw CC bitstream and to produce - * a source file for later CC processing or conversion. As a result, - * it also allows for interopability with ccextractor for processing CC data - * extracted via ffmpeg. The format is simple to parse and can be used - * to retain all lines and variants of CC. * * This muxer implements the specification as of March 2024, which has * been stable and unchanged since April 2014. @@ -159,7 +154,6 @@ static int rcwt_write_trailer(AVFormatContext *avf) const FFOutputFormat ff_rcwt_muxer = { .p.name = "rcwt", .p.long_name = NULL_IF_CONFIG_SMALL("RCWT (Raw Captions With Time)"), - .p.extensions = "bin", .p.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT, .p.video_codec = AV_CODEC_ID_NONE, .p.audio_codec = AV_CODEC_ID_NONE, diff --git a/libavformat/rdt.c b/libavformat/rdt.c index 9a6b9b53d..2fa53d34a 100644 --- a/libavformat/rdt.c +++ b/libavformat/rdt.c @@ -27,6 +27,7 @@ #include "avformat.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "demux.h" #include "rtpdec.h" #include "rdt.h" diff --git a/libavformat/realtextdec.c b/libavformat/realtextdec.c index ccf87e937..31f226334 100644 --- a/libavformat/realtextdec.c +++ b/libavformat/realtextdec.c @@ -30,7 +30,7 @@ #include "subtitles.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" -#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" typedef struct { FFDemuxSubtitlesQueue q; diff --git a/libavformat/riff.c b/libavformat/riff.c index 157976583..ca81b4837 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -161,7 +161,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', 'P', 'E', 'G') }, { AV_CODEC_ID_MPEG1VIDEO, MKTAG('P', 'I', 'M', '1') }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG('P', 'I', 'M', '2') }, - { AV_CODEC_ID_MPEG1VIDEO, MKTAG('V', 'C', 'R', '2') }, + { AV_CODEC_ID_MPEG2VIDEO, MKTAG('V', 'C', 'R', '2') }, { AV_CODEC_ID_MPEG1VIDEO, MKTAG( 1 , 0 , 0 , 16) }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG( 2 , 0 , 0 , 16) }, { AV_CODEC_ID_MPEG4, MKTAG( 4 , 0 , 0 , 16) }, @@ -506,6 +506,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_RTV1, MKTAG('R', 'T', 'V', '1') }, { AV_CODEC_ID_VMIX, MKTAG('V', 'M', 'X', '1') }, { AV_CODEC_ID_LEAD, MKTAG('L', 'E', 'A', 'D') }, + { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') }, { AV_CODEC_ID_NONE, 0 } }; diff --git a/libavformat/riffdec.c b/libavformat/riffdec.c index 0fe4e02b7..b7a85a6ab 100644 --- a/libavformat/riffdec.c +++ b/libavformat/riffdec.c @@ -24,6 +24,7 @@ #include "libavutil/error.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "demux.h" diff --git a/libavformat/riffenc.c b/libavformat/riffenc.c index 8accb6954..59c9932c3 100644 --- a/libavformat/riffenc.c +++ b/libavformat/riffenc.c @@ -72,7 +72,7 @@ int ff_put_wav_header(AVFormatContext *s, AVIOContext *pb, } /* We use the known constant frame size for the codec if known, otherwise - * fall back on using AVCodecContext.frame_size, which is not as reliable + * fall back on using AVCodecParameters.frame_size, which is not as reliable * for indicating packet duration. */ frame_size = av_get_audio_frame_duration2(par, par->block_align); diff --git a/libavformat/riscv/Makefile b/libavformat/riscv/Makefile new file mode 100644 index 000000000..52857aacb --- /dev/null +++ b/libavformat/riscv/Makefile @@ -0,0 +1 @@ +SHLIBOBJS += riscv/cpu_common.o diff --git a/libavformat/riscv/cpu_common.c b/libavformat/riscv/cpu_common.c new file mode 100644 index 000000000..17c9b392c --- /dev/null +++ b/libavformat/riscv/cpu_common.c @@ -0,0 +1 @@ +#include "libavutil/riscv/cpu_common.c" diff --git a/libavformat/rl2.c b/libavformat/rl2.c index d64c4b81d..aa5933278 100644 --- a/libavformat/rl2.c +++ b/libavformat/rl2.c @@ -36,6 +36,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c index 70e1b4d4b..4b21105d3 100644 --- a/libavformat/rmdec.c +++ b/libavformat/rmdec.c @@ -26,6 +26,7 @@ #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "demux.h" @@ -187,7 +188,8 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, st->codecpar->ch_layout.nb_channels = avio_rb16(pb); if (version == 5) { ast->deint_id = avio_rl32(pb); - avio_read(pb, buf, 4); + if (avio_read(pb, buf, 4) != 4) + return AVERROR_INVALIDDATA; buf[4] = 0; } else { AV_WL32(buf, 0); diff --git a/libavformat/rpl.c b/libavformat/rpl.c index 09d0b68f7..b30d769ef 100644 --- a/libavformat/rpl.c +++ b/libavformat/rpl.c @@ -102,7 +102,7 @@ static AVRational read_fps(const char* line, int* error) line++; for (; *line>='0' && *line<='9'; line++) { // Truncate any numerator too large to fit into an int64_t - if (num > (INT64_MAX - 9) / 10 || den > INT64_MAX / 10) + if (num > (INT64_MAX - 9) / 10ULL || den > INT64_MAX / 10ULL) break; num = 10 * num + (*line - '0'); den *= 10; @@ -202,7 +202,11 @@ static int rpl_read_header(AVFormatContext *s) ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; ast->codecpar->codec_tag = audio_format; ast->codecpar->sample_rate = read_line_and_int(pb, &error); // audio bitrate + if (ast->codecpar->sample_rate < 0) + return AVERROR_INVALIDDATA; channels = read_line_and_int(pb, &error); // number of audio channels + if (channels <= 0) + return AVERROR_INVALIDDATA; error |= read_line(pb, line, sizeof(line)); ast->codecpar->bits_per_coded_sample = read_int(line, &endptr, &error); // audio bits per sample av_strlcpy(audio_type, endptr, RPL_LINE_LENGTH); diff --git a/libavformat/rtmphttp.c b/libavformat/rtmphttp.c index c920c19ab..69dde826a 100644 --- a/libavformat/rtmphttp.c +++ b/libavformat/rtmphttp.c @@ -25,10 +25,9 @@ */ #include "libavutil/avstring.h" -#include "libavutil/intfloat.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time.h" -#include "internal.h" #include "http.h" #include "rtmp.h" diff --git a/libavformat/rtmppkt.c b/libavformat/rtmppkt.c index 905469c14..ec10c89fc 100644 --- a/libavformat/rtmppkt.c +++ b/libavformat/rtmppkt.c @@ -20,9 +20,8 @@ */ #include "libavcodec/bytestream.h" -#include "libavutil/avstring.h" #include "libavutil/intfloat.h" -#include "avformat.h" +#include "libavutil/mem.h" #include "rtmppkt.h" #include "flv.h" diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 871d97e8a..91f18b608 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -32,6 +32,7 @@ #include "libavutil/intfloat.h" #include "libavutil/lfg.h" #include "libavutil/md5.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/random_seed.h" #include "avformat.h" @@ -2917,10 +2918,6 @@ reconnect: return 0; fail: - av_freep(&rt->playpath); - av_freep(&rt->tcurl); - av_freep(&rt->flashver); - av_dict_free(opts); rtmp_close(s); return ret; } diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index fa7544cc0..729bf8368 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -22,6 +22,7 @@ #include "libavutil/mathematics.h" #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/time.h" #include "libavcodec/bytestream.h" diff --git a/libavformat/rtpdec_asf.c b/libavformat/rtpdec_asf.c index 20ca8295f..9664623e5 100644 --- a/libavformat/rtpdec_asf.c +++ b/libavformat/rtpdec_asf.c @@ -28,6 +28,7 @@ #include "libavutil/base64.h" #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "rtpdec_formats.h" #include "rtsp.h" #include "asf.h" diff --git a/libavformat/rtpdec_h264.c b/libavformat/rtpdec_h264.c index a785120c2..72724c290 100644 --- a/libavformat/rtpdec_h264.c +++ b/libavformat/rtpdec_h264.c @@ -37,6 +37,7 @@ #include "libavutil/base64.h" #include "libavutil/intreadwrite.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "avformat.h" #include "rtpdec.h" diff --git a/libavformat/rtpdec_hevc.c b/libavformat/rtpdec_hevc.c index a739ed5bd..0e29efc3d 100644 --- a/libavformat/rtpdec_hevc.c +++ b/libavformat/rtpdec_hevc.c @@ -21,6 +21,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "avformat.h" #include "internal.h" diff --git a/libavformat/rtpdec_latm.c b/libavformat/rtpdec_latm.c index 329b8dbc3..2b4478289 100644 --- a/libavformat/rtpdec_latm.c +++ b/libavformat/rtpdec_latm.c @@ -23,6 +23,7 @@ #include "rtpdec_formats.h" #include "internal.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavcodec/get_bits.h" struct PayloadContext { diff --git a/libavformat/rtpdec_mpa_robust.c b/libavformat/rtpdec_mpa_robust.c index c0355edec..8709b0d4e 100644 --- a/libavformat/rtpdec_mpa_robust.c +++ b/libavformat/rtpdec_mpa_robust.c @@ -21,6 +21,7 @@ #include "libavutil/attributes.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avio_internal.h" #include "rtpdec_formats.h" diff --git a/libavformat/rtpdec_mpeg4.c b/libavformat/rtpdec_mpeg4.c index 723b6fc6e..6531632b2 100644 --- a/libavformat/rtpdec_mpeg4.c +++ b/libavformat/rtpdec_mpeg4.c @@ -31,6 +31,7 @@ #include "internal.h" #include "libavutil/attributes.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavcodec/get_bits.h" #define MAX_AAC_HBR_FRAME_SIZE 8191 diff --git a/libavformat/rtpdec_qt.c b/libavformat/rtpdec_qt.c index b71055f8b..af00a7e76 100644 --- a/libavformat/rtpdec_qt.c +++ b/libavformat/rtpdec_qt.c @@ -25,6 +25,7 @@ * @author Ronald S. Bultje */ +#include "libavutil/mem.h" #include "avformat.h" #include "internal.h" #include "avio_internal.h" diff --git a/libavformat/rtpdec_rfc4175.c b/libavformat/rtpdec_rfc4175.c index 83abe499f..d6260ab69 100644 --- a/libavformat/rtpdec_rfc4175.c +++ b/libavformat/rtpdec_rfc4175.c @@ -24,6 +24,7 @@ #include "avio_internal.h" #include "rtpdec_formats.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/parseutils.h" diff --git a/libavformat/rtpdec_xiph.c b/libavformat/rtpdec_xiph.c index c2db10dab..95f4bdf3a 100644 --- a/libavformat/rtpdec_xiph.c +++ b/libavformat/rtpdec_xiph.c @@ -31,6 +31,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/base64.h" +#include "libavutil/mem.h" #include "libavcodec/bytestream.h" #include "avio_internal.h" diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index a8d296a15..7b4ae37d1 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -24,6 +24,7 @@ #include "internal.h" #include "mux.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/random_seed.h" #include "libavutil/opt.h" diff --git a/libavformat/rtpenc_h264_hevc.c b/libavformat/rtpenc_h264_hevc.c index 0c88fc2a2..4d222dca7 100644 --- a/libavformat/rtpenc_h264_hevc.c +++ b/libavformat/rtpenc_h264_hevc.c @@ -31,6 +31,7 @@ #include "avformat.h" #include "avc.h" +#include "nal.h" #include "rtpenc.h" static void flush_buffered(AVFormatContext *s1, int last) @@ -185,20 +186,20 @@ void ff_rtp_send_h264_hevc(AVFormatContext *s1, const uint8_t *buf1, int size) s->timestamp = s->cur_timestamp; s->buf_ptr = s->buf; if (s->nal_length_size) - r = ff_avc_mp4_find_startcode(buf1, end, s->nal_length_size) ? buf1 : end; + r = ff_nal_mp4_find_startcode(buf1, end, s->nal_length_size) ? buf1 : end; else - r = ff_avc_find_startcode(buf1, end); + r = ff_nal_find_startcode(buf1, end); while (r < end) { const uint8_t *r1; if (s->nal_length_size) { - r1 = ff_avc_mp4_find_startcode(r, end, s->nal_length_size); + r1 = ff_nal_mp4_find_startcode(r, end, s->nal_length_size); if (!r1) r1 = end; r += s->nal_length_size; } else { while (!*(r++)); - r1 = ff_avc_find_startcode(r, end); + r1 = ff_nal_find_startcode(r, end); } nal_send(s1, r, r1 - r, r1 == end); r = r1; diff --git a/libavformat/rtpenc_mpegts.c b/libavformat/rtpenc_mpegts.c index 0d6403a04..f9ff7e99c 100644 --- a/libavformat/rtpenc_mpegts.c +++ b/libavformat/rtpenc_mpegts.c @@ -20,6 +20,7 @@ */ #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "avformat.h" #include "avio_internal.h" diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c index cac361047..15d005093 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -24,6 +24,7 @@ * RTP protocol */ +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "libavutil/avstring.h" #include "libavutil/opt.h" @@ -34,7 +35,6 @@ #include "ip.h" #include -#include "internal.h" #include "network.h" #include "os_support.h" #include @@ -379,6 +379,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) return 0; fail: + ff_ip_reset_filters(&s->filters); ffurl_closep(&s->rtp_hd); ffurl_closep(&s->rtcp_hd); ffurl_closep(&s->fec_hd); diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index caf7fcd2d..5ea471b40 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -27,6 +27,7 @@ #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "libavutil/random_seed.h" #include "libavutil/dict.h" @@ -1726,7 +1727,7 @@ void ff_rtsp_close_connections(AVFormatContext *s) int ff_rtsp_connect(AVFormatContext *s) { RTSPState *rt = s->priv_data; - char proto[128], host[1024], path[1024]; + char proto[128], host[1024], path[2048]; char tcpname[1024], cmd[MAX_URL_SIZE], auth[128]; const char *lower_rtsp_proto = "tcp"; int port, err, tcp_fd; @@ -2076,6 +2077,7 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, if (fdsnum != 2) { av_log(s, AV_LOG_ERROR, "Number of fds %d not supported\n", fdsnum); + av_freep(&fds); return AVERROR_INVALIDDATA; } for (fdsidx = 0; fdsidx < fdsnum; fdsidx++) { @@ -2318,7 +2320,7 @@ redo: } // Make real NTP start time available in AVFormatContext if (s->start_time_realtime == AV_NOPTS_VALUE) { - s->start_time_realtime = av_rescale (rtpctx->first_rtcp_ntp_time - (NTP_OFFSET << 32), 1000000, 1LL << 32); + s->start_time_realtime = ff_parse_ntp_time(rtpctx->first_rtcp_ntp_time) - NTP_OFFSET_US; if (rtpctx->st) { s->start_time_realtime -= av_rescale_q (rtpctx->rtcp_ts_offset, rtpctx->st->time_base, AV_TIME_BASE_Q); diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c index 8ca6f723e..10078ce2f 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -24,6 +24,7 @@ #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/random_seed.h" #include "libavutil/time.h" #include "avformat.h" diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c index 3d444ccbf..f2f4b6d52 100644 --- a/libavformat/rtspenc.c +++ b/libavformat/rtspenc.c @@ -32,6 +32,7 @@ #include "avio_internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/time.h" #include "url.h" diff --git a/libavformat/sapdec.c b/libavformat/sapdec.c index 710eb408b..d5b5d71c0 100644 --- a/libavformat/sapdec.c +++ b/libavformat/sapdec.c @@ -23,6 +23,7 @@ #include "demux.h" #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "network.h" #include "os_support.h" #include "internal.h" diff --git a/libavformat/sapenc.c b/libavformat/sapenc.c index 28839b837..87a834a8d 100644 --- a/libavformat/sapenc.c +++ b/libavformat/sapenc.c @@ -20,6 +20,7 @@ */ #include "avformat.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "libavutil/random_seed.h" #include "libavutil/avstring.h" diff --git a/libavformat/sauce.c b/libavformat/sauce.c index a9ee9697a..96e9bfc33 100644 --- a/libavformat/sauce.c +++ b/libavformat/sauce.c @@ -24,8 +24,8 @@ * SAUCE header parser */ -#include "libavutil/intreadwrite.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "avformat.h" #include "sauce.h" diff --git a/libavformat/sbgdec.c b/libavformat/sbgdec.c index e60eb1481..bf319be22 100644 --- a/libavformat/sbgdec.c +++ b/libavformat/sbgdec.c @@ -26,6 +26,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time_internal.h" #include "avformat.h" diff --git a/libavformat/scd.c b/libavformat/scd.c index 1eef83477..ee118c166 100644 --- a/libavformat/scd.c +++ b/libavformat/scd.c @@ -21,11 +21,13 @@ * 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/avstring.h" + +#include + #include "libavutil/intreadwrite.h" #include "libavutil/internal.h" #include "libavutil/macros.h" -#include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavformat/internal.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/sdp.c b/libavformat/sdp.c index 69e285afe..a9e964bae 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -24,6 +24,7 @@ #include "libavutil/avstring.h" #include "libavutil/base64.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "libavutil/opt.h" #include "libavcodec/xiph.h" @@ -32,6 +33,7 @@ #include "internal.h" #include "avc.h" #include "hevc.h" +#include "nal.h" #include "rtp.h" #include "version.h" #if CONFIG_NETWORK @@ -189,14 +191,14 @@ static int extradata2psets(AVFormatContext *s, const AVCodecParameters *par, } memcpy(psets, pset_string, strlen(pset_string)); p = psets + strlen(pset_string); - r = ff_avc_find_startcode(extradata, extradata + extradata_size); + r = ff_nal_find_startcode(extradata, extradata + extradata_size); while (r < extradata + extradata_size) { const uint8_t *r1; uint8_t nal_type; while (!*(r++)); nal_type = *r & 0x1f; - r1 = ff_avc_find_startcode(r, extradata + extradata_size); + r1 = ff_nal_find_startcode(r, extradata + extradata_size); if (nal_type != 7 && nal_type != 8) { /* Only output SPS and PPS */ r = r1; continue; diff --git a/libavformat/seek.c b/libavformat/seek.c index 9ac133bf2..800ef4057 100644 --- a/libavformat/seek.c +++ b/libavformat/seek.c @@ -23,6 +23,7 @@ #include "libavutil/avassert.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/timestamp.h" #include "libavcodec/avcodec.h" diff --git a/libavformat/segafilm.c b/libavformat/segafilm.c index f86845f35..e72d872f9 100644 --- a/libavformat/segafilm.c +++ b/libavformat/segafilm.c @@ -28,10 +28,10 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" -#include "avio_internal.h" #define FILM_TAG MKBETAG('F', 'I', 'L', 'M') #define FDSC_TAG MKBETAG('F', 'D', 'S', 'C') @@ -234,6 +234,7 @@ static int film_read_header(AVFormatContext *s) else if (film->audio_type != AV_CODEC_ID_NONE) audio_frame_counter += (film->sample_table[i].sample_size / (film->audio_channels * film->audio_bits / 8)); + film->sample_table[i].keyframe = 1; } else { film->sample_table[i].stream = film->video_stream_index; film->sample_table[i].pts = AV_RB32(&scratch[8]) & 0x7FFFFFFF; diff --git a/libavformat/segment.c b/libavformat/segment.c index a38baa4f2..65323ec67 100644 --- a/libavformat/segment.c +++ b/libavformat/segment.c @@ -35,6 +35,7 @@ #include "libavutil/avassert.h" #include "libavutil/internal.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/avstring.h" #include "libavutil/parseutils.h" diff --git a/libavformat/sierravmd.c b/libavformat/sierravmd.c index 039c6436d..2103ff64d 100644 --- a/libavformat/sierravmd.c +++ b/libavformat/sierravmd.c @@ -29,6 +29,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/smacker.c b/libavformat/smacker.c index c87174476..774aad679 100644 --- a/libavformat/smacker.c +++ b/libavformat/smacker.c @@ -27,6 +27,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "demux.h" diff --git a/libavformat/smjpegdec.c b/libavformat/smjpegdec.c index 0003dbf0f..9f058d8eb 100644 --- a/libavformat/smjpegdec.c +++ b/libavformat/smjpegdec.c @@ -26,10 +26,10 @@ #include +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" -#include "riff.h" #include "smjpeg.h" typedef struct SMJPEGContext { diff --git a/libavformat/smoothstreamingenc.c b/libavformat/smoothstreamingenc.c index e9c9f5d59..adf300800 100644 --- a/libavformat/smoothstreamingenc.c +++ b/libavformat/smoothstreamingenc.c @@ -31,6 +31,7 @@ #include "avc.h" #include "url.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/avstring.h" #include "libavutil/mathematics.h" @@ -330,7 +331,9 @@ static int ism_write_header(AVFormatContext *s) if (!(st = avformat_new_stream(ctx, NULL))) { return AVERROR(ENOMEM); } - avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar); + if ((ret = avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar)) < 0) { + return ret; + } st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; st->time_base = s->streams[i]->time_base; diff --git a/libavformat/soxdec.c b/libavformat/soxdec.c index 661d6b30e..ba349c870 100644 --- a/libavformat/soxdec.c +++ b/libavformat/soxdec.c @@ -32,6 +32,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/spdifdec.c b/libavformat/spdifdec.c index 6a01f2ba2..dcfe471f4 100644 --- a/libavformat/spdifdec.c +++ b/libavformat/spdifdec.c @@ -236,6 +236,8 @@ int ff_spdif_read_packet(AVFormatContext *s, AVPacket *pkt) st->codecpar->codec_id = codec_id; if (codec_id == AV_CODEC_ID_EAC3) ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL; + else + ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS; } else if (codec_id != s->streams[0]->codecpar->codec_id) { avpriv_report_missing_feature(s, "Codec change in IEC 61937"); return AVERROR_PATCHWELCOME; diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index f97f4d017..ab3f73da0 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -54,6 +54,7 @@ #include "libavcodec/adts_parser.h" #include "libavcodec/dca.h" #include "libavcodec/dca_syncwords.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" typedef struct IEC61937Context { diff --git a/libavformat/srtp.c b/libavformat/srtp.c index f8b686c5a..7e5a42e32 100644 --- a/libavformat/srtp.c +++ b/libavformat/srtp.c @@ -24,6 +24,7 @@ #include "libavutil/hmac.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "rtp.h" #include "rtpdec.h" #include "srtp.h" diff --git a/libavformat/srtpproto.c b/libavformat/srtpproto.c index 61669e05a..02cf15632 100644 --- a/libavformat/srtpproto.c +++ b/libavformat/srtpproto.c @@ -61,7 +61,7 @@ static int srtp_close(URLContext *h) return 0; } -static int srtp_open(URLContext *h, const char *uri, int flags) +static int srtp_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { SRTPProtoContext *s = h->priv_data; char hostname[256], buf[1024], path[1024]; @@ -78,7 +78,7 @@ static int srtp_open(URLContext *h, const char *uri, int flags) path, sizeof(path), uri); ff_url_join(buf, sizeof(buf), "rtp", NULL, hostname, rtp_port, "%s", path); if ((ret = ffurl_open_whitelist(&s->rtp_hd, buf, flags, &h->interrupt_callback, - NULL, h->protocol_whitelist, h->protocol_blacklist, h)) < 0) + options, h->protocol_whitelist, h->protocol_blacklist, h)) < 0) goto fail; h->max_packet_size = FFMIN(s->rtp_hd->max_packet_size, @@ -131,7 +131,7 @@ static int srtp_get_multi_file_handle(URLContext *h, int **handles, const URLProtocol ff_srtp_protocol = { .name = "srtp", - .url_open = srtp_open, + .url_open2 = srtp_open, .url_read = srtp_read, .url_write = srtp_write, .url_close = srtp_close, diff --git a/libavformat/subtitles.c b/libavformat/subtitles.c index 3413763c7..69e4df88a 100644 --- a/libavformat/subtitles.c +++ b/libavformat/subtitles.c @@ -21,7 +21,9 @@ #include "avformat.h" #include "subtitles.h" #include "avio_internal.h" +#include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" void ff_text_init_avio(void *s, FFTextReader *r, AVIOContext *pb) { @@ -111,15 +113,19 @@ AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q, { AVPacket **subs, *sub; + av_assert1(event || len == 0); + if (merge && q->nb_subs > 0) { /* merge with previous event */ int old_len; sub = q->subs[q->nb_subs - 1]; old_len = sub->size; - if (av_grow_packet(sub, len) < 0) - return NULL; - memcpy(sub->data + old_len, event, len); + if (event) { + if (av_grow_packet(sub, len) < 0) + return NULL; + memcpy(sub->data + old_len, event, len); + } } else { /* new event */ @@ -133,14 +139,16 @@ AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q, sub = av_packet_alloc(); if (!sub) return NULL; - if (av_new_packet(sub, len) < 0) { - av_packet_free(&sub); - return NULL; + if (event) { + if (av_new_packet(sub, len) < 0) { + av_packet_free(&sub); + return NULL; + } + memcpy(sub->data, event, len); } - subs[q->nb_subs++] = sub; sub->flags |= AV_PKT_FLAG_KEY; sub->pts = sub->dts = 0; - memcpy(sub->data, event, len); + subs[q->nb_subs++] = sub; } return sub; } diff --git a/libavformat/subtitles.h b/libavformat/subtitles.h index 88665663c..ad6b96ca6 100644 --- a/libavformat/subtitles.h +++ b/libavformat/subtitles.h @@ -112,7 +112,7 @@ typedef struct { /** * Insert a new subtitle event. * - * @param event the subtitle line, may not be zero terminated + * @param event the subtitle line (not zero terminated) or NULL on not yet available event * @param len the length of the event (in strlen() sense, so without '\0') * @param merge set to 1 if the current event should be concatenated with the * previous one instead of adding a new entry, 0 otherwise diff --git a/libavformat/swfdec.c b/libavformat/swfdec.c index 6bba5fb7e..29eefc68a 100644 --- a/libavformat/swfdec.c +++ b/libavformat/swfdec.c @@ -31,6 +31,7 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/get_bits.h" #include "demux.h" #include "swf.h" diff --git a/libavformat/takdec.c b/libavformat/takdec.c index 5c405ebd2..21fff3fcb 100644 --- a/libavformat/takdec.c +++ b/libavformat/takdec.c @@ -20,6 +20,7 @@ */ #include "libavutil/crc.h" +#include "libavutil/mem.h" #define BITSTREAM_READER_LE #include "libavcodec/tak.h" diff --git a/libavformat/tcp.c b/libavformat/tcp.c index db41394a8..755e3af24 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -20,11 +20,11 @@ */ #include "avformat.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "libavutil/opt.h" #include "libavutil/time.h" -#include "internal.h" #include "network.h" #include "os_support.h" #include "url.h" diff --git a/libavformat/tee.c b/libavformat/tee.c index 9597137ec..1a2a8ead8 100644 --- a/libavformat/tee.c +++ b/libavformat/tee.c @@ -22,6 +22,7 @@ #include "libavutil/avutil.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/bsf.h" #include "internal.h" @@ -118,7 +119,6 @@ static int parse_slave_fifo_options(const char *fifo_options, TeeSlave *tee_slav static int close_slave(TeeSlave *tee_slave) { AVFormatContext *avf; - unsigned i; int ret = 0; av_dict_free(&tee_slave->fifo_options); @@ -130,7 +130,7 @@ static int close_slave(TeeSlave *tee_slave) ret = av_write_trailer(avf); if (tee_slave->bsfs) { - for (i = 0; i < avf->nb_streams; ++i) + for (unsigned i = 0; i < avf->nb_streams; ++i) av_bsf_free(&tee_slave->bsfs[i]); } av_freep(&tee_slave->stream_map); @@ -145,9 +145,8 @@ static int close_slave(TeeSlave *tee_slave) static void close_slaves(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; - unsigned i; - for (i = 0; i < tee->nb_slaves; i++) { + for (unsigned i = 0; i < tee->nb_slaves; i++) { close_slave(&tee->slaves[i]); } av_freep(&tee->slaves); @@ -155,14 +154,12 @@ static void close_slaves(AVFormatContext *avf) static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) { - int i, ret; + int ret; AVDictionary *options = NULL, *bsf_options = NULL; - AVDictionaryEntry *entry; + const AVDictionaryEntry *entry; char *filename; - char *format = NULL, *select = NULL, *on_fail = NULL; - char *use_fifo = NULL, *fifo_options_str = NULL; + char *format = NULL, *select = NULL; AVFormatContext *avf2 = NULL; - AVStream *st, *st2; int stream_count; int fullret; char *subselect = NULL, *next_subselect = NULL, *first_subselect = NULL, *tmp_select = NULL; @@ -171,30 +168,34 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) return ret; #define CONSUME_OPTION(option, field, action) do { \ - if ((entry = av_dict_get(options, option, NULL, 0))) { \ - field = entry->value; \ + AVDictionaryEntry *en = av_dict_get(options, option, NULL, 0); \ + if (en) { \ + field = en->value; \ { action } \ av_dict_set(&options, option, NULL, 0); \ } \ } while (0) #define STEAL_OPTION(option, field) \ CONSUME_OPTION(option, field, \ - entry->value = NULL; /* prevent it from being freed */) -#define PROCESS_OPTION(option, field, function, on_error) \ - CONSUME_OPTION(option, field, if ((ret = function) < 0) { { on_error } goto end; }) + en->value = NULL; /* prevent it from being freed */) +#define PROCESS_OPTION(option, function, on_error) do { \ + const char *value; \ + CONSUME_OPTION(option, value, if ((ret = function) < 0) \ + { { on_error } goto end; }); \ + } while (0) STEAL_OPTION("f", format); STEAL_OPTION("select", select); - PROCESS_OPTION("onfail", on_fail, - parse_slave_failure_policy_option(on_fail, tee_slave), + PROCESS_OPTION("onfail", + parse_slave_failure_policy_option(value, tee_slave), av_log(avf, AV_LOG_ERROR, "Invalid onfail option value, " "valid options are 'abort' and 'ignore'\n");); - PROCESS_OPTION("use_fifo", use_fifo, - parse_slave_fifo_policy(use_fifo, tee_slave), + PROCESS_OPTION("use_fifo", + parse_slave_fifo_policy(value, tee_slave), av_log(avf, AV_LOG_ERROR, "Error parsing fifo options: %s\n", av_err2str(ret));); - PROCESS_OPTION("fifo_options", fifo_options_str, - parse_slave_fifo_options(fifo_options_str, tee_slave), ;); + PROCESS_OPTION("fifo_options", + parse_slave_fifo_options(value, tee_slave), ;); entry = NULL; while ((entry = av_dict_get(options, "bsfs", entry, AV_DICT_IGNORE_SUFFIX))) { /* trim out strlen("bsfs") characters from key */ @@ -248,8 +249,9 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) } stream_count = 0; - for (i = 0; i < avf->nb_streams; i++) { - st = avf->streams[i]; + for (unsigned i = 0; i < avf->nb_streams; i++) { + const AVStream *st = avf->streams[i]; + AVStream *st2; if (select) { tmp_select = av_strdup(select); // av_strtok is destructive so we regenerate it in each loop if (!tmp_select) { @@ -311,7 +313,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) } entry = NULL; - while (entry = av_dict_get(bsf_options, "", NULL, AV_DICT_IGNORE_SUFFIX)) { + while (entry = av_dict_iterate(bsf_options, NULL)) { const char *spec = entry->key; if (*spec) { if (strspn(spec, slave_bsfs_spec_sep) != 1) { @@ -324,7 +326,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) spec++; /* consume separator */ } - for (i = 0; i < avf2->nb_streams; i++) { + for (unsigned i = 0; i < avf2->nb_streams; i++) { ret = avformat_match_stream_specifier(avf2, avf2->streams[i], spec); if (ret < 0) { av_log(avf, AV_LOG_ERROR, @@ -355,7 +357,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) av_dict_set(&bsf_options, entry->key, NULL, 0); } - for (i = 0; i < avf->nb_streams; i++){ + for (unsigned i = 0; i < avf->nb_streams; i++){ int target_stream = tee_slave->stream_map[i]; if (target_stream < 0) continue; @@ -388,7 +390,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) if (options) { entry = NULL; - while ((entry = av_dict_get(options, "", entry, AV_DICT_IGNORE_SUFFIX))) + while ((entry = av_dict_iterate(options, entry))) av_log(avf2, AV_LOG_ERROR, "Unknown option '%s'\n", entry->key); ret = AVERROR_OPTION_NOT_FOUND; goto end; @@ -405,10 +407,9 @@ end: static void log_slave(TeeSlave *slave, void *log_ctx, int log_level) { - int i; av_log(log_ctx, log_level, "filename:'%s' format:%s\n", slave->avf->url, slave->avf->oformat->name); - for (i = 0; i < slave->avf->nb_streams; i++) { + for (unsigned i = 0; i < slave->avf->nb_streams; i++) { AVStream *st = slave->avf->streams[i]; AVBSFContext *bsf = slave->bsfs[i]; const char *bsf_name; @@ -448,7 +449,7 @@ static int tee_process_slave_failure(AVFormatContext *avf, unsigned slave_idx, i static int tee_write_header(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; - unsigned nb_slaves = 0, i; + unsigned nb_slaves = 0; const char *filename = avf->url; char **slaves = NULL; int ret; @@ -474,7 +475,7 @@ static int tee_write_header(AVFormatContext *avf) } tee->nb_slaves = tee->nb_alive = nb_slaves; - for (i = 0; i < nb_slaves; i++) { + for (unsigned i = 0; i < nb_slaves; i++) { tee->slaves[i].use_fifo = tee->use_fifo; ret = av_dict_copy(&tee->slaves[i].fifo_options, tee->fifo_options, 0); @@ -491,9 +492,9 @@ static int tee_write_header(AVFormatContext *avf) av_freep(&slaves[i]); } - for (i = 0; i < avf->nb_streams; i++) { - int j, mapped = 0; - for (j = 0; j < tee->nb_slaves; j++) + for (unsigned i = 0; i < avf->nb_streams; i++) { + int mapped = 0; + for (unsigned j = 0; j < tee->nb_slaves; j++) if (tee->slaves[j].avf) mapped += tee->slaves[j].stream_map[i] >= 0; if (!mapped) @@ -504,7 +505,7 @@ static int tee_write_header(AVFormatContext *avf) return 0; fail: - for (i = 0; i < nb_slaves; i++) + for (unsigned i = 0; i < nb_slaves; i++) av_freep(&slaves[i]); close_slaves(avf); av_free(slaves); @@ -515,9 +516,8 @@ static int tee_write_trailer(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; int ret_all = 0, ret; - unsigned i; - for (i = 0; i < tee->nb_slaves; i++) { + for (unsigned i = 0; i < tee->nb_slaves; i++) { if ((ret = close_slave(&tee->slaves[i])) < 0) { ret = tee_process_slave_failure(avf, i, ret); if (!ret_all && ret < 0) @@ -531,15 +531,16 @@ static int tee_write_trailer(AVFormatContext *avf) static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt) { TeeContext *tee = avf->priv_data; - AVFormatContext *avf2; - AVBSFContext *bsfs; AVPacket *const pkt2 = ffformatcontext(avf)->pkt; int ret_all = 0, ret; - unsigned i, s; + unsigned s; int s2; - for (i = 0; i < tee->nb_slaves; i++) { - if (!(avf2 = tee->slaves[i].avf)) + for (unsigned i = 0; i < tee->nb_slaves; i++) { + AVFormatContext *avf2 = tee->slaves[i].avf; + AVBSFContext *bsfs; + + if (!avf2) continue; /* Flush slave if pkt is NULL*/ diff --git a/libavformat/tests/movenc.c b/libavformat/tests/movenc.c index 1ec9b6729..23a827e97 100644 --- a/libavformat/tests/movenc.c +++ b/libavformat/tests/movenc.c @@ -23,6 +23,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/md5.h" +#include "libavutil/mem.h" #include "libavformat/avformat.h" @@ -57,7 +58,7 @@ struct AVMD5* md5; uint8_t hash[HASH_SIZE]; AVPacket *pkt; -AVStream *video_st, *audio_st; +AVStream *video_st, *audio_st, *id3_st; int64_t audio_dts, video_dts; int bframes; @@ -176,7 +177,7 @@ static void check_func(int value, int line, const char *msg, ...) } #define check(value, ...) check_func(value, __LINE__, __VA_ARGS__) -static void init_fps(int bf, int audio_preroll, int fps) +static void init_fps(int bf, int audio_preroll, int fps, int id3) { AVStream *st; int iobuf_size = force_iobuf_size ? force_iobuf_size : sizeof(iobuf); @@ -214,6 +215,7 @@ static void init_fps(int bf, int audio_preroll, int fps) st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_id = AV_CODEC_ID_AAC; st->codecpar->sample_rate = 44100; + st->codecpar->frame_size = 1024; st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; st->time_base.num = 1; st->time_base.den = 44100; @@ -224,6 +226,17 @@ static void init_fps(int bf, int audio_preroll, int fps) memcpy(st->codecpar->extradata, aac_extradata, sizeof(aac_extradata)); audio_st = st; + if (id3) { + st = avformat_new_stream(ctx, NULL); + if (!st) + exit(1); + st->codecpar->codec_type = AVMEDIA_TYPE_DATA; + st->codecpar->codec_id = AV_CODEC_ID_TIMED_ID3; + st->time_base.num = 1; + st->time_base.den = 1000; + id3_st = st; + } + if (avformat_write_header(ctx, &opts) < 0) exit(1); av_dict_free(&opts); @@ -231,9 +244,10 @@ static void init_fps(int bf, int audio_preroll, int fps) frames = 0; gop_size = 30; duration = video_st->time_base.den / fps; - audio_duration = 1024LL * audio_st->time_base.den / audio_st->codecpar->sample_rate; + audio_duration = (long long)audio_st->codecpar->frame_size * + audio_st->time_base.den / audio_st->codecpar->sample_rate; if (audio_preroll) - audio_preroll = 2048LL * audio_st->time_base.den / audio_st->codecpar->sample_rate; + audio_preroll = 2 * audio_duration; bframes = bf; video_dts = bframes ? -duration : 0; @@ -242,7 +256,7 @@ static void init_fps(int bf, int audio_preroll, int fps) static void init(int bf, int audio_preroll) { - init_fps(bf, audio_preroll, 30); + init_fps(bf, audio_preroll, 30, 0); } static void mux_frames(int n, int c) @@ -256,6 +270,7 @@ static void mux_frames(int n, int c) pkt->dts = pkt->pts = audio_dts; pkt->stream_index = 1; pkt->duration = audio_duration; + pkt->flags |= AV_PKT_FLAG_KEY; audio_dts += audio_duration; } else { if (frames == end_frames) @@ -313,6 +328,23 @@ static void mux_frames(int n, int c) } } +static void mux_id3(void) +{ + uint8_t pktdata[8] = { 0 }; + av_packet_unref(pkt); + + pkt->dts = pkt->pts = av_rescale_q(video_dts + (bframes ? duration : 0), + video_st->time_base, id3_st->time_base); + pkt->stream_index = id3_st->index; + pkt->duration = 0; + + AV_WB32(pktdata + 4, pkt->pts); + pkt->data = pktdata; + pkt->size = 8; + + av_write_frame(ctx, pkt); +} + static void mux_gops(int n) { mux_frames(gop_size * n, 0); @@ -441,6 +473,7 @@ int main(int argc, char **argv) // Similar to the previous one, but with input that doesn't start at // pts/dts 0. avoid_negative_ts behaves in the same way as // in non-empty-moov-no-elst above. + init_count_warnings(); init_out("empty-moov-no-elst"); av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov", 0); init(1, 0); @@ -448,6 +481,9 @@ int main(int argc, char **argv) finish(); close_out(); + reset_count_warnings(); + check(num_warnings == 0, "Unexpected warnings printed"); + // Same as the previous one, but disable avoid_negative_ts (which // would require using an edit list, but with empty_moov, one can't // write a sensible edit list, when the start timestamps aren't known). @@ -701,7 +737,7 @@ int main(int argc, char **argv) // by the edit list. init_out("vfr"); av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov+dash", 0); - init_fps(1, 1, 3); + init_fps(1, 1, 3, 0); mux_frames(gop_size/2, 0); duration /= 10; mux_frames(gop_size/2, 0); @@ -720,7 +756,7 @@ int main(int argc, char **argv) clear_duration = 1; init_out("vfr-noduration"); av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov+dash", 0); - init_fps(1, 1, 3); + init_fps(1, 1, 3, 0); mux_frames(gop_size/2, 0); duration /= 10; mux_frames(gop_size/2, 0); @@ -736,7 +772,7 @@ int main(int argc, char **argv) force_iobuf_size = 1500; init_out("large_frag"); av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0); - init_fps(1, 1, 3); + init_fps(1, 1, 3, 0); mux_gops(2); finish(); close_out(); @@ -750,7 +786,7 @@ int main(int argc, char **argv) init_out("vfr-noduration-interleave"); av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0); av_dict_set(&opts, "frag_duration", "650000", 0); - init_fps(1, 1, 30); + init_fps(1, 1, 30, 0); mux_frames(gop_size/2, 0); // Pretend that the packet duration is the normal, even if // we actually skip a bunch of frames. (I.e., simulate that @@ -787,6 +823,19 @@ int main(int argc, char **argv) finish(); close_out(); + // Write a manually fragmented file, with timed ID3 packets at the head + // of each fragment. + init_out("emsg"); + av_dict_set(&opts, "movflags", "+frag_custom+cmaf", 0); + init_fps(1, 0, 30, 1); + mux_id3(); + mux_gops(2); + av_write_frame(ctx, NULL); // Flush fragment. + mux_id3(); + mux_gops(2); + finish(); + close_out(); + av_free(md5); av_packet_free(&pkt); diff --git a/libavformat/tiertexseq.c b/libavformat/tiertexseq.c index 86b102386..844b98e18 100644 --- a/libavformat/tiertexseq.c +++ b/libavformat/tiertexseq.c @@ -25,6 +25,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/tls.c b/libavformat/tls.c index 33e8ec384..f96ff6215 100644 --- a/libavformat/tls.c +++ b/libavformat/tls.c @@ -20,14 +20,13 @@ */ #include "avformat.h" -#include "internal.h" #include "network.h" #include "os_support.h" #include "url.h" #include "tls.h" #include "libavutil/avstring.h" #include "libavutil/getenv_utf8.h" -#include "libavutil/opt.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" static int set_options(TLSShared *c, const char *uri) diff --git a/libavformat/tls_gnutls.c b/libavformat/tls_gnutls.c index 2ab38a199..df251ad79 100644 --- a/libavformat/tls_gnutls.c +++ b/libavformat/tls_gnutls.c @@ -25,15 +25,12 @@ #include #include "avformat.h" -#include "internal.h" #include "network.h" #include "os_support.h" #include "url.h" #include "tls.h" -#include "libavcodec/internal.h" -#include "libavutil/avstring.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" +#include "libavutil/thread.h" #ifndef GNUTLS_VERSION_NUMBER #define GNUTLS_VERSION_NUMBER LIBGNUTLS_VERSION_NUMBER @@ -41,7 +38,6 @@ #if HAVE_THREADS && GNUTLS_VERSION_NUMBER <= 0x020b00 #include -#include "libavutil/thread.h" GCRY_THREAD_OPTION_PTHREAD_IMPL; #endif @@ -54,22 +50,24 @@ typedef struct TLSContext { int io_err; } TLSContext; +static AVMutex gnutls_mutex = AV_MUTEX_INITIALIZER; + void ff_gnutls_init(void) { - ff_lock_avformat(); + ff_mutex_lock(&gnutls_mutex); #if HAVE_THREADS && GNUTLS_VERSION_NUMBER < 0x020b00 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0) gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); #endif gnutls_global_init(); - ff_unlock_avformat(); + ff_mutex_unlock(&gnutls_mutex); } void ff_gnutls_deinit(void) { - ff_lock_avformat(); + ff_mutex_lock(&gnutls_mutex); gnutls_global_deinit(); - ff_unlock_avformat(); + ff_mutex_unlock(&gnutls_mutex); } static int print_tls_error(URLContext *h, int ret) diff --git a/libavformat/tls_mbedtls.c b/libavformat/tls_mbedtls.c index 8503523b6..e802c6b87 100644 --- a/libavformat/tls_mbedtls.c +++ b/libavformat/tls_mbedtls.c @@ -26,12 +26,18 @@ #include #include #include +#include +#ifdef MBEDTLS_PSA_CRYPTO_C +#include +#endif #include "avformat.h" #include "internal.h" #include "url.h" #include "tls.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" +#include "libavutil/avstring.h" typedef struct TLSContext { const AVClass *class; @@ -108,6 +114,13 @@ static int mbedtls_recv(void *ctx, unsigned char *buf, size_t len) return handle_transport_error(h, "ffurl_read", MBEDTLS_ERR_SSL_WANT_READ, ret); } +static void mbedtls_debug(void *ctx, int lvl, const char *file, int line, const char *msg) +{ + URLContext *h = (URLContext*) ctx; + int av_lvl = lvl >= 4 ? AV_LOG_TRACE : AV_LOG_DEBUG; + av_log(h, av_lvl, "%s:%d: %s", av_basename(file), line, msg); +} + static void handle_pk_parse_error(URLContext *h, int ret) { switch (ret) { @@ -137,6 +150,9 @@ static void handle_handshake_error(URLContext *h, int ret) case MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE: av_log(h, AV_LOG_ERROR, "TLS handshake failed.\n"); break; + case MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION: + av_log(h, AV_LOG_ERROR, "TLS protocol version mismatch.\n"); + break; #endif case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE: av_log(h, AV_LOG_ERROR, "A fatal alert message was received from the peer, has the peer a correct certificate?\n"); @@ -144,9 +160,15 @@ static void handle_handshake_error(URLContext *h, int ret) case MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED: av_log(h, AV_LOG_ERROR, "No CA chain is set, but required to operate. Was the CA correctly set?\n"); break; + case MBEDTLS_ERR_SSL_INTERNAL_ERROR: + av_log(h, AV_LOG_ERROR, "Internal error encountered.\n"); + break; case MBEDTLS_ERR_NET_CONN_RESET: av_log(h, AV_LOG_ERROR, "TLS handshake was aborted by peer.\n"); break; + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + av_log(h, AV_LOG_ERROR, "Certificate verification failed.\n"); + break; default: av_log(h, AV_LOG_ERROR, "mbedtls_ssl_handshake returned -0x%x\n", -ret); break; @@ -177,6 +199,13 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op if ((ret = ff_tls_open_underlying(shr, h, uri, options)) < 0) goto fail; +#ifdef MBEDTLS_PSA_CRYPTO_C + if ((ret = psa_crypto_init()) != PSA_SUCCESS) { + av_log(h, AV_LOG_ERROR, "psa_crypto_init returned %d\n", ret); + goto fail; + } +#endif + mbedtls_ssl_init(&tls_ctx->ssl_context); mbedtls_ssl_config_init(&tls_ctx->ssl_config); mbedtls_entropy_init(&tls_ctx->entropy_context); @@ -184,6 +213,14 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op mbedtls_x509_crt_init(&tls_ctx->ca_cert); mbedtls_pk_init(&tls_ctx->priv_key); + if (av_log_get_level() >= AV_LOG_DEBUG) { + mbedtls_ssl_conf_dbg(&tls_ctx->ssl_config, mbedtls_debug, shr->tcp); + /* + * Note: we can't call mbedtls_debug_set_threshold() here because + * it's global state. The user is thus expected to manage this. + */ + } + // load trusted CA if (shr->ca_file) { if ((ret = mbedtls_x509_crt_parse_file(&tls_ctx->ca_cert, shr->ca_file)) != 0) { @@ -232,8 +269,17 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op goto fail; } +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 + // this version does not allow disabling certificate verification with TLSv1.3 (yes, really). + if (mbedtls_version_get_number() == 0x03060000 && !shr->verify) { + av_log(h, AV_LOG_INFO, "Forcing TLSv1.2 because certificate verification is disabled\n"); + mbedtls_ssl_conf_max_tls_version(&tls_ctx->ssl_config, MBEDTLS_SSL_VERSION_TLS1_2); + } +#endif + + // not VERIFY_REQUIRED because we manually check after handshake mbedtls_ssl_conf_authmode(&tls_ctx->ssl_config, - shr->verify ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE); + shr->verify ? MBEDTLS_SSL_VERIFY_OPTIONAL : MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_rng(&tls_ctx->ssl_config, mbedtls_ctr_drbg_random, &tls_ctx->ctr_drbg_context); mbedtls_ssl_conf_ca_chain(&tls_ctx->ssl_config, &tls_ctx->ca_cert, NULL); @@ -290,6 +336,9 @@ static int handle_tls_error(URLContext *h, const char* func_name, int ret) switch (ret) { case MBEDTLS_ERR_SSL_WANT_READ: case MBEDTLS_ERR_SSL_WANT_WRITE: +#ifdef MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET + case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET: +#endif return AVERROR(EAGAIN); case MBEDTLS_ERR_NET_SEND_FAILED: case MBEDTLS_ERR_NET_RECV_FAILED: @@ -309,6 +358,8 @@ static int tls_read(URLContext *h, uint8_t *buf, int size) TLSContext *tls_ctx = h->priv_data; int ret; + tls_ctx->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + tls_ctx->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; if ((ret = mbedtls_ssl_read(&tls_ctx->ssl_context, buf, size)) > 0) { // return read length return ret; @@ -322,6 +373,8 @@ static int tls_write(URLContext *h, const uint8_t *buf, int size) TLSContext *tls_ctx = h->priv_data; int ret; + tls_ctx->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + tls_ctx->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; if ((ret = mbedtls_ssl_write(&tls_ctx->ssl_context, buf, size)) > 0) { // return written length return ret; diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index 8bf766c01..8b0cf9efb 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -19,24 +19,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "avformat.h" -#include "internal.h" #include "network.h" #include "os_support.h" #include "url.h" #include "tls.h" -#include "libavutil/avstring.h" -#include "libavutil/avutil.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" -#include "libavutil/thread.h" #include #include #include -static int openssl_init; - typedef struct TLSContext { const AVClass *class; TLSShared tls_shared; @@ -48,8 +40,22 @@ typedef struct TLSContext { int io_err; } TLSContext; -#if HAVE_THREADS && OPENSSL_VERSION_NUMBER < 0x10100000L +/* OpenSSL 1.0.2 or below, then you would use SSL_library_init. If you are + * using OpenSSL 1.1.0 or above, then the library will initialize + * itself automatically. + * https://wiki.openssl.org/index.php/Library_Initialization + */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#include "libavutil/thread.h" + +static AVMutex openssl_mutex = AV_MUTEX_INITIALIZER; + +static int openssl_init; + +#if HAVE_THREADS #include +#include "libavutil/mem.h" + pthread_mutex_t *openssl_mutexes; static void openssl_lock(int mode, int type, const char *file, int line) { @@ -68,23 +74,16 @@ static unsigned long openssl_thread_id(void) int ff_openssl_init(void) { - ff_lock_avformat(); + ff_mutex_lock(&openssl_mutex); if (!openssl_init) { - /* OpenSSL 1.0.2 or below, then you would use SSL_library_init. If you are - * using OpenSSL 1.1.0 or above, then the library will initialize - * itself automatically. - * https://wiki.openssl.org/index.php/Library_Initialization - */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_library_init(); SSL_load_error_strings(); -#endif -#if HAVE_THREADS && OPENSSL_VERSION_NUMBER < 0x10100000L +#if HAVE_THREADS if (!CRYPTO_get_locking_callback()) { int i; openssl_mutexes = av_malloc_array(sizeof(pthread_mutex_t), CRYPTO_num_locks()); if (!openssl_mutexes) { - ff_unlock_avformat(); + ff_mutex_unlock(&openssl_mutex); return AVERROR(ENOMEM); } @@ -98,17 +97,17 @@ int ff_openssl_init(void) #endif } openssl_init++; - ff_unlock_avformat(); + ff_mutex_unlock(&openssl_mutex); return 0; } void ff_openssl_deinit(void) { - ff_lock_avformat(); + ff_mutex_lock(&openssl_mutex); openssl_init--; if (!openssl_init) { -#if HAVE_THREADS && OPENSSL_VERSION_NUMBER < 0x10100000L +#if HAVE_THREADS if (CRYPTO_get_locking_callback() == openssl_lock) { int i; CRYPTO_set_locking_callback(NULL); @@ -118,8 +117,9 @@ void ff_openssl_deinit(void) } #endif } - ff_unlock_avformat(); + ff_mutex_unlock(&openssl_mutex); } +#endif static int print_tls_error(URLContext *h, int ret) { @@ -159,7 +159,9 @@ static int tls_close(URLContext *h) if (c->url_bio_method) BIO_meth_free(c->url_bio_method); #endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L ff_openssl_deinit(); +#endif return 0; } @@ -255,8 +257,10 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op BIO *bio; int ret; +#if OPENSSL_VERSION_NUMBER < 0x10100000L if ((ret = ff_openssl_init()) < 0) return ret; +#endif if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) goto fail; diff --git a/libavformat/tls_schannel.c b/libavformat/tls_schannel.c index bbeb8a81f..ae9a311d2 100644 --- a/libavformat/tls_schannel.c +++ b/libavformat/tls_schannel.c @@ -20,6 +20,7 @@ /** Based on the CURL SChannel module */ +#include "libavutil/mem.h" #include "avformat.h" #include "internal.h" #include "network.h" @@ -112,6 +113,7 @@ static int tls_shutdown_client(URLContext *h) c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags, &c->ctxt_timestamp); if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_CONTEXT_EXPIRED) { + s->tcp->flags &= ~AVIO_FLAG_NONBLOCK; ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer); FreeContextBuffer(outbuf.pvBuffer); if (ret < 0 || ret != outbuf.cbBuffer) @@ -315,6 +317,7 @@ static int tls_client_handshake(URLContext *h) goto fail; } + s->tcp->flags &= ~AVIO_FLAG_NONBLOCK; ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer); FreeContextBuffer(outbuf.pvBuffer); if (ret < 0 || ret != outbuf.cbBuffer) { @@ -415,11 +418,16 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) } } + s->tcp->flags &= ~AVIO_FLAG_NONBLOCK; + s->tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = ffurl_read(s->tcp, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset); if (ret == AVERROR_EOF) { c->connection_closed = 1; ret = 0; + } else if (ret == AVERROR(EAGAIN)) { + ret = 0; } else if (ret < 0) { av_log(h, AV_LOG_ERROR, "Unable to read from socket\n"); return ret; @@ -563,8 +571,14 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0); if (sspi_ret == SEC_E_OK) { len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; + + s->tcp->flags &= ~AVIO_FLAG_NONBLOCK; + s->tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = ffurl_write(s->tcp, data, len); - if (ret < 0 || ret != len) { + if (ret == AVERROR(EAGAIN)) { + goto done; + } else if (ret < 0 || ret != len) { ret = AVERROR(EIO); av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n"); goto done; diff --git a/libavformat/tls_securetransport.c b/libavformat/tls_securetransport.c index f6a1a5e7b..a5a3bd87a 100644 --- a/libavformat/tls_securetransport.c +++ b/libavformat/tls_securetransport.c @@ -30,6 +30,7 @@ #include "tls.h" #include "libavcodec/internal.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" diff --git a/libavformat/ty.c b/libavformat/ty.c index 4a1c820c0..f524b74ba 100644 --- a/libavformat/ty.c +++ b/libavformat/ty.c @@ -24,6 +24,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/udp.c b/libavformat/udp.c index d9514f502..c1ebdd122 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -29,13 +29,13 @@ #include "avformat.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/parseutils.h" #include "libavutil/fifo.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "libavutil/log.h" #include "libavutil/time.h" -#include "internal.h" #include "network.h" #include "os_support.h" #include "url.h" diff --git a/libavformat/usmdec.c b/libavformat/usmdec.c index 5a57c59ea..6de2a73ed 100644 --- a/libavformat/usmdec.c +++ b/libavformat/usmdec.c @@ -20,6 +20,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/bytestream.h" #include "avformat.h" diff --git a/libavformat/utils.c b/libavformat/utils.c index c72274374..e892e8bde 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -26,7 +26,7 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/internal.h" -#include "libavutil/thread.h" +#include "libavutil/mem.h" #include "libavutil/time.h" #include "libavcodec/internal.h" @@ -39,23 +39,11 @@ #endif #include "os_support.h" -static AVMutex avformat_mutex = AV_MUTEX_INITIALIZER; - /** * @file * various utility functions for use within FFmpeg */ -int ff_lock_avformat(void) -{ - return ff_mutex_lock(&avformat_mutex) ? -1 : 0; -} - -int ff_unlock_avformat(void) -{ - return ff_mutex_unlock(&avformat_mutex) ? -1 : 0; -} - /* an arbitrarily chosen "sane" max packet size -- 50M */ #define SANE_CHUNK_SIZE (50000000) @@ -292,7 +280,7 @@ uint64_t ff_parse_ntp_time(uint64_t ntp_ts) return (sec * 1000000) + usec; } -int av_get_frame_filename2(char *buf, int buf_size, const char *path, int number, int flags) +int ff_get_frame_filename(char *buf, int buf_size, const char *path, int64_t number, int flags) { const char *p; char *q, buf1[20], c; @@ -325,7 +313,7 @@ int av_get_frame_filename2(char *buf, int buf_size, const char *path, int number percentd_found = 1; if (number < 0) nd += 1; - snprintf(buf1, sizeof(buf1), "%0*d", nd, number); + snprintf(buf1, sizeof(buf1), "%0*" PRId64, nd, number); len = strlen(buf1); if ((q - buf + len) > buf_size - 1) goto fail; @@ -350,9 +338,14 @@ fail: return -1; } +int av_get_frame_filename2(char *buf, int buf_size, const char *path, int number, int flags) +{ + return ff_get_frame_filename(buf, buf_size, path, number, flags); +} + int av_get_frame_filename(char *buf, int buf_size, const char *path, int number) { - return av_get_frame_filename2(buf, buf_size, path, number, 0); + return ff_get_frame_filename(buf, buf_size, path, number, 0); } void av_url_split(char *proto, int proto_size, diff --git a/libavformat/vapoursynth.c b/libavformat/vapoursynth.c index b5d80abf3..0fa5affa6 100644 --- a/libavformat/vapoursynth.c +++ b/libavformat/vapoursynth.c @@ -25,33 +25,50 @@ #include -#include -#include +#include #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/eval.h" #include "libavutil/frame.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avformat.h" #include "demux.h" #include "internal.h" +/* Platform-specific directives. */ +#ifdef _WIN32 + #include + #include "compat/w32dlfcn.h" + #include "libavutil/wchar_filename.h" + #undef EXTERN_C + #define VSSCRIPT_LIB "VSScript.dll" +#else + #include + #define VSSCRIPT_NAME "libvapoursynth-script" + #define VSSCRIPT_LIB VSSCRIPT_NAME SLIBSUF +#endif + struct VSState { + const VSSCRIPTAPI *vssapi; VSScript *vss; }; +typedef const VSSCRIPTAPI *(*VSScriptGetAPIFunc)(int version); + typedef struct VSContext { const AVClass *class; AVBufferRef *vss_state; + const VSSCRIPTAPI *vssapi; const VSAPI *vsapi; - VSCore *vscore; + void *vslibrary; - VSNodeRef *outnode; + VSNode *outnode; int is_cfr; int current_frame; @@ -69,13 +86,46 @@ static const AVOption options[] = { {NULL} }; +static av_cold void* vs_load_library(VSScriptGetAPIFunc *get_vssapi) +{ + void *vslibrary = NULL; +#ifdef _WIN32 + const HKEY hkeys[] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}; + LONG r; + WCHAR vss_path[512]; + DWORD buf_size = sizeof(vss_path) - 2; + char *vss_path_utf8; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(hkeys); i++) { + if ((r = RegGetValueW(hkeys[i], L"SOFTWARE\\VapourSynth", + L"VSScriptDLL", RRF_RT_REG_SZ, NULL, + &vss_path, &buf_size)) == ERROR_SUCCESS) + break; + } + if (r == ERROR_SUCCESS && wchartoutf8(vss_path, &vss_path_utf8) == 0) { + vslibrary = dlopen(vss_path_utf8, RTLD_NOW | RTLD_GLOBAL); + av_free(vss_path_utf8); + } + else +#endif + vslibrary = dlopen(VSSCRIPT_LIB, RTLD_NOW | RTLD_GLOBAL); + + if (vslibrary != NULL) { + if (!(*get_vssapi = (VSScriptGetAPIFunc)dlsym(vslibrary, "getVSScriptAPI"))) { + dlclose(vslibrary); + return NULL; + } + } + return vslibrary; +} + static void free_vss_state(void *opaque, uint8_t *data) { struct VSState *vss = opaque; if (vss->vss) { - vsscript_freeScript(vss->vss); - vsscript_finalize(); + vss->vssapi->freeScript(vss->vss); } } @@ -89,9 +139,11 @@ static av_cold int read_close_vs(AVFormatContext *s) av_buffer_unref(&vs->vss_state); vs->vsapi = NULL; - vs->vscore = NULL; vs->outnode = NULL; + if (vs->vslibrary) + dlclose(vs->vslibrary); + return 0; } @@ -105,7 +157,7 @@ static av_cold int is_native_endian(enum AVPixelFormat pixfmt) return pd && (!!HAVE_BIGENDIAN == !!(pd->flags & AV_PIX_FMT_FLAG_BE)); } -static av_cold enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[4]) +static av_cold enum AVPixelFormat match_pixfmt(const VSVideoFormat *vsf, int c_order[4]) { static const int yuv_order[4] = {0, 1, 2, 0}; static const int rgb_order[4] = {1, 2, 0, 0}; @@ -127,13 +179,12 @@ static av_cold enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[ pd->log2_chroma_h != vsf->subSamplingH) continue; - is_rgb = vsf->colorFamily == cmRGB; + is_rgb = vsf->colorFamily == cfRGB; if (is_rgb != !!(pd->flags & AV_PIX_FMT_FLAG_RGB)) continue; - is_yuv = vsf->colorFamily == cmYUV || - vsf->colorFamily == cmYCoCg || - vsf->colorFamily == cmGray; + is_yuv = vsf->colorFamily == cfYUV || + vsf->colorFamily == cfGray; if (!is_rgb && !is_yuv) continue; @@ -172,18 +223,41 @@ static av_cold int read_header_vs(AVFormatContext *s) AVStream *st; AVIOContext *pb = s->pb; VSContext *vs = s->priv_data; + VSScriptGetAPIFunc get_vssapi; int64_t sz = avio_size(pb); char *buf = NULL; char dummy; + char vsfmt[32]; const VSVideoInfo *info; struct VSState *vss_state; int err = 0; + if (!(vs->vslibrary = vs_load_library(&get_vssapi))) { + av_log(s, AV_LOG_ERROR, "Could not open " VSSCRIPT_LIB ". " + "Check VapourSynth installation.\n"); + err = AVERROR_EXTERNAL; + goto done; + } + + if (!(vs->vssapi = get_vssapi(VSSCRIPT_API_VERSION))) { + av_log(s, AV_LOG_ERROR, "Failed to initialize VSScript (possibly PYTHONPATH not set).\n"); + err = AVERROR_EXTERNAL; + goto done; + } + + if (!(vs->vsapi = vs->vssapi->getVSAPI(VAPOURSYNTH_API_VERSION))) { + av_log(s, AV_LOG_ERROR, "Could not get VSAPI. " + "Check VapourSynth installation.\n"); + err = AVERROR_EXTERNAL; + goto done; + } + vss_state = av_mallocz(sizeof(*vss_state)); if (!vss_state) { err = AVERROR(ENOMEM); goto done; } + vss_state->vssapi = vs->vssapi; vs->vss_state = av_buffer_create(NULL, 0, free_vss_state, vss_state, 0); if (!vs->vss_state) { @@ -192,16 +266,9 @@ static av_cold int read_header_vs(AVFormatContext *s) goto done; } - if (!vsscript_init()) { - av_log(s, AV_LOG_ERROR, "Failed to initialize VSScript (possibly PYTHONPATH not set).\n"); - err = AVERROR_EXTERNAL; - goto done; - } - - if (vsscript_createScript(&vss_state->vss)) { + if (!(vss_state->vss = vs->vssapi->createScript(NULL))) { av_log(s, AV_LOG_ERROR, "Failed to create script instance.\n"); err = AVERROR_EXTERNAL; - vsscript_finalize(); goto done; } @@ -234,17 +301,14 @@ static av_cold int read_header_vs(AVFormatContext *s) } buf[sz] = '\0'; - if (vsscript_evaluateScript(&vss_state->vss, buf, s->url, 0)) { - const char *msg = vsscript_getError(vss_state->vss); + if (vs->vssapi->evaluateBuffer(vss_state->vss, buf, s->url)) { + const char *msg = vs->vssapi->getError(vss_state->vss); av_log(s, AV_LOG_ERROR, "Failed to parse script: %s\n", msg ? msg : "(unknown)"); err = AVERROR_EXTERNAL; goto done; } - vs->vsapi = vsscript_getVSApi(); - vs->vscore = vsscript_getCore(vss_state->vss); - - vs->outnode = vsscript_getOutput(vss_state->vss, 0); + vs->outnode = vs->vssapi->getOutputNode(vss_state->vss, 0); if (!vs->outnode) { av_log(s, AV_LOG_ERROR, "Could not get script output node.\n"); err = AVERROR_EXTERNAL; @@ -259,7 +323,7 @@ static av_cold int read_header_vs(AVFormatContext *s) info = vs->vsapi->getVideoInfo(vs->outnode); - if (!info->format || !info->width || !info->height) { + if (!info->format.colorFamily || !info->width || !info->height) { av_log(s, AV_LOG_ERROR, "Non-constant input format not supported.\n"); err = AVERROR_PATCHWELCOME; goto done; @@ -279,19 +343,18 @@ static av_cold int read_header_vs(AVFormatContext *s) st->codecpar->codec_id = AV_CODEC_ID_WRAPPED_AVFRAME; st->codecpar->width = info->width; st->codecpar->height = info->height; - st->codecpar->format = match_pixfmt(info->format, vs->c_order); + st->codecpar->format = match_pixfmt(&info->format, vs->c_order); if (st->codecpar->format == AV_PIX_FMT_NONE) { - av_log(s, AV_LOG_ERROR, "Unsupported VS pixel format %s\n", info->format->name); + av_log(s, AV_LOG_ERROR, "Unsupported VS pixel format %s\n", + vs->vsapi->getVideoFormatName(&info->format, vsfmt) ? vsfmt : "(unknown)"); err = AVERROR_EXTERNAL; goto done; } - av_log(s, AV_LOG_VERBOSE, "VS format %s -> pixfmt %s\n", info->format->name, + av_log(s, AV_LOG_VERBOSE, "VS format %s -> pixfmt %s\n", + vs->vsapi->getVideoFormatName(&info->format, vsfmt) ? vsfmt : "(unknown)", av_get_pix_fmt_name(st->codecpar->format)); - if (info->format->colorFamily == cmYCoCg) - st->codecpar->color_space = AVCOL_SPC_YCGCO; - done: av_free(buf); return err; @@ -310,13 +373,13 @@ static int get_vs_prop_int(AVFormatContext *s, const VSMap *map, const char *nam int64_t res; int err = 1; - res = vs->vsapi->propGetInt(map, name, 0, &err); + res = vs->vsapi->mapGetInt(map, name, 0, &err); return err || res < INT_MIN || res > INT_MAX ? def : res; } struct vsframe_ref_data { const VSAPI *vsapi; - const VSFrameRef *frame; + const VSFrame *frame; AVBufferRef *vss_state; }; @@ -338,7 +401,7 @@ static int read_packet_vs(AVFormatContext *s, AVPacket *pkt) AVStream *st = s->streams[0]; AVFrame *frame = NULL; char vserr[80]; - const VSFrameRef *vsframe; + const VSFrame *vsframe; const VSVideoInfo *info = vs->vsapi->getVideoInfo(vs->outnode); const VSMap *props; const AVPixFmtDescriptor *desc; @@ -380,7 +443,7 @@ static int read_packet_vs(AVFormatContext *s, AVPacket *pkt) goto end; } - props = vs->vsapi->getFramePropsRO(vsframe); + props = vs->vsapi->getFramePropertiesRO(vsframe); frame = av_frame_alloc(); if (!frame) { @@ -409,7 +472,7 @@ static int read_packet_vs(AVFormatContext *s, AVPacket *pkt) desc = av_pix_fmt_desc_get(frame->format); - for (i = 0; i < info->format->numPlanes; i++) { + for (i = 0; i < info->format.numPlanes; i++) { int p = vs->c_order[i]; ptrdiff_t plane_h = frame->height; diff --git a/libavformat/version.c b/libavformat/version.c index 5f321d847..c0781d3f4 100644 --- a/libavformat/version.c +++ b/libavformat/version.c @@ -18,9 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "config.h" -#include "libavutil/avassert.h" #include "avformat.h" #include "version.h" @@ -29,7 +30,7 @@ const char av_format_ffversion[] = "FFmpeg version " FFMPEG_VERSION; unsigned avformat_version(void) { - av_assert0(LIBAVFORMAT_VERSION_MICRO >= 100); + static_assert(LIBAVFORMAT_VERSION_MICRO >= 100, "micro version starts at 100"); return LIBAVFORMAT_VERSION_INT; } diff --git a/libavformat/version.h b/libavformat/version.h index a7c80dc56..70c554c19 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #include "version_major.h" -#define LIBAVFORMAT_VERSION_MINOR 1 +#define LIBAVFORMAT_VERSION_MINOR 7 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ diff --git a/libavformat/version_major.h b/libavformat/version_major.h index 44ad23c6b..7a9b06703 100644 --- a/libavformat/version_major.h +++ b/libavformat/version_major.h @@ -47,6 +47,7 @@ #define FF_API_AVSTREAM_SIDE_DATA (LIBAVFORMAT_VERSION_MAJOR < 62) #define FF_API_GET_DUR_ESTIMATE_METHOD (LIBAVFORMAT_VERSION_MAJOR < 62) +#define FF_API_INTERNAL_TIMING (LIBAVFORMAT_VERSION_MAJOR < 62) #define FF_API_R_FRAME_RATE 1 diff --git a/libavformat/vividas.c b/libavformat/vividas.c index ee4048415..bec4ad7ce 100644 --- a/libavformat/vividas.c +++ b/libavformat/vividas.c @@ -30,6 +30,7 @@ #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avio_internal.h" #include "avformat.h" #include "demux.h" @@ -566,7 +567,8 @@ static int viv_read_header(AVFormatContext *s) v = avio_r8(pb); avio_seek(pb, v, SEEK_CUR); - avio_read(pb, keybuffer, 187); + if (avio_read(pb, keybuffer, 187) != 187) + return AVERROR_INVALIDDATA; key = decode_key(keybuffer); viv->sb_key = key; diff --git a/libavformat/vqf.c b/libavformat/vqf.c index 409c014a9..58b1546f5 100644 --- a/libavformat/vqf.c +++ b/libavformat/vqf.c @@ -25,7 +25,8 @@ #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "libavutil/mathematics.h" -#include "riff.h" +#include "libavutil/mem.h" +#include "metadata.h" typedef struct VqfContext { int frame_bit_len; @@ -50,22 +51,28 @@ static int vqf_probe(const AVProbeData *probe_packet) return AVPROBE_SCORE_EXTENSION; } -static void add_metadata(AVFormatContext *s, uint32_t tag, +static int add_metadata(AVFormatContext *s, uint32_t tag, unsigned int tag_len, unsigned int remaining) { int len = FFMIN(tag_len, remaining); char *buf, key[5] = {0}; + int ret; if (len == UINT_MAX) - return; + return AVERROR_INVALIDDATA; buf = av_malloc(len+1); if (!buf) - return; - avio_read(s->pb, buf, len); + return AVERROR(ENOMEM); + + ret = avio_read(s->pb, buf, len); + if (ret < 0) + return ret; + if (len != ret) + return AVERROR_INVALIDDATA; buf[len] = 0; AV_WL32(key, tag); - av_dict_set(&s->metadata, key, buf, AV_DICT_DONT_STRDUP_VAL); + return av_dict_set(&s->metadata, key, buf, AV_DICT_DONT_STRDUP_VAL); } static const AVMetadataConv vqf_metadata_conv[] = { @@ -163,7 +170,9 @@ static int vqf_read_header(AVFormatContext *s) avio_skip(s->pb, FFMIN(len, header_size)); break; default: - add_metadata(s, chunk_tag, len, header_size); + ret = add_metadata(s, chunk_tag, len, header_size); + if (ret < 0) + return ret; break; } diff --git a/libavformat/vvc.c b/libavformat/vvc.c index d5b3237ae..b293ff46d 100644 --- a/libavformat/vvc.c +++ b/libavformat/vvc.c @@ -26,11 +26,23 @@ #include "libavcodec/vvc.h" #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avc.h" #include "avio.h" #include "avio_internal.h" +#include "nal.h" #include "vvc.h" +enum { + OPI_INDEX, + VPS_INDEX, + SPS_INDEX, + PPS_INDEX, + SEI_PREFIX_INDEX, + SEI_SUFFIX_INDEX, + NB_ARRAYS +}; + typedef struct VVCCNALUnitArray { uint8_t array_completeness; uint8_t NAL_unit_type; @@ -66,35 +78,18 @@ typedef struct VVCDecoderConfigurationRecord { uint16_t max_picture_height; uint16_t avg_frame_rate; uint8_t num_of_arrays; - VVCCNALUnitArray *array; + VVCCNALUnitArray arrays[NB_ARRAYS]; } VVCDecoderConfigurationRecord; -typedef struct VVCCProfileTierLevel { - uint8_t profile_idc; - uint8_t tier_flag; - uint8_t general_level_idc; - uint8_t ptl_frame_only_constraint_flag; - uint8_t ptl_multilayer_enabled_flag; -// general_constraint_info - uint8_t gci_present_flag; - uint8_t gci_general_constraints[9]; - uint8_t gci_num_reserved_bits; -// end general_constraint_info - uint8_t ptl_sublayer_level_present_flag[VVC_MAX_SUBLAYERS - 1]; - uint8_t sublayer_level_idc[VVC_MAX_SUBLAYERS - 1]; - uint8_t ptl_num_sub_profiles; - uint32_t general_sub_profile_idc[VVC_MAX_SUB_PROFILES]; -} VVCCProfileTierLevel; - static void vvcc_update_ptl(VVCDecoderConfigurationRecord *vvcc, - VVCCProfileTierLevel *ptl) + VVCPTLRecord *ptl) { /* * The level indication general_level_idc must indicate a level of * capability equal to or greater than the highest level indicated for the * highest tier in all the parameter sets. */ - if (vvcc->ptl.general_tier_flag < ptl->tier_flag) + if (vvcc->ptl.general_tier_flag < ptl->general_tier_flag) vvcc->ptl.general_level_idc = ptl->general_level_idc; else vvcc->ptl.general_level_idc = @@ -105,7 +100,7 @@ static void vvcc_update_ptl(VVCDecoderConfigurationRecord *vvcc, * greater than the highest tier indicated in all the parameter sets. */ vvcc->ptl.general_tier_flag = - FFMAX(vvcc->ptl.general_tier_flag, ptl->tier_flag); + FFMAX(vvcc->ptl.general_tier_flag, ptl->general_tier_flag); /* * The profile indication general_profile_idc must indicate a profile to @@ -122,7 +117,7 @@ static void vvcc_update_ptl(VVCDecoderConfigurationRecord *vvcc, * Note: set the profile to the highest value for the sake of simplicity. */ vvcc->ptl.general_profile_idc = - FFMAX(vvcc->ptl.general_profile_idc, ptl->profile_idc); + FFMAX(vvcc->ptl.general_profile_idc, ptl->general_profile_idc); /* * Each bit in flags may only be set if all @@ -135,14 +130,13 @@ static void vvcc_update_ptl(VVCDecoderConfigurationRecord *vvcc, /* * Constraints Info */ - if (ptl->gci_present_flag) { - vvcc->ptl.num_bytes_constraint_info = 9; + if (ptl->num_bytes_constraint_info) { + vvcc->ptl.num_bytes_constraint_info = ptl->num_bytes_constraint_info; memcpy(&vvcc->ptl.general_constraint_info[0], - &ptl->gci_general_constraints[0], sizeof(uint8_t) * 9); - + &ptl->general_constraint_info[0], ptl->num_bytes_constraint_info); } else { vvcc->ptl.num_bytes_constraint_info = 1; - memset(&vvcc->ptl.general_constraint_info[0], 0, sizeof(uint8_t) * 9); + memset(&vvcc->ptl.general_constraint_info[0], 0, sizeof(vvcc->ptl.general_constraint_info)); } /* @@ -186,36 +180,35 @@ static void vvcc_parse_ptl(GetBitContext *gb, unsigned int profileTierPresentFlag, unsigned int max_sub_layers_minus1) { - VVCCProfileTierLevel general_ptl = { 0 }; - int j; + VVCPTLRecord general_ptl = { 0 }; if (profileTierPresentFlag) { - general_ptl.profile_idc = get_bits(gb, 7); - general_ptl.tier_flag = get_bits1(gb); + general_ptl.general_profile_idc = get_bits(gb, 7); + general_ptl.general_tier_flag = get_bits1(gb); } general_ptl.general_level_idc = get_bits(gb, 8); general_ptl.ptl_frame_only_constraint_flag = get_bits1(gb); general_ptl.ptl_multilayer_enabled_flag = get_bits1(gb); if (profileTierPresentFlag) { // parse constraint info - general_ptl.gci_present_flag = get_bits1(gb); - if (general_ptl.gci_present_flag) { + general_ptl.num_bytes_constraint_info = get_bits1(gb); // gci_present_flag + if (general_ptl.num_bytes_constraint_info) { + int gci_num_reserved_bits, j; for (j = 0; j < 8; j++) - general_ptl.gci_general_constraints[j] = get_bits(gb, 8); - general_ptl.gci_general_constraints[8] = get_bits(gb, 7); + general_ptl.general_constraint_info[j] = get_bits(gb, 8); + general_ptl.general_constraint_info[j++] = get_bits(gb, 7); - general_ptl.gci_num_reserved_bits = get_bits(gb, 8); - skip_bits(gb, general_ptl.gci_num_reserved_bits); + gci_num_reserved_bits = get_bits(gb, 8); + general_ptl.num_bytes_constraint_info = j; + skip_bits(gb, gci_num_reserved_bits); } - while (gb->index % 8 != 0) - skip_bits1(gb); + align_get_bits(gb); } for (int i = max_sub_layers_minus1 - 1; i >= 0; i--) general_ptl.ptl_sublayer_level_present_flag[i] = get_bits1(gb); - while (gb->index % 8 != 0) - skip_bits1(gb); + align_get_bits(gb); for (int i = max_sub_layers_minus1 - 1; i >= 0; i--) { if (general_ptl.ptl_sublayer_level_present_flag[i]) @@ -240,8 +233,6 @@ static int vvcc_parse_vps(GetBitContext *gb, unsigned int vps_max_sublayers_minus1; unsigned int vps_default_ptl_dpb_hrd_max_tid_flag; unsigned int vps_all_independent_layers_flag; - unsigned int vps_each_layer_is_an_ols_flag; - unsigned int vps_ols_mode_idc; unsigned int vps_pt_present_flag[VVC_MAX_PTLS]; unsigned int vps_ptl_max_tid[VVC_MAX_PTLS]; @@ -290,11 +281,13 @@ static int vvcc_parse_vps(GetBitContext *gb, } if (vps_max_layers_minus1 > 0) { + unsigned int vps_each_layer_is_an_ols_flag; if (vps_all_independent_layers_flag) vps_each_layer_is_an_ols_flag = get_bits1(gb); else vps_each_layer_is_an_ols_flag = 0; if (!vps_each_layer_is_an_ols_flag) { + unsigned int vps_ols_mode_idc; if (!vps_all_independent_layers_flag) vps_ols_mode_idc = get_bits(gb, 2); else @@ -309,8 +302,6 @@ static int vvcc_parse_vps(GetBitContext *gb, } } vps_num_ptls_minus1 = get_bits(gb, 8); - } else { - vps_each_layer_is_an_ols_flag = 0; } for (int i = 0; i <= vps_num_ptls_minus1; i++) { @@ -325,8 +316,7 @@ static int vvcc_parse_vps(GetBitContext *gb, vps_ptl_max_tid[i] = vps_max_sublayers_minus1; } - while (gb->index % 8 != 0) - skip_bits1(gb); + align_get_bits(gb); for (int i = 0; i <= vps_num_ptls_minus1; i++) vvcc_parse_ptl(gb, vvcc, vps_pt_present_flag[i], vps_ptl_max_tid[i]); @@ -453,32 +443,11 @@ static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type) static int vvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, uint8_t nal_type, int ps_array_completeness, - VVCDecoderConfigurationRecord *vvcc) + VVCCNALUnitArray *array) { int ret; - uint8_t index; uint16_t num_nalus; - VVCCNALUnitArray *array; - for (index = 0; index < vvcc->num_of_arrays; index++) - if (vvcc->array[index].NAL_unit_type == nal_type) - break; - - if (index >= vvcc->num_of_arrays) { - uint8_t i; - - ret = - av_reallocp_array(&vvcc->array, index + 1, - sizeof(VVCCNALUnitArray)); - if (ret < 0) - return ret; - - for (i = vvcc->num_of_arrays; i <= index; i++) - memset(&vvcc->array[i], 0, sizeof(VVCCNALUnitArray)); - vvcc->num_of_arrays = index + 1; - } - - array = &vvcc->array[index]; num_nalus = array->num_nalus; ret = av_reallocp_array(&array->nal_unit, num_nalus + 1, sizeof(uint8_t *)); @@ -525,7 +494,8 @@ static int vvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, static int vvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, int ps_array_completeness, - VVCDecoderConfigurationRecord *vvcc) + VVCDecoderConfigurationRecord *vvcc, + unsigned array_idx) { int ret = 0; GetBitContext gbc; @@ -550,33 +520,25 @@ static int vvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, * vvcc. Perhaps the SEI playload type should be checked * and non-declarative SEI messages discarded? */ - switch (nal_type) { - case VVC_OPI_NUT: - case VVC_VPS_NUT: - case VVC_SPS_NUT: - case VVC_PPS_NUT: - case VVC_PREFIX_SEI_NUT: - case VVC_SUFFIX_SEI_NUT: - ret = vvcc_array_add_nal_unit(nal_buf, nal_size, nal_type, - ps_array_completeness, vvcc); - if (ret < 0) - goto end; - else if (nal_type == VVC_VPS_NUT) - ret = vvcc_parse_vps(&gbc, vvcc); - else if (nal_type == VVC_SPS_NUT) - ret = vvcc_parse_sps(&gbc, vvcc); - else if (nal_type == VVC_PPS_NUT) - ret = vvcc_parse_pps(&gbc, vvcc); - else if (nal_type == VVC_OPI_NUT) { - // not yet supported - } - if (ret < 0) - goto end; - break; - default: - ret = AVERROR_INVALIDDATA; + ret = vvcc_array_add_nal_unit(nal_buf, nal_size, nal_type, + ps_array_completeness, + &vvcc->arrays[array_idx]); + if (ret < 0) goto end; + if (vvcc->arrays[array_idx].num_nalus == 1) + vvcc->num_of_arrays++; + + if (nal_type == VVC_VPS_NUT) + ret = vvcc_parse_vps(&gbc, vvcc); + else if (nal_type == VVC_SPS_NUT) + ret = vvcc_parse_sps(&gbc, vvcc); + else if (nal_type == VVC_PPS_NUT) + ret = vvcc_parse_pps(&gbc, vvcc); + else if (nal_type == VVC_OPI_NUT) { + // not yet supported } + if (ret < 0) + goto end; end: av_free(rbsp_buf); @@ -593,22 +555,20 @@ static void vvcc_init(VVCDecoderConfigurationRecord *vvcc) static void vvcc_close(VVCDecoderConfigurationRecord *vvcc) { - uint8_t i; + for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) { + VVCCNALUnitArray *const array = &vvcc->arrays[i]; - for (i = 0; i < vvcc->num_of_arrays; i++) { - vvcc->array[i].num_nalus = 0; - av_freep(&vvcc->array[i].nal_unit); - av_freep(&vvcc->array[i].nal_unit_length); + array->num_nalus = 0; + av_freep(&array->nal_unit); + av_freep(&array->nal_unit_length); } vvcc->num_of_arrays = 0; - av_freep(&vvcc->array); } static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc) { - uint8_t i; - uint16_t j, vps_count = 0, sps_count = 0, pps_count = 0; + uint16_t vps_count = 0, sps_count = 0, pps_count = 0; /* * It's unclear how to properly compute these fields, so * let's always set them to values meaning 'unspecified'. @@ -655,18 +615,18 @@ static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc) av_log(NULL, AV_LOG_TRACE, "ptl_multilayer_enabled_flag: %" PRIu8 "\n", vvcc->ptl.ptl_multilayer_enabled_flag); - for (i = 0; i < vvcc->ptl.num_bytes_constraint_info; i++) { + for (int i = 0; i < vvcc->ptl.num_bytes_constraint_info; i++) { av_log(NULL, AV_LOG_TRACE, "general_constraint_info[%d]: %" PRIu8 "\n", i, vvcc->ptl.general_constraint_info[i]); } - for (i = 0; i < vvcc->num_sublayers - 1; i++) { + for (int i = 0; i < vvcc->num_sublayers - 1; i++) { av_log(NULL, AV_LOG_TRACE, - "ptl_sublayer_level_present_flag[%" PRIu8 "]: %" PRIu8 "\n", i, + "ptl_sublayer_level_present_flag[%d]: %" PRIu8 "\n", i, vvcc->ptl.ptl_sublayer_level_present_flag[i]); av_log(NULL, AV_LOG_TRACE, - "sublayer_level_idc[%" PRIu8 "]: %" PRIu8 "\n", i, + "sublayer_level_idc[%d]: %" PRIu8 "\n", i, vvcc->ptl.sublayer_level_idc[i]); } @@ -674,9 +634,9 @@ static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc) "num_sub_profiles: %" PRIu8 "\n", vvcc->ptl.ptl_num_sub_profiles); - for (i = 0; i < vvcc->ptl.ptl_num_sub_profiles; i++) { + for (unsigned i = 0; i < vvcc->ptl.ptl_num_sub_profiles; i++) { av_log(NULL, AV_LOG_TRACE, - "general_sub_profile_idc[%" PRIu8 "]: %" PRIx32 "\n", i, + "general_sub_profile_idc[%u]: %" PRIx32 "\n", i, vvcc->ptl.general_sub_profile_idc[i]); } @@ -693,40 +653,33 @@ static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc) av_log(NULL, AV_LOG_TRACE, "num_of_arrays: %" PRIu8 "\n", vvcc->num_of_arrays); - for (i = 0; i < vvcc->num_of_arrays; i++) { + for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) { + const VVCCNALUnitArray *const array = &vvcc->arrays[i]; + + if (array->num_nalus == 0) + continue; + av_log(NULL, AV_LOG_TRACE, - "array_completeness[%" PRIu8 "]: %" PRIu8 "\n", i, - vvcc->array[i].array_completeness); + "array_completeness[%u]: %" PRIu8 "\n", i, + array->array_completeness); av_log(NULL, AV_LOG_TRACE, - "NAL_unit_type[%" PRIu8 "]: %" PRIu8 "\n", i, - vvcc->array[i].NAL_unit_type); + "NAL_unit_type[%u]: %" PRIu8 "\n", i, + array->NAL_unit_type); av_log(NULL, AV_LOG_TRACE, - "num_nalus[%" PRIu8 "]: %" PRIu16 "\n", i, - vvcc->array[i].num_nalus); - for (j = 0; j < vvcc->array[i].num_nalus; j++) + "num_nalus[%u]: %" PRIu16 "\n", i, + array->num_nalus); + for (unsigned j = 0; j < array->num_nalus; j++) av_log(NULL, AV_LOG_TRACE, - "nal_unit_length[%" PRIu8 "][%" PRIu16 "]: %" - PRIu16 "\n", i, j, vvcc->array[i].nal_unit_length[j]); + "nal_unit_length[%u][%u]: %" + PRIu16 "\n", i, j, array->nal_unit_length[j]); } /* - * We need at least one of each: VPS and SPS. + * We need at least one of each: SPS and PPS. */ - for (i = 0; i < vvcc->num_of_arrays; i++) - switch (vvcc->array[i].NAL_unit_type) { - case VVC_VPS_NUT: - vps_count += vvcc->array[i].num_nalus; - break; - case VVC_SPS_NUT: - sps_count += vvcc->array[i].num_nalus; - break; - case VVC_PPS_NUT: - pps_count += vvcc->array[i].num_nalus; - break; - default: - break; - } - + vps_count = vvcc->arrays[VPS_INDEX].num_nalus; + sps_count = vvcc->arrays[SPS_INDEX].num_nalus; + pps_count = vvcc->arrays[PPS_INDEX].num_nalus; if (vps_count > VVC_MAX_VPS_COUNT) return AVERROR_INVALIDDATA; if (!sps_count || sps_count > VVC_MAX_SPS_COUNT) @@ -778,11 +731,11 @@ static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc) put_bits(&pbc, 1, vvcc->ptl.ptl_frame_only_constraint_flag); put_bits(&pbc, 1, vvcc->ptl.ptl_multilayer_enabled_flag); av_assert0(vvcc->ptl.num_bytes_constraint_info); - if (vvcc->ptl.num_bytes_constraint_info > 1) - ff_copy_bits(&pbc, vvcc->ptl.general_constraint_info, (vvcc->ptl.num_bytes_constraint_info - 1) * 8); + for (int i = 0; i < vvcc->ptl.num_bytes_constraint_info - 1; i++) + put_bits(&pbc, 8, vvcc->ptl.general_constraint_info[i]); put_bits(&pbc, 6, vvcc->ptl.general_constraint_info[vvcc->ptl.num_bytes_constraint_info - 1] & 0x3f); flush_put_bits(&pbc); - avio_write(pb, buf, put_bytes_count(&pbc, 1)); + avio_write(pb, buf, put_bytes_output(&pbc)); if (vvcc->num_sublayers > 1) { uint8_t ptl_sublayer_level_present_flags = 0; @@ -825,25 +778,29 @@ static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc) /* unsigned int(8) num_of_arrays; */ avio_w8(pb, vvcc->num_of_arrays); - for (i = 0; i < vvcc->num_of_arrays; i++) { + for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) { + const VVCCNALUnitArray *const array = &vvcc->arrays[i]; + + if (!array->num_nalus) + continue; /* * bit(1) array_completeness; * unsigned int(2) reserved = 0; * unsigned int(5) NAL_unit_type; */ - avio_w8(pb, vvcc->array[i].array_completeness << 7 | - vvcc->array[i].NAL_unit_type & 0x1f); + avio_w8(pb, array->array_completeness << 7 | + array->NAL_unit_type & 0x1f); /* unsigned int(16) num_nalus; */ - if (vvcc->array[i].NAL_unit_type != VVC_DCI_NUT && - vvcc->array[i].NAL_unit_type != VVC_OPI_NUT) - avio_wb16(pb, vvcc->array[i].num_nalus); - for (j = 0; j < vvcc->array[i].num_nalus; j++) { + if (array->NAL_unit_type != VVC_DCI_NUT && + array->NAL_unit_type != VVC_OPI_NUT) + avio_wb16(pb, array->num_nalus); + for (int j = 0; j < array->num_nalus; j++) { /* unsigned int(16) nal_unit_length; */ - avio_wb16(pb, vvcc->array[i].nal_unit_length[j]); + avio_wb16(pb, array->nal_unit_length[j]); /* bit(8*nal_unit_length) nal_unit; */ - avio_write(pb, vvcc->array[i].nal_unit[j], - vvcc->array[i].nal_unit_length[j]); + avio_write(pb, array->nal_unit[j], + array->nal_unit_length[j]); } } @@ -857,11 +814,11 @@ int ff_vvc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in, uint8_t *buf, *end, *start = NULL; if (!filter_ps) { - ret = ff_avc_parse_nal_units(pb, buf_in, size); + ret = ff_nal_parse_units(pb, buf_in, size); goto end; } - ret = ff_avc_parse_nal_units_buf(buf_in, &start, &size); + ret = ff_nal_parse_units_buf(buf_in, &start, &size); if (ret < 0) goto end; @@ -938,7 +895,7 @@ int ff_isom_write_vvcc(AVIOContext *pb, const uint8_t *data, return AVERROR_INVALIDDATA; } - ret = ff_avc_parse_nal_units_buf(data, &start, &size); + ret = ff_nal_parse_units_buf(data, &start, &size); if (ret < 0) return ret; @@ -953,19 +910,18 @@ int ff_isom_write_vvcc(AVIOContext *pb, const uint8_t *data, buf += 4; - switch (type) { - case VVC_OPI_NUT: - case VVC_VPS_NUT: - case VVC_SPS_NUT: - case VVC_PPS_NUT: - case VVC_PREFIX_SEI_NUT: - case VVC_SUFFIX_SEI_NUT: - ret = vvcc_add_nal_unit(buf, len, ps_array_completeness, &vvcc); - if (ret < 0) - goto end; - break; - default: - break; + for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc.arrays); i++) { + static const uint8_t array_idx_to_type[] = + { VVC_OPI_NUT, VVC_VPS_NUT, VVC_SPS_NUT, + VVC_PPS_NUT, VVC_PREFIX_SEI_NUT, VVC_SUFFIX_SEI_NUT }; + + if (type == array_idx_to_type[i]) { + ret = vvcc_add_nal_unit(buf, len, ps_array_completeness, + &vvcc, i); + if (ret < 0) + goto end; + break; + } } buf += len; diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c index 0fed1ee63..ae6ff0e02 100644 --- a/libavformat/wavdec.c +++ b/libavformat/wavdec.c @@ -33,6 +33,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/internal.h" #include "avformat.h" @@ -873,8 +874,7 @@ static int w64_read_header(AVFormatContext *s) uint8_t guid[16]; int ret; - avio_read(pb, guid, 16); - if (memcmp(guid, ff_w64_guid_riff, 16)) + if (avio_read(pb, guid, 16) != 16 || memcmp(guid, ff_w64_guid_riff, 16)) return AVERROR_INVALIDDATA; /* riff + wave + fmt + sizes */ @@ -912,10 +912,10 @@ static int w64_read_header(AVFormatContext *s) if (st->codecpar->block_align && st->codecpar->ch_layout.nb_channels < FF_SANE_NB_CHANNELS && st->codecpar->bits_per_coded_sample < 128) { - int block_align = st->codecpar->block_align; + int64_t block_align = st->codecpar->block_align; block_align = FFMAX(block_align, - ((st->codecpar->bits_per_coded_sample + 7) / 8) * + ((st->codecpar->bits_per_coded_sample + 7LL) / 8) * st->codecpar->ch_layout.nb_channels); if (block_align > st->codecpar->block_align) { av_log(s, AV_LOG_WARNING, "invalid block_align: %d, broken file.\n", diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c index 7e853ce2f..679eb2ce5 100644 --- a/libavformat/wavenc.c +++ b/libavformat/wavenc.c @@ -39,6 +39,7 @@ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time.h" #include "libavutil/time_internal.h" diff --git a/libavformat/wc3movie.c b/libavformat/wc3movie.c index c6b182dcb..f4063353b 100644 --- a/libavformat/wc3movie.c +++ b/libavformat/wc3movie.c @@ -31,6 +31,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavformat/webm_chunk.c b/libavformat/webm_chunk.c index 494a83f50..255b8697c 100644 --- a/libavformat/webm_chunk.c +++ b/libavformat/webm_chunk.c @@ -31,6 +31,7 @@ #include "mux.h" #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/mathematics.h" diff --git a/libavformat/webmdashenc.c b/libavformat/webmdashenc.c index 31ea3c6e8..3d9badc0d 100644 --- a/libavformat/webmdashenc.c +++ b/libavformat/webmdashenc.c @@ -37,6 +37,7 @@ #include "libavutil/avstring.h" #include "libavutil/dict.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/time_internal.h" diff --git a/libavformat/westwood_vqa.c b/libavformat/westwood_vqa.c index 3a31e3f5e..9755fcc9c 100644 --- a/libavformat/westwood_vqa.c +++ b/libavformat/westwood_vqa.c @@ -201,8 +201,10 @@ static int wsvqa_read_packet(AVFormatContext *s, /* We need a big seekback buffer because there can be SNxx, VIEW and ZBUF * chunks (<512 KiB total) in the stream before we read VQFR (<256 KiB) and * seek back here. */ - ffio_ensure_seekback(pb, wsvqa->vqfl_chunk_size + (512 + 256) * 1024); + ret = ffio_ensure_seekback(pb, wsvqa->vqfl_chunk_size + (512 + 256) * 1024); avio_skip(pb, chunk_size + skip_byte); + if (ret < 0) + return ret; continue; } else if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) || (chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) { diff --git a/libavformat/wsddec.c b/libavformat/wsddec.c index f9408be5e..b0bf49cb0 100644 --- a/libavformat/wsddec.c +++ b/libavformat/wsddec.c @@ -21,10 +21,10 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/timecode.h" #include "avformat.h" #include "demux.h" -#include "internal.h" #include "rawdec.h" static int wsd_probe(const AVProbeData *p) diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c index f41b0f2c6..21c964986 100644 --- a/libavformat/wtvdec.c +++ b/libavformat/wtvdec.c @@ -31,6 +31,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" +#include "libavutil/mem.h" #include "libavutil/time_internal.h" #include "avformat.h" #include "demux.h" @@ -184,7 +185,7 @@ static AVIOContext * wtvfile_open_sector(unsigned first_sector, uint64_t length, int nb_sectors1 = read_ints(s->pb, sectors1, WTV_SECTOR_SIZE / 4); int i; - wf->sectors = av_malloc_array(nb_sectors1, 1 << WTV_SECTOR_BITS); + wf->sectors = av_calloc(nb_sectors1, 1 << WTV_SECTOR_BITS); if (!wf->sectors) { av_free(wf); return NULL; @@ -832,7 +833,7 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p int stream_index = ff_find_stream_index(s, sid); if (stream_index >= 0) { AVStream *st = s->streams[stream_index]; - uint8_t buf[258]; + uint8_t buf[258] = {0}; const uint8_t *pbuf = buf; int buf_size; @@ -845,7 +846,8 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p } buf_size = FFMIN(len - consumed, sizeof(buf)); - avio_read(pb, buf, buf_size); + if (avio_read(pb, buf, buf_size) != buf_size) + return AVERROR_INVALIDDATA; consumed += buf_size; ff_parse_mpeg2_descriptor(s, st, 0, &pbuf, buf + buf_size, NULL, 0, 0, NULL); } diff --git a/libavformat/wtvenc.c b/libavformat/wtvenc.c index c0e562164..02fe84573 100644 --- a/libavformat/wtvenc.c +++ b/libavformat/wtvenc.c @@ -26,6 +26,7 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "avformat.h" #include "avio_internal.h" #include "internal.h" diff --git a/libavformat/wvdec.c b/libavformat/wvdec.c index b25c1eee8..e2a79957f 100644 --- a/libavformat/wvdec.c +++ b/libavformat/wvdec.c @@ -268,7 +268,7 @@ static int wv_read_header(AVFormatContext *s) if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { int64_t cur = avio_tell(s->pb); wc->apetag_start = ff_ape_parse_tag(s); - if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) + if (av_dict_count(s->metadata) == 0) ff_id3v1_read(s); avio_seek(s->pb, cur, SEEK_SET); } diff --git a/libavformat/xmv.c b/libavformat/xmv.c index cd58d96c5..ed59f7b85 100644 --- a/libavformat/xmv.c +++ b/libavformat/xmv.c @@ -28,6 +28,7 @@ #include #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" diff --git a/libavformat/xwma.c b/libavformat/xwma.c index 525baee6f..b77c6ed60 100644 --- a/libavformat/xwma.c +++ b/libavformat/xwma.c @@ -22,6 +22,7 @@ #include #include +#include "libavutil/mem.h" #include "avformat.h" #include "demux.h" #include "internal.h" diff --git a/libavutil/aarch64/cpu.c b/libavutil/aarch64/cpu.c index 5ddc7ca88..7631d13de 100644 --- a/libavutil/aarch64/cpu.c +++ b/libavutil/aarch64/cpu.c @@ -20,7 +20,7 @@ #include "libavutil/cpu_internal.h" #include "config.h" -#if (defined(__linux__) || defined(__ANDROID__)) && HAVE_GETAUXVAL +#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO #include #include @@ -31,8 +31,8 @@ static int detect_flags(void) { int flags = 0; - unsigned long hwcap = getauxval(AT_HWCAP); - unsigned long hwcap2 = getauxval(AT_HWCAP2); + unsigned long hwcap = ff_getauxval(AT_HWCAP); + unsigned long hwcap2 = ff_getauxval(AT_HWCAP2); if (hwcap & HWCAP_AARCH64_ASIMDDP) flags |= AV_CPU_FLAG_DOTPROD; @@ -45,22 +45,23 @@ static int detect_flags(void) #elif defined(__APPLE__) && HAVE_SYSCTLBYNAME #include +static int have_feature(const char *feature) { + uint32_t value = 0; + size_t size = sizeof(value); + if (!sysctlbyname(feature, &value, &size, NULL, 0)) + return value; + return 0; +} + static int detect_flags(void) { - uint32_t value = 0; - size_t size; int flags = 0; - size = sizeof(value); - if (!sysctlbyname("hw.optional.arm.FEAT_DotProd", &value, &size, NULL, 0)) { - if (value) - flags |= AV_CPU_FLAG_DOTPROD; - } - size = sizeof(value); - if (!sysctlbyname("hw.optional.arm.FEAT_I8MM", &value, &size, NULL, 0)) { - if (value) - flags |= AV_CPU_FLAG_I8MM; - } + if (have_feature("hw.optional.arm.FEAT_DotProd")) + flags |= AV_CPU_FLAG_DOTPROD; + if (have_feature("hw.optional.arm.FEAT_I8MM")) + flags |= AV_CPU_FLAG_I8MM; + return flags; } diff --git a/libavutil/aarch64/intreadwrite.h b/libavutil/aarch64/intreadwrite.h new file mode 100644 index 000000000..4ce2d6498 --- /dev/null +++ b/libavutil/aarch64/intreadwrite.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 AVUTIL_AARCH64_INTREADWRITE_H +#define AVUTIL_AARCH64_INTREADWRITE_H + +#if HAVE_INTRINSICS_NEON + +#include + +#define AV_COPY128 AV_COPY128 +static av_always_inline void AV_COPY128(void *d, const void *s) +{ + uint8x16_t tmp = vld1q_u8((const uint8_t *)s); + vst1q_u8((uint8_t *)d, tmp); +} + +#define AV_ZERO128 AV_ZERO128 +static av_always_inline void AV_ZERO128(void *d) +{ + uint8x16_t zero = vdupq_n_u8(0); + vst1q_u8((uint8_t *)d, zero); +} + +#endif /* HAVE_INTRINSICS_NEON */ + +#endif /* AVUTIL_AARCH64_INTREADWRITE_H */ diff --git a/libavutil/aarch64/timer.h b/libavutil/aarch64/timer.h index 8b28fd354..922b0c559 100644 --- a/libavutil/aarch64/timer.h +++ b/libavutil/aarch64/timer.h @@ -24,13 +24,7 @@ #include #include "config.h" -#if defined(__APPLE__) - -#include - -#define AV_READ_TIME mach_absolute_time - -#elif HAVE_INLINE_ASM +#if HAVE_INLINE_ASM #define AV_READ_TIME read_time @@ -39,7 +33,16 @@ static inline uint64_t read_time(void) uint64_t cycle_counter; __asm__ volatile( "isb \t\n" +#if defined(__ANDROID__) || defined(__APPLE__) + // cntvct_el0 has lower resolution than pmccntr_el0, but is usually + // accessible from user space by default. + "mrs %0, cntvct_el0 " +#else + // pmccntr_el0 has higher resolution, but is usually not accessible + // from user space by default (but access can be enabled with a custom + // kernel module). "mrs %0, pmccntr_el0 " +#endif : "=r"(cycle_counter) :: "memory" ); return cycle_counter; diff --git a/libavutil/ambient_viewing_environment.c b/libavutil/ambient_viewing_environment.c index c47458cfa..e35972777 100644 --- a/libavutil/ambient_viewing_environment.c +++ b/libavutil/ambient_viewing_environment.c @@ -21,6 +21,13 @@ #include "ambient_viewing_environment.h" #include "mem.h" +static void get_defaults(AVAmbientViewingEnvironment *env) +{ + env->ambient_illuminance = + env->ambient_light_x = + env->ambient_light_y = (AVRational) { 0, 1 }; +} + AVAmbientViewingEnvironment *av_ambient_viewing_environment_alloc(size_t *size) { AVAmbientViewingEnvironment *env = @@ -28,6 +35,8 @@ AVAmbientViewingEnvironment *av_ambient_viewing_environment_alloc(size_t *size) if (!env) return NULL; + get_defaults(env); + if (size) *size = sizeof(*env); @@ -44,6 +53,7 @@ AVAmbientViewingEnvironment *av_ambient_viewing_environment_create_side_data(AVF return NULL; memset(side_data->data, 0, side_data->size); + get_defaults((AVAmbientViewingEnvironment *)side_data->data); return (AVAmbientViewingEnvironment *)side_data->data; } diff --git a/libavutil/arm/bswap.h b/libavutil/arm/bswap.h index c3460e035..48fefa4da 100644 --- a/libavutil/arm/bswap.h +++ b/libavutil/arm/bswap.h @@ -45,26 +45,6 @@ static av_always_inline av_const unsigned av_bswap16(unsigned x) return y; } #endif - -#if AV_GCC_VERSION_AT_MOST(4,4) -#define av_bswap32 av_bswap32 -static av_always_inline av_const uint32_t av_bswap32(uint32_t x) -{ - uint32_t y; -#if HAVE_ARMV6_INLINE - __asm__("rev %0, %1" : "=r"(y) : "r"(x)); -#else - uint32_t t; - __asm__ ("eor %1, %2, %2, ror #16 \n\t" - "bic %1, %1, #0xFF0000 \n\t" - "mov %0, %2, ror #8 \n\t" - "eor %0, %0, %1, lsr #8 \n\t" - : "=r"(y), "=&r"(t) : "r"(x)); -#endif /* HAVE_ARMV6_INLINE */ - return y; -} -#endif /* AV_GCC_VERSION_AT_MOST(4,4) */ - #endif /* __ARMCC_VERSION */ #endif /* AVUTIL_ARM_BSWAP_H */ diff --git a/libavutil/arm/cpu.c b/libavutil/arm/cpu.c index c84a655c3..b84882005 100644 --- a/libavutil/arm/cpu.c +++ b/libavutil/arm/cpu.c @@ -55,7 +55,7 @@ static int get_auxval(uint32_t *hwcap) { #if HAVE_GETAUXVAL - unsigned long ret = getauxval(AT_HWCAP); + unsigned long ret = ff_getauxval(AT_HWCAP); if (ret == 0) return -1; *hwcap = ret; diff --git a/libavutil/arm/intreadwrite.h b/libavutil/arm/intreadwrite.h deleted file mode 100644 index 60fc860cb..000000000 --- a/libavutil/arm/intreadwrite.h +++ /dev/null @@ -1,91 +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 AVUTIL_ARM_INTREADWRITE_H -#define AVUTIL_ARM_INTREADWRITE_H - -#include -#include "config.h" -#include "libavutil/attributes.h" - -#if HAVE_FAST_UNALIGNED && HAVE_INLINE_ASM && AV_GCC_VERSION_AT_MOST(4,6) - -#define AV_RN16 AV_RN16 -static av_always_inline unsigned AV_RN16(const void *p) -{ - const uint8_t *q = p; - unsigned v; -#if AV_GCC_VERSION_AT_MOST(4,5) - __asm__ ("ldrh %0, %1" : "=r"(v) : "m"(*(const uint16_t *)q)); -#elif defined __thumb__ - __asm__ ("ldrh %0, %1" : "=r"(v) : "m"(q[0]), "m"(q[1])); -#else - __asm__ ("ldrh %0, %1" : "=r"(v) : "Uq"(q[0]), "m"(q[1])); -#endif - return v; -} - -#define AV_WN16 AV_WN16 -static av_always_inline void AV_WN16(void *p, uint16_t v) -{ - __asm__ ("strh %1, %0" : "=m"(*(uint16_t *)p) : "r"(v)); -} - -#define AV_RN32 AV_RN32 -static av_always_inline uint32_t AV_RN32(const void *p) -{ - const struct __attribute__((packed)) { uint32_t v; } *q = p; - uint32_t v; - __asm__ ("ldr %0, %1" : "=r"(v) : "m"(*q)); - return v; -} - -#define AV_WN32 AV_WN32 -static av_always_inline void AV_WN32(void *p, uint32_t v) -{ - __asm__ ("str %1, %0" : "=m"(*(uint32_t *)p) : "r"(v)); -} - -#if HAVE_ASM_MOD_Q - -#define AV_RN64 AV_RN64 -static av_always_inline uint64_t AV_RN64(const void *p) -{ - const struct __attribute__((packed)) { uint32_t v; } *q = p; - uint64_t v; - __asm__ ("ldr %Q0, %1 \n\t" - "ldr %R0, %2 \n\t" - : "=&r"(v) - : "m"(q[0]), "m"(q[1])); - return v; -} - -#define AV_WN64 AV_WN64 -static av_always_inline void AV_WN64(void *p, uint64_t v) -{ - __asm__ ("str %Q2, %0 \n\t" - "str %R2, %1 \n\t" - : "=m"(*(uint32_t*)p), "=m"(*((uint32_t*)p+1)) - : "r"(v)); -} - -#endif /* HAVE_ASM_MOD_Q */ - -#endif /* HAVE_INLINE_ASM */ - -#endif /* AVUTIL_ARM_INTREADWRITE_H */ diff --git a/libavutil/avr32/intreadwrite.h b/libavutil/avr32/intreadwrite.h deleted file mode 100644 index 95179f1d1..000000000 --- a/libavutil/avr32/intreadwrite.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2009 Mans Rullgard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVUTIL_AVR32_INTREADWRITE_H -#define AVUTIL_AVR32_INTREADWRITE_H - -#include -#include "config.h" -#include "libavutil/bswap.h" - -/* - * AVR32 does not support unaligned memory accesses, except for the AP - * series which supports unaligned 32-bit loads and stores. 16-bit - * and 64-bit accesses must be aligned to 16 and 32 bits, respectively. - * This means we cannot use the byte-swapping load/store instructions - * here. - * - * For 16-bit, 24-bit, and (on UC series) 32-bit loads, we instead use - * the LDINS.B instruction, which gcc fails to utilise with the - * generic code. GCC also fails to use plain LD.W and ST.W even for - * AP processors, so we override the generic code. The 64-bit - * versions are improved by using our optimised 32-bit functions. - */ - -#define AV_RL16 AV_RL16 -static av_always_inline uint16_t AV_RL16(const void *p) -{ - uint16_t v; - __asm__ ("ld.ub %0, %1 \n\t" - "ldins.b %0:l, %2 \n\t" - : "=&r"(v) - : "m"(*(const uint8_t*)p), "RKs12"(*((const uint8_t*)p+1))); - return v; -} - -#define AV_RB16 AV_RB16 -static av_always_inline uint16_t AV_RB16(const void *p) -{ - uint16_t v; - __asm__ ("ld.ub %0, %2 \n\t" - "ldins.b %0:l, %1 \n\t" - : "=&r"(v) - : "RKs12"(*(const uint8_t*)p), "m"(*((const uint8_t*)p+1))); - return v; -} - -#define AV_RB24 AV_RB24 -static av_always_inline uint32_t AV_RB24(const void *p) -{ - uint32_t v; - __asm__ ("ld.ub %0, %3 \n\t" - "ldins.b %0:l, %2 \n\t" - "ldins.b %0:u, %1 \n\t" - : "=&r"(v) - : "RKs12"(* (const uint8_t*)p), - "RKs12"(*((const uint8_t*)p+1)), - "m" (*((const uint8_t*)p+2))); - return v; -} - -#define AV_RL24 AV_RL24 -static av_always_inline uint32_t AV_RL24(const void *p) -{ - uint32_t v; - __asm__ ("ld.ub %0, %1 \n\t" - "ldins.b %0:l, %2 \n\t" - "ldins.b %0:u, %3 \n\t" - : "=&r"(v) - : "m" (* (const uint8_t*)p), - "RKs12"(*((const uint8_t*)p+1)), - "RKs12"(*((const uint8_t*)p+2))); - return v; -} - -#if ARCH_AVR32_AP - -#define AV_RB32 AV_RB32 -static av_always_inline uint32_t AV_RB32(const void *p) -{ - uint32_t v; - __asm__ ("ld.w %0, %1" : "=r"(v) : "m"(*(const uint32_t*)p)); - return v; -} - -#define AV_WB32 AV_WB32 -static av_always_inline void AV_WB32(void *p, uint32_t v) -{ - __asm__ ("st.w %0, %1" : "=m"(*(uint32_t*)p) : "r"(v)); -} - -/* These two would be defined by generic code, but we need them sooner. */ -#define AV_RL32(p) av_bswap32(AV_RB32(p)) -#define AV_WL32(p, v) AV_WB32(p, av_bswap32(v)) - -#define AV_WB64 AV_WB64 -static av_always_inline void AV_WB64(void *p, uint64_t v) -{ - union { uint64_t v; uint32_t hl[2]; } vv = { v }; - AV_WB32(p, vv.hl[0]); - AV_WB32((uint32_t*)p+1, vv.hl[1]); -} - -#define AV_WL64 AV_WL64 -static av_always_inline void AV_WL64(void *p, uint64_t v) -{ - union { uint64_t v; uint32_t hl[2]; } vv = { v }; - AV_WL32(p, vv.hl[1]); - AV_WL32((uint32_t*)p+1, vv.hl[0]); -} - -#else /* ARCH_AVR32_AP */ - -#define AV_RB32 AV_RB32 -static av_always_inline uint32_t AV_RB32(const void *p) -{ - uint32_t v; - __asm__ ("ld.ub %0, %4 \n\t" - "ldins.b %0:l, %3 \n\t" - "ldins.b %0:u, %2 \n\t" - "ldins.b %0:t, %1 \n\t" - : "=&r"(v) - : "RKs12"(* (const uint8_t*)p), - "RKs12"(*((const uint8_t*)p+1)), - "RKs12"(*((const uint8_t*)p+2)), - "m" (*((const uint8_t*)p+3))); - return v; -} - -#define AV_RL32 AV_RL32 -static av_always_inline uint32_t AV_RL32(const void *p) -{ - uint32_t v; - __asm__ ("ld.ub %0, %1 \n\t" - "ldins.b %0:l, %2 \n\t" - "ldins.b %0:u, %3 \n\t" - "ldins.b %0:t, %4 \n\t" - : "=&r"(v) - : "m" (* (const uint8_t*)p), - "RKs12"(*((const uint8_t*)p+1)), - "RKs12"(*((const uint8_t*)p+2)), - "RKs12"(*((const uint8_t*)p+3))); - return v; -} - -#endif /* ARCH_AVR32_AP */ - -#define AV_RB64 AV_RB64 -static av_always_inline uint64_t AV_RB64(const void *p) -{ - union { uint64_t v; uint32_t hl[2]; } v; - v.hl[0] = AV_RB32(p); - v.hl[1] = AV_RB32((const uint32_t*)p+1); - return v.v; -} - -#define AV_RL64 AV_RL64 -static av_always_inline uint64_t AV_RL64(const void *p) -{ - union { uint64_t v; uint32_t hl[2]; } v; - v.hl[1] = AV_RL32(p); - v.hl[0] = AV_RL32((const uint32_t*)p+1); - return v.v; -} - -#endif /* AVUTIL_AVR32_INTREADWRITE_H */ diff --git a/libavutil/avsscanf.c b/libavutil/avsscanf.c index 7061e6d96..94f771004 100644 --- a/libavutil/avsscanf.c +++ b/libavutil/avsscanf.c @@ -669,7 +669,6 @@ static double fffloatscan(FFFILE *f, int prec, int pok) while (i--) shunget(f); return NAN; } - return NAN; } if (i) { diff --git a/libavutil/avstring.c b/libavutil/avstring.c index 2071dd36a..875eb691d 100644 --- a/libavutil/avstring.c +++ b/libavutil/avstring.c @@ -452,10 +452,12 @@ int av_match_list(const char *name, const char *list, char separator) if (k && (!p[k] || p[k] == separator)) return 1; q = strchr(q, separator); - q += !!q; + if(q) + q++; } p = strchr(p, separator); - p += !!p; + if (p) + p++; } return 0; diff --git a/libavutil/bswap.h b/libavutil/bswap.h index 4840ab433..f53e5768a 100644 --- a/libavutil/bswap.h +++ b/libavutil/bswap.h @@ -34,16 +34,10 @@ #include "config.h" -#if ARCH_AARCH64 -# include "aarch64/bswap.h" -#elif ARCH_ARM +#if ARCH_ARM # include "arm/bswap.h" -#elif ARCH_AVR32 -# include "avr32/bswap.h" #elif ARCH_RISCV # include "riscv/bswap.h" -#elif ARCH_SH4 -# include "sh4/bswap.h" #elif ARCH_X86 # include "x86/bswap.h" #endif diff --git a/libavutil/channel_layout.c b/libavutil/channel_layout.c index 3054ee08a..2d6963b6d 100644 --- a/libavutil/channel_layout.c +++ b/libavutil/channel_layout.c @@ -33,6 +33,7 @@ #include "common.h" #include "error.h" #include "macros.h" +#include "mem.h" #include "opt.h" #define CHAN_IS_AMBI(x) ((x) >= AV_CHAN_AMBISONIC_BASE &&\ @@ -74,6 +75,10 @@ static const struct channel_name channel_names[] = { [AV_CHAN_BOTTOM_FRONT_CENTER ] = { "BFC", "bottom front center" }, [AV_CHAN_BOTTOM_FRONT_LEFT ] = { "BFL", "bottom front left" }, [AV_CHAN_BOTTOM_FRONT_RIGHT ] = { "BFR", "bottom front right" }, + [AV_CHAN_SIDE_SURROUND_LEFT ] = { "SSL", "side surround left" }, + [AV_CHAN_SIDE_SURROUND_RIGHT ] = { "SSR", "side surround right" }, + [AV_CHAN_TOP_SURROUND_LEFT ] = { "TTL", "top surround left" }, + [AV_CHAN_TOP_SURROUND_RIGHT ] = { "TTR", "top surround right" }, }; void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id) @@ -472,15 +477,14 @@ static int has_channel_names(const AVChannelLayout *channel_layout) return 0; } -/** - * If the layout is n-th order standard-order ambisonic, with optional - * extra non-diegetic channels at the end, return the order. - * Return a negative error code otherwise. - */ -static int ambisonic_order(const AVChannelLayout *channel_layout) +int av_channel_layout_ambisonic_order(const AVChannelLayout *channel_layout) { int i, highest_ambi, order; + if (channel_layout->order != AV_CHANNEL_ORDER_AMBISONIC && + channel_layout->order != AV_CHANNEL_ORDER_CUSTOM) + return AVERROR(EINVAL); + highest_ambi = -1; if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) highest_ambi = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask) - 1; @@ -535,7 +539,7 @@ static enum AVChannelOrder canonical_order(AVChannelLayout *channel_layout) if (masked_description(channel_layout, 0) > 0) return AV_CHANNEL_ORDER_NATIVE; - order = ambisonic_order(channel_layout); + order = av_channel_layout_ambisonic_order(channel_layout); if (order >= 0 && masked_description(channel_layout, (order + 1) * (order + 1)) >= 0) return AV_CHANNEL_ORDER_AMBISONIC; @@ -550,7 +554,7 @@ static enum AVChannelOrder canonical_order(AVChannelLayout *channel_layout) static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout) { int nb_ambi_channels; - int order = ambisonic_order(channel_layout); + int order = av_channel_layout_ambisonic_order(channel_layout); if (order < 0) return order; @@ -944,7 +948,7 @@ int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrde if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) { int64_t mask; int nb_channels = channel_layout->nb_channels; - int order = ambisonic_order(channel_layout); + int order = av_channel_layout_ambisonic_order(channel_layout); if (order < 0) return AVERROR(ENOSYS); mask = masked_description(channel_layout, (order + 1) * (order + 1)); diff --git a/libavutil/channel_layout.h b/libavutil/channel_layout.h index 8a078d160..3a96c2d9b 100644 --- a/libavutil/channel_layout.h +++ b/libavutil/channel_layout.h @@ -79,6 +79,10 @@ enum AVChannel { AV_CHAN_BOTTOM_FRONT_CENTER, AV_CHAN_BOTTOM_FRONT_LEFT, AV_CHAN_BOTTOM_FRONT_RIGHT, + AV_CHAN_SIDE_SURROUND_LEFT, ///< +90 degrees, Lss, SiL + AV_CHAN_SIDE_SURROUND_RIGHT, ///< -90 degrees, Rss, SiR + AV_CHAN_TOP_SURROUND_LEFT, ///< +110 degrees, Lvs, TpLS + AV_CHAN_TOP_SURROUND_RIGHT, ///< -110 degrees, Rvs, TpRS /** Channel is empty can be safely skipped. */ AV_CHAN_UNUSED = 0x200, @@ -195,6 +199,10 @@ enum AVChannelOrder { #define AV_CH_BOTTOM_FRONT_CENTER (1ULL << AV_CHAN_BOTTOM_FRONT_CENTER ) #define AV_CH_BOTTOM_FRONT_LEFT (1ULL << AV_CHAN_BOTTOM_FRONT_LEFT ) #define AV_CH_BOTTOM_FRONT_RIGHT (1ULL << AV_CHAN_BOTTOM_FRONT_RIGHT ) +#define AV_CH_SIDE_SURROUND_LEFT (1ULL << AV_CHAN_SIDE_SURROUND_LEFT ) +#define AV_CH_SIDE_SURROUND_RIGHT (1ULL << AV_CHAN_SIDE_SURROUND_RIGHT ) +#define AV_CH_TOP_SURROUND_LEFT (1ULL << AV_CHAN_TOP_SURROUND_LEFT ) +#define AV_CH_TOP_SURROUND_RIGHT (1ULL << AV_CHAN_TOP_SURROUND_RIGHT ) /** * @} @@ -679,6 +687,16 @@ int av_channel_layout_check(const AVChannelLayout *channel_layout); */ int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1); +/** + * Return the order if the layout is n-th order standard-order ambisonic. + * The presence of optional extra non-diegetic channels at the end is not taken + * into account. + * + * @param channel_layout input channel layout + * @return the order of the layout, a negative error code otherwise. + */ +int av_channel_layout_ambisonic_order(const AVChannelLayout *channel_layout); + /** * The conversion must be lossless. */ diff --git a/libavutil/common.h b/libavutil/common.h index 57c87f191..3b830daf3 100644 --- a/libavutil/common.h +++ b/libavutil/common.h @@ -42,12 +42,14 @@ #include "attributes.h" #include "error.h" #include "macros.h" -#include "mem.h" +#include "version.h" #ifdef HAVE_AV_CONFIG_H # include "config.h" # include "intmath.h" # include "internal.h" +#else +# include "mem.h" #endif /* HAVE_AV_CONFIG_H */ //rounded division & shift @@ -121,9 +123,6 @@ #ifndef av_clip_uintp2 # define av_clip_uintp2 av_clip_uintp2_c #endif -#ifndef av_mod_uintp2 -# define av_mod_uintp2 av_mod_uintp2_c -#endif #ifndef av_sat_add32 # define av_sat_add32 av_sat_add32_c #endif @@ -148,6 +147,9 @@ #ifndef av_clipd # define av_clipd av_clipd_c #endif +#ifndef av_zero_extend +# define av_zero_extend av_zero_extend_c +#endif #ifndef av_popcount # define av_popcount av_popcount_c #endif @@ -251,8 +253,8 @@ static av_always_inline av_const int16_t av_clip_int16_c(int a) */ static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a) { - if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF); - else return (int32_t)a; + if ((a+UINT64_C(0x80000000)) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF); + else return (int32_t)a; } /** @@ -263,7 +265,7 @@ static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a) */ static av_always_inline av_const int av_clip_intp2_c(int a, int p) { - if (((unsigned)a + (1 << p)) & ~((2 << p) - 1)) + if (((unsigned)a + (1U << p)) & ~((2U << p) - 1)) return (a >> 31) ^ ((1 << p) - 1); else return a; @@ -277,21 +279,35 @@ static av_always_inline av_const int av_clip_intp2_c(int a, int p) */ static av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p) { - if (a & ~((1<> 31 & ((1<> 31 & ((1U<= 2 + if (p > 31) abort(); +#endif return a & ((1U << p) - 1); } +#if FF_API_MOD_UINTP2 +#ifndef av_mod_uintp2 +# define av_mod_uintp2 av_mod_uintp2_c +#endif +attribute_deprecated +static av_always_inline av_const unsigned av_mod_uintp2_c(unsigned a, unsigned p) +{ + return av_zero_extend_c(a, p); +} +#endif + /** * Add two signed 32-bit values with saturation. * diff --git a/libavutil/cpu.c b/libavutil/cpu.c index 48d195168..44cbb9e9f 100644 --- a/libavutil/cpu.c +++ b/libavutil/cpu.c @@ -49,8 +49,12 @@ #include #endif -static atomic_int cpu_flags = ATOMIC_VAR_INIT(-1); -static atomic_int cpu_count = ATOMIC_VAR_INIT(-1); +#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO +#include +#endif + +static atomic_int cpu_flags = -1; +static atomic_int cpu_count = -1; static int get_cpu_flags(void) { @@ -116,6 +120,8 @@ int av_parse_cpu_caps(unsigned *flags, const char *s) { "flags" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" }, #if ARCH_PPC { "altivec" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ALTIVEC }, .unit = "flags" }, + { "vsx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VSX }, .unit = "flags" }, + { "power8" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_POWER8 }, .unit = "flags" }, #elif ARCH_X86 { "mmx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" }, { "mmx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX2 }, .unit = "flags" }, @@ -184,14 +190,14 @@ int av_parse_cpu_caps(unsigned *flags, const char *s) { "lasx", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_LASX }, .unit = "flags" }, #elif ARCH_RISCV { "rvi", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVI }, .unit = "flags" }, - { "rvf", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVF }, .unit = "flags" }, - { "rvd", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVD }, .unit = "flags" }, + { "rvb", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVB }, .unit = "flags" }, { "zve32x", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVV_I32 }, .unit = "flags" }, { "zve32f", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVV_F32 }, .unit = "flags" }, { "zve64x", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVV_I64 }, .unit = "flags" }, { "zve64d", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVV_F64 }, .unit = "flags" }, - { "zba", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVB_ADDR }, .unit = "flags" }, { "zbb", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVB_BASIC }, .unit = "flags" }, + { "zvbb", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RV_ZVBB }, .unit = "flags" }, + { "misaligned", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RV_MISALIGNED }, .unit = "flags" }, #endif { NULL }, }; @@ -208,7 +214,7 @@ int av_parse_cpu_caps(unsigned *flags, const char *s) int av_cpu_count(void) { - static atomic_int printed = ATOMIC_VAR_INIT(0); + static atomic_int printed = 0; int nb_cpus = 1; int count = 0; @@ -283,3 +289,20 @@ size_t av_cpu_max_align(void) return 8; } + +unsigned long ff_getauxval(unsigned long type) +{ +#if HAVE_GETAUXVAL + return getauxval(type); +#elif HAVE_ELF_AUX_INFO + unsigned long aux = 0; + int ret = elf_aux_info(type, &aux, sizeof(aux)); + if (ret != 0) { + errno = ret; + } + return aux; +#else + errno = ENOSYS; + return 0; +#endif +} diff --git a/libavutil/cpu.h b/libavutil/cpu.h index 8dff34188..ba6c234e0 100644 --- a/libavutil/cpu.h +++ b/libavutil/cpu.h @@ -22,6 +22,7 @@ #define AVUTIL_CPU_H #include +#include "version.h" #define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ @@ -82,14 +83,21 @@ // RISC-V extensions #define AV_CPU_FLAG_RVI (1 << 0) ///< I (full GPR bank) +#if FF_API_RISCV_FD_ZBA #define AV_CPU_FLAG_RVF (1 << 1) ///< F (single precision FP) #define AV_CPU_FLAG_RVD (1 << 2) ///< D (double precision FP) +#endif #define AV_CPU_FLAG_RVV_I32 (1 << 3) ///< Vectors of 8/16/32-bit int's */ #define AV_CPU_FLAG_RVV_F32 (1 << 4) ///< Vectors of float's */ #define AV_CPU_FLAG_RVV_I64 (1 << 5) ///< Vectors of 64-bit int's */ #define AV_CPU_FLAG_RVV_F64 (1 << 6) ///< Vectors of double's #define AV_CPU_FLAG_RVB_BASIC (1 << 7) ///< Basic bit-manipulations +#if FF_API_RISCV_FD_ZBA #define AV_CPU_FLAG_RVB_ADDR (1 << 8) ///< Address bit-manipulations +#endif +#define AV_CPU_FLAG_RV_ZVBB (1 << 9) ///< Vector basic bit-manipulations +#define AV_CPU_FLAG_RV_MISALIGNED (1 <<10) ///< Fast misaligned accesses +#define AV_CPU_FLAG_RVB (1 <<11) ///< B (bit manipulations) /** * Return the flags which specify extensions supported by the CPU. diff --git a/libavutil/cpu_internal.h b/libavutil/cpu_internal.h index 634f28bac..585a115c4 100644 --- a/libavutil/cpu_internal.h +++ b/libavutil/cpu_internal.h @@ -59,4 +59,6 @@ size_t ff_get_cpu_max_align_ppc(void); size_t ff_get_cpu_max_align_x86(void); size_t ff_get_cpu_max_align_loongarch(void); +unsigned long ff_getauxval(unsigned long type); + #endif /* AVUTIL_CPU_INTERNAL_H */ diff --git a/libavutil/detection_bbox.c b/libavutil/detection_bbox.c index bae8f0642..cb157b355 100644 --- a/libavutil/detection_bbox.c +++ b/libavutil/detection_bbox.c @@ -17,6 +17,7 @@ */ #include "detection_bbox.h" +#include "mem.h" AVDetectionBBoxHeader *av_detection_bbox_alloc(uint32_t nb_bboxes, size_t *out_size) { diff --git a/libavutil/dovi_meta.c b/libavutil/dovi_meta.c index 9c50da561..dfa4a438e 100644 --- a/libavutil/dovi_meta.c +++ b/libavutil/dovi_meta.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "dovi_meta.h" #include "mem.h" @@ -39,6 +41,7 @@ typedef struct AVDOVIMetadataInternal { AVDOVIRpuDataHeader header; AVDOVIDataMapping mapping; AVDOVIColorMetadata color; + AVDOVIDmData ext_blocks[AV_DOVI_MAX_EXT_BLOCKS]; } AVDOVIMetadataInternal; AVDOVIMetadata *av_dovi_metadata_alloc(size_t *size) @@ -51,10 +54,23 @@ AVDOVIMetadata *av_dovi_metadata_alloc(size_t *size) *size = sizeof(*dovi); dovi->metadata = (struct AVDOVIMetadata) { - .header_offset = offsetof(AVDOVIMetadataInternal, header), - .mapping_offset = offsetof(AVDOVIMetadataInternal, mapping), - .color_offset = offsetof(AVDOVIMetadataInternal, color), + .header_offset = offsetof(AVDOVIMetadataInternal, header), + .mapping_offset = offsetof(AVDOVIMetadataInternal, mapping), + .color_offset = offsetof(AVDOVIMetadataInternal, color), + .ext_block_offset = offsetof(AVDOVIMetadataInternal, ext_blocks), + .ext_block_size = sizeof(AVDOVIDmData), }; return &dovi->metadata; } + +AVDOVIDmData *av_dovi_find_level(const AVDOVIMetadata *data, uint8_t level) +{ + for (int i = 0; i < data->num_ext_blocks; i++) { + AVDOVIDmData *ext = av_dovi_get_ext(data, i); + if (ext->level == level) + return ext; + } + + return NULL; +} diff --git a/libavutil/dovi_meta.h b/libavutil/dovi_meta.h index 3d11e02bf..5e8a1e43d 100644 --- a/libavutil/dovi_meta.h +++ b/libavutil/dovi_meta.h @@ -29,7 +29,9 @@ #include #include + #include "rational.h" +#include "csp.h" /* * DOVI configuration @@ -44,6 +46,7 @@ * uint8_t el_present_flag * uint8_t bl_present_flag * uint8_t dv_bl_signal_compatibility_id + * uint8_t dv_md_compression, the compression method in use * @endcode * * @note The struct must be allocated with av_dovi_alloc() and @@ -58,8 +61,16 @@ typedef struct AVDOVIDecoderConfigurationRecord { uint8_t el_present_flag; uint8_t bl_present_flag; uint8_t dv_bl_signal_compatibility_id; + uint8_t dv_md_compression; } AVDOVIDecoderConfigurationRecord; +enum AVDOVICompression { + AV_DOVI_COMPRESSION_NONE = 0, + AV_DOVI_COMPRESSION_LIMITED = 1, + AV_DOVI_COMPRESSION_RESERVED = 2, + AV_DOVI_COMPRESSION_EXTENDED = 3, +}; + /** * Allocate a AVDOVIDecoderConfigurationRecord structure and initialize its * fields to default values. @@ -89,6 +100,8 @@ typedef struct AVDOVIRpuDataHeader { uint8_t spatial_resampling_filter_flag; uint8_t el_spatial_resampling_filter_flag; uint8_t disable_residual_flag; + uint8_t ext_mapping_idc_0_4; /* extended base layer inverse mapping indicator */ + uint8_t ext_mapping_idc_5_7; /* reserved */ } AVDOVIRpuDataHeader; enum AVDOVIMappingMethod { @@ -147,6 +160,7 @@ typedef struct AVDOVIDataMapping { uint32_t num_x_partitions; uint32_t num_y_partitions; AVDOVINLQParams nlq[3]; /* per component */ + uint16_t nlq_pivots[2]; } AVDOVIDataMapping; /** @@ -186,6 +200,132 @@ typedef struct AVDOVIColorMetadata { uint16_t source_diagonal; } AVDOVIColorMetadata; +typedef struct AVDOVIDmLevel1 { + /* Per-frame brightness metadata */ + uint16_t min_pq; + uint16_t max_pq; + uint16_t avg_pq; +} AVDOVIDmLevel1; + +typedef struct AVDOVIDmLevel2 { + /* Usually derived from level 8 (at different levels) */ + uint16_t target_max_pq; + uint16_t trim_slope; + uint16_t trim_offset; + uint16_t trim_power; + uint16_t trim_chroma_weight; + uint16_t trim_saturation_gain; + int16_t ms_weight; +} AVDOVIDmLevel2; + +typedef struct AVDOVIDmLevel3 { + uint16_t min_pq_offset; + uint16_t max_pq_offset; + uint16_t avg_pq_offset; +} AVDOVIDmLevel3; + +typedef struct AVDOVIDmLevel4 { + uint16_t anchor_pq; + uint16_t anchor_power; +} AVDOVIDmLevel4; + +typedef struct AVDOVIDmLevel5 { + /* Active area definition */ + uint16_t left_offset; + uint16_t right_offset; + uint16_t top_offset; + uint16_t bottom_offset; +} AVDOVIDmLevel5; + +typedef struct AVDOVIDmLevel6 { + /* Static HDR10 metadata */ + uint16_t max_luminance; + uint16_t min_luminance; + uint16_t max_cll; + uint16_t max_fall; +} AVDOVIDmLevel6; + +typedef struct AVDOVIDmLevel8 { + /* Extended version of level 2 */ + uint8_t target_display_index; + uint16_t trim_slope; + uint16_t trim_offset; + uint16_t trim_power; + uint16_t trim_chroma_weight; + uint16_t trim_saturation_gain; + uint16_t ms_weight; + uint16_t target_mid_contrast; + uint16_t clip_trim; + uint8_t saturation_vector_field[6]; + uint8_t hue_vector_field[6]; +} AVDOVIDmLevel8; + +typedef struct AVDOVIDmLevel9 { + /* Source display characteristics */ + uint8_t source_primary_index; + AVColorPrimariesDesc source_display_primaries; +} AVDOVIDmLevel9; + +typedef struct AVDOVIDmLevel10 { + /* Target display characteristics */ + uint8_t target_display_index; + uint16_t target_max_pq; + uint16_t target_min_pq; + uint8_t target_primary_index; + AVColorPrimariesDesc target_display_primaries; +} AVDOVIDmLevel10; + +typedef struct AVDOVIDmLevel11 { + uint8_t content_type; + uint8_t whitepoint; + uint8_t reference_mode_flag; + uint8_t sharpness; + uint8_t noise_reduction; + uint8_t mpeg_noise_reduction; + uint8_t frame_rate_conversion; + uint8_t brightness; + uint8_t color; +} AVDOVIDmLevel11; + +typedef struct AVDOVIDmLevel254 { + /* DMv2 info block, always present in samples with DMv2 metadata */ + uint8_t dm_mode; + uint8_t dm_version_index; +} AVDOVIDmLevel254; + +typedef struct AVDOVIDmLevel255 { + /* Debug block, not really used in samples */ + uint8_t dm_run_mode; + uint8_t dm_run_version; + uint8_t dm_debug[4]; +} AVDOVIDmLevel255; + +/** + * Dolby Vision metadata extension block. Dynamic extension blocks may change + * from frame to frame, while static blocks are constant throughout the entire + * sequence. + * + * @note sizeof(AVDOVIDmData) is not part of the public API. + */ +typedef struct AVDOVIDmData { + uint8_t level; /* [1, 255] */ + union { + AVDOVIDmLevel1 l1; /* dynamic */ + AVDOVIDmLevel2 l2; /* dynamic, may appear multiple times */ + AVDOVIDmLevel3 l3; /* dynamic */ + AVDOVIDmLevel4 l4; /* dynamic */ + AVDOVIDmLevel5 l5; /* dynamic */ + AVDOVIDmLevel6 l6; /* static */ + /* level 7 is currently unused */ + AVDOVIDmLevel8 l8; /* dynamic, may appear multiple times */ + AVDOVIDmLevel9 l9; /* dynamic */ + AVDOVIDmLevel10 l10; /* static, may appear multiple times */ + AVDOVIDmLevel11 l11; /* dynamic */ + AVDOVIDmLevel254 l254; /* static */ + AVDOVIDmLevel255 l255; /* static */ + }; +} AVDOVIDmData; + /** * Combined struct representing a combination of header, mapping and color * metadata, for attaching to frames as side data. @@ -202,6 +342,13 @@ typedef struct AVDOVIMetadata { size_t header_offset; /* AVDOVIRpuDataHeader */ size_t mapping_offset; /* AVDOVIDataMapping */ size_t color_offset; /* AVDOVIColorMetadata */ + + size_t ext_block_offset; /* offset to start of ext blocks array */ + size_t ext_block_size; /* size per element */ + int num_ext_blocks; /* number of extension blocks */ + + /* static limit on num_ext_blocks, derived from bitstream limitations */ +#define AV_DOVI_MAX_EXT_BLOCKS 32 } AVDOVIMetadata; static av_always_inline AVDOVIRpuDataHeader * @@ -222,6 +369,19 @@ av_dovi_get_color(const AVDOVIMetadata *data) return (AVDOVIColorMetadata *)((uint8_t *) data + data->color_offset); } +static av_always_inline AVDOVIDmData * +av_dovi_get_ext(const AVDOVIMetadata *data, int index) +{ + return (AVDOVIDmData *)((uint8_t *) data + data->ext_block_offset + + data->ext_block_size * index); +} + +/** + * Find an extension block with a given level, or NULL. In the case of + * multiple extension blocks, only the first is returned. + */ +AVDOVIDmData *av_dovi_find_level(const AVDOVIMetadata *data, uint8_t level); + /** * Allocate an AVDOVIMetadata structure and initialize its * fields to default values. diff --git a/libavutil/downmix_info.c b/libavutil/downmix_info.c index c634c6a79..7e6c3e854 100644 --- a/libavutil/downmix_info.c +++ b/libavutil/downmix_info.c @@ -27,9 +27,12 @@ AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame) side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO); - if (!side_data) + if (!side_data) { side_data = av_frame_new_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO, sizeof(AVDownmixInfo)); + if (side_data) + memset(side_data->data, 0, sizeof(AVDownmixInfo)); + } if (!side_data) return NULL; diff --git a/libavutil/error.c b/libavutil/error.c index 938a8bc00..90bab7b9d 100644 --- a/libavutil/error.c +++ b/libavutil/error.c @@ -61,6 +61,7 @@ static const struct error_entry error_entries[] = { { ERROR_TAG(HTTP_UNAUTHORIZED), "Server returned 401 Unauthorized (authorization failed)" }, { ERROR_TAG(HTTP_FORBIDDEN), "Server returned 403 Forbidden (access denied)" }, { ERROR_TAG(HTTP_NOT_FOUND), "Server returned 404 Not Found" }, + { ERROR_TAG(HTTP_TOO_MANY_REQUESTS), "Server returned 429 Too Many Requests" }, { ERROR_TAG(HTTP_OTHER_4XX), "Server returned 4XX Client Error, but not one of 40{0,1,3,4}" }, { ERROR_TAG(HTTP_SERVER_ERROR), "Server returned 5XX Server Error reply" }, #if !HAVE_STRERROR_R diff --git a/libavutil/error.h b/libavutil/error.h index 0d3269aa6..1efa86c4c 100644 --- a/libavutil/error.h +++ b/libavutil/error.h @@ -79,6 +79,7 @@ #define AVERROR_HTTP_UNAUTHORIZED FFERRTAG(0xF8,'4','0','1') #define AVERROR_HTTP_FORBIDDEN FFERRTAG(0xF8,'4','0','3') #define AVERROR_HTTP_NOT_FOUND FFERRTAG(0xF8,'4','0','4') +#define AVERROR_HTTP_TOO_MANY_REQUESTS FFERRTAG(0xF8,'4','2','9') #define AVERROR_HTTP_OTHER_4XX FFERRTAG(0xF8,'4','X','X') #define AVERROR_HTTP_SERVER_ERROR FFERRTAG(0xF8,'5','X','X') diff --git a/libavutil/eval.c b/libavutil/eval.c index bc4a00d7d..298925a6e 100644 --- a/libavutil/eval.c +++ b/libavutil/eval.c @@ -32,13 +32,12 @@ #include "common.h" #include "eval.h" #include "ffmath.h" -#include "internal.h" #include "log.h" #include "mathematics.h" +#include "mem.h" #include "sfc64.h" #include "time.h" #include "avstring.h" -#include "timer.h" #include "reverse.h" typedef struct Parser { diff --git a/libavutil/executor.c b/libavutil/executor.c index 0da919f4e..bfce2ac44 100644 --- a/libavutil/executor.c +++ b/libavutil/executor.c @@ -17,7 +17,11 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "internal.h" + +#include "config.h" + +#include + #include "mem.h" #include "thread.h" @@ -47,6 +51,7 @@ typedef struct ThreadInfo { struct AVExecutor { AVTaskCallbacks cb; int thread_count; + bool recursive; ThreadInfo *threads; uint8_t *local_contexts; @@ -80,9 +85,11 @@ static int run_one_task(AVExecutor *e, void *lc) /* nothing */; if (*prev) { AVTask *t = remove_task(prev, *prev); - ff_mutex_unlock(&e->lock); + if (e->thread_count > 0) + ff_mutex_unlock(&e->lock); cb->run(t, lc, cb->user_data); - ff_mutex_lock(&e->lock); + if (e->thread_count > 0) + ff_mutex_lock(&e->lock); return 1; } return 0; @@ -144,14 +151,17 @@ AVExecutor* av_executor_alloc(const AVTaskCallbacks *cb, int thread_count) return NULL; e->cb = *cb; - e->local_contexts = av_calloc(thread_count, e->cb.local_context_size); + e->local_contexts = av_calloc(FFMAX(thread_count, 1), e->cb.local_context_size); if (!e->local_contexts) goto free_executor; - e->threads = av_calloc(thread_count, sizeof(*e->threads)); + 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); @@ -173,9 +183,12 @@ free_executor: void av_executor_free(AVExecutor **executor) { + int thread_count; + if (!executor || !*executor) return; - executor_free(*executor, 1, 1); + thread_count = (*executor)->thread_count; + executor_free(*executor, thread_count, thread_count); *executor = NULL; } @@ -184,18 +197,25 @@ void av_executor_execute(AVExecutor *e, AVTask *t) AVTaskCallbacks *cb = &e->cb; AVTask **prev; - ff_mutex_lock(&e->lock); + if (e->thread_count) + ff_mutex_lock(&e->lock); if (t) { for (prev = &e->tasks; *prev && cb->priority_higher(*prev, t); prev = &(*prev)->next) /* nothing */; add_task(prev, t); } - ff_cond_signal(&e->cond); - ff_mutex_unlock(&e->lock); + if (e->thread_count) { + ff_cond_signal(&e->cond); + ff_mutex_unlock(&e->lock); + } -#if !HAVE_THREADS - // We are running in a single-threaded environment, so we must handle all tasks ourselves - while (run_one_task(e, e->local_contexts)) - /* nothing */; -#endif + 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/libavutil/executor.h b/libavutil/executor.h index c602bcb61..0eb21c10c 100644 --- a/libavutil/executor.h +++ b/libavutil/executor.h @@ -46,7 +46,7 @@ typedef struct AVTaskCallbacks { /** * Alloc executor * @param callbacks callback structure for executor - * @param thread_count worker thread number + * @param thread_count worker thread number, 0 for run on caller's thread directly * @return return the executor */ AVExecutor* av_executor_alloc(const AVTaskCallbacks *callbacks, int thread_count); diff --git a/libavutil/fifo.h b/libavutil/fifo.h index 048298214..f2206c35f 100644 --- a/libavutil/fifo.h +++ b/libavutil/fifo.h @@ -26,10 +26,6 @@ #define AVUTIL_FIFO_H #include -#include - -#include "attributes.h" -#include "version.h" /** * @defgroup lavu_fifo AVFifo diff --git a/libavutil/file.c b/libavutil/file.c index 2d1063b6a..db8507286 100644 --- a/libavutil/file.c +++ b/libavutil/file.c @@ -60,21 +60,18 @@ int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, struct stat st; av_unused void *ptr; off_t off_size; - char errbuf[128]; *bufptr = NULL; *size = 0; if (fd < 0) { err = AVERROR(errno); - av_strerror(err, errbuf, sizeof(errbuf)); - av_log(&file_log_ctx, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename, errbuf); + av_log(&file_log_ctx, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename, av_err2str(err)); return err; } if (fstat(fd, &st) < 0) { err = AVERROR(errno); - av_strerror(err, errbuf, sizeof(errbuf)); - av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in fstat(): %s\n", errbuf); + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in fstat(): %s\n", av_err2str(err)); close(fd); return err; } @@ -97,8 +94,7 @@ int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, ptr = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (ptr == MAP_FAILED) { err = AVERROR(errno); - av_strerror(err, errbuf, sizeof(errbuf)); - av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in mmap(): %s\n", errbuf); + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in mmap(): %s\n", av_err2str(err)); close(fd); *size = 0; return err; diff --git a/libavutil/file.h b/libavutil/file.h index b5a762c28..fced17010 100644 --- a/libavutil/file.h +++ b/libavutil/file.h @@ -22,7 +22,6 @@ #include #include -#include "version.h" #include "attributes.h" /** diff --git a/libavutil/file_open.c b/libavutil/file_open.c index 24ef33e3d..4692035d5 100644 --- a/libavutil/file_open.c +++ b/libavutil/file_open.c @@ -112,7 +112,10 @@ int avpriv_tempfile(const char *prefix, char **filename, int log_offset, void *l { FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx }; int fd = -1; -#if !HAVE_MKSTEMP +#if HAVE_MKSTEMP + size_t len = strlen(prefix) + 12; /* room for "/tmp/" and "XXXXXX\0" */ + *filename = av_malloc(len); +#elif HAVE_TEMPNAM void *ptr= tempnam(NULL, prefix); if(!ptr) ptr= tempnam(".", prefix); @@ -120,8 +123,7 @@ int avpriv_tempfile(const char *prefix, char **filename, int log_offset, void *l #undef free free(ptr); #else - size_t len = strlen(prefix) + 12; /* room for "/tmp/" and "XXXXXX\0" */ - *filename = av_malloc(len); + return AVERROR(ENOSYS); #endif /* -----common section-----*/ if (!*filename) { diff --git a/libavutil/film_grain_params.c b/libavutil/film_grain_params.c index 8f8dcee56..0a6004b6b 100644 --- a/libavutil/film_grain_params.c +++ b/libavutil/film_grain_params.c @@ -17,6 +17,7 @@ */ #include "film_grain_params.h" +#include "mem.h" #include "pixdesc.h" AVFilmGrainParams *av_film_grain_params_alloc(size_t *size) diff --git a/libavutil/fixed_dsp.c b/libavutil/fixed_dsp.c index b144aa359..95f0eb259 100644 --- a/libavutil/fixed_dsp.c +++ b/libavutil/fixed_dsp.c @@ -47,6 +47,7 @@ #include "common.h" #include "fixed_dsp.h" +#include "mem.h" static void vector_fmul_add_c(int *dst, const int *src0, const int *src1, const int *src2, int len){ int i; diff --git a/libavutil/float_dsp.c b/libavutil/float_dsp.c index e9fb02346..08bbc85e3 100644 --- a/libavutil/float_dsp.c +++ b/libavutil/float_dsp.c @@ -132,6 +132,17 @@ float avpriv_scalarproduct_float_c(const float *v1, const float *v2, int len) return p; } +double ff_scalarproduct_double_c(const double *v1, const double *v2, + size_t len) +{ + double p = 0.0; + + for (size_t i = 0; i < len; i++) + p += v1[i] * v2[i]; + + return p; +} + av_cold AVFloatDSPContext *avpriv_float_dsp_alloc(int bit_exact) { AVFloatDSPContext *fdsp = av_mallocz(sizeof(AVFloatDSPContext)); @@ -149,6 +160,7 @@ av_cold AVFloatDSPContext *avpriv_float_dsp_alloc(int bit_exact) fdsp->vector_fmul_reverse = vector_fmul_reverse_c; fdsp->butterflies_float = butterflies_float_c; fdsp->scalarproduct_float = avpriv_scalarproduct_float_c; + fdsp->scalarproduct_double = ff_scalarproduct_double_c; #if ARCH_AARCH64 ff_float_dsp_init_aarch64(fdsp); diff --git a/libavutil/float_dsp.h b/libavutil/float_dsp.h index 342a8715c..a99edc39b 100644 --- a/libavutil/float_dsp.h +++ b/libavutil/float_dsp.h @@ -19,6 +19,8 @@ #ifndef AVUTIL_FLOAT_DSP_H #define AVUTIL_FLOAT_DSP_H +#include + typedef struct AVFloatDSPContext { /** * Calculate the entry wise product of two vectors of floats and store the result in @@ -187,10 +189,25 @@ typedef struct AVFloatDSPContext { */ void (*vector_dmul)(double *dst, const double *src0, const double *src1, int len); + + /** + * Calculate the scalar product of two vectors of doubles. + * + * @param v1 first vector + * constraints: 32-byte aligned + * @param v2 second vector + * constraints: 32-byte aligned + * @param len length of vectors + * constraints: multiple of 16 + * + * @return inner product of the vectors + */ + double (*scalarproduct_double)(const double *v1, const double *v2, + size_t len); } AVFloatDSPContext; /** - * Return the scalar product of two vectors. + * Return the scalar product of two vectors of floats. * * @param v1 first input vector * @param v2 first input vector @@ -200,6 +217,18 @@ typedef struct AVFloatDSPContext { */ float avpriv_scalarproduct_float_c(const float *v1, const float *v2, int len); +/** + * Return the scalar product of two vectors of doubles. + * + * @param v1 first input vector + * @param v2 first input vector + * @param len number of elements + * + * @return inner product of the vectors + */ +double ff_scalarproduct_double_c(const double *v1, const double *v2, + size_t len); + void ff_float_dsp_init_aarch64(AVFloatDSPContext *fdsp); void ff_float_dsp_init_arm(AVFloatDSPContext *fdsp); void ff_float_dsp_init_ppc(AVFloatDSPContext *fdsp, int strict); diff --git a/libavutil/frame.c b/libavutil/frame.c index 67fbf89f1..f0a0dba01 100644 --- a/libavutil/frame.c +++ b/libavutil/frame.c @@ -28,6 +28,38 @@ #include "samplefmt.h" #include "hwcontext.h" +static const AVSideDataDescriptor sd_props[] = { + [AV_FRAME_DATA_PANSCAN] = { "AVPanScan" }, + [AV_FRAME_DATA_A53_CC] = { "ATSC A53 Part 4 Closed Captions" }, + [AV_FRAME_DATA_MATRIXENCODING] = { "AVMatrixEncoding" }, + [AV_FRAME_DATA_DOWNMIX_INFO] = { "Metadata relevant to a downmix procedure" }, + [AV_FRAME_DATA_AFD] = { "Active format description" }, + [AV_FRAME_DATA_MOTION_VECTORS] = { "Motion vectors" }, + [AV_FRAME_DATA_SKIP_SAMPLES] = { "Skip samples" }, + [AV_FRAME_DATA_GOP_TIMECODE] = { "GOP timecode" }, + [AV_FRAME_DATA_S12M_TIMECODE] = { "SMPTE 12-1 timecode" }, + [AV_FRAME_DATA_DYNAMIC_HDR_PLUS] = { "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)" }, + [AV_FRAME_DATA_DYNAMIC_HDR_VIVID] = { "HDR Dynamic Metadata CUVA 005.1 2021 (Vivid)" }, + [AV_FRAME_DATA_REGIONS_OF_INTEREST] = { "Regions Of Interest" }, + [AV_FRAME_DATA_VIDEO_ENC_PARAMS] = { "Video encoding parameters" }, + [AV_FRAME_DATA_FILM_GRAIN_PARAMS] = { "Film grain parameters" }, + [AV_FRAME_DATA_DETECTION_BBOXES] = { "Bounding boxes for object detection and classification" }, + [AV_FRAME_DATA_DOVI_RPU_BUFFER] = { "Dolby Vision RPU Data" }, + [AV_FRAME_DATA_DOVI_METADATA] = { "Dolby Vision Metadata" }, + [AV_FRAME_DATA_LCEVC] = { "LCEVC NAL data" }, + [AV_FRAME_DATA_VIEW_ID] = { "View ID" }, + [AV_FRAME_DATA_STEREO3D] = { "Stereo 3D", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_REPLAYGAIN] = { "AVReplayGain", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_DISPLAYMATRIX] = { "3x3 displaymatrix", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_AUDIO_SERVICE_TYPE] = { "Audio service type", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_MASTERING_DISPLAY_METADATA] = { "Mastering display metadata", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_CONTENT_LIGHT_LEVEL] = { "Content light level metadata", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT] = { "Ambient viewing environment", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_SPHERICAL] = { "Spherical Mapping", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_ICC_PROFILE] = { "ICC profile", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_SEI_UNREGISTERED] = { "H.26[45] User Data Unregistered SEI message", AV_SIDE_DATA_PROP_MULTI }, +}; + static void get_frame_defaults(AVFrame *frame) { memset(frame, 0, sizeof(*frame)); @@ -136,6 +168,8 @@ void av_frame_free(AVFrame **frame) av_freep(frame); } +#define ALIGN (HAVE_SIMD_ALIGN_64 ? 64 : 32) + static int get_video_buffer(AVFrame *frame, int align) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); @@ -152,7 +186,7 @@ static int get_video_buffer(AVFrame *frame, int align) if (!frame->linesize[0]) { if (align <= 0) - align = 32; /* STRIDE_ALIGN. Should be av_cpu_max_align() */ + align = ALIGN; for (int i = 1; i <= align; i += i) { ret = av_image_fill_linesizes(frame->linesize, frame->format, @@ -774,15 +808,37 @@ AVFrameSideData *av_frame_new_side_data(AVFrame *frame, return ret; } +static AVFrameSideData *replace_side_data_from_buf(AVFrameSideData *dst, + AVBufferRef *buf, int flags) +{ + if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE)) + return NULL; + + av_dict_free(&dst->metadata); + av_buffer_unref(&dst->buf); + dst->buf = buf; + dst->data = buf->data; + dst->size = buf->size; + return dst; +} + AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd, enum AVFrameSideDataType type, size_t size, unsigned int flags) { + const AVSideDataDescriptor *desc = av_frame_side_data_desc(type); AVBufferRef *buf = av_buffer_alloc(size); AVFrameSideData *ret = NULL; if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE) remove_side_data(sd, nb_sd, type); + if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) && + (ret = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, type))) { + ret = replace_side_data_from_buf(ret, buf, flags); + if (!ret) + av_buffer_unref(&buf); + return ret; + } ret = add_side_data_from_buf(sd, nb_sd, type, buf); if (!ret) @@ -791,9 +847,36 @@ AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd, return ret; } +AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type, + AVBufferRef **pbuf, unsigned int flags) +{ + const AVSideDataDescriptor *desc = av_frame_side_data_desc(type); + AVFrameSideData *sd_dst = NULL; + AVBufferRef *buf = *pbuf; + + if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE) + remove_side_data(sd, nb_sd, type); + if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) && + (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, type))) { + sd_dst = replace_side_data_from_buf(sd_dst, buf, flags); + if (sd_dst) + *pbuf = NULL; + return sd_dst; + } + + sd_dst = add_side_data_from_buf(sd, nb_sd, type, buf); + if (!sd_dst) + return NULL; + + *pbuf = NULL; + return sd_dst; +} + int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd, const AVFrameSideData *src, unsigned int flags) { + const AVSideDataDescriptor *desc; AVBufferRef *buf = NULL; AVFrameSideData *sd_dst = NULL; int ret = AVERROR_BUG; @@ -801,13 +884,37 @@ int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd, if (!sd || !src || !nb_sd || (*nb_sd && !*sd)) return AVERROR(EINVAL); + desc = av_frame_side_data_desc(src->type); + if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE) + remove_side_data(sd, nb_sd, src->type); + if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) && + (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, src->type))) { + AVDictionary *dict = NULL; + + if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE)) + return AVERROR(EEXIST); + + ret = av_dict_copy(&dict, src->metadata, 0); + if (ret < 0) + return ret; + + ret = av_buffer_replace(&sd_dst->buf, src->buf); + if (ret < 0) { + av_dict_free(&dict); + return ret; + } + + av_dict_free(&sd_dst->metadata); + sd_dst->metadata = dict; + sd_dst->data = src->data; + sd_dst->size = src->size; + return 0; + } + buf = av_buffer_ref(src->buf); if (!buf) return AVERROR(ENOMEM); - if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE) - remove_side_data(sd, nb_sd, src->type); - sd_dst = add_side_data_from_buf_ext(sd, nb_sd, src->type, buf, src->data, src->size); if (!sd_dst) { @@ -835,6 +942,12 @@ const AVFrameSideData *av_frame_side_data_get_c(const AVFrameSideData * const *s return NULL; } +void av_frame_side_data_remove(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type) +{ + remove_side_data(sd, nb_sd, type); +} + AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type) { @@ -906,38 +1019,18 @@ void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type) remove_side_data(&frame->side_data, &frame->nb_side_data, type); } +const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType type) +{ + unsigned t = type; + if (t < FF_ARRAY_ELEMS(sd_props) && sd_props[t].name) + return &sd_props[t]; + return NULL; +} + const char *av_frame_side_data_name(enum AVFrameSideDataType type) { - switch(type) { - case AV_FRAME_DATA_PANSCAN: return "AVPanScan"; - case AV_FRAME_DATA_A53_CC: return "ATSC A53 Part 4 Closed Captions"; - case AV_FRAME_DATA_STEREO3D: return "Stereo 3D"; - case AV_FRAME_DATA_MATRIXENCODING: return "AVMatrixEncoding"; - case AV_FRAME_DATA_DOWNMIX_INFO: return "Metadata relevant to a downmix procedure"; - case AV_FRAME_DATA_REPLAYGAIN: return "AVReplayGain"; - case AV_FRAME_DATA_DISPLAYMATRIX: return "3x3 displaymatrix"; - case AV_FRAME_DATA_AFD: return "Active format description"; - case AV_FRAME_DATA_MOTION_VECTORS: return "Motion vectors"; - case AV_FRAME_DATA_SKIP_SAMPLES: return "Skip samples"; - case AV_FRAME_DATA_AUDIO_SERVICE_TYPE: return "Audio service type"; - case AV_FRAME_DATA_MASTERING_DISPLAY_METADATA: return "Mastering display metadata"; - case AV_FRAME_DATA_CONTENT_LIGHT_LEVEL: return "Content light level metadata"; - case AV_FRAME_DATA_GOP_TIMECODE: return "GOP timecode"; - case AV_FRAME_DATA_S12M_TIMECODE: return "SMPTE 12-1 timecode"; - case AV_FRAME_DATA_SPHERICAL: return "Spherical Mapping"; - case AV_FRAME_DATA_ICC_PROFILE: return "ICC profile"; - case AV_FRAME_DATA_DYNAMIC_HDR_PLUS: return "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)"; - case AV_FRAME_DATA_DYNAMIC_HDR_VIVID: return "HDR Dynamic Metadata CUVA 005.1 2021 (Vivid)"; - case AV_FRAME_DATA_REGIONS_OF_INTEREST: return "Regions Of Interest"; - case AV_FRAME_DATA_VIDEO_ENC_PARAMS: return "Video encoding parameters"; - case AV_FRAME_DATA_SEI_UNREGISTERED: return "H.26[45] User Data Unregistered SEI message"; - case AV_FRAME_DATA_FILM_GRAIN_PARAMS: return "Film grain parameters"; - case AV_FRAME_DATA_DETECTION_BBOXES: return "Bounding boxes for object detection and classification"; - case AV_FRAME_DATA_DOVI_RPU_BUFFER: return "Dolby Vision RPU Data"; - case AV_FRAME_DATA_DOVI_METADATA: return "Dolby Vision Metadata"; - case AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT: return "Ambient viewing environment"; - } - return NULL; + const AVSideDataDescriptor *desc = av_frame_side_data_desc(type); + return desc ? desc->name : NULL; } static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame, diff --git a/libavutil/frame.h b/libavutil/frame.h index 8aa05ec12..f7806566d 100644 --- a/libavutil/frame.h +++ b/libavutil/frame.h @@ -228,6 +228,21 @@ enum AVFrameSideDataType { * encoding. */ AV_FRAME_DATA_VIDEO_HINT, + + /** + * Raw LCEVC payload data, as a uint8_t array, with NAL emulation + * bytes intact. + */ + AV_FRAME_DATA_LCEVC, + + /** + * This side data must be associated with a video frame. + * The presence of this side data indicates that the video stream is + * composed of multiple views (e.g. stereoscopic 3D content, + * cf. H.264 Annex H or H.265 Annex G). + * The data is an int storing the view ID. + */ + AV_FRAME_DATA_VIEW_ID, }; enum AVActiveFormatDescription { @@ -255,6 +270,37 @@ typedef struct AVFrameSideData { AVBufferRef *buf; } AVFrameSideData; +enum AVSideDataProps { + /** + * The side data type can be used in stream-global structures. + * Side data types without this property are only meaningful on per-frame + * basis. + */ + AV_SIDE_DATA_PROP_GLOBAL = (1 << 0), + + /** + * Multiple instances of this side data type can be meaningfully present in + * a single side data array. + */ + AV_SIDE_DATA_PROP_MULTI = (1 << 1), +}; + +/** + * This struct describes the properties of a side data type. Its instance + * corresponding to a given type can be obtained from av_frame_side_data_desc(). + */ +typedef struct AVSideDataDescriptor { + /** + * Human-readable side data description. + */ + const char *name; + + /** + * Side data property flags, a combination of AVSideDataProps values. + */ + unsigned props; +} AVSideDataDescriptor; + /** * Structure describing a single Region Of Interest. * @@ -338,8 +384,7 @@ typedef struct AVRegionOfInterest { * to the end with a minor bump. * * Fields can be accessed through AVOptions, the name string used, matches the - * C structure field name for fields accessible through AVOptions. The AVClass - * for AVFrame can be obtained from avcodec_get_frame_class() + * C structure field name for fields accessible through AVOptions. */ typedef struct AVFrame { #define AV_NUM_DATA_POINTERS 8 @@ -992,6 +1037,12 @@ int av_frame_apply_cropping(AVFrame *frame, int flags); */ const char *av_frame_side_data_name(enum AVFrameSideDataType type); +/** + * @return side data descriptor corresponding to a given side data type, NULL + * when not available. + */ +const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType type); + /** * Free all side data entries and their contents, then zeroes out the * values which the pointers are pointing to. @@ -1003,7 +1054,15 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type); */ void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd); +/** + * Remove existing entries before adding new ones. + */ #define AV_FRAME_SIDE_DATA_FLAG_UNIQUE (1 << 0) +/** + * Don't add a new entry if another of the same type exists. + * Applies only for side data types without the AV_SIDE_DATA_PROP_MULTI prop. + */ +#define AV_FRAME_SIDE_DATA_FLAG_REPLACE (1 << 1) /** * Add new side data entry to an array. @@ -1016,15 +1075,43 @@ void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd); * @param size size of the side data * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, or 0. * - * @return newly added side data on success, NULL on error. In case of - * AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of matching - * AVFrameSideDataType will be removed before the addition is - * attempted. + * @return newly added side data on success, NULL on error. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of + * matching AVFrameSideDataType will be removed before the addition + * is attempted. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_REPLACE being set, if an + * entry of the same type already exists, it will be replaced instead. */ AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd, enum AVFrameSideDataType type, size_t size, unsigned int flags); +/** + * Add a new side data entry to an array from an existing AVBufferRef. + * + * @param sd pointer to array of side data to which to add another entry, + * or to NULL in order to start a new array. + * @param nb_sd pointer to an integer containing the number of entries in + * the array. + * @param type type of the added side data + * @param buf Pointer to AVBufferRef to add to the array. On success, + * the function takes ownership of the AVBufferRef and *buf is + * set to NULL, unless AV_FRAME_SIDE_DATA_FLAG_NEW_REF is set + * in which case the ownership will remain with the caller. + * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, or 0. + * + * @return newly added side data on success, NULL on error. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of + * matching AVFrameSideDataType will be removed before the addition + * is attempted. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_REPLACE being set, if an + * entry of the same type already exists, it will be replaced instead. + * + */ +AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type, + AVBufferRef **buf, unsigned int flags); + /** * Add a new side data entry to an array based on existing side data, taking * a reference towards the contained AVBufferRef. @@ -1037,10 +1124,12 @@ AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd, * for the buffer. * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, or 0. * - * @return negative error code on failure, >=0 on success. In case of - * AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of matching - * AVFrameSideDataType will be removed before the addition is - * attempted. + * @return negative error code on failure, >=0 on success. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of + * matching AVFrameSideDataType will be removed before the addition + * is attempted. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_REPLACE being set, if an + * entry of the same type already exists, it will be replaced instead. */ int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd, const AVFrameSideData *src, unsigned int flags); @@ -1074,6 +1163,11 @@ const AVFrameSideData *av_frame_side_data_get(AVFrameSideData * const *sd, nb_sd, type); } +/** + * Remove and free all side data instances of the given type from an array. + */ +void av_frame_side_data_remove(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type); /** * @} */ diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c index 553428e67..9b3c5f389 100644 --- a/libavutil/hwcontext_d3d11va.c +++ b/libavutil/hwcontext_d3d11va.c @@ -36,6 +36,7 @@ #include "hwcontext_d3d11va.h" #include "hwcontext_internal.h" #include "imgutils.h" +#include "mem.h" #include "pixdesc.h" #include "pixfmt.h" #include "thread.h" diff --git a/libavutil/hwcontext_d3d12va.c b/libavutil/hwcontext_d3d12va.c index 353807359..6507cf69c 100644 --- a/libavutil/hwcontext_d3d12va.c +++ b/libavutil/hwcontext_d3d12va.c @@ -27,6 +27,7 @@ #include "hwcontext_d3d12va_internal.h" #include "hwcontext_d3d12va.h" #include "imgutils.h" +#include "mem.h" #include "pixdesc.h" #include "pixfmt.h" #include "thread.h" @@ -246,7 +247,7 @@ static AVBufferRef *d3d12va_pool_alloc(void *opaque, size_t size) .Format = hwctx->format, .SampleDesc = {.Count = 1, .Quality = 0 }, .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN, - .Flags = D3D12_RESOURCE_FLAG_NONE, + .Flags = hwctx->flags, }; frame = av_mallocz(sizeof(AVD3D12VAFrame)); diff --git a/libavutil/hwcontext_d3d12va.h b/libavutil/hwcontext_d3d12va.h index ff06e6f2e..212a6a614 100644 --- a/libavutil/hwcontext_d3d12va.h +++ b/libavutil/hwcontext_d3d12va.h @@ -129,6 +129,14 @@ typedef struct AVD3D12VAFramesContext { * If unset, will be automatically set. */ DXGI_FORMAT format; + + /** + * Options for working with resources. + * If unset, this will be D3D12_RESOURCE_FLAG_NONE. + * + * @see https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_resource_flags + */ + D3D12_RESOURCE_FLAGS flags; } AVD3D12VAFramesContext; #endif /* AVUTIL_HWCONTEXT_D3D12VA_H */ diff --git a/libavutil/hwcontext_drm.c b/libavutil/hwcontext_drm.c index 7a9fdbd26..0847db09a 100644 --- a/libavutil/hwcontext_drm.c +++ b/libavutil/hwcontext_drm.c @@ -38,6 +38,7 @@ #include "hwcontext_drm.h" #include "hwcontext_internal.h" #include "imgutils.h" +#include "mem.h" static void drm_device_free(AVHWDeviceContext *hwdev) diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c index 377bf6eb7..0b76966eb 100644 --- a/libavutil/hwcontext_dxva2.c +++ b/libavutil/hwcontext_dxva2.c @@ -31,6 +31,7 @@ #include "hwcontext_dxva2.h" #include "hwcontext_internal.h" #include "imgutils.h" +#include "mem.h" #include "pixdesc.h" #include "pixfmt.h" #include "compat/w32dlfcn.h" diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index ce71d0ff2..721c841c2 100644 --- a/libavutil/hwcontext_qsv.c +++ b/libavutil/hwcontext_qsv.c @@ -119,8 +119,15 @@ typedef struct QSVFramesContext { #endif AVFrame realigned_upload_frame; AVFrame realigned_download_frame; + + mfxFrameInfo frame_info; } QSVFramesContext; +typedef struct QSVSurface { + mfxFrameSurface1 mfx_surface; + AVFrame *child_frame; +} QSVSurface; + static const struct { enum AVPixelFormat pix_fmt; uint32_t fourcc; @@ -166,6 +173,8 @@ extern int ff_qsv_get_surface_base_handle(mfxFrameSurface1 *surf, enum AVHWDeviceType base_dev_type, void **base_handle); +static int qsv_init_surface(AVHWFramesContext *ctx, mfxFrameSurface1 *surf); + /** * Caller needs to allocate enough space for base_handle pointer. **/ @@ -374,7 +383,32 @@ static void qsv_pool_release_dummy(void *opaque, uint8_t *data) { } -static AVBufferRef *qsv_pool_alloc(void *opaque, size_t size) +static void qsv_pool_release(void *opaque, uint8_t *data) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; + QSVFramesContext *s = ctx->hwctx; + QSVSurface *qsv_surface = (QSVSurface *)data; + mfxHDLPair *hdl_pair = (mfxHDLPair *)qsv_surface->mfx_surface.Data.MemId; + AVHWFramesContext *child_frames_ctx; + + if (!s->child_frames_ref) + return; + + child_frames_ctx = (AVHWFramesContext*)s->child_frames_ref->data; + if (!child_frames_ctx->device_ctx) + return; + +#if CONFIG_VAAPI + if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_VAAPI) + av_freep(&hdl_pair->first); +#endif + + av_freep(&hdl_pair); + av_frame_free(&qsv_surface->child_frame); + av_freep(&qsv_surface); +} + +static AVBufferRef *qsv_fixed_pool_alloc(void *opaque, size_t size) { AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; QSVFramesContext *s = ctx->hwctx; @@ -389,6 +423,104 @@ static AVBufferRef *qsv_pool_alloc(void *opaque, size_t size) return NULL; } +static AVBufferRef *qsv_dynamic_pool_alloc(void *opaque, size_t size) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; + QSVFramesContext *s = ctx->hwctx; + AVHWFramesContext *child_frames_ctx; + QSVSurface *qsv_surface = NULL; + mfxHDLPair *handle_pairs_internal = NULL; + int ret; + + if (!s->child_frames_ref) + goto fail; + + child_frames_ctx = (AVHWFramesContext*)s->child_frames_ref->data; + if (!child_frames_ctx->device_ctx) + goto fail; + +#if CONFIG_DXVA2 + if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { + av_log(ctx, AV_LOG_ERROR, + "QSV on dxva2 requires a fixed frame pool size\n"); + goto fail; + } +#endif + + qsv_surface = av_calloc(1, sizeof(*qsv_surface)); + if (!qsv_surface) + goto fail; + + qsv_surface->child_frame = av_frame_alloc(); + if (!qsv_surface->child_frame) + goto fail; + + ret = av_hwframe_get_buffer(s->child_frames_ref, qsv_surface->child_frame, 0); + if (ret < 0) + goto fail; + + handle_pairs_internal = av_calloc(1, sizeof(*handle_pairs_internal)); + if (!handle_pairs_internal) + goto fail; + + ret = qsv_init_surface(ctx, &qsv_surface->mfx_surface); + if (ret < 0) + goto fail; + +#if CONFIG_VAAPI + if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_VAAPI) { + VASurfaceID *surface_id_internal; + + surface_id_internal = av_calloc(1, sizeof(*surface_id_internal)); + if (!surface_id_internal) + goto fail; + + *surface_id_internal = (VASurfaceID)(uintptr_t)qsv_surface->child_frame->data[3]; + handle_pairs_internal->first = (mfxHDL)surface_id_internal; + handle_pairs_internal->second = (mfxMemId)MFX_INFINITE; + } +#endif + +#if CONFIG_D3D11VA + if (child_frames_ctx->device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { + AVD3D11VAFramesContext *child_frames_hwctx = child_frames_ctx->hwctx; + handle_pairs_internal->first = (mfxMemId)qsv_surface->child_frame->data[0]; + + if (child_frames_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) + handle_pairs_internal->second = (mfxMemId)MFX_INFINITE; + else + handle_pairs_internal->second = (mfxMemId)qsv_surface->child_frame->data[1]; + + } +#endif + + qsv_surface->mfx_surface.Data.MemId = (mfxMemId)handle_pairs_internal; + return av_buffer_create((uint8_t *)qsv_surface, sizeof(*qsv_surface), + qsv_pool_release, ctx, 0); + +fail: + if (qsv_surface) { + av_frame_free(&qsv_surface->child_frame); + } + + av_freep(&qsv_surface); + av_freep(&handle_pairs_internal); + + return NULL; +} + +static AVBufferRef *qsv_pool_alloc(void *opaque, size_t size) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; + AVQSVFramesContext *hwctx = ctx->hwctx; + + if (hwctx->nb_surfaces == 0) { + return qsv_dynamic_pool_alloc(opaque, size); + } else { + return qsv_fixed_pool_alloc(opaque, size); + } +} + static int qsv_init_child_ctx(AVHWFramesContext *ctx) { QSVDeviceContext *device_priv = ctx->device_ctx->hwctx; @@ -577,9 +709,28 @@ static int qsv_init_pool(AVHWFramesContext *ctx, uint32_t fourcc) int i, ret = 0; - if (ctx->initial_pool_size <= 0) { - av_log(ctx, AV_LOG_ERROR, "QSV requires a fixed frame pool size\n"); + if (ctx->initial_pool_size < 0) { + av_log(ctx, AV_LOG_ERROR, "Invalid frame pool size\n"); return AVERROR(EINVAL); + } else if (ctx->initial_pool_size == 0) { + mfxFrameSurface1 mfx_surf1; + + ret = qsv_init_child_ctx(ctx); + if (ret < 0) + return ret; + + ffhwframesctx(ctx)->pool_internal = av_buffer_pool_init2(sizeof(mfxFrameSurface1), + ctx, qsv_pool_alloc, NULL); + if (!ffhwframesctx(ctx)->pool_internal) + return AVERROR(ENOMEM); + + memset(&mfx_surf1, 0, sizeof(mfx_surf1)); + qsv_init_surface(ctx, &mfx_surf1); + s->frame_info = mfx_surf1.Info; + frames_hwctx->info = &s->frame_info; + frames_hwctx->nb_surfaces = 0; + + return 0; } s->handle_pairs_internal = av_calloc(ctx->initial_pool_size, @@ -628,7 +779,7 @@ static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, QSVFramesContext *s = ctx->hwctx; AVQSVFramesContext *hwctx = &s->p; mfxFrameInfo *i = &req->Info; - mfxFrameInfo *i1 = &hwctx->surfaces[0].Info; + mfxFrameInfo *i1 = hwctx->nb_surfaces ? &hwctx->surfaces[0].Info : hwctx->info; if (!(req->Type & MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET) || !(req->Type & (MFX_MEMTYPE_FROM_VPPIN | MFX_MEMTYPE_FROM_VPPOUT)) || @@ -1223,7 +1374,7 @@ static int qsv_init_internal_session(AVHWFramesContext *ctx, MFX_IOPATTERN_OUT_SYSTEM_MEMORY; par.AsyncDepth = 1; - par.vpp.In = frames_hwctx->surfaces[0].Info; + par.vpp.In = frames_hwctx->nb_surfaces ? frames_hwctx->surfaces[0].Info : *frames_hwctx->info; /* Apparently VPP requires the frame rate to be set to some value, otherwise * init will fail (probably for the framerate conversion filter). Since we @@ -1398,8 +1549,11 @@ static int qsv_frames_derive_from(AVHWFramesContext *dst_ctx, dst_hwctx->texture_infos[i].texture = (ID3D11Texture2D*)pair->first; dst_hwctx->texture_infos[i].index = pair->second == (mfxMemId)MFX_INFINITE ? (intptr_t)0 : (intptr_t)pair->second; } - ID3D11Texture2D_GetDesc(dst_hwctx->texture_infos[0].texture, &texDesc); - dst_hwctx->BindFlags = texDesc.BindFlags; + if (src_hwctx->nb_surfaces) { + ID3D11Texture2D_GetDesc(dst_hwctx->texture_infos[0].texture, &texDesc); + dst_hwctx->BindFlags = texDesc.BindFlags; + } else + dst_hwctx->BindFlags = qsv_get_d3d11va_bind_flags(src_hwctx->frame_type); } break; #endif @@ -1838,19 +1992,53 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, return 0; } -static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx, - AVHWFramesContext *src_ctx, int flags) +static int qsv_dynamic_frames_derive_to(AVHWFramesContext *dst_ctx, + AVHWFramesContext *src_ctx, int flags) +{ + QSVFramesContext *s = dst_ctx->hwctx; + AVQSVFramesContext *dst_hwctx = &s->p; + mfxFrameSurface1 mfx_surf1; + + switch (src_ctx->device_ctx->type) { +#if CONFIG_VAAPI + case AV_HWDEVICE_TYPE_VAAPI: + dst_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + break; +#endif + +#if CONFIG_D3D11VA + case AV_HWDEVICE_TYPE_D3D11VA: + { + AVD3D11VAFramesContext *src_hwctx = src_ctx->hwctx; + + if (src_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) { + dst_hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET; + } else { + dst_hwctx->frame_type |= MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + } + } + break; +#endif + + default: + return AVERROR(ENOSYS); + } + + memset(&mfx_surf1, 0, sizeof(mfx_surf1)); + qsv_init_surface(dst_ctx, &mfx_surf1); + s->frame_info = mfx_surf1.Info; + dst_hwctx->info = &s->frame_info; + dst_hwctx->nb_surfaces = 0; + return 0; +} + +static int qsv_fixed_frames_derive_to(AVHWFramesContext *dst_ctx, + AVHWFramesContext *src_ctx, int flags) { QSVFramesContext *s = dst_ctx->hwctx; AVQSVFramesContext *dst_hwctx = &s->p; int i; - if (src_ctx->initial_pool_size == 0) { - av_log(dst_ctx, AV_LOG_ERROR, "Only fixed-size pools can be " - "mapped to QSV frames.\n"); - return AVERROR(EINVAL); - } - switch (src_ctx->device_ctx->type) { #if CONFIG_VAAPI case AV_HWDEVICE_TYPE_VAAPI: @@ -1941,8 +2129,21 @@ static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx, return 0; } -static int qsv_map_to(AVHWFramesContext *dst_ctx, - AVFrame *dst, const AVFrame *src, int flags) +static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx, + AVHWFramesContext *src_ctx, int flags) +{ + if (src_ctx->initial_pool_size < 0) { + av_log(dst_ctx, AV_LOG_ERROR, "Invalid src frame pool. \n"); + return AVERROR(EINVAL); + } else if (src_ctx->initial_pool_size == 0) { + return qsv_dynamic_frames_derive_to(dst_ctx, src_ctx, flags); + } else { + return qsv_fixed_frames_derive_to(dst_ctx, src_ctx, flags); + } +} + +static int qsv_fixed_pool_map_to(AVHWFramesContext *dst_ctx, + AVFrame *dst, const AVFrame *src, int flags) { AVQSVFramesContext *hwctx = dst_ctx->hwctx; int i, err, index = -1; @@ -2001,6 +2202,133 @@ static int qsv_map_to(AVHWFramesContext *dst_ctx, return 0; } +static void qsv_dynamic_pool_unmap(AVHWFramesContext *ctx, HWMapDescriptor *hwmap) +{ + mfxFrameSurface1 *surfaces_internal = (mfxFrameSurface1 *)hwmap->priv; + mfxHDLPair *handle_pairs_internal = (mfxHDLPair *)surfaces_internal->Data.MemId; + AVHWFramesContext *src_ctx = (AVHWFramesContext *)ffhwframesctx(ctx)->source_frames->data; + + switch (src_ctx->format) { +#if CONFIG_VAAPI + case AV_PIX_FMT_VAAPI: + { + av_freep(&handle_pairs_internal->first); + + break; + } +#endif + +#if CONFIG_D3D11VA + case AV_PIX_FMT_D3D11: + { + /* Do nothing */ + break; + } +#endif + default: + av_log(ctx, AV_LOG_ERROR, "Should not reach here. \n"); + break; + } + + av_freep(&handle_pairs_internal); + av_freep(&surfaces_internal); +} + +static int qsv_dynamic_pool_map_to(AVHWFramesContext *dst_ctx, + AVFrame *dst, const AVFrame *src, int flags) +{ + mfxFrameSurface1 *surfaces_internal = NULL; + mfxHDLPair *handle_pairs_internal = NULL; + int ret = 0; + + surfaces_internal = av_calloc(1, sizeof(*surfaces_internal)); + if (!surfaces_internal) { + ret = AVERROR(ENOMEM); + goto fail; + } + + handle_pairs_internal = av_calloc(1, sizeof(*handle_pairs_internal)); + if (!handle_pairs_internal) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = qsv_init_surface(dst_ctx, surfaces_internal); + if (ret < 0) + goto fail; + + switch (src->format) { +#if CONFIG_VAAPI + case AV_PIX_FMT_VAAPI: + { + VASurfaceID *surface_id_internal; + + surface_id_internal = av_calloc(1, sizeof(*surface_id_internal)); + if (!surface_id_internal) { + ret =AVERROR(ENOMEM); + goto fail; + } + + *surface_id_internal = (VASurfaceID)(uintptr_t)src->data[3]; + handle_pairs_internal->first = (mfxHDL)surface_id_internal; + handle_pairs_internal->second = (mfxMemId)MFX_INFINITE; + + break; + } +#endif + +#if CONFIG_D3D11VA + case AV_PIX_FMT_D3D11: + { + AVHWFramesContext *src_ctx = (AVHWFramesContext*)src->hw_frames_ctx->data; + AVD3D11VAFramesContext *src_hwctx = src_ctx->hwctx; + + handle_pairs_internal->first = (mfxMemId)src->data[0]; + + if (src_hwctx->BindFlags & D3D11_BIND_RENDER_TARGET) { + handle_pairs_internal->second = (mfxMemId)MFX_INFINITE; + } else { + handle_pairs_internal->second = (mfxMemId)src->data[1]; + } + + break; + } +#endif + default: + ret = AVERROR(ENOSYS); + goto fail; + } + + surfaces_internal->Data.MemId = (mfxMemId)handle_pairs_internal; + + ret = ff_hwframe_map_create(dst->hw_frames_ctx, + dst, src, qsv_dynamic_pool_unmap, surfaces_internal); + if (ret) + goto fail; + + dst->width = src->width; + dst->height = src->height; + dst->data[3] = (uint8_t*)surfaces_internal; + + return 0; + +fail: + av_freep(&handle_pairs_internal); + av_freep(&surfaces_internal); + return ret; +} + +static int qsv_map_to(AVHWFramesContext *dst_ctx, + AVFrame *dst, const AVFrame *src, int flags) +{ + AVQSVFramesContext *hwctx = dst_ctx->hwctx; + + if (hwctx->nb_surfaces) + return qsv_fixed_pool_map_to(dst_ctx, dst, src, flags); + else + return qsv_dynamic_pool_map_to(dst_ctx, dst, src, flags); +} + static int qsv_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints) @@ -2244,8 +2572,8 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device, // used on recent Intel hardware. Set options to the VAAPI device // creation so that we should pick a usable setup by default if // possible, even when multiple devices and drivers are available. - av_dict_set(&child_device_opts, "kernel_driver", "i915", 0); - av_dict_set(&child_device_opts, "driver", "iHD", 0); + av_dict_set(&child_device_opts, "vendor_id", "0x8086", 0); + av_dict_set(&child_device_opts, "driver", "iHD", 0); } break; #endif diff --git a/libavutil/hwcontext_qsv.h b/libavutil/hwcontext_qsv.h index e2dba8ad8..35530e4e9 100644 --- a/libavutil/hwcontext_qsv.h +++ b/libavutil/hwcontext_qsv.h @@ -25,8 +25,8 @@ * @file * An API-specific header for AV_HWDEVICE_TYPE_QSV. * - * This API does not support dynamic frame pools. AVHWFramesContext.pool must - * contain AVBufferRefs whose data pointer points to an mfxFrameSurface1 struct. + * AVHWFramesContext.pool must contain AVBufferRefs whose data pointer points + * to a mfxFrameSurface1 struct. */ /** @@ -51,13 +51,36 @@ typedef struct AVQSVDeviceContext { * This struct is allocated as AVHWFramesContext.hwctx */ typedef struct AVQSVFramesContext { + /** + * A pointer to a mfxFrameSurface1 struct + * + * It is available when nb_surfaces is non-zero. + */ mfxFrameSurface1 *surfaces; + + /** + * Number of frames in the pool + * + * It is 0 for dynamic frame pools or AVHWFramesContext.initial_pool_size + * for fixed frame pools. + * + * Note only oneVPL GPU runtime 2.9+ can support dynamic frame pools + * on d3d11va or vaapi + */ int nb_surfaces; /** * A combination of MFX_MEMTYPE_* describing the frame pool. */ int frame_type; + + /** + * A pointer to a mfxFrameInfo struct + * + * It is available when nb_surfaces is 0, all buffers allocated from the + * pool have the same mfxFrameInfo. + */ + mfxFrameInfo *info; } AVQSVFramesContext; #endif /* AVUTIL_HWCONTEXT_QSV_H */ diff --git a/libavutil/hwcontext_vaapi.c b/libavutil/hwcontext_vaapi.c index 95a68e62c..95aa38d9d 100644 --- a/libavutil/hwcontext_vaapi.c +++ b/libavutil/hwcontext_vaapi.c @@ -809,6 +809,9 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, VAStatus vas; void *address = NULL; int err, i; +#if VA_CHECK_VERSION(1, 21, 0) + uint32_t vaflags = 0; +#endif surface_id = (VASurfaceID)(uintptr_t)src->data[3]; av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id); @@ -892,7 +895,16 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, } } +#if VA_CHECK_VERSION(1, 21, 0) + if (flags & AV_HWFRAME_MAP_READ) + vaflags |= VA_MAPBUFFER_FLAG_READ; + if (flags & AV_HWFRAME_MAP_WRITE) + vaflags |= VA_MAPBUFFER_FLAG_WRITE; + // On drivers not implementing vaMapBuffer2 libva calls vaMapBuffer instead. + vas = vaMapBuffer2(hwctx->display, map->image.buf, &address, vaflags); +#else vas = vaMapBuffer(hwctx->display, map->image.buf, &address); +#endif if (vas != VA_STATUS_SUCCESS) { av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface " "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); @@ -1736,7 +1748,9 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, #if CONFIG_LIBDRM drmVersion *info; const AVDictionaryEntry *kernel_driver; + const AVDictionaryEntry *vendor_id; kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0); + vendor_id = av_dict_get(opts, "vendor_id", NULL, 0); #endif for (n = 0; n < max_devices; n++) { snprintf(path, sizeof(path), @@ -1791,6 +1805,33 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, close(priv->drm_fd); priv->drm_fd = -1; continue; + } else if (vendor_id) { + drmDevicePtr device; + char drm_vendor[8]; + if (drmGetDevice(priv->drm_fd, &device)) { + av_log(ctx, AV_LOG_VERBOSE, + "Failed to get DRM device info for device %d.\n", n); + close(priv->drm_fd); + priv->drm_fd = -1; + continue; + } + + snprintf(drm_vendor, sizeof(drm_vendor), "0x%x", device->deviceinfo.pci->vendor_id); + if (strcmp(vendor_id->value, drm_vendor)) { + av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d " + "with non-matching vendor id (%s).\n", + n, vendor_id->value); + drmFreeDevice(&device); + close(priv->drm_fd); + priv->drm_fd = -1; + continue; + } + av_log(ctx, AV_LOG_VERBOSE, "Trying to use " + "DRM render node for device %d, " + "with matching vendor id (%s).\n", + n, vendor_id->value); + drmFreeDevice(&device); + break; } drmFreeVersion(info); #endif diff --git a/libavutil/hwcontext_videotoolbox.c b/libavutil/hwcontext_videotoolbox.c index 9f82b104c..122a61d5e 100644 --- a/libavutil/hwcontext_videotoolbox.c +++ b/libavutil/hwcontext_videotoolbox.c @@ -342,8 +342,10 @@ static int vt_pixbuf_set_par(void *log_ctx, CFNumberRef num = NULL, den = NULL; AVRational avpar = src->sample_aspect_ratio; - if (avpar.num == 0) + if (avpar.num == 0) { + CVBufferRemoveAttachment(pixbuf, kCVImageBufferPixelAspectRatioKey); return 0; + } av_reduce(&avpar.num, &avpar.den, avpar.num, avpar.den, @@ -423,7 +425,10 @@ static int vt_pixbuf_set_chromaloc(void *log_ctx, kCVImageBufferChromaLocationTopFieldKey, loc, kCVAttachmentMode_ShouldPropagate); - } + } else + CVBufferRemoveAttachment( + pixbuf, + kCVImageBufferChromaLocationTopFieldKey); return 0; } @@ -527,59 +532,116 @@ CFStringRef av_map_videotoolbox_color_trc_from_av(enum AVColorTransferCharacteri } } +/** + * Copy all attachments for the specified mode from the given buffer. + */ +static CFDictionaryRef vt_cv_buffer_copy_attachments(CVBufferRef buffer, + CVAttachmentMode attachment_mode) +{ + CFDictionaryRef dict; + + // Check that our SDK is at least macOS 12 / iOS 15 / tvOS 15 + #if (TARGET_OS_OSX && defined(__MAC_12_0) && __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_12_0) || \ + (TARGET_OS_IOS && defined(__IPHONE_15_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_0) || \ + (TARGET_OS_TV && defined(__TVOS_15_0) && __TV_OS_VERSION_MAX_ALLOWED >= __TVOS_15_0) + // On recent enough versions, just use the respective API + if (__builtin_available(macOS 12.0, iOS 15.0, tvOS 15.0, *)) + return CVBufferCopyAttachments(buffer, attachment_mode); + #endif + + // Check that the target is lower than macOS 12 / iOS 15 / tvOS 15 + // else this would generate a deprecation warning and anyway never run because + // the runtime availability check above would be always true. + #if (TARGET_OS_OSX && (!defined(__MAC_12_0) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_12_0)) || \ + (TARGET_OS_IOS && (!defined(__IPHONE_15_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_15_0)) || \ + (TARGET_OS_TV && (!defined(__TVOS_15_0) || __TV_OS_VERSION_MIN_REQUIRED < __TVOS_15_0)) + // Fallback on SDKs or runtime versions < macOS 12 / iOS 15 / tvOS 15 + dict = CVBufferGetAttachments(buffer, attachment_mode); + return (dict) ? CFDictionaryCreateCopy(NULL, dict) : NULL; + #else + return NULL; // Impossible, just make the compiler happy + #endif +} + static int vt_pixbuf_set_colorspace(void *log_ctx, CVPixelBufferRef pixbuf, const AVFrame *src) { + CGColorSpaceRef colorspace = NULL; CFStringRef colormatrix = NULL, colorpri = NULL, colortrc = NULL; Float32 gamma = 0; colormatrix = av_map_videotoolbox_color_matrix_from_av(src->colorspace); - if (!colormatrix && src->colorspace != AVCOL_SPC_UNSPECIFIED) - av_log(log_ctx, AV_LOG_WARNING, "Color space %s is not supported.\n", av_color_space_name(src->colorspace)); + if (colormatrix) + CVBufferSetAttachment(pixbuf, kCVImageBufferYCbCrMatrixKey, + colormatrix, kCVAttachmentMode_ShouldPropagate); + else { + CVBufferRemoveAttachment(pixbuf, kCVImageBufferYCbCrMatrixKey); + if (src->colorspace != AVCOL_SPC_UNSPECIFIED && src->colorspace != AVCOL_SPC_RGB) + av_log(log_ctx, AV_LOG_WARNING, + "Color space %s is not supported.\n", + av_color_space_name(src->colorspace)); + } colorpri = av_map_videotoolbox_color_primaries_from_av(src->color_primaries); - if (!colorpri && src->color_primaries != AVCOL_PRI_UNSPECIFIED) - av_log(log_ctx, AV_LOG_WARNING, "Color primaries %s is not supported.\n", av_color_primaries_name(src->color_primaries)); + if (colorpri) + CVBufferSetAttachment(pixbuf, kCVImageBufferColorPrimariesKey, + colorpri, kCVAttachmentMode_ShouldPropagate); + else { + CVBufferRemoveAttachment(pixbuf, kCVImageBufferColorPrimariesKey); + if (src->color_primaries != AVCOL_SPC_UNSPECIFIED) + av_log(log_ctx, AV_LOG_WARNING, + "Color primaries %s is not supported.\n", + av_color_primaries_name(src->color_primaries)); + } colortrc = av_map_videotoolbox_color_trc_from_av(src->color_trc); - if (!colortrc && src->color_trc != AVCOL_TRC_UNSPECIFIED) - av_log(log_ctx, AV_LOG_WARNING, "Color transfer function %s is not supported.\n", av_color_transfer_name(src->color_trc)); + if (colortrc) + CVBufferSetAttachment(pixbuf, kCVImageBufferTransferFunctionKey, + colortrc, kCVAttachmentMode_ShouldPropagate); + else { + CVBufferRemoveAttachment(pixbuf, kCVImageBufferTransferFunctionKey); + if (src->color_trc != AVCOL_TRC_UNSPECIFIED) + av_log(log_ctx, AV_LOG_WARNING, + "Color transfer function %s is not supported.\n", + av_color_transfer_name(src->color_trc)); + } if (src->color_trc == AVCOL_TRC_GAMMA22) gamma = 2.2; else if (src->color_trc == AVCOL_TRC_GAMMA28) gamma = 2.8; - if (colormatrix) { - CVBufferSetAttachment( - pixbuf, - kCVImageBufferYCbCrMatrixKey, - colormatrix, - kCVAttachmentMode_ShouldPropagate); - } - if (colorpri) { - CVBufferSetAttachment( - pixbuf, - kCVImageBufferColorPrimariesKey, - colorpri, - kCVAttachmentMode_ShouldPropagate); - } - if (colortrc) { - CVBufferSetAttachment( - pixbuf, - kCVImageBufferTransferFunctionKey, - colortrc, - kCVAttachmentMode_ShouldPropagate); - } if (gamma != 0) { CFNumberRef gamma_level = CFNumberCreate(NULL, kCFNumberFloat32Type, &gamma); - CVBufferSetAttachment( - pixbuf, - kCVImageBufferGammaLevelKey, - gamma_level, - kCVAttachmentMode_ShouldPropagate); + CVBufferSetAttachment(pixbuf, kCVImageBufferGammaLevelKey, + gamma_level, kCVAttachmentMode_ShouldPropagate); CFRelease(gamma_level); + } else + CVBufferRemoveAttachment(pixbuf, kCVImageBufferGammaLevelKey); + +#if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MAX_ALLOWED >= 100800) || \ + (TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000) + if (__builtin_available(macOS 10.8, iOS 10, *)) { + CFDictionaryRef attachments = + vt_cv_buffer_copy_attachments(pixbuf, kCVAttachmentMode_ShouldPropagate); + + if (attachments) { + colorspace = + CVImageBufferCreateColorSpaceFromAttachments(attachments); + CFRelease(attachments); + } } +#endif + + // Done outside the above preprocessor code and if's so that + // in any case a wrong kCVImageBufferCGColorSpaceKey is removed + // if the above code is not used or fails. + if (colorspace) { + CVBufferSetAttachment(pixbuf, kCVImageBufferCGColorSpaceKey, + colorspace, kCVAttachmentMode_ShouldPropagate); + CFRelease(colorspace); + } else + CVBufferRemoveAttachment(pixbuf, kCVImageBufferCGColorSpaceKey); return 0; } diff --git a/libavutil/hwcontext_videotoolbox.h b/libavutil/hwcontext_videotoolbox.h index 600e9f2c8..d35cfbb6c 100644 --- a/libavutil/hwcontext_videotoolbox.h +++ b/libavutil/hwcontext_videotoolbox.h @@ -90,8 +90,15 @@ CFStringRef av_map_videotoolbox_color_primaries_from_av(enum AVColorPrimaries pr CFStringRef av_map_videotoolbox_color_trc_from_av(enum AVColorTransferCharacteristic trc); /** - * Update a CVPixelBufferRef's metadata to based on an AVFrame. - * Returns 0 if no known equivalent was found. + * Set CVPixelBufferRef's metadata based on an AVFrame. + * + * Sets/unsets the CVPixelBuffer attachments to match as closely as possible the + * AVFrame metadata. To prevent inconsistent attachments, the attachments for properties + * that could not be matched or are unspecified in the given AVFrame are unset. So if + * any attachments already covered by AVFrame metadata need to be set to a specific + * value, this should happen after calling this function. + * + * Returns < 0 in case of an error. */ int av_vt_pixbuf_set_attachments(void *log_ctx, CVPixelBufferRef pixbuf, const struct AVFrame *src); diff --git a/libavutil/hwcontext_vulkan.c b/libavutil/hwcontext_vulkan.c index 6e3b96b73..6317ab7d0 100644 --- a/libavutil/hwcontext_vulkan.c +++ b/libavutil/hwcontext_vulkan.c @@ -37,9 +37,9 @@ #include "avstring.h" #include "imgutils.h" #include "hwcontext.h" -#include "avassert.h" #include "hwcontext_internal.h" #include "hwcontext_vulkan.h" +#include "mem.h" #include "vulkan.h" #include "vulkan_loader.h" @@ -61,25 +61,17 @@ #include "hwcontext_drm.h" #endif +#if HAVE_LINUX_DMA_BUF_H +#include +#include +#endif + #if CONFIG_CUDA #include "hwcontext_cuda_internal.h" #include "cuda_check.h" #define CHECK_CU(x) FF_CUDA_CHECK_DL(cuda_cu, cu, x) #endif -typedef struct VulkanQueueCtx { - VkFence fence; - VkQueue queue; - int was_synchronous; - int qf; - int qidx; - - /* Buffer dependencies */ - AVBufferRef **buf_deps; - int nb_buf_deps; - unsigned int buf_deps_alloc_size; -} VulkanQueueCtx; - typedef struct VulkanDevicePriv { /** * The public AVVulkanDeviceContext. See hwcontext_vulkan.h for it. @@ -105,6 +97,9 @@ typedef struct VulkanDevicePriv { VkPhysicalDeviceDescriptorBufferFeaturesEXT desc_buf_features; VkPhysicalDeviceShaderAtomicFloatFeaturesEXT atomic_float_features; VkPhysicalDeviceCooperativeMatrixFeaturesKHR coop_matrix_features; + VkPhysicalDeviceOpticalFlowFeaturesNV optical_flow_features; + VkPhysicalDeviceShaderObjectFeaturesEXT shader_object_features; + VkPhysicalDeviceVideoMaintenance1FeaturesKHR video_maint_1_features; /* Queues */ pthread_mutex_t **qf_mutex; @@ -141,6 +136,9 @@ typedef struct VulkanFramesPriv { FFVkExecPool upload_exec; FFVkExecPool download_exec; + /* Temporary buffer pools */ + AVBufferPool *tmp; + /* Modifier info list to free at uninit */ VkImageDrmFormatModifierListCreateInfoEXT *modifier_info; } VulkanFramesPriv; @@ -193,6 +191,7 @@ static const struct FFVkFormatEntry { { VK_FORMAT_B8G8R8A8_UNORM, AV_PIX_FMT_BGR0, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_B8G8R8A8_UNORM } }, { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_RGB0, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_R8G8B8A8_UNORM } }, { VK_FORMAT_A2R10G10B10_UNORM_PACK32, AV_PIX_FMT_X2RGB10, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_A2R10G10B10_UNORM_PACK32 } }, + { VK_FORMAT_A2B10G10R10_UNORM_PACK32, AV_PIX_FMT_X2BGR10, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, 1, { VK_FORMAT_A2B10G10R10_UNORM_PACK32 } }, /* Planar RGB */ { VK_FORMAT_R8_UNORM, AV_PIX_FMT_GBRAP, VK_IMAGE_ASPECT_COLOR_BIT, 1, 4, 4, { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UNORM } }, @@ -423,12 +422,14 @@ static const VulkanOptExtension optional_instance_exts[] = { static const VulkanOptExtension optional_device_exts[] = { /* Misc or required by other extensions */ { VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, FF_VK_EXT_NO_FLAG }, - { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, FF_VK_EXT_NO_FLAG }, - { VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, FF_VK_EXT_NO_FLAG }, + { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, FF_VK_EXT_PUSH_DESCRIPTOR }, { VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, FF_VK_EXT_DESCRIPTOR_BUFFER, }, { VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME, FF_VK_EXT_DEVICE_DRM }, { VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME, FF_VK_EXT_ATOMIC_FLOAT }, { VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, FF_VK_EXT_COOP_MATRIX }, + { VK_NV_OPTICAL_FLOW_EXTENSION_NAME, FF_VK_EXT_OPTICAL_FLOW }, + { VK_EXT_SHADER_OBJECT_EXTENSION_NAME, FF_VK_EXT_SHADER_OBJECT }, + { VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME, FF_VK_EXT_VIDEO_MAINTENANCE_1 }, /* Imports/exports */ { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_MEMORY }, @@ -443,8 +444,11 @@ static const VulkanOptExtension optional_device_exts[] = { /* Video encoding/decoding */ { VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_QUEUE }, + { VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_QUEUE }, { VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_QUEUE }, + { VK_KHR_VIDEO_ENCODE_H264_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_H264 }, { VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H264 }, + { VK_KHR_VIDEO_ENCODE_H265_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_H265 }, { VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H265 }, { VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_AV1 }, }; @@ -457,6 +461,17 @@ static VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEX int l; AVHWDeviceContext *ctx = priv; + /* Ignore false positives */ + switch (data->messageIdNumber) { + case 0x086974c1: /* BestPractices-vkCreateCommandPool-command-buffer-reset */ + case 0xfd92477a: /* BestPractices-vkAllocateMemory-small-allocation */ + case 0x618ab1e7: /* VUID-VkImageViewCreateInfo-usage-02275 */ + case 0x30f4ac70: /* VUID-VkImageCreateInfo-pNext-06811 */ + return VK_FALSE; + default: + break; + } + switch (severity) { case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: l = AV_LOG_VERBOSE; break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: l = AV_LOG_INFO; break; @@ -469,7 +484,7 @@ static VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEX for (int i = 0; i < data->cmdBufLabelCount; i++) av_log(ctx, l, "\t%i: %s\n", i, data->pCmdBufLabels[i].pLabelName); - return 0; + return VK_FALSE; } #define ADD_VAL_TO_LIST(list, count, val) \ @@ -493,8 +508,19 @@ static VkBool32 VKAPI_CALL vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEX av_free((void *)props); \ } +enum FFVulkanDebugMode { + FF_VULKAN_DEBUG_NONE = 0, + /* Standard GPU-assisted validation */ + FF_VULKAN_DEBUG_VALIDATE = 1, + /* Passes printfs in shaders to the debug callback */ + FF_VULKAN_DEBUG_PRINTF = 2, + /* Enables extra printouts */ + FF_VULKAN_DEBUG_PRACTICES = 3, +}; + static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, - const char * const **dst, uint32_t *num, int debug) + const char * const **dst, uint32_t *num, + enum FFVulkanDebugMode debug_mode) { const char *tstr; const char **extension_names = NULL; @@ -552,6 +578,12 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, for (int i = 0; i < optional_exts_num; i++) { tstr = optional_exts[i].name; found = 0; + + if (dev && debug_mode && + !strcmp(tstr, VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME)) { + continue; + } + for (int j = 0; j < sup_ext_count; j++) { if (!strcmp(tstr, sup_ext[j].extensionName)) { found = 1; @@ -566,7 +598,10 @@ static int check_extensions(AVHWDeviceContext *ctx, int dev, AVDictionary *opts, ADD_VAL_TO_LIST(extension_names, extensions_found, tstr); } - if (debug && !dev) { + if (!dev && + ((debug_mode == FF_VULKAN_DEBUG_VALIDATE) || + (debug_mode == FF_VULKAN_DEBUG_PRINTF) || + (debug_mode == FF_VULKAN_DEBUG_PRACTICES))) { tstr = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; found = 0; for (int j = 0; j < sup_ext_count; j++) { @@ -622,20 +657,21 @@ fail: return err; } -static int check_validation_layers(AVHWDeviceContext *ctx, AVDictionary *opts, - const char * const **dst, uint32_t *num, - int *debug_mode) +static int check_layers(AVHWDeviceContext *ctx, AVDictionary *opts, + const char * const **dst, uint32_t *num, + enum FFVulkanDebugMode *debug_mode) { - static const char default_layer[] = { "VK_LAYER_KHRONOS_validation" }; - - int found = 0, err = 0; + int err = 0; VulkanDevicePriv *priv = ctx->hwctx; FFVulkanFunctions *vk = &priv->vkctx.vkfn; + static const char layer_standard_validation[] = { "VK_LAYER_KHRONOS_validation" }; + int layer_standard_validation_found = 0; + uint32_t sup_layer_count; VkLayerProperties *sup_layers; - AVDictionaryEntry *user_layers; + AVDictionaryEntry *user_layers = av_dict_get(opts, "layers", NULL, 0); char *user_layers_str = NULL; char *save, *token; @@ -643,98 +679,135 @@ static int check_validation_layers(AVHWDeviceContext *ctx, AVDictionary *opts, uint32_t enabled_layers_count = 0; AVDictionaryEntry *debug_opt = av_dict_get(opts, "debug", NULL, 0); - int debug = debug_opt && strtol(debug_opt->value, NULL, 10); + enum FFVulkanDebugMode mode; - /* If `debug=0`, enable no layers at all. */ - if (debug_opt && !debug) - return 0; + *debug_mode = mode = FF_VULKAN_DEBUG_NONE; + /* Get a list of all layers */ vk->EnumerateInstanceLayerProperties(&sup_layer_count, NULL); sup_layers = av_malloc_array(sup_layer_count, sizeof(VkLayerProperties)); if (!sup_layers) return AVERROR(ENOMEM); vk->EnumerateInstanceLayerProperties(&sup_layer_count, sup_layers); - av_log(ctx, AV_LOG_VERBOSE, "Supported validation layers:\n"); + av_log(ctx, AV_LOG_VERBOSE, "Supported layers:\n"); for (int i = 0; i < sup_layer_count; i++) av_log(ctx, AV_LOG_VERBOSE, "\t%s\n", sup_layers[i].layerName); - /* If `debug=1` is specified, enable the standard validation layer extension */ - if (debug) { - *debug_mode = debug; - for (int i = 0; i < sup_layer_count; i++) { - if (!strcmp(default_layer, sup_layers[i].layerName)) { - found = 1; - av_log(ctx, AV_LOG_VERBOSE, "Default validation layer %s is enabled\n", - default_layer); - ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, default_layer); - break; - } - } - } - - user_layers = av_dict_get(opts, "validation_layers", NULL, 0); - if (!user_layers) + /* If no user layers or debug layers are given, return */ + if (!debug_opt && !user_layers) goto end; - user_layers_str = av_strdup(user_layers->value); - if (!user_layers_str) { - err = AVERROR(ENOMEM); - goto fail; + /* Check for any properly supported validation layer */ + if (debug_opt) { + if (!strcmp(debug_opt->value, "printf")) { + mode = FF_VULKAN_DEBUG_PRINTF; + } else if (!strcmp(debug_opt->value, "validate")) { + mode = FF_VULKAN_DEBUG_VALIDATE; + } else if (!strcmp(debug_opt->value, "practices")) { + mode = FF_VULKAN_DEBUG_PRACTICES; + } else { + char *end_ptr = NULL; + int idx = strtol(debug_opt->value, &end_ptr, 10); + if (end_ptr == debug_opt->value || end_ptr[0] != '\0' || + idx < 0 || idx > FF_VULKAN_DEBUG_PRACTICES) { + av_log(ctx, AV_LOG_ERROR, "Invalid debugging mode \"%s\"\n", + debug_opt->value); + err = AVERROR(EINVAL); + goto end; + } + mode = idx; + } } - token = av_strtok(user_layers_str, "+", &save); - while (token) { - found = 0; - if (!strcmp(default_layer, token)) { - if (debug) { - /* if the `debug=1`, default_layer is enabled, skip here */ - token = av_strtok(NULL, "+", &save); - continue; - } else { - /* if the `debug=0`, enable debug mode to load its callback properly */ - *debug_mode = debug; - } - } - for (int j = 0; j < sup_layer_count; j++) { - if (!strcmp(token, sup_layers[j].layerName)) { - found = 1; + /* If mode is VALIDATE or PRINTF, try to find the standard validation layer extension */ + if ((mode == FF_VULKAN_DEBUG_VALIDATE) || + (mode == FF_VULKAN_DEBUG_PRINTF) || + (mode == FF_VULKAN_DEBUG_PRACTICES)) { + for (int i = 0; i < sup_layer_count; i++) { + if (!strcmp(layer_standard_validation, sup_layers[i].layerName)) { + av_log(ctx, AV_LOG_VERBOSE, "Standard validation layer %s is enabled\n", + layer_standard_validation); + ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, layer_standard_validation); + *debug_mode = mode; + layer_standard_validation_found = 1; break; } } - if (found) { - av_log(ctx, AV_LOG_VERBOSE, "Requested Validation Layer: %s\n", token); - ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, token); - } else { + if (!layer_standard_validation_found) { av_log(ctx, AV_LOG_ERROR, - "Validation Layer \"%s\" not support.\n", token); - err = AVERROR(EINVAL); - goto fail; + "Validation Layer \"%s\" not supported\n", layer_standard_validation); + err = AVERROR(ENOTSUP); + goto end; } - token = av_strtok(NULL, "+", &save); } - av_free(user_layers_str); + /* Process any custom layers enabled */ + if (user_layers) { + int found; -end: - av_free(sup_layers); + user_layers_str = av_strdup(user_layers->value); + if (!user_layers_str) { + err = AVERROR(ENOMEM); + goto fail; + } - *dst = enabled_layers; - *num = enabled_layers_count; + token = av_strtok(user_layers_str, "+", &save); + while (token) { + found = 0; - return 0; + /* If debug=1/2 was specified as an option, skip this layer */ + if (!strcmp(layer_standard_validation, token) && layer_standard_validation_found) { + token = av_strtok(NULL, "+", &save); + break; + } + + /* Try to find the layer in the list of supported layers */ + for (int j = 0; j < sup_layer_count; j++) { + if (!strcmp(token, sup_layers[j].layerName)) { + found = 1; + break; + } + } + + if (found) { + av_log(ctx, AV_LOG_VERBOSE, "Using layer: %s\n", token); + ADD_VAL_TO_LIST(enabled_layers, enabled_layers_count, token); + + /* If debug was not set as an option, force it */ + if (!strcmp(layer_standard_validation, token)) + *debug_mode = FF_VULKAN_DEBUG_VALIDATE; + } else { + av_log(ctx, AV_LOG_ERROR, + "Layer \"%s\" not supported\n", token); + err = AVERROR(EINVAL); + goto end; + } + + token = av_strtok(NULL, "+", &save); + } + } fail: - RELEASE_PROPS(enabled_layers, enabled_layers_count); +end: av_free(sup_layers); av_free(user_layers_str); + + if (err < 0) { + RELEASE_PROPS(enabled_layers, enabled_layers_count); + } else { + *dst = enabled_layers; + *num = enabled_layers_count; + } + return err; } /* Creates a VkInstance */ -static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts) +static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts, + enum FFVulkanDebugMode *debug_mode) { - int err = 0, debug_mode = 0; + int err = 0; VkResult ret; VulkanDevicePriv *p = ctx->hwctx; AVVulkanDeviceContext *hwctx = &p->p; @@ -771,27 +844,45 @@ static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts) return err; } - err = check_validation_layers(ctx, opts, &inst_props.ppEnabledLayerNames, - &inst_props.enabledLayerCount, &debug_mode); + err = check_layers(ctx, opts, &inst_props.ppEnabledLayerNames, + &inst_props.enabledLayerCount, debug_mode); if (err) goto fail; /* Check for present/missing extensions */ err = check_extensions(ctx, 0, opts, &inst_props.ppEnabledExtensionNames, - &inst_props.enabledExtensionCount, debug_mode); + &inst_props.enabledExtensionCount, *debug_mode); hwctx->enabled_inst_extensions = inst_props.ppEnabledExtensionNames; hwctx->nb_enabled_inst_extensions = inst_props.enabledExtensionCount; if (err < 0) goto fail; - if (debug_mode) { - VkValidationFeatureEnableEXT feat_list[] = { - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + /* Enable debug features if needed */ + if (*debug_mode == FF_VULKAN_DEBUG_VALIDATE) { + static const VkValidationFeatureEnableEXT feat_list_validate[] = { VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, }; - validation_features.pEnabledValidationFeatures = feat_list; - validation_features.enabledValidationFeatureCount = FF_ARRAY_ELEMS(feat_list); + validation_features.pEnabledValidationFeatures = feat_list_validate; + validation_features.enabledValidationFeatureCount = FF_ARRAY_ELEMS(feat_list_validate); + inst_props.pNext = &validation_features; + } else if (*debug_mode == FF_VULKAN_DEBUG_PRINTF) { + static const VkValidationFeatureEnableEXT feat_list_debug[] = { + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT, + VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, + VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT, + }; + validation_features.pEnabledValidationFeatures = feat_list_debug; + validation_features.enabledValidationFeatureCount = FF_ARRAY_ELEMS(feat_list_debug); + inst_props.pNext = &validation_features; + } else if (*debug_mode == FF_VULKAN_DEBUG_PRACTICES) { + static const VkValidationFeatureEnableEXT feat_list_practices[] = { + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT, + VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT, + }; + validation_features.pEnabledValidationFeatures = feat_list_practices; + validation_features.enabledValidationFeatureCount = FF_ARRAY_ELEMS(feat_list_practices); inst_props.pNext = &validation_features; } @@ -822,7 +913,10 @@ static int create_instance(AVHWDeviceContext *ctx, AVDictionary *opts) goto fail; } - if (debug_mode) { + /* Setup debugging callback if needed */ + if ((*debug_mode == FF_VULKAN_DEBUG_VALIDATE) || + (*debug_mode == FF_VULKAN_DEBUG_PRINTF) || + (*debug_mode == FF_VULKAN_DEBUG_PRACTICES)) { VkDebugUtilsMessengerCreateInfoEXT dbg = { .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | @@ -1028,16 +1122,22 @@ end: } /* Picks the least used qf with the fewest unneeded flags, or -1 if none found */ -static inline int pick_queue_family(VkQueueFamilyProperties *qf, uint32_t num_qf, +static inline int pick_queue_family(VkQueueFamilyProperties2 *qf, uint32_t num_qf, VkQueueFlagBits flags) { int index = -1; uint32_t min_score = UINT32_MAX; for (int i = 0; i < num_qf; i++) { - const VkQueueFlagBits qflags = qf[i].queueFlags; + VkQueueFlagBits qflags = qf[i].queueFamilyProperties.queueFlags; + + /* Per the spec, reporting transfer caps is optional for these 2 types */ + if ((flags & VK_QUEUE_TRANSFER_BIT) && + (qflags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT))) + qflags |= VK_QUEUE_TRANSFER_BIT; + if (qflags & flags) { - uint32_t score = av_popcount(qflags) + qf[i].timestampValidBits; + uint32_t score = av_popcount(qflags) + qf[i].queueFamilyProperties.timestampValidBits; if (score < min_score) { index = i; min_score = score; @@ -1046,7 +1146,36 @@ static inline int pick_queue_family(VkQueueFamilyProperties *qf, uint32_t num_qf } if (index > -1) - qf[index].timestampValidBits++; + qf[index].queueFamilyProperties.timestampValidBits++; + + return index; +} + +static inline int pick_video_queue_family(VkQueueFamilyProperties2 *qf, + VkQueueFamilyVideoPropertiesKHR *qf_vid, uint32_t num_qf, + VkVideoCodecOperationFlagBitsKHR flags) +{ + int index = -1; + uint32_t min_score = UINT32_MAX; + + for (int i = 0; i < num_qf; i++) { + const VkQueueFlagBits qflags = qf[i].queueFamilyProperties.queueFlags; + const VkQueueFlagBits vflags = qf_vid[i].videoCodecOperations; + + if (!(qflags & (VK_QUEUE_VIDEO_ENCODE_BIT_KHR | VK_QUEUE_VIDEO_DECODE_BIT_KHR))) + continue; + + if (vflags & flags) { + uint32_t score = av_popcount(vflags) + qf[i].queueFamilyProperties.timestampValidBits; + if (score < min_score) { + index = i; + min_score = score; + } + } + } + + if (index > -1) + qf[index].queueFamilyProperties.timestampValidBits++; return index; } @@ -1054,12 +1183,12 @@ static inline int pick_queue_family(VkQueueFamilyProperties *qf, uint32_t num_qf static int setup_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd) { uint32_t num; - float *weights; - VkQueueFamilyProperties *qf = NULL; VulkanDevicePriv *p = ctx->hwctx; AVVulkanDeviceContext *hwctx = &p->p; FFVulkanFunctions *vk = &p->vkctx.vkfn; - int graph_index, comp_index, tx_index, enc_index, dec_index; + + VkQueueFamilyProperties2 *qf = NULL; + VkQueueFamilyVideoPropertiesKHR *qf_vid = NULL; /* First get the number of queue families */ vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, NULL); @@ -1069,118 +1198,161 @@ static int setup_queue_families(AVHWDeviceContext *ctx, VkDeviceCreateInfo *cd) } /* Then allocate memory */ - qf = av_malloc_array(num, sizeof(VkQueueFamilyProperties)); + qf = av_malloc_array(num, sizeof(VkQueueFamilyProperties2)); if (!qf) return AVERROR(ENOMEM); + qf_vid = av_malloc_array(num, sizeof(VkQueueFamilyVideoPropertiesKHR)); + if (!qf_vid) + return AVERROR(ENOMEM); + + for (uint32_t i = 0; i < num; i++) { + qf_vid[i] = (VkQueueFamilyVideoPropertiesKHR) { + .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR, + }; + qf[i] = (VkQueueFamilyProperties2) { + .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, + .pNext = &qf_vid[i], + }; + } + /* Finally retrieve the queue families */ - vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &num, qf); + vk->GetPhysicalDeviceQueueFamilyProperties2(hwctx->phys_dev, &num, qf); av_log(ctx, AV_LOG_VERBOSE, "Queue families:\n"); for (int i = 0; i < num; i++) { - av_log(ctx, AV_LOG_VERBOSE, " %i:%s%s%s%s%s%s%s (queues: %i)\n", i, - ((qf[i].queueFlags) & VK_QUEUE_GRAPHICS_BIT) ? " graphics" : "", - ((qf[i].queueFlags) & VK_QUEUE_COMPUTE_BIT) ? " compute" : "", - ((qf[i].queueFlags) & VK_QUEUE_TRANSFER_BIT) ? " transfer" : "", - ((qf[i].queueFlags) & VK_QUEUE_VIDEO_ENCODE_BIT_KHR) ? " encode" : "", - ((qf[i].queueFlags) & VK_QUEUE_VIDEO_DECODE_BIT_KHR) ? " decode" : "", - ((qf[i].queueFlags) & VK_QUEUE_SPARSE_BINDING_BIT) ? " sparse" : "", - ((qf[i].queueFlags) & VK_QUEUE_PROTECTED_BIT) ? " protected" : "", - qf[i].queueCount); + av_log(ctx, AV_LOG_VERBOSE, " %i:%s%s%s%s%s%s%s%s (queues: %i)\n", i, + ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_GRAPHICS_BIT) ? " graphics" : "", + ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_COMPUTE_BIT) ? " compute" : "", + ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_TRANSFER_BIT) ? " transfer" : "", + ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_VIDEO_ENCODE_BIT_KHR) ? " encode" : "", + ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_VIDEO_DECODE_BIT_KHR) ? " decode" : "", + ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_SPARSE_BINDING_BIT) ? " sparse" : "", + ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_OPTICAL_FLOW_BIT_NV) ? " optical_flow" : "", + ((qf[i].queueFamilyProperties.queueFlags) & VK_QUEUE_PROTECTED_BIT) ? " protected" : "", + qf[i].queueFamilyProperties.queueCount); /* We use this field to keep a score of how many times we've used that * queue family in order to make better choices. */ - qf[i].timestampValidBits = 0; + qf[i].queueFamilyProperties.timestampValidBits = 0; } + hwctx->nb_qf = 0; + /* Pick each queue family to use */ - graph_index = pick_queue_family(qf, num, VK_QUEUE_GRAPHICS_BIT); - comp_index = pick_queue_family(qf, num, VK_QUEUE_COMPUTE_BIT); - tx_index = pick_queue_family(qf, num, VK_QUEUE_TRANSFER_BIT); - enc_index = pick_queue_family(qf, num, VK_QUEUE_VIDEO_ENCODE_BIT_KHR); - dec_index = pick_queue_family(qf, num, VK_QUEUE_VIDEO_DECODE_BIT_KHR); +#define PICK_QF(type, vid_op) \ + do { \ + uint32_t i; \ + uint32_t idx; \ + \ + if (vid_op) \ + idx = pick_video_queue_family(qf, qf_vid, num, vid_op); \ + else \ + idx = pick_queue_family(qf, num, type); \ + \ + if (idx == -1) \ + continue; \ + \ + for (i = 0; i < hwctx->nb_qf; i++) { \ + if (hwctx->qf[i].idx == idx) { \ + hwctx->qf[i].flags |= type; \ + hwctx->qf[i].video_caps |= vid_op; \ + break; \ + } \ + } \ + if (i == hwctx->nb_qf) { \ + hwctx->qf[i].idx = idx; \ + hwctx->qf[i].num = qf[idx].queueFamilyProperties.queueCount; \ + hwctx->qf[i].flags = type; \ + hwctx->qf[i].video_caps = vid_op; \ + hwctx->nb_qf++; \ + } \ + } while (0) - /* Signalling the transfer capabilities on a queue family is optional */ - if (tx_index < 0) { - tx_index = pick_queue_family(qf, num, VK_QUEUE_COMPUTE_BIT); - if (tx_index < 0) - tx_index = pick_queue_family(qf, num, VK_QUEUE_GRAPHICS_BIT); + PICK_QF(VK_QUEUE_GRAPHICS_BIT, VK_VIDEO_CODEC_OPERATION_NONE_KHR); + PICK_QF(VK_QUEUE_COMPUTE_BIT, VK_VIDEO_CODEC_OPERATION_NONE_KHR); + PICK_QF(VK_QUEUE_TRANSFER_BIT, VK_VIDEO_CODEC_OPERATION_NONE_KHR); + PICK_QF(VK_QUEUE_OPTICAL_FLOW_BIT_NV, VK_VIDEO_CODEC_OPERATION_NONE_KHR); + + PICK_QF(VK_QUEUE_VIDEO_ENCODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR); + PICK_QF(VK_QUEUE_VIDEO_DECODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR); + + PICK_QF(VK_QUEUE_VIDEO_ENCODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR); + PICK_QF(VK_QUEUE_VIDEO_DECODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR); + + PICK_QF(VK_QUEUE_VIDEO_DECODE_BIT_KHR, VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR); + + av_free(qf); + av_free(qf_vid); + +#undef PICK_QF + + cd->pQueueCreateInfos = av_malloc_array(hwctx->nb_qf, + sizeof(VkDeviceQueueCreateInfo)); + if (!cd->pQueueCreateInfos) + return AVERROR(ENOMEM); + + for (uint32_t i = 0; i < hwctx->nb_qf; i++) { + int dup = 0; + float *weights = NULL; + VkDeviceQueueCreateInfo *pc; + for (uint32_t j = 0; j < cd->queueCreateInfoCount; j++) { + if (hwctx->qf[i].idx == cd->pQueueCreateInfos[j].queueFamilyIndex) { + dup = 1; + break; + } + } + if (dup) + continue; + + weights = av_malloc_array(hwctx->qf[i].num, sizeof(float)); + if (!weights) { + for (uint32_t j = 0; j < cd->queueCreateInfoCount; j++) + av_free((void *)cd->pQueueCreateInfos[i].pQueuePriorities); + av_free((void *)cd->pQueueCreateInfos); + return AVERROR(ENOMEM); + } + + for (uint32_t j = 0; j < hwctx->qf[i].num; j++) + weights[j] = 1.0; + + pc = (VkDeviceQueueCreateInfo *)cd->pQueueCreateInfos; + pc[cd->queueCreateInfoCount++] = (VkDeviceQueueCreateInfo) { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = hwctx->qf[i].idx, + .queueCount = hwctx->qf[i].num, + .pQueuePriorities = weights, + }; } +#if FF_API_VULKAN_FIXED_QUEUES +FF_DISABLE_DEPRECATION_WARNINGS + /* Setup deprecated fields */ hwctx->queue_family_index = -1; hwctx->queue_family_comp_index = -1; hwctx->queue_family_tx_index = -1; hwctx->queue_family_encode_index = -1; hwctx->queue_family_decode_index = -1; -#define SETUP_QUEUE(qf_idx) \ - if (qf_idx > -1) { \ - int fidx = qf_idx; \ - int qc = qf[fidx].queueCount; \ - VkDeviceQueueCreateInfo *pc; \ - \ - if (fidx == graph_index) { \ - hwctx->queue_family_index = fidx; \ - hwctx->nb_graphics_queues = qc; \ - graph_index = -1; \ - } \ - if (fidx == comp_index) { \ - hwctx->queue_family_comp_index = fidx; \ - hwctx->nb_comp_queues = qc; \ - comp_index = -1; \ - } \ - if (fidx == tx_index) { \ - hwctx->queue_family_tx_index = fidx; \ - hwctx->nb_tx_queues = qc; \ - tx_index = -1; \ - } \ - if (fidx == enc_index) { \ - hwctx->queue_family_encode_index = fidx; \ - hwctx->nb_encode_queues = qc; \ - enc_index = -1; \ - } \ - if (fidx == dec_index) { \ - hwctx->queue_family_decode_index = fidx; \ - hwctx->nb_decode_queues = qc; \ - dec_index = -1; \ - } \ - \ - pc = av_realloc((void *)cd->pQueueCreateInfos, \ - sizeof(*pc) * (cd->queueCreateInfoCount + 1)); \ - if (!pc) { \ - av_free(qf); \ - return AVERROR(ENOMEM); \ - } \ - cd->pQueueCreateInfos = pc; \ - pc = &pc[cd->queueCreateInfoCount]; \ - \ - weights = av_malloc(qc * sizeof(float)); \ - if (!weights) { \ - av_free(qf); \ - return AVERROR(ENOMEM); \ - } \ - \ - memset(pc, 0, sizeof(*pc)); \ - pc->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; \ - pc->queueFamilyIndex = fidx; \ - pc->queueCount = qc; \ - pc->pQueuePriorities = weights; \ - \ - for (int i = 0; i < qc; i++) \ - weights[i] = 1.0f / qc; \ - \ - cd->queueCreateInfoCount++; \ +#define SET_OLD_QF(field, nb_field, type) \ + do { \ + if (field < 0 && hwctx->qf[i].flags & type) { \ + field = hwctx->qf[i].idx; \ + nb_field = hwctx->qf[i].num; \ + } \ + } while (0) + + for (uint32_t i = 0; i < hwctx->nb_qf; i++) { + SET_OLD_QF(hwctx->queue_family_index, hwctx->nb_graphics_queues, VK_QUEUE_GRAPHICS_BIT); + SET_OLD_QF(hwctx->queue_family_comp_index, hwctx->nb_comp_queues, VK_QUEUE_COMPUTE_BIT); + SET_OLD_QF(hwctx->queue_family_tx_index, hwctx->nb_tx_queues, VK_QUEUE_TRANSFER_BIT); + SET_OLD_QF(hwctx->queue_family_encode_index, hwctx->nb_encode_queues, VK_QUEUE_VIDEO_ENCODE_BIT_KHR); + SET_OLD_QF(hwctx->queue_family_decode_index, hwctx->nb_decode_queues, VK_QUEUE_VIDEO_DECODE_BIT_KHR); } - SETUP_QUEUE(graph_index) - SETUP_QUEUE(comp_index) - SETUP_QUEUE(tx_index) - SETUP_QUEUE(enc_index) - SETUP_QUEUE(dec_index) - -#undef SETUP_QUEUE - - av_free(qf); +#undef SET_OLD_QF +FF_ENABLE_DEPRECATION_WARNINGS +#endif return 0; } @@ -1237,6 +1409,7 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx, VulkanDevicePriv *p = ctx->hwctx; AVVulkanDeviceContext *hwctx = &p->p; FFVulkanFunctions *vk = &p->vkctx.vkfn; + enum FFVulkanDebugMode debug_mode = FF_VULKAN_DEBUG_NONE; /* * VkPhysicalDeviceVulkan12Features has a timelineSemaphore field, but @@ -1246,9 +1419,21 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx, VkPhysicalDeviceTimelineSemaphoreFeatures timeline_features = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, }; + VkPhysicalDeviceVideoMaintenance1FeaturesKHR video_maint_1_features = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR, + .pNext = &timeline_features, + }; + VkPhysicalDeviceShaderObjectFeaturesEXT shader_object_features = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT, + .pNext = &video_maint_1_features, + }; + VkPhysicalDeviceOpticalFlowFeaturesNV optical_flow_features = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV, + .pNext = &shader_object_features, + }; VkPhysicalDeviceCooperativeMatrixFeaturesKHR coop_matrix_features = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR, - .pNext = &timeline_features, + .pNext = &optical_flow_features, }; VkPhysicalDeviceShaderAtomicFloatFeaturesEXT atomic_float_features = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT, @@ -1279,25 +1464,10 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx, .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, }; - hwctx->device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - hwctx->device_features.pNext = &p->device_features_1_1; - p->device_features_1_1.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; - p->device_features_1_1.pNext = &p->device_features_1_2; - p->device_features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - p->device_features_1_2.pNext = &p->device_features_1_3; - p->device_features_1_3.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; - p->device_features_1_3.pNext = &p->desc_buf_features; - p->desc_buf_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT; - p->desc_buf_features.pNext = &p->atomic_float_features; - p->atomic_float_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT; - p->atomic_float_features.pNext = &p->coop_matrix_features; - p->coop_matrix_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR; - p->coop_matrix_features.pNext = NULL; - ctx->free = vulkan_device_free; /* Create an instance if not given one */ - if ((err = create_instance(ctx, opts))) + if ((err = create_instance(ctx, opts, &debug_mode))) goto end; /* Find a device (if not given one) */ @@ -1327,6 +1497,8 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx, p->device_features_1_1.samplerYcbcrConversion = dev_features_1_1.samplerYcbcrConversion; p->device_features_1_1.storagePushConstant16 = dev_features_1_1.storagePushConstant16; + p->device_features_1_1.storageBuffer16BitAccess = dev_features_1_1.storageBuffer16BitAccess; + p->device_features_1_1.uniformAndStorageBuffer16BitAccess = dev_features_1_1.uniformAndStorageBuffer16BitAccess; p->device_features_1_2.timelineSemaphore = 1; p->device_features_1_2.bufferDeviceAddress = dev_features_1_2.bufferDeviceAddress; @@ -1348,6 +1520,8 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx, p->device_features_1_3.shaderZeroInitializeWorkgroupMemory = dev_features_1_3.shaderZeroInitializeWorkgroupMemory; p->device_features_1_3.dynamicRendering = dev_features_1_3.dynamicRendering; + p->video_maint_1_features.videoMaintenance1 = video_maint_1_features.videoMaintenance1; + p->desc_buf_features.descriptorBuffer = desc_buf_features.descriptorBuffer; p->desc_buf_features.descriptorBufferPushDescriptors = desc_buf_features.descriptorBufferPushDescriptors; @@ -1356,20 +1530,58 @@ static int vulkan_device_create_internal(AVHWDeviceContext *ctx, p->coop_matrix_features.cooperativeMatrix = coop_matrix_features.cooperativeMatrix; - dev_info.pNext = &hwctx->device_features; + p->optical_flow_features.opticalFlow = optical_flow_features.opticalFlow; - /* Setup queue family */ - if ((err = setup_queue_families(ctx, &dev_info))) - goto end; + p->shader_object_features.shaderObject = shader_object_features.shaderObject; + /* Find and enable extensions */ if ((err = check_extensions(ctx, 1, opts, &dev_info.ppEnabledExtensionNames, - &dev_info.enabledExtensionCount, 0))) { + &dev_info.enabledExtensionCount, debug_mode))) { for (int i = 0; i < dev_info.queueCreateInfoCount; i++) av_free((void *)dev_info.pQueueCreateInfos[i].pQueuePriorities); av_free((void *)dev_info.pQueueCreateInfos); goto end; } + /* Setup enabled device features */ + hwctx->device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + hwctx->device_features.pNext = &p->device_features_1_1; + p->device_features_1_1.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; + p->device_features_1_1.pNext = &p->device_features_1_2; + p->device_features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + p->device_features_1_2.pNext = &p->device_features_1_3; + p->device_features_1_3.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; + p->device_features_1_3.pNext = NULL; + +#define OPT_CHAIN(EXT_FLAG, STRUCT_P, TYPE) \ + do { \ + if (p->vkctx.extensions & EXT_FLAG) { \ + (STRUCT_P)->sType = TYPE; \ + ff_vk_link_struct(hwctx->device_features.pNext, STRUCT_P); \ + } \ + } while (0) + + OPT_CHAIN(FF_VK_EXT_DESCRIPTOR_BUFFER, &p->desc_buf_features, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT); + OPT_CHAIN(FF_VK_EXT_ATOMIC_FLOAT, &p->atomic_float_features, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT); + OPT_CHAIN(FF_VK_EXT_COOP_MATRIX, &p->coop_matrix_features, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR); + OPT_CHAIN(FF_VK_EXT_SHADER_OBJECT, &p->shader_object_features, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT); + OPT_CHAIN(FF_VK_EXT_OPTICAL_FLOW, &p->optical_flow_features, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV); + OPT_CHAIN(FF_VK_EXT_VIDEO_MAINTENANCE_1, &p->video_maint_1_features, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR); +#undef OPT_CHAIN + + /* Add the enabled features into the pnext chain of device creation */ + dev_info.pNext = &hwctx->device_features; + + /* Setup enabled queue families */ + if ((err = setup_queue_families(ctx, &dev_info))) + goto end; + ret = vk->CreateDevice(hwctx->phys_dev, &dev_info, hwctx->alloc, &hwctx->act_dev); @@ -1423,12 +1635,13 @@ static void unlock_queue(AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t static int vulkan_device_init(AVHWDeviceContext *ctx) { - int err; + int err = 0; uint32_t qf_num; VulkanDevicePriv *p = ctx->hwctx; AVVulkanDeviceContext *hwctx = &p->p; FFVulkanFunctions *vk = &p->vkctx.vkfn; - VkQueueFamilyProperties *qf; + VkQueueFamilyProperties2 *qf; + VkQueueFamilyVideoPropertiesKHR *qf_vid; int graph_index, comp_index, tx_index, enc_index, dec_index; /* Set device extension flags */ @@ -1474,38 +1687,55 @@ static int vulkan_device_init(AVHWDeviceContext *ctx) return AVERROR_EXTERNAL; } - qf = av_malloc_array(qf_num, sizeof(VkQueueFamilyProperties)); + qf = av_malloc_array(qf_num, sizeof(VkQueueFamilyProperties2)); if (!qf) return AVERROR(ENOMEM); - vk->GetPhysicalDeviceQueueFamilyProperties(hwctx->phys_dev, &qf_num, qf); + qf_vid = av_malloc_array(qf_num, sizeof(VkQueueFamilyVideoPropertiesKHR)); + if (!qf_vid) { + av_free(qf); + return AVERROR(ENOMEM); + } + + for (uint32_t i = 0; i < qf_num; i++) { + qf_vid[i] = (VkQueueFamilyVideoPropertiesKHR) { + .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR, + }; + qf[i] = (VkQueueFamilyProperties2) { + .sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, + .pNext = &qf_vid[i], + }; + } + + vk->GetPhysicalDeviceQueueFamilyProperties2(hwctx->phys_dev, &qf_num, qf); p->qf_mutex = av_calloc(qf_num, sizeof(*p->qf_mutex)); if (!p->qf_mutex) { - av_free(qf); - return AVERROR(ENOMEM); + err = AVERROR(ENOMEM); + goto end; } p->nb_tot_qfs = qf_num; for (uint32_t i = 0; i < qf_num; i++) { - p->qf_mutex[i] = av_calloc(qf[i].queueCount, sizeof(**p->qf_mutex)); + p->qf_mutex[i] = av_calloc(qf[i].queueFamilyProperties.queueCount, + sizeof(**p->qf_mutex)); if (!p->qf_mutex[i]) { - av_free(qf); - return AVERROR(ENOMEM); + err = AVERROR(ENOMEM); + goto end; } - for (uint32_t j = 0; j < qf[i].queueCount; j++) { + for (uint32_t j = 0; j < qf[i].queueFamilyProperties.queueCount; j++) { err = pthread_mutex_init(&p->qf_mutex[i][j], NULL); if (err != 0) { av_log(ctx, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", av_err2str(err)); - av_free(qf); - return AVERROR(err); + err = AVERROR(err); + goto end; } } } - av_free(qf); - +#if FF_API_VULKAN_FIXED_QUEUES +FF_DISABLE_DEPRECATION_WARNINGS graph_index = hwctx->nb_graphics_queues ? hwctx->queue_family_index : -1; comp_index = hwctx->nb_comp_queues ? hwctx->queue_family_comp_index : -1; tx_index = hwctx->nb_tx_queues ? hwctx->queue_family_tx_index : -1; @@ -1517,13 +1747,15 @@ static int vulkan_device_init(AVHWDeviceContext *ctx) if (ctx_qf < 0 && required) { \ av_log(ctx, AV_LOG_ERROR, "%s queue family is required, but marked as missing" \ " in the context!\n", type); \ - return AVERROR(EINVAL); \ + err = AVERROR(EINVAL); \ + goto end; \ } else if (fidx < 0 || ctx_qf < 0) { \ break; \ } else if (ctx_qf >= qf_num) { \ av_log(ctx, AV_LOG_ERROR, "Invalid %s family index %i (device has %i families)!\n", \ type, ctx_qf, qf_num); \ - return AVERROR(EINVAL); \ + err = AVERROR(EINVAL); \ + goto end; \ } \ \ av_log(ctx, AV_LOG_VERBOSE, "Using queue family %i (queues: %i)" \ @@ -1539,7 +1771,6 @@ static int vulkan_device_init(AVHWDeviceContext *ctx) tx_index = (ctx_qf == tx_index) ? -1 : tx_index; \ enc_index = (ctx_qf == enc_index) ? -1 : enc_index; \ dec_index = (ctx_qf == dec_index) ? -1 : dec_index; \ - p->img_qfs[p->nb_img_qfs++] = ctx_qf; \ } while (0) CHECK_QUEUE("graphics", 0, graph_index, hwctx->queue_family_index, hwctx->nb_graphics_queues); @@ -1550,6 +1781,54 @@ static int vulkan_device_init(AVHWDeviceContext *ctx) #undef CHECK_QUEUE + /* Update the new queue family fields. If non-zero already, + * it means API users have set it. */ + if (!hwctx->nb_qf) { +#define ADD_QUEUE(ctx_qf, qc, flag) \ + do { \ + if (ctx_qf != -1) { \ + hwctx->qf[hwctx->nb_qf++] = (AVVulkanDeviceQueueFamily) { \ + .idx = ctx_qf, \ + .num = qc, \ + .flags = flag, \ + }; \ + } \ + } while (0) + + ADD_QUEUE(hwctx->queue_family_index, hwctx->nb_graphics_queues, VK_QUEUE_GRAPHICS_BIT); + ADD_QUEUE(hwctx->queue_family_comp_index, hwctx->nb_comp_queues, VK_QUEUE_COMPUTE_BIT); + ADD_QUEUE(hwctx->queue_family_tx_index, hwctx->nb_tx_queues, VK_QUEUE_TRANSFER_BIT); + ADD_QUEUE(hwctx->queue_family_decode_index, hwctx->nb_decode_queues, VK_QUEUE_VIDEO_DECODE_BIT_KHR); + ADD_QUEUE(hwctx->queue_family_encode_index, hwctx->nb_encode_queues, VK_QUEUE_VIDEO_ENCODE_BIT_KHR); +#undef ADD_QUEUE + } +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + for (int i = 0; i < hwctx->nb_qf; i++) { + if (!hwctx->qf[i].video_caps && + hwctx->qf[i].flags & (VK_QUEUE_VIDEO_DECODE_BIT_KHR | + VK_QUEUE_VIDEO_ENCODE_BIT_KHR)) { + hwctx->qf[i].video_caps = qf_vid[hwctx->qf[i].idx].videoCodecOperations; + } + } + + /* Setup array for pQueueFamilyIndices with used queue families */ + p->nb_img_qfs = 0; + for (int i = 0; i < hwctx->nb_qf; i++) { + int seen = 0; + /* Make sure each entry is unique + * (VUID-VkBufferCreateInfo-sharingMode-01419) */ + for (int j = (i - 1); j >= 0; j--) { + if (hwctx->qf[i].idx == hwctx->qf[j].idx) { + seen = 1; + break; + } + } + if (!seen) + p->img_qfs[p->nb_img_qfs++] = hwctx->qf[i].idx; + } + if (!hwctx->lock_queue) hwctx->lock_queue = lock_queue; if (!hwctx->unlock_queue) @@ -1565,7 +1844,10 @@ static int vulkan_device_init(AVHWDeviceContext *ctx) ff_vk_qf_init(&p->vkctx, &p->compute_qf, VK_QUEUE_COMPUTE_BIT); ff_vk_qf_init(&p->vkctx, &p->transfer_qf, VK_QUEUE_TRANSFER_BIT); - return 0; +end: + av_free(qf_vid); + av_free(qf); + return err; } static int vulkan_device_create(AVHWDeviceContext *ctx, const char *device, @@ -1936,11 +2218,13 @@ static int alloc_bind_mem(AVHWFramesContext *hwfc, AVVkFrame *f, } enum PrepMode { + PREP_MODE_GENERAL, PREP_MODE_WRITE, PREP_MODE_EXTERNAL_EXPORT, PREP_MODE_EXTERNAL_IMPORT, PREP_MODE_DECODING_DST, PREP_MODE_DECODING_DPB, + PREP_MODE_ENCODING_DPB, }; static int prepare_frame(AVHWFramesContext *hwfc, FFVkExecPool *ectx, @@ -1980,6 +2264,10 @@ static int prepare_frame(AVHWFramesContext *hwfc, FFVkExecPool *ectx, return err; switch (pmode) { + case PREP_MODE_GENERAL: + new_layout = VK_IMAGE_LAYOUT_GENERAL; + new_access = VK_ACCESS_TRANSFER_WRITE_BIT; + break; case PREP_MODE_WRITE: new_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; new_access = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -2002,6 +2290,10 @@ static int prepare_frame(AVHWFramesContext *hwfc, FFVkExecPool *ectx, new_layout = VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR; new_access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; break; + case PREP_MODE_ENCODING_DPB: + new_layout = VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR; + new_access = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; + break; } ff_vk_frame_barrier(&p->vkctx, exec, &tmp_frame, img_bar, &nb_img_bar, @@ -2262,8 +2554,12 @@ static AVBufferRef *vulkan_pool_alloc(void *opaque, size_t size) err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DPB); else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR) err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_DECODING_DST); - else + else if (hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR) + err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_ENCODING_DPB); + else if (hwctx->usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_WRITE); + else + err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_GENERAL); if (err) goto fail; @@ -2303,6 +2599,8 @@ static void vulkan_frames_uninit(AVHWFramesContext *hwfc) ff_vk_exec_pool_free(&p->vkctx, &fp->compute_exec); ff_vk_exec_pool_free(&p->vkctx, &fp->upload_exec); ff_vk_exec_pool_free(&p->vkctx, &fp->download_exec); + + av_buffer_pool_uninit(&fp->tmp); } static int vulkan_frames_init(AVHWFramesContext *hwfc) @@ -2350,7 +2648,8 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) err = vkfmt_from_pixfmt2(hwfc->device_ctx, hwfc->sw_format, hwctx->tiling, NULL, NULL, NULL, &supported_usage, 0, - hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT); + !hwctx->usage || + (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT)); if (err < 0) { av_log(hwfc, AV_LOG_ERROR, "Unsupported sw format: %s!\n", av_get_pix_fmt_name(hwfc->sw_format)); @@ -2361,7 +2660,8 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) hwctx->tiling, hwctx->format, NULL, NULL, &supported_usage, disable_multiplane, - hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT); + !hwctx->usage || + (hwctx->usage & VK_IMAGE_USAGE_STORAGE_BIT)); if (err < 0) return err; } @@ -2372,14 +2672,21 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + + /* Enables encoding of images, if supported by format and extensions */ + if ((supported_usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) && + (p->vkctx.extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE | + FF_VK_EXT_VIDEO_MAINTENANCE_1))) + hwctx->usage |= VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR; } /* Image creation flags. * Only fill them in automatically if the image is not going to be used as * a DPB-only image, and we have SAMPLED/STORAGE bits set. */ if (!hwctx->img_flags) { - int is_lone_dpb = (hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) && - !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR); + int is_lone_dpb = ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR) || + ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR) && + !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR))); int sampleable = hwctx->usage & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT); if (sampleable && !is_lone_dpb) { @@ -2390,6 +2697,29 @@ static int vulkan_frames_init(AVHWFramesContext *hwfc) } } + /* If the image has an ENCODE_SRC usage, and the maintenance1 + * extension is supported, check if it has a profile list. + * If there's no profile list, or it has no encode operations, + * then allow creating the image with no specific profile. */ + if ((hwctx->usage & VK_IMAGE_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) && + (p->vkctx.extensions & (FF_VK_EXT_VIDEO_ENCODE_QUEUE | + FF_VK_EXT_VIDEO_MAINTENANCE_1))) { + const VkVideoProfileListInfoKHR *pl; + pl = ff_vk_find_struct(hwctx->create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR); + if (!pl) { + hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR; + } else { + uint32_t i; + for (i = 0; i < pl->profileCount; i++) { + /* Video ops start at exactly 0x00010000 */ + if (pl->pProfiles[i].videoCodecOperation & 0xFFFF0000) + break; + } + if (i == pl->profileCount) + hwctx->img_flags |= VK_IMAGE_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR; + } + } + if (!hwctx->lock_frame) hwctx->lock_frame = lock_frame; @@ -2491,6 +2821,10 @@ static const struct { { DRM_FORMAT_XRGB8888, VK_FORMAT_B8G8R8A8_UNORM }, { DRM_FORMAT_ABGR8888, VK_FORMAT_R8G8B8A8_UNORM }, { DRM_FORMAT_XBGR8888, VK_FORMAT_R8G8B8A8_UNORM }, + { DRM_FORMAT_ARGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 }, + { DRM_FORMAT_ABGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 }, + { DRM_FORMAT_XRGB2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32 }, + { DRM_FORMAT_XBGR2101010, VK_FORMAT_A2R10G10B10_UNORM_PACK32 }, // All these DRM_FORMATs were added in the same libdrm commit. #ifdef DRM_FORMAT_XYUV8888 @@ -2511,7 +2845,7 @@ static inline VkFormat drm_to_vulkan_fmt(uint32_t drm_fourcc) } static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **frame, - const AVFrame *src) + const AVFrame *src, int flags) { int err = 0; VkResult ret; @@ -2521,7 +2855,6 @@ static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **f VulkanDevicePriv *p = ctx->hwctx; AVVulkanDeviceContext *hwctx = &p->p; FFVulkanFunctions *vk = &p->vkctx.vkfn; - VulkanFramesPriv *fp = hwfc->hwctx; const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0]; VkBindImageMemoryInfo bind_info[AV_DRM_MAX_PLANES]; VkBindImagePlaneMemoryInfo plane_info[AV_DRM_MAX_PLANES]; @@ -2580,8 +2913,7 @@ static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **f .flags = 0x0, .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, /* specs say so */ - .usage = VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + .usage = 0x0, /* filled in below */ .samples = VK_SAMPLE_COUNT_1_BIT, .pQueueFamilyIndices = p->img_qfs, .queueFamilyIndexCount = p->nb_img_qfs, @@ -2609,7 +2941,16 @@ static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **f .pNext = &props_drm_mod, .handleType = ext_img_spec.handleTypes, }; - VkPhysicalDeviceImageFormatInfo2 fmt_props = { + VkPhysicalDeviceImageFormatInfo2 fmt_props; + + if (flags & AV_HWFRAME_MAP_READ) + create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + if (flags & AV_HWFRAME_MAP_WRITE) + create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + fmt_props = (VkPhysicalDeviceImageFormatInfo2) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, .pNext = &props_ext, .format = create_info.format, @@ -2661,12 +3002,7 @@ static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **f goto fail; } - /* We'd import a semaphore onto the one we created using - * vkImportSemaphoreFdKHR but unfortunately neither DRM nor VAAPI - * offer us anything we could import and sync with, so instead - * just signal the semaphore we created. */ - - f->queue_family[i] = p->nb_img_qfs > 1 ? VK_QUEUE_FAMILY_IGNORED : p->img_qfs[0]; + f->queue_family[i] = VK_QUEUE_FAMILY_EXTERNAL; f->layout[i] = create_info.initialLayout; f->access[i] = 0x0; f->sem_value[i] = 0; @@ -2768,10 +3104,6 @@ static int vulkan_map_from_drm_frame_desc(AVHWFramesContext *hwfc, AVVkFrame **f goto fail; } - err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_EXTERNAL_IMPORT); - if (err) - goto fail; - *frame = f; return 0; @@ -2782,13 +3114,140 @@ fail: return err; } +static int vulkan_map_from_drm_frame_sync(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + int err; + VkResult ret; + AVHWDeviceContext *ctx = hwfc->device_ctx; + VulkanDevicePriv *p = ctx->hwctx; + VulkanFramesPriv *fp = hwfc->hwctx; + AVVulkanDeviceContext *hwctx = &p->p; + FFVulkanFunctions *vk = &p->vkctx.vkfn; + + const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)src->data[0]; + +#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE + if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) { + VkCommandBuffer cmd_buf; + FFVkExecContext *exec; + VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS]; + VkSemaphore drm_sync_sem[AV_DRM_MAX_PLANES] = { 0 }; + int nb_img_bar = 0; + + for (int i = 0; i < desc->nb_objects; i++) { + VkSemaphoreTypeCreateInfo sem_type_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + .semaphoreType = VK_SEMAPHORE_TYPE_BINARY, + }; + VkSemaphoreCreateInfo sem_spawn = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &sem_type_info, + }; + VkImportSemaphoreFdInfoKHR import_info; + struct dma_buf_export_sync_file implicit_fd_info = { + .flags = DMA_BUF_SYNC_READ, + .fd = -1, + }; + + if (ioctl(desc->objects[i].fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, + &implicit_fd_info)) { + err = AVERROR(errno); + av_log(hwctx, AV_LOG_ERROR, "Failed to retrieve implicit DRM sync file: %s\n", + av_err2str(err)); + for (; i >= 0; i--) + vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc); + return err; + } + + ret = vk->CreateSemaphore(hwctx->act_dev, &sem_spawn, + hwctx->alloc, &drm_sync_sem[i]); + if (ret != VK_SUCCESS) { + av_log(hwctx, AV_LOG_ERROR, "Failed to create semaphore: %s\n", + ff_vk_ret2str(ret)); + err = AVERROR_EXTERNAL; + for (; i >= 0; i--) + vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc); + return err; + } + + import_info = (VkImportSemaphoreFdInfoKHR) { + .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR, + .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, + .semaphore = drm_sync_sem[i], + .fd = implicit_fd_info.fd, + }; + + ret = vk->ImportSemaphoreFdKHR(hwctx->act_dev, &import_info); + if (ret != VK_SUCCESS) { + av_log(hwctx, AV_LOG_ERROR, "Failed to import semaphore: %s\n", + ff_vk_ret2str(ret)); + err = AVERROR_EXTERNAL; + for (; i >= 0; i--) + vk->DestroySemaphore(hwctx->act_dev, drm_sync_sem[i], hwctx->alloc); + return err; + } + } + + exec = ff_vk_exec_get(&fp->compute_exec); + cmd_buf = exec->buf; + + ff_vk_exec_start(&p->vkctx, exec); + + /* Ownership of semaphores is passed */ + err = ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec, + drm_sync_sem, desc->nb_objects, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 1); + if (err < 0) + return err; + + err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, dst, + VK_PIPELINE_STAGE_2_NONE, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT); + if (err < 0) + return err; + + ff_vk_frame_barrier(&p->vkctx, exec, dst, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_NONE, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + ((flags & AV_HWFRAME_MAP_READ) ? + VK_ACCESS_2_SHADER_SAMPLED_READ_BIT : 0x0) | + ((flags & AV_HWFRAME_MAP_WRITE) ? + VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT : 0x0), + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_IGNORED); + + vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); + + err = ff_vk_exec_submit(&p->vkctx, exec); + if (err < 0) + return err; + } else +#endif + { + AVVkFrame *f = (AVVkFrame *)dst->data[0]; + av_log(hwctx, AV_LOG_WARNING, "No support for synchronization when importing DMA-BUFs, " + "image may be corrupted.\n"); + err = prepare_frame(hwfc, &fp->compute_exec, f, PREP_MODE_EXTERNAL_IMPORT); + if (err) + return err; + } + + return 0; +} + static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags) { int err = 0; AVVkFrame *f; - if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src))) + if ((err = vulkan_map_from_drm_frame_desc(hwfc, &f, src, flags))) return err; /* The unmapping function will free this */ @@ -2801,6 +3260,10 @@ static int vulkan_map_from_drm(AVHWFramesContext *hwfc, AVFrame *dst, if (err < 0) goto fail; + err = vulkan_map_from_drm_frame_sync(hwfc, dst, src, flags); + if (err < 0) + return err; + av_log(hwfc, AV_LOG_DEBUG, "Mapped DRM object to Vulkan!\n"); return 0; @@ -3323,128 +3786,290 @@ static int vulkan_map_from(AVHWFramesContext *hwfc, AVFrame *dst, return AVERROR(ENOSYS); } -static size_t get_req_buffer_size(VulkanDevicePriv *p, int *stride, int height) +static int copy_buffer_data(AVHWFramesContext *hwfc, AVBufferRef *buf, + AVFrame *swf, VkBufferImageCopy *region, + int planes, int upload) { - size_t size; - *stride = FFALIGN(*stride, p->props.properties.limits.optimalBufferCopyRowPitchAlignment); - size = height*(*stride); - size = FFALIGN(size, p->props.properties.limits.minMemoryMapAlignment); - return size; -} - -static int transfer_image_buf(AVHWFramesContext *hwfc, AVFrame *f, - AVBufferRef **bufs, size_t *buf_offsets, - const int *buf_stride, int w, - int h, enum AVPixelFormat pix_fmt, int to_buf) -{ - int err; - AVVkFrame *frame = (AVVkFrame *)f->data[0]; - VulkanFramesPriv *fp = hwfc->hwctx; + VkResult ret; VulkanDevicePriv *p = hwfc->device_ctx->hwctx; FFVulkanFunctions *vk = &p->vkctx.vkfn; - VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS]; - int nb_img_bar = 0; + AVVulkanDeviceContext *hwctx = &p->p; - const int nb_images = ff_vk_count_images(frame); - int pixfmt_planes = av_pix_fmt_count_planes(pix_fmt); - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + FFVkBuffer *vkbuf = (FFVkBuffer *)buf->data; - VkCommandBuffer cmd_buf; - FFVkExecContext *exec = ff_vk_exec_get(to_buf ? &fp->download_exec : - &fp->upload_exec); - cmd_buf = exec->buf; - ff_vk_exec_start(&p->vkctx, exec); + const VkMappedMemoryRange flush_info = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = vkbuf->mem, + .size = VK_WHOLE_SIZE, + }; - err = ff_vk_exec_add_dep_buf(&p->vkctx, exec, bufs, pixfmt_planes, 1); - if (err < 0) - return err; - - err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, f, - VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_2_TRANSFER_BIT); - if (err < 0) - return err; - - ff_vk_frame_barrier(&p->vkctx, exec, f, img_bar, &nb_img_bar, - VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, - to_buf ? VK_ACCESS_TRANSFER_READ_BIT : - VK_ACCESS_TRANSFER_WRITE_BIT, - to_buf ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED); - - vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) { - .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - .pImageMemoryBarriers = img_bar, - .imageMemoryBarrierCount = nb_img_bar, - }); - - /* Schedule a copy for each plane */ - for (int i = 0; i < pixfmt_planes; i++) { - int idx = FFMIN(i, nb_images - 1); - VkImageAspectFlags plane_aspect[] = { VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_ASPECT_PLANE_0_BIT, - VK_IMAGE_ASPECT_PLANE_1_BIT, - VK_IMAGE_ASPECT_PLANE_2_BIT, }; - - FFVkBuffer *vkbuf = (FFVkBuffer *)bufs[i]->data; - VkBufferImageCopy buf_reg = { - .bufferOffset = buf_offsets[i], - .bufferRowLength = buf_stride[i] / desc->comp[i].step, - .imageSubresource.layerCount = 1, - .imageSubresource.aspectMask = plane_aspect[(pixfmt_planes != nb_images) + - i*(pixfmt_planes != nb_images)], - .imageOffset = { 0, 0, 0, }, - }; - - uint32_t p_w, p_h; - get_plane_wh(&p_w, &p_h, pix_fmt, w, h, i); - - buf_reg.bufferImageHeight = p_h; - buf_reg.imageExtent = (VkExtent3D){ p_w, p_h, 1, }; - - if (to_buf) - vk->CmdCopyImageToBuffer(cmd_buf, frame->img[idx], - img_bar[0].newLayout, - vkbuf->buf, - 1, &buf_reg); - else - vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf, frame->img[idx], - img_bar[0].newLayout, - 1, &buf_reg); + if (!(vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) && !upload) { + ret = vk->InvalidateMappedMemoryRanges(hwctx->act_dev, 1, + &flush_info); + if (ret != VK_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to invalidate buffer data: %s\n", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } } - err = ff_vk_exec_submit(&p->vkctx, exec); - if (err < 0) - return err; + for (int i = 0; i < planes; i++) + av_image_copy_plane(vkbuf->mapped_mem + region[i].bufferOffset, + region[i].bufferRowLength, + swf->data[i], + swf->linesize[i], + swf->linesize[i], + region[i].imageExtent.height); - ff_vk_exec_wait(&p->vkctx, exec); + if (!(vkbuf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) && upload) { + ret = vk->FlushMappedMemoryRanges(hwctx->act_dev, 1, + &flush_info); + if (ret != VK_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to flush buffer data: %s\n", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } + } return 0; } -static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf, - const AVFrame *swf, int from) +static int get_plane_buf(AVHWFramesContext *hwfc, AVBufferRef **dst, + AVFrame *swf, VkBufferImageCopy *region, int upload) { - int err = 0; - VkResult ret; - AVHWDeviceContext *dev_ctx = hwfc->device_ctx; - VulkanDevicePriv *p = dev_ctx->hwctx; - AVVulkanDeviceContext *hwctx = &p->p; - FFVulkanFunctions *vk = &p->vkctx.vkfn; - - AVFrame tmp; - FFVkBuffer *vkbufs[AV_NUM_DATA_POINTERS]; - AVBufferRef *bufs[AV_NUM_DATA_POINTERS] = { 0 }; - size_t buf_offsets[AV_NUM_DATA_POINTERS] = { 0 }; - - uint32_t p_w, p_h; + int err; + VulkanFramesPriv *fp = hwfc->hwctx; + VulkanDevicePriv *p = hwfc->device_ctx->hwctx; const int planes = av_pix_fmt_count_planes(swf->format); - int host_mapped[AV_NUM_DATA_POINTERS] = { 0 }; - const int map_host = !!(p->vkctx.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY); + size_t buf_offset = 0; + for (int i = 0; i < planes; i++) { + size_t size; + ptrdiff_t linesize = swf->linesize[i]; + uint32_t p_w, p_h; + get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i); + + linesize = FFALIGN(linesize, + p->props.properties.limits.optimalBufferCopyRowPitchAlignment); + size = p_h*linesize; + + region[i] = (VkBufferImageCopy) { + .bufferOffset = buf_offset, + .bufferRowLength = linesize, + .bufferImageHeight = p_h, + .imageSubresource.layerCount = 1, + .imageExtent = (VkExtent3D){ p_w, p_h, 1 }, + /* Rest of the fields adjusted/filled in later */ + }; + + buf_offset = FFALIGN(buf_offset + size, + p->props.properties.limits.optimalBufferCopyOffsetAlignment); + } + + err = ff_vk_get_pooled_buffer(&p->vkctx, &fp->tmp, dst, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + NULL, buf_offset, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + if (err < 0) + return err; + + return 0; +} + +static int create_mapped_buffer(AVHWFramesContext *hwfc, + FFVkBuffer *vkb, VkBufferUsageFlags usage, + size_t size, + VkExternalMemoryBufferCreateInfo *create_desc, + VkImportMemoryHostPointerInfoEXT *import_desc, + VkMemoryHostPointerPropertiesEXT props) +{ + int err; + VkResult ret; + VulkanDevicePriv *p = hwfc->device_ctx->hwctx; + FFVulkanFunctions *vk = &p->vkctx.vkfn; + AVVulkanDeviceContext *hwctx = &p->p; + + VkBufferCreateInfo buf_spawn = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = create_desc, + .usage = usage, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .size = size, + }; + VkMemoryRequirements req = { + .size = size, + .alignment = p->hprops.minImportedHostPointerAlignment, + .memoryTypeBits = props.memoryTypeBits, + }; + + err = ff_vk_alloc_mem(&p->vkctx, &req, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + import_desc, &vkb->flags, &vkb->mem); + if (err < 0) + return err; + + ret = vk->CreateBuffer(hwctx->act_dev, &buf_spawn, hwctx->alloc, &vkb->buf); + if (ret != VK_SUCCESS) { + vk->FreeMemory(hwctx->act_dev, vkb->mem, hwctx->alloc); + return AVERROR_EXTERNAL; + } + + ret = vk->BindBufferMemory(hwctx->act_dev, vkb->buf, vkb->mem, 0); + if (ret != VK_SUCCESS) { + vk->FreeMemory(hwctx->act_dev, vkb->mem, hwctx->alloc); + vk->DestroyBuffer(hwctx->act_dev, vkb->buf, hwctx->alloc); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static void destroy_avvkbuf(void *opaque, uint8_t *data) +{ + FFVulkanContext *s = opaque; + FFVkBuffer *buf = (FFVkBuffer *)data; + ff_vk_free_buf(s, buf); + av_free(buf); +} + +static int host_map_frame(AVHWFramesContext *hwfc, AVBufferRef **dst, int *nb_bufs, + AVFrame *swf, VkBufferImageCopy *region, int upload) +{ + int err; + VkResult ret; + VulkanDevicePriv *p = hwfc->device_ctx->hwctx; + FFVulkanFunctions *vk = &p->vkctx.vkfn; + AVVulkanDeviceContext *hwctx = &p->p; + + const int planes = av_pix_fmt_count_planes(swf->format); + + VkExternalMemoryBufferCreateInfo create_desc = { + .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, + }; + VkImportMemoryHostPointerInfoEXT import_desc = { + .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, + }; + VkMemoryHostPointerPropertiesEXT props; + + for (int i = 0; i < planes; i++) { + FFVkBuffer *vkb; + uint32_t p_w, p_h; + size_t offs; + size_t buffer_size; + + /* We can't host map images with negative strides */ + if (swf->linesize[i] < 0) { + err = AVERROR(EINVAL); + goto fail; + } + + get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i); + + /* Get the previous point at which mapping was possible and use it */ + offs = (uintptr_t)swf->data[i] % p->hprops.minImportedHostPointerAlignment; + import_desc.pHostPointer = swf->data[i] - offs; + + props = (VkMemoryHostPointerPropertiesEXT) { + VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT, + }; + ret = vk->GetMemoryHostPointerPropertiesEXT(hwctx->act_dev, + import_desc.handleType, + import_desc.pHostPointer, + &props); + if (!(ret == VK_SUCCESS && props.memoryTypeBits)) { + err = AVERROR(EINVAL); + goto fail; + } + + /* Buffer region for this plane */ + region[i] = (VkBufferImageCopy) { + .bufferOffset = offs, + .bufferRowLength = swf->linesize[i], + .bufferImageHeight = p_h, + .imageSubresource.layerCount = 1, + .imageExtent = (VkExtent3D){ p_w, p_h, 1 }, + /* Rest of the fields adjusted/filled in later */ + }; + + /* Add the offset at the start, which gets ignored */ + buffer_size = offs + swf->linesize[i]*p_h; + buffer_size = FFALIGN(buffer_size, p->props.properties.limits.minMemoryMapAlignment); + buffer_size = FFALIGN(buffer_size, p->hprops.minImportedHostPointerAlignment); + + /* Create a buffer */ + vkb = av_mallocz(sizeof(*vkb)); + if (!vkb) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = create_mapped_buffer(hwfc, vkb, + upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT : + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + buffer_size, &create_desc, &import_desc, + props); + if (err < 0) { + av_free(vkb); + goto fail; + } + + /* Create a ref */ + dst[*nb_bufs] = av_buffer_create((uint8_t *)vkb, sizeof(*vkb), + destroy_avvkbuf, &p->vkctx, 0); + if (!dst[*nb_bufs]) { + destroy_avvkbuf(&p->vkctx, (uint8_t *)vkb); + err = AVERROR(ENOMEM); + goto fail; + } + + (*nb_bufs)++; + } + + return 0; + +fail: + for (int i = 0; i < (*nb_bufs); i++) + av_buffer_unref(&dst[i]); + return err; +} + +static int vulkan_transfer_frame(AVHWFramesContext *hwfc, + AVFrame *swf, AVFrame *hwf, + int upload) +{ + int err; + VulkanFramesPriv *fp = hwfc->hwctx; + VulkanDevicePriv *p = hwfc->device_ctx->hwctx; + FFVulkanFunctions *vk = &p->vkctx.vkfn; + + int host_mapped = 0; + + AVVkFrame *hwf_vk = (AVVkFrame *)hwf->data[0]; + VkBufferImageCopy region[AV_NUM_DATA_POINTERS]; // always one per plane + + const int planes = av_pix_fmt_count_planes(swf->format); + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(swf->format); + const int nb_images = ff_vk_count_images(hwf_vk); + static const VkImageAspectFlags plane_aspect[] = { VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_ASPECT_PLANE_0_BIT, + VK_IMAGE_ASPECT_PLANE_1_BIT, + VK_IMAGE_ASPECT_PLANE_2_BIT, }; + + VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS]; + int nb_img_bar = 0; + + AVBufferRef *bufs[AV_NUM_DATA_POINTERS]; + int nb_bufs = 0; + + VkCommandBuffer cmd_buf; + FFVkExecContext *exec; + + /* Sanity checking */ if ((swf->format != AV_PIX_FMT_NONE && !av_vkfmt_from_pixfmt(swf->format))) { av_log(hwfc, AV_LOG_ERROR, "Unsupported software frame pixel format!\n"); return AVERROR(EINVAL); @@ -3453,115 +4078,97 @@ static int vulkan_transfer_data(AVHWFramesContext *hwfc, const AVFrame *vkf, if (swf->width > hwfc->width || swf->height > hwfc->height) return AVERROR(EINVAL); - /* Create buffers */ - for (int i = 0; i < planes; i++) { - size_t req_size; + /* Setup buffers first */ + if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_HOST_MEMORY) { + err = host_map_frame(hwfc, bufs, &nb_bufs, swf, region, upload); + if (err >= 0) + host_mapped = 1; + } - VkExternalMemoryBufferCreateInfo create_desc = { - .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, - .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, - }; - - VkImportMemoryHostPointerInfoEXT import_desc = { - .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT, - .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, - }; - - VkMemoryHostPointerPropertiesEXT p_props = { - .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT, - }; - - get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i); - - tmp.linesize[i] = FFABS(swf->linesize[i]); - - /* Do not map images with a negative stride */ - if (map_host && swf->linesize[i] > 0) { - size_t offs; - offs = (uintptr_t)swf->data[i] % p->hprops.minImportedHostPointerAlignment; - import_desc.pHostPointer = swf->data[i] - offs; - - /* We have to compensate for the few extra bytes of padding we - * completely ignore at the start */ - req_size = FFALIGN(offs + tmp.linesize[i] * p_h, - p->hprops.minImportedHostPointerAlignment); - - ret = vk->GetMemoryHostPointerPropertiesEXT(hwctx->act_dev, - import_desc.handleType, - import_desc.pHostPointer, - &p_props); - if (ret == VK_SUCCESS && p_props.memoryTypeBits) { - host_mapped[i] = 1; - buf_offsets[i] = offs; - } - } - - if (!host_mapped[i]) - req_size = get_req_buffer_size(p, &tmp.linesize[i], p_h); - - err = ff_vk_create_avbuf(&p->vkctx, &bufs[i], req_size, - host_mapped[i] ? &create_desc : NULL, - host_mapped[i] ? &import_desc : NULL, - from ? VK_BUFFER_USAGE_TRANSFER_DST_BIT : - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - (host_mapped[i] ? - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT : 0x0)); + if (!host_mapped) { + err = get_plane_buf(hwfc, &bufs[0], swf, region, upload); if (err < 0) goto end; + nb_bufs = 1; - vkbufs[i] = (FFVkBuffer *)bufs[i]->data; + if (upload) { + err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 1); + if (err < 0) + goto end; + } } - if (!from) { - /* Map, copy image TO buffer (which then goes to the VkImage), unmap */ - if ((err = ff_vk_map_buffers(&p->vkctx, vkbufs, tmp.data, planes, 0))) + exec = ff_vk_exec_get(&fp->upload_exec); + cmd_buf = exec->buf; + + ff_vk_exec_start(&p->vkctx, exec); + + /* Prep destination Vulkan frame */ + err = ff_vk_exec_add_dep_frame(&p->vkctx, exec, hwf, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_TRANSFER_BIT); + if (err < 0) + goto end; + + /* No need to declare buf deps for synchronous transfers */ + if (upload) { + err = ff_vk_exec_add_dep_buf(&p->vkctx, exec, bufs, nb_bufs, 1); + if (err < 0) { + ff_vk_exec_discard_deps(&p->vkctx, exec); goto end; - - for (int i = 0; i < planes; i++) { - if (host_mapped[i]) - continue; - - get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i); - - av_image_copy_plane(tmp.data[i], tmp.linesize[i], - (const uint8_t *)swf->data[i], swf->linesize[i], - FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])), - p_h); } - - if ((err = ff_vk_unmap_buffers(&p->vkctx, vkbufs, planes, 1))) - goto end; } - /* Copy buffers into/from image */ - err = transfer_image_buf(hwfc, (AVFrame *)vkf, bufs, buf_offsets, - tmp.linesize, swf->width, swf->height, swf->format, - from); + ff_vk_frame_barrier(&p->vkctx, exec, hwf, img_bar, &nb_img_bar, + VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR, + upload ? VK_ACCESS_TRANSFER_WRITE_BIT : + VK_ACCESS_TRANSFER_READ_BIT, + upload ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL : + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED); - if (from) { - /* Map, copy buffer (which came FROM the VkImage) to the frame, unmap */ - if ((err = ff_vk_map_buffers(&p->vkctx, vkbufs, tmp.data, planes, 0))) - goto end; + vk->CmdPipelineBarrier2(cmd_buf, &(VkDependencyInfo) { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pImageMemoryBarriers = img_bar, + .imageMemoryBarrierCount = nb_img_bar, + }); - for (int i = 0; i < planes; i++) { - if (host_mapped[i]) - continue; + for (int i = 0; i < planes; i++) { + int buf_idx = FFMIN(i, (nb_bufs - 1)); + int img_idx = FFMIN(i, (nb_images - 1)); + FFVkBuffer *vkbuf = (FFVkBuffer *)bufs[buf_idx]->data; - get_plane_wh(&p_w, &p_h, swf->format, swf->width, swf->height, i); + uint32_t orig_stride = region[i].bufferRowLength; + region[i].bufferRowLength /= desc->comp[i].step; + region[i].imageSubresource.aspectMask = plane_aspect[(planes != nb_images) + + i*(planes != nb_images)]; - av_image_copy_plane_uc_from(swf->data[i], swf->linesize[i], - (const uint8_t *)tmp.data[i], tmp.linesize[i], - FFMIN(tmp.linesize[i], FFABS(swf->linesize[i])), - p_h); - } + if (upload) + vk->CmdCopyBufferToImage(cmd_buf, vkbuf->buf, + hwf_vk->img[img_idx], + img_bar[img_idx].newLayout, + 1, ®ion[i]); + else + vk->CmdCopyImageToBuffer(cmd_buf, hwf_vk->img[img_idx], + img_bar[img_idx].newLayout, + vkbuf->buf, + 1, ®ion[i]); - if ((err = ff_vk_unmap_buffers(&p->vkctx, vkbufs, planes, 1))) - goto end; + region[i].bufferRowLength = orig_stride; + } + + err = ff_vk_exec_submit(&p->vkctx, exec); + if (err < 0) { + ff_vk_exec_discard_deps(&p->vkctx, exec); + } else if (!upload) { + ff_vk_exec_wait(&p->vkctx, exec); + if (!host_mapped) + err = copy_buffer_data(hwfc, bufs[0], swf, region, planes, 0); } end: - for (int i = 0; i < planes; i++) + for (int i = 0; i < nb_bufs; i++) av_buffer_unref(&bufs[i]); return err; @@ -3588,7 +4195,7 @@ static int vulkan_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, if (src->hw_frames_ctx) return AVERROR(ENOSYS); else - return vulkan_transfer_data(hwfc, dst, src, 0); + return vulkan_transfer_frame(hwfc, (AVFrame *)src, dst, 1); } } @@ -3705,7 +4312,7 @@ static int vulkan_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, if (dst->hw_frames_ctx) return AVERROR(ENOSYS); else - return vulkan_transfer_data(hwfc, src, dst, 1); + return vulkan_transfer_frame(hwfc, dst, (AVFrame *)src, 0); } } diff --git a/libavutil/hwcontext_vulkan.h b/libavutil/hwcontext_vulkan.h index 895794c86..2688a4757 100644 --- a/libavutil/hwcontext_vulkan.h +++ b/libavutil/hwcontext_vulkan.h @@ -26,9 +26,24 @@ #include "pixfmt.h" #include "frame.h" +#include "hwcontext.h" typedef struct AVVkFrame AVVkFrame; +typedef struct AVVulkanDeviceQueueFamily { + /* Queue family index */ + int idx; + /* Number of queues in the queue family in use */ + int num; + /* Queue family capabilities. Must be non-zero. + * Flags may be removed to indicate the queue family may not be used + * for a given purpose. */ + VkQueueFlagBits flags; + /* Vulkan implementations are allowed to list multiple video queues + * which differ in what they can encode or decode. */ + VkVideoCodecOperationFlagBitsKHR video_caps; +} AVVulkanDeviceQueueFamily; + /** * @file * API-specific header for AV_HWDEVICE_TYPE_VULKAN. @@ -48,9 +63,8 @@ typedef struct AVVulkanDeviceContext { const VkAllocationCallbacks *alloc; /** - * Pointer to the instance-provided vkGetInstanceProcAddr loading function. - * If NULL, will pick either libvulkan or libvolk, depending on libavutil's - * compilation settings, and set this field. + * Pointer to a vkGetInstanceProcAddr loading function. + * If unset, will dynamically load and use libvulkan. */ PFN_vkGetInstanceProcAddr get_proc_addr; @@ -98,6 +112,7 @@ typedef struct AVVulkanDeviceContext { const char * const *enabled_dev_extensions; int nb_enabled_dev_extensions; +#if FF_API_VULKAN_FIXED_QUEUES /** * Queue family index for graphics operations, and the number of queues * enabled for it. If unavaiable, will be set to -1. Not required. @@ -105,21 +120,27 @@ typedef struct AVVulkanDeviceContext { * queue family, or pick the one with the least unrelated flags set. * Queue indices here may overlap if a queue has to share capabilities. */ + attribute_deprecated int queue_family_index; + attribute_deprecated int nb_graphics_queues; /** * Queue family index for transfer operations and the number of queues * enabled. Required. */ + attribute_deprecated int queue_family_tx_index; + attribute_deprecated int nb_tx_queues; /** * Queue family index for compute operations and the number of queues * enabled. Required. */ + attribute_deprecated int queue_family_comp_index; + attribute_deprecated int nb_comp_queues; /** @@ -127,7 +148,9 @@ typedef struct AVVulkanDeviceContext { * If the device doesn't support such, queue_family_encode_index will be -1. * Not required. */ + attribute_deprecated int queue_family_encode_index; + attribute_deprecated int nb_encode_queues; /** @@ -135,8 +158,11 @@ typedef struct AVVulkanDeviceContext { * If the device doesn't support such, queue_family_decode_index will be -1. * Not required. */ + attribute_deprecated int queue_family_decode_index; + attribute_deprecated int nb_decode_queues; +#endif /** * Locks a queue, preventing other threads from submitting any command @@ -150,6 +176,17 @@ typedef struct AVVulkanDeviceContext { * Similar to lock_queue(), unlocks a queue. Must only be called after locking. */ void (*unlock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index); + + /** + * Queue families used. Must be preferentially ordered. List may contain + * duplicates. + * + * For compatibility reasons, all the enabled queue families listed above + * (queue_family_(tx/comp/encode/decode)_index) must also be included in + * this list until they're removed after deprecation. + */ + AVVulkanDeviceQueueFamily qf[64]; + int nb_qf; } AVVulkanDeviceContext; /** diff --git a/libavutil/iamf.c b/libavutil/iamf.c index 14f49cba9..791954d95 100644 --- a/libavutil/iamf.c +++ b/libavutil/iamf.c @@ -64,8 +64,8 @@ child_type *av_iamf_ ## parent_name ## _add_ ## child_name(parent_type *parent_n // #define OFFSET(x) offsetof(AVIAMFMixGain, x) static const AVOption mix_gain_options[] = { - { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration), AV_OPT_TYPE_INT, {.i64 = 1 }, 1, UINT_MAX, FLAGS }, - { "animation_type", "set animation_type", OFFSET(animation_type), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, FLAGS }, + { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration), AV_OPT_TYPE_UINT, {.i64 = 1 }, 1, UINT_MAX, FLAGS }, + { "animation_type", "set animation_type", OFFSET(animation_type), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, 2, FLAGS }, { "start_point_value", "set start_point_value", OFFSET(start_point_value), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, -128.0, 128.0, FLAGS }, { "end_point_value", "set end_point_value", OFFSET(end_point_value), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, -128.0, 128.0, FLAGS }, { "control_point_value", "set control_point_value", OFFSET(control_point_value), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, -128.0, 128.0, FLAGS }, @@ -83,8 +83,8 @@ static const AVClass mix_gain_class = { #undef OFFSET #define OFFSET(x) offsetof(AVIAMFDemixingInfo, x) static const AVOption demixing_info_options[] = { - { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration), AV_OPT_TYPE_INT, {.i64 = 1 }, 1, UINT_MAX, FLAGS }, - { "dmixp_mode", "set dmixp_mode", OFFSET(dmixp_mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 6, FLAGS }, + { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration), AV_OPT_TYPE_UINT, {.i64 = 1 }, 1, UINT_MAX, FLAGS }, + { "dmixp_mode", "set dmixp_mode", OFFSET(dmixp_mode), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, 6, FLAGS }, { NULL }, }; @@ -98,7 +98,7 @@ static const AVClass demixing_info_class = { #undef OFFSET #define OFFSET(x) offsetof(AVIAMFReconGain, x) static const AVOption recon_gain_options[] = { - { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration), AV_OPT_TYPE_INT, {.i64 = 1 }, 1, UINT_MAX, FLAGS }, + { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration), AV_OPT_TYPE_UINT, {.i64 = 1 }, 1, UINT_MAX, FLAGS }, { NULL }, }; @@ -112,10 +112,10 @@ static const AVClass recon_gain_class = { #undef OFFSET #define OFFSET(x) offsetof(AVIAMFParamDefinition, x) static const AVOption param_definition_options[] = { - { "parameter_id", "set parameter_id", OFFSET(parameter_id), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, - { "parameter_rate", "set parameter_rate", OFFSET(parameter_rate), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, - { "duration", "set duration", OFFSET(duration), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, - { "constant_subblock_duration", "set constant_subblock_duration", OFFSET(constant_subblock_duration), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, + { "parameter_id", "set parameter_id", OFFSET(parameter_id), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, + { "parameter_rate", "set parameter_rate", OFFSET(parameter_rate), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, + { "duration", "set duration", OFFSET(duration), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, + { "constant_subblock_duration", "set constant_subblock_duration", OFFSET(constant_subblock_duration), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, { NULL }, }; @@ -289,7 +289,7 @@ static const AVOption audio_element_options[] = { { .i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL }, .unit = "audio_element_type" }, { "scene", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE }, .unit = "audio_element_type" }, - { "default_w", "set default_w", OFFSET(default_w), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 10, FLAGS }, + { "default_w", "set default_w", OFFSET(default_w), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, 10, FLAGS }, { NULL }, }; diff --git a/libavutil/iamf.h b/libavutil/iamf.h index 93785d9fe..1fa73893c 100644 --- a/libavutil/iamf.h +++ b/libavutil/iamf.h @@ -37,20 +37,29 @@ #include "rational.h" /** + * @defgroup lavu_iamf Immersive Audio Model and Formats + * @ingroup lavu_audio + * + * Immersive Audio Model and Formats related functions and defines + * * @defgroup lavu_iamf_params Parameter Definition + * @ingroup lavu_iamf * @{ * Parameters as defined in section 3.6.1 and 3.8 of IAMF. * @} + * * @defgroup lavu_iamf_audio Audio Element + * @ingroup lavu_iamf * @{ * Audio Elements as defined in section 3.6 of IAMF. * @} + * * @defgroup lavu_iamf_mix Mix Presentation + * @ingroup lavu_iamf * @{ * Mix Presentations as defined in section 3.7 of IAMF. * @} * - * @} * @addtogroup lavu_iamf_params * @{ */ @@ -673,6 +682,7 @@ AVIAMFSubmixLayout *av_iamf_submix_add_layout(AVIAMFSubmix *submix); * upon return, *mix_presentation will be set to NULL. */ void av_iamf_mix_presentation_free(AVIAMFMixPresentation **mix_presentation); + /** * @} */ diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c index b5413aa41..7b88738e2 100644 --- a/libavutil/imgutils.c +++ b/libavutil/imgutils.c @@ -25,10 +25,10 @@ #include "common.h" #include "imgutils.h" #include "imgutils_internal.h" -#include "internal.h" #include "intreadwrite.h" #include "log.h" #include "mathematics.h" +#include "mem.h" #include "pixdesc.h" #include "rational.h" diff --git a/libavutil/imgutils_internal.h b/libavutil/imgutils_internal.h index d51585841..3e47731a5 100644 --- a/libavutil/imgutils_internal.h +++ b/libavutil/imgutils_internal.h @@ -22,6 +22,10 @@ #include #include +#include "pixfmt.h" + +int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt); + int ff_image_copy_plane_uc_from_x86(uint8_t *dst, ptrdiff_t dst_linesize, const uint8_t *src, ptrdiff_t src_linesize, ptrdiff_t bytewidth, int height); diff --git a/libavutil/internal.h b/libavutil/internal.h index 461c0df9a..ac1af367e 100644 --- a/libavutil/internal.h +++ b/libavutil/internal.h @@ -40,8 +40,8 @@ #include #include "config.h" #include "attributes.h" +#include "libm.h" #include "macros.h" -#include "pixfmt.h" #ifndef attribute_align_arg #if ARCH_X86_32 && AV_GCC_VERSION_AT_LEAST(4,2) @@ -74,16 +74,6 @@ #endif -#define FF_MEMORY_POISON 0x2a - -/* Check if the hard coded offset of a struct member still matches reality. - * Induce a compilation failure if not. - */ -#define AV_CHECK_OFFSET(s, m, o) struct check_##o { \ - int x_##o[offsetof(s, m) == o? 1: -1]; \ - } - - #define FF_ALLOC_TYPED_ARRAY(p, nelem) (p = av_malloc_array(nelem, sizeof(*p))) #define FF_ALLOCZ_TYPED_ARRAY(p, nelem) (p = av_calloc(nelem, sizeof(*p))) @@ -94,8 +84,6 @@ */ #define FF_FIELD_AT(type, off, obj) (*(type *)((char *)&(obj) + (off))) -#include "libm.h" - /** * Return NULL if CONFIG_SMALL is true, otherwise the argument * without modification. Used to disable the definition of strings. @@ -163,8 +151,6 @@ void avpriv_request_sample(void *avc, #define SUINT32 uint32_t #endif -int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt); - static av_always_inline av_const int avpriv_mirror(int x, int w) { if (!w) diff --git a/libavutil/intmath.h b/libavutil/intmath.h index c54d23b7b..52e11a8d5 100644 --- a/libavutil/intmath.h +++ b/libavutil/intmath.h @@ -119,7 +119,7 @@ static av_always_inline av_const int ff_ctz_c(int v) 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; - return debruijn_ctz32[(uint32_t)((v & -v) * 0x077CB531U) >> 27]; + return debruijn_ctz32[(uint32_t)((v & -(uint32_t)v) * 0x077CB531U) >> 27]; } #endif @@ -135,7 +135,7 @@ static av_always_inline av_const int ff_ctzll_c(long long v) 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 }; - return debruijn_ctz64[(uint64_t)((v & -v) * 0x022FDD63CC95386DU) >> 58]; + return debruijn_ctz64[(uint64_t)((v & -(uint64_t)v) * 0x022FDD63CC95386DU) >> 58]; } #endif diff --git a/libavutil/intreadwrite.h b/libavutil/intreadwrite.h index d0a5773b5..ffd15a150 100644 --- a/libavutil/intreadwrite.h +++ b/libavutil/intreadwrite.h @@ -64,10 +64,8 @@ typedef union { #include "config.h" -#if ARCH_ARM -# include "arm/intreadwrite.h" -#elif ARCH_AVR32 -# include "avr32/intreadwrite.h" +#if ARCH_AARCH64 +# include "aarch64/intreadwrite.h" #elif ARCH_MIPS # include "mips/intreadwrite.h" #elif ARCH_PPC @@ -543,9 +541,41 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; #if AV_HAVE_BIGENDIAN # define AV_RLA(s, p) av_bswap##s(AV_RN##s##A(p)) # define AV_WLA(s, p, v) AV_WN##s##A(p, av_bswap##s(v)) +# define AV_RBA(s, p) AV_RN##s##A(p) +# define AV_WBA(s, p, v) AV_WN##s##A(p, v) #else # define AV_RLA(s, p) AV_RN##s##A(p) # define AV_WLA(s, p, v) AV_WN##s##A(p, v) +# define AV_RBA(s, p) av_bswap##s(AV_RN##s##A(p)) +# define AV_WBA(s, p, v) AV_WN##s##A(p, av_bswap##s(v)) +#endif + +#ifndef AV_RL16A +# define AV_RL16A(p) AV_RLA(16, p) +#endif +#ifndef AV_WL16A +# define AV_WL16A(p, v) AV_WLA(16, p, v) +#endif + +#ifndef AV_RB16A +# define AV_RB16A(p) AV_RBA(16, p) +#endif +#ifndef AV_WB16A +# define AV_WB16A(p, v) AV_WBA(16, p, v) +#endif + +#ifndef AV_RL32A +# define AV_RL32A(p) AV_RLA(32, p) +#endif +#ifndef AV_WL32A +# define AV_WL32A(p, v) AV_WLA(32, p, v) +#endif + +#ifndef AV_RB32A +# define AV_RB32A(p) AV_RBA(32, p) +#endif +#ifndef AV_WB32A +# define AV_WB32A(p, v) AV_WBA(32, p, v) #endif #ifndef AV_RL64A @@ -555,6 +585,13 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; # define AV_WL64A(p, v) AV_WLA(64, p, v) #endif +#ifndef AV_RB64A +# define AV_RB64A(p) AV_RBA(64, p) +#endif +#ifndef AV_WB64A +# define AV_WB64A(p, v) AV_WBA(64, p, v) +#endif + /* * The AV_COPYxxU macros are suitable for copying data to/from unaligned * memory locations. diff --git a/libavutil/lls.c b/libavutil/lls.c index c1e038daf..fe8f55976 100644 --- a/libavutil/lls.c +++ b/libavutil/lls.c @@ -30,6 +30,7 @@ #include "config.h" #include "attributes.h" +#include "float_dsp.h" #include "lls.h" static void update_lls(LLSModel *m, const double *var) @@ -102,13 +103,7 @@ void avpriv_solve_lls(LLSModel *m, double threshold, unsigned short min_order) static double evaluate_lls(LLSModel *m, const double *param, int order) { - int i; - double out = 0; - - for (i = 0; i <= order; i++) - out += param[i] * m->coeff[order][i]; - - return out; + return ff_scalarproduct_double_c(m->coeff[order], param, order + 1); } av_cold void avpriv_init_lls(LLSModel *m, int indep_count) @@ -117,7 +112,9 @@ av_cold void avpriv_init_lls(LLSModel *m, int indep_count) m->indep_count = indep_count; m->update_lls = update_lls; m->evaluate_lls = evaluate_lls; -#if ARCH_X86 +#if ARCH_RISCV + ff_init_lls_riscv(m); +#elif ARCH_X86 ff_init_lls_x86(m); #endif } diff --git a/libavutil/lls.h b/libavutil/lls.h index 070927582..7acef4eff 100644 --- a/libavutil/lls.h +++ b/libavutil/lls.h @@ -57,6 +57,7 @@ typedef struct LLSModel { } LLSModel; void avpriv_init_lls(LLSModel *m, int indep_count); +void ff_init_lls_riscv(LLSModel *m); void ff_init_lls_x86(LLSModel *m); void avpriv_solve_lls(LLSModel *m, double threshold, unsigned short min_order); diff --git a/libavutil/loongarch/cpu.c b/libavutil/loongarch/cpu.c index cad8504fd..d8c67ad7c 100644 --- a/libavutil/loongarch/cpu.c +++ b/libavutil/loongarch/cpu.c @@ -28,7 +28,7 @@ static int cpu_flags_getauxval(void) { int flags = 0; - int flag = (int)getauxval(AT_HWCAP); + int flag = (int)ff_getauxval(AT_HWCAP); if (flag & LA_HWCAP_LSX) flags |= AV_CPU_FLAG_LSX; diff --git a/libavutil/macos_kperf.c b/libavutil/macos_kperf.c index 9fb047eee..b2c1d164a 100644 --- a/libavutil/macos_kperf.c +++ b/libavutil/macos_kperf.c @@ -67,14 +67,15 @@ KPERF_LIST #define KPC_CLASS_POWER_MASK (1 << 2) #define KPC_CLASS_RAWPMU_MASK (1 << 3) -#define COUNTERS_COUNT 10 +#define KPC_MAX_COUNTERS 32 #define CONFIG_COUNT 8 #define KPC_MASK (KPC_CLASS_CONFIGURABLE_MASK | KPC_CLASS_FIXED_MASK) static void kperf_init(void) { - uint64_t config[COUNTERS_COUNT] = {0}; + uint64_t config[CONFIG_COUNT] = {0}; void *kperf = NULL; + uint32_t n; av_assert0(kperf = dlopen("/System/Library/PrivateFrameworks/kperf.framework/Versions/A/kperf", RTLD_LAZY)); @@ -82,8 +83,10 @@ static void kperf_init(void) KPERF_LIST #undef F - av_assert0(kpc_get_counter_count(KPC_MASK) == COUNTERS_COUNT); - av_assert0(kpc_get_config_count(KPC_MASK) == CONFIG_COUNT); + n = kpc_get_counter_count(KPC_MASK); + av_assert0(n <= KPC_MAX_COUNTERS); + n = kpc_get_config_count(KPC_MASK); + av_assert0(n <= CONFIG_COUNT); config[0] = CPMU_CORE_CYCLE | CFGWORD_EL0A64EN_MASK; // config[3] = CPMU_INST_BRANCH | CFGWORD_EL0A64EN_MASK; @@ -104,8 +107,9 @@ void ff_kperf_init(void) uint64_t ff_kperf_cycles(void) { - uint64_t counters[COUNTERS_COUNT]; - if (kpc_get_thread_counters(0, COUNTERS_COUNT, counters)) { + uint64_t counters[KPC_MAX_COUNTERS]; + + if (kpc_get_thread_counters(0, KPC_MAX_COUNTERS, counters)) { return -1; } diff --git a/libavutil/mastering_display_metadata.c b/libavutil/mastering_display_metadata.c index 606934761..dd37ed7d0 100644 --- a/libavutil/mastering_display_metadata.c +++ b/libavutil/mastering_display_metadata.c @@ -18,15 +18,41 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include "mastering_display_metadata.h" #include "mem.h" +static void get_defaults(AVMasteringDisplayMetadata *mastering) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + mastering->display_primaries[i][j] = (AVRational) { 0, 1 }; + mastering->white_point[0] = + mastering->white_point[1] = + mastering->min_luminance = + mastering->max_luminance = (AVRational) { 0, 1 }; +} + AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void) { - return av_mallocz(sizeof(AVMasteringDisplayMetadata)); + return av_mastering_display_metadata_alloc_size(NULL); +} + +AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc_size(size_t *size) +{ + AVMasteringDisplayMetadata *mastering = av_mallocz(sizeof(AVMasteringDisplayMetadata)); + if (!mastering) + return NULL; + + get_defaults(mastering); + + if (size) + *size = sizeof(*mastering); + + return mastering; } AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame) @@ -38,6 +64,7 @@ AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFra return NULL; memset(side_data->data, 0, sizeof(AVMasteringDisplayMetadata)); + get_defaults((AVMasteringDisplayMetadata *)side_data->data); return (AVMasteringDisplayMetadata *)side_data->data; } diff --git a/libavutil/mastering_display_metadata.h b/libavutil/mastering_display_metadata.h index c23b07c3c..52fcef9e3 100644 --- a/libavutil/mastering_display_metadata.h +++ b/libavutil/mastering_display_metadata.h @@ -77,6 +77,15 @@ typedef struct AVMasteringDisplayMetadata { */ AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void); +/** + * Allocate an AVMasteringDisplayMetadata structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVMasteringDisplayMetadata filled with default values or NULL + * on failure. + */ +AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc_size(size_t *size); + /** * Allocate a complete AVMasteringDisplayMetadata and add it to the frame. * diff --git a/libavutil/mem.c b/libavutil/mem.c index 62163b4cb..b205d3fb2 100644 --- a/libavutil/mem.c +++ b/libavutil/mem.c @@ -64,12 +64,14 @@ void free(void *ptr); #define ALIGN (HAVE_SIMD_ALIGN_64 ? 64 : (HAVE_SIMD_ALIGN_32 ? 32 : 16)) +#define FF_MEMORY_POISON 0x2a + /* NOTE: if you want to override these functions with your own * implementations (not recommended) you have to link libav* as * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags. * Note that this will cost performance. */ -static atomic_size_t max_alloc_size = ATOMIC_VAR_INIT(INT_MAX); +static atomic_size_t max_alloc_size = INT_MAX; void av_max_alloc(size_t max){ atomic_store_explicit(&max_alloc_size, max, memory_order_relaxed); diff --git a/libavutil/mips/cpu.c b/libavutil/mips/cpu.c index 59619d54d..2009c70f7 100644 --- a/libavutil/mips/cpu.c +++ b/libavutil/mips/cpu.c @@ -34,7 +34,7 @@ static int cpucfg_available(void) { - return getauxval(AT_HWCAP) & HWCAP_LOONGSON_CPUCFG; + return ff_getauxval(AT_HWCAP) & HWCAP_LOONGSON_CPUCFG; } /* Most toolchains have no CPUCFG support yet */ diff --git a/libavutil/opt.c b/libavutil/opt.c index 685206f41..93f2bb132 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -29,10 +29,10 @@ #include "avassert.h" #include "avstring.h" #include "channel_layout.h" -#include "common.h" #include "dict.h" #include "eval.h" #include "log.h" +#include "mem.h" #include "parseutils.h" #include "pixdesc.h" #include "mathematics.h" @@ -62,6 +62,7 @@ static const size_t opt_elem_size[] = { [AV_OPT_TYPE_FLAGS] = sizeof(unsigned), [AV_OPT_TYPE_INT] = sizeof(int), [AV_OPT_TYPE_INT64] = sizeof(int64_t), + [AV_OPT_TYPE_UINT] = sizeof(unsigned), [AV_OPT_TYPE_UINT64] = sizeof(uint64_t), [AV_OPT_TYPE_DOUBLE] = sizeof(double), [AV_OPT_TYPE_FLOAT] = sizeof(float), @@ -97,6 +98,7 @@ static int opt_is_pod(enum AVOptionType type) case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_COLOR: case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_UINT: return 1; } return 0; @@ -120,9 +122,9 @@ static unsigned *opt_array_pcount(const void *parray) return (unsigned *)((const void * const *)parray + 1); } -static void opt_free_elem(const AVOption *o, void *ptr) +static void opt_free_elem(enum AVOptionType type, void *ptr) { - switch (TYPE_BASE(o->type)) { + switch (TYPE_BASE(type)) { case AV_OPT_TYPE_STRING: case AV_OPT_TYPE_BINARY: av_freep(ptr); @@ -144,7 +146,7 @@ static void opt_free_elem(const AVOption *o, void *ptr) static void opt_free_array(const AVOption *o, void *parray, unsigned *count) { for (unsigned i = 0; i < *count; i++) - opt_free_elem(o, opt_array_pelem(o, *(void **)parray, i)); + opt_free_elem(o->type, opt_array_pelem(o, *(void **)parray, i)); av_freep(parray); *count = 0; @@ -152,7 +154,7 @@ static void opt_free_array(const AVOption *o, void *parray, unsigned *count) static int read_number(const AVOption *o, const void *dst, double *num, int *den, int64_t *intnum) { - switch (o->type) { + switch (TYPE_BASE(o->type)) { case AV_OPT_TYPE_FLAGS: *intnum = *(unsigned int*)dst; return 0; @@ -166,6 +168,9 @@ static int read_number(const AVOption *o, const void *dst, double *num, int *den case AV_OPT_TYPE_INT: *intnum = *(int *)dst; return 0; + case AV_OPT_TYPE_UINT: + *intnum = *(unsigned int *)dst; + return 0; case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: @@ -219,6 +224,7 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int case AV_OPT_TYPE_BOOL: case AV_OPT_TYPE_FLAGS: case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: *(int *)dst = llrint(num / den) * intnum; break; case AV_OPT_TYPE_DURATION: @@ -309,6 +315,8 @@ static int set_string_binary(void *obj, const AVOption *o, const char *val, uint static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **dst) { av_freep(dst); + if (!val) + return 0; *dst = av_strdup(val); return *dst ? 0 : AVERROR(ENOMEM); } @@ -317,6 +325,7 @@ static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **d opt->type == AV_OPT_TYPE_UINT64 || \ opt->type == AV_OPT_TYPE_CONST || \ opt->type == AV_OPT_TYPE_FLAGS || \ + opt->type == AV_OPT_TYPE_UINT || \ opt->type == AV_OPT_TYPE_INT) \ ? opt->default_val.i64 \ : opt->default_val.dbl) @@ -603,6 +612,7 @@ static int opt_set_elem(void *obj, void *target_obj, const AVOption *o, return set_string_binary(obj, o, val, dst); case AV_OPT_TYPE_FLAGS: case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_FLOAT: @@ -765,6 +775,7 @@ int av_opt_eval_ ## name(void *obj, const AVOption *o, \ OPT_EVAL_NUMBER(flags, AV_OPT_TYPE_FLAGS, int) OPT_EVAL_NUMBER(int, AV_OPT_TYPE_INT, int) +OPT_EVAL_NUMBER(uint, AV_OPT_TYPE_UINT, unsigned) OPT_EVAL_NUMBER(int64, AV_OPT_TYPE_INT64, int64_t) OPT_EVAL_NUMBER(float, AV_OPT_TYPE_FLOAT, float) OPT_EVAL_NUMBER(double, AV_OPT_TYPE_DOUBLE, double) @@ -924,9 +935,8 @@ int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, dst = (AVDictionary **)(((uint8_t *)target_obj) + o->offset); av_dict_free(dst); - av_dict_copy(dst, val, 0); - return 0; + return av_dict_copy(dst, val, 0); } int av_opt_set_chlayout(void *obj, const char *name, @@ -939,6 +949,8 @@ int av_opt_set_chlayout(void *obj, const char *name, if (!o || !target_obj) return AVERROR_OPTION_NOT_FOUND; + if (o->flags & AV_OPT_FLAG_READONLY) + return AVERROR(EINVAL); dst = (AVChannelLayout*)((uint8_t*)target_obj + o->offset); @@ -981,7 +993,7 @@ static void format_duration(char *buf, size_t size, int64_t d) } static int opt_get_elem(const AVOption *o, uint8_t **pbuf, size_t buf_len, - void *dst, int search_flags) + const void *dst, int search_flags) { int ret; @@ -995,6 +1007,9 @@ static int opt_get_elem(const AVOption *o, uint8_t **pbuf, size_t buf_len, case AV_OPT_TYPE_INT: ret = snprintf(*pbuf, buf_len, "%d", *(int *)dst); break; + case AV_OPT_TYPE_UINT: + ret = snprintf(*pbuf, buf_len, "%u", *(unsigned *)dst); + break; case AV_OPT_TYPE_INT64: ret = snprintf(*pbuf, buf_len, "%"PRId64, *(int64_t *)dst); break; @@ -1263,18 +1278,7 @@ int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_ int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val) { - int64_t intnum = 1; - double num = 1; - int ret, den = 1; - - if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) - return ret; - - if (num == 1.0 && (int)intnum == intnum) - *out_val = (AVRational) { intnum, den }; - else - *out_val = av_d2q(num * intnum / den, 1 << 24); - return 0; + return av_opt_get_q(obj, name, search_flags, out_val); } static int get_format(void *obj, const char *name, int search_flags, int *out_fmt, @@ -1333,9 +1337,8 @@ int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDiction return AVERROR(EINVAL); src = *(AVDictionary **)(((uint8_t *)target_obj) + o->offset); - av_dict_copy(out_val, src, 0); - return 0; + return av_dict_copy(out_val, src, 0); } int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name) @@ -1442,6 +1445,7 @@ static void log_type(void *av_log_obj, const AVOption *o, [AV_OPT_TYPE_FLAGS] = "", [AV_OPT_TYPE_INT] = "", [AV_OPT_TYPE_INT64] = "", + [AV_OPT_TYPE_UINT] = "", [AV_OPT_TYPE_UINT64] = "", [AV_OPT_TYPE_DOUBLE] = "", [AV_OPT_TYPE_FLOAT] = "", @@ -1513,6 +1517,7 @@ static void log_default(void *obj, void *av_log_obj, const AVOption *opt) av_log(av_log_obj, AV_LOG_INFO, "%s", buf); break; } + case AV_OPT_TYPE_UINT: case AV_OPT_TYPE_INT: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_INT64: { @@ -1598,6 +1603,7 @@ static void opt_list(void *obj, void *av_log_obj, const char *unit, if (av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) >= 0) { switch (opt->type) { case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_DOUBLE: @@ -1674,6 +1680,7 @@ void av_opt_set_defaults2(void *s, int mask, int flags) case AV_OPT_TYPE_BOOL: case AV_OPT_TYPE_FLAGS: case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_DURATION: @@ -1859,7 +1866,6 @@ int av_opt_set_from_string(void *ctx, const char *opts, { int ret, count = 0; const char *dummy_shorthand = NULL; - char *av_uninit(parsed_key), *av_uninit(value); const char *key; if (!opts) @@ -1868,6 +1874,7 @@ int av_opt_set_from_string(void *ctx, const char *opts, shorthand = &dummy_shorthand; while (*opts) { + char *parsed_key, *value; ret = av_opt_get_key_value(&opts, key_val_sep, pairs_sep, *shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0, &parsed_key, &value); @@ -1914,7 +1921,7 @@ void av_opt_free(void *obj) if (o->type & AV_OPT_TYPE_FLAG_ARRAY) opt_free_array(o, pitem, opt_array_pcount(pitem)); else - opt_free_elem(o, pitem); + opt_free_elem(o->type, pitem); } } @@ -2026,16 +2033,19 @@ void *av_opt_ptr(const AVClass *class, void *obj, const char *name) static int opt_copy_elem(void *logctx, enum AVOptionType type, void *dst, const void *src) { - uint8_t **dst8 = (uint8_t **)dst; - const uint8_t **src8 = (const uint8_t **)src; - if (type == AV_OPT_TYPE_STRING) { - if (*dst8 != *src8) - av_freep(dst8); - *dst8 = av_strdup(*src8); - if (*src8 && !*dst8) - return AVERROR(ENOMEM); + const char *src_str = *(const char *const *)src; + char **dstp = (char **)dst; + if (*dstp != src_str) + av_freep(dstp); + if (src_str) { + *dstp = av_strdup(src_str); + if (!*dstp) + return AVERROR(ENOMEM); + } } else if (type == AV_OPT_TYPE_BINARY) { + const uint8_t *const *src8 = (const uint8_t *const *)src; + uint8_t **dst8 = (uint8_t **)dst; int len = *(const int *)(src8 + 1); if (*dst8 != *src8) av_freep(dst8); @@ -2048,12 +2058,12 @@ static int opt_copy_elem(void *logctx, enum AVOptionType type, } else if (type == AV_OPT_TYPE_CONST) { // do nothing } else if (type == AV_OPT_TYPE_DICT) { - AVDictionary **sdict = (AVDictionary **)src; - AVDictionary **ddict = (AVDictionary **)dst; - if (*sdict != *ddict) - av_dict_free(ddict); - *ddict = NULL; - return av_dict_copy(ddict, *sdict, 0); + const AVDictionary *sdict = *(const AVDictionary * const *)src; + AVDictionary **ddictp = (AVDictionary **)dst; + if (sdict != *ddictp) + av_dict_free(ddictp); + *ddictp = NULL; + return av_dict_copy(ddictp, sdict, 0); } else if (type == AV_OPT_TYPE_CHLAYOUT) { if (dst != src) return av_channel_layout_copy(dst, src); @@ -2128,6 +2138,299 @@ int av_opt_copy(void *dst, const void *src) return ret; } +int av_opt_get_array_size(void *obj, const char *name, int search_flags, + unsigned int *out_val) +{ + void *target_obj, *parray; + const AVOption *o; + + o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (!(o->type & AV_OPT_TYPE_FLAG_ARRAY)) + return AVERROR(EINVAL); + + parray = (uint8_t *)target_obj + o->offset; + *out_val = *opt_array_pcount(parray); + + return 0; +} + +int av_opt_get_array(void *obj, const char *name, int search_flags, + unsigned int start_elem, unsigned int nb_elems, + enum AVOptionType out_type, void *out_val) +{ + const size_t elem_size_out = opt_elem_size[TYPE_BASE(out_type)]; + + const AVOption *o; + void *target_obj; + + const void *parray; + unsigned array_size; + + int ret; + + o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (!(o->type & AV_OPT_TYPE_FLAG_ARRAY) || + (out_type & AV_OPT_TYPE_FLAG_ARRAY)) + return AVERROR(EINVAL); + + parray = (uint8_t *)target_obj + o->offset; + array_size = *opt_array_pcount(parray); + + if (start_elem >= array_size || + array_size - start_elem < nb_elems) + return AVERROR(EINVAL); + + for (unsigned i = 0; i < nb_elems; i++) { + const void *src = opt_array_pelem(o, *(void**)parray, start_elem + i); + void *dst = (uint8_t*)out_val + i * elem_size_out; + + if (out_type == TYPE_BASE(o->type)) { + ret = opt_copy_elem(obj, out_type, dst, src); + if (ret < 0) + goto fail; + } else if (out_type == AV_OPT_TYPE_STRING) { + uint8_t buf[128], *out = buf; + + ret = opt_get_elem(o, &out, sizeof(buf), src, search_flags); + if (ret < 0) + goto fail; + + if (out == buf) { + out = av_strdup(buf); + if (!out) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + *(uint8_t**)dst = out; + } else if (out_type == AV_OPT_TYPE_INT64 || + out_type == AV_OPT_TYPE_DOUBLE || + out_type == AV_OPT_TYPE_RATIONAL) { + double num = 1.0; + int den = 1; + int64_t intnum = 1; + + ret = read_number(o, src, &num, &den, &intnum); + if (ret < 0) + goto fail; + + switch (out_type) { + case AV_OPT_TYPE_INT64: + *(int64_t*)dst = (num == den) ? intnum : num * intnum / den; + break; + case AV_OPT_TYPE_DOUBLE: + *(double*)dst = num * intnum / den; + break; + case AV_OPT_TYPE_RATIONAL: + *(AVRational*)dst = (num == 1.0 && (int)intnum == intnum) ? + (AVRational){ intnum, den } : + av_d2q(num * intnum / den, 1<<24); + break; + default: av_assert0(0); + } + } else + return AVERROR(ENOSYS); + } + + return 0; +fail: + for (unsigned i = 0; i < nb_elems; i++) + opt_free_elem(out_type, (uint8_t*)out_val + i * elem_size_out); + return ret; +} + +int av_opt_set_array(void *obj, const char *name, int search_flags, + unsigned int start_elem, unsigned int nb_elems, + enum AVOptionType val_type, const void *val) +{ + const size_t elem_size_val = opt_elem_size[TYPE_BASE(val_type)]; + + const AVOption *o; + const AVOptionArrayDef *arr; + void *target_obj; + + void *parray; + void *new_elems; + unsigned *array_size, new_size; + size_t elem_size; + + int ret = 0; + + o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (!(o->type & AV_OPT_TYPE_FLAG_ARRAY) || + (val_type & AV_OPT_TYPE_FLAG_ARRAY)) + return AVERROR(EINVAL); + + arr = o->default_val.arr; + parray = (uint8_t *)target_obj + o->offset; + array_size = opt_array_pcount(parray); + elem_size = opt_elem_size[TYPE_BASE(o->type)]; + + if (start_elem > *array_size) + return AVERROR(EINVAL); + + // compute new array size + if (!val) { + if (*array_size - start_elem < nb_elems) + return AVERROR(EINVAL); + + new_size = *array_size - nb_elems; + } else if (search_flags & AV_OPT_ARRAY_REPLACE) { + if (start_elem >= UINT_MAX - nb_elems) + return AVERROR(EINVAL); + + new_size = FFMAX(*array_size, start_elem + nb_elems); + } else { + if (nb_elems >= UINT_MAX - *array_size) + return AVERROR(EINVAL); + + new_size = *array_size + nb_elems; + } + + if (arr && + ((arr->size_max && new_size > arr->size_max) || + (arr->size_min && new_size < arr->size_min))) + return AVERROR(EINVAL); + + // desired operation is shrinking the array + if (!val) { + void *array = *(void**)parray; + + for (unsigned i = 0; i < nb_elems; i++) { + opt_free_elem(o->type, + opt_array_pelem(o, array, start_elem + i)); + } + + if (new_size > 0) { + memmove(opt_array_pelem(o, array, start_elem), + opt_array_pelem(o, array, start_elem + nb_elems), + elem_size * (*array_size - start_elem - nb_elems)); + + array = av_realloc_array(array, new_size, elem_size); + if (!array) + return AVERROR(ENOMEM); + + *(void**)parray = array; + } else + av_freep(parray); + + *array_size = new_size; + + return 0; + } + + // otherwise, desired operation is insert/replace; + // first, store new elements in a separate array to simplify + // rollback on failure + new_elems = av_calloc(nb_elems, elem_size); + if (!new_elems) + return AVERROR(ENOMEM); + + // convert/validate each new element + for (unsigned i = 0; i < nb_elems; i++) { + void *dst = opt_array_pelem(o, new_elems, i); + const void *src = (uint8_t*)val + i * elem_size_val; + + double num = 1.0; + int den = 1; + int64_t intnum = 1; + + if (val_type == TYPE_BASE(o->type)) { + int err; + + ret = opt_copy_elem(obj, val_type, dst, src); + if (ret < 0) + goto fail; + + // validate the range for numeric options + err = read_number(o, dst, &num, &den, &intnum); + if (err >= 0 && TYPE_BASE(o->type) != AV_OPT_TYPE_FLAGS && + (!den || o->max * den < num * intnum || o->min * den > num * intnum)) { + num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN); + av_log(obj, AV_LOG_ERROR, "Cannot set array element %u for " + "parameter '%s': value %f out of range [%g - %g]\n", + start_elem + i, o->name, num, o->min, o->max); + ret = AVERROR(ERANGE); + goto fail; + } + } else if (val_type == AV_OPT_TYPE_STRING) { + ret = opt_set_elem(obj, target_obj, o, *(const char **)src, dst); + if (ret < 0) + goto fail; + } else if (val_type == AV_OPT_TYPE_INT || + val_type == AV_OPT_TYPE_INT64 || + val_type == AV_OPT_TYPE_FLOAT || + val_type == AV_OPT_TYPE_DOUBLE || + val_type == AV_OPT_TYPE_RATIONAL) { + + switch (val_type) { + case AV_OPT_TYPE_INT: intnum = *(int*)src; break; + case AV_OPT_TYPE_INT64: intnum = *(int64_t*)src; break; + case AV_OPT_TYPE_FLOAT: num = *(float*)src; break; + case AV_OPT_TYPE_DOUBLE: num = *(double*)src; break; + case AV_OPT_TYPE_RATIONAL: intnum = ((AVRational*)src)->num; + den = ((AVRational*)src)->den; break; + default: av_assert0(0); + } + + ret = write_number(obj, o, dst, num, den, intnum); + if (ret < 0) + goto fail; + } else { + ret = AVERROR(ENOSYS); + goto fail; + } + } + + // commit new elements to the array + if (start_elem == 0 && nb_elems == new_size) { + // replacing the existing array entirely + opt_free_array(o, parray, array_size); + *(void**)parray = new_elems; + *array_size = nb_elems; + + new_elems = NULL; + nb_elems = 0; + } else { + void *array = av_realloc_array(*(void**)parray, new_size, elem_size); + if (!array) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (search_flags & AV_OPT_ARRAY_REPLACE) { + // free the elements being overwritten + for (unsigned i = start_elem; i < FFMIN(start_elem + nb_elems, *array_size); i++) + opt_free_elem(o->type, opt_array_pelem(o, array, i)); + } else { + // shift existing elements to the end + memmove(opt_array_pelem(o, array, start_elem + nb_elems), + opt_array_pelem(o, array, start_elem), + elem_size * (*array_size - start_elem)); + } + + memcpy((uint8_t*)array + elem_size * start_elem, new_elems, elem_size * nb_elems); + + av_freep(&new_elems); + nb_elems = 0; + + *(void**)parray = array; + *array_size = new_size; + } + +fail: + opt_free_array(o, &new_elems, &nb_elems); + + return ret; +} + int av_opt_query_ranges(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags) { int ret; @@ -2172,6 +2475,7 @@ int av_opt_query_ranges_default(AVOptionRanges **ranges_arg, void *obj, const ch switch (field->type) { case AV_OPT_TYPE_BOOL: case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_PIXEL_FMT: @@ -2276,6 +2580,7 @@ int av_opt_is_set_to_default(void *obj, const AVOption *o) case AV_OPT_TYPE_PIXEL_FMT: case AV_OPT_TYPE_SAMPLE_FMT: case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: @@ -2287,7 +2592,9 @@ int av_opt_is_set_to_default(void *obj, const AVOption *o) if ((ret = av_channel_layout_from_string(&ch_layout, o->default_val.str)) < 0) return ret; } - return !av_channel_layout_compare((AVChannelLayout *)dst, &ch_layout); + ret = !av_channel_layout_compare((AVChannelLayout *)dst, &ch_layout); + av_channel_layout_uninit(&ch_layout); + return ret; } case AV_OPT_TYPE_STRING: str = *(char **)dst; @@ -2381,14 +2688,54 @@ int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_fla return av_opt_is_set_to_default(target, o); } +static int opt_serialize(void *obj, int opt_flags, int flags, int *cnt, + AVBPrint *bprint, const char key_val_sep, const char pairs_sep) +{ + const AVOption *o = NULL; + void *child = NULL; + uint8_t *buf; + int ret; + const char special_chars[] = {pairs_sep, key_val_sep, '\0'}; + + if (flags & AV_OPT_SERIALIZE_SEARCH_CHILDREN) + while (child = av_opt_child_next(obj, child)) { + ret = opt_serialize(child, opt_flags, flags, cnt, bprint, + key_val_sep, pairs_sep); + if (ret < 0) + return ret; + } + + while (o = av_opt_next(obj, o)) { + if (o->type == AV_OPT_TYPE_CONST) + continue; + if ((flags & AV_OPT_SERIALIZE_OPT_FLAGS_EXACT) && o->flags != opt_flags) + continue; + else if (((o->flags & opt_flags) != opt_flags)) + continue; + if (flags & AV_OPT_SERIALIZE_SKIP_DEFAULTS && av_opt_is_set_to_default(obj, o) > 0) + continue; + if ((ret = av_opt_get(obj, o->name, 0, &buf)) < 0) { + av_bprint_finalize(bprint, NULL); + return ret; + } + if (buf) { + if ((*cnt)++) + av_bprint_append_data(bprint, &pairs_sep, 1); + av_bprint_escape(bprint, o->name, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + av_bprint_append_data(bprint, &key_val_sep, 1); + av_bprint_escape(bprint, buf, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + av_freep(&buf); + } + } + + return 0; +} + int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, const char key_val_sep, const char pairs_sep) { - const AVOption *o = NULL; - uint8_t *buf; AVBPrint bprint; int ret, cnt = 0; - const char special_chars[] = {pairs_sep, key_val_sep, '\0'}; if (pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep || pairs_sep == '\\' || key_val_sep == '\\') { @@ -2402,28 +2749,11 @@ int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, *buffer = NULL; av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); - while (o = av_opt_next(obj, o)) { - if (o->type == AV_OPT_TYPE_CONST) - continue; - if ((flags & AV_OPT_SERIALIZE_OPT_FLAGS_EXACT) && o->flags != opt_flags) - continue; - else if (((o->flags & opt_flags) != opt_flags)) - continue; - if (flags & AV_OPT_SERIALIZE_SKIP_DEFAULTS && av_opt_is_set_to_default(obj, o) > 0) - continue; - if ((ret = av_opt_get(obj, o->name, 0, &buf)) < 0) { - av_bprint_finalize(&bprint, NULL); - return ret; - } - if (buf) { - if (cnt++) - av_bprint_append_data(&bprint, &pairs_sep, 1); - av_bprint_escape(&bprint, o->name, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); - av_bprint_append_data(&bprint, &key_val_sep, 1); - av_bprint_escape(&bprint, buf, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); - av_freep(&buf); - } - } + ret = opt_serialize(obj, opt_flags, flags, &cnt, &bprint, + key_val_sep, pairs_sep); + if (ret < 0) + return ret; + ret = av_bprint_finalize(&bprint, buffer); if (ret < 0) return ret; diff --git a/libavutil/opt.h b/libavutil/opt.h index e6013662f..be189f765 100644 --- a/libavutil/opt.h +++ b/libavutil/opt.h @@ -53,6 +53,16 @@ * question is allowed to access the field. This allows us to extend the * semantics of those fields without breaking API compatibility. * + * @section avoptions_scope Scope of AVOptions + * + * AVOptions is designed to support any set of multimedia configuration options + * that can be defined at compile-time. Although it is mainly used to expose + * FFmpeg options, you are welcome to adapt it to your own use case. + * + * No single approach can ever fully solve the problem of configuration, + * but please submit a patch if you believe you have found a problem + * that is best solved by extending AVOptions. + * * @section avoptions_implement Implementing AVOptions * This section describes how to add AVOptions capabilities to a struct. * @@ -230,26 +240,99 @@ * before the file is actually opened. */ +/** + * An option type determines: + * - for native access, the underlying C type of the field that an AVOption + * refers to; + * - for foreign access, the semantics of accessing the option through this API, + * e.g. which av_opt_get_*() and av_opt_set_*() functions can be called, or + * what format will av_opt_get()/av_opt_set() expect/produce. + */ enum AVOptionType{ + /** + * Underlying C type is unsigned int. + */ AV_OPT_TYPE_FLAGS = 1, + /** + * Underlying C type is int. + */ AV_OPT_TYPE_INT, + /** + * Underlying C type is int64_t. + */ AV_OPT_TYPE_INT64, + /** + * Underlying C type is double. + */ AV_OPT_TYPE_DOUBLE, + /** + * Underlying C type is float. + */ AV_OPT_TYPE_FLOAT, + /** + * Underlying C type is a uint8_t* that is either NULL or points to a C + * string allocated with the av_malloc() family of functions. + */ AV_OPT_TYPE_STRING, + /** + * Underlying C type is AVRational. + */ AV_OPT_TYPE_RATIONAL, - AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + /** + * Underlying C type is a uint8_t* that is either NULL or points to an array + * allocated with the av_malloc() family of functions. The pointer is + * immediately followed by an int containing the array length in bytes. + */ + AV_OPT_TYPE_BINARY, + /** + * Underlying C type is AVDictionary*. + */ AV_OPT_TYPE_DICT, + /** + * Underlying C type is uint64_t. + */ AV_OPT_TYPE_UINT64, + /** + * Special option type for declaring named constants. Does not correspond to + * an actual field in the object, offset must be 0. + */ AV_OPT_TYPE_CONST, - AV_OPT_TYPE_IMAGE_SIZE, ///< offset must point to two consecutive integers + /** + * Underlying C type is two consecutive integers. + */ + AV_OPT_TYPE_IMAGE_SIZE, + /** + * Underlying C type is enum AVPixelFormat. + */ AV_OPT_TYPE_PIXEL_FMT, + /** + * Underlying C type is enum AVSampleFormat. + */ AV_OPT_TYPE_SAMPLE_FMT, - AV_OPT_TYPE_VIDEO_RATE, ///< offset must point to AVRational + /** + * Underlying C type is AVRational. + */ + AV_OPT_TYPE_VIDEO_RATE, + /** + * Underlying C type is int64_t. + */ AV_OPT_TYPE_DURATION, + /** + * Underlying C type is uint8_t[4]. + */ AV_OPT_TYPE_COLOR, + /** + * Underlying C type is int. + */ AV_OPT_TYPE_BOOL, + /** + * Underlying C type is AVChannelLayout. + */ AV_OPT_TYPE_CHLAYOUT, + /** + * Underlying C type is unsigned int. + */ + AV_OPT_TYPE_UINT, /** * May be combined with another regular option type to declare an array @@ -535,6 +618,12 @@ const AVClass *av_opt_child_class_iterate(const AVClass *parent, void **iter); */ #define AV_OPT_ALLOW_NULL (1 << 2) +/** + * May be used with av_opt_set_array() to signal that new elements should + * replace the existing ones in the indicated range. + */ +#define AV_OPT_ARRAY_REPLACE (1 << 3) + /** * Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than * one component for certain option types. @@ -786,6 +875,10 @@ int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_ int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags); int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags); int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags); +/** + * @note Any old chlayout present is discarded and replaced with a copy of the new one. The + * caller still owns layout and is responsible for uninitializing it. + */ int av_opt_set_chlayout(void *obj, const char *name, const AVChannelLayout *layout, int search_flags); /** * @note Any old dictionary present is discarded and replaced with a copy of the new one. The @@ -809,6 +902,56 @@ int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, in av_opt_set_bin(obj, name, (const uint8_t *)(val), \ av_int_list_length(val, term) * sizeof(*(val)), flags)) +/** + * Add, replace, or remove elements for an array option. Which of these + * operations is performed depends on the values of val and search_flags. + * + * @param start_elem Index of the first array element to modify; must not be + * larger than array size as returned by + * av_opt_get_array_size(). + * @param nb_elems number of array elements to modify; when val is NULL, + * start_elem+nb_elems must not be larger than array size as + * returned by av_opt_get_array_size() + * + * @param val_type Option type corresponding to the type of val, ignored when val is + * NULL. + * + * The effect of this function will will be as if av_opt_setX() + * was called for each element, where X is specified by type. + * E.g. AV_OPT_TYPE_STRING corresponds to av_opt_set(). + * + * Typically this should be the same as the scalarized type of + * the AVOption being set, but certain conversions are also + * possible - the same as those done by the corresponding + * av_opt_set*() function. E.g. any option type can be set from + * a string, numeric types can be set from int64, double, or + * rational, etc. + * + * @param val Array with nb_elems elements or NULL. + * + * When NULL, nb_elems array elements starting at start_elem are + * removed from the array. Any array elements remaining at the end + * are shifted by nb_elems towards the first element in order to keep + * the array contiguous. + * + * Otherwise (val is non-NULL), the type of val must match the + * underlying C type as documented for val_type. + * + * When AV_OPT_ARRAY_REPLACE is not set in search_flags, the array is + * enlarged by nb_elems, and the contents of val are inserted at + * start_elem. Previously existing array elements from start_elem + * onwards (if present) are shifted by nb_elems away from the first + * element in order to make space for the new elements. + * + * When AV_OPT_ARRAY_REPLACE is set in search_flags, the contents + * of val replace existing array elements from start_elem to + * start_elem+nb_elems (if present). New array size is + * max(start_elem + nb_elems, old array size). + */ +int av_opt_set_array(void *obj, const char *name, int search_flags, + unsigned int start_elem, unsigned int nb_elems, + enum AVOptionType val_type, const void *val); + /** * @} * @} @@ -847,12 +990,56 @@ int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_ int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt); int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt); int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val); +/** + * @param[out] layout The returned layout is a copy of the actual value and must + * be freed with av_channel_layout_uninit() by the caller + */ int av_opt_get_chlayout(void *obj, const char *name, int search_flags, AVChannelLayout *layout); /** * @param[out] out_val The returned dictionary is a copy of the actual value and must * be freed with av_dict_free() by the caller */ int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val); + +/** + * For an array-type option, get the number of elements in the array. + */ +int av_opt_get_array_size(void *obj, const char *name, int search_flags, + unsigned int *out_val); + +/** + * For an array-type option, retrieve the values of one or more array elements. + * + * @param start_elem index of the first array element to retrieve + * @param nb_elems number of array elements to retrieve; start_elem+nb_elems + * must not be larger than array size as returned by + * av_opt_get_array_size() + * + * @param out_type Option type corresponding to the desired output. + * + * The array elements produced by this function will + * will be as if av_opt_getX() was called for each element, + * where X is specified by out_type. E.g. AV_OPT_TYPE_STRING + * corresponds to av_opt_get(). + * + * Typically this should be the same as the scalarized type of + * the AVOption being retrieved, but certain conversions are + * also possible - the same as those done by the corresponding + * av_opt_get*() function. E.g. any option type can be retrieved + * as a string, numeric types can be retrieved as int64, double, + * or rational, etc. + * + * @param out_val Array with nb_elems members into which the output will be + * written. The array type must match the underlying C type as + * documented for out_type, and be zeroed on entry to this + * function. + * + * For dynamically allocated types (strings, binary, dicts, + * etc.), the result is owned and freed by the caller. + */ +int av_opt_get_array(void *obj, const char *name, int search_flags, + unsigned int start_elem, unsigned int nb_elems, + enum AVOptionType out_type, void *out_val); /** * @} */ @@ -873,6 +1060,7 @@ int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDiction */ int av_opt_eval_flags (void *obj, const AVOption *o, const char *val, int *flags_out); int av_opt_eval_int (void *obj, const AVOption *o, const char *val, int *int_out); +int av_opt_eval_uint (void *obj, const AVOption *o, const char *val, unsigned *uint_out); int av_opt_eval_int64 (void *obj, const AVOption *o, const char *val, int64_t *int64_out); int av_opt_eval_float (void *obj, const AVOption *o, const char *val, float *float_out); int av_opt_eval_double(void *obj, const AVOption *o, const char *val, double *double_out); @@ -929,6 +1117,7 @@ int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name) #define AV_OPT_SERIALIZE_SKIP_DEFAULTS 0x00000001 ///< Serialize options that are not set to default values only. #define AV_OPT_SERIALIZE_OPT_FLAGS_EXACT 0x00000002 ///< Serialize options that exactly match opt_flags only. +#define AV_OPT_SERIALIZE_SEARCH_CHILDREN 0x00000004 ///< Serialize options in possible children of the given object. /** * Serialize object's options. diff --git a/libavutil/pca.c b/libavutil/pca.c index 4e52c7b36..7c3eb42b1 100644 --- a/libavutil/pca.c +++ b/libavutil/pca.c @@ -25,6 +25,7 @@ */ #include "common.h" +#include "mem.h" #include "pca.h" typedef struct PCA{ diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c index 9c708520b..1c0bcf223 100644 --- a/libavutil/pixdesc.c +++ b/libavutil/pixdesc.c @@ -2854,6 +2854,9 @@ static const char * const color_space_names[] = { [AVCOL_SPC_CHROMA_DERIVED_NCL] = "chroma-derived-nc", [AVCOL_SPC_CHROMA_DERIVED_CL] = "chroma-derived-c", [AVCOL_SPC_ICTCP] = "ictcp", + [AVCOL_SPC_IPT_C2] = "ipt-c2", + [AVCOL_SPC_YCGCO_RE] = "ycgco-re", + [AVCOL_SPC_YCGCO_RO] = "ycgco-ro", }; static const char * const chroma_location_names[] = { diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h index 4aa20e4e5..a7f50e169 100644 --- a/libavutil/pixfmt.h +++ b/libavutil/pixfmt.h @@ -623,6 +623,9 @@ enum AVColorSpace { AVCOL_SPC_CHROMA_DERIVED_NCL = 12, ///< Chromaticity-derived non-constant luminance system AVCOL_SPC_CHROMA_DERIVED_CL = 13, ///< Chromaticity-derived constant luminance system AVCOL_SPC_ICTCP = 14, ///< ITU-R BT.2100-0, ICtCp + AVCOL_SPC_IPT_C2 = 15, ///< SMPTE ST 2128, IPT-C2 + AVCOL_SPC_YCGCO_RE = 16, ///< YCgCo-R, even addition of bits + AVCOL_SPC_YCGCO_RO = 17, ///< YCgCo-R, odd addition of bits AVCOL_SPC_NB ///< Not part of ABI }; diff --git a/libavutil/ppc/cpu.c b/libavutil/ppc/cpu.c index 2b13cda66..9f9c07343 100644 --- a/libavutil/ppc/cpu.c +++ b/libavutil/ppc/cpu.c @@ -20,6 +20,11 @@ #ifdef __APPLE__ #include +#elif HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO +#ifdef __FreeBSD__ +#include +#endif +#include #elif defined(__linux__) #include #include @@ -41,6 +46,17 @@ #include "libavutil/cpu.h" #include "libavutil/cpu_internal.h" +#ifndef AT_HWCAP +#define AT_HWCAP 16 +#endif +#ifndef AT_HWCAP2 +#define AT_HWCAP2 26 +#endif + +#define HWCAP_PPC_VSX (1U << 7) +#define HWCAP_PPC_ALTIVEC (1U << 28) +#define HWCAP2_PPC_ARCH_2_07 (1U << 31) + /** * This function MAY rely on signal() or fork() in order to make sure AltiVec * is present. @@ -56,6 +72,20 @@ int ff_get_cpu_flags_ppc(void) if (result == VECTORTYPE_ALTIVEC) return AV_CPU_FLAG_ALTIVEC; return 0; +#elif HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO + int flags = 0; + + unsigned long hwcap = ff_getauxval(AT_HWCAP); + unsigned long hwcap2 = ff_getauxval(AT_HWCAP2); + + if (hwcap & HWCAP_PPC_ALTIVEC) + flags |= AV_CPU_FLAG_ALTIVEC; + if (hwcap & HWCAP_PPC_VSX) + flags |= AV_CPU_FLAG_VSX; + if (hwcap2 & HWCAP2_PPC_ARCH_2_07) + flags |= AV_CPU_FLAG_POWER8; + + return flags; #elif defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) #if defined(__NetBSD__) || defined(__OpenBSD__) int sels[2] = {CTL_MACHDEP, CPU_ALTIVEC}; @@ -87,23 +117,17 @@ int ff_get_cpu_flags_ppc(void) if (buf[i] == AT_NULL) goto out; if (buf[i] == AT_HWCAP) { - if (buf[i + 1] & PPC_FEATURE_HAS_ALTIVEC) + if (buf[i + 1] & HWCAP_PPC_ALTIVEC) ret = AV_CPU_FLAG_ALTIVEC; -#ifdef PPC_FEATURE_HAS_VSX - if (buf[i + 1] & PPC_FEATURE_HAS_VSX) + if (buf[i + 1] & HWCAP_PPC_VSX) ret |= AV_CPU_FLAG_VSX; -#endif if (ret & AV_CPU_FLAG_VSX) av_assert0(ret & AV_CPU_FLAG_ALTIVEC); } -#ifdef AT_HWCAP2 /* not introduced until glibc 2.18 */ else if (buf[i] == AT_HWCAP2) { -#ifdef PPC_FEATURE2_ARCH_2_07 - if (buf[i + 1] & PPC_FEATURE2_ARCH_2_07) + if (buf[i + 1] & HWCAP2_PPC_ARCH_2_07) ret |= AV_CPU_FLAG_POWER8; -#endif } -#endif /* AT_HWCAP2 */ } } diff --git a/libavutil/random_seed.c b/libavutil/random_seed.c index 6d399cee4..8a4e4f1fc 100644 --- a/libavutil/random_seed.c +++ b/libavutil/random_seed.c @@ -158,10 +158,10 @@ int av_random_bytes(uint8_t* buf, size_t len) #elif CONFIG_OPENSSL if (RAND_bytes(buf, len) == 1) return 0; - err = AVERROR_EXTERNAL; -#endif - + return AVERROR_EXTERNAL; +#else return err; +#endif } uint32_t av_get_random_seed(void) diff --git a/libavutil/riscv/Makefile b/libavutil/riscv/Makefile index 1597154ba..5db4c432d 100644 --- a/libavutil/riscv/Makefile +++ b/libavutil/riscv/Makefile @@ -1,5 +1,8 @@ OBJS += riscv/float_dsp_init.o \ riscv/fixed_dsp_init.o \ - riscv/cpu.o + riscv/lls_init.o \ + riscv/cpu.o \ + riscv/cpu_common.o RVV-OBJS += riscv/float_dsp_rvv.o \ - riscv/fixed_dsp_rvv.o + riscv/fixed_dsp_rvv.o \ + riscv/lls_rvv.o diff --git a/libavutil/riscv/asm.S b/libavutil/riscv/asm.S index 0a9e2e0d3..ec68a042d 100644 --- a/libavutil/riscv/asm.S +++ b/libavutil/riscv/asm.S @@ -36,19 +36,31 @@ #define HWD #endif - .macro func sym, ext= - .text - .align 2 - - .option push - .ifnb \ext - .option arch, +\ext + .macro archadd ext=, more:vararg + .ifnb \ext + .ifc \ext, b + # B was defined later, is known to fewer assemblers. + archadd zba, zbb, zbs + .else + .option arch, +\ext + .endif + archadd \more .endif + .endm + + .macro func sym, exts:vararg + .text + .option push + archadd \exts .global \sym .hidden \sym .type \sym, %function + .option push + .option norvc + .align 2 \sym: + .option pop .macro endfunc .size \sym, . - \sym @@ -74,101 +86,154 @@ .endm .endm -#if !defined (__riscv_zba) - /* SH{1,2,3}ADD definitions for pre-Zba assemblers */ - .macro shnadd n, rd, rs1, rs2 - .insn r OP, 2 * \n, 16, \rd, \rs1, \rs2 - .endm - - .macro sh1add rd, rs1, rs2 - shnadd 1, \rd, \rs1, \rs2 - .endm - - .macro sh2add rd, rs1, rs2 - shnadd 2, \rd, \rs1, \rs2 - .endm - - .macro sh3add rd, rs1, rs2 - shnadd 3, \rd, \rs1, \rs2 - .endm -#endif -#if !defined (__riscv_zbb) - .macro min rd, rs1, rs2 - .insn r OP, 4, 5, \rd, \rs1, \rs2 +#if !defined (__riscv_zicfilp) + .macro lpad lpl + auipc zero, \lpl .endm #endif - /* Convenience macro to load a Vector type (vtype) as immediate */ - .macro lvtypei rd, e, m=m1, tp=tu, mp=mu +#if defined (__riscv_v_elen) +# define RV_V_ELEN __riscv_v_elen +#else +/* Run-time detection of the V extension implies ELEN >= 64. */ +# define RV_V_ELEN 64 +#endif +#if RV_V_ELEN == 32 +# define VSEW_MAX 2 +#else +# define VSEW_MAX 3 +#endif - .ifc \e,e8 - .equ ei, 0 + .macro parse_vtype ew, tp, mp + .ifc \ew,e8 + .equ vsew, 0 .else - .ifc \e,e16 - .equ ei, 8 + .ifc \ew,e16 + .equ vsew, 1 .else - .ifc \e,e32 - .equ ei, 16 + .ifc \ew,e32 + .equ vsew, 2 .else - .ifc \e,e64 - .equ ei, 24 + .ifc \ew,e64 + .equ vsew, 3 .else - .error "Unknown element type" + .error "Unknown element width \ew" .endif .endif .endif .endif - .ifc \m,m1 - .equ mi, 0 + .ifc \tp,tu + .equ tp, 0 .else - .ifc \m,m2 - .equ mi, 1 + .ifc \tp,ta + .equ tp, 1 .else - .ifc \m,m4 - .equ mi, 2 - .else - .ifc \m,m8 - .equ mi, 3 - .else - .ifc \m,mf8 - .equ mi, 5 - .else - .ifc \m,mf4 - .equ mi, 6 - .else - .ifc \m,mf2 - .equ mi, 7 - .else - .error "Unknown multiplier" - .equ mi, 3 - .endif - .endif - .endif - .endif - .endif - .endif - .endif - - .ifc \tp,tu - .equ tpi, 0 - .else - .ifc \tp,ta - .equ tpi, 64 - .else - .error "Unknown tail policy" + .error "Unknown tail policy \tp" .endif .endif - .ifc \mp,mu - .equ mpi, 0 + .ifc \mp,mu + .equ mp, 0 .else - .ifc \mp,ma - .equ mpi, 128 + .ifc \mp,ma + .equ mp, 1 .else - .error "Unknown mask policy" + .error "Unknown mask policy \mp" .endif .endif + .endm - li \rd, (ei | mi | tpi | mpi) + /** + * Gets the vector type with the smallest suitable LMUL value. + * @param[out] rd vector type destination register + * @param vl vector length constant + * @param ew element width: e8, e16, e32 or e64 + * @param tp tail policy: tu or ta + * @param mp mask policty: mu or ma + */ + .macro vtype_ivli rd, avl, ew, tp=tu, mp=mu + .if \avl <= 1 + .equ log2vl, 0 + .elseif \avl <= 2 + .equ log2vl, 1 + .elseif \avl <= 4 + .equ log2vl, 2 + .elseif \avl <= 8 + .equ log2vl, 3 + .elseif \avl <= 16 + .equ log2vl, 4 + .elseif \avl <= 32 + .equ log2vl, 5 + .elseif \avl <= 64 + .equ log2vl, 6 + .elseif \avl <= 128 + .equ log2vl, 7 + .else + .error "Vector length \avl out of range" + .endif + parse_vtype \ew, \tp, \mp + csrr \rd, vlenb + clz \rd, \rd + addi \rd, \rd, log2vl + 1 + VSEW_MAX - __riscv_xlen + max \rd, \rd, zero // VLMUL must be >= VSEW - VSEW_MAX + .if vsew < VSEW_MAX + addi \rd, \rd, vsew - VSEW_MAX + andi \rd, \rd, 7 + .endif + ori \rd, \rd, (vsew << 3) | (tp << 6) | (mp << 7) + .endm + + /** + * Gets the vector type with the smallest suitable LMUL value. + * @param[out] rd vector type destination register + * @param rs vector length source register + * @param[out] tmp temporary register to be clobbered + * @param ew element width: e8, e16, e32 or e64 + * @param tp tail policy: tu or ta + * @param mp mask policty: mu or ma + * @param addend optional addend for the vector length register + */ + .macro vtype_vli rd, rs, tmp, ew, tp=tu, mp=mu, addend=0 + parse_vtype \ew, \tp, \mp + /* + * The difference between the CLZ's notionally equals the VLMUL value + * for 4-bit elements. But we want the value for SEW_MAX-bit elements. + */ + slli \tmp, \rs, 1 + VSEW_MAX + .if \addend - 1 + addi \tmp, \tmp, \addend - 1 + .endif + csrr \rd, vlenb + clz \tmp, \tmp + clz \rd, \rd + sub \rd, \rd, \tmp + max \rd, \rd, zero // VLMUL must be >= VSEW - VSEW_MAX + .if vsew < VSEW_MAX + addi \rd, \rd, vsew - VSEW_MAX + andi \rd, \rd, 7 + .endif + ori \rd, \rd, (vsew << 3) | (tp << 6) | (mp << 7) + .endm + + /** + * Widens a vector type. + * @param[out] rd widened vector type destination register + * @param rs vector type source register + * @param n number of times to widen (once by default) + */ + .macro vwtypei rd, rs, n=1 + xori \rd, \rs, 4 + addi \rd, \rd, (\n) * 011 + xori \rd, \rd, 4 + .endm + + /** + * Narrows a vector type. + * @param[out] rd narrowed vector type destination register + * @param rs vector type source register + * @param n number of times to narrow (once by default) + */ + .macro vntypei rd, rs, n=1 + vwtypei \rd, \rs, -(\n) .endm diff --git a/libavutil/riscv/bswap.h b/libavutil/riscv/bswap.h index ce75de974..886893e24 100644 --- a/libavutil/riscv/bswap.h +++ b/libavutil/riscv/bswap.h @@ -22,11 +22,51 @@ #include #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/riscv/cpu.h" #if defined (__GNUC__) || defined (__clang__) #define av_bswap16 __builtin_bswap16 -#define av_bswap32 __builtin_bswap32 -#define av_bswap64 __builtin_bswap64 + +static av_always_inline av_const uint32_t av_bswap32_rv(uint32_t x) +{ +#if HAVE_RV && !defined(__riscv_zbb) + if (!__builtin_constant_p(x) && + __builtin_expect(ff_rv_zbb_support(), 1)) { + uintptr_t y; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" + "rev8 %0, %1\n" + ".option pop" : "=r" (y) : "r" (x)); + return y >> (__riscv_xlen - 32); + } +#endif + return __builtin_bswap32(x); +} +#define av_bswap32 av_bswap32_rv + +#if __riscv_xlen >= 64 +static av_always_inline av_const uint64_t av_bswap64_rv(uint64_t x) +{ +#if HAVE_RV && !defined(__riscv_zbb) + if (!__builtin_constant_p(x) && + __builtin_expect(ff_rv_zbb_support(), 1)) { + uintptr_t y; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" + "rev8 %0, %1\n" + ".option pop" : "=r" (y) : "r" (x)); + return y >> (__riscv_xlen - 64); + } +#endif + return __builtin_bswap64(x); +} +#define av_bswap64 av_bswap64_rv +#endif + #endif #endif /* AVUTIL_RISCV_BSWAP_H */ diff --git a/libavutil/riscv/bswap_rvb.S b/libavutil/riscv/bswap_rvb.S index 3ff53ccb5..bc07779c4 100644 --- a/libavutil/riscv/bswap_rvb.S +++ b/libavutil/riscv/bswap_rvb.S @@ -20,21 +20,21 @@ #if (__riscv_xlen >= 64) .macro bswap32_rvb out, in, count - andi t0, \count, 4 + andi t0, \count, 1 beqz t0, 1f /* Align input to 64-bit */ lwu t0, (\in) addi \out, \out, 4 rev8 t0, t0 - addi \count, \count, -1 + addi \count, \count, -4 srli t0, t0, __riscv_xlen - 32 addi \in, \in, 4 sw t0, -4(\out) 1: - andi t3, \count, -2 - sh2add \count, \count, \out + andi t3, \count, -8 + add \count, \count, \out beqz t3, 3f - sh2add t3, t3, \out + add t3, t3, \out 2: /* 2 elements (64 bits) at a time on a 64-bit boundary */ ld t0, (\in) addi \out, \out, 8 diff --git a/libavutil/riscv/cpu.c b/libavutil/riscv/cpu.c index 460d3e9f9..163e4fc14 100644 --- a/libavutil/riscv/cpu.c +++ b/libavutil/riscv/cpu.c @@ -18,53 +18,99 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE #include "libavutil/cpu.h" #include "libavutil/cpu_internal.h" +#include "libavutil/macros.h" #include "libavutil/log.h" #include "config.h" -#if HAVE_GETAUXVAL +#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO #include #define HWCAP_RV(letter) (1ul << ((letter) - 'A')) #endif +#if HAVE_SYS_HWPROBE_H +#include +#elif HAVE_ASM_HWPROBE_H +#include +#include +#include + +static int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpu_count, unsigned long *cpus, + unsigned int flags) +{ + return syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, + flags); +} +#endif int ff_get_cpu_flags_riscv(void) { int ret = 0; -#if HAVE_GETAUXVAL - const unsigned long hwcap = getauxval(AT_HWCAP); +#if HAVE_SYS_HWPROBE_H || HAVE_ASM_HWPROBE_H + struct riscv_hwprobe pairs[] = { + { RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0 }, + { RISCV_HWPROBE_KEY_IMA_EXT_0, 0 }, + { RISCV_HWPROBE_KEY_CPUPERF_0, 0 }, + }; - if (hwcap & HWCAP_RV('I')) - ret |= AV_CPU_FLAG_RVI; - if (hwcap & HWCAP_RV('F')) - ret |= AV_CPU_FLAG_RVF; - if (hwcap & HWCAP_RV('D')) - ret |= AV_CPU_FLAG_RVD; - if (hwcap & HWCAP_RV('B')) - ret |= AV_CPU_FLAG_RVB_ADDR | AV_CPU_FLAG_RVB_BASIC; + if (__riscv_hwprobe(pairs, FF_ARRAY_ELEMS(pairs), 0, NULL, 0) == 0) { + if (pairs[0].value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA) + ret |= AV_CPU_FLAG_RVI; +#ifdef RISCV_HWPROBE_IMA_V + if (pairs[1].value & RISCV_HWPROBE_IMA_V) + ret |= AV_CPU_FLAG_RVV_I32 | AV_CPU_FLAG_RVV_I64 + | AV_CPU_FLAG_RVV_F32 | AV_CPU_FLAG_RVV_F64; +#endif +#ifdef RISCV_HWPROBE_EXT_ZBB + if (pairs[1].value & RISCV_HWPROBE_EXT_ZBB) + ret |= AV_CPU_FLAG_RVB_BASIC; +#if defined (RISCV_HWPROBE_EXT_ZBA) && defined (RISCV_HWPROBE_EXT_ZBS) + if ((pairs[1].value & RISCV_HWPROBE_EXT_ZBA) && + (pairs[1].value & RISCV_HWPROBE_EXT_ZBB) && + (pairs[1].value & RISCV_HWPROBE_EXT_ZBS)) + ret |= AV_CPU_FLAG_RVB; +#endif +#endif +#ifdef RISCV_HWPROBE_EXT_ZVBB + if (pairs[1].value & RISCV_HWPROBE_EXT_ZVBB) + ret |= AV_CPU_FLAG_RV_ZVBB; +#endif + switch (pairs[2].value & RISCV_HWPROBE_MISALIGNED_MASK) { + case RISCV_HWPROBE_MISALIGNED_FAST: + ret |= AV_CPU_FLAG_RV_MISALIGNED; + break; + default: + } + } +#elif HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO + { + const unsigned long hwcap = ff_getauxval(AT_HWCAP); - /* The V extension implies all Zve* functional subsets */ - if (hwcap & HWCAP_RV('V')) - ret |= AV_CPU_FLAG_RVV_I32 | AV_CPU_FLAG_RVV_I64 - | AV_CPU_FLAG_RVV_F32 | AV_CPU_FLAG_RVV_F64; + if (hwcap & HWCAP_RV('I')) + ret |= AV_CPU_FLAG_RVI; + if (hwcap & HWCAP_RV('B')) + ret |= AV_CPU_FLAG_RVB_BASIC | AV_CPU_FLAG_RVB; + + /* The V extension implies all Zve* functional subsets */ + if (hwcap & HWCAP_RV('V')) + ret |= AV_CPU_FLAG_RVV_I32 | AV_CPU_FLAG_RVV_I64 + | AV_CPU_FLAG_RVV_F32 | AV_CPU_FLAG_RVV_F64; + } #endif #ifdef __riscv_i ret |= AV_CPU_FLAG_RVI; #endif -#if defined (__riscv_flen) && (__riscv_flen >= 32) - ret |= AV_CPU_FLAG_RVF; -#if (__riscv_flen >= 64) - ret |= AV_CPU_FLAG_RVD; -#endif -#endif -#ifdef __riscv_zba - ret |= AV_CPU_FLAG_RVB_ADDR; -#endif #ifdef __riscv_zbb ret |= AV_CPU_FLAG_RVB_BASIC; #endif +#if defined (__riscv_b) || \ + (defined (__riscv_zba) && defined (__riscv_zbb) && defined (__riscv_zbs)) + ret |= AV_CPU_FLAG_RVB; +#endif /* If RV-V is enabled statically at compile-time, check the details. */ #ifdef __riscv_vector @@ -78,6 +124,9 @@ int ff_get_cpu_flags_riscv(void) ret |= AV_CPU_FLAG_RVV_F64; #endif #endif +#endif +#ifdef __riscv_zvbb + ret |= AV_CPU_FLAG_RV_ZVBB; #endif return ret; diff --git a/libavutil/riscv/cpu.h b/libavutil/riscv/cpu.h index 56035f855..f2e6b7b43 100644 --- a/libavutil/riscv/cpu.h +++ b/libavutil/riscv/cpu.h @@ -22,9 +22,24 @@ #define AVUTIL_RISCV_CPU_H #include "config.h" +#include #include +#include "libavutil/attributes_internal.h" #include "libavutil/cpu.h" +#ifndef __riscv_zbb +extern attribute_visibility_hidden bool ff_rv_zbb_supported; +#endif + +static inline av_const bool ff_rv_zbb_support(void) +{ +#ifndef __riscv_zbb + return ff_rv_zbb_supported; +#else + return true; +#endif +} + #if HAVE_RVV /** * Returns the vector size in bytes (always a power of two and at least 4). @@ -41,5 +56,25 @@ static inline size_t ff_get_rv_vlenb(void) ".option pop\n" : "=r" (vlenb)); return vlenb; } + +/** + * Checks that the vector bit-size is at least the given value. + * This is potentially undefined behaviour if vectors are not implemented. + */ +static inline bool ff_rv_vlen_least(unsigned int bits) +{ +#ifdef __riscv_v_min_vlen + if (bits <= __riscv_v_min_vlen) + return true; +#else + /* + * Vector lengths smaller than 128 bits are only possible in embedded cases + * and cannot be run-time detected, so we can assume 128 bits at least. + */ + if (bits <= 128) + return true; #endif + return bits <= (8 * ff_get_rv_vlenb()); +} #endif +#endif /* HAVE_RVV */ diff --git a/compat/atomics/pthread/stdatomic.c b/libavutil/riscv/cpu_common.c similarity index 68% rename from compat/atomics/pthread/stdatomic.c rename to libavutil/riscv/cpu_common.c index 9fca98980..3ecf95809 100644 --- a/compat/atomics/pthread/stdatomic.c +++ b/libavutil/riscv/cpu_common.c @@ -1,4 +1,6 @@ /* + * Copyright © 2024 Rémi Denis-Courmont. + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -16,24 +18,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - * based on vlc_atomic.h from VLC - * Copyright (C) 2010 Rémi Denis-Courmont - */ +#include "libavutil/cpu.h" -#include -#include +#ifndef __riscv_zbb +unsigned char ff_rv_zbb_supported = 0; -#include "stdatomic.h" - -static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER; - -void avpriv_atomic_lock(void) +#ifdef __ELF__ +__attribute__((constructor)) +static void probe_zbb(void) { - pthread_mutex_lock(&atomic_lock); -} - -void avpriv_atomic_unlock(void) -{ - pthread_mutex_unlock(&atomic_lock); + ff_rv_zbb_supported = (av_get_cpu_flags() & AV_CPU_FLAG_RVB_BASIC) != 0; } +#endif +#endif diff --git a/libavutil/riscv/fixed_dsp_init.c b/libavutil/riscv/fixed_dsp_init.c index cd318af48..36612d49e 100644 --- a/libavutil/riscv/fixed_dsp_init.c +++ b/libavutil/riscv/fixed_dsp_init.c @@ -45,7 +45,7 @@ av_cold void ff_fixed_dsp_init_riscv(AVFixedDSPContext *fdsp) #if HAVE_RVV int flags = av_get_cpu_flags(); - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { if (flags & AV_CPU_FLAG_RVV_I64) { fdsp->vector_fmul_window_scaled = ff_vector_fmul_window_scaled_rvv; fdsp->vector_fmul_window = ff_vector_fmul_window_fixed_rvv; diff --git a/libavutil/riscv/fixed_dsp_rvv.S b/libavutil/riscv/fixed_dsp_rvv.S index 6bac5813b..e60ee8cad 100644 --- a/libavutil/riscv/fixed_dsp_rvv.S +++ b/libavutil/riscv/fixed_dsp_rvv.S @@ -20,7 +20,8 @@ #include "asm.S" -func ff_vector_fmul_window_scaled_rvv, zve64x +func ff_vector_fmul_window_scaled_rvv, zve64x, zba + lpad 0 csrwi vxrm, 0 vsetvli t0, zero, e16, m1, ta, ma sh2add a2, a4, a2 @@ -68,7 +69,8 @@ func ff_vector_fmul_window_scaled_rvv, zve64x ret endfunc -func ff_vector_fmul_window_fixed_rvv, zve64x +func ff_vector_fmul_window_fixed_rvv, zve64x, zba + lpad 0 csrwi vxrm, 0 vsetvli t0, zero, e16, m1, ta, ma sh2add a2, a4, a2 @@ -112,7 +114,8 @@ func ff_vector_fmul_window_fixed_rvv, zve64x ret endfunc -func ff_vector_fmul_fixed_rvv, zve32x +func ff_vector_fmul_fixed_rvv, zve32x, zba + lpad 0 csrwi vxrm, 0 1: vsetvli t0, a3, e32, m4, ta, ma @@ -129,7 +132,7 @@ func ff_vector_fmul_fixed_rvv, zve32x ret endfunc -func ff_vector_fmul_reverse_fixed_rvv, zve32x +func ff_vector_fmul_reverse_fixed_rvv, zve32x, zba csrwi vxrm, 0 // e16/m4 and e32/m8 are possible but slow the gathers down. vsetvli t0, zero, e16, m1, ta, ma @@ -155,7 +158,8 @@ func ff_vector_fmul_reverse_fixed_rvv, zve32x ret endfunc -func ff_vector_fmul_add_fixed_rvv, zve32x +func ff_vector_fmul_add_fixed_rvv, zve32x, zba + lpad 0 csrwi vxrm, 0 1: vsetvli t0, a4, e32, m8, ta, ma @@ -175,7 +179,8 @@ func ff_vector_fmul_add_fixed_rvv, zve32x ret endfunc -func ff_scalarproduct_fixed_rvv, zve64x +func ff_scalarproduct_fixed_rvv, zve64x, zba + lpad 0 li t1, 1 << 30 vsetvli t0, zero, e64, m8, ta, ma vmv.v.x v8, zero @@ -198,7 +203,8 @@ func ff_scalarproduct_fixed_rvv, zve64x endfunc // (a0) = (a0) + (a1), (a1) = (a0) - (a1) [0..a2-1] -func ff_butterflies_fixed_rvv, zve32x +func ff_butterflies_fixed_rvv, zve32x, zba + lpad 0 1: vsetvli t0, a2, e32, m4, ta, ma vle32.v v16, (a0) diff --git a/libavutil/riscv/float_dsp_init.c b/libavutil/riscv/float_dsp_init.c index 585f23722..91fd9982e 100644 --- a/libavutil/riscv/float_dsp_init.c +++ b/libavutil/riscv/float_dsp_init.c @@ -46,13 +46,15 @@ void ff_vector_dmac_scalar_rvv(double *dst, const double *src, double mul, int len); void ff_vector_dmul_scalar_rvv(double *dst, const double *src, double mul, int len); +double ff_scalarproduct_double_rvv(const double *v1, const double *v2, + size_t len); av_cold void ff_float_dsp_init_riscv(AVFloatDSPContext *fdsp) { #if HAVE_RVV int flags = av_get_cpu_flags(); - if (flags & AV_CPU_FLAG_RVB_ADDR) { + if (flags & AV_CPU_FLAG_RVB) { if (flags & AV_CPU_FLAG_RVV_F32) { fdsp->vector_fmul = ff_vector_fmul_rvv; fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_rvv; @@ -68,6 +70,7 @@ av_cold void ff_float_dsp_init_riscv(AVFloatDSPContext *fdsp) fdsp->vector_dmul = ff_vector_dmul_rvv; fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_rvv; fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_rvv; + fdsp->scalarproduct_double = ff_scalarproduct_double_rvv; } } #endif diff --git a/libavutil/riscv/float_dsp_rvv.S b/libavutil/riscv/float_dsp_rvv.S index e6ec182a7..fd5ee5374 100644 --- a/libavutil/riscv/float_dsp_rvv.S +++ b/libavutil/riscv/float_dsp_rvv.S @@ -21,7 +21,8 @@ #include "asm.S" // (a0) = (a1) * (a2) [0..a3-1] -func ff_vector_fmul_rvv, zve32f +func ff_vector_fmul_rvv, zve32f, zba + lpad 0 1: vsetvli t0, a3, e32, m8, ta, ma vle32.v v16, (a1) @@ -38,7 +39,8 @@ func ff_vector_fmul_rvv, zve32f endfunc // (a0) += (a1) * fa0 [0..a2-1] -func ff_vector_fmac_scalar_rvv, zve32f +func ff_vector_fmac_scalar_rvv, zve32f, zba + lpad 0 NOHWF fmv.w.x fa0, a2 NOHWF mv a2, a3 1: @@ -57,7 +59,8 @@ NOHWF mv a2, a3 endfunc // (a0) = (a1) * fa0 [0..a2-1] -func ff_vector_fmul_scalar_rvv, zve32f +func ff_vector_fmul_scalar_rvv, zve32f, zba + lpad 0 NOHWF fmv.w.x fa0, a2 NOHWF mv a2, a3 1: @@ -73,7 +76,8 @@ NOHWF mv a2, a3 ret endfunc -func ff_vector_fmul_window_rvv, zve32f +func ff_vector_fmul_window_rvv, zve32f, zba + lpad 0 // a0: dst, a1: src0, a2: src1, a3: window, a4: length // e16/m2 and e32/m4 are possible but slower due to gather. vsetvli t0, zero, e16, m1, ta, ma @@ -113,7 +117,8 @@ func ff_vector_fmul_window_rvv, zve32f endfunc // (a0) = (a1) * (a2) + (a3) [0..a4-1] -func ff_vector_fmul_add_rvv, zve32f +func ff_vector_fmul_add_rvv, zve32f, zba + lpad 0 1: vsetvli t0, a4, e32, m8, ta, ma vle32.v v8, (a1) @@ -133,7 +138,8 @@ endfunc // TODO factor vrsub, separate last iteration? // (a0) = (a1) * reverse(a2) [0..a3-1] -func ff_vector_fmul_reverse_rvv, zve32f +func ff_vector_fmul_reverse_rvv, zve32f, zba + lpad 0 // e16/m4 and e32/m8 are possible but slower due to gather. vsetvli t0, zero, e16, m1, ta, ma sh2add a2, a3, a2 @@ -159,7 +165,8 @@ func ff_vector_fmul_reverse_rvv, zve32f endfunc // (a0) = (a0) + (a1), (a1) = (a0) - (a1) [0..a2-1] -func ff_butterflies_float_rvv, zve32f +func ff_butterflies_float_rvv, zve32f, zba + lpad 0 1: vsetvli t0, a2, e32, m8, ta, ma vle32.v v16, (a0) @@ -177,7 +184,8 @@ func ff_butterflies_float_rvv, zve32f endfunc // a0 = (a0).(a1) [0..a2-1] -func ff_scalarproduct_float_rvv, zve32f +func ff_scalarproduct_float_rvv, zve32f, zba + lpad 0 vsetvli t0, zero, e32, m8, ta, ma vmv.v.x v8, zero vmv.s.x v0, zero @@ -199,7 +207,8 @@ NOHWF fmv.x.w a0, fa0 endfunc // (a0) = (a1) * (a2) [0..a3-1] -func ff_vector_dmul_rvv, zve64d +func ff_vector_dmul_rvv, zve64d, zba + lpad 0 1: vsetvli t0, a3, e64, m8, ta, ma vle64.v v16, (a1) @@ -216,7 +225,8 @@ func ff_vector_dmul_rvv, zve64d endfunc // (a0) += (a1) * fa0 [0..a2-1] -func ff_vector_dmac_scalar_rvv, zve64d +func ff_vector_dmac_scalar_rvv, zve64d, zba + lpad 0 NOHWD fmv.d.x fa0, a2 NOHWD mv a2, a3 1: @@ -234,7 +244,8 @@ NOHWD mv a2, a3 endfunc // (a0) = (a1) * fa0 [0..a2-1] -func ff_vector_dmul_scalar_rvv, zve64d +func ff_vector_dmul_scalar_rvv, zve64d, zba + lpad 0 NOHWD fmv.d.x fa0, a2 NOHWD mv a2, a3 1: @@ -249,3 +260,25 @@ NOHWD mv a2, a3 ret endfunc + +func ff_scalarproduct_double_rvv, zve64f, zba + lpad 0 + vsetvli t0, zero, e64, m8, ta, ma + vmv.v.x v8, zero + vmv.s.x v0, zero +1: + vsetvli t0, a2, e64, m8, tu, ma + vle64.v v16, (a0) + sub a2, a2, t0 + vle64.v v24, (a1) + sh3add a0, t0, a0 + vfmacc.vv v8, v16, v24 + sh3add a1, t0, a1 + bnez a2, 1b + + vsetvli t0, zero, e64, m8, ta, ma + vfredusum.vs v0, v8, v0 + vfmv.f.s fa0, v0 +NOHWD fmv.x.w a0, fa0 + ret +endfunc diff --git a/libavutil/riscv/intmath.h b/libavutil/riscv/intmath.h index ae9ee7775..a09248f90 100644 --- a/libavutil/riscv/intmath.h +++ b/libavutil/riscv/intmath.h @@ -1,4 +1,6 @@ /* + * Copyright © 2022-2024 Rémi Denis-Courmont. + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -20,9 +22,11 @@ #define AVUTIL_RISCV_INTMATH_H #include +#include #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/riscv/cpu.h" /* * The compiler is forced to sign-extend the result anyhow, so it is faster to @@ -69,13 +73,194 @@ static av_always_inline av_const int av_clip_intp2_rvi(int a, int p) return b; } -#if defined (__GNUC__) || defined (__clang__) -#define av_popcount __builtin_popcount -#if (__riscv_xlen >= 64) -#define av_popcount64 __builtin_popcountl -#else -#define av_popcount64 __builtin_popcountll +#if defined (__riscv_f) || defined (__riscv_zfinx) +#define av_clipf av_clipf_rvf +static av_always_inline av_const float av_clipf_rvf(float a, float min, + float max) +{ + return fminf(fmaxf(a, min), max); +} #endif + +#if defined (__riscv_d) || defined (__riscv_zdinx) +#define av_clipd av_clipd_rvd +static av_always_inline av_const double av_clipd_rvd(double a, double min, + double max) +{ + return fmin(fmax(a, min), max); +} +#endif + +#if defined (__GNUC__) || defined (__clang__) +static inline av_const int ff_ctz_rv(int x) +{ +#if HAVE_RV && !defined(__riscv_zbb) + if (!__builtin_constant_p(x) && + __builtin_expect(ff_rv_zbb_support(), true)) { + int y; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" +#if __riscv_xlen >= 64 + "ctzw %0, %1\n" +#else + "ctz %0, %1\n" +#endif + ".option pop" : "=r" (y) : "r" (x)); + if (y > 32) + __builtin_unreachable(); + return y; + } +#endif + return __builtin_ctz(x); +} +#define ff_ctz ff_ctz_rv + +static inline av_const int ff_ctzll_rv(long long x) +{ +#if HAVE_RV && !defined(__riscv_zbb) && __riscv_xlen == 64 + if (!__builtin_constant_p(x) && + __builtin_expect(ff_rv_zbb_support(), true)) { + int y; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" + "ctz %0, %1\n" + ".option pop" : "=r" (y) : "r" (x)); + if (y > 64) + __builtin_unreachable(); + return y; + } +#endif + return __builtin_ctzll(x); +} +#define ff_ctzll ff_ctzll_rv + +static inline av_const int ff_clz_rv(int x) +{ +#if HAVE_RV && !defined(__riscv_zbb) + if (!__builtin_constant_p(x) && + __builtin_expect(ff_rv_zbb_support(), true)) { + int y; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" +#if __riscv_xlen >= 64 + "clzw %0, %1\n" +#else + "clz %0, %1\n" +#endif + ".option pop" : "=r" (y) : "r" (x)); + if (y > 32) + __builtin_unreachable(); + return y; + } +#endif + return __builtin_clz(x); +} +#define ff_clz ff_clz_rv + +#if __riscv_xlen == 64 +static inline av_const int ff_clzll_rv(long long x) +{ +#if HAVE_RV && !defined(__riscv_zbb) + if (!__builtin_constant_p(x) && + __builtin_expect(ff_rv_zbb_support(), true)) { + int y; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" + "clz %0, %1\n" + ".option pop" : "=r" (y) : "r" (x)); + if (y > 64) + __builtin_unreachable(); + return y; + } +#endif + return __builtin_clzll(x); +} +#define ff_clz ff_clz_rv +#endif + +static inline av_const int ff_log2_rv(unsigned int x) +{ + return 31 - ff_clz_rv(x | 1); +} +#define ff_log2 ff_log2_rv +#define ff_log2_16bit ff_log2_rv + +static inline av_const int av_popcount_rv(unsigned int x) +{ +#if HAVE_RV && !defined(__riscv_zbb) + if (!__builtin_constant_p(x) && + __builtin_expect(ff_rv_zbb_support(), true)) { + int y; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" +#if __riscv_xlen >= 64 + "cpopw %0, %1\n" +#else + "cpop %0, %1\n" +#endif + ".option pop" : "=r" (y) : "r" (x)); + if (y > 32) + __builtin_unreachable(); + return y; + } +#endif + return __builtin_popcount(x); +} +#define av_popcount av_popcount_rv + +static inline av_const int av_popcount64_rv(uint64_t x) +{ +#if HAVE_RV && !defined(__riscv_zbb) && __riscv_xlen >= 64 + if (!__builtin_constant_p(x) && + __builtin_expect(ff_rv_zbb_support(), true)) { + int y; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" + "cpop %0, %1\n" + ".option pop" : "=r" (y) : "r" (x)); + if (y > 64) + __builtin_unreachable(); + return y; + } +#endif + return __builtin_popcountl(x); +} +#define av_popcount64 av_popcount64_rv + +static inline av_const int av_parity_rv(unsigned int x) +{ +#if HAVE_RV && !defined(__riscv_zbb) + if (!__builtin_constant_p(x) && + __builtin_expect(ff_rv_zbb_support(), true)) { + int y; + + __asm__ ( + ".option push\n" + ".option arch, +zbb\n" +#if __riscv_xlen >= 64 + "cpopw %0, %1\n" +#else + "cpop %0, %1\n" +#endif + ".option pop" : "=r" (y) : "r" (x)); + return y & 1; + } +#endif + return __builtin_parity(x); +} +#define av_parity av_parity_rv #endif #endif /* AVUTIL_RISCV_INTMATH_H */ diff --git a/libavutil/riscv/lls_init.c b/libavutil/riscv/lls_init.c new file mode 100644 index 000000000..d6ba31955 --- /dev/null +++ b/libavutil/riscv/lls_init.c @@ -0,0 +1,56 @@ +/* + * 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 +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/riscv/cpu.h" +#include "libavutil/lls.h" + +void ff_lls_update_covariance_rvv(double covar[][36], const double *var, + int count); +double ff_scalarproduct_double_rvv(const double *, const double *, size_t); + +static void ff_lls_update_rvv(struct LLSModel *m, const double *var) +{ + ff_lls_update_covariance_rvv(m->covariance, var, m->indep_count + 1); +} + +static double ff_lls_evaluate_rvv(struct LLSModel *m, const double *var, + int order) +{ + return ff_scalarproduct_double_rvv(m->coeff[order], var, order + 1); +} + +av_cold void ff_init_lls_riscv(LLSModel *m) +{ +#if HAVE_RVV + int flags = av_get_cpu_flags(); + + if ((flags & AV_CPU_FLAG_RVB) && (flags & AV_CPU_FLAG_RVV_F64)) { + if (ff_get_rv_vlenb() > m->indep_count) + m->update_lls = ff_lls_update_rvv; + m->evaluate_lls = ff_lls_evaluate_rvv; + } +#endif +} diff --git a/libavutil/riscv/lls_rvv.S b/libavutil/riscv/lls_rvv.S new file mode 100644 index 000000000..bd9f74ee5 --- /dev/null +++ b/libavutil/riscv/lls_rvv.S @@ -0,0 +1,39 @@ +/* + * 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 "asm.S" + +func ff_lls_update_covariance_rvv, zve64d, zbb + lpad 0 + vtype_vli t0, a2, t1, e64, ta, ma + vsetvl zero, a2, t0 + vle64.v v8, (a1) +1: + vfmv.f.s ft0, v8 + vle64.v v16, (a0) + vfmacc.vf v16, ft0, v8 + addi a2, a2, -1 + vslidedown.vi v8, v8, 1 + vse64.v v16, (a0) + addi a0, a0, (36 + 1) * 8 # 1 row + 1 element + bnez a2, 1b + + ret +endfunc diff --git a/libavutil/spherical.c b/libavutil/spherical.c index 800d3459a..64ade1d0e 100644 --- a/libavutil/spherical.c +++ b/libavutil/spherical.c @@ -29,6 +29,8 @@ AVSphericalMapping *av_spherical_alloc(size_t *size) if (!spherical) return NULL; + spherical->projection = AV_SPHERICAL_RECTILINEAR; + if (size) *size = sizeof(*spherical); @@ -57,6 +59,9 @@ static const char *const spherical_projection_names[] = { [AV_SPHERICAL_EQUIRECTANGULAR] = "equirectangular", [AV_SPHERICAL_CUBEMAP] = "cubemap", [AV_SPHERICAL_EQUIRECTANGULAR_TILE] = "tiled equirectangular", + [AV_SPHERICAL_HALF_EQUIRECTANGULAR] = "half equirectangular", + [AV_SPHERICAL_RECTILINEAR] = "rectilinear", + [AV_SPHERICAL_FISHEYE] = "fisheye", }; const char *av_spherical_projection_name(enum AVSphericalProjection projection) diff --git a/libavutil/spherical.h b/libavutil/spherical.h index 828ac836d..2e90f7752 100644 --- a/libavutil/spherical.h +++ b/libavutil/spherical.h @@ -66,6 +66,22 @@ enum AVSphericalProjection { * the position of the current video in a larger surface. */ AV_SPHERICAL_EQUIRECTANGULAR_TILE, + + /** + * Video frame displays as a 180 degree equirectangular projection. + */ + AV_SPHERICAL_HALF_EQUIRECTANGULAR, + + /** + * Video frame displays on a flat, rectangular 2D surface. + */ + AV_SPHERICAL_RECTILINEAR, + + /** + * Fisheye projection (Apple). + * See: https://developer.apple.com/documentation/coremedia/cmprojectiontype/fisheye + */ + AV_SPHERICAL_FISHEYE, }; /** diff --git a/libavutil/stereo3d.c b/libavutil/stereo3d.c index 9c29ab01b..d6de47653 100644 --- a/libavutil/stereo3d.c +++ b/libavutil/stereo3d.c @@ -26,9 +26,29 @@ #include "mem.h" #include "stereo3d.h" +static void get_defaults(AVStereo3D *stereo) +{ + stereo->horizontal_disparity_adjustment = (AVRational) { 0, 1 }; + stereo->horizontal_field_of_view = (AVRational) { 0, 1 }; +} + AVStereo3D *av_stereo3d_alloc(void) { - return av_mallocz(sizeof(AVStereo3D)); + return av_stereo3d_alloc_size(NULL); +} + +AVStereo3D *av_stereo3d_alloc_size(size_t *size) +{ + AVStereo3D *stereo = av_mallocz(sizeof(AVStereo3D)); + if (!stereo) + return NULL; + + get_defaults(stereo); + + if (size) + *size = sizeof(*stereo); + + return stereo; } AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame) @@ -40,6 +60,7 @@ AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame) return NULL; memset(side_data->data, 0, sizeof(AVStereo3D)); + get_defaults((AVStereo3D *)side_data->data); return (AVStereo3D *)side_data->data; } @@ -53,6 +74,20 @@ static const char * const stereo3d_type_names[] = { [AV_STEREO3D_SIDEBYSIDE_QUINCUNX] = "side by side (quincunx subsampling)", [AV_STEREO3D_LINES] = "interleaved lines", [AV_STEREO3D_COLUMNS] = "interleaved columns", + [AV_STEREO3D_UNSPEC] = "unspecified", +}; + +static const char * const stereo3d_view_names[] = { + [AV_STEREO3D_VIEW_PACKED] = "packed", + [AV_STEREO3D_VIEW_LEFT] = "left", + [AV_STEREO3D_VIEW_RIGHT] = "right", + [AV_STEREO3D_VIEW_UNSPEC] = "unspecified", +}; + +static const char * const stereo3d_primary_eye_names[] = { + [AV_PRIMARY_EYE_NONE] = "none", + [AV_PRIMARY_EYE_LEFT] = "left", + [AV_PRIMARY_EYE_RIGHT] = "right", }; const char *av_stereo3d_type_name(unsigned int type) @@ -74,3 +109,43 @@ int av_stereo3d_from_name(const char *name) return -1; } + +const char *av_stereo3d_view_name(unsigned int view) +{ + if (view >= FF_ARRAY_ELEMS(stereo3d_view_names)) + return "unknown"; + + return stereo3d_view_names[view]; +} + +int av_stereo3d_view_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(stereo3d_view_names); i++) { + if (av_strstart(name, stereo3d_view_names[i], NULL)) + return i; + } + + return -1; +} + +const char *av_stereo3d_primary_eye_name(unsigned int eye) +{ + if (eye >= FF_ARRAY_ELEMS(stereo3d_primary_eye_names)) + return "unknown"; + + return stereo3d_primary_eye_names[eye]; +} + +int av_stereo3d_primary_eye_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(stereo3d_primary_eye_names); i++) { + if (av_strstart(name, stereo3d_primary_eye_names[i], NULL)) + return i; + } + + return -1; +} diff --git a/libavutil/stereo3d.h b/libavutil/stereo3d.h index 3aab959b7..c0a4ab3f2 100644 --- a/libavutil/stereo3d.h +++ b/libavutil/stereo3d.h @@ -136,6 +136,11 @@ enum AVStereo3DType { * @endcode */ AV_STEREO3D_COLUMNS, + + /** + * Video is stereoscopic but the packing is unspecified. + */ + AV_STEREO3D_UNSPEC, }; /** @@ -156,6 +161,31 @@ enum AVStereo3DView { * Frame contains only the right view. */ AV_STEREO3D_VIEW_RIGHT, + + /** + * Content is unspecified. + */ + AV_STEREO3D_VIEW_UNSPEC, +}; + +/** + * List of possible primary eyes. + */ +enum AVStereo3DPrimaryEye { + /** + * Neither eye. + */ + AV_PRIMARY_EYE_NONE, + + /** + * Left eye. + */ + AV_PRIMARY_EYE_LEFT, + + /** + * Right eye + */ + AV_PRIMARY_EYE_RIGHT, }; /** @@ -185,6 +215,28 @@ typedef struct AVStereo3D { * Determines which views are packed. */ enum AVStereo3DView view; + + /** + * Which eye is the primary eye when rendering in 2D. + */ + enum AVStereo3DPrimaryEye primary_eye; + + /** + * The distance between the centres of the lenses of the camera system, + * in micrometers. Zero if unset. + */ + uint32_t baseline; + + /** + * Relative shift of the left and right images, which changes the zero parallax plane. + * Range is -1.0 to 1.0. Zero if unset. + */ + AVRational horizontal_disparity_adjustment; + + /** + * Horizontal field of view, in degrees. Zero if unset. + */ + AVRational horizontal_field_of_view; } AVStereo3D; /** @@ -195,6 +247,14 @@ typedef struct AVStereo3D { */ AVStereo3D *av_stereo3d_alloc(void); +/** + * Allocate an AVStereo3D structure and set its fields to default values. + * The resulting struct can be freed using av_freep(). + * + * @return An AVStereo3D filled with default values or NULL on failure. + */ +AVStereo3D *av_stereo3d_alloc_size(size_t *size); + /** * Allocate a complete AVFrameSideData and add it to the frame. * @@ -222,6 +282,42 @@ const char *av_stereo3d_type_name(unsigned int type); */ int av_stereo3d_from_name(const char *name); +/** + * Provide a human-readable name of a given stereo3d view. + * + * @param type The input stereo3d view value. + * + * @return The name of the stereo3d view value, or "unknown". + */ +const char *av_stereo3d_view_name(unsigned int view); + +/** + * Get the AVStereo3DView form a human-readable name. + * + * @param name The input string. + * + * @return The AVStereo3DView value, or -1 if not found. + */ +int av_stereo3d_view_from_name(const char *name); + +/** + * Provide a human-readable name of a given stereo3d primary eye. + * + * @param type The input stereo3d primary eye value. + * + * @return The name of the stereo3d primary eye value, or "unknown". + */ +const char *av_stereo3d_primary_eye_name(unsigned int eye); + +/** + * Get the AVStereo3DPrimaryEye form a human-readable name. + * + * @param name The input string. + * + * @return The AVStereo3DPrimaryEye value, or -1 if not found. + */ +int av_stereo3d_primary_eye_from_name(const char *name); + /** * @} */ diff --git a/libavutil/tests/cpu.c b/libavutil/tests/cpu.c index d91bfeab5..53e9f9995 100644 --- a/libavutil/tests/cpu.c +++ b/libavutil/tests/cpu.c @@ -51,6 +51,8 @@ static const struct { { AV_CPU_FLAG_SETEND, "setend" }, #elif ARCH_PPC { AV_CPU_FLAG_ALTIVEC, "altivec" }, + { AV_CPU_FLAG_VSX, "vsx" }, + { AV_CPU_FLAG_POWER8, "power8" }, #elif ARCH_MIPS { AV_CPU_FLAG_MMI, "mmi" }, { AV_CPU_FLAG_MSA, "msa" }, @@ -86,14 +88,14 @@ static const struct { { AV_CPU_FLAG_LASX, "lasx" }, #elif ARCH_RISCV { AV_CPU_FLAG_RVI, "rvi" }, - { AV_CPU_FLAG_RVF, "rvf" }, - { AV_CPU_FLAG_RVD, "rvd" }, - { AV_CPU_FLAG_RVB_ADDR, "zba" }, { AV_CPU_FLAG_RVB_BASIC, "zbb" }, + { AV_CPU_FLAG_RVB, "rvb" }, { AV_CPU_FLAG_RVV_I32, "zve32x" }, { AV_CPU_FLAG_RVV_F32, "zve32f" }, { AV_CPU_FLAG_RVV_I64, "zve64x" }, { AV_CPU_FLAG_RVV_F64, "zve64d" }, + { AV_CPU_FLAG_RV_ZVBB, "zvbb" }, + { AV_CPU_FLAG_RV_MISALIGNED, "misaligned" }, #endif { 0 } }; diff --git a/libavutil/tests/dict.c b/libavutil/tests/dict.c index d60081889..21368203c 100644 --- a/libavutil/tests/dict.c +++ b/libavutil/tests/dict.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" + #include "libavutil/dict.c" static const AVDictionaryEntry *dict_iterate(const AVDictionary *m, diff --git a/libavutil/tests/imgutils.c b/libavutil/tests/imgutils.c index 582a35815..6a5097bc3 100644 --- a/libavutil/tests/imgutils.c +++ b/libavutil/tests/imgutils.c @@ -18,6 +18,7 @@ #include "libavutil/imgutils.c" #include "libavutil/crc.h" +#include "libavutil/mem.h" #undef printf static int check_image_fill(enum AVPixelFormat pix_fmt, int w, int h) { diff --git a/libavutil/tests/lfg.c b/libavutil/tests/lfg.c index bf127e303..859ada73a 100644 --- a/libavutil/tests/lfg.c +++ b/libavutil/tests/lfg.c @@ -17,6 +17,7 @@ */ #include "libavutil/log.h" +#include "libavutil/mem.h" #include "libavutil/timer.h" #include "libavutil/lfg.h" diff --git a/libavutil/tests/opt.c b/libavutil/tests/opt.c index 281ad0dc3..bfe351b4b 100644 --- a/libavutil/tests/opt.c +++ b/libavutil/tests/opt.c @@ -30,7 +30,9 @@ typedef struct TestContext { const AVClass *class; + struct ChildContext *child; int num; + int unum; int toggle; char *string; int flags; @@ -85,7 +87,8 @@ static const AVOptionArrayDef array_dict = { }; static const AVOption test_options[]= { - {"num", "set num", OFFSET(num), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, 1 }, + {"num", "set num", OFFSET(num), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, 100, 1 }, + {"unum", "set unum", OFFSET(unum), AV_OPT_TYPE_UINT, { .i64 = 1U << 31 }, 0, 1U << 31, 1 }, {"toggle", "set toggle", OFFSET(toggle), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, 1 }, {"rational", "set rational", OFFSET(rational), AV_OPT_TYPE_RATIONAL, { .dbl = 1 }, 0, 10, 1 }, {"string", "set string", OFFSET(string), AV_OPT_TYPE_STRING, { .str = "default" }, CHAR_MIN, CHAR_MAX, 1 }, @@ -104,7 +107,7 @@ static const AVOption test_options[]= { {"bin", "set binary value", OFFSET(binary), AV_OPT_TYPE_BINARY, { .str="62696e00" }, 0, 0, 1 }, {"bin1", "set binary value", OFFSET(binary1), AV_OPT_TYPE_BINARY, { .str=NULL }, 0, 0, 1 }, {"bin2", "set binary value", OFFSET(binary2), AV_OPT_TYPE_BINARY, { .str="" }, 0, 0, 1 }, - {"num64", "set num 64bit", OFFSET(num64), AV_OPT_TYPE_INT64, { .i64 = 1 }, 0, 100, 1 }, + {"num64", "set num 64bit", OFFSET(num64), AV_OPT_TYPE_INT64, { .i64 = 1LL << 32 }, -1, 1LL << 32, 1 }, {"flt", "set float", OFFSET(flt), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 / 3 }, 0, 100, 1 }, {"dbl", "set double", OFFSET(dbl), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 / 3 }, 0, 100, 1 }, {"bool1", "set boolean value", OFFSET(bool1), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, 1 }, @@ -123,10 +126,46 @@ static const char *test_get_name(void *ctx) return "test"; } +typedef struct ChildContext { + const AVClass *class; + int64_t child_num64; + int child_num; +} ChildContext; + +#undef OFFSET +#define OFFSET(x) offsetof(ChildContext, x) + +static const AVOption child_options[]= { + {"child_num64", "set num 64bit", OFFSET(child_num64), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, 100, 1 }, + {"child_num", "set child_num", OFFSET(child_num), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 100, 1 }, + { NULL }, +}; + +static const char *child_get_name(void *ctx) +{ + return "child"; +} + +static const AVClass child_class = { + .class_name = "ChildContext", + .item_name = child_get_name, + .option = child_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static void *test_child_next(void *obj, void *prev) +{ + TestContext *test_ctx = obj; + if (!prev) + return test_ctx->child; + return NULL; +} + static const AVClass test_class = { .class_name = "TestContext", .item_name = test_get_name, .option = test_options, + .child_next = test_child_next, .version = LIBAVUTIL_VERSION_INT, }; @@ -149,6 +188,7 @@ int main(void) av_opt_set_defaults(&test_ctx); printf("num=%d\n", test_ctx.num); + printf("unum=%u\n", test_ctx.unum); printf("toggle=%d\n", test_ctx.toggle); printf("string=%s\n", test_ctx.string); printf("escape=%s\n", test_ctx.escape); @@ -260,6 +300,69 @@ int main(void) av_opt_free(&test2_ctx); } + printf("\nTesting av_opt_get_array()\n"); + { + static const int int_array[] = { 5, 0, 42, 137, INT_MAX }; + + TestContext test_ctx = { 0 }; + + int out_int [FF_ARRAY_ELEMS(int_array)] = { 0 }; + double out_double[FF_ARRAY_ELEMS(int_array)] = { 0. }; + char *out_str [FF_ARRAY_ELEMS(int_array)] = { NULL }; + AVDictionary *out_dict[2] = { NULL }; + + int ret; + + test_ctx.class = &test_class; + + av_log_set_level(AV_LOG_QUIET); + + av_opt_set_defaults(&test_ctx); + + test_ctx.array_int = av_memdup(int_array, sizeof(int_array)); + test_ctx.nb_array_int = FF_ARRAY_ELEMS(int_array); + + // retrieve as int + ret = av_opt_get_array(&test_ctx, "array_int", 0, + 1, 3, AV_OPT_TYPE_INT, out_int); + printf("av_opt_get_array(\"array_int\", 1, 3, INT)=%d -> [ %d, %d, %d ]\n", + ret, out_int[0], out_int[1], out_int[2]); + + // retrieve as double + ret = av_opt_get_array(&test_ctx, "array_int", 0, + 3, 2, AV_OPT_TYPE_DOUBLE, out_double); + printf("av_opt_get_array(\"array_int\", 3, 2, DOUBLE)=%d -> [ %.2f, %.2f ]\n", + ret, out_double[0], out_double[1]); + + // retrieve as str + ret = av_opt_get_array(&test_ctx, "array_int", 0, + 0, 5, AV_OPT_TYPE_STRING, out_str); + printf("av_opt_get_array(\"array_int\", 0, 5, STRING)=%d -> " + "[ %s, %s, %s, %s, %s ]\n", ret, + out_str[0], out_str[1], out_str[2], out_str[3], out_str[4]); + + for (int i = 0; i < FF_ARRAY_ELEMS(out_str); i++) + av_freep(&out_str[i]); + + ret = av_opt_get_array(&test_ctx, "array_dict", 0, 0, 2, + AV_OPT_TYPE_DICT, out_dict); + printf("av_opt_get_array(\"array_dict\", 0, 2, DICT)=%d\n", ret); + + for (int i = 0; i < test_ctx.nb_array_dict; i++) { + const AVDictionaryEntry *e = NULL; + while ((e = av_dict_iterate(test_ctx.array_dict[i], e))) { + const AVDictionaryEntry *e1 = av_dict_get(out_dict[i], e->key, NULL, 0); + if (!e1 || strcmp(e->value, e1->value)) { + printf("mismatching dict entry %s: %s/%s\n", + e->key, e->value, e1 ? e1->value : ""); + } + } + av_dict_free(&out_dict[i]); + } + + av_opt_free(&test_ctx); + } + printf("\nTest av_opt_serialize()\n"); { TestContext test_ctx = { 0 }; @@ -280,8 +383,19 @@ int main(void) if (ret < 0) printf("Error ret '%d'\n", ret); if (av_opt_serialize(&test_ctx, 0, 0, &buf, '=', ',') >= 0) { + ChildContext child_ctx = { 0 }; printf("%s\n", buf); av_free(buf); + child_ctx.class = &child_class; + test_ctx.child = &child_ctx; + if (av_opt_serialize(&test_ctx, 0, + AV_OPT_SERIALIZE_SKIP_DEFAULTS|AV_OPT_SERIALIZE_SEARCH_CHILDREN, + &buf, '=', ',') >= 0) { + printf("%s\n", buf); + av_free(buf); + } + av_opt_free(&child_ctx); + test_ctx.child = NULL; } } av_opt_free(&test_ctx); @@ -335,11 +449,25 @@ int main(void) "bin=boguss", "bin=111", "bin=ffff", + "num=bogus", + "num=44", + "num=44.4", + "num=-1", + "num=-2", + "num=101", + "unum=bogus", + "unum=44", + "unum=44.4", + "unum=-1", + "unum=2147483648", + "unum=2147483649", "num64=bogus", "num64=44", "num64=44.4", "num64=-1", - "num64=101", + "num64=-2", + "num64=4294967296", + "num64=4294967297", "flt=bogus", "flt=2", "flt=2.2", @@ -407,5 +535,54 @@ int main(void) av_opt_free(&test_ctx); } + printf("\nTesting av_opt_find2()\n"); + { + TestContext test_ctx = { 0 }; + ChildContext child_ctx = { 0 }; + void *target; + const AVOption *opt; + + test_ctx.class = &test_class; + child_ctx.class = &child_class; + test_ctx.child = &child_ctx; + + av_log_set_level(AV_LOG_QUIET); + + // Should succeed. num exists and has opt_flags 1 + opt = av_opt_find2(&test_ctx, "num", NULL, 1, 0, &target); + if (opt && target == &test_ctx) + printf("OK '%s'\n", opt->name); + else + printf("Error 'num'\n"); + + // Should fail. num64 exists but has opt_flags 1, not 2 + opt = av_opt_find(&test_ctx, "num64", NULL, 2, 0); + if (opt) + printf("OK '%s'\n", opt->name); + else + printf("Error 'num64'\n"); + + // Should fail. child_num exists but in a child object we're not searching + opt = av_opt_find(&test_ctx, "child_num", NULL, 0, 0); + if (opt) + printf("OK '%s'\n", opt->name); + else + printf("Error 'child_num'\n"); + + // Should succeed. child_num exists in a child object we're searching + opt = av_opt_find2(&test_ctx, "child_num", NULL, 0, AV_OPT_SEARCH_CHILDREN, &target); + if (opt && target == &child_ctx) + printf("OK '%s'\n", opt->name); + else + printf("Error 'child_num'\n"); + + // Should fail. foo doesn't exist + opt = av_opt_find(&test_ctx, "foo", NULL, 0, 0); + if (opt) + printf("OK '%s'\n", opt->name); + else + printf("Error 'foo'\n"); + } + return 0; } diff --git a/libavutil/tests/side_data_array.c b/libavutil/tests/side_data_array.c index 793a62c00..633e9ee68 100644 --- a/libavutil/tests/side_data_array.c +++ b/libavutil/tests/side_data_array.c @@ -20,23 +20,22 @@ #include #include "libavutil/frame.c" -#include "libavutil/mastering_display_metadata.h" +#include "libavutil/internal.h" -static void print_clls(const AVFrameSideData **sd, const int nb_sd) +static void print_entries(const AVFrameSideData **sd, const int nb_sd) { for (int i = 0; i < nb_sd; i++) { const AVFrameSideData *entry = sd[i]; - printf("sd %d, %s", - i, av_frame_side_data_name(entry->type)); + printf("sd %d (size %"SIZE_SPECIFIER"), %s", + i, entry->size, av_frame_side_data_name(entry->type)); - if (entry->type != AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) { + if (entry->type != AV_FRAME_DATA_SEI_UNREGISTERED) { putchar('\n'); continue; } - printf(": MaxCLL: %u\n", - ((AVContentLightMetadata *)entry->data)->MaxCLL); + printf(": %d\n", *(int32_t *)entry->data); } } @@ -51,51 +50,60 @@ int main(void) av_assert0( av_frame_side_data_new(&set.sd, &set.nb_sd, - AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT, - 0, 0)); + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + sizeof(int64_t), 0)); + av_assert0( + av_frame_side_data_new(&set.sd, &set.nb_sd, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + sizeof(int32_t), AV_FRAME_SIDE_DATA_FLAG_REPLACE)); // test entries in the middle for (int value = 1; value < 4; value++) { AVFrameSideData *sd = av_frame_side_data_new( - &set.sd, &set.nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, - sizeof(AVContentLightMetadata), 0); + &set.sd, &set.nb_sd, AV_FRAME_DATA_SEI_UNREGISTERED, + sizeof(int32_t), 0); av_assert0(sd); - ((AVContentLightMetadata *)sd->data)->MaxCLL = value; + *(int32_t *)sd->data = value; } av_assert0( av_frame_side_data_new( - &set.sd, &set.nb_sd, AV_FRAME_DATA_SPHERICAL, 0, 0)); + &set.sd, &set.nb_sd, AV_FRAME_DATA_SPHERICAL, + sizeof(int64_t), 0)); + + av_assert0( + av_frame_side_data_new( + &set.sd, &set.nb_sd, AV_FRAME_DATA_SPHERICAL, + sizeof(int32_t), AV_FRAME_SIDE_DATA_FLAG_REPLACE)); // test entries at the end for (int value = 1; value < 4; value++) { AVFrameSideData *sd = av_frame_side_data_new( - &set.sd, &set.nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, - sizeof(AVContentLightMetadata), 0); + &set.sd, &set.nb_sd, AV_FRAME_DATA_SEI_UNREGISTERED, + sizeof(int32_t), 0); av_assert0(sd); - ((AVContentLightMetadata *)sd->data)->MaxCLL = value + 3; + *(int32_t *)sd->data = value + 3; } puts("Initial addition results with duplicates:"); - print_clls((const AVFrameSideData **)set.sd, set.nb_sd); + print_entries((const AVFrameSideData **)set.sd, set.nb_sd); { AVFrameSideData *sd = av_frame_side_data_new( - &set.sd, &set.nb_sd, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, - sizeof(AVContentLightMetadata), - AV_FRAME_SIDE_DATA_FLAG_UNIQUE); + &set.sd, &set.nb_sd, AV_FRAME_DATA_SEI_UNREGISTERED, + sizeof(int32_t), AV_FRAME_SIDE_DATA_FLAG_UNIQUE); av_assert0(sd); - ((AVContentLightMetadata *)sd->data)->MaxCLL = 1337; + *(int32_t *)sd->data = 1337; } puts("\nFinal state after a single 'no-duplicates' addition:"); - print_clls((const AVFrameSideData **)set.sd, set.nb_sd); + print_entries((const AVFrameSideData **)set.sd, set.nb_sd); av_frame_side_data_free(&set.sd, &set.nb_sd); diff --git a/libavutil/tests/tea.c b/libavutil/tests/tea.c index 605bb524a..738920e99 100644 --- a/libavutil/tests/tea.c +++ b/libavutil/tests/tea.c @@ -25,6 +25,7 @@ #include #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/tea.h" #define TEA_NUM_TESTS 4 diff --git a/libavutil/tests/tree.c b/libavutil/tests/tree.c index 750322897..5cd3e70de 100644 --- a/libavutil/tests/tree.c +++ b/libavutil/tests/tree.c @@ -23,6 +23,7 @@ #include "libavutil/common.h" #include "libavutil/lfg.h" #include "libavutil/log.h" +#include "libavutil/mem.h" static int check(AVTreeNode *t) { diff --git a/libavutil/timecode.c b/libavutil/timecode.c index f40a10eb3..f454466f9 100644 --- a/libavutil/timecode.c +++ b/libavutil/timecode.c @@ -61,8 +61,8 @@ uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum) framenum = av_timecode_adjust_ntsc_framenum2(framenum, tc->fps); ff = framenum % fps; ss = framenum / fps % 60; - mm = framenum / (fps*60) % 60; - hh = framenum / (fps*3600) % 24; + mm = framenum / (fps*60LL) % 60; + hh = framenum / (fps*3600LL) % 24; return av_timecode_get_smpte(tc->rate, drop, hh, mm, ss, ff); } diff --git a/libavutil/timer.h b/libavutil/timer.h index 2cd299eca..03706b0d1 100644 --- a/libavutil/timer.h +++ b/libavutil/timer.h @@ -44,8 +44,12 @@ #if CONFIG_MACOS_KPERF #include "macos_kperf.h" -#elif HAVE_MACH_ABSOLUTE_TIME +#endif + +#if HAVE_MACH_ABSOLUTE_TIME #include +#elif HAVE_CLOCK_GETTIME +#include #endif #include "common.h" @@ -57,8 +61,6 @@ # include "arm/timer.h" #elif ARCH_PPC # include "ppc/timer.h" -#elif ARCH_RISCV -# include "riscv/timer.h" #elif ARCH_X86 # include "x86/timer.h" #elif ARCH_LOONGARCH @@ -70,6 +72,15 @@ # define AV_READ_TIME gethrtime # elif HAVE_MACH_ABSOLUTE_TIME # define AV_READ_TIME mach_absolute_time +# elif HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) + static inline int64_t ff_read_time(void) + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * INT64_C(1000000000) + ts.tv_nsec; + } +# define AV_READ_TIME ff_read_time +# define FF_TIMER_UNITS "ns" # endif #endif diff --git a/libavutil/tx.c b/libavutil/tx.c index 7a0e9effb..0aae4c7cf 100644 --- a/libavutil/tx.c +++ b/libavutil/tx.c @@ -19,6 +19,7 @@ #include "avassert.h" #include "intmath.h" #include "cpu.h" +#include "mem.h" #include "qsort.h" #include "bprint.h" diff --git a/libavutil/tx_template.c b/libavutil/tx_template.c index a2c27465c..701ef0d6d 100644 --- a/libavutil/tx_template.c +++ b/libavutil/tx_template.c @@ -24,6 +24,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "mem.h" + #define TABLE_DEF(name, size) \ DECLARE_ALIGNED(32, TXSample, TX_TAB(ff_tx_tab_ ##name))[size] diff --git a/libavutil/version.c b/libavutil/version.c index baead7c4a..afab19033 100644 --- a/libavutil/version.c +++ b/libavutil/version.c @@ -18,8 +18,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "config.h" -#include "avassert.h" #include "avutil.h" #include "samplefmt.h" #include "version.h" @@ -34,10 +35,11 @@ const char *av_version_info(void) unsigned avutil_version(void) { - av_assert0(AV_SAMPLE_FMT_DBLP == 9); - av_assert0(AVMEDIA_TYPE_ATTACHMENT == 4); - av_assert0(AV_PICTURE_TYPE_BI == 7); - av_assert0(LIBAVUTIL_VERSION_MICRO >= 100); + static_assert(AV_SAMPLE_FMT_S64P == 11 && + AVMEDIA_TYPE_ATTACHMENT == 4 && + AV_PICTURE_TYPE_BI == 7, + "Don't insert new sample/media/picture types in the middle of the list"); + static_assert(LIBAVUTIL_VERSION_MICRO >= 100, "micro version starts at 100"); return LIBAVUTIL_VERSION_INT; } diff --git a/libavutil/version.h b/libavutil/version.h index 0a3f5dd0c..753f85b91 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 59 -#define LIBAVUTIL_VERSION_MINOR 8 +#define LIBAVUTIL_VERSION_MINOR 39 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ @@ -112,6 +112,9 @@ #define FF_API_PALETTE_HAS_CHANGED (LIBAVUTIL_VERSION_MAJOR < 60) #define FF_API_VULKAN_CONTIGUOUS_MEMORY (LIBAVUTIL_VERSION_MAJOR < 60) #define FF_API_H274_FILM_GRAIN_VCS (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_MOD_UINTP2 (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_RISCV_FD_ZBA (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_VULKAN_FIXED_QUEUES (LIBAVUTIL_VERSION_MAJOR < 60) /** * @} diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c index 67b952625..046ac5d67 100644 --- a/libavutil/vulkan.c +++ b/libavutil/vulkan.c @@ -19,8 +19,10 @@ */ #include "avassert.h" +#include "mem.h" #include "vulkan.h" +#include "libavutil/vulkan_loader.h" const VkComponentMapping ff_comp_identity_map = { .r = VK_COMPONENT_SWIZZLE_IDENTITY, @@ -82,6 +84,25 @@ const char *ff_vk_ret2str(VkResult res) #undef CASE } +static void load_enabled_qfs(FFVulkanContext *s) +{ + s->nb_qfs = 0; + for (int i = 0; i < s->hwctx->nb_qf; i++) { + /* Skip duplicates */ + int skip = 0; + for (int j = 0; j < s->nb_qfs; j++) { + if (s->qfs[j] == s->hwctx->qf[i].idx) { + skip = 1; + break; + } + } + if (skip) + continue; + + s->qfs[s->nb_qfs++] = s->hwctx->qf[i].idx; + } +} + int ff_vk_load_props(FFVulkanContext *s) { FFVulkanFunctions *vk = &s->vkfn; @@ -89,9 +110,13 @@ int ff_vk_load_props(FFVulkanContext *s) s->hprops = (VkPhysicalDeviceExternalMemoryHostPropertiesEXT) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT, }; + s->optical_flow_props = (VkPhysicalDeviceOpticalFlowPropertiesNV) { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV, + .pNext = &s->hprops, + }; s->coop_matrix_props = (VkPhysicalDeviceCooperativeMatrixPropertiesKHR) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR, - .pNext = &s->hprops, + .pNext = &s->optical_flow_props, }; s->subgroup_props = (VkPhysicalDeviceSubgroupSizeControlProperties) { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, @@ -126,6 +151,8 @@ int ff_vk_load_props(FFVulkanContext *s) vk->GetPhysicalDeviceMemoryProperties(s->hwctx->phys_dev, &s->mprops); vk->GetPhysicalDeviceFeatures2(s->hwctx->phys_dev, &s->feats); + load_enabled_qfs(s); + if (s->qf_props) return 0; @@ -188,66 +215,22 @@ int ff_vk_load_props(FFVulkanContext *s) static int vk_qf_get_index(FFVulkanContext *s, VkQueueFlagBits dev_family, int *nb) { - int ret, num; - - switch (dev_family) { - case VK_QUEUE_GRAPHICS_BIT: - ret = s->hwctx->queue_family_index; - num = s->hwctx->nb_graphics_queues; - break; - case VK_QUEUE_COMPUTE_BIT: - ret = s->hwctx->queue_family_comp_index; - num = s->hwctx->nb_comp_queues; - break; - case VK_QUEUE_TRANSFER_BIT: - ret = s->hwctx->queue_family_tx_index; - num = s->hwctx->nb_tx_queues; - break; - case VK_QUEUE_VIDEO_ENCODE_BIT_KHR: - ret = s->hwctx->queue_family_encode_index; - num = s->hwctx->nb_encode_queues; - break; - case VK_QUEUE_VIDEO_DECODE_BIT_KHR: - ret = s->hwctx->queue_family_decode_index; - num = s->hwctx->nb_decode_queues; - break; - default: - av_assert0(0); /* Should never happen */ + for (int i = 0; i < s->hwctx->nb_qf; i++) { + if (s->hwctx->qf[i].flags & dev_family) { + *nb = s->hwctx->qf[i].num; + return s->hwctx->qf[i].idx; + } } - if (nb) - *nb = num; - - return ret; + av_assert0(0); /* Should never happen */ } int ff_vk_qf_init(FFVulkanContext *s, FFVkQueueFamilyCtx *qf, VkQueueFlagBits dev_family) { /* Fill in queue families from context if not done yet */ - if (!s->nb_qfs) { - s->nb_qfs = 0; - - /* Simply fills in all unique queues into s->qfs */ - if (s->hwctx->queue_family_index >= 0) - s->qfs[s->nb_qfs++] = s->hwctx->queue_family_index; - if (!s->nb_qfs || s->qfs[0] != s->hwctx->queue_family_tx_index) - s->qfs[s->nb_qfs++] = s->hwctx->queue_family_tx_index; - if (!s->nb_qfs || (s->qfs[0] != s->hwctx->queue_family_comp_index && - s->qfs[1] != s->hwctx->queue_family_comp_index)) - s->qfs[s->nb_qfs++] = s->hwctx->queue_family_comp_index; - if (s->hwctx->queue_family_decode_index >= 0 && - (s->qfs[0] != s->hwctx->queue_family_decode_index && - s->qfs[1] != s->hwctx->queue_family_decode_index && - s->qfs[2] != s->hwctx->queue_family_decode_index)) - s->qfs[s->nb_qfs++] = s->hwctx->queue_family_decode_index; - if (s->hwctx->queue_family_encode_index >= 0 && - (s->qfs[0] != s->hwctx->queue_family_encode_index && - s->qfs[1] != s->hwctx->queue_family_encode_index && - s->qfs[2] != s->hwctx->queue_family_encode_index && - s->qfs[3] != s->hwctx->queue_family_encode_index)) - s->qfs[s->nb_qfs++] = s->hwctx->queue_family_encode_index; - } + if (!s->nb_qfs) + load_enabled_qfs(s); return (qf->queue_family = vk_qf_get_index(s, dev_family, &qf->nb_queues)); } @@ -304,6 +287,15 @@ int ff_vk_exec_pool_init(FFVulkanContext *s, FFVkQueueFamilyCtx *qf, VkCommandPoolCreateInfo cqueue_create; VkCommandBufferAllocateInfo cbuf_create; + const VkQueryPoolVideoEncodeFeedbackCreateInfoKHR *ef = NULL; + + if (query_type == VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR) { + ef = ff_vk_find_struct(query_create_pnext, + VK_STRUCTURE_TYPE_QUERY_POOL_VIDEO_ENCODE_FEEDBACK_CREATE_INFO_KHR); + if (!ef) + return AVERROR(EINVAL); + } + /* Create command pool */ cqueue_create = (VkCommandPoolCreateInfo) { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, @@ -361,21 +353,18 @@ int ff_vk_exec_pool_init(FFVulkanContext *s, FFVkQueueFamilyCtx *qf, } pool->nb_queries = nb_queries; - pool->query_status_stride = 2; + pool->query_status_stride = 1 + 1; /* One result, one status by default */ pool->query_results = nb_queries; - pool->query_statuses = 0; /* if radv supports it, nb_queries; */ + pool->query_statuses = nb_queries; -#if 0 /* CONFIG_VULKAN_ENCODE */ /* Video encode quieries produce two results per query */ if (query_type == VK_QUERY_TYPE_VIDEO_ENCODE_FEEDBACK_KHR) { - pool->query_status_stride = 3; /* skip,skip,result,skip,skip,result */ - pool->query_results *= 2; - } else -#endif - if (query_type == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR) { + int nb_results = av_popcount(ef->encodeFeedbackFlags); + pool->query_status_stride = nb_results + 1; + pool->query_results *= nb_results; + } else if (query_type == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR) { pool->query_status_stride = 1; pool->query_results = 0; - pool->query_statuses = nb_queries; } pool->qd_size = (pool->query_results + pool->query_statuses)*(query_64bit ? 8 : 4); @@ -444,53 +433,31 @@ fail: } VkResult ff_vk_exec_get_query(FFVulkanContext *s, FFVkExecContext *e, - void **data, int64_t *status) + void **data, VkQueryResultFlagBits flags) { - VkResult ret; FFVulkanFunctions *vk = &s->vkfn; const FFVkExecPool *pool = e->parent; + VkQueryResultFlags qf = flags & ~(VK_QUERY_RESULT_64_BIT | + VK_QUERY_RESULT_WITH_STATUS_BIT_KHR); - int32_t *res32 = e->query_data; - int64_t *res64 = e->query_data; - int64_t res = 0; - VkQueryResultFlags qf = 0; - - if (!e->had_submission) - return VK_NOT_READY; + if (!e->query_data) { + av_log(s, AV_LOG_ERROR, "Requested a query with a NULL query_data pointer!\n"); + return VK_INCOMPLETE; + } qf |= pool->query_64bit ? VK_QUERY_RESULT_64_BIT : 0x0; qf |= pool->query_statuses ? VK_QUERY_RESULT_WITH_STATUS_BIT_KHR : 0x0; - ret = vk->GetQueryPoolResults(s->hwctx->act_dev, pool->query_pool, - e->query_idx, - pool->nb_queries, - pool->qd_size, e->query_data, - pool->query_64bit ? 8 : 4, qf); - if (ret != VK_SUCCESS) - return ret; - - if (pool->query_statuses && pool->query_64bit) { - for (int i = 0; i < pool->query_statuses; i++) { - res = (res64[i] < res) || (res >= 0 && res64[i] > res) ? - res64[i] : res; - res64 += pool->query_status_stride; - } - } else if (pool->query_statuses) { - for (int i = 0; i < pool->query_statuses; i++) { - res = (res32[i] < res) || (res >= 0 && res32[i] > res) ? - res32[i] : res; - res32 += pool->query_status_stride; - } - } - if (data) *data = e->query_data; - if (status) - *status = res; - return VK_SUCCESS; + return vk->GetQueryPoolResults(s->hwctx->act_dev, pool->query_pool, + e->query_idx, + pool->nb_queries, + pool->qd_size, e->query_data, + pool->qd_size, qf); } FFVkExecContext *ff_vk_exec_get(FFVkExecPool *pool) @@ -595,6 +562,104 @@ int ff_vk_exec_add_dep_buf(FFVulkanContext *s, FFVkExecContext *e, return 0; } +#define ARR_REALLOC(str, arr, alloc_s, cnt) \ + do { \ + arr = av_fast_realloc(str->arr, alloc_s, (cnt + 1)*sizeof(*arr)); \ + if (!arr) { \ + ff_vk_exec_discard_deps(s, e); \ + return AVERROR(ENOMEM); \ + } \ + str->arr = arr; \ + } while (0) + +typedef struct TempSyncCtx { + int nb_sem; + VkSemaphore sem[]; +} TempSyncCtx; + +static void destroy_tmp_semaphores(void *opaque, uint8_t *data) +{ + FFVulkanContext *s = opaque; + FFVulkanFunctions *vk = &s->vkfn; + TempSyncCtx *ts = (TempSyncCtx *)data; + + for (int i = 0; i < ts->nb_sem; i++) + vk->DestroySemaphore(s->hwctx->act_dev, ts->sem[i], s->hwctx->alloc); + + av_free(ts); +} + +int ff_vk_exec_add_dep_bool_sem(FFVulkanContext *s, FFVkExecContext *e, + VkSemaphore *sem, int nb, + VkPipelineStageFlagBits2 stage, + int wait) +{ + int err; + size_t buf_size; + AVBufferRef *buf; + TempSyncCtx *ts; + FFVulkanFunctions *vk = &s->vkfn; + + /* Do not transfer ownership if we're signalling a binary semaphore, + * since we're probably exporting it. */ + if (!wait) { + for (int i = 0; i < nb; i++) { + VkSemaphoreSubmitInfo *sem_sig; + ARR_REALLOC(e, sem_sig, &e->sem_sig_alloc, e->sem_sig_cnt); + + e->sem_sig[e->sem_sig_cnt++] = (VkSemaphoreSubmitInfo) { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = sem[i], + .stageMask = stage, + }; + } + + return 0; + } + + buf_size = sizeof(int) + sizeof(VkSemaphore)*nb; + ts = av_mallocz(buf_size); + if (!ts) { + err = AVERROR(ENOMEM); + goto fail; + } + + memcpy(ts->sem, sem, nb*sizeof(*sem)); + ts->nb_sem = nb; + + buf = av_buffer_create((uint8_t *)ts, buf_size, destroy_tmp_semaphores, s, 0); + if (!buf) { + av_free(ts); + err = AVERROR(ENOMEM); + goto fail; + } + + err = ff_vk_exec_add_dep_buf(s, e, &buf, 1, 0); + if (err < 0) { + av_buffer_unref(&buf); + return err; + } + + for (int i = 0; i < nb; i++) { + VkSemaphoreSubmitInfo *sem_wait; + ARR_REALLOC(e, sem_wait, &e->sem_wait_alloc, e->sem_wait_cnt); + + e->sem_wait[e->sem_wait_cnt++] = (VkSemaphoreSubmitInfo) { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = sem[i], + .stageMask = stage, + }; + } + + return 0; + +fail: + for (int i = 0; i < nb; i++) + vk->DestroySemaphore(s->hwctx->act_dev, sem[i], s->hwctx->alloc); + + return err; +} + int ff_vk_exec_add_dep_frame(FFVulkanContext *s, FFVkExecContext *e, AVFrame *f, VkPipelineStageFlagBits2 wait_stage, VkPipelineStageFlagBits2 signal_stage) @@ -616,16 +681,6 @@ int ff_vk_exec_add_dep_frame(FFVulkanContext *s, FFVkExecContext *e, AVFrame *f, if (e->frame_deps[i]->data[0] == f->data[0]) return 1; -#define ARR_REALLOC(str, arr, alloc_s, cnt) \ - do { \ - arr = av_fast_realloc(str->arr, alloc_s, (cnt + 1)*sizeof(*arr)); \ - if (!arr) { \ - ff_vk_exec_discard_deps(s, e); \ - return AVERROR(ENOMEM); \ - } \ - str->arr = arr; \ - } while (0) - ARR_REALLOC(e, layout_dst, &e->layout_dst_alloc, e->nb_frame_deps); ARR_REALLOC(e, queue_family_dst, &e->queue_family_dst_alloc, e->nb_frame_deps); ARR_REALLOC(e, access_dst, &e->access_dst_alloc, e->nb_frame_deps); @@ -823,7 +878,7 @@ int ff_vk_alloc_mem(FFVulkanContext *s, VkMemoryRequirements *req, } if (index < 0) { - av_log(s->device, AV_LOG_ERROR, "No memory type found for flags 0x%x\n", + av_log(s, AV_LOG_ERROR, "No memory type found for flags 0x%x\n", req_flags); return AVERROR(EINVAL); } @@ -832,11 +887,8 @@ int ff_vk_alloc_mem(FFVulkanContext *s, VkMemoryRequirements *req, ret = vk->AllocateMemory(s->hwctx->act_dev, &alloc_info, s->hwctx->alloc, mem); - if (ret != VK_SUCCESS) { - av_log(s, AV_LOG_ERROR, "Failed to allocate memory: %s\n", - ff_vk_ret2str(ret)); + if (ret != VK_SUCCESS) return AVERROR(ENOMEM); - } if (mem_flags) *mem_flags |= s->mprops.memoryTypes[index].propertyFlags; @@ -881,7 +933,7 @@ int ff_vk_create_buf(FFVulkanContext *s, FFVkBuffer *buf, size_t size, .pNext = &ded_req, }; - ret = vk->CreateBuffer(s->hwctx->act_dev, &buf_spawn, NULL, &buf->buf); + ret = vk->CreateBuffer(s->hwctx->act_dev, &buf_spawn, s->hwctx->alloc, &buf->buf); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Failed to create buffer: %s\n", ff_vk_ret2str(ret)); @@ -1198,7 +1250,8 @@ int ff_vk_mt_is_np_rgb(enum AVPixelFormat pix_fmt) pix_fmt == AV_PIX_FMT_BGR24 || pix_fmt == AV_PIX_FMT_RGB48 || pix_fmt == AV_PIX_FMT_RGBA64 || pix_fmt == AV_PIX_FMT_RGB565 || pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_BGR0 || - pix_fmt == AV_PIX_FMT_0BGR || pix_fmt == AV_PIX_FMT_RGB0) + pix_fmt == AV_PIX_FMT_0BGR || pix_fmt == AV_PIX_FMT_RGB0 || + pix_fmt == AV_PIX_FMT_X2RGB10 || pix_fmt == AV_PIX_FMT_X2BGR10) return 1; return 0; } @@ -1211,8 +1264,8 @@ const char *ff_vk_shader_rep_fmt(enum AVPixelFormat pixfmt) } typedef struct ImageViewCtx { - VkImageView views[AV_NUM_DATA_POINTERS]; int nb_views; + VkImageView views[]; } ImageViewCtx; static void destroy_imageviews(void *opaque, uint8_t *data) @@ -1241,7 +1294,8 @@ int ff_vk_create_imageviews(FFVulkanContext *s, FFVkExecContext *e, const int nb_images = ff_vk_count_images(vkf); const int nb_planes = av_pix_fmt_count_planes(hwfc->sw_format); - ImageViewCtx *iv = av_mallocz(sizeof(*iv)); + const size_t buf_size = sizeof(int) + nb_planes*sizeof(VkImageView); + ImageViewCtx *iv = av_mallocz(buf_size); if (!iv) return AVERROR(ENOMEM); @@ -1278,7 +1332,7 @@ int ff_vk_create_imageviews(FFVulkanContext *s, FFVkExecContext *e, iv->nb_views++; } - buf = av_buffer_create((uint8_t *)iv, sizeof(*iv), destroy_imageviews, s, 0); + buf = av_buffer_create((uint8_t *)iv, buf_size, destroy_imageviews, s, 0); if (!buf) { err = AVERROR(ENOMEM); goto fail; @@ -1464,13 +1518,10 @@ static const struct descriptor_props { int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl, FFVkSPIRVShader *shd, FFVulkanDescriptorSetBinding *desc, int nb, - int read_only, int print_to_shader_only) + int singular, int print_to_shader_only) { - VkResult ret; int has_sampler = 0; - FFVulkanFunctions *vk = &s->vkfn; FFVulkanDescriptorSet *set; - VkDescriptorSetLayoutCreateInfo desc_create_layout; if (print_to_shader_only) goto print; @@ -1481,6 +1532,7 @@ int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl, if (!set) return AVERROR(ENOMEM); pl->desc_set = set; + set = &set[pl->nb_descriptor_sets]; memset(set, 0, sizeof(*set)); @@ -1494,13 +1546,6 @@ int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl, return AVERROR(ENOMEM); } - desc_create_layout = (VkDescriptorSetLayoutCreateInfo) { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = nb, - .pBindings = set->binding, - .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT, - }; - for (int i = 0; i < nb; i++) { set->binding[i].binding = i; set->binding[i].descriptorType = desc[i].type; @@ -1518,23 +1563,30 @@ int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl, if (has_sampler) set->usage |= VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; - ret = vk->CreateDescriptorSetLayout(s->hwctx->act_dev, &desc_create_layout, - s->hwctx->alloc, &set->layout); - if (ret != VK_SUCCESS) { - av_log(s, AV_LOG_ERROR, "Unable to init descriptor set layout: %s", - ff_vk_ret2str(ret)); - return AVERROR_EXTERNAL; + if (!(s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER)) { + for (int i = 0; i < nb; i++) { + int j; + VkDescriptorPoolSize *desc_pool_size; + for (j = 0; j < pl->nb_desc_pool_size; j++) + if (pl->desc_pool_size[j].type == desc[i].type) + break; + if (j >= pl->nb_desc_pool_size) { + desc_pool_size = av_realloc_array(pl->desc_pool_size, + sizeof(*desc_pool_size), + pl->nb_desc_pool_size + 1); + if (!desc_pool_size) + return AVERROR(ENOMEM); + + pl->desc_pool_size = desc_pool_size; + pl->nb_desc_pool_size++; + memset(&desc_pool_size[j], 0, sizeof(VkDescriptorPoolSize)); + } + pl->desc_pool_size[j].type = desc[i].type; + pl->desc_pool_size[j].descriptorCount += FFMAX(desc[i].elems, 1); + } } - vk->GetDescriptorSetLayoutSizeEXT(s->hwctx->act_dev, set->layout, &set->layout_size); - - set->aligned_size = FFALIGN(set->layout_size, s->desc_buf_props.descriptorBufferOffsetAlignment); - - for (int i = 0; i < nb; i++) - vk->GetDescriptorSetLayoutBindingOffsetEXT(s->hwctx->act_dev, set->layout, - i, &set->binding_offset[i]); - - set->read_only = read_only; + set->singular = singular; set->nb_bindings = nb; pl->nb_descriptor_sets++; @@ -1580,37 +1632,102 @@ int ff_vk_exec_pipeline_register(FFVulkanContext *s, FFVkExecPool *pool, { int err; - pl->desc_bind = av_calloc(pl->nb_descriptor_sets, sizeof(*pl->desc_bind)); - if (!pl->desc_bind) - return AVERROR(ENOMEM); + if (!pl->nb_descriptor_sets) + return 0; - pl->bound_buffer_indices = av_calloc(pl->nb_descriptor_sets, - sizeof(*pl->bound_buffer_indices)); - if (!pl->bound_buffer_indices) - return AVERROR(ENOMEM); + if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) { + pl->desc_bind = av_calloc(pl->nb_descriptor_sets, sizeof(*pl->desc_bind)); + if (!pl->desc_bind) + return AVERROR(ENOMEM); - for (int i = 0; i < pl->nb_descriptor_sets; i++) { - FFVulkanDescriptorSet *set = &pl->desc_set[i]; - int nb = set->read_only ? 1 : pool->pool_size; + pl->bound_buffer_indices = av_calloc(pl->nb_descriptor_sets, + sizeof(*pl->bound_buffer_indices)); + if (!pl->bound_buffer_indices) + return AVERROR(ENOMEM); - err = ff_vk_create_buf(s, &set->buf, set->aligned_size*nb, - NULL, NULL, set->usage, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - if (err < 0) - return err; + for (int i = 0; i < pl->nb_descriptor_sets; i++) { + FFVulkanDescriptorSet *set = &pl->desc_set[i]; + int nb = set->singular ? 1 : pool->pool_size; - err = ff_vk_map_buffer(s, &set->buf, &set->desc_mem, 0); - if (err < 0) - return err; + err = ff_vk_create_buf(s, &set->buf, set->aligned_size*nb, + NULL, NULL, set->usage, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (err < 0) + return err; - pl->desc_bind[i] = (VkDescriptorBufferBindingInfoEXT) { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT, - .usage = set->usage, - .address = set->buf.address, + err = ff_vk_map_buffer(s, &set->buf, &set->desc_mem, 0); + if (err < 0) + return err; + + pl->desc_bind[i] = (VkDescriptorBufferBindingInfoEXT) { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT, + .usage = set->usage, + .address = set->buf.address, + }; + + pl->bound_buffer_indices[i] = i; + } + } else if (!pl->use_push) { + VkResult ret; + FFVulkanFunctions *vk = &s->vkfn; + VkDescriptorSetLayout *tmp_layouts; + VkDescriptorSetAllocateInfo set_alloc_info; + VkDescriptorPoolCreateInfo pool_create_info; + + for (int i = 0; i < pl->nb_desc_pool_size; i++) + pl->desc_pool_size[i].descriptorCount *= pool->pool_size; + + pool_create_info = (VkDescriptorPoolCreateInfo) { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .flags = 0, + .pPoolSizes = pl->desc_pool_size, + .poolSizeCount = pl->nb_desc_pool_size, + .maxSets = pl->nb_descriptor_sets*pool->pool_size, }; - pl->bound_buffer_indices[i] = i; + ret = vk->CreateDescriptorPool(s->hwctx->act_dev, &pool_create_info, + s->hwctx->alloc, &pl->desc_pool); + if (ret != VK_SUCCESS) { + av_log(s, AV_LOG_ERROR, "Unable to create descriptor pool: %s\n", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } + + tmp_layouts = av_malloc_array(pool_create_info.maxSets, sizeof(*tmp_layouts)); + if (!tmp_layouts) + return AVERROR(ENOMEM); + + /* Colate each execution context's descriptor set layouts */ + for (int i = 0; i < pool->pool_size; i++) + for (int j = 0; j < pl->nb_descriptor_sets; j++) + tmp_layouts[i*pl->nb_descriptor_sets + j] = pl->desc_layout[j]; + + set_alloc_info = (VkDescriptorSetAllocateInfo) { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = pl->desc_pool, + .pSetLayouts = tmp_layouts, + .descriptorSetCount = pool_create_info.maxSets, + }; + + pl->desc_sets = av_malloc_array(pool_create_info.maxSets, + sizeof(*tmp_layouts)); + if (!pl->desc_sets) { + av_free(tmp_layouts); + return AVERROR(ENOMEM); + } + ret = vk->AllocateDescriptorSets(s->hwctx->act_dev, &set_alloc_info, + pl->desc_sets); + av_free(tmp_layouts); + if (ret != VK_SUCCESS) { + av_log(s, AV_LOG_ERROR, "Unable to allocate descriptor set: %s\n", + ff_vk_ret2str(ret)); + av_freep(&pl->desc_sets); + return AVERROR_EXTERNAL; + } + + pl->assoc_pool = pool; } return 0; @@ -1623,7 +1740,7 @@ static inline void update_set_descriptor(FFVulkanContext *s, FFVkExecContext *e, size_t desc_size) { FFVulkanFunctions *vk = &s->vkfn; - const size_t exec_offset = set->read_only ? 0 : set->aligned_size*e->idx; + const size_t exec_offset = set->singular ? 0 : set->aligned_size*e->idx; void *desc = set->desc_mem + /* Base */ exec_offset + /* Execution context */ set->binding_offset[bind_idx] + /* Descriptor binding */ @@ -1632,93 +1749,158 @@ static inline void update_set_descriptor(FFVulkanContext *s, FFVkExecContext *e, vk->GetDescriptorEXT(s->hwctx->act_dev, desc_get_info, desc_size, desc); } +static inline void update_set_pool_write(FFVulkanContext *s, + FFVulkanPipeline *pl, + FFVkExecContext *e, + FFVulkanDescriptorSet *desc_set, int set, + VkWriteDescriptorSet *write_info) +{ + FFVulkanFunctions *vk = &s->vkfn; + if (desc_set->singular) { + for (int i = 0; i < pl->assoc_pool->pool_size; i++) { + write_info->dstSet = pl->desc_sets[i*pl->nb_descriptor_sets + set]; + vk->UpdateDescriptorSets(s->hwctx->act_dev, 1, write_info, 0, NULL); + } + } else { + if (pl->use_push) { + vk->CmdPushDescriptorSetKHR(e->buf, + pl->bind_point, + pl->pipeline_layout, + set, 1, + write_info); + } else { + write_info->dstSet = pl->desc_sets[e->idx*pl->nb_descriptor_sets + set]; + vk->UpdateDescriptorSets(s->hwctx->act_dev, 1, write_info, 0, NULL); + } + } +} + static int vk_set_descriptor_image(FFVulkanContext *s, FFVulkanPipeline *pl, FFVkExecContext *e, int set, int bind, int offs, VkImageView view, VkImageLayout layout, VkSampler sampler) { FFVulkanDescriptorSet *desc_set = &pl->desc_set[set]; - VkDescriptorGetInfoEXT desc_get_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT, - .type = desc_set->binding[bind].descriptorType, - }; - VkDescriptorImageInfo desc_img_info = { - .imageView = view, - .sampler = sampler, - .imageLayout = layout, - }; - size_t desc_size; - switch (desc_get_info.type) { - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - desc_get_info.data.pSampledImage = &desc_img_info; - desc_size = s->desc_buf_props.sampledImageDescriptorSize; - break; - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - desc_get_info.data.pStorageImage = &desc_img_info; - desc_size = s->desc_buf_props.storageImageDescriptorSize; - break; - case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: - desc_get_info.data.pInputAttachmentImage = &desc_img_info; - desc_size = s->desc_buf_props.inputAttachmentDescriptorSize; - break; - case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - desc_get_info.data.pCombinedImageSampler = &desc_img_info; - desc_size = s->desc_buf_props.combinedImageSamplerDescriptorSize; - break; - default: - av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n", - set, bind, desc_get_info.type); - return AVERROR(EINVAL); - break; - }; + if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) { + VkDescriptorGetInfoEXT desc_get_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT, + .type = desc_set->binding[bind].descriptorType, + }; + VkDescriptorImageInfo desc_img_info = { + .imageView = view, + .sampler = sampler, + .imageLayout = layout, + }; + size_t desc_size; - update_set_descriptor(s, e, desc_set, bind, offs, &desc_get_info, desc_size); + switch (desc_get_info.type) { + case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + desc_get_info.data.pSampledImage = &desc_img_info; + desc_size = s->desc_buf_props.sampledImageDescriptorSize; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: + desc_get_info.data.pStorageImage = &desc_img_info; + desc_size = s->desc_buf_props.storageImageDescriptorSize; + break; + case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + desc_get_info.data.pInputAttachmentImage = &desc_img_info; + desc_size = s->desc_buf_props.inputAttachmentDescriptorSize; + break; + case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + desc_get_info.data.pCombinedImageSampler = &desc_img_info; + desc_size = s->desc_buf_props.combinedImageSamplerDescriptorSize; + break; + default: + av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n", + set, bind, desc_get_info.type); + return AVERROR(EINVAL); + break; + }; + + update_set_descriptor(s, e, desc_set, bind, offs, + &desc_get_info, desc_size); + } else { + VkDescriptorImageInfo desc_pool_write_info_img = { + .sampler = sampler, + .imageView = view, + .imageLayout = layout, + }; + VkWriteDescriptorSet desc_pool_write_info = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstBinding = bind, + .descriptorCount = 1, + .dstArrayElement = offs, + .descriptorType = desc_set->binding[bind].descriptorType, + .pImageInfo = &desc_pool_write_info_img, + }; + update_set_pool_write(s, pl, e, desc_set, set, &desc_pool_write_info); + } return 0; } int ff_vk_set_descriptor_buffer(FFVulkanContext *s, FFVulkanPipeline *pl, - FFVkExecContext *e, int set, int bind, int offs, - VkDeviceAddress addr, VkDeviceSize len, VkFormat fmt) + FFVkExecContext *e, int set, int bind, int elem, + FFVkBuffer *buf, VkDeviceSize offset, VkDeviceSize len, + VkFormat fmt) { FFVulkanDescriptorSet *desc_set = &pl->desc_set[set]; - VkDescriptorGetInfoEXT desc_get_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT, - .type = desc_set->binding[bind].descriptorType, - }; - VkDescriptorAddressInfoEXT desc_buf_info = { - .address = addr, - .range = len, - .format = fmt, - }; - size_t desc_size; - switch (desc_get_info.type) { - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - desc_get_info.data.pUniformBuffer = &desc_buf_info; - desc_size = s->desc_buf_props.uniformBufferDescriptorSize; - break; - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: - desc_get_info.data.pStorageBuffer = &desc_buf_info; - desc_size = s->desc_buf_props.storageBufferDescriptorSize; - break; - case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - desc_get_info.data.pUniformTexelBuffer = &desc_buf_info; - desc_size = s->desc_buf_props.uniformTexelBufferDescriptorSize; - break; - case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - desc_get_info.data.pStorageTexelBuffer = &desc_buf_info; - desc_size = s->desc_buf_props.storageTexelBufferDescriptorSize; - break; - default: - av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n", - set, bind, desc_get_info.type); - return AVERROR(EINVAL); - break; - }; + if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) { + VkDescriptorGetInfoEXT desc_get_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT, + .type = desc_set->binding[bind].descriptorType, + }; + VkDescriptorAddressInfoEXT desc_buf_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT, + .address = buf->address + offset, + .range = len, + .format = fmt, + }; + size_t desc_size; - update_set_descriptor(s, e, desc_set, bind, offs, &desc_get_info, desc_size); + switch (desc_get_info.type) { + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + desc_get_info.data.pUniformBuffer = &desc_buf_info; + desc_size = s->desc_buf_props.uniformBufferDescriptorSize; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: + desc_get_info.data.pStorageBuffer = &desc_buf_info; + desc_size = s->desc_buf_props.storageBufferDescriptorSize; + break; + case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: + desc_get_info.data.pUniformTexelBuffer = &desc_buf_info; + desc_size = s->desc_buf_props.uniformTexelBufferDescriptorSize; + break; + case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: + desc_get_info.data.pStorageTexelBuffer = &desc_buf_info; + desc_size = s->desc_buf_props.storageTexelBufferDescriptorSize; + break; + default: + av_log(s, AV_LOG_ERROR, "Invalid descriptor type at set %i binding %i: %i!\n", + set, bind, desc_get_info.type); + return AVERROR(EINVAL); + break; + }; + + update_set_descriptor(s, e, desc_set, bind, elem, &desc_get_info, desc_size); + } else { + VkDescriptorBufferInfo desc_pool_write_info_buf = { + .buffer = buf->buf, + .offset = offset, + .range = len, + }; + VkWriteDescriptorSet desc_pool_write_info = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstBinding = bind, + .descriptorCount = 1, + .dstArrayElement = elem, + .descriptorType = desc_set->binding[bind].descriptorType, + .pBufferInfo = &desc_pool_write_info_buf, + }; + update_set_pool_write(s, pl, e, desc_set, set, &desc_pool_write_info); + } return 0; } @@ -1746,24 +1928,80 @@ void ff_vk_update_push_exec(FFVulkanContext *s, FFVkExecContext *e, stage, offset, size, src); } +static int init_descriptors(FFVulkanContext *s, FFVulkanPipeline *pl) +{ + VkResult ret; + FFVulkanFunctions *vk = &s->vkfn; + + pl->desc_layout = av_malloc_array(pl->nb_descriptor_sets, + sizeof(*pl->desc_layout)); + if (!pl->desc_layout) + return AVERROR(ENOMEM); + + if (!(s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER)) { + int has_singular = 0; + for (int i = 0; i < pl->nb_descriptor_sets; i++) { + if (pl->desc_set[i].singular) { + has_singular = 1; + break; + } + } + pl->use_push = (s->extensions & FF_VK_EXT_PUSH_DESCRIPTOR) && + (pl->nb_descriptor_sets == 1) && + !has_singular; + } + + for (int i = 0; i < pl->nb_descriptor_sets; i++) { + FFVulkanDescriptorSet *set = &pl->desc_set[i]; + VkDescriptorSetLayoutCreateInfo desc_layout_create = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = set->nb_bindings, + .pBindings = set->binding, + .flags = (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) ? + VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT : + (pl->use_push) ? + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR : + 0x0, + }; + + ret = vk->CreateDescriptorSetLayout(s->hwctx->act_dev, + &desc_layout_create, + s->hwctx->alloc, + &pl->desc_layout[i]); + if (ret != VK_SUCCESS) { + av_log(s, AV_LOG_ERROR, "Unable to create descriptor set layout: %s", + ff_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } + + if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) { + vk->GetDescriptorSetLayoutSizeEXT(s->hwctx->act_dev, pl->desc_layout[i], + &set->layout_size); + + set->aligned_size = FFALIGN(set->layout_size, + s->desc_buf_props.descriptorBufferOffsetAlignment); + + for (int j = 0; j < set->nb_bindings; j++) + vk->GetDescriptorSetLayoutBindingOffsetEXT(s->hwctx->act_dev, + pl->desc_layout[i], + j, + &set->binding_offset[j]); + } + } + + return 0; +} + static int init_pipeline_layout(FFVulkanContext *s, FFVulkanPipeline *pl) { VkResult ret; FFVulkanFunctions *vk = &s->vkfn; VkPipelineLayoutCreateInfo pipeline_layout_info; - VkDescriptorSetLayout *desc_layouts = av_malloc(pl->nb_descriptor_sets* - sizeof(desc_layouts)); - if (!desc_layouts) - return AVERROR(ENOMEM); - - for (int i = 0; i < pl->nb_descriptor_sets; i++) - desc_layouts[i] = pl->desc_set[i].layout; - /* Finally create the pipeline layout */ pipeline_layout_info = (VkPipelineLayoutCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .pSetLayouts = desc_layouts, + .pSetLayouts = pl->desc_layout, .setLayoutCount = pl->nb_descriptor_sets, .pushConstantRangeCount = pl->push_consts_num, .pPushConstantRanges = pl->push_consts, @@ -1771,7 +2009,6 @@ static int init_pipeline_layout(FFVulkanContext *s, FFVulkanPipeline *pl) ret = vk->CreatePipelineLayout(s->hwctx->act_dev, &pipeline_layout_info, s->hwctx->alloc, &pl->pipeline_layout); - av_free(desc_layouts); if (ret != VK_SUCCESS) { av_log(s, AV_LOG_ERROR, "Unable to init pipeline layout: %s\n", ff_vk_ret2str(ret)); @@ -1790,13 +2027,18 @@ int ff_vk_init_compute_pipeline(FFVulkanContext *s, FFVulkanPipeline *pl, VkComputePipelineCreateInfo pipeline_create_info; + err = init_descriptors(s, pl); + if (err < 0) + return err; + err = init_pipeline_layout(s, pl); if (err < 0) return err; pipeline_create_info = (VkComputePipelineCreateInfo) { .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, - .flags = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT, + .flags = (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) ? + VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT : 0x0, .layout = pl->pipeline_layout, .stage = shd->shader, }; @@ -1828,15 +2070,22 @@ void ff_vk_exec_bind_pipeline(FFVulkanContext *s, FFVkExecContext *e, vk->CmdBindPipeline(e->buf, pl->bind_point, pl->pipeline); if (pl->nb_descriptor_sets) { - for (int i = 0; i < pl->nb_descriptor_sets; i++) - offsets[i] = pl->desc_set[i].read_only ? 0 : pl->desc_set[i].aligned_size*e->idx; + if (s->extensions & FF_VK_EXT_DESCRIPTOR_BUFFER) { + for (int i = 0; i < pl->nb_descriptor_sets; i++) + offsets[i] = pl->desc_set[i].singular ? 0 : pl->desc_set[i].aligned_size*e->idx; - /* Bind descriptor buffers */ - vk->CmdBindDescriptorBuffersEXT(e->buf, pl->nb_descriptor_sets, pl->desc_bind); - /* Binding offsets */ - vk->CmdSetDescriptorBufferOffsetsEXT(e->buf, pl->bind_point, pl->pipeline_layout, - 0, pl->nb_descriptor_sets, - pl->bound_buffer_indices, offsets); + /* Bind descriptor buffers */ + vk->CmdBindDescriptorBuffersEXT(e->buf, pl->nb_descriptor_sets, pl->desc_bind); + /* Binding offsets */ + vk->CmdSetDescriptorBufferOffsetsEXT(e->buf, pl->bind_point, pl->pipeline_layout, + 0, pl->nb_descriptor_sets, + pl->bound_buffer_indices, offsets); + } else if (!pl->use_push) { + vk->CmdBindDescriptorSets(e->buf, pl->bind_point, pl->pipeline_layout, + 0, pl->nb_descriptor_sets, + &pl->desc_sets[e->idx*pl->nb_descriptor_sets], + 0, NULL); + } } } @@ -1855,13 +2104,22 @@ void ff_vk_pipeline_free(FFVulkanContext *s, FFVulkanPipeline *pl) if (set->buf.mem) ff_vk_unmap_buffer(s, &set->buf, 0); ff_vk_free_buf(s, &set->buf); - if (set->layout) - vk->DestroyDescriptorSetLayout(s->hwctx->act_dev, set->layout, - s->hwctx->alloc); av_free(set->binding); av_free(set->binding_offset); } + for (int i = 0; i < pl->nb_descriptor_sets; i++) + if (pl->desc_layout[i]) + vk->DestroyDescriptorSetLayout(s->hwctx->act_dev, pl->desc_layout[i], + s->hwctx->alloc); + + if (pl->desc_pool) + vk->DestroyDescriptorPool(s->hwctx->act_dev, pl->desc_pool, + s->hwctx->alloc); + + av_freep(&pl->desc_pool_size); + av_freep(&pl->desc_layout); + av_freep(&pl->desc_sets); av_freep(&pl->desc_set); av_freep(&pl->desc_bind); av_freep(&pl->bound_buffer_indices); @@ -1876,5 +2134,59 @@ void ff_vk_uninit(FFVulkanContext *s) av_freep(&s->video_props); av_freep(&s->coop_mat_props); + av_buffer_unref(&s->device_ref); av_buffer_unref(&s->frames_ref); } + +int ff_vk_init(FFVulkanContext *s, void *log_parent, + AVBufferRef *device_ref, AVBufferRef *frames_ref) +{ + int err; + + static const AVClass vulkan_context_class = { + .class_name = "vk", + .version = LIBAVUTIL_VERSION_INT, + .parent_log_context_offset = offsetof(FFVulkanContext, log_parent), + }; + + memset(s, 0, sizeof(*s)); + s->log_parent = log_parent; + s->class = &vulkan_context_class; + + if (frames_ref) { + s->frames_ref = av_buffer_ref(frames_ref); + if (!s->frames_ref) + return AVERROR(ENOMEM); + + s->frames = (AVHWFramesContext *)s->frames_ref->data; + s->hwfc = s->frames->hwctx; + + device_ref = s->frames->device_ref; + } + + s->device_ref = av_buffer_ref(device_ref); + if (!s->device_ref) { + ff_vk_uninit(s); + return AVERROR(ENOMEM); + } + + s->device = (AVHWDeviceContext *)s->device_ref->data; + s->hwctx = s->device->hwctx; + + s->extensions = ff_vk_extensions_to_mask(s->hwctx->enabled_dev_extensions, + s->hwctx->nb_enabled_dev_extensions); + + err = ff_vk_load_functions(s->device, &s->vkfn, s->extensions, 1, 1); + if (err < 0) { + ff_vk_uninit(s); + return err; + } + + err = ff_vk_load_props(s); + if (err < 0) { + ff_vk_uninit(s); + return err; + } + + return 0; +} diff --git a/libavutil/vulkan.h b/libavutil/vulkan.h index 15d954fcb..e03fd702c 100644 --- a/libavutil/vulkan.h +++ b/libavutil/vulkan.h @@ -112,43 +112,6 @@ typedef struct FFVkQueueFamilyCtx { int nb_queues; } FFVkQueueFamilyCtx; -typedef struct FFVulkanDescriptorSet { - VkDescriptorSetLayout layout; - FFVkBuffer buf; - uint8_t *desc_mem; - VkDeviceSize layout_size; - VkDeviceSize aligned_size; /* descriptorBufferOffsetAlignment */ - VkDeviceSize total_size; /* Once registered to an exec context */ - VkBufferUsageFlags usage; - - VkDescriptorSetLayoutBinding *binding; - VkDeviceSize *binding_offset; - int nb_bindings; - - int read_only; -} FFVulkanDescriptorSet; - -typedef struct FFVulkanPipeline { - VkPipelineBindPoint bind_point; - - /* Contexts */ - VkPipelineLayout pipeline_layout; - VkPipeline pipeline; - - /* Push consts */ - VkPushConstantRange *push_consts; - int push_consts_num; - - /* Workgroup */ - int wg_size[3]; - - /* Descriptors */ - FFVulkanDescriptorSet *desc_set; - VkDescriptorBufferBindingInfoEXT *desc_bind; - uint32_t *bound_buffer_indices; - int nb_descriptor_sets; -} FFVulkanPipeline; - typedef struct FFVkExecContext { uint32_t idx; const struct FFVkExecPool *parent; @@ -225,8 +188,56 @@ typedef struct FFVkExecPool { size_t qd_size; } FFVkExecPool; +typedef struct FFVulkanDescriptorSet { + FFVkBuffer buf; + uint8_t *desc_mem; + VkDeviceSize layout_size; + VkDeviceSize aligned_size; /* descriptorBufferOffsetAlignment */ + VkDeviceSize total_size; /* Once registered to an exec context */ + VkBufferUsageFlags usage; + + VkDescriptorSetLayoutBinding *binding; + VkDeviceSize *binding_offset; + int nb_bindings; + + /* Descriptor set is shared between all submissions */ + int singular; +} FFVulkanDescriptorSet; + +typedef struct FFVulkanPipeline { + VkPipelineBindPoint bind_point; + + /* Contexts */ + VkPipelineLayout pipeline_layout; + VkPipeline pipeline; + + /* Push consts */ + VkPushConstantRange *push_consts; + int push_consts_num; + + /* Workgroup */ + int wg_size[3]; + + /* Descriptor buffer */ + VkDescriptorSetLayout *desc_layout; + FFVulkanDescriptorSet *desc_set; + VkDescriptorBufferBindingInfoEXT *desc_bind; + uint32_t *bound_buffer_indices; + int nb_descriptor_sets; + + /* Descriptor pool */ + int use_push; + VkDescriptorSet *desc_sets; + VkDescriptorPool desc_pool; + VkDescriptorPoolSize *desc_pool_size; + int nb_desc_pool_size; + int total_desc_sets; + FFVkExecPool *assoc_pool; +} FFVulkanPipeline; + typedef struct FFVulkanContext { - const AVClass *class; /* Filters and encoders use this */ + const AVClass *class; + void *log_parent; FFVulkanFunctions vkfn; FFVulkanExtensions extensions; @@ -237,6 +248,7 @@ typedef struct FFVulkanContext { VkPhysicalDeviceDescriptorBufferPropertiesEXT desc_buf_props; VkPhysicalDeviceSubgroupSizeControlProperties subgroup_props; VkPhysicalDeviceCooperativeMatrixPropertiesKHR coop_matrix_props; + VkPhysicalDeviceOpticalFlowPropertiesNV optical_flow_props; VkQueueFamilyQueryResultStatusPropertiesKHR *query_props; VkQueueFamilyVideoPropertiesKHR *video_props; VkQueueFamilyProperties2 *qf_props; @@ -249,6 +261,7 @@ typedef struct FFVulkanContext { VkPhysicalDeviceVulkan12Features feats_12; VkPhysicalDeviceFeatures2 feats; + AVBufferRef *device_ref; AVHWDeviceContext *device; AVVulkanDeviceContext *hwctx; @@ -257,7 +270,7 @@ typedef struct FFVulkanContext { AVHWFramesContext *frames; AVVulkanFramesContext *hwfc; - uint32_t qfs[5]; + uint32_t qfs[64]; int nb_qfs; /* Properties */ @@ -289,9 +302,26 @@ static inline const void *ff_vk_find_struct(const void *chain, VkStructureType s return NULL; } +static inline void ff_vk_link_struct(void *chain, const void *in) +{ + VkBaseOutStructure *out = chain; + while (out->pNext) + out = out->pNext; + + out->pNext = (void *)in; +} + /* Identity mapping - r = r, b = b, g = g, a = a */ extern const VkComponentMapping ff_comp_identity_map; +/** + * Initializes the AVClass, in case this context is not used + * as the main user's context. + * May use either a frames context reference, or a device context reference. + */ +int ff_vk_init(FFVulkanContext *s, void *log_parent, + AVBufferRef *device_ref, AVBufferRef *frames_ref); + /** * Converts Vulkan return values to strings */ @@ -336,10 +366,11 @@ FFVkExecContext *ff_vk_exec_get(FFVkExecPool *pool); /** * Performs nb_queries queries and returns their results and statuses. - * Execution must have been waited on to produce valid results. + * 64_BIT and WITH_STATUS flags are ignored as 64_BIT must be specified via + * query_64bit in ff_vk_exec_pool_init() and WITH_STATUS is always enabled. */ VkResult ff_vk_exec_get_query(FFVulkanContext *s, FFVkExecContext *e, - void **data, int64_t *status); + void **data, VkQueryResultFlagBits flags); /** * Start/submit/wait an execution. @@ -361,6 +392,10 @@ void ff_vk_exec_wait(FFVulkanContext *s, FFVkExecContext *e); */ int ff_vk_exec_add_dep_buf(FFVulkanContext *s, FFVkExecContext *e, AVBufferRef **deps, int nb_deps, int ref); +int ff_vk_exec_add_dep_bool_sem(FFVulkanContext *s, FFVkExecContext *e, + VkSemaphore *sem, int nb, + VkPipelineStageFlagBits2 stage, + int wait); /* Ownership transferred if !wait */ int ff_vk_exec_add_dep_frame(FFVulkanContext *s, FFVkExecContext *e, AVFrame *f, VkPipelineStageFlagBits2 wait_stage, VkPipelineStageFlagBits2 signal_stage); @@ -463,7 +498,7 @@ void ff_vk_update_push_exec(FFVulkanContext *s, FFVkExecContext *e, int ff_vk_pipeline_descriptor_set_add(FFVulkanContext *s, FFVulkanPipeline *pl, FFVkSPIRVShader *shd, FFVulkanDescriptorSetBinding *desc, int nb, - int read_only, int print_to_shader_only); + int singular, int print_to_shader_only); /* Initialize/free a pipeline. */ int ff_vk_init_compute_pipeline(FFVulkanContext *s, FFVulkanPipeline *pl, @@ -482,8 +517,9 @@ void ff_vk_exec_bind_pipeline(FFVulkanContext *s, FFVkExecContext *e, FFVulkanPipeline *pl); int ff_vk_set_descriptor_buffer(FFVulkanContext *s, FFVulkanPipeline *pl, - FFVkExecContext *e, int set, int bind, int offs, - VkDeviceAddress addr, VkDeviceSize len, VkFormat fmt); + FFVkExecContext *e, int set, int bind, int elem, + FFVkBuffer *buf, VkDeviceSize offset, VkDeviceSize len, + VkFormat fmt); void ff_vk_update_descriptor_img_array(FFVulkanContext *s, FFVulkanPipeline *pl, FFVkExecContext *e, AVFrame *f, diff --git a/libavutil/vulkan_functions.h b/libavutil/vulkan_functions.h index 6b379acf9..91dd8b91e 100644 --- a/libavutil/vulkan_functions.h +++ b/libavutil/vulkan_functions.h @@ -46,6 +46,14 @@ typedef enum FFVulkanExtensions { FF_VK_EXT_VIDEO_DECODE_AV1 = 1ULL << 14, /* VK_KHR_video_decode_av1 */ FF_VK_EXT_ATOMIC_FLOAT = 1ULL << 15, /* VK_EXT_shader_atomic_float */ FF_VK_EXT_COOP_MATRIX = 1ULL << 16, /* VK_KHR_cooperative_matrix */ + FF_VK_EXT_OPTICAL_FLOW = 1ULL << 17, /* VK_NV_optical_flow */ + FF_VK_EXT_SHADER_OBJECT = 1ULL << 18, /* VK_EXT_shader_object */ + FF_VK_EXT_PUSH_DESCRIPTOR = 1ULL << 19, /* VK_KHR_push_descriptor */ + + FF_VK_EXT_VIDEO_MAINTENANCE_1 = 1ULL << 27, /* VK_KHR_video_maintenance1 */ + FF_VK_EXT_VIDEO_ENCODE_QUEUE = 1ULL << 28, /* VK_KHR_video_encode_queue */ + FF_VK_EXT_VIDEO_ENCODE_H264 = 1ULL << 29, /* VK_KHR_video_encode_h264 */ + FF_VK_EXT_VIDEO_ENCODE_H265 = 1ULL << 30, /* VK_KHR_video_encode_h265 */ FF_VK_EXT_NO_FLAG = 1ULL << 31, } FFVulkanExtensions; @@ -107,6 +115,7 @@ typedef enum FFVulkanExtensions { \ /* Semaphores */ \ MACRO(1, 1, FF_VK_EXT_EXTERNAL_FD_SEM, GetSemaphoreFdKHR) \ + MACRO(1, 1, FF_VK_EXT_EXTERNAL_FD_SEM, ImportSemaphoreFdKHR) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateSemaphore) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, WaitSemaphores) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, DestroySemaphore) \ @@ -168,6 +177,10 @@ typedef enum FFVulkanExtensions { MACRO(1, 1, FF_VK_EXT_NO_FLAG, UpdateDescriptorSetWithTemplate) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateDescriptorUpdateTemplate) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, DestroyDescriptorUpdateTemplate) \ + \ + /* Descriptors */ \ + MACRO(1, 1, FF_VK_EXT_NO_FLAG, UpdateDescriptorSets) \ + MACRO(1, 1, FF_VK_EXT_PUSH_DESCRIPTOR, CmdPushDescriptorSetKHR) \ \ /* Queries */ \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateQueryPool) \ @@ -194,6 +207,11 @@ typedef enum FFVulkanExtensions { \ /* Video decoding */ \ MACRO(1, 1, FF_VK_EXT_VIDEO_DECODE_QUEUE, CmdDecodeVideoKHR) \ + \ + /* Video encoding */ \ + MACRO(1, 1, FF_VK_EXT_VIDEO_ENCODE_QUEUE, CmdEncodeVideoKHR) \ + MACRO(1, 1, FF_VK_EXT_VIDEO_ENCODE_QUEUE, GetEncodedVideoSessionParametersKHR) \ + MACRO(1, 0, FF_VK_EXT_VIDEO_ENCODE_QUEUE, GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR) \ \ /* Pipeline */ \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreatePipelineLayout) \ @@ -208,10 +226,21 @@ typedef enum FFVulkanExtensions { MACRO(1, 1, FF_VK_EXT_NO_FLAG, DestroySamplerYcbcrConversion) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateSampler) \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, DestroySampler) \ + \ + /* Optical flow */ \ + MACRO(1, 1, FF_VK_EXT_OPTICAL_FLOW, BindOpticalFlowSessionImageNV) \ + MACRO(1, 1, FF_VK_EXT_OPTICAL_FLOW, CmdOpticalFlowExecuteNV) \ + MACRO(1, 1, FF_VK_EXT_OPTICAL_FLOW, CreateOpticalFlowSessionNV) \ + MACRO(1, 1, FF_VK_EXT_OPTICAL_FLOW, DestroyOpticalFlowSessionNV) \ + MACRO(1, 0, FF_VK_EXT_OPTICAL_FLOW, GetPhysicalDeviceOpticalFlowImageFormatsNV)\ \ /* Shaders */ \ MACRO(1, 1, FF_VK_EXT_NO_FLAG, CreateShaderModule) \ - MACRO(1, 1, FF_VK_EXT_NO_FLAG, DestroyShaderModule) + MACRO(1, 1, FF_VK_EXT_NO_FLAG, DestroyShaderModule) \ + MACRO(1, 1, FF_VK_EXT_SHADER_OBJECT, CmdBindShadersEXT) \ + MACRO(1, 1, FF_VK_EXT_SHADER_OBJECT, CreateShadersEXT) \ + MACRO(1, 1, FF_VK_EXT_SHADER_OBJECT, DestroyShaderEXT) \ + MACRO(1, 1, FF_VK_EXT_SHADER_OBJECT, GetShaderBinaryDataEXT) /* Macro containing every win32 specific function that we utilize in our codebase */ #define FN_LIST_WIN32(MACRO) \ diff --git a/libavutil/vulkan_loader.h b/libavutil/vulkan_loader.h index 73cf03935..2022eb320 100644 --- a/libavutil/vulkan_loader.h +++ b/libavutil/vulkan_loader.h @@ -49,16 +49,23 @@ static inline uint64_t ff_vk_extensions_to_mask(const char * const *extensions, { VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME, FF_VK_EXT_DEVICE_DRM }, { VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME, FF_VK_EXT_ATOMIC_FLOAT }, { VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, FF_VK_EXT_COOP_MATRIX }, + { VK_NV_OPTICAL_FLOW_EXTENSION_NAME, FF_VK_EXT_OPTICAL_FLOW }, + { VK_EXT_SHADER_OBJECT_EXTENSION_NAME, FF_VK_EXT_SHADER_OBJECT }, + { VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME, FF_VK_EXT_VIDEO_MAINTENANCE_1 }, #ifdef _WIN32 { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_MEMORY }, { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_SEM }, #endif { VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, FF_VK_EXT_DESCRIPTOR_BUFFER, }, { VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_QUEUE }, + { VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_QUEUE }, { VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_QUEUE }, + { VK_KHR_VIDEO_ENCODE_H264_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_H264 }, { VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H264 }, + { VK_KHR_VIDEO_ENCODE_H265_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_H265 }, { VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H265 }, { VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_AV1 }, + { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, FF_VK_EXT_PUSH_DESCRIPTOR }, }; FFVulkanExtensions mask = 0x0; diff --git a/libavutil/wchar_filename.h b/libavutil/wchar_filename.h index 23cc92aa2..1370a084c 100644 --- a/libavutil/wchar_filename.h +++ b/libavutil/wchar_filename.h @@ -57,7 +57,7 @@ static inline int wchartocp(unsigned int code_page, const wchar_t *filename_w, errno = EINVAL; return -1; } - *filename = av_malloc_array(num_chars, sizeof **filename); + *filename = (char *)av_malloc_array(num_chars, sizeof **filename); if (!*filename) { errno = ENOMEM; return -1; diff --git a/libavutil/x86/bswap.h b/libavutil/x86/bswap.h index b2f18b6c9..1ce9dcfc6 100644 --- a/libavutil/x86/bswap.h +++ b/libavutil/x86/bswap.h @@ -57,16 +57,7 @@ static inline uint64_t av_const av_bswap64(uint64_t x) #elif HAVE_INLINE_ASM -#if AV_GCC_VERSION_AT_MOST(4,0) -#define av_bswap16 av_bswap16 -static av_always_inline av_const unsigned av_bswap16(unsigned x) -{ - __asm__("rorw $8, %w0" : "+r"(x)); - return x; -} -#endif /* AV_GCC_VERSION_AT_MOST(4,0) */ - -#if AV_GCC_VERSION_AT_MOST(4,4) || defined(__INTEL_COMPILER) +#ifdef __INTEL_COMPILER #define av_bswap32 av_bswap32 static av_always_inline av_const uint32_t av_bswap32(uint32_t x) { @@ -82,7 +73,7 @@ static inline uint64_t av_const av_bswap64(uint64_t x) return x; } #endif -#endif /* AV_GCC_VERSION_AT_MOST(4,4) */ +#endif /* __INTEL_COMPILER */ #endif /* HAVE_INLINE_ASM */ #endif /* AVUTIL_X86_BSWAP_H */ diff --git a/libavutil/x86/float_dsp.asm b/libavutil/x86/float_dsp.asm index e84ba5256..cac2a2b66 100644 --- a/libavutil/x86/float_dsp.asm +++ b/libavutil/x86/float_dsp.asm @@ -567,6 +567,58 @@ cglobal scalarproduct_float, 3,5,8, v1, v2, size, len, offset %endif RET +;--------------------------------------------------------------------------------- +; double scalarproduct_double(const double *v1, const double *v2, size_t len) +;--------------------------------------------------------------------------------- +%macro SCALARPRODUCT_DOUBLE 0 +cglobal scalarproduct_double, 3,3,8, v1, v2, offset + shl offsetq, 3 + add v1q, offsetq + add v2q, offsetq + neg offsetq + xorpd m0, m0 + xorpd m1, m1 + movapd m2, m0 + movapd m3, m1 +align 16 +.loop: + movapd m4, [v1q+offsetq+mmsize*0] + movapd m5, [v1q+offsetq+mmsize*1] + movapd m6, [v1q+offsetq+mmsize*2] + movapd m7, [v1q+offsetq+mmsize*3] + mulpd m4, [v2q+offsetq+mmsize*0] + mulpd m5, [v2q+offsetq+mmsize*1] + mulpd m6, [v2q+offsetq+mmsize*2] + mulpd m7, [v2q+offsetq+mmsize*3] + addpd m0, m4 + addpd m1, m5 + addpd m2, m6 + addpd m3, m7 + add offsetq, mmsize*4 + jl .loop + addpd m0, m1 + addpd m2, m3 + addpd m0, m2 +%if mmsize == 32 + vextractf128 xm1, m0, 1 + addpd xm0, xm1 +%endif + movhlps xm1, xm0 + addsd xm0, xm1 +%if ARCH_X86_64 == 0 + movsd r0m, xm0 + fld qword r0m +%endif + RET +%endmacro + +INIT_XMM sse2 +SCALARPRODUCT_DOUBLE +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +SCALARPRODUCT_DOUBLE +%endif + ;----------------------------------------------------------------------------- ; void ff_butterflies_float(float *src0, float *src1, int len); ;----------------------------------------------------------------------------- diff --git a/libavutil/x86/float_dsp_init.c b/libavutil/x86/float_dsp_init.c index 093bce9b9..6cf0b4a27 100644 --- a/libavutil/x86/float_dsp_init.c +++ b/libavutil/x86/float_dsp_init.c @@ -73,6 +73,9 @@ void ff_vector_fmul_reverse_avx2(float *dst, const float *src0, float ff_scalarproduct_float_sse(const float *v1, const float *v2, int order); float ff_scalarproduct_float_fma3(const float *v1, const float *v2, int order); +double ff_scalarproduct_double_sse2(const double *v1, const double *v2, size_t order); +double ff_scalarproduct_double_avx(const double *v1, const double *v2, size_t order); + void ff_butterflies_float_sse(float *restrict src0, float *restrict src1, int len); av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp) @@ -93,6 +96,7 @@ av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp) fdsp->vector_dmul = ff_vector_dmul_sse2; fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_sse2; fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_sse2; + fdsp->scalarproduct_double = ff_scalarproduct_double_sse2; } if (EXTERNAL_AVX_FAST(cpu_flags)) { fdsp->vector_fmul = ff_vector_fmul_avx; @@ -102,6 +106,7 @@ av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp) fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_avx; fdsp->vector_fmul_add = ff_vector_fmul_add_avx; fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_avx; + fdsp->scalarproduct_double = ff_scalarproduct_double_avx; } if (EXTERNAL_AVX2_FAST(cpu_flags)) { fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_avx2; diff --git a/libavutil/x86/intmath.h b/libavutil/x86/intmath.h index 8a6b5ae26..4893a1f1b 100644 --- a/libavutil/x86/intmath.h +++ b/libavutil/x86/intmath.h @@ -82,16 +82,28 @@ static av_always_inline av_const int ff_ctzll_x86(long long v) #if defined(__BMI2__) #if AV_GCC_VERSION_AT_LEAST(5,1) -#define av_mod_uintp2 __builtin_ia32_bzhi_si +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 +#define av_zero_extend av_zero_extend_bmi2 +static av_always_inline av_const unsigned av_zero_extend_bmi2(unsigned a, unsigned p) +{ + if (p > 31) abort(); + return __builtin_ia32_bzhi_si(a, p); +} +#else +#define av_zero_extend __builtin_ia32_bzhi_si +#endif #elif HAVE_INLINE_ASM /* GCC releases before 5.1.0 have a broken bzhi builtin, so for those we * implement it using inline assembly */ -#define av_mod_uintp2 av_mod_uintp2_bmi2 -static av_always_inline av_const unsigned av_mod_uintp2_bmi2(unsigned a, unsigned p) +#define av_zero_extend av_zero_extend_bmi2 +static av_always_inline av_const unsigned av_zero_extend_bmi2(unsigned a, unsigned p) { +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (p > 31) abort(); +#endif if (av_builtin_constant_p(p)) - return a & ((1 << p) - 1); + return a & ((1U << p) - 1); else { unsigned x; __asm__ ("bzhi %2, %1, %0 \n\t" : "=r"(x) : "rm"(a), "r"(p)); diff --git a/libavutil/x86/intreadwrite.h b/libavutil/x86/intreadwrite.h index 5e57d6a8c..c92b75ed1 100644 --- a/libavutil/x86/intreadwrite.h +++ b/libavutil/x86/intreadwrite.h @@ -23,41 +23,34 @@ #include #include "config.h" +#if HAVE_INTRINSICS_SSE2 && defined(__SSE2__) +#include +#endif #include "libavutil/attributes.h" -#if HAVE_MMX - -#ifdef __SSE__ +#if HAVE_INTRINSICS_SSE2 && defined(__SSE2__) #define AV_COPY128 AV_COPY128 static av_always_inline void AV_COPY128(void *d, const void *s) { - struct v {uint64_t v[2];}; - - __asm__("movaps %1, %%xmm0 \n\t" - "movaps %%xmm0, %0 \n\t" - : "=m"(*(struct v*)d) - : "m" (*(const struct v*)s) - : "xmm0"); + __m128i tmp = _mm_load_si128((const __m128i *)s); + _mm_store_si128((__m128i *)d, tmp); } -#endif /* __SSE__ */ - -#ifdef __SSE2__ +#define AV_COPY128U AV_COPY128U +static av_always_inline void AV_COPY128U(void *d, const void *s) +{ + __m128i tmp = _mm_loadu_si128((const __m128i *)s); + _mm_storeu_si128((__m128i *)d, tmp); +} #define AV_ZERO128 AV_ZERO128 static av_always_inline void AV_ZERO128(void *d) { - struct v {uint64_t v[2];}; - - __asm__("pxor %%xmm0, %%xmm0 \n\t" - "movdqa %%xmm0, %0 \n\t" - : "=m"(*(struct v*)d) - :: "xmm0"); + __m128i zero = _mm_setzero_si128(); + _mm_store_si128((__m128i *)d, zero); } -#endif /* __SSE2__ */ - -#endif /* HAVE_MMX */ +#endif /* HAVE_INTRINSICS_SSE2 && defined(__SSE2__) */ #endif /* AVUTIL_X86_INTREADWRITE_H */ diff --git a/libavutil/x86/tx_float_init.c b/libavutil/x86/tx_float_init.c index 84ec1122f..36da9325e 100644 --- a/libavutil/x86/tx_float_init.c +++ b/libavutil/x86/tx_float_init.c @@ -19,6 +19,7 @@ #define TX_FLOAT #include "libavutil/tx_priv.h" #include "libavutil/attributes.h" +#include "libavutil/mem.h" #include "libavutil/x86/cpu.h" #include "config.h" diff --git a/libpostproc/postprocess.c b/libpostproc/postprocess.c index 0586e458b..015bc9d50 100644 --- a/libpostproc/postprocess.c +++ b/libpostproc/postprocess.c @@ -72,15 +72,15 @@ try to unroll inner for(x=0 ... loop to avoid these damn if(x ... checks //Changelog: use git log -#include "config.h" -#include "libavutil/avutil.h" -#include "libavutil/avassert.h" -#include "libavutil/cpu.h" -#include "libavutil/intreadwrite.h" -#include -#include +#include #include #include + +#include "config.h" +#include "libavutil/common.h" +#include "libavutil/cpu.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" //#undef HAVE_MMXEXT_INLINE //#undef HAVE_MMX_INLINE //#undef ARCH_X86 @@ -88,7 +88,6 @@ try to unroll inner for(x=0 ... loop to avoid these damn if(x ... checks #include "postprocess.h" #include "postprocess_internal.h" #include "libavutil/avstring.h" -#include "libavutil/ppc/util_altivec.h" #define GET_MODE_BUFFER_SIZE 500 #define OPTIONS_ARRAY_SIZE 10 @@ -499,6 +498,8 @@ static av_always_inline void do_a_deblock_C(uint8_t *src, int step, #include "postprocess_template.c" #if HAVE_ALTIVEC +#include "libavutil/ppc/util_altivec.h" + # define TEMPLATE_PP_ALTIVEC 1 # include "postprocess_altivec_template.c" # include "postprocess_template.c" diff --git a/libpostproc/postprocess_template.c b/libpostproc/postprocess_template.c index ade1d6ce2..d56b45d3b 100644 --- a/libpostproc/postprocess_template.c +++ b/libpostproc/postprocess_template.c @@ -22,9 +22,12 @@ * @file * mmx/mmx2/sse2 postprocess code. */ +#include "config.h" #include "libavutil/mem_internal.h" +#if ARCH_X86 #include "libavutil/x86/asm.h" +#endif /* A single TEMPLATE_PP_* should be defined (to 1) when this template is * included. The following macros will define its dependencies to 1 as well @@ -830,7 +833,7 @@ static inline void RENAME(doVertDefFilter)(uint8_t src[], int stride, PPContext #if !TEMPLATE_PP_ALTIVEC static inline void RENAME(dering)(uint8_t src[], int stride, PPContext *c) { -#if HAVE_7REGS && TEMPLATE_PP_MMXEXT +#if TEMPLATE_PP_MMXEXT && HAVE_7REGS DECLARE_ALIGNED(8, uint64_t, tmp)[3]; __asm__ volatile( "pxor %%mm6, %%mm6 \n\t" diff --git a/libpostproc/version.c b/libpostproc/version.c index 494575ae6..304abe08e 100644 --- a/libpostproc/version.c +++ b/libpostproc/version.c @@ -18,8 +18,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "config.h" -#include "libavutil/avassert.h" #include "postprocess.h" #include "version.h" @@ -28,7 +29,7 @@ const char postproc_ffversion[] = "FFmpeg version " FFMPEG_VERSION; unsigned postproc_version(void) { - av_assert0(LIBPOSTPROC_VERSION_MICRO >= 100); + static_assert(LIBPOSTPROC_VERSION_MICRO >= 100, "micro version starts at 100"); return LIBPOSTPROC_VERSION_INT; } diff --git a/libpostproc/version.h b/libpostproc/version.h index 8294f007b..e77dff98c 100644 --- a/libpostproc/version.h +++ b/libpostproc/version.h @@ -30,7 +30,7 @@ #include "version_major.h" -#define LIBPOSTPROC_VERSION_MINOR 1 +#define LIBPOSTPROC_VERSION_MINOR 3 #define LIBPOSTPROC_VERSION_MICRO 100 #define LIBPOSTPROC_VERSION_INT AV_VERSION_INT(LIBPOSTPROC_VERSION_MAJOR, \ diff --git a/libswresample/arm/resample.S b/libswresample/arm/resample.S index 3ce762324..791f4cc01 100644 --- a/libswresample/arm/resample.S +++ b/libswresample/arm/resample.S @@ -30,7 +30,7 @@ function ff_resample_common_apply_filter_x4_float_neon, export=1 vpadd.f32 d0, d0, d1 @ pair adding of the 4x32-bit accumulated values vpadd.f32 d0, d0, d0 @ pair adding of the 4x32-bit accumulator values vst1.32 {d0[0]}, [r0] @ write accumulator - mov pc, lr + bx lr endfunc function ff_resample_common_apply_filter_x8_float_neon, export=1 @@ -46,7 +46,7 @@ function ff_resample_common_apply_filter_x8_float_neon, export=1 vpadd.f32 d0, d0, d1 @ pair adding of the 4x32-bit accumulated values vpadd.f32 d0, d0, d0 @ pair adding of the 4x32-bit accumulator values vst1.32 {d0[0]}, [r0] @ write accumulator - mov pc, lr + bx lr endfunc function ff_resample_common_apply_filter_x4_s16_neon, export=1 @@ -59,7 +59,7 @@ function ff_resample_common_apply_filter_x4_s16_neon, export=1 vpadd.s32 d0, d0, d1 @ pair adding of the 4x32-bit accumulated values vpadd.s32 d0, d0, d0 @ pair adding of the 4x32-bit accumulator values vst1.32 {d0[0]}, [r0] @ write accumulator - mov pc, lr + bx lr endfunc function ff_resample_common_apply_filter_x8_s16_neon, export=1 @@ -73,5 +73,5 @@ function ff_resample_common_apply_filter_x8_s16_neon, export=1 vpadd.s32 d0, d0, d1 @ pair adding of the 4x32-bit accumulated values vpadd.s32 d0, d0, d0 @ pair adding of the 4x32-bit accumulator values vst1.32 {d0[0]}, [r0] @ write accumulator - mov pc, lr + bx lr endfunc diff --git a/libswresample/audioconvert.c b/libswresample/audioconvert.c index 1d75ba149..04108fb96 100644 --- a/libswresample/audioconvert.c +++ b/libswresample/audioconvert.c @@ -25,9 +25,9 @@ * @author Michael Niedermayer */ -#include "libavutil/avstring.h" #include "libavutil/avassert.h" #include "libavutil/libm.h" +#include "libavutil/mem.h" #include "libavutil/samplefmt.h" #include "audioconvert.h" diff --git a/libswresample/dither.c b/libswresample/dither.c index 64068d35b..61151a26e 100644 --- a/libswresample/dither.c +++ b/libswresample/dither.c @@ -19,6 +19,7 @@ */ #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "swresample_internal.h" #include "noise_shaping_data.c" diff --git a/libswresample/options.c b/libswresample/options.c index a3284a489..11b2884e3 100644 --- a/libswresample/options.c +++ b/libswresample/options.c @@ -19,6 +19,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "swresample_internal.h" diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c index fb4d9aecf..b9bf4dcac 100644 --- a/libswresample/rematrix.c +++ b/libswresample/rematrix.c @@ -21,6 +21,7 @@ #include "swresample_internal.h" #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/mem.h" #define TEMPLATE_REMATRIX_FLT #include "rematrix_template.c" diff --git a/libswresample/resample.c b/libswresample/resample.c index 17cebad01..2b8571bbd 100644 --- a/libswresample/resample.c +++ b/libswresample/resample.c @@ -27,7 +27,7 @@ */ #include "libavutil/avassert.h" -#include "libavutil/cpu.h" +#include "libavutil/mem.h" #include "resample.h" /** diff --git a/libswresample/swresample.c b/libswresample/swresample.c index 71b07d69b..0a4e216f9 100644 --- a/libswresample/swresample.c +++ b/libswresample/swresample.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "swresample_internal.h" #include "audioconvert.h" diff --git a/libswresample/swresample.h b/libswresample/swresample.h index 217e5461b..0e1929b3e 100644 --- a/libswresample/swresample.h +++ b/libswresample/swresample.h @@ -49,8 +49,8 @@ * matrix). This is using the swr_alloc() function. * @code * SwrContext *swr = swr_alloc(); - * av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0); - * av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); + * av_opt_set_chlayout(swr, "in_chlayout", &(AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1, 0); + * av_opt_set_chlayout(swr, "out_chlayout", &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO, 0); * av_opt_set_int(swr, "in_sample_rate", 48000, 0); * av_opt_set_int(swr, "out_sample_rate", 44100, 0); * av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); diff --git a/libswresample/version.c b/libswresample/version.c index 00f71e339..40fbbabf9 100644 --- a/libswresample/version.c +++ b/libswresample/version.c @@ -18,8 +18,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "config.h" -#include "libavutil/avassert.h" #include "swresample.h" #include "version.h" @@ -28,7 +29,7 @@ const char swr_ffversion[] = "FFmpeg version " FFMPEG_VERSION; unsigned swresample_version(void) { - av_assert0(LIBSWRESAMPLE_VERSION_MICRO >= 100); + static_assert(LIBSWRESAMPLE_VERSION_MICRO >= 100, "micro version starts at 100"); return LIBSWRESAMPLE_VERSION_INT; } diff --git a/libswresample/version.h b/libswresample/version.h index 9c223e142..d1795b554 100644 --- a/libswresample/version.h +++ b/libswresample/version.h @@ -30,7 +30,7 @@ #include "version_major.h" -#define LIBSWRESAMPLE_VERSION_MINOR 1 +#define LIBSWRESAMPLE_VERSION_MINOR 3 #define LIBSWRESAMPLE_VERSION_MICRO 100 #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ diff --git a/libswresample/x86/rematrix_init.c b/libswresample/x86/rematrix_init.c index ce794eef9..623e154f5 100644 --- a/libswresample/x86/rematrix_init.c +++ b/libswresample/x86/rematrix_init.c @@ -19,6 +19,7 @@ */ #include "libavutil/attributes.h" +#include "libavutil/mem.h" #include "libavutil/x86/cpu.h" #include "libswresample/swresample_internal.h" diff --git a/libswscale/aarch64/Makefile b/libswscale/aarch64/Makefile index da1d90956..1de8c9c0d 100644 --- a/libswscale/aarch64/Makefile +++ b/libswscale/aarch64/Makefile @@ -3,6 +3,9 @@ OBJS += aarch64/rgb2rgb.o \ aarch64/swscale_unscaled.o \ NEON-OBJS += aarch64/hscale.o \ + aarch64/input.o \ aarch64/output.o \ + aarch64/range_convert_neon.o \ aarch64/rgb2rgb_neon.o \ + aarch64/swscale_unscaled_neon.o \ aarch64/yuv2rgb_neon.o \ diff --git a/libswscale/aarch64/input.S b/libswscale/aarch64/input.S new file mode 100644 index 000000000..5cb18711f --- /dev/null +++ b/libswscale/aarch64/input.S @@ -0,0 +1,315 @@ +/* + * 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/aarch64/asm.S" + +.macro rgb_to_yuv_load_rgb src, element=3 + .if \element == 3 + ld3 { v16.16b, v17.16b, v18.16b }, [\src] + .else + ld4 { v16.16b, v17.16b, v18.16b, v19.16b }, [\src] + .endif + uxtl v19.8h, v16.8b // v19: r + uxtl v20.8h, v17.8b // v20: g + uxtl v21.8h, v18.8b // v21: b + uxtl2 v22.8h, v16.16b // v22: r + uxtl2 v23.8h, v17.16b // v23: g + uxtl2 v24.8h, v18.16b // v24: b +.endm + +.macro argb_to_yuv_load_rgb src + ld4 { v16.16b, v17.16b, v18.16b, v19.16b }, [\src] + uxtl v21.8h, v19.8b // v21: b + uxtl2 v24.8h, v19.16b // v24: b + uxtl v19.8h, v17.8b // v19: r + uxtl v20.8h, v18.8b // v20: g + uxtl2 v22.8h, v17.16b // v22: r + uxtl2 v23.8h, v18.16b // v23: g +.endm + +.macro rgb_to_yuv_product r, g, b, dst1, dst2, dst, coef0, coef1, coef2, right_shift + mov \dst1\().16b, v6.16b // dst1 = const_offset + mov \dst2\().16b, v6.16b // dst2 = const_offset + smlal \dst1\().4s, \coef0\().4h, \r\().4h // dst1 += rx * r + smlal \dst1\().4s, \coef1\().4h, \g\().4h // dst1 += gx * g + smlal \dst1\().4s, \coef2\().4h, \b\().4h // dst1 += bx * b + smlal2 \dst2\().4s, \coef0\().8h, \r\().8h // dst2 += rx * r + smlal2 \dst2\().4s, \coef1\().8h, \g\().8h // dst2 += gx * g + smlal2 \dst2\().4s, \coef2\().8h, \b\().8h // dst2 += bx * b + sqshrn \dst\().4h, \dst1\().4s, \right_shift // dst_lower_half = dst1 >> right_shift + sqshrn2 \dst\().8h, \dst2\().4s, \right_shift // dst_higher_half = dst2 >> right_shift +.endm + +.macro rgbToY_neon fmt_bgr, fmt_rgb, element, alpha_first=0 +function ff_\fmt_bgr\()ToY_neon, export=1 + cmp w4, #0 // check width > 0 + ldp w12, w11, [x5] // w12: ry, w11: gy + ldr w10, [x5, #8] // w10: by + b.gt 4f + ret +endfunc + +function ff_\fmt_rgb\()ToY_neon, export=1 + cmp w4, #0 // check width > 0 + ldp w10, w11, [x5] // w10: ry, w11: gy + ldr w12, [x5, #8] // w12: by + b.le 3f +4: + mov w9, #256 // w9 = 1 << (RGB2YUV_SHIFT - 7) + movk w9, #8, lsl #16 // w9 += 32 << (RGB2YUV_SHIFT - 1) + dup v6.4s, w9 // w9: const_offset + + cmp w4, #16 + dup v0.8h, w10 + dup v1.8h, w11 + dup v2.8h, w12 + b.lt 2f +1: + .if \alpha_first + argb_to_yuv_load_rgb x1 + .else + rgb_to_yuv_load_rgb x1, \element + .endif + rgb_to_yuv_product v19, v20, v21, v25, v26, v16, v0, v1, v2, #9 + rgb_to_yuv_product v22, v23, v24, v27, v28, v17, v0, v1, v2, #9 + sub w4, w4, #16 // width -= 16 + add x1, x1, #(16*\element) + cmp w4, #16 // width >= 16 ? + stp q16, q17, [x0], #32 // store to dst + b.ge 1b + cbz x4, 3f +2: + .if \alpha_first + ldrb w13, [x1, #1] // w13: r + ldrb w14, [x1, #2] // w14: g + ldrb w15, [x1, #3] // w15: b + .else + ldrb w13, [x1] // w13: r + ldrb w14, [x1, #1] // w14: g + ldrb w15, [x1, #2] // w15: b + .endif + + smaddl x13, w13, w10, x9 // x13 = ry * r + const_offset + smaddl x13, w14, w11, x13 // x13 += gy * g + smaddl x13, w15, w12, x13 // x13 += by * b + asr w13, w13, #9 // x13 >>= 9 + sub w4, w4, #1 // width-- + add x1, x1, #\element + strh w13, [x0], #2 // store to dst + cbnz w4, 2b +3: + ret +endfunc +.endm + +rgbToY_neon bgr24, rgb24, element=3 + +rgbToY_neon bgra32, rgba32, element=4 + +rgbToY_neon abgr32, argb32, element=4, alpha_first=1 + +.macro rgb_set_uv_coeff half + .if \half + mov w9, #512 + movk w9, #128, lsl #16 // w9: const_offset + .else + mov w9, #256 + movk w9, #64, lsl #16 // w9: const_offset + .endif + dup v0.8h, w10 + dup v1.8h, w11 + dup v2.8h, w12 + dup v3.8h, w13 + dup v4.8h, w14 + dup v5.8h, w15 + dup v6.4s, w9 +.endm + +.macro rgb_load_add_half off_r1, off_r2, off_g1, off_g2, off_b1, off_b2 + ldrb w2, [x3, #\off_r1] // w2: r1 + ldrb w4, [x3, #\off_r2] // w4: r2 + add w2, w2, w4 // w2 = r1 + r2 + + ldrb w4, [x3, #\off_g1] // w4: g1 + ldrb w7, [x3, #\off_g2] // w7: g2 + add w4, w4, w7 // w4 = g1 + g2 + + ldrb w7, [x3, #\off_b1] // w7: b1 + ldrb w8, [x3, #\off_b2] // w8: b2 + add w7, w7, w8 // w7 = b1 + b2 +.endm + +.macro rgbToUV_half_neon fmt_bgr, fmt_rgb, element, alpha_first=0 +function ff_\fmt_bgr\()ToUV_half_neon, export=1 + cmp w5, #0 // check width > 0 + b.le 3f + + ldp w12, w11, [x6, #12] + ldp w10, w15, [x6, #20] + ldp w14, w13, [x6, #28] + b 4f +endfunc + +function ff_\fmt_rgb\()ToUV_half_neon, export=1 + cmp w5, #0 // check width > 0 + b.le 3f + + ldp w10, w11, [x6, #12] // w10: ru, w11: gu + ldp w12, w13, [x6, #20] // w12: bu, w13: rv + ldp w14, w15, [x6, #28] // w14: gv, w15: bv +4: + cmp w5, #8 + rgb_set_uv_coeff half=1 + b.lt 2f +1: + .if \element == 3 + ld3 { v16.16b, v17.16b, v18.16b }, [x3] + .else + ld4 { v16.16b, v17.16b, v18.16b, v19.16b }, [x3] + .endif + .if \alpha_first + uaddlp v21.8h, v19.16b + uaddlp v20.8h, v18.16b + uaddlp v19.8h, v17.16b + .else + uaddlp v19.8h, v16.16b // v19: r + uaddlp v20.8h, v17.16b // v20: g + uaddlp v21.8h, v18.16b // v21: b + .endif + + rgb_to_yuv_product v19, v20, v21, v22, v23, v16, v0, v1, v2, #10 + rgb_to_yuv_product v19, v20, v21, v24, v25, v17, v3, v4, v5, #10 + sub w5, w5, #8 // width -= 8 + add x3, x3, #(16*\element) + cmp w5, #8 // width >= 8 ? + str q16, [x0], #16 // store dst_u + str q17, [x1], #16 // store dst_v + b.ge 1b + cbz w5, 3f +2: +.if \alpha_first + rgb_load_add_half 1, 5, 2, 6, 3, 7 +.else + .if \element == 3 + rgb_load_add_half 0, 3, 1, 4, 2, 5 + .else + rgb_load_add_half 0, 4, 1, 5, 2, 6 + .endif +.endif + + smaddl x8, w2, w10, x9 // dst_u = ru * r + const_offset + smaddl x8, w4, w11, x8 // dst_u += gu * g + smaddl x8, w7, w12, x8 // dst_u += bu * b + asr x8, x8, #10 // dst_u >>= 10 + strh w8, [x0], #2 // store dst_u + + smaddl x8, w2, w13, x9 // dst_v = rv * r + const_offset + smaddl x8, w4, w14, x8 // dst_v += gv * g + smaddl x8, w7, w15, x8 // dst_v += bv * b + asr x8, x8, #10 // dst_v >>= 10 + sub w5, w5, #1 + add x3, x3, #(2*\element) + strh w8, [x1], #2 // store dst_v + cbnz w5, 2b +3: + ret +endfunc +.endm + +rgbToUV_half_neon bgr24, rgb24, element=3 + +rgbToUV_half_neon bgra32, rgba32, element=4 + +rgbToUV_half_neon abgr32, argb32, element=4, alpha_first=1 + +.macro rgbToUV_neon fmt_bgr, fmt_rgb, element, alpha_first=0 +function ff_\fmt_bgr\()ToUV_neon, export=1 + cmp w5, #0 // check width > 0 + b.le 3f + + ldp w12, w11, [x6, #12] + ldp w10, w15, [x6, #20] + ldp w14, w13, [x6, #28] + b 4f +endfunc + +function ff_\fmt_rgb\()ToUV_neon, export=1 + cmp w5, #0 // check width > 0 + b.le 3f + + ldp w10, w11, [x6, #12] // w10: ru, w11: gu + ldp w12, w13, [x6, #20] // w12: bu, w13: rv + ldp w14, w15, [x6, #28] // w14: gv, w15: bv +4: + cmp w5, #16 + rgb_set_uv_coeff half=0 + b.lt 2f +1: + .if \alpha_first + argb_to_yuv_load_rgb x3 + .else + rgb_to_yuv_load_rgb x3, \element + .endif + rgb_to_yuv_product v19, v20, v21, v25, v26, v16, v0, v1, v2, #9 + rgb_to_yuv_product v22, v23, v24, v27, v28, v17, v0, v1, v2, #9 + rgb_to_yuv_product v19, v20, v21, v25, v26, v18, v3, v4, v5, #9 + rgb_to_yuv_product v22, v23, v24, v27, v28, v19, v3, v4, v5, #9 + sub w5, w5, #16 + add x3, x3, #(16*\element) + cmp w5, #16 + stp q16, q17, [x0], #32 // store to dst_u + stp q18, q19, [x1], #32 // store to dst_v + b.ge 1b + cbz w5, 3f +2: + .if \alpha_first + ldrb w16, [x3, #1] // w16: r + ldrb w17, [x3, #2] // w17: g + ldrb w4, [x3, #3] // w4: b + .else + ldrb w16, [x3] // w16: r + ldrb w17, [x3, #1] // w17: g + ldrb w4, [x3, #2] // w4: b + .endif + + smaddl x8, w16, w10, x9 // x8 = ru * r + const_offset + smaddl x8, w17, w11, x8 // x8 += gu * g + smaddl x8, w4, w12, x8 // x8 += bu * b + asr w8, w8, #9 // x8 >>= 9 + strh w8, [x0], #2 // store to dst_u + + smaddl x8, w16, w13, x9 // x8 = rv * r + const_offset + smaddl x8, w17, w14, x8 // x8 += gv * g + smaddl x8, w4, w15, x8 // x8 += bv * b + asr w8, w8, #9 // x8 >>= 9 + sub w5, w5, #1 // width-- + add x3, x3, #\element + strh w8, [x1], #2 // store to dst_v + cbnz w5, 2b +3: + ret +endfunc +.endm + +rgbToUV_neon bgr24, rgb24, element=3 + +rgbToUV_neon bgra32, rgba32, element=4 + +rgbToUV_neon abgr32, argb32, element=4, alpha_first=1 diff --git a/libswscale/aarch64/range_convert_neon.S b/libswscale/aarch64/range_convert_neon.S new file mode 100644 index 000000000..30991ab2a --- /dev/null +++ b/libswscale/aarch64/range_convert_neon.S @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 Ramiro Polla + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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" + +.macro lumConvertRange name, max, mult, offset, shift +function ff_\name, export=1 +.if \max != 0 + mov w3, #\max + dup v24.8h, w3 +.endif + mov w3, #\mult + dup v25.4s, w3 + movz w3, #(\offset & 0xffff) + movk w3, #((\offset >> 16) & 0xffff), lsl #16 + dup v26.4s, w3 +1: + ld1 {v0.8h}, [x0] +.if \max != 0 + smin v0.8h, v0.8h, v24.8h +.endif + mov v16.16b, v26.16b + mov v18.16b, v26.16b + sxtl v20.4s, v0.4h + sxtl2 v22.4s, v0.8h + mla v16.4s, v20.4s, v25.4s + mla v18.4s, v22.4s, v25.4s + shrn v0.4h, v16.4s, #\shift + shrn2 v0.8h, v18.4s, #\shift + subs w1, w1, #8 + st1 {v0.8h}, [x0], #16 + b.gt 1b + ret +endfunc +.endm + +.macro chrConvertRange name, max, mult, offset, shift +function ff_\name, export=1 +.if \max != 0 + mov w3, #\max + dup v24.8h, w3 +.endif + mov w3, #\mult + dup v25.4s, w3 + movz w3, #(\offset & 0xffff) + movk w3, #((\offset >> 16) & 0xffff), lsl #16 + dup v26.4s, w3 +1: + ld1 {v0.8h}, [x0] + ld1 {v1.8h}, [x1] +.if \max != 0 + smin v0.8h, v0.8h, v24.8h + smin v1.8h, v1.8h, v24.8h +.endif + mov v16.16b, v26.16b + mov v17.16b, v26.16b + mov v18.16b, v26.16b + mov v19.16b, v26.16b + sxtl v20.4s, v0.4h + sxtl v21.4s, v1.4h + sxtl2 v22.4s, v0.8h + sxtl2 v23.4s, v1.8h + mla v16.4s, v20.4s, v25.4s + mla v17.4s, v21.4s, v25.4s + mla v18.4s, v22.4s, v25.4s + mla v19.4s, v23.4s, v25.4s + shrn v0.4h, v16.4s, #\shift + shrn v1.4h, v17.4s, #\shift + shrn2 v0.8h, v18.4s, #\shift + shrn2 v1.8h, v19.4s, #\shift + subs w2, w2, #8 + st1 {v0.8h}, [x0], #16 + st1 {v1.8h}, [x1], #16 + b.gt 1b + ret +endfunc +.endm + +lumConvertRange lumRangeToJpeg_neon, 30189, 19077, -39057361, 14 +chrConvertRange chrRangeToJpeg_neon, 30775, 4663, -9289992, 12 +lumConvertRange lumRangeFromJpeg_neon, 0, 14071, 33561947, 14 +chrConvertRange chrRangeFromJpeg_neon, 0, 1799, 4081085, 11 diff --git a/libswscale/aarch64/rgb2rgb.c b/libswscale/aarch64/rgb2rgb.c index a9bf6ff9e..20a25033c 100644 --- a/libswscale/aarch64/rgb2rgb.c +++ b/libswscale/aarch64/rgb2rgb.c @@ -27,15 +27,44 @@ #include "libswscale/swscale.h" #include "libswscale/swscale_internal.h" +// Only handle width aligned to 16 +void ff_rgb24toyv12_neon(const uint8_t *src, uint8_t *ydst, uint8_t *udst, + uint8_t *vdst, int width, int height, int lumStride, + int chromStride, int srcStride, int32_t *rgb2yuv); + +static void rgb24toyv12(const uint8_t *src, uint8_t *ydst, uint8_t *udst, + uint8_t *vdst, int width, int height, int lumStride, + int chromStride, int srcStride, int32_t *rgb2yuv) +{ + int width_align = width & (~15); + + if (width_align > 0) + ff_rgb24toyv12_neon(src, ydst, udst, vdst, width_align, height, + lumStride, chromStride, srcStride, rgb2yuv); + if (width_align < width) { + src += width_align * 3; + ydst += width_align; + udst += width_align / 2; + vdst += width_align / 2; + ff_rgb24toyv12_c(src, ydst, udst, vdst, width - width_align, height, + lumStride, chromStride, srcStride, rgb2yuv); + } +} + void ff_interleave_bytes_neon(const uint8_t *src1, const uint8_t *src2, uint8_t *dest, int width, int height, int src1Stride, int src2Stride, int dstStride); +void ff_deinterleave_bytes_neon(const uint8_t *src, uint8_t *dst1, uint8_t *dst2, + int width, int height, int srcStride, + int dst1Stride, int dst2Stride); av_cold void rgb2rgb_init_aarch64(void) { int cpu_flags = av_get_cpu_flags(); if (have_neon(cpu_flags)) { + ff_rgb24toyv12 = rgb24toyv12; interleaveBytes = ff_interleave_bytes_neon; + deinterleaveBytes = ff_deinterleave_bytes_neon; } } diff --git a/libswscale/aarch64/rgb2rgb_neon.S b/libswscale/aarch64/rgb2rgb_neon.S index d81110ec5..1382e0026 100644 --- a/libswscale/aarch64/rgb2rgb_neon.S +++ b/libswscale/aarch64/rgb2rgb_neon.S @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Martin Storsjo + * Copyright (c) 2024 Ramiro Polla * * This file is part of FFmpeg. * @@ -20,6 +21,165 @@ #include "libavutil/aarch64/asm.S" +#define RGB2YUV_COEFFS 16*4+16*32 +#define BY v0.h[0] +#define GY v0.h[1] +#define RY v0.h[2] +#define BU v1.h[0] +#define GU v1.h[1] +#define RU v1.h[2] +#define BV v2.h[0] +#define GV v2.h[1] +#define RV v2.h[2] +#define Y_OFFSET v22 +#define UV_OFFSET v23 + +// convert rgb to 16-bit y, u, or v +// uses v3 and v4 +.macro rgbconv16 dst, b, g, r, bc, gc, rc + smull v3.4s, \b\().4h, \bc + smlal v3.4s, \g\().4h, \gc + smlal v3.4s, \r\().4h, \rc + smull2 v4.4s, \b\().8h, \bc + smlal2 v4.4s, \g\().8h, \gc + smlal2 v4.4s, \r\().8h, \rc // v3:v4 = b * bc + g * gc + r * rc (32-bit) + shrn \dst\().4h, v3.4s, #7 + shrn2 \dst\().8h, v4.4s, #7 // dst = b * bc + g * gc + r * rc (16-bit) +.endm + +// void ff_rgb24toyv12_neon(const uint8_t *src, uint8_t *ydst, uint8_t *udst, +// uint8_t *vdst, int width, int height, int lumStride, +// int chromStride, int srcStride, int32_t *rgb2yuv); +function ff_rgb24toyv12_neon, export=1 +// x0 const uint8_t *src +// x1 uint8_t *ydst +// x2 uint8_t *udst +// x3 uint8_t *vdst +// w4 int width +// w5 int height +// w6 int lumStride +// w7 int chromStride + ldrsw x14, [sp] + ldr x15, [sp, #8] +// x14 int srcStride +// x15 int32_t *rgb2yuv + + // extend width and stride parameters + uxtw x4, w4 + sxtw x6, w6 + sxtw x7, w7 + + // src1 = x0 + // src2 = x10 + add x10, x0, x14 // x10 = src + srcStride + lsl x14, x14, #1 // srcStride *= 2 + add x11, x4, x4, lsl #1 // x11 = 3 * width + sub x14, x14, x11 // srcPadding = (2 * srcStride) - (3 * width) + + // ydst1 = x1 + // ydst2 = x11 + add x11, x1, x6 // x11 = ydst + lumStride + lsl x6, x6, #1 // lumStride *= 2 + sub x6, x6, x4 // lumPadding = (2 * lumStride) - width + + sub x7, x7, x4, lsr #1 // chromPadding = chromStride - (width / 2) + + // load rgb2yuv coefficients into v0, v1, and v2 + add x15, x15, #RGB2YUV_COEFFS + ld1 {v0.8h-v2.8h}, [x15] // load 24 values + + // load offset constants + movi Y_OFFSET.8h, #0x10, lsl #8 + movi UV_OFFSET.8h, #0x80, lsl #8 + +1: + mov w15, w4 // w15 = width + +2: + // load first line + ld3 {v26.16b, v27.16b, v28.16b}, [x0], #48 + + // widen first line to 16-bit + uxtl v16.8h, v26.8b // v16 = B11 + uxtl v17.8h, v27.8b // v17 = G11 + uxtl v18.8h, v28.8b // v18 = R11 + uxtl2 v19.8h, v26.16b // v19 = B12 + uxtl2 v20.8h, v27.16b // v20 = G12 + uxtl2 v21.8h, v28.16b // v21 = R12 + + // calculate Y values for first line + rgbconv16 v24, v16, v17, v18, BY, GY, RY // v24 = Y11 + rgbconv16 v25, v19, v20, v21, BY, GY, RY // v25 = Y12 + + // load second line + ld3 {v26.16b, v27.16b, v28.16b}, [x10], #48 + + // pairwise add and save rgb values to calculate average + addp v5.8h, v16.8h, v19.8h + addp v6.8h, v17.8h, v20.8h + addp v7.8h, v18.8h, v21.8h + + // widen second line to 16-bit + uxtl v16.8h, v26.8b // v16 = B21 + uxtl v17.8h, v27.8b // v17 = G21 + uxtl v18.8h, v28.8b // v18 = R21 + uxtl2 v19.8h, v26.16b // v19 = B22 + uxtl2 v20.8h, v27.16b // v20 = G22 + uxtl2 v21.8h, v28.16b // v21 = R22 + + // calculate Y values for second line + rgbconv16 v26, v16, v17, v18, BY, GY, RY // v26 = Y21 + rgbconv16 v27, v19, v20, v21, BY, GY, RY // v27 = Y22 + + // pairwise add rgb values to calculate average + addp v16.8h, v16.8h, v19.8h + addp v17.8h, v17.8h, v20.8h + addp v18.8h, v18.8h, v21.8h + + // calculate average + add v16.8h, v16.8h, v5.8h + add v17.8h, v17.8h, v6.8h + add v18.8h, v18.8h, v7.8h + ushr v16.8h, v16.8h, #2 + ushr v17.8h, v17.8h, #2 + ushr v18.8h, v18.8h, #2 + + // calculate U and V values + rgbconv16 v28, v16, v17, v18, BU, GU, RU // v28 = U + rgbconv16 v29, v16, v17, v18, BV, GV, RV // v29 = V + + // add offsets and narrow all values + addhn v24.8b, v24.8h, Y_OFFSET.8h + addhn v25.8b, v25.8h, Y_OFFSET.8h + addhn v26.8b, v26.8h, Y_OFFSET.8h + addhn v27.8b, v27.8h, Y_OFFSET.8h + addhn v28.8b, v28.8h, UV_OFFSET.8h + addhn v29.8b, v29.8h, UV_OFFSET.8h + + subs w15, w15, #16 + + // store output + st1 {v24.8b, v25.8b}, [x1], #16 // store ydst1 + st1 {v26.8b, v27.8b}, [x11], #16 // store ydst2 + st1 {v28.8b}, [x2], #8 // store udst + st1 {v29.8b}, [x3], #8 // store vdst + + b.gt 2b + + subs w5, w5, #2 + + // row += 2 + add x0, x0, x14 // src1 += srcPadding + add x10, x10, x14 // src2 += srcPadding + add x1, x1, x6 // ydst1 += lumPadding + add x11, x11, x6 // ydst2 += lumPadding + add x2, x2, x7 // udst += chromPadding + add x3, x3, x7 // vdst += chromPadding + b.gt 1b + + ret +endfunc + // void ff_interleave_bytes_neon(const uint8_t *src1, const uint8_t *src2, // uint8_t *dest, int width, int height, // int src1Stride, int src2Stride, int dstStride); @@ -77,3 +237,62 @@ function ff_interleave_bytes_neon, export=1 0: ret endfunc + +// void ff_deinterleave_bytes_neon(const uint8_t *src, uint8_t *dst1, uint8_t *dst2, +// int width, int height, int srcStride, +// int dst1Stride, int dst2Stride); +function ff_deinterleave_bytes_neon, export=1 + sub w5, w5, w3, lsl #1 + sub w6, w6, w3 + sub w7, w7, w3 +1: + ands w8, w3, #0xfffffff0 // & ~15 + b.eq 3f +2: + ld2 {v0.16b, v1.16b}, [x0], #32 + subs w8, w8, #16 + st1 {v0.16b}, [x1], #16 + st1 {v1.16b}, [x2], #16 + b.gt 2b + + tst w3, #15 + b.eq 9f + +3: + tst w3, #8 + b.eq 4f + ld2 {v0.8b, v1.8b}, [x0], #16 + st1 {v0.8b}, [x1], #8 + st1 {v1.8b}, [x2], #8 +4: + tst w3, #4 + b.eq 5f + + ld1 {v0.8b}, [x0], #8 + shrn v1.8b, v0.8h, #8 + xtn v0.8b, v0.8h + st1 {v0.s}[0], [x1], #4 + st1 {v1.s}[0], [x2], #4 + +5: + ands w8, w3, #3 + b.eq 9f +6: + ldrh w9, [x0], #2 + subs w8, w8, #1 + ubfx w10, w9, #8, #8 + strb w9, [x1], #1 + strb w10, [x2], #1 + b.gt 6b + +9: + subs w4, w4, #1 + b.eq 0f + add x0, x0, w5, sxtw + add x1, x1, w6, sxtw + add x2, x2, w7, sxtw + b 1b + +0: + ret +endfunc diff --git a/libswscale/aarch64/swscale.c b/libswscale/aarch64/swscale.c index bbd9719a4..eb907284e 100644 --- a/libswscale/aarch64/swscale.c +++ b/libswscale/aarch64/swscale.c @@ -201,6 +201,43 @@ void ff_yuv2plane1_8_neon( default: break; \ } +#define NEON_INPUT(name) \ +void ff_##name##ToY_neon(uint8_t *dst, const uint8_t *src, const uint8_t *, \ + const uint8_t *, int w, uint32_t *coeffs, void *); \ +void ff_##name##ToUV_neon(uint8_t *, uint8_t *, const uint8_t *, \ + const uint8_t *, const uint8_t *, int w, \ + uint32_t *coeffs, void *); \ +void ff_##name##ToUV_half_neon(uint8_t *, uint8_t *, const uint8_t *, \ + const uint8_t *, const uint8_t *, int w, \ + uint32_t *coeffs, void *) + +NEON_INPUT(abgr32); +NEON_INPUT(argb32); +NEON_INPUT(bgr24); +NEON_INPUT(bgra32); +NEON_INPUT(rgb24); +NEON_INPUT(rgba32); + +void ff_lumRangeFromJpeg_neon(int16_t *dst, int width); +void ff_chrRangeFromJpeg_neon(int16_t *dstU, int16_t *dstV, int width); +void ff_lumRangeToJpeg_neon(int16_t *dst, int width); +void ff_chrRangeToJpeg_neon(int16_t *dstU, int16_t *dstV, int width); + +av_cold void ff_sws_init_range_convert_aarch64(SwsContext *c) +{ + if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) { + if (c->dstBpc <= 14) { + if (c->srcRange) { + c->lumConvertRange = ff_lumRangeFromJpeg_neon; + c->chrConvertRange = ff_chrRangeFromJpeg_neon; + } else { + c->lumConvertRange = ff_lumRangeToJpeg_neon; + c->chrConvertRange = ff_chrRangeToJpeg_neon; + } + } + } +} + av_cold void ff_sws_init_swscale_aarch64(SwsContext *c) { int cpu_flags = av_get_cpu_flags(); @@ -212,5 +249,53 @@ av_cold void ff_sws_init_swscale_aarch64(SwsContext *c) if (c->dstBpc == 8) { c->yuv2planeX = ff_yuv2planeX_8_neon; } + switch (c->srcFormat) { + case AV_PIX_FMT_ABGR: + c->lumToYV12 = ff_abgr32ToY_neon; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_abgr32ToUV_half_neon; + else + c->chrToYV12 = ff_abgr32ToUV_neon; + break; + + case AV_PIX_FMT_ARGB: + c->lumToYV12 = ff_argb32ToY_neon; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_argb32ToUV_half_neon; + else + c->chrToYV12 = ff_argb32ToUV_neon; + break; + case AV_PIX_FMT_BGR24: + c->lumToYV12 = ff_bgr24ToY_neon; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_bgr24ToUV_half_neon; + else + c->chrToYV12 = ff_bgr24ToUV_neon; + break; + case AV_PIX_FMT_BGRA: + c->lumToYV12 = ff_bgra32ToY_neon; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_bgra32ToUV_half_neon; + else + c->chrToYV12 = ff_bgra32ToUV_neon; + break; + case AV_PIX_FMT_RGB24: + c->lumToYV12 = ff_rgb24ToY_neon; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_rgb24ToUV_half_neon; + else + c->chrToYV12 = ff_rgb24ToUV_neon; + break; + case AV_PIX_FMT_RGBA: + c->lumToYV12 = ff_rgba32ToY_neon; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_rgba32ToUV_half_neon; + else + c->chrToYV12 = ff_rgba32ToUV_neon; + break; + default: + break; + } + ff_sws_init_range_convert_aarch64(c); } } diff --git a/libswscale/aarch64/swscale_unscaled.c b/libswscale/aarch64/swscale_unscaled.c index b3093bbc9..9dfccc0fd 100644 --- a/libswscale/aarch64/swscale_unscaled.c +++ b/libswscale/aarch64/swscale_unscaled.c @@ -52,11 +52,41 @@ static int ifmt##_to_##ofmt##_neon_wrapper(SwsContext *c, const uint8_t *src[], c->yuv2rgb_y_coeff); \ } \ +#define DECLARE_FF_YUVX_TO_GBRP_FUNCS(ifmt, ofmt) \ +int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \ + uint8_t *dst, int linesize, \ + const uint8_t *srcY, int linesizeY, \ + const uint8_t *srcU, int linesizeU, \ + const uint8_t *srcV, int linesizeV, \ + const int16_t *table, \ + int y_offset, \ + int y_coeff, \ + uint8_t *dst1, int linesize1, \ + uint8_t *dst2, int linesize2); \ + \ +static int ifmt##_to_##ofmt##_neon_wrapper(SwsContext *c, const uint8_t *src[], \ + int srcStride[], int srcSliceY, int srcSliceH, \ + uint8_t *dst[], int dstStride[]) { \ + const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \ + \ + return ff_##ifmt##_to_##ofmt##_neon(c->srcW, srcSliceH, \ + dst[0] + srcSliceY * dstStride[0], dstStride[0], \ + src[0], srcStride[0], \ + src[1], srcStride[1], \ + src[2], srcStride[2], \ + yuv2rgb_table, \ + c->yuv2rgb_y_offset >> 6, \ + c->yuv2rgb_y_coeff, \ + dst[1] + srcSliceY * dstStride[1], dstStride[1], \ + dst[2] + srcSliceY * dstStride[2], dstStride[2]); \ +} \ + #define DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuvx) \ DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, argb) \ DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, rgba) \ DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, abgr) \ DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, bgra) \ +DECLARE_FF_YUVX_TO_GBRP_FUNCS(yuvx, gbrp) \ DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv420p) DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv422p) @@ -83,11 +113,63 @@ static int ifmt##_to_##ofmt##_neon_wrapper(SwsContext *c, const uint8_t *src[], c->yuv2rgb_y_coeff); \ } \ +#define DECLARE_FF_NVX_TO_GBRP_FUNCS(ifmt, ofmt) \ +int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \ + uint8_t *dst, int linesize, \ + const uint8_t *srcY, int linesizeY, \ + const uint8_t *srcC, int linesizeC, \ + const int16_t *table, \ + int y_offset, \ + int y_coeff, \ + uint8_t *dst1, int linesize1, \ + uint8_t *dst2, int linesize2); \ + \ +static int ifmt##_to_##ofmt##_neon_wrapper(SwsContext *c, const uint8_t *src[], \ + int srcStride[], int srcSliceY, int srcSliceH, \ + uint8_t *dst[], int dstStride[]) { \ + const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \ + \ + return ff_##ifmt##_to_##ofmt##_neon(c->srcW, srcSliceH, \ + dst[0] + srcSliceY * dstStride[0], dstStride[0], \ + src[0], srcStride[0], src[1], srcStride[1], \ + yuv2rgb_table, \ + c->yuv2rgb_y_offset >> 6, \ + c->yuv2rgb_y_coeff, \ + dst[1] + srcSliceY * dstStride[1], dstStride[1], \ + dst[2] + srcSliceY * dstStride[2], dstStride[2]); \ +} \ + +void ff_nv24_to_yuv420p_chroma_neon(uint8_t *dst1, int dstStride1, + uint8_t *dst2, int dstStride2, + const uint8_t *src, int srcStride, + int w, int h); + +static int nv24_to_yuv420p_neon_wrapper(SwsContext *c, const uint8_t *src[], + int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + uint8_t *dst1 = dst[1] + dstStride[1] * srcSliceY / 2; + uint8_t *dst2 = dst[2] + dstStride[2] * srcSliceY / 2; + + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dst[0], dstStride[0]); + + if (c->srcFormat == AV_PIX_FMT_NV24) + ff_nv24_to_yuv420p_chroma_neon(dst1, dstStride[1], dst2, dstStride[2], + src[1], srcStride[1], c->srcW / 2, srcSliceH); + else + ff_nv24_to_yuv420p_chroma_neon(dst2, dstStride[2], dst1, dstStride[1], + src[1], srcStride[1], c->srcW / 2, srcSliceH); + + return srcSliceH; +} + #define DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nvx) \ DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, argb) \ DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, rgba) \ DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, abgr) \ DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, bgra) \ +DECLARE_FF_NVX_TO_GBRP_FUNCS(nvx, gbrp) \ DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv12) DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv21) @@ -110,6 +192,7 @@ DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv21) SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, rgba, RGBA, accurate_rnd); \ SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, abgr, ABGR, accurate_rnd); \ SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, bgra, BGRA, accurate_rnd); \ + SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, gbrp, GBRP, accurate_rnd); \ } while (0) static void get_unscaled_swscale_neon(SwsContext *c) { @@ -119,6 +202,11 @@ static void get_unscaled_swscale_neon(SwsContext *c) { SET_FF_NVX_TO_ALL_RGBX_FUNC(nv21, NV21, accurate_rnd); SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv420p, YUV420P, accurate_rnd); SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv422p, YUV422P, accurate_rnd); + + if (c->dstFormat == AV_PIX_FMT_YUV420P && + (c->srcFormat == AV_PIX_FMT_NV24 || c->srcFormat == AV_PIX_FMT_NV42) && + !(c->srcH & 1) && !(c->srcW & 15) && !accurate_rnd) + c->convert_unscaled = nv24_to_yuv420p_neon_wrapper; } void ff_get_unscaled_swscale_aarch64(SwsContext *c) diff --git a/libswscale/aarch64/swscale_unscaled_neon.S b/libswscale/aarch64/swscale_unscaled_neon.S new file mode 100644 index 000000000..a074b187e --- /dev/null +++ b/libswscale/aarch64/swscale_unscaled_neon.S @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 Ramiro Polla + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_nv24_to_yuv420p_chroma_neon, export=1 +// x0 uint8_t *dst1 +// x1 int dstStride1 +// x2 uint8_t *dst2 +// x3 int dstStride2 +// x4 const uint8_t *src +// x5 int srcStride +// w6 int w +// w7 int h + + add x9, x4, w5, sxtw // x9 = src + srcStride + lsl w5, w5, #1 // srcStride *= 2 + sub w5, w5, w6, lsl #2 // srcPadding = (2 * srcStride) - (4 * w) + sub w1, w1, w6 // dstPadding1 = dstStride1 - w + sub w3, w3, w6 // dstPadding2 = dstStride2 - w + +1: + mov w10, w6 // w10 = w + +2: + ld2 {v0.16b, v1.16b}, [x4], #32 // v0 = U1, v1 = V1 + ld2 {v2.16b, v3.16b}, [x9], #32 // v2 = U2, v3 = V2 + + uaddlp v0.8h, v0.16b // pairwise add U1 into v0 + uaddlp v1.8h, v1.16b // pairwise add V1 into v1 + uadalp v0.8h, v2.16b // pairwise add U2, accumulate into v0 + uadalp v1.8h, v3.16b // pairwise add V2, accumulate into v1 + + shrn v0.8b, v0.8h, #2 // divide by 4 + shrn v1.8b, v1.8h, #2 // divide by 4 + + st1 {v0.8b}, [x0], #8 // store U into dst1 + st1 {v1.8b}, [x2], #8 // store V into dst2 + + subs w10, w10, #8 + b.gt 2b + + // next row + add x4, x4, w5, sxtw // src1 += srcPadding + add x9, x9, w5, sxtw // src2 += srcPadding + add x0, x0, w1, sxtw // dst1 += dstPadding1 + add x2, x2, w3, sxtw // dst2 += dstPadding2 + + subs w7, w7, #2 + b.gt 1b + + ret +endfunc diff --git a/libswscale/aarch64/yuv2rgb_neon.S b/libswscale/aarch64/yuv2rgb_neon.S index 89d69e7f6..cc7d8b58f 100644 --- a/libswscale/aarch64/yuv2rgb_neon.S +++ b/libswscale/aarch64/yuv2rgb_neon.S @@ -30,23 +30,43 @@ #endif .endm -.macro load_args_nv12 +.macro load_dst1_dst2 dst1 linesize1 dst2 linesize2 +#if defined(__APPLE__) +#define DST_OFFSET 8 +#else +#define DST_OFFSET 0 +#endif + ldr x10, [sp, #\dst1 - DST_OFFSET] + ldr w12, [sp, #\linesize1 - DST_OFFSET] + ldr x15, [sp, #\dst2 - DST_OFFSET] + ldr w16, [sp, #\linesize2 - DST_OFFSET] +#undef DST_OFFSET + sub w12, w12, w0 // w12 = linesize1 - width (padding1) + sub w16, w16, w0 // w16 = linesize2 - width (padding2) +.endm + +.macro load_args_nv12 ofmt ldr x8, [sp] // table load_yoff_ycoeff 8, 16 // y_offset, y_coeff ld1 {v1.1d}, [x8] dup v0.8h, w10 dup v3.8h, w9 +.ifc \ofmt,gbrp + load_dst1_dst2 24, 32, 40, 48 + sub w3, w3, w0 // w3 = linesize - width (padding) +.else sub w3, w3, w0, lsl #2 // w3 = linesize - width * 4 (padding) +.endif sub w5, w5, w0 // w5 = linesizeY - width (paddingY) sub w7, w7, w0 // w7 = linesizeC - width (paddingC) neg w11, w0 .endm -.macro load_args_nv21 - load_args_nv12 +.macro load_args_nv21 ofmt + load_args_nv12 \ofmt .endm -.macro load_args_yuv420p +.macro load_args_yuv420p ofmt ldr x13, [sp] // srcV ldr w14, [sp, #8] // linesizeV ldr x8, [sp, #16] // table @@ -54,7 +74,12 @@ ld1 {v1.1d}, [x8] dup v0.8h, w10 dup v3.8h, w9 +.ifc \ofmt,gbrp + load_dst1_dst2 40, 48, 56, 64 + sub w3, w3, w0 // w3 = linesize - width (padding) +.else sub w3, w3, w0, lsl #2 // w3 = linesize - width * 4 (padding) +.endif sub w5, w5, w0 // w5 = linesizeY - width (paddingY) sub w7, w7, w0, lsr #1 // w7 = linesizeU - width / 2 (paddingU) sub w14, w14, w0, lsr #1 // w14 = linesizeV - width / 2 (paddingV) @@ -62,7 +87,7 @@ neg w11, w11 .endm -.macro load_args_yuv422p +.macro load_args_yuv422p ofmt ldr x13, [sp] // srcV ldr w14, [sp, #8] // linesizeV ldr x8, [sp, #16] // table @@ -70,7 +95,12 @@ ld1 {v1.1d}, [x8] dup v0.8h, w10 dup v3.8h, w9 +.ifc \ofmt,gbrp + load_dst1_dst2 40, 48, 56, 64 + sub w3, w3, w0 // w3 = linesize - width (padding) +.else sub w3, w3, w0, lsl #2 // w3 = linesize - width * 4 (padding) +.endif sub w5, w5, w0 // w5 = linesizeY - width (paddingY) sub w7, w7, w0, lsr #1 // w7 = linesizeU - width / 2 (paddingU) sub w14, w14, w0, lsr #1 // w14 = linesizeV - width / 2 (paddingV) @@ -100,9 +130,9 @@ .endm .macro increment_nv12 - ands w15, w1, #1 - csel w16, w7, w11, ne // incC = (h & 1) ? paddincC : -width - add x6, x6, w16, sxtw // srcC += incC + ands w17, w1, #1 + csel w17, w7, w11, ne // incC = (h & 1) ? paddincC : -width + add x6, x6, w17, sxtw // srcC += incC .endm .macro increment_nv21 @@ -110,10 +140,10 @@ .endm .macro increment_yuv420p - ands w15, w1, #1 - csel w16, w7, w11, ne // incU = (h & 1) ? paddincU : -width/2 + ands w17, w1, #1 + csel w17, w7, w11, ne // incU = (h & 1) ? paddincU : -width/2 + add x6, x6, w17, sxtw // srcU += incU csel w17, w14, w11, ne // incV = (h & 1) ? paddincV : -width/2 - add x6, x6, w16, sxtw // srcU += incU add x13, x13, w17, sxtw // srcV += incV .endm @@ -122,7 +152,7 @@ add x13, x13, w14, sxtw // srcV += incV .endm -.macro compute_rgba r1 g1 b1 a1 r2 g2 b2 a2 +.macro compute_rgb r1 g1 b1 r2 g2 b2 add v20.8h, v26.8h, v20.8h // Y1 + R1 add v21.8h, v27.8h, v21.8h // Y2 + R2 add v22.8h, v26.8h, v22.8h // Y1 + G1 @@ -135,13 +165,18 @@ sqrshrun \g2, v23.8h, #1 // clip_u8((Y2 + G1) >> 1) sqrshrun \b1, v24.8h, #1 // clip_u8((Y1 + B1) >> 1) sqrshrun \b2, v25.8h, #1 // clip_u8((Y2 + B1) >> 1) +.endm + +.macro compute_rgba r1 g1 b1 a1 r2 g2 b2 a2 + compute_rgb \r1, \g1, \b1, \r2, \g2, \b2 movi \a1, #255 movi \a2, #255 .endm .macro declare_func ifmt ofmt function ff_\ifmt\()_to_\ofmt\()_neon, export=1 - load_args_\ifmt + load_args_\ifmt \ofmt + mov w9, w1 1: mov w8, w0 // w8 = width @@ -185,11 +220,22 @@ function ff_\ifmt\()_to_\ofmt\()_neon, export=1 compute_rgba v6.8b,v5.8b,v4.8b,v7.8b, v18.8b,v17.8b,v16.8b,v19.8b .endif +.ifc \ofmt,gbrp + compute_rgb v18.8b,v4.8b,v6.8b, v19.8b,v5.8b,v7.8b + st1 { v4.8b, v5.8b }, [x2], #16 + st1 { v6.8b, v7.8b }, [x10], #16 + st1 { v18.8b, v19.8b }, [x15], #16 +.else st4 { v4.8b, v5.8b, v6.8b, v7.8b}, [x2], #32 st4 {v16.8b,v17.8b,v18.8b,v19.8b}, [x2], #32 +.endif subs w8, w8, #16 // width -= 16 b.gt 2b add x2, x2, w3, sxtw // dst += padding +.ifc \ofmt,gbrp + add x10, x10, w12, sxtw // dst1 += padding1 + add x15, x15, w16, sxtw // dst2 += padding2 +.endif add x4, x4, w5, sxtw // srcY += paddingY increment_\ifmt subs w1, w1, #1 // height -= 1 @@ -204,6 +250,7 @@ endfunc declare_func \ifmt, rgba declare_func \ifmt, abgr declare_func \ifmt, bgra + declare_func \ifmt, gbrp .endm declare_rgb_funcs nv12 diff --git a/libswscale/arm/hscale.S b/libswscale/arm/hscale.S index dd4d45395..5c3551a0f 100644 --- a/libswscale/arm/hscale.S +++ b/libswscale/arm/hscale.S @@ -65,6 +65,5 @@ function ff_hscale_8_to_15_neon, export=1 subs r2, #2 @ dstW -= 2 bgt 1b @ loop until end of line vpop {q4-q7} - pop {r4-r12, lr} - mov pc, lr + pop {r4-r12, pc} endfunc diff --git a/libswscale/arm/output.S b/libswscale/arm/output.S index 70846dee1..5f10585f8 100644 --- a/libswscale/arm/output.S +++ b/libswscale/arm/output.S @@ -73,6 +73,5 @@ function ff_yuv2planeX_8_neon, export=1 subs r4, r4, #8 @ dstW -= 8 bgt 2b @ loop until width is consumed vpop {q4-q7} - pop {r4-r12, lr} - mov pc, lr + pop {r4-r12, pc} endfunc diff --git a/libswscale/arm/yuv2rgb_neon.S b/libswscale/arm/yuv2rgb_neon.S index 10950e70b..6777d625f 100644 --- a/libswscale/arm/yuv2rgb_neon.S +++ b/libswscale/arm/yuv2rgb_neon.S @@ -75,8 +75,8 @@ vzip.8 d7, d11 @ d7 = G1G2G3G4G5G6G7G8 d11 = G9G10G11G12G13G14G15G16 vzip.8 d8, d12 @ d8 = B1B2B3B4B5B6B7B8 d12 = B9B10B11B12B13B14B15B16 vzip.8 d9, d13 @ d9 = A1A2A3A4A5A6A7A8 d13 = A9A10A11A12A13A14A15A16 - vst4.8 {q3, q4}, [\dst,:128]! - vst4.8 {q5, q6}, [\dst,:128]! + vst4.8 {q3, q4}, [\dst]! + vst4.8 {q5, q6}, [\dst]! .endm .macro process_1l_internal dst src ofmt @@ -262,8 +262,7 @@ function ff_\ifmt\()_to_\ofmt\()_neon, export=1 increment_and_test_\ifmt bgt 1b vpop {q4-q7} - pop {r4-r12, lr} - mov pc, lr + pop {r4-r12, pc} endfunc .endm diff --git a/libswscale/gamma.c b/libswscale/gamma.c index d7470cb1c..7c5534e1b 100644 --- a/libswscale/gamma.c +++ b/libswscale/gamma.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "swscale_internal.h" typedef struct GammaContext diff --git a/libswscale/hscale.c b/libswscale/hscale.c index 6789ce754..5a949732b 100644 --- a/libswscale/hscale.c +++ b/libswscale/hscale.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "swscale_internal.h" /// Scaler instance data diff --git a/libswscale/loongarch/Makefile b/libswscale/loongarch/Makefile index c35ba309a..7ba11d492 100644 --- a/libswscale/loongarch/Makefile +++ b/libswscale/loongarch/Makefile @@ -9,4 +9,5 @@ LSX-OBJS-$(CONFIG_SWSCALE) += loongarch/swscale.o \ loongarch/input.o \ loongarch/output.o \ loongarch/output_lsx.o \ + loongarch/input_lsx.o \ loongarch/yuv2rgb_lsx.o diff --git a/libswscale/loongarch/input.S b/libswscale/loongarch/input.S index d01f7384b..717592b00 100644 --- a/libswscale/loongarch/input.S +++ b/libswscale/loongarch/input.S @@ -283,3 +283,498 @@ function planar_rgb_to_uv_lsx ld.d s3, sp, 16 addi.d sp, sp, 24 endfunc + +/* + * void yuy2ToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + * const uint8_t *src2, int width, uint32_t *unused, void *opq) + */ +function yuy2ToUV_lsx + andi t0, a5, 7 + srli.d a5, a5, 3 + beqz a5, 2f +1: + vld vr0, a3, 1 + vld vr1, a3, 17 + addi.d a5, a5, -1 + addi.d a3, a3, 32 + vpickev.b vr2, vr1, vr0 + vpickev.b vr0, vr2, vr2 + vpickod.b vr1, vr2, vr2 + fst.d f0, a0, 0 + fst.d f1, a1, 0 + addi.d a0, a0, 8 + addi.d a1, a1, 8 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 1 + ld.b t2, a3, 3 + addi.d a3, a3, 4 + addi.d t0, t0, -1 + st.b t1, a0, 0 + st.b t2, a1, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +function yuy2ToUV_lasx + andi t0, a5, 15 + srli.d a5, a5, 4 + beqz a5, 2f +1: + xvld xr0, a3, 1 + xvld xr1, a3, 33 + addi.d a5, a5, -1 + addi.d a3, a3, 64 + xvpickev.b xr2, xr1, xr0 + xvpermi.d xr2, xr2, 0xd8 + xvpickev.b xr0, xr2, xr2 + xvpermi.d xr0, xr0, 0xd8 + xvpickod.b xr1, xr2, xr2 + xvpermi.d xr1, xr1, 0xd8 + vst vr0, a0, 0 + vst vr1, a1, 0 + addi.d a0, a0, 16 + addi.d a1, a1, 16 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 1 + ld.b t2, a3, 3 + addi.d a3, a3, 4 + addi.d t0, t0, -1 + st.b t1, a0, 0 + st.b t2, a1, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +/* + * void yvy2ToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + * const uint8_t *src2, int width, uint32_t *unused, void *opq) + */ +function yvy2ToUV_lsx + andi t0, a5, 7 + srli.d a5, a5, 3 + beqz a5, 2f +1: + vld vr0, a3, 1 + vld vr1, a3, 17 + addi.d a5, a5, -1 + addi.d a3, a3, 32 + vpickev.b vr2, vr1, vr0 + vpickev.b vr0, vr2, vr2 + vpickod.b vr1, vr2, vr2 + fst.d f0, a1, 0 + fst.d f1, a0, 0 + addi.d a0, a0, 8 + addi.d a1, a1, 8 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 1 + ld.b t2, a3, 3 + addi.d a3, a3, 4 + addi.d t0, t0, -1 + st.b t1, a1, 0 + st.b t2, a0, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +function yvy2ToUV_lasx + andi t0, a5, 15 + srli.d a5, a5, 4 + beqz a5, 2f +1: + xvld xr0, a3, 1 + xvld xr1, a3, 33 + addi.d a5, a5, -1 + addi.d a3, a3, 64 + xvpickev.b xr2, xr1, xr0 + xvpermi.d xr2, xr2, 0xd8 + xvpickev.b xr0, xr2, xr2 + xvpermi.d xr0, xr0, 0xd8 + xvpickod.b xr1, xr2, xr2 + xvpermi.d xr1, xr1, 0xd8 + vst vr0, a1, 0 + vst vr1, a0, 0 + addi.d a0, a0, 16 + addi.d a1, a1, 16 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 1 + ld.b t2, a3, 3 + addi.d a3, a3, 4 + addi.d t0, t0, -1 + st.b t1, a1, 0 + st.b t2, a0, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +/* + * void uyvyToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + * const uint8_t *src2, int width, uint32_t *unused, void *opq) + */ +function uyvyToUV_lsx + andi t0, a5, 7 + srli.d a5, a5, 3 + beqz a5, 2f +1: + vld vr0, a3, 0 + vld vr1, a3, 16 + addi.d a5, a5, -1 + addi.d a3, a3, 32 + vpickev.b vr2, vr1, vr0 + vpickev.b vr0, vr2, vr2 + vpickod.b vr1, vr2, vr2 + fst.d f0, a0, 0 + fst.d f1, a1, 0 + addi.d a0, a0, 8 + addi.d a1, a1, 8 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 1 + ld.b t2, a3, 3 + addi.d a3, a3, 4 + addi.d t0, t0, -1 + st.b t1, a0, 0 + st.b t2, a1, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +function uyvyToUV_lasx + andi t0, a5, 15 + srli.d a5, a5, 4 + beqz a5, 2f +1: + xvld xr0, a3, 0 + xvld xr1, a3, 32 + addi.d a5, a5, -1 + addi.d a3, a3, 64 + xvpickev.b xr2, xr1, xr0 + xvpermi.d xr2, xr2, 0xd8 + xvpickev.b xr0, xr2, xr2 + xvpermi.d xr0, xr0, 0xd8 + xvpickod.b xr1, xr2, xr2 + xvpermi.d xr1, xr1, 0xd8 + vst vr0, a0, 0 + vst vr1, a1, 0 + addi.d a0, a0, 16 + addi.d a1, a1, 16 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 1 + ld.b t2, a3, 3 + addi.d a3, a3, 4 + addi.d t0, t0, -1 + st.b t1, a0, 0 + st.b t2, a1, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +/* + * void nv12ToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + * const uint8_t *src2, int width, uint32_t *unused, void *opq) + */ +function nv12ToUV_lsx + andi t0, a5, 15 + srli.d a5, a5, 4 + beqz a5, 2f +1: + vld vr0, a3, 0 + vld vr1, a3, 16 + addi.d a5, a5, -1 + addi.d a3, a3, 32 + vpickev.b vr2, vr1, vr0 + vpickod.b vr3, vr1, vr0 + vst vr2, a0, 0 + vst vr3, a1, 0 + addi.d a0, a0, 16 + addi.d a1, a1, 16 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 0 + ld.b t2, a3, 1 + addi.d a3, a3, 2 + addi.d t0, t0, -1 + st.b t1, a0, 0 + st.b t2, a1, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +function nv12ToUV_lasx + andi t0, a5, 31 + srli.d a5, a5, 5 + beqz a5, 2f +1: + xvld xr0, a3, 0 + xvld xr1, a3, 32 + addi.d a5, a5, -1 + addi.d a3, a3, 64 + xvpickev.b xr2, xr1, xr0 + xvpickod.b xr3, xr1, xr0 + xvpermi.d xr2, xr2, 0xd8 + xvpermi.d xr3, xr3, 0xd8 + xvst xr2, a0, 0 + xvst xr3, a1, 0 + addi.d a0, a0, 32 + addi.d a1, a1, 32 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 0 + ld.b t2, a3, 1 + addi.d a3, a3, 2 + addi.d t0, t0, -1 + st.b t1, a0, 0 + st.b t2, a1, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +/* + * void nv21ToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + * const uint8_t *src2, int width, uint32_t *unused, void *opq) + */ +function nv21ToUV_lsx + andi t0, a5, 15 + srli.d a5, a5, 4 + beqz a5, 2f +1: + vld vr0, a3, 0 + vld vr1, a3, 16 + addi.d a5, a5, -1 + addi.d a3, a3, 32 + vpickev.b vr2, vr1, vr0 + vpickod.b vr3, vr1, vr0 + vst vr2, a1, 0 + vst vr3, a0, 0 + addi.d a0, a0, 16 + addi.d a1, a1, 16 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 0 + ld.b t2, a3, 1 + addi.d a3, a3, 2 + addi.d t0, t0, -1 + st.b t1, a1, 0 + st.b t2, a0, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +function nv21ToUV_lasx + andi t0, a5, 31 + srli.d a5, a5, 5 + beqz a5, 2f +1: + xvld xr0, a3, 0 + xvld xr1, a3, 32 + addi.d a5, a5, -1 + addi.d a3, a3, 64 + xvpickev.b xr2, xr1, xr0 + xvpickod.b xr3, xr1, xr0 + xvpermi.d xr2, xr2, 0xd8 + xvpermi.d xr3, xr3, 0xd8 + xvst xr2, a1, 0 + xvst xr3, a0, 0 + addi.d a0, a0, 32 + addi.d a1, a1, 32 + bnez a5, 1b +2: + beqz t0, 4f +3: + ld.b t1, a3, 0 + ld.b t2, a3, 1 + addi.d a3, a3, 2 + addi.d t0, t0, -1 + st.b t1, a1, 0 + st.b t2, a0, 0 + addi.d a0, a0, 1 + addi.d a1, a1, 1 + bnez t0, 3b +4: +endfunc + +/* + *void abgrToA_lsx(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + * const uint8_t *unused2, int width, uint32_t *unused, void *opq) + */ +function abgrToA_lsx + andi t0, a4, 7 + srli.d a4, a4, 3 + vxor.v vr0, vr0, vr0 + beqz a4, 2f +1: + vld vr1, a1, 0 + vld vr2, a1, 16 + addi.d a4, a4, -1 + addi.d a1, a1, 32 + vpickev.b vr3, vr2, vr1 + vpackev.b vr3, vr0, vr3 + vslli.h vr1, vr3, 6 + vsrli.h vr2, vr3, 2 + vor.v vr3, vr2, vr1 + vst vr3, a0, 0 + addi.d a0, a0, 16 + bnez a4, 1b +2: + beqz t0, 4f +3: + ld.b t1, a1, 3 + addi.d t0, t0, -1 + addi.d a1, a1, 4 + andi t1, t1, 0xff + slli.w t2, t1, 6 + srli.w t3, t1, 2 + or t1, t2, t3 + st.h t1, a0, 0 + addi.d a0, a0, 2 + bnez t0, 3b +4: +endfunc + +function abgrToA_lasx + andi t0, a4, 15 + srli.d a4, a4, 4 + xvxor.v xr0, xr0, xr0 + beqz a4, 2f +1: + xvld xr1, a1, 0 + xvld xr2, a1, 32 + addi.d a4, a4, -1 + addi.d a1, a1, 64 + xvpickev.b xr3, xr2, xr1 + xvpermi.d xr3, xr3, 0xd8 + xvpackev.b xr3, xr0, xr3 + xvslli.h xr1, xr3, 6 + xvsrli.h xr2, xr3, 2 + xvor.v xr3, xr2, xr1 + xvst xr3, a0, 0 + addi.d a0, a0, 32 + bnez a4, 1b +2: + beqz t0, 4f +3: + ld.b t1, a1, 3 + addi.d t0, t0, -1 + addi.d a1, a1, 4 + andi t1, t1, 0xff + slli.w t2, t1, 6 + srli.w t3, t1, 2 + or t1, t2, t3 + st.h t1, a0, 0 + addi.d a0, a0, 2 + bnez t0, 3b +4: +endfunc + +/* + *void rgbaToA_lsx(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + * const uint8_t *unused2, int width, uint32_t *unused, void *opq) + */ +function rgbaToA_lsx + andi t0, a4, 7 + srli.d a4, a4, 3 + vxor.v vr0, vr0, vr0 + beqz a4, 2f +1: + vld vr1, a1, 3 + vld vr2, a1, 19 + addi.d a4, a4, -1 + addi.d a1, a1, 32 + vpickev.b vr3, vr2, vr1 + vpackev.b vr3, vr0, vr3 + vslli.h vr1, vr3, 6 + vsrli.h vr2, vr3, 2 + vor.v vr3, vr2, vr1 + vst vr3, a0, 0 + addi.d a0, a0, 16 + bnez a4, 1b +2: + beqz t0, 4f +3: + ld.b t1, a1, 3 + addi.d t0, t0, -1 + addi.d a1, a1, 4 + andi t1, t1, 0xff + slli.w t2, t1, 6 + srli.w t3, t1, 2 + or t1, t2, t3 + st.h t1, a0, 0 + addi.d a0, a0, 2 + bnez t0, 3b +4: +endfunc + +function rgbaToA_lasx + andi t0, a4, 15 + srli.d a4, a4, 4 + xvxor.v xr0, xr0, xr0 + beqz a4, 2f +1: + xvld xr1, a1, 3 + xvld xr2, a1, 35 + addi.d a4, a4, -1 + addi.d a1, a1, 64 + xvpickev.b xr3, xr2, xr1 + xvpermi.d xr3, xr3, 0xd8 + xvpackev.b xr3, xr0, xr3 + xvslli.h xr1, xr3, 6 + xvsrli.h xr2, xr3, 2 + xvor.v xr3, xr2, xr1 + xvst xr3, a0, 0 + addi.d a0, a0, 32 + bnez a4, 1b +2: + beqz t0, 4f +3: + ld.b t1, a1, 3 + addi.d t0, t0, -1 + addi.d a1, a1, 4 + andi t1, t1, 0xff + slli.w t2, t1, 6 + srli.w t3, t1, 2 + or t1, t2, t3 + st.h t1, a0, 0 + addi.d a0, a0, 2 + bnez t0, 3b +4: +endfunc diff --git a/libswscale/loongarch/input_lasx.c b/libswscale/loongarch/input_lasx.c index 4830072ea..0f1d95488 100644 --- a/libswscale/loongarch/input_lasx.c +++ b/libswscale/loongarch/input_lasx.c @@ -200,3 +200,46 @@ void planar_rgb_to_y_lasx(uint8_t *_dst, const uint8_t *src[4], int width, dst[i] = (tem_ry * r + tem_gy * g + tem_by * b + set) >> shift; } } + +av_cold void ff_sws_init_input_lasx(SwsContext *c) +{ + enum AVPixelFormat srcFormat = c->srcFormat; + + switch (srcFormat) { + case AV_PIX_FMT_YUYV422: + c->chrToYV12 = yuy2ToUV_lasx; + break; + case AV_PIX_FMT_YVYU422: + c->chrToYV12 = yvy2ToUV_lasx; + break; + case AV_PIX_FMT_UYVY422: + c->chrToYV12 = uyvyToUV_lasx; + break; + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_NV16: + case AV_PIX_FMT_NV24: + c->chrToYV12 = nv12ToUV_lasx; + break; + case AV_PIX_FMT_NV21: + case AV_PIX_FMT_NV42: + c->chrToYV12 = nv21ToUV_lasx; + break; + case AV_PIX_FMT_GBRAP: + case AV_PIX_FMT_GBRP: + c->readChrPlanar = planar_rgb_to_uv_lasx; + break; + } + + if (c->needAlpha) { + switch (srcFormat) { + case AV_PIX_FMT_BGRA: + case AV_PIX_FMT_RGBA: + c->alpToYV12 = rgbaToA_lasx; + break; + case AV_PIX_FMT_ABGR: + case AV_PIX_FMT_ARGB: + c->alpToYV12 = abgrToA_lasx; + break; + } + } +} diff --git a/libswscale/loongarch/input_lsx.c b/libswscale/loongarch/input_lsx.c new file mode 100644 index 000000000..1bb04457b --- /dev/null +++ b/libswscale/loongarch/input_lsx.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + * Contributed by Shiyou Yin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 "swscale_loongarch.h" + +av_cold void ff_sws_init_input_lsx(SwsContext *c) +{ + enum AVPixelFormat srcFormat = c->srcFormat; + + switch (srcFormat) { + case AV_PIX_FMT_YUYV422: + c->chrToYV12 = yuy2ToUV_lsx; + break; + case AV_PIX_FMT_YVYU422: + c->chrToYV12 = yvy2ToUV_lsx; + break; + case AV_PIX_FMT_UYVY422: + c->chrToYV12 = uyvyToUV_lsx; + break; + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_NV16: + case AV_PIX_FMT_NV24: + c->chrToYV12 = nv12ToUV_lsx; + break; + case AV_PIX_FMT_NV21: + case AV_PIX_FMT_NV42: + c->chrToYV12 = nv21ToUV_lsx; + break; + case AV_PIX_FMT_GBRAP: + case AV_PIX_FMT_GBRP: + c->readChrPlanar = planar_rgb_to_uv_lsx; + break; + } + + if (c->needAlpha) { + switch (srcFormat) { + case AV_PIX_FMT_BGRA: + case AV_PIX_FMT_RGBA: + c->alpToYV12 = rgbaToA_lsx; + break; + case AV_PIX_FMT_ABGR: + case AV_PIX_FMT_ARGB: + c->alpToYV12 = abgrToA_lsx; + break; + } + } +} diff --git a/libswscale/loongarch/output.S b/libswscale/loongarch/output.S index b44bac502..d71667e38 100644 --- a/libswscale/loongarch/output.S +++ b/libswscale/loongarch/output.S @@ -23,11 +23,11 @@ #include "libavcodec/loongarch/loongson_asm.S" -/* static void ff_yuv2planeX_8_lsx(const int16_t *filter, int filterSize, +/* static void yuv2planeX_8_lsx(const int16_t *filter, int filterSize, * const int16_t **src, uint8_t *dest, int dstW, * const uint8_t *dither, int offset) */ -function ff_yuv2planeX_8_lsx +function yuv2planeX_8_lsx addi.w t1, a6, 1 addi.w t2, a6, 2 addi.w t3, a6, 3 @@ -136,3 +136,253 @@ function ff_yuv2planeX_8_lsx blt zero, a4, .DEST .END: endfunc + +/* + * void yuv2plane1_8_lsx(const int16_t *src, uint8_t *dest, int dstW, + * const uint8_t *dither, int offset) + */ +function yuv2plane1_8_lsx + addi.w t1, a4, 1 + addi.w t2, a4, 2 + addi.w t3, a4, 3 + addi.w t4, a4, 4 + addi.w t5, a4, 5 + addi.w t6, a4, 6 + addi.w t7, a4, 7 + andi t0, a4, 7 + andi t1, t1, 7 + andi t2, t2, 7 + andi t3, t3, 7 + andi t4, t4, 7 + andi t5, t5, 7 + andi t6, t6, 7 + andi t7, t7, 7 + ldx.bu t0, a3, t0 + ldx.bu t1, a3, t1 + ldx.bu t2, a3, t2 + ldx.bu t3, a3, t3 + ldx.bu t4, a3, t4 + ldx.bu t5, a3, t5 + ldx.bu t6, a3, t6 + ldx.bu t7, a3, t7 + vinsgr2vr.h vr1, t0, 0 + vinsgr2vr.h vr1, t1, 1 + vinsgr2vr.h vr1, t2, 2 + vinsgr2vr.h vr1, t3, 3 + vinsgr2vr.h vr1, t4, 4 + vinsgr2vr.h vr1, t5, 5 + vinsgr2vr.h vr1, t6, 6 + vinsgr2vr.h vr1, t7, 7 + vsub.h vr0, vr0, vr0 + vilvl.h vr2, vr0, vr1 + vilvh.h vr3, vr0, vr1 + + andi t8, a2, 7 + srli.d a2, a2, 3 + beqz a2, 2f +1: + vld vr1, a0, 0 + addi.d a0, a0, 16 + vshuf4i.d vr0, vr1, 8 + vexth.w.h vr4, vr0 + vexth.w.h vr5, vr1 + + vadd.w vr4, vr2, vr4 + vadd.w vr5, vr3, vr5 + vsrai.w vr4, vr4, 7 + vsrai.w vr5, vr5, 7 + vclip255.w vr4, vr4 + vclip255.w vr5, vr5 + vpickev.h vr1, vr5, vr4 + vpickev.b vr1, vr1, vr1 + fst.d f1, a1, 0 + addi.d a1, a1, 8 + addi.d a2, a2, -1 + bnez a2, 1b +2: + beqz t8, 4f +3: + add.w a4, a4, t8 + addi.w t1, a4, 1 + addi.w t2, a4, 2 + addi.w t3, a4, 3 + addi.w t4, a4, 4 + addi.w t5, a4, 5 + addi.w t6, a4, 6 + addi.w t7, a4, 7 + andi t0, a4, 7 + andi t1, t1, 7 + andi t2, t2, 7 + andi t3, t3, 7 + andi t4, t4, 7 + andi t5, t5, 7 + andi t6, t6, 7 + andi t7, t7, 7 + ldx.bu t0, a3, t0 + ldx.bu t1, a3, t1 + ldx.bu t2, a3, t2 + ldx.bu t3, a3, t3 + ldx.bu t4, a3, t4 + ldx.bu t5, a3, t5 + ldx.bu t6, a3, t6 + ldx.bu t7, a3, t7 + vinsgr2vr.h vr1, t0, 0 + vinsgr2vr.h vr1, t1, 1 + vinsgr2vr.h vr1, t2, 2 + vinsgr2vr.h vr1, t3, 3 + vinsgr2vr.h vr1, t4, 4 + vinsgr2vr.h vr1, t5, 5 + vinsgr2vr.h vr1, t6, 6 + vinsgr2vr.h vr1, t7, 7 + vsub.h vr0, vr0, vr0 + vilvl.h vr2, vr0, vr1 + vilvh.h vr3, vr0, vr1 + + addi.d a0, a0, -16 + add.d a0, a0, t8 + add.d a0, a0, t8 + addi.d a1, a1, -8 + add.d a1, a1, t8 + + vld vr1, a0, 0 + vshuf4i.d vr0, vr1, 8 + vexth.w.h vr4, vr0 + vexth.w.h vr5, vr1 + + vadd.w vr4, vr2, vr4 + vadd.w vr5, vr3, vr5 + vsrai.w vr4, vr4, 7 + vsrai.w vr5, vr5, 7 + vclip255.w vr4, vr4 + vclip255.w vr5, vr5 + vpickev.h vr1, vr5, vr4 + vpickev.b vr1, vr1, vr1 + fst.d f1, a1, 0 +4: +endfunc + +function yuv2plane1_8_lasx + addi.w t1, a4, 1 + addi.w t2, a4, 2 + addi.w t3, a4, 3 + addi.w t4, a4, 4 + addi.w t5, a4, 5 + addi.w t6, a4, 6 + addi.w t7, a4, 7 + andi t0, a4, 7 + andi t1, t1, 7 + andi t2, t2, 7 + andi t3, t3, 7 + andi t4, t4, 7 + andi t5, t5, 7 + andi t6, t6, 7 + andi t7, t7, 7 + ldx.bu t0, a3, t0 + ldx.bu t1, a3, t1 + ldx.bu t2, a3, t2 + ldx.bu t3, a3, t3 + ldx.bu t4, a3, t4 + ldx.bu t5, a3, t5 + ldx.bu t6, a3, t6 + ldx.bu t7, a3, t7 + vinsgr2vr.h vr1, t0, 0 + vinsgr2vr.h vr1, t1, 1 + vinsgr2vr.h vr1, t2, 2 + vinsgr2vr.h vr1, t3, 3 + vinsgr2vr.h vr1, t4, 4 + vinsgr2vr.h vr1, t5, 5 + vinsgr2vr.h vr1, t6, 6 + vinsgr2vr.h vr1, t7, 7 + xvpermi.q xr1, xr1, 0 + xvsub.h xr0, xr0, xr0 + xvilvl.h xr2, xr0, xr1 + xvilvh.h xr3, xr0, xr1 + + andi t8, a2, 15 + srli.d a2, a2, 4 + beqz a2, 2f +1: + xvld xr1, a0, 0 + addi.d a0, a0, 32 + xvpermi.d xr0, xr1, 0xa0 + xvexth.w.h xr4, xr0 + xvexth.w.h xr5, xr1 + + xvadd.w xr4, xr2, xr4 + xvadd.w xr5, xr3, xr5 + xvsrai.w xr4, xr4, 7 + xvsrai.w xr5, xr5, 7 + xvclip255.w xr4, xr4 + xvclip255.w xr5, xr5 + xvpickev.h xr1, xr5, xr4 + xvpickev.b xr0, xr1, xr1 + xvpermi.q xr1, xr0, 1 + fst.d f0, a1, 0 + fst.d f1, a1, 8 + addi.d a1, a1, 16 + addi.d a2, a2, -1 + bnez a2, 1b +2: + beqz t8, 4f +3: + add.w a4, a4, t8 + addi.w t1, a4, 1 + addi.w t2, a4, 2 + addi.w t3, a4, 3 + addi.w t4, a4, 4 + addi.w t5, a4, 5 + addi.w t6, a4, 6 + addi.w t7, a4, 7 + andi t0, a4, 7 + andi t1, t1, 7 + andi t2, t2, 7 + andi t3, t3, 7 + andi t4, t4, 7 + andi t5, t5, 7 + andi t6, t6, 7 + andi t7, t7, 7 + ldx.bu t0, a3, t0 + ldx.bu t1, a3, t1 + ldx.bu t2, a3, t2 + ldx.bu t3, a3, t3 + ldx.bu t4, a3, t4 + ldx.bu t5, a3, t5 + ldx.bu t6, a3, t6 + ldx.bu t7, a3, t7 + vinsgr2vr.h vr1, t0, 0 + vinsgr2vr.h vr1, t1, 1 + vinsgr2vr.h vr1, t2, 2 + vinsgr2vr.h vr1, t3, 3 + vinsgr2vr.h vr1, t4, 4 + vinsgr2vr.h vr1, t5, 5 + vinsgr2vr.h vr1, t6, 6 + vinsgr2vr.h vr1, t7, 7 + xvpermi.q xr1, xr1, 0 + xvsub.h xr0, xr0, xr0 + xvilvl.h xr2, xr0, xr1 + xvilvh.h xr3, xr0, xr1 + + addi.d a0, a0, -32 + add.d a0, a0, t8 + add.d a0, a0, t8 + addi.d a1, a1, -16 + add.d a1, a1, t8 + + xvld xr1, a0, 0 + xvpermi.d xr0, xr1, 0xa0 + xvexth.w.h xr4, xr0 + xvexth.w.h xr5, xr1 + + xvadd.w xr4, xr2, xr4 + xvadd.w xr5, xr3, xr5 + xvsrai.w xr4, xr4, 7 + xvsrai.w xr5, xr5, 7 + xvclip255.w xr4, xr4 + xvclip255.w xr5, xr5 + xvpickev.h xr1, xr5, xr4 + xvpickev.b xr0, xr1, xr1 + xvpermi.q xr1, xr0, 1 + fst.d f0, a1, 0 + fst.d f1, a1, 8 +4: +endfunc diff --git a/libswscale/loongarch/output_lasx.c b/libswscale/loongarch/output_lasx.c index 277d7063e..bc8ab8cf3 100644 --- a/libswscale/loongarch/output_lasx.c +++ b/libswscale/loongarch/output_lasx.c @@ -22,7 +22,7 @@ #include "swscale_loongarch.h" #include "libavutil/loongarch/loongson_intrinsics.h" -void ff_yuv2planeX_8_lasx(const int16_t *filter, int filterSize, +void yuv2planeX_8_lasx(const int16_t *filter, int filterSize, const int16_t **src, uint8_t *dest, int dstW, const uint8_t *dither, int offset) { @@ -1775,8 +1775,27 @@ YUV2RGBWRAPPER(yuv2, rgb_full, bgr8_full, AV_PIX_FMT_BGR8, 0) YUV2RGBWRAPPER(yuv2, rgb_full, rgb8_full, AV_PIX_FMT_RGB8, 0) -av_cold void ff_sws_init_output_lasx(SwsContext *c) +av_cold void ff_sws_init_output_lasx(SwsContext *c, + yuv2planar1_fn *yuv2plane1, + yuv2planarX_fn *yuv2planeX, + yuv2interleavedX_fn *yuv2nv12cX, + yuv2packed1_fn *yuv2packed1, + yuv2packed2_fn *yuv2packed2, + yuv2packedX_fn *yuv2packedX, + yuv2anyX_fn *yuv2anyX) { + enum AVPixelFormat dstFormat = c->dstFormat; + + /* Add initialization once optimized */ + if (isSemiPlanarYUV(dstFormat) && isDataInHighBits(dstFormat)) { + } else if (is16BPS(dstFormat)) { + } else if (isNBPS(dstFormat)) { + } else if (dstFormat == AV_PIX_FMT_GRAYF32BE) { + } else if (dstFormat == AV_PIX_FMT_GRAYF32LE) { + } else { + *yuv2plane1 = yuv2plane1_8_lasx; + *yuv2planeX = yuv2planeX_8_lasx; + } if(c->flags & SWS_FULL_CHR_H_INT) { switch (c->dstFormat) { diff --git a/libswscale/loongarch/output_lsx.c b/libswscale/loongarch/output_lsx.c index 768cc3abc..de9b1534e 100644 --- a/libswscale/loongarch/output_lsx.c +++ b/libswscale/loongarch/output_lsx.c @@ -1624,8 +1624,28 @@ YUV2RGBWRAPPER(yuv2, rgb_full, bgr8_full, AV_PIX_FMT_BGR8, 0) YUV2RGBWRAPPER(yuv2, rgb_full, rgb8_full, AV_PIX_FMT_RGB8, 0) -av_cold void ff_sws_init_output_lsx(SwsContext *c) +av_cold void ff_sws_init_output_lsx(SwsContext *c, + yuv2planar1_fn *yuv2plane1, + yuv2planarX_fn *yuv2planeX, + yuv2interleavedX_fn *yuv2nv12cX, + yuv2packed1_fn *yuv2packed1, + yuv2packed2_fn *yuv2packed2, + yuv2packedX_fn *yuv2packedX, + yuv2anyX_fn *yuv2anyX) { + enum AVPixelFormat dstFormat = c->dstFormat; + + /* Add initialization once optimized */ + if (isSemiPlanarYUV(dstFormat) && isDataInHighBits(dstFormat)) { + } else if (is16BPS(dstFormat)) { + } else if (isNBPS(dstFormat)) { + } else if (dstFormat == AV_PIX_FMT_GRAYF32BE) { + } else if (dstFormat == AV_PIX_FMT_GRAYF32LE) { + } else { + *yuv2plane1 = yuv2plane1_8_lsx; + *yuv2planeX = yuv2planeX_8_lsx; + } + if(c->flags & SWS_FULL_CHR_H_INT) { switch (c->dstFormat) { case AV_PIX_FMT_RGBA: diff --git a/libswscale/loongarch/swscale.S b/libswscale/loongarch/swscale.S index aa4c5cbe2..67b1bc834 100644 --- a/libswscale/loongarch/swscale.S +++ b/libswscale/loongarch/swscale.S @@ -1866,3 +1866,371 @@ function ff_hscale_16_to_19_sub_lsx ld.d s8, sp, 64 addi.d sp, sp, 72 endfunc + +function lumRangeFromJpeg_lsx + li.w t0, 14071 + li.w t1, 33561947 + vreplgr2vr.h vr0, t0 + srli.w t2, a1, 3 + andi t3, a1, 7 + beqz t2, 2f +1: + vld vr1, a0, 0 + vreplgr2vr.w vr2, t1 + vreplgr2vr.w vr3, t1 + vmaddwev.w.h vr2, vr0, vr1 + vmaddwod.w.h vr3, vr0, vr1 + vsrai.w vr2, vr2, 14 + vsrai.w vr3, vr3, 14 + vpackev.h vr1, vr3, vr2 + vst vr1, a0, 0 + addi.d a0, a0, 16 + addi.d t2, t2, -1 + bnez t2, 1b +2: + beqz t3, 4f +3: + ld.h t4, a0, 0 + mul.w t4, t4, t0 + add.w t4, t4, t1 + srai.w t4, t4, 14 + st.h t4, a0, 0 + addi.d a0, a0, 2 + addi.d t3, t3, -1 + bnez t3, 3b +4: +endfunc + +function lumRangeFromJpeg_lasx + li.w t0, 14071 + li.w t1, 33561947 + xvreplgr2vr.h xr0, t0 + srli.w t2, a1, 4 + andi t3, a1, 15 + beqz t2, 2f +1: + xvld xr1, a0, 0 + xvreplgr2vr.w xr2, t1 + xvreplgr2vr.w xr3, t1 + xvmaddwev.w.h xr2, xr0, xr1 + xvmaddwod.w.h xr3, xr0, xr1 + xvsrai.w xr2, xr2, 14 + xvsrai.w xr3, xr3, 14 + xvpackev.h xr1, xr3, xr2 + xvst xr1, a0, 0 + addi.d a0, a0, 32 + addi.d t2, t2, -1 + bnez t2, 1b +2: + beqz t3, 4f +3: + ld.h t4, a0, 0 + mul.w t4, t4, t0 + add.w t4, t4, t1 + srai.w t4, t4, 14 + st.h t4, a0, 0 + addi.d a0, a0, 2 + addi.d t3, t3, -1 + bnez t3, 3b +4: +endfunc + +function lumRangeToJpeg_lsx + li.w t0, 19077 + li.w t1, -39057361 + li.w t2, 30189 + vreplgr2vr.h vr0, t0 + vreplgr2vr.h vr4, t2 + srli.w t2, a1, 3 + andi t3, a1, 7 + beqz t2, 2f +1: + vld vr1, a0, 0 + vreplgr2vr.w vr2, t1 + vreplgr2vr.w vr3, t1 + vmin.h vr1, vr1, vr4 + vmaddwev.w.h vr2, vr0, vr1 + vmaddwod.w.h vr3, vr0, vr1 + vsrai.w vr2, vr2, 14 + vsrai.w vr3, vr3, 14 + vpackev.h vr1, vr3, vr2 + vst vr1, a0, 0 + addi.d a0, a0, 16 + addi.d t2, t2, -1 + bnez t2, 1b +2: + beqz t3, 4f +3: + ld.h t4, a0, 0 + vreplgr2vr.h vr1, t4 + vmin.h vr1, vr1, vr4 + vpickve2gr.h t4, vr1, 0 + mul.w t4, t4, t0 + add.w t4, t4, t1 + srai.w t4, t4, 14 + st.h t4, a0, 0 + addi.d a0, a0, 2 + addi.d t3, t3, -1 + bnez t3, 3b +4: +endfunc + +function lumRangeToJpeg_lasx + li.w t0, 19077 + li.w t1, -39057361 + li.w t2, 30189 + xvreplgr2vr.h xr0, t0 + xvreplgr2vr.h xr4, t2 + srli.w t2, a1, 4 + andi t3, a1, 15 + beqz t2, 2f +1: + xvld xr1, a0, 0 + xvreplgr2vr.w xr2, t1 + xvreplgr2vr.w xr3, t1 + xvmin.h xr1, xr1, xr4 + xvmaddwev.w.h xr2, xr0, xr1 + xvmaddwod.w.h xr3, xr0, xr1 + xvsrai.w xr2, xr2, 14 + xvsrai.w xr3, xr3, 14 + xvpackev.h xr1, xr3, xr2 + xvst xr1, a0, 0 + addi.d a0, a0, 32 + addi.d t2, t2, -1 + bnez t2, 1b +2: + beqz t3, 4f +3: + ld.h t4, a0, 0 + vreplgr2vr.h vr1, t4 + vmin.h vr1, vr1, vr4 + vpickve2gr.h t4, vr1, 0 + mul.w t4, t4, t0 + add.w t4, t4, t1 + srai.w t4, t4, 14 + st.h t4, a0, 0 + addi.d a0, a0, 2 + addi.d t3, t3, -1 + bnez t3, 3b +4: +endfunc + +function chrRangeFromJpeg_lsx + li.w t0, 1799 + li.w t1, 4081085 + vreplgr2vr.h vr0, t0 + srli.w t2, a2, 3 + andi t3, a2, 7 + beqz t2, 2f +1: + vld vr1, a0, 0 + vld vr2, a1, 0 + vreplgr2vr.w vr3, t1 + vreplgr2vr.w vr4, t1 + vreplgr2vr.w vr5, t1 + vreplgr2vr.w vr6, t1 + vmaddwev.w.h vr3, vr0, vr1 + vmaddwod.w.h vr4, vr0, vr1 + vmaddwev.w.h vr5, vr0, vr2 + vmaddwod.w.h vr6, vr0, vr2 + vsrai.w vr3, vr3, 11 + vsrai.w vr4, vr4, 11 + vsrai.w vr5, vr5, 11 + vsrai.w vr6, vr6, 11 + vpackev.h vr1, vr4, vr3 + vpackev.h vr2, vr6, vr5 + vst vr1, a0, 0 + vst vr2, a1, 0 + addi.d a0, a0, 16 + addi.d a1, a1, 16 + addi.d t2, t2, -1 + bnez t2, 1b +2: + beqz t3, 4f +3: + ld.h t4, a0, 0 + ld.h t5, a1, 0 + mul.w t4, t4, t0 + mul.w t5, t5, t0 + add.w t4, t4, t1 + add.w t5, t5, t1 + srai.w t4, t4, 11 + srai.w t5, t5, 11 + st.h t4, a0, 0 + st.h t5, a1, 0 + addi.d a0, a0, 2 + addi.d a1, a1, 2 + addi.d t3, t3, -1 + bnez t3, 3b +4: +endfunc + +function chrRangeFromJpeg_lasx + li.w t0, 1799 + li.w t1, 4081085 + xvreplgr2vr.h xr0, t0 + srli.w t2, a2, 4 + andi t3, a2, 15 + beqz t2, 2f +1: + xvld xr1, a0, 0 + xvld xr2, a1, 0 + xvreplgr2vr.w xr3, t1 + xvreplgr2vr.w xr4, t1 + xvreplgr2vr.w xr5, t1 + xvreplgr2vr.w xr6, t1 + xvmaddwev.w.h xr3, xr0, xr1 + xvmaddwod.w.h xr4, xr0, xr1 + xvmaddwev.w.h xr5, xr0, xr2 + xvmaddwod.w.h xr6, xr0, xr2 + xvsrai.w xr3, xr3, 11 + xvsrai.w xr4, xr4, 11 + xvsrai.w xr5, xr5, 11 + xvsrai.w xr6, xr6, 11 + xvpackev.h xr1, xr4, xr3 + xvpackev.h xr2, xr6, xr5 + xvst xr1, a0, 0 + xvst xr2, a1, 0 + addi.d a0, a0, 32 + addi.d a1, a1, 32 + addi.d t2, t2, -1 + bnez t2, 1b +2: + beqz t3, 4f +3: + ld.h t4, a0, 0 + ld.h t5, a1, 0 + mul.w t4, t4, t0 + mul.w t5, t5, t0 + add.w t4, t4, t1 + add.w t5, t5, t1 + srai.w t4, t4, 11 + srai.w t5, t5, 11 + st.h t4, a0, 0 + st.h t5, a1, 0 + addi.d a0, a0, 2 + addi.d a1, a1, 2 + addi.d t3, t3, -1 + bnez t3, 3b +4: +endfunc + +function chrRangeToJpeg_lsx + li.w t0, 4663 + li.w t1, -9289992 + li.w t2, 30775 + vreplgr2vr.h vr0, t0 + vreplgr2vr.h vr7, t2 + srli.w t2, a2, 3 + andi t3, a2, 7 + beqz t2, 2f +1: + vld vr1, a0, 0 + vld vr2, a1, 0 + vreplgr2vr.w vr3, t1 + vreplgr2vr.w vr4, t1 + vreplgr2vr.w vr5, t1 + vreplgr2vr.w vr6, t1 + vmin.h vr1, vr1, vr7 + vmin.h vr2, vr2, vr7 + vmaddwev.w.h vr3, vr0, vr1 + vmaddwod.w.h vr4, vr0, vr1 + vmaddwev.w.h vr5, vr0, vr2 + vmaddwod.w.h vr6, vr0, vr2 + vsrai.w vr3, vr3, 12 + vsrai.w vr4, vr4, 12 + vsrai.w vr5, vr5, 12 + vsrai.w vr6, vr6, 12 + vpackev.h vr1, vr4, vr3 + vpackev.h vr2, vr6, vr5 + vst vr1, a0, 0 + vst vr2, a1, 0 + addi.d a0, a0, 16 + addi.d a1, a1, 16 + addi.d t2, t2, -1 + bnez t2, 1b +2: + beqz t3, 4f +3: + ld.h t4, a0, 0 + ld.h t5, a1, 0 + vreplgr2vr.h vr1, t4 + vreplgr2vr.h vr2, t5 + vmin.h vr1, vr1, vr7 + vmin.h vr2, vr2, vr7 + vpickve2gr.h t4, vr1, 0 + vpickve2gr.h t5, vr2, 0 + mul.w t4, t4, t0 + mul.w t5, t5, t0 + add.w t4, t4, t1 + add.w t5, t5, t1 + srai.w t4, t4, 12 + srai.w t5, t5, 12 + st.h t4, a0, 0 + st.h t5, a1, 0 + addi.d a0, a0, 2 + addi.d a1, a1, 2 + addi.d t3, t3, -1 + bnez t3, 3b +4: +endfunc + +function chrRangeToJpeg_lasx + li.w t0, 4663 + li.w t1, -9289992 + li.w t2, 30775 + xvreplgr2vr.h xr0, t0 + xvreplgr2vr.h xr7, t2 + srli.w t2, a2, 4 + andi t3, a2, 15 + beqz t2, 2f +1: + xvld xr1, a0, 0 + xvld xr2, a1, 0 + xvreplgr2vr.w xr3, t1 + xvreplgr2vr.w xr4, t1 + xvreplgr2vr.w xr5, t1 + xvreplgr2vr.w xr6, t1 + xvmin.h xr1, xr1, xr7 + xvmin.h xr2, xr2, xr7 + xvmaddwev.w.h xr3, xr0, xr1 + xvmaddwod.w.h xr4, xr0, xr1 + xvmaddwev.w.h xr5, xr0, xr2 + xvmaddwod.w.h xr6, xr0, xr2 + xvsrai.w xr3, xr3, 12 + xvsrai.w xr4, xr4, 12 + xvsrai.w xr5, xr5, 12 + xvsrai.w xr6, xr6, 12 + xvpackev.h xr1, xr4, xr3 + xvpackev.h xr2, xr6, xr5 + xvst xr1, a0, 0 + xvst xr2, a1, 0 + addi.d a0, a0, 32 + addi.d a1, a1, 32 + addi.d t2, t2, -1 + bnez t2, 1b +2: + beqz t3, 4f +3: + ld.h t4, a0, 0 + ld.h t5, a1, 0 + vreplgr2vr.h vr1, t4 + vreplgr2vr.h vr2, t5 + vmin.h vr1, vr1, vr7 + vmin.h vr2, vr2, vr7 + vpickve2gr.h t4, vr1, 0 + vpickve2gr.h t5, vr2, 0 + mul.w t4, t4, t0 + mul.w t5, t5, t0 + add.w t4, t4, t1 + add.w t5, t5, t1 + srai.w t4, t4, 12 + srai.w t5, t5, 12 + st.h t4, a0, 0 + st.h t5, a1, 0 + addi.d a0, a0, 2 + addi.d a1, a1, 2 + addi.d t3, t3, -1 + bnez t3, 3b +4: +endfunc diff --git a/libswscale/loongarch/swscale_init_loongarch.c b/libswscale/loongarch/swscale_init_loongarch.c index 51bfdd56d..2a95ede6d 100644 --- a/libswscale/loongarch/swscale_init_loongarch.c +++ b/libswscale/loongarch/swscale_init_loongarch.c @@ -24,11 +24,48 @@ #include "libswscale/rgb2rgb.h" #include "libavutil/loongarch/cpu.h" +av_cold void ff_sws_init_range_convert_loongarch(SwsContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_lsx(cpu_flags)) { + if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) { + if (c->dstBpc <= 14) { + if (c->srcRange) { + c->lumConvertRange = lumRangeFromJpeg_lsx; + c->chrConvertRange = chrRangeFromJpeg_lsx; + } else { + c->lumConvertRange = lumRangeToJpeg_lsx; + c->chrConvertRange = chrRangeToJpeg_lsx; + } + } + } + } +#if HAVE_LASX + if (have_lasx(cpu_flags)) { + if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) { + if (c->dstBpc <= 14) { + if (c->srcRange) { + c->lumConvertRange = lumRangeFromJpeg_lasx; + c->chrConvertRange = chrRangeFromJpeg_lasx; + } else { + c->lumConvertRange = lumRangeToJpeg_lasx; + c->chrConvertRange = chrRangeToJpeg_lasx; + } + } + } + } +#endif // #if HAVE_LASX +} + av_cold void ff_sws_init_swscale_loongarch(SwsContext *c) { int cpu_flags = av_get_cpu_flags(); if (have_lsx(cpu_flags)) { - ff_sws_init_output_lsx(c); + ff_sws_init_output_lsx(c, &c->yuv2plane1, &c->yuv2planeX, + &c->yuv2nv12cX, &c->yuv2packed1, + &c->yuv2packed2, &c->yuv2packedX, &c->yuv2anyX); + ff_sws_init_input_lsx(c); if (c->srcBpc == 8) { if (c->dstBpc <= 14) { c->hyScale = c->hcScale = ff_hscale_8_to_15_lsx; @@ -39,21 +76,13 @@ av_cold void ff_sws_init_swscale_loongarch(SwsContext *c) c->hyScale = c->hcScale = c->dstBpc > 14 ? ff_hscale_16_to_19_lsx : ff_hscale_16_to_15_lsx; } - switch (c->srcFormat) { - case AV_PIX_FMT_GBRAP: - case AV_PIX_FMT_GBRP: - { - c->readChrPlanar = planar_rgb_to_uv_lsx; - c->readLumPlanar = planar_rgb_to_y_lsx; - } - break; - } - if (c->dstBpc == 8) - c->yuv2planeX = ff_yuv2planeX_8_lsx; } #if HAVE_LASX if (have_lasx(cpu_flags)) { - ff_sws_init_output_lasx(c); + ff_sws_init_output_lasx(c, &c->yuv2plane1, &c->yuv2planeX, + &c->yuv2nv12cX, &c->yuv2packed1, + &c->yuv2packed2, &c->yuv2packedX, &c->yuv2anyX); + ff_sws_init_input_lasx(c); if (c->srcBpc == 8) { if (c->dstBpc <= 14) { c->hyScale = c->hcScale = ff_hscale_8_to_15_lasx; @@ -64,19 +93,9 @@ av_cold void ff_sws_init_swscale_loongarch(SwsContext *c) c->hyScale = c->hcScale = c->dstBpc > 14 ? ff_hscale_16_to_19_lasx : ff_hscale_16_to_15_lasx; } - switch (c->srcFormat) { - case AV_PIX_FMT_GBRAP: - case AV_PIX_FMT_GBRP: - { - c->readChrPlanar = planar_rgb_to_uv_lasx; - c->readLumPlanar = planar_rgb_to_y_lasx; - } - break; - } - if (c->dstBpc == 8) - c->yuv2planeX = ff_yuv2planeX_8_lasx; } #endif // #if HAVE_LASX + ff_sws_init_range_convert_loongarch(c); } av_cold void rgb2rgb_init_loongarch(void) diff --git a/libswscale/loongarch/swscale_loongarch.h b/libswscale/loongarch/swscale_loongarch.h index 0514abae2..07c91bc25 100644 --- a/libswscale/loongarch/swscale_loongarch.h +++ b/libswscale/loongarch/swscale_loongarch.h @@ -50,17 +50,55 @@ void ff_hscale_16_to_19_sub_lsx(SwsContext *c, int16_t *_dst, int dstW, const uint8_t *_src, const int16_t *filter, const int32_t *filterPos, int filterSize, int sh); +void lumRangeFromJpeg_lsx(int16_t *dst, int width); +void chrRangeFromJpeg_lsx(int16_t *dstU, int16_t *dstV, int width); +void lumRangeToJpeg_lsx(int16_t *dst, int width); +void chrRangeToJpeg_lsx(int16_t *dstU, int16_t *dstV, int width); + void planar_rgb_to_uv_lsx(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *src[4], int width, int32_t *rgb2yuv, void *opq); void planar_rgb_to_y_lsx(uint8_t *_dst, const uint8_t *src[4], int width, int32_t *rgb2yuv, void *opq); -void ff_yuv2planeX_8_lsx(const int16_t *filter, int filterSize, +void yuv2planeX_8_lsx(const int16_t *filter, int filterSize, const int16_t **src, uint8_t *dest, int dstW, const uint8_t *dither, int offset); -av_cold void ff_sws_init_output_lsx(SwsContext *c); +void yuv2plane1_8_lsx(const int16_t *src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset); + +void yuy2ToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void yvy2ToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void uyvyToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void nv12ToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void nv21ToUV_lsx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void abgrToA_lsx(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq); + +void rgbaToA_lsx(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq); + +av_cold void ff_sws_init_input_lsx(SwsContext *c); + +av_cold void ff_sws_init_output_lsx(SwsContext *c, + yuv2planar1_fn *yuv2plane1, + yuv2planarX_fn *yuv2planeX, + yuv2interleavedX_fn *yuv2nv12cX, + yuv2packed1_fn *yuv2packed1, + yuv2packed2_fn *yuv2packed2, + yuv2packedX_fn *yuv2packedX, + yuv2anyX_fn *yuv2anyX); int yuv420_rgb24_lsx(SwsContext *c, const uint8_t *src[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t *dst[], int dstStride[]); @@ -97,6 +135,11 @@ void ff_hscale_16_to_15_lasx(SwsContext *c, int16_t *dst, int dstW, const uint8_t *_src, const int16_t *filter, const int32_t *filterPos, int filterSize); +void lumRangeFromJpeg_lasx(int16_t *dst, int width); +void chrRangeFromJpeg_lasx(int16_t *dstU, int16_t *dstV, int width); +void lumRangeToJpeg_lasx(int16_t *dst, int width); +void chrRangeToJpeg_lasx(int16_t *dstU, int16_t *dstV, int width); + void planar_rgb_to_uv_lasx(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *src[4], int width, int32_t *rgb2yuv, void *opq); @@ -125,11 +168,44 @@ void ff_interleave_bytes_lasx(const uint8_t *src1, const uint8_t *src2, uint8_t *dest, int width, int height, int src1Stride, int src2Stride, int dstStride); -void ff_yuv2planeX_8_lasx(const int16_t *filter, int filterSize, +void yuv2planeX_8_lasx(const int16_t *filter, int filterSize, const int16_t **src, uint8_t *dest, int dstW, const uint8_t *dither, int offset); -av_cold void ff_sws_init_output_lasx(SwsContext *c); +void yuv2plane1_8_lasx(const int16_t *src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset); + +void yuy2ToUV_lasx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void yvy2ToUV_lasx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void uyvyToUV_lasx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void nv12ToUV_lasx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void nv21ToUV_lasx(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq); + +void abgrToA_lasx(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq); + +void rgbaToA_lasx(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq); + +av_cold void ff_sws_init_input_lasx(SwsContext *c); + +av_cold void ff_sws_init_output_lasx(SwsContext *c, + yuv2planar1_fn *yuv2plane1, + yuv2planarX_fn *yuv2planeX, + yuv2interleavedX_fn *yuv2nv12cX, + yuv2packed1_fn *yuv2packed1, + yuv2packed2_fn *yuv2packed2, + yuv2packedX_fn *yuv2packedX, + yuv2anyX_fn *yuv2anyX); #endif // #if HAVE_LASX #endif /* SWSCALE_LOONGARCH_SWSCALE_LOONGARCH_H */ diff --git a/libswscale/options.c b/libswscale/options.c index b36f13c87..53c4f0651 100644 --- a/libswscale/options.c +++ b/libswscale/options.c @@ -62,10 +62,10 @@ static const AVOption swscale_options[] = { { "param0", "scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, VE }, { "param1", "scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, VE }, - { "src_v_chr_pos", "source vertical chroma position in luma grid/256" , OFFSET(src_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 512, VE }, - { "src_h_chr_pos", "source horizontal chroma position in luma grid/256", OFFSET(src_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 512, VE }, - { "dst_v_chr_pos", "destination vertical chroma position in luma grid/256" , OFFSET(dst_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 512, VE }, - { "dst_h_chr_pos", "destination horizontal chroma position in luma grid/256", OFFSET(dst_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 512, VE }, + { "src_v_chr_pos", "source vertical chroma position in luma grid/256" , OFFSET(src_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 1024, VE }, + { "src_h_chr_pos", "source horizontal chroma position in luma grid/256", OFFSET(src_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 1024, VE }, + { "dst_v_chr_pos", "destination vertical chroma position in luma grid/256" , OFFSET(dst_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 1024, VE }, + { "dst_h_chr_pos", "destination horizontal chroma position in luma grid/256", OFFSET(dst_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 1024, VE }, { "sws_dither", "set dithering algorithm", OFFSET(dither), AV_OPT_TYPE_INT, { .i64 = SWS_DITHER_AUTO }, 0, NB_SWS_DITHER, VE, .unit = "sws_dither" }, { "auto", "leave choice to sws", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_AUTO }, INT_MIN, INT_MAX, VE, .unit = "sws_dither" }, diff --git a/libswscale/output.c b/libswscale/output.c index e8dd2145c..366883ab1 100644 --- a/libswscale/output.c +++ b/libswscale/output.c @@ -664,7 +664,7 @@ yuv2mono_2_c_template(SwsContext *c, const int16_t *buf[2], if (c->dither == SWS_DITHER_ED) { int err = 0; - int acc = 0; + unsigned acc = 0; for (i = 0; i < dstW; i +=2) { int Y; @@ -686,7 +686,8 @@ yuv2mono_2_c_template(SwsContext *c, const int16_t *buf[2], c->dither_error[0][i] = err; } else { for (i = 0; i < dstW; i += 8) { - int Y, acc = 0; + int Y; + unsigned acc = 0; Y = (buf0[i + 0] * yalpha1 + buf1[i + 0] * yalpha) >> 19; accumulate_bit(acc, Y + d128[0]); @@ -721,7 +722,7 @@ yuv2mono_1_c_template(SwsContext *c, const int16_t *buf0, if (c->dither == SWS_DITHER_ED) { int err = 0; - int acc = 0; + unsigned acc = 0; for (i = 0; i < dstW; i +=2) { int Y; @@ -743,7 +744,7 @@ yuv2mono_1_c_template(SwsContext *c, const int16_t *buf0, c->dither_error[0][i] = err; } else { for (i = 0; i < dstW; i += 8) { - int acc = 0; + unsigned acc = 0; accumulate_bit(acc, ((buf0[i + 0] + 64) >> 7) + d128[0]); accumulate_bit(acc, ((buf0[i + 1] + 64) >> 7) + d128[1]); accumulate_bit(acc, ((buf0[i + 2] + 64) >> 7) + d128[2]); @@ -1150,8 +1151,8 @@ yuv2rgba64_2_c_template(SwsContext *c, const int32_t *buf[2], av_assert2(uvalpha <= 4096U); for (i = 0; i < ((dstW + 1) >> 1); i++) { - int Y1 = (buf0[i * 2] * yalpha1 + buf1[i * 2] * yalpha) >> 14; - int Y2 = (buf0[i * 2 + 1] * yalpha1 + buf1[i * 2 + 1] * yalpha) >> 14; + unsigned Y1 = (buf0[i * 2] * yalpha1 + buf1[i * 2] * yalpha) >> 14; + unsigned Y2 = (buf0[i * 2 + 1] * yalpha1 + buf1[i * 2 + 1] * yalpha) >> 14; int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha - (128 << 23)) >> 14; int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha - (128 << 23)) >> 14; int R, G, B; @@ -1175,20 +1176,20 @@ yuv2rgba64_2_c_template(SwsContext *c, const int32_t *buf[2], A2 += 1 << 13; } - output_pixel(&dest[0], av_clip_uintp2(((R_B + Y1) >> 14) + (1<<15), 16)); - output_pixel(&dest[1], av_clip_uintp2((( G + Y1) >> 14) + (1<<15), 16)); - output_pixel(&dest[2], av_clip_uintp2(((B_R + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y1) >> 14) + (1<<15), 16)); if (eightbytes) { output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14); - output_pixel(&dest[4], av_clip_uintp2(((R_B + Y2) >> 14) + (1<<15), 16)); - output_pixel(&dest[5], av_clip_uintp2((( G + Y2) >> 14) + (1<<15), 16)); - output_pixel(&dest[6], av_clip_uintp2(((B_R + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[4], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[6], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); output_pixel(&dest[7], av_clip_uintp2(A2 , 30) >> 14); dest += 8; } else { - output_pixel(&dest[3], av_clip_uintp2(((R_B + Y2) >> 14) + (1<<15), 16)); - output_pixel(&dest[4], av_clip_uintp2((( G + Y2) >> 14) + (1<<15), 16)); - output_pixel(&dest[5], av_clip_uintp2(((B_R + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[3], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[4], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); dest += 6; } } @@ -1351,9 +1352,9 @@ yuv2rgba64_full_X_c_template(SwsContext *c, const int16_t *lumFilter, B = U * c->yuv2rgb_u2b_coeff; // 8bit: 30 - 22 = 8bit, 16bit: 30bit - 14 = 16bit - output_pixel(&dest[0], av_clip_uintp2(((R_B + Y)>>14) + (1<<15), 16)); - output_pixel(&dest[1], av_clip_uintp2((( G + Y)>>14) + (1<<15), 16)); - output_pixel(&dest[2], av_clip_uintp2(((B_R + Y)>>14) + (1<<15), 16)); + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + (unsigned)Y)>>14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + (unsigned)Y)>>14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + (unsigned)Y)>>14) + (1<<15), 16)); if (eightbytes) { output_pixel(&dest[3], av_clip_uintp2(A, 30) >> 14); dest += 4; @@ -2650,7 +2651,7 @@ yuv2xv36le_X_c(SwsContext *c, const int16_t *lumFilter, { int i; for (i = 0; i < dstW; i++) { - int Y = 1 << 14, U = 1 << 14, V = 1 << 14; + int Y = 1 << 14, U = 1 << 14, V = 1 << 14, A = 255; int j; for (j = 0; j < lumFilterSize; j++) @@ -2664,6 +2665,7 @@ yuv2xv36le_X_c(SwsContext *c, const int16_t *lumFilter, AV_WL16(dest + 8 * i + 2, av_clip_uintp2(Y >> 15, 12) << 4); AV_WL16(dest + 8 * i + 0, av_clip_uintp2(U >> 15, 12) << 4); AV_WL16(dest + 8 * i + 4, av_clip_uintp2(V >> 15, 12) << 4); + AV_WL16(dest + 8 * i + 6, A); } } @@ -2672,10 +2674,8 @@ yuv2vuyX_X_c(SwsContext *c, const int16_t *lumFilter, const int16_t **lumSrc, int lumFilterSize, const int16_t *chrFilter, const int16_t **chrUSrc, const int16_t **chrVSrc, int chrFilterSize, - const int16_t **alpSrc, uint8_t *dest, int dstW, int y, - int destHasAlpha) + const int16_t **alpSrc, uint8_t *dest, int dstW, int y) { - int hasAlpha = destHasAlpha && (!!alpSrc); int i; for (i = 0; i < dstW; i++) { @@ -2703,7 +2703,7 @@ yuv2vuyX_X_c(SwsContext *c, const int16_t *lumFilter, if (V & 0x100) V = av_clip_uint8(V); - if (hasAlpha) { + if (alpSrc) { A = 1 << 18; for (j = 0; j < lumFilterSize; j++) @@ -2718,33 +2718,10 @@ yuv2vuyX_X_c(SwsContext *c, const int16_t *lumFilter, dest[4 * i ] = V; dest[4 * i + 1] = U; dest[4 * i + 2] = Y; - if (destHasAlpha) - dest[4 * i + 3] = A; + dest[4 * i + 3] = A; } } -static void -yuv2vuya_X_c(SwsContext *c, const int16_t *lumFilter, - const int16_t **lumSrc, int lumFilterSize, - const int16_t *chrFilter, const int16_t **chrUSrc, - const int16_t **chrVSrc, int chrFilterSize, - const int16_t **alpSrc, uint8_t *dest, int dstW, int y) -{ - yuv2vuyX_X_c(c, lumFilter, lumSrc, lumFilterSize, chrFilter, - chrUSrc, chrVSrc, chrFilterSize, alpSrc, dest, dstW, y, 1); -} - -static void -yuv2vuyx_X_c(SwsContext *c, const int16_t *lumFilter, - const int16_t **lumSrc, int lumFilterSize, - const int16_t *chrFilter, const int16_t **chrUSrc, - const int16_t **chrVSrc, int chrFilterSize, - const int16_t **alpSrc, uint8_t *dest, int dstW, int y) -{ - yuv2vuyX_X_c(c, lumFilter, lumSrc, lumFilterSize, chrFilter, - chrUSrc, chrVSrc, chrFilterSize, alpSrc, dest, dstW, y, 0); -} - #define output_pixel(pos, val, bits) \ AV_WL16(pos, av_clip_uintp2(val >> shift, bits) << output_shift); @@ -3298,10 +3275,8 @@ av_cold void ff_sws_init_output_funcs(SwsContext *c, *yuv2packedX = yuv2ayuv64le_X_c; break; case AV_PIX_FMT_VUYA: - *yuv2packedX = yuv2vuya_X_c; - break; case AV_PIX_FMT_VUYX: - *yuv2packedX = yuv2vuyx_X_c; + *yuv2packedX = yuv2vuyX_X_c; break; case AV_PIX_FMT_XV30LE: *yuv2packedX = yuv2xv30le_X_c; diff --git a/libswscale/ppc/swscale_altivec.c b/libswscale/ppc/swscale_altivec.c index 1630355f5..9bf72738d 100644 --- a/libswscale/ppc/swscale_altivec.c +++ b/libswscale/ppc/swscale_altivec.c @@ -107,17 +107,14 @@ #endif /* HAVE_BIGENDIAN */ -#define output_pixel(pos, val, bias, signedness) \ - if (big_endian) { \ - AV_WB16(pos, bias + av_clip_ ## signedness ## 16(val >> shift)); \ - } else { \ - AV_WL16(pos, bias + av_clip_ ## signedness ## 16(val >> shift)); \ - } +#define SHIFT 3 + +#define get_pixel(val, bias, signedness) \ + (bias + av_clip_ ## signedness ## 16(val >> shift)) static void yuv2plane1_float_u(const int32_t *src, float *dest, int dstW, int start) { - static const int big_endian = HAVE_BIGENDIAN; static const int shift = 3; static const float float_mult = 1.0f / 65535.0f; int i, val; @@ -125,7 +122,7 @@ yuv2plane1_float_u(const int32_t *src, float *dest, int dstW, int start) for (i = start; i < dstW; ++i){ val = src[i] + (1 << (shift - 1)); - output_pixel(&val_uint, val, 0, uint); + val_uint = get_pixel(val, 0, uint); dest[i] = float_mult * (float)val_uint; } } @@ -133,7 +130,6 @@ yuv2plane1_float_u(const int32_t *src, float *dest, int dstW, int start) static void yuv2plane1_float_bswap_u(const int32_t *src, uint32_t *dest, int dstW, int start) { - static const int big_endian = HAVE_BIGENDIAN; static const int shift = 3; static const float float_mult = 1.0f / 65535.0f; int i, val; @@ -141,7 +137,7 @@ yuv2plane1_float_bswap_u(const int32_t *src, uint32_t *dest, int dstW, int start for (i = start; i < dstW; ++i){ val = src[i] + (1 << (shift - 1)); - output_pixel(&val_uint, val, 0, uint); + val_uint = get_pixel(val, 0, uint); dest[i] = av_bswap32(av_float2int(float_mult * (float)val_uint)); } } @@ -149,12 +145,11 @@ yuv2plane1_float_bswap_u(const int32_t *src, uint32_t *dest, int dstW, int start static void yuv2plane1_float_altivec(const int32_t *src, float *dest, int dstW) { const int dst_u = -(uintptr_t)dest & 3; - const int shift = 3; - const int add = (1 << (shift - 1)); + const int add = (1 << (SHIFT - 1)); const int clip = (1 << 16) - 1; const float fmult = 1.0f / 65535.0f; const vec_u32 vadd = (vec_u32) {add, add, add, add}; - const vec_u32 vshift = (vec_u32) vec_splat_u32(shift); + const vec_u32 vshift = (vec_u32) vec_splat_u32(SHIFT); const vec_u32 vlargest = (vec_u32) {clip, clip, clip, clip}; const vec_f vmul = (vec_f) {fmult, fmult, fmult, fmult}; const vec_f vzero = (vec_f) {0, 0, 0, 0}; @@ -182,12 +177,11 @@ static void yuv2plane1_float_altivec(const int32_t *src, float *dest, int dstW) static void yuv2plane1_float_bswap_altivec(const int32_t *src, uint32_t *dest, int dstW) { const int dst_u = -(uintptr_t)dest & 3; - const int shift = 3; - const int add = (1 << (shift - 1)); + const int add = (1 << (SHIFT - 1)); const int clip = (1 << 16) - 1; const float fmult = 1.0f / 65535.0f; const vec_u32 vadd = (vec_u32) {add, add, add, add}; - const vec_u32 vshift = (vec_u32) vec_splat_u32(shift); + const vec_u32 vshift = (vec_u32) vec_splat_u32(SHIFT); const vec_u32 vlargest = (vec_u32) {clip, clip, clip, clip}; const vec_f vmul = (vec_f) {fmult, fmult, fmult, fmult}; const vec_f vzero = (vec_f) {0, 0, 0, 0}; diff --git a/libswscale/ppc/swscale_ppc_template.c b/libswscale/ppc/swscale_ppc_template.c index 84641f3a8..3c2addd4a 100644 --- a/libswscale/ppc/swscale_ppc_template.c +++ b/libswscale/ppc/swscale_ppc_template.c @@ -101,11 +101,70 @@ static void FUNC(hScale_real)(SwsContext *c, int16_t *dst, int dstW, const uint8_t *src, const int16_t *filter, const int32_t *filterPos, int filterSize) { - register int i; LOCAL_ALIGNED(16, int, tempo, [4]); - if (filterSize % 4) { - for (i = 0; i < dstW; i++) { + switch (filterSize) { + case 4: + for (register int i = 0; i < dstW; i++) { + register int srcPos = filterPos[i]; + + vector unsigned char src_vF = unaligned_load(srcPos, src); + vector signed short src_v, filter_v; + vector signed int val_vEven, val_s; + src_v = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); + // now put our elements in the even slots + src_v = vec_mergeh(src_v, (vector signed short)vzero); + GET_VF4(i, filter_v, filter); + val_vEven = vec_mule(src_v, filter_v); + val_s = vec_sums(val_vEven, vzero); + vec_st(val_s, 0, tempo); + dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); + } + break; + case 8: + for (register int i = 0; i < dstW; i++) { + register int srcPos = filterPos[i]; + vector unsigned char src_vF, av_unused src_v0, av_unused src_v1; + vector unsigned char av_unused permS; + vector signed short src_v, filter_v; + vector signed int val_v, val_s; + FIRST_LOAD(src_v0, srcPos, src, permS); + LOAD_SRCV8(srcPos, 0, src, permS, src_v0, src_v1, src_vF); + src_v = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); + filter_v = vec_ld(i << 4, filter); + val_v = vec_msums(src_v, filter_v, (vector signed int)vzero); + val_s = vec_sums(val_v, vzero); + vec_st(val_s, 0, tempo); + dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); + } + break; + + case 16: + for (register int i = 0; i < dstW; i++) { + register int srcPos = filterPos[i]; + + vector unsigned char src_vF = unaligned_load(srcPos, src); + vector signed short src_vA = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); + vector signed short src_vB = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEL((vector unsigned char)vzero, src_vF)); + vector signed short filter_v0 = vec_ld(i << 5, filter); + vector signed short filter_v1 = vec_ld((i << 5) + 16, filter); + + vector signed int val_acc = vec_msums(src_vA, filter_v0, (vector signed int)vzero); + vector signed int val_v = vec_msums(src_vB, filter_v1, val_acc); + + vector signed int val_s = vec_sums(val_v, vzero); + + VEC_ST(val_s, 0, tempo); + dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); + } + break; + + default: + for (register int i = 0; i < dstW; i++) { register int j; register int srcPos = filterPos[i]; register int val = 0; @@ -113,110 +172,6 @@ static void FUNC(hScale_real)(SwsContext *c, int16_t *dst, int dstW, val += ((int)src[srcPos + j]) * filter[filterSize * i + j]; dst[i] = FFMIN(val >> 7, (1 << 15) - 1); } - } else - switch (filterSize) { - case 4: - for (i = 0; i < dstW; i++) { - register int srcPos = filterPos[i]; - - vector unsigned char src_vF = unaligned_load(srcPos, src); - vector signed short src_v, filter_v; - vector signed int val_vEven, val_s; - src_v = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - // now put our elements in the even slots - src_v = vec_mergeh(src_v, (vector signed short)vzero); - GET_VF4(i, filter_v, filter); - val_vEven = vec_mule(src_v, filter_v); - val_s = vec_sums(val_vEven, vzero); - vec_st(val_s, 0, tempo); - dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); - } break; - case 8: - for (i = 0; i < dstW; i++) { - register int srcPos = filterPos[i]; - vector unsigned char src_vF, av_unused src_v0, av_unused src_v1; - vector unsigned char av_unused permS; - vector signed short src_v, filter_v; - vector signed int val_v, val_s; - FIRST_LOAD(src_v0, srcPos, src, permS); - LOAD_SRCV8(srcPos, 0, src, permS, src_v0, src_v1, src_vF); - src_v = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - filter_v = vec_ld(i << 4, filter); - val_v = vec_msums(src_v, filter_v, (vector signed int)vzero); - val_s = vec_sums(val_v, vzero); - vec_st(val_s, 0, tempo); - dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); - } - break; - - case 16: - for (i = 0; i < dstW; i++) { - register int srcPos = filterPos[i]; - - vector unsigned char src_vF = unaligned_load(srcPos, src); - vector signed short src_vA = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - vector signed short src_vB = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEL((vector unsigned char)vzero, src_vF)); - vector signed short filter_v0 = vec_ld(i << 5, filter); - vector signed short filter_v1 = vec_ld((i << 5) + 16, filter); - - vector signed int val_acc = vec_msums(src_vA, filter_v0, (vector signed int)vzero); - vector signed int val_v = vec_msums(src_vB, filter_v1, val_acc); - - vector signed int val_s = vec_sums(val_v, vzero); - - VEC_ST(val_s, 0, tempo); - dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); - } - break; - - default: - for (i = 0; i < dstW; i++) { - register int j, av_unused offset = i * 2 * filterSize; - register int srcPos = filterPos[i]; - - vector signed int val_s, val_v = (vector signed int)vzero; - vector signed short av_unused filter_v0R; - vector unsigned char av_unused permF, av_unused src_v0, av_unused permS; - FIRST_LOAD(filter_v0R, offset, filter, permF); - FIRST_LOAD(src_v0, srcPos, src, permS); - - for (j = 0; j < filterSize - 15; j += 16) { - vector unsigned char av_unused src_v1, src_vF; - vector signed short av_unused filter_v1R, av_unused filter_v2R, - filter_v0, filter_v1, src_vA, src_vB; - vector signed int val_acc; - LOAD_SRCV(srcPos, j, src, permS, src_v0, src_v1, src_vF); - src_vA = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - src_vB = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEL((vector unsigned char)vzero, src_vF)); - GET_VFD(i, j, filter, filter_v0R, filter_v1R, permF, filter_v0, 0); - GET_VFD(i, j, filter, filter_v1R, filter_v2R, permF, filter_v1, 16); - - val_acc = vec_msums(src_vA, filter_v0, val_v); - val_v = vec_msums(src_vB, filter_v1, val_acc); - UPDATE_PTR(filter_v2R, filter_v0R, src_v1, src_v0); - } - - if (j < filterSize - 7) { - // loading src_v0 is useless, it's already done above - vector unsigned char av_unused src_v1, src_vF; - vector signed short src_v, av_unused filter_v1R, filter_v; - LOAD_SRCV8(srcPos, j, src, permS, src_v0, src_v1, src_vF); - src_v = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - GET_VFD(i, j, filter, filter_v0R, filter_v1R, permF, filter_v, 0); - val_v = vec_msums(src_v, filter_v, val_v); - } - val_s = vec_sums(val_v, vzero); - - VEC_ST(val_s, 0, tempo); - dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); - } - } + } } diff --git a/libswscale/rgb2rgb.h b/libswscale/rgb2rgb.h index f3951d523..e3b088390 100644 --- a/libswscale/rgb2rgb.h +++ b/libswscale/rgb2rgb.h @@ -121,8 +121,6 @@ extern void (*yuv422ptouyvy)(const uint8_t *ysrc, const uint8_t *usrc, const uin /** * Height should be a multiple of 2 and width should be a multiple of 2. * (If this is a problem for anyone then tell me, and I will fix it.) - * Chrominance data is only taken from every second line, others are ignored. - * FIXME: Write high quality version. */ extern void (*ff_rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, int width, int height, diff --git a/libswscale/rgb2rgb_template.c b/libswscale/rgb2rgb_template.c index 42c69801b..d4204153d 100644 --- a/libswscale/rgb2rgb_template.c +++ b/libswscale/rgb2rgb_template.c @@ -640,11 +640,8 @@ static inline void uyvytoyv12_c(const uint8_t *src, uint8_t *ydst, } /** - * Height should be a multiple of 2 and width should be a multiple of 2. + * width should be a multiple of 2. * (If this is a problem for anyone then tell me, and I will fix it.) - * Chrominance data is only taken from every second line, - * others are ignored in the C version. - * FIXME: Write HQ version. */ void ff_rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, int width, int height, int lumStride, @@ -655,55 +652,57 @@ void ff_rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst, int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; int y; const int chromWidth = width >> 1; + const uint8_t *src1 = src; + const uint8_t *src2 = src1 + srcStride; + uint8_t *ydst1 = ydst; + uint8_t *ydst2 = ydst + lumStride; for (y = 0; y < height; y += 2) { int i; - for (i = 0; i < chromWidth; i++) { - unsigned int b = src[6 * i + 0]; - unsigned int g = src[6 * i + 1]; - unsigned int r = src[6 * i + 2]; - - unsigned int Y = ((ry * r + gy * g + by * b) >> RGB2YUV_SHIFT) + 16; - unsigned int V = ((rv * r + gv * g + bv * b) >> RGB2YUV_SHIFT) + 128; - unsigned int U = ((ru * r + gu * g + bu * b) >> RGB2YUV_SHIFT) + 128; - - udst[i] = U; - vdst[i] = V; - ydst[2 * i] = Y; - - b = src[6 * i + 3]; - g = src[6 * i + 4]; - r = src[6 * i + 5]; - - Y = ((ry * r + gy * g + by * b) >> RGB2YUV_SHIFT) + 16; - ydst[2 * i + 1] = Y; + if (y + 1 == height) { + ydst2 = ydst1; + src2 = src1; } - ydst += lumStride; - src += srcStride; - - if (y+1 == height) - break; for (i = 0; i < chromWidth; i++) { - unsigned int b = src[6 * i + 0]; - unsigned int g = src[6 * i + 1]; - unsigned int r = src[6 * i + 2]; + unsigned int b11 = src1[6 * i + 0]; + unsigned int g11 = src1[6 * i + 1]; + unsigned int r11 = src1[6 * i + 2]; + unsigned int b12 = src1[6 * i + 3]; + unsigned int g12 = src1[6 * i + 4]; + unsigned int r12 = src1[6 * i + 5]; + unsigned int b21 = src2[6 * i + 0]; + unsigned int g21 = src2[6 * i + 1]; + unsigned int r21 = src2[6 * i + 2]; + unsigned int b22 = src2[6 * i + 3]; + unsigned int g22 = src2[6 * i + 4]; + unsigned int r22 = src2[6 * i + 5]; - unsigned int Y = ((ry * r + gy * g + by * b) >> RGB2YUV_SHIFT) + 16; + unsigned int Y11 = ((ry * r11 + gy * g11 + by * b11) >> RGB2YUV_SHIFT) + 16; + unsigned int Y12 = ((ry * r12 + gy * g12 + by * b12) >> RGB2YUV_SHIFT) + 16; + unsigned int Y21 = ((ry * r21 + gy * g21 + by * b21) >> RGB2YUV_SHIFT) + 16; + unsigned int Y22 = ((ry * r22 + gy * g22 + by * b22) >> RGB2YUV_SHIFT) + 16; - ydst[2 * i] = Y; + unsigned int bx = (b11 + b12 + b21 + b22) >> 2; + unsigned int gx = (g11 + g12 + g21 + g22) >> 2; + unsigned int rx = (r11 + r12 + r21 + r22) >> 2; - b = src[6 * i + 3]; - g = src[6 * i + 4]; - r = src[6 * i + 5]; + unsigned int U = ((ru * rx + gu * gx + bu * bx) >> RGB2YUV_SHIFT) + 128; + unsigned int V = ((rv * rx + gv * gx + bv * bx) >> RGB2YUV_SHIFT) + 128; - Y = ((ry * r + gy * g + by * b) >> RGB2YUV_SHIFT) + 16; - ydst[2 * i + 1] = Y; + ydst1[2 * i + 0] = Y11; + ydst1[2 * i + 1] = Y12; + ydst2[2 * i + 0] = Y21; + ydst2[2 * i + 1] = Y22; + udst[i] = U; + vdst[i] = V; } - udst += chromStride; - vdst += chromStride; - ydst += lumStride; - src += srcStride; + src1 += srcStride * 2; + src2 += srcStride * 2; + ydst1 += lumStride * 2; + ydst2 += lumStride * 2; + udst += chromStride; + vdst += chromStride; } } diff --git a/libswscale/riscv/Makefile b/libswscale/riscv/Makefile index 48afaf62a..7c8977d94 100644 --- a/libswscale/riscv/Makefile +++ b/libswscale/riscv/Makefile @@ -1,3 +1,8 @@ -OBJS += riscv/rgb2rgb.o +OBJS += riscv/rgb2rgb.o \ + riscv/swscale.o RV-OBJS += riscv/rgb2rgb_rvb.o -RVV-OBJS += riscv/rgb2rgb_rvv.o +RVV-OBJS += riscv/input_rvv.o \ + riscv/range_rvv.o \ + riscv/rgb2rgb_rvv.o + +SHLIBOBJS += riscv/cpu_common.o diff --git a/libswscale/riscv/cpu_common.c b/libswscale/riscv/cpu_common.c new file mode 100644 index 000000000..17c9b392c --- /dev/null +++ b/libswscale/riscv/cpu_common.c @@ -0,0 +1 @@ +#include "libavutil/riscv/cpu_common.c" diff --git a/libswscale/riscv/input_rvv.S b/libswscale/riscv/input_rvv.S new file mode 100644 index 000000000..759f15771 --- /dev/null +++ b/libswscale/riscv/input_rvv.S @@ -0,0 +1,321 @@ +/* + * 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_bgr24ToY_rvv, zve32x + lpad 0 + lw t1, 8(a5) # BY + lw t3, 0(a5) # RY + j 1f +endfunc + +func ff_rgb24ToY_rvv, zve32x, zba + lpad 0 + lw t1, 0(a5) # RY + lw t3, 8(a5) # BY +1: + lw t2, 4(a5) # GY + li t4, (32 << (15 - 1)) + (1 << (15 - 7)) +2: + vsetvli t0, a4, e32, m8, ta, ma + vlseg3e8.v v0, (a1) + sub a4, a4, t0 + vzext.vf4 v8, v0 + sh1add t5, t0, t0 # t1 = 3 * t0 + vzext.vf4 v16, v2 + vzext.vf4 v24, v4 + add a1, t5, a1 + vmul.vx v8, v8, t1 + vmacc.vx v8, t2, v16 + vmacc.vx v8, t3, v24 + vadd.vx v8, v8, t4 + vsetvli zero, zero, e16, m4, ta, ma + vnsra.wi v0, v8, 15 - 6 + vse16.v v0, (a0) + sh1add a0, t0, a0 + bnez a4, 2b + + ret +endfunc + +func ff_bgr24ToUV_rvv, zve32x + lpad 0 + lw t1, 20(a6) # BU + lw t4, 32(a6) # BV + lw t3, 12(a6) # RU + lw t6, 24(a6) # RV + j 1f +endfunc + +func ff_rgb24ToUV_rvv, zve32x, zba + lpad 0 + lw t1, 12(a6) # RU + lw t4, 24(a6) # RV + lw t3, 20(a6) # BU + lw t6, 32(a6) # BV +1: + lw t2, 16(a6) # GU + lw t5, 28(a6) # GV + li a7, (256 << (15 - 1)) + (1 << (15 - 7)) +2: + vsetvli t0, a5, e32, m8, ta, ma + vlseg3e8.v v0, (a3) + sub a5, a5, t0 + vzext.vf4 v16, v0 + sh1add a6, t0, t0 + vzext.vf4 v24, v2 + vmul.vx v8, v16, t1 + add a3, a6, a3 + vmul.vx v16, v16, t4 + vmacc.vx v8, t2, v24 + vmacc.vx v16, t5, v24 + vzext.vf4 v24, v4 + vadd.vx v8, v8, a7 + vadd.vx v16, v16, a7 + vmacc.vx v8, t3, v24 + vmacc.vx v16, t6, v24 + vsetvli zero, zero, e16, m4, ta, ma + vnsra.wi v0, v8, 15 - 6 + vnsra.wi v4, v16, 15 - 6 + vse16.v v0, (a0) + sh1add a0, t0, a0 + vse16.v v4, (a1) + sh1add a1, t0, a1 + bnez a5, 2b + + ret +endfunc + +func ff_bgr24ToUV_half_rvv, zve32x + lpad 0 + lw t1, 20(a6) # BU + lw t4, 32(a6) # BV + lw t3, 12(a6) # RU + lw t6, 24(a6) # RV + j 1f +endfunc + +func ff_rgb24ToUV_half_rvv, zve32x, zba + lpad 0 + lw t1, 12(a6) # RU + lw t4, 24(a6) # RV + lw t3, 20(a6) # BU + lw t6, 32(a6) # BV +1: + lw t2, 16(a6) # GU + lw t5, 28(a6) # GV + li a7, (256 << 15) + (1 << (15 - 6)) +2: + vsetvli t0, a5, e8, m1, ta, ma + vlseg6e8.v v0, (a3) + sh1add a6, t0, t0 + vwaddu.vv v8, v0, v3 + sub a5, a5, t0 + vwaddu.vv v10, v1, v4 + sh1add a3, a6, a3 + vwaddu.vv v12, v2, v5 + vsetvli zero, zero, e32, m4, ta, ma + vzext.vf2 v20, v8 + vzext.vf2 v24, v10 + vzext.vf2 v28, v12 + vmul.vx v0, v20, t1 + vmul.vx v4, v20, t4 + vmacc.vx v0, t2, v24 + vmacc.vx v4, t5, v24 + vmacc.vx v0, t3, v28 + vmacc.vx v4, t6, v28 + vadd.vx v0, v0, a7 + vadd.vx v4, v4, a7 + vsetvli zero, zero, e16, m2, ta, ma + vnsra.wi v0, v0, 15 - 5 + vnsra.wi v2, v4, 15 - 5 + vse16.v v0, (a0) + sh1add a0, t0, a0 + vse16.v v2, (a1) + sh1add a1, t0, a1 + bnez a5, 2b + + ret +endfunc + + .macro rgba_input chr0, chr1, high +func ff_\chr1\()ToY_rvv, zve32x + lpad 0 + lw t1, 8(a5) # BY + lw t3, 0(a5) # RY + j 1f +endfunc + +func ff_\chr0\()ToY_rvv, zve32x, zba + lpad 0 + lw t1, 0(a5) # RY + lw t3, 8(a5) # BY +1: + lw t2, 4(a5) # GY + li t4, (32 << (15 - 1)) + (1 << (15 - 7)) + li t5, 0xff +2: + vsetvli t0, a4, e32, m8, ta, ma + vle32.v v0, (a1) + sub a4, a4, t0 + .if \high + vsrl.vi v8, v0, 24 + .else + vand.vx v8, v0, t5 + .endif + sh2add a1, t0, a1 + vsrl.vi v16, v0, 8 * (1 + \high) + vmul.vx v24, v8, t1 + vand.vx v16, v16, t5 + vsrl.vi v8, v0, 8 * (2 - \high) + vmacc.vx v24, t2, v16 + vand.vx v8, v8, t5 + vadd.vx v24, v24, t4 + vmacc.vx v24, t3, v8 + vsetvli zero, zero, e16, m4, ta, ma + vnsra.wi v0, v24, 15 - 6 + vse16.v v0, (a0) + sh1add a0, t0, a0 + bnez a4, 2b + + ret +endfunc + +func ff_\chr1\()ToUV_rvv, zve32x + lpad 0 + lw t1, 20(a6) # BU + lw t4, 32(a6) # BV + lw t3, 12(a6) # RU + lw t6, 24(a6) # RV + j 1f +endfunc + +func ff_\chr0\()ToUV_rvv, zve32x, zba + lpad 0 + lw t1, 12(a6) # RU + lw t4, 24(a6) # RV + lw t3, 20(a6) # BU + lw t6, 32(a6) # BV +1: + lw t2, 16(a6) # GU + lw t5, 28(a6) # GV + li a6, 0xff + li a7, (256 << (15 - 1)) + (1 << (15 - 7)) +2: + vsetvli t0, a5, e32, m8, ta, ma + vle32.v v0, (a3) + sub a5, a5, t0 + .if \high + vsrl.vi v24, v0, 24 + .else + vand.vx v24, v0, a6 + .endif + sh2add a3, t0, a3 + vsrl.vi v8, v0, 8 * (1 + \high) + vmul.vx v16, v24, t1 + vand.vx v8, v8, a6 + vmul.vx v24, v24, t4 + vmacc.vx v16, t2, v8 + vsrl.vi v0, v0, 8 * (2 - \high) + vmacc.vx v24, t5, v8 + vand.vx v0, v0, a6 + vadd.vx v16, v16, a7 + vadd.vx v24, v24, a7 + vmacc.vx v16, t3, v0 + vmacc.vx v24, t6, v0 + vsetvli zero, zero, e16, m4, ta, ma + vnsra.wi v0, v16, 15 - 6 + vnsra.wi v4, v24, 15 - 6 + vse16.v v0, (a0) + sh1add a0, t0, a0 + vse16.v v4, (a1) + sh1add a1, t0, a1 + bnez a5, 2b + + ret +endfunc + +func ff_\chr1\()ToUV_half_rvv, zve32x + lpad 0 + lw t1, 20(a6) # BU + lw t4, 32(a6) # BV + lw t3, 12(a6) # RU + lw t6, 24(a6) # RV + j 1f +endfunc + +func ff_\chr0\()ToUV_half_rvv, zve32x, zba + lpad 0 + lw t1, 12(a6) # RU + lw t4, 24(a6) # RV + lw t3, 20(a6) # BU + lw t6, 32(a6) # BV +1: + lw t2, 16(a6) # GU + lw t5, 28(a6) # GV + li a6, 0xff + li a7, (256 << 15) + (1 << (15 - 6)) +2: + vsetvli t0, a5, e32, m4, ta, ma + vlseg2e32.v v0, (a3) + sub a5, a5, t0 + .if \high + vsrl.vi v8, v0, 24 + vsrl.vi v12, v4, 24 + .else + vand.vx v8, v0, a6 + vand.vx v12, v4, a6 + .endif + sh3add a3, t0, a3 + vsrl.vi v16, v0, 8 * (1 + \high) + vsrl.vi v20, v4, 8 * (1 + \high) + vsrl.vi v24, v0, 8 * (2 - \high) + vsrl.vi v28, v4, 8 * (2 - \high) + vand.vx v16, v16, a6 + vand.vx v20, v20, a6 + vand.vx v24, v24, a6 + vand.vx v28, v28, a6 + vadd.vv v8, v8, v12 + vadd.vv v16, v16, v20 + vadd.vv v24, v24, v28 + vmul.vx v0, v8, t1 + vmul.vx v4, v8, t4 + vmacc.vx v0, t2, v16 + vmacc.vx v4, t5, v16 + vmacc.vx v0, t3, v24 + vmacc.vx v4, t6, v24 + vadd.vx v0, v0, a7 + vadd.vx v4, v4, a7 + vsetvli zero, zero, e16, m2, ta, ma + vnsra.wi v0, v0, 15 - 5 + vnsra.wi v2, v4, 15 - 5 + vse16.v v0, (a0) + sh1add a0, t0, a0 + vse16.v v2, (a1) + sh1add a1, t0, a1 + bnez a5, 2b + + ret +endfunc + .endm + +rgba_input rgba32, bgra32, 0 +rgba_input abgr32, argb32, 1 diff --git a/libswscale/riscv/range_rvv.S b/libswscale/riscv/range_rvv.S new file mode 100644 index 000000000..24005170a --- /dev/null +++ b/libswscale/riscv/range_rvv.S @@ -0,0 +1,118 @@ +/* + * 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_range_lum_to_jpeg_16_rvv, zve32x, zba + lpad 0 + li t1, 30189 + li t2, 19077 + li t3, -39057361 +1: + vsetvli t0, a1, e16, m4, ta, ma + vle16.v v0, (a0) + sub a1, a1, t0 + vmin.vx v0, v0, t1 + vwmul.vx v8, v0, t2 + vsetvli zero, zero, e32, m8, ta, ma + vadd.vx v8, v8, t3 + vsetvli zero, zero, e16, m4, ta, ma + vnsra.wi v0, v8, 14 + vse16.v v0, (a0) + sh1add a0, t0, a0 + bnez a1, 1b + + ret +endfunc + +func ff_range_lum_from_jpeg_16_rvv, zve32x, zba + lpad 0 + li t1, 14071 + li t2, 33561947 +1: + vsetvli t0, a1, e16, m4, ta, ma + vle16.v v0, (a0) + sub a1, a1, t0 + vwmul.vx v8, v0, t1 + vsetvli zero, zero, e32, m8, ta, ma + vadd.vx v8, v8, t2 + vsetvli zero, zero, e16, m4, ta, ma + vnsra.wi v0, v8, 14 + vse16.v v0, (a0) + sh1add a0, t0, a0 + bnez a1, 1b + + ret +endfunc + +func ff_range_chr_to_jpeg_16_rvv, zve32x, zba + lpad 0 + li t1, 30775 + li t2, 4663 + li t3, -9289992 +1: + vsetvli t0, a2, e16, m4, ta, ma + vle16.v v0, (a0) + sub a2, a2, t0 + vle16.v v4, (a1) + vmin.vx v0, v0, t1 + vmin.vx v4, v4, t1 + vwmul.vx v8, v0, t2 + vwmul.vx v16, v4, t2 + vsetvli zero, zero, e32, m8, ta, ma + vadd.vx v8, v8, t3 + vadd.vx v16, v16, t3 + vsetvli zero, zero, e16, m4, ta, ma + vnsra.wi v0, v8, 12 + vnsra.wi v4, v16, 12 + vse16.v v0, (a0) + sh1add a0, t0, a0 + vse16.v v4, (a1) + sh1add a1, t0, a1 + bnez a2, 1b + + ret +endfunc + +func ff_range_chr_from_jpeg_16_rvv, zve32x, zba + lpad 0 + li t1, 1799 + li t2, 4081085 +1: + vsetvli t0, a2, e16, m4, ta, ma + vle16.v v0, (a0) + sub a2, a2, t0 + vle16.v v4, (a1) + vwmul.vx v8, v0, t1 + vwmul.vx v16, v4, t1 + vsetvli zero, zero, e32, m8, ta, ma + vadd.vx v8, v8, t2 + vadd.vx v16, v16, t2 + vsetvli zero, zero, e16, m4, ta, ma + vnsra.wi v0, v8, 11 + vnsra.wi v4, v16, 11 + vse16.v v0, (a0) + sh1add a0, t0, a0 + vse16.v v0, (a1) + sh1add a1, t0, a1 + bnez a2, 1b + + ret +endfunc diff --git a/libswscale/riscv/rgb2rgb.c b/libswscale/riscv/rgb2rgb.c index e751e1107..3581954e3 100644 --- a/libswscale/riscv/rgb2rgb.c +++ b/libswscale/riscv/rgb2rgb.c @@ -33,6 +33,9 @@ void ff_shuffle_bytes_3210_rvb(const uint8_t *src, uint8_t *dst, int src_len); void ff_interleave_bytes_rvv(const uint8_t *src1, const uint8_t *src2, uint8_t *dst, int width, int height, int s1stride, int s2stride, int dstride); +void ff_deinterleave_bytes_rvv(const uint8_t *src, uint8_t *dst1, + uint8_t *dst2, int width, int height, + int srcStride, int dst1Stride, int dst2Stride); void ff_uyvytoyuv422_rvv(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, int width, int height, int ystride, int uvstride, int src_stride); @@ -46,20 +49,19 @@ av_cold void rgb2rgb_init_riscv(void) int flags = av_get_cpu_flags(); #if (__riscv_xlen == 64) - if ((flags & AV_CPU_FLAG_RVB_BASIC) && (flags & AV_CPU_FLAG_RVB_ADDR)) + if (flags & AV_CPU_FLAG_RVB_BASIC) shuffle_bytes_3210 = ff_shuffle_bytes_3210_rvb; #endif #if HAVE_RVV - if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB_ADDR)) { + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { shuffle_bytes_0321 = ff_shuffle_bytes_0321_rvv; shuffle_bytes_2103 = ff_shuffle_bytes_2103_rvv; shuffle_bytes_1230 = ff_shuffle_bytes_1230_rvv; shuffle_bytes_3012 = ff_shuffle_bytes_3012_rvv; interleaveBytes = ff_interleave_bytes_rvv; - if (flags & AV_CPU_FLAG_RVB_BASIC) { - uyvytoyuv422 = ff_uyvytoyuv422_rvv; - yuyvtoyuv422 = ff_yuyvtoyuv422_rvv; - } + deinterleaveBytes = ff_deinterleave_bytes_rvv; + uyvytoyuv422 = ff_uyvytoyuv422_rvv; + yuyvtoyuv422 = ff_yuyvtoyuv422_rvv; } #endif #endif diff --git a/libswscale/riscv/rgb2rgb_rvb.S b/libswscale/riscv/rgb2rgb_rvb.S index af127b32e..d44130824 100644 --- a/libswscale/riscv/rgb2rgb_rvb.S +++ b/libswscale/riscv/rgb2rgb_rvb.S @@ -24,7 +24,7 @@ #if (__riscv_xlen >= 64) func ff_shuffle_bytes_3210_rvb, zbb - srli a2, a2, 2 + lpad 0 bswap32_rvb a1, a0, a2 endfunc #endif diff --git a/libswscale/riscv/rgb2rgb_rvv.S b/libswscale/riscv/rgb2rgb_rvv.S index 21e30ab8b..a1a927b00 100644 --- a/libswscale/riscv/rgb2rgb_rvv.S +++ b/libswscale/riscv/rgb2rgb_rvv.S @@ -21,11 +21,13 @@ #include "libavutil/riscv/asm.S" func ff_shuffle_bytes_0321_rvv, zve32x + lpad 0 li t1, 0x00ff00ff j 1f endfunc -func ff_shuffle_bytes_2103_rvv, zve32x +func ff_shuffle_bytes_2103_rvv, zve32x, zba + lpad 0 li t1, ~0x00ff00ff 1: not t2, t1 @@ -49,12 +51,14 @@ func ff_shuffle_bytes_2103_rvv, zve32x endfunc func ff_shuffle_bytes_1230_rvv, zve32x + lpad 0 li t1, 24 li t2, 8 j 3f endfunc -func ff_shuffle_bytes_3012_rvv, zve32x +func ff_shuffle_bytes_3012_rvv, zve32x, zba + lpad 0 li t1, 8 li t2, 24 3: @@ -74,7 +78,8 @@ func ff_shuffle_bytes_3012_rvv, zve32x ret endfunc -func ff_interleave_bytes_rvv, zve32x +func ff_interleave_bytes_rvv, zve32x, zba + lpad 0 1: mv t0, a0 mv t1, a1 @@ -100,7 +105,8 @@ func ff_interleave_bytes_rvv, zve32x ret endfunc -func ff_deinterleave_bytes_rvv, zve32x +func ff_deinterleave_bytes_rvv, zve32x, zba + lpad 0 1: mv t0, a0 mv t1, a1 @@ -127,6 +133,7 @@ func ff_deinterleave_bytes_rvv, zve32x endfunc .macro yuy2_to_i422p luma, chroma + lpad 0 srai t4, a4, 1 // pixel width -> chroma width lw t6, (sp) slli t5, a4, 1 // pixel width -> (source) byte width @@ -165,10 +172,10 @@ endfunc ret .endm -func ff_uyvytoyuv422_rvv, zve32x +func ff_uyvytoyuv422_rvv, zve32x, b yuy2_to_i422p v20, v16 endfunc -func ff_yuyvtoyuv422_rvv, zve32x +func ff_yuyvtoyuv422_rvv, zve32x, b yuy2_to_i422p v16, v20 endfunc diff --git a/libswscale/riscv/swscale.c b/libswscale/riscv/swscale.c new file mode 100644 index 000000000..c452d93e5 --- /dev/null +++ b/libswscale/riscv/swscale.c @@ -0,0 +1,126 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/riscv/cpu.h" +#include "libswscale/swscale_internal.h" + +void ff_range_lum_to_jpeg_16_rvv(int16_t *, int); +void ff_range_chr_to_jpeg_16_rvv(int16_t *, int16_t *, int); +void ff_range_lum_from_jpeg_16_rvv(int16_t *, int); +void ff_range_chr_from_jpeg_16_rvv(int16_t *, int16_t *, int); + +av_cold static void ff_sws_init_range_convert_riscv(SwsContext *c, int flags) +{ +#if HAVE_RVV + static const struct { + void (*lum)(int16_t *, int); + void (*chr)(int16_t *, int16_t *, int); + } convs[2] = { + { ff_range_lum_to_jpeg_16_rvv, ff_range_chr_to_jpeg_16_rvv }, + { ff_range_lum_from_jpeg_16_rvv, ff_range_chr_from_jpeg_16_rvv }, + }; + + if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat) && + c->dstBpc <= 14 && + (flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { + bool from = c->srcRange != 0; + + c->lumConvertRange = convs[from].lum; + c->chrConvertRange = convs[from].chr; + } +#endif +} + +#define RVV_INPUT(name) \ +void ff_##name##ToY_rvv(uint8_t *dst, const uint8_t *src, const uint8_t *, \ + const uint8_t *, int w, uint32_t *coeffs, void *); \ +void ff_##name##ToUV_rvv(uint8_t *, uint8_t *, const uint8_t *, \ + const uint8_t *, const uint8_t *, int w, \ + uint32_t *coeffs, void *); \ +void ff_##name##ToUV_half_rvv(uint8_t *, uint8_t *, const uint8_t *, \ + const uint8_t *, const uint8_t *, int w, \ + uint32_t *coeffs, void *) + +RVV_INPUT(abgr32); +RVV_INPUT(argb32); +RVV_INPUT(bgr24); +RVV_INPUT(bgra32); +RVV_INPUT(rgb24); +RVV_INPUT(rgba32); + +av_cold void ff_sws_init_swscale_riscv(SwsContext *c) +{ + int flags = av_get_cpu_flags(); + +#if HAVE_RVV + if ((flags & AV_CPU_FLAG_RVV_I32) && (flags & AV_CPU_FLAG_RVB)) { + switch (c->srcFormat) { + case AV_PIX_FMT_ABGR: + c->lumToYV12 = ff_abgr32ToY_rvv; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_abgr32ToUV_half_rvv; + else + c->chrToYV12 = ff_abgr32ToUV_rvv; + break; + + case AV_PIX_FMT_ARGB: + c->lumToYV12 = ff_argb32ToY_rvv; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_argb32ToUV_half_rvv; + else + c->chrToYV12 = ff_argb32ToUV_rvv; + break; + + case AV_PIX_FMT_BGR24: + c->lumToYV12 = ff_bgr24ToY_rvv; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_bgr24ToUV_half_rvv; + else + c->chrToYV12 = ff_bgr24ToUV_rvv; + break; + + case AV_PIX_FMT_BGRA: + c->lumToYV12 = ff_bgra32ToY_rvv; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_bgra32ToUV_half_rvv; + else + c->chrToYV12 = ff_bgra32ToUV_rvv; + break; + + case AV_PIX_FMT_RGB24: + c->lumToYV12 = ff_rgb24ToY_rvv; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_rgb24ToUV_half_rvv; + else + c->chrToYV12 = ff_rgb24ToUV_rvv; + break; + + case AV_PIX_FMT_RGBA: + c->lumToYV12 = ff_rgba32ToY_rvv; + if (c->chrSrcHSubSample) + c->chrToYV12 = ff_rgba32ToUV_half_rvv; + else + c->chrToYV12 = ff_rgba32ToUV_rvv; + break; + } + } +#endif + ff_sws_init_range_convert_riscv(c, flags); +} diff --git a/libswscale/slice.c b/libswscale/slice.c index db1c69672..951912fb7 100644 --- a/libswscale/slice.c +++ b/libswscale/slice.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/mem.h" #include "swscale_internal.h" static void free_lines(SwsSlice *s) @@ -59,7 +60,7 @@ static int alloc_lines(SwsSlice *s, int size, int width) for (j = 0; j < n; ++j) { // chroma plane line U and V are expected to be contiguous in memory // by mmx vertical scaler code - s->plane[i].line[j] = av_malloc(size * 2 + 32); + s->plane[i].line[j] = av_mallocz(size * 2 + 32); if (!s->plane[i].line[j]) { free_lines(s); return AVERROR(ENOMEM); diff --git a/libswscale/swscale.c b/libswscale/swscale.c index f08f2ac3b..8b6a3a84b 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -28,6 +28,7 @@ #include "libavutil/cpu.h" #include "libavutil/emms.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/pixdesc.h" #include "config.h" @@ -223,7 +224,7 @@ static void lumRangeFromJpeg16_c(int16_t *_dst, int width) int i; int32_t *dst = (int32_t *) _dst; for (i = 0; i < width; i++) - dst[i] = (dst[i]*(14071/4) + (33561947<<4)/4)>>12; + dst[i] = ((int)(dst[i]*(14071U/4) + (33561947<<4)/4)) >> 12; } @@ -601,6 +602,8 @@ void ff_sws_init_scale(SwsContext *c) ff_sws_init_swscale_arm(c); #elif ARCH_LOONGARCH64 ff_sws_init_swscale_loongarch(c); +#elif ARCH_RISCV + ff_sws_init_swscale_riscv(c); #endif } diff --git a/libswscale/swscale.h b/libswscale/swscale.h index 9d4612aaf..e575695c0 100644 --- a/libswscale/swscale.h +++ b/libswscale/swscale.h @@ -82,11 +82,35 @@ const char *swscale_license(void); #define SWS_PRINT_INFO 0x1000 //the following 3 flags are not completely implemented -//internal chrominance subsampling info + +/** + * Perform full chroma upsampling when upscaling to RGB. + * + * For example, when converting 50x50 yuv420p to 100x100 rgba, setting this flag + * will scale the chroma plane from 25x25 to 100x100 (4:4:4), and then convert + * the 100x100 yuv444p image to rgba in the final output step. + * + * Without this flag, the chroma plane is instead scaled to 50x100 (4:2:2), + * with a single chroma sample being re-used for both of the horizontally + * adjacent RGBA output pixels. + */ #define SWS_FULL_CHR_H_INT 0x2000 -//input subsampling info + +/** + * Perform full chroma interpolation when downscaling RGB sources. + * + * For example, when converting a 100x100 rgba source to 50x50 yuv444p, setting + * this flag will generate a 100x100 (4:4:4) chroma plane, which is then + * downscaled to the required 50x50. + * + * Without this flag, the chroma plane is instead generated at 50x100 (dropping + * every other pixel), before then being downscaled to the required 50x50 + * resolution. + */ #define SWS_FULL_CHR_H_INP 0x4000 + #define SWS_DIRECT_BGR 0x8000 + #define SWS_ACCURATE_RND 0x40000 #define SWS_BITEXACT 0x80000 #define SWS_ERROR_DIFFUSION 0x800000 diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index abeebbb00..50127d288 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -34,7 +34,9 @@ #include "libavutil/pixfmt.h" #include "libavutil/pixdesc.h" #include "libavutil/slicethread.h" +#if HAVE_ALTIVEC #include "libavutil/ppc/util_altivec.h" +#endif #include "libavutil/half2float.h" #define STR(s) AV_TOSTRING(s) // AV_STRINGIFY is too long @@ -44,8 +46,6 @@ #define MAX_FILTER_SIZE SWS_MAX_FILTER_SIZE -#define DITHER1XBPP - #if HAVE_BIGENDIAN #define ALT32_CORR (-1) #else @@ -695,6 +695,9 @@ void ff_yuv2rgb_init_tables_ppc(SwsContext *c, const int inv_table[4], void ff_updateMMXDitherTables(SwsContext *c, int dstY); av_cold void ff_sws_init_range_convert(SwsContext *c); +av_cold void ff_sws_init_range_convert_aarch64(SwsContext *c); +av_cold void ff_sws_init_range_convert_loongarch(SwsContext *c); +av_cold void ff_sws_init_range_convert_x86(SwsContext *c); SwsFunc ff_yuv2rgb_init_x86(SwsContext *c); SwsFunc ff_yuv2rgb_init_ppc(SwsContext *c); @@ -985,6 +988,7 @@ void ff_sws_init_swscale_x86(SwsContext *c); void ff_sws_init_swscale_aarch64(SwsContext *c); void ff_sws_init_swscale_arm(SwsContext *c); void ff_sws_init_swscale_loongarch(SwsContext *c); +void ff_sws_init_swscale_riscv(SwsContext *c); void ff_hyscale_fast_c(SwsContext *c, int16_t *dst, int dstWidth, const uint8_t *src, int srcW, int xInc); @@ -1001,46 +1005,31 @@ void ff_hcscale_fast_mmxext(SwsContext *c, int16_t *dst1, int16_t *dst2, int dstWidth, const uint8_t *src1, const uint8_t *src2, int srcW, int xInc); -/** - * Allocate and return an SwsContext. - * This is like sws_getContext() but does not perform the init step, allowing - * the user to set additional AVOptions. - * - * @see sws_getContext() - */ -struct SwsContext *sws_alloc_set_opts(int srcW, int srcH, enum AVPixelFormat srcFormat, - int dstW, int dstH, enum AVPixelFormat dstFormat, - int flags, const double *param); - int ff_sws_alphablendaway(SwsContext *c, const uint8_t *src[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t *dst[], int dstStride[]); +void ff_copyPlane(const uint8_t *src, int srcStride, + int srcSliceY, int srcSliceH, int width, + uint8_t *dst, int dstStride); + static inline void fillPlane16(uint8_t *plane, int stride, int width, int height, int y, int alpha, int bits, const int big_endian) { - int i, j; uint8_t *ptr = plane + stride * y; int v = alpha ? 0xFFFF>>(16-bits) : (1<<(bits-1)); - for (i = 0; i < height; i++) { -#define FILL(wfunc) \ - for (j = 0; j < width; j++) {\ - wfunc(ptr+2*j, v);\ - } - if (big_endian) { - FILL(AV_WB16); - } else { - FILL(AV_WL16); - } + if (big_endian != HAVE_BIGENDIAN) + v = av_bswap16(v); + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) + AV_WN16(ptr + 2 * j, v); ptr += stride; } -#undef FILL } static inline void fillPlane32(uint8_t *plane, int stride, int width, int height, int y, int alpha, int bits, const int big_endian, int is_float) { - int i, j; uint8_t *ptr = plane + stride * y; uint32_t v; uint32_t onef32 = 0x3f800000; @@ -1048,20 +1037,14 @@ static inline void fillPlane32(uint8_t *plane, int stride, int width, int height v = alpha ? onef32 : 0; else v = alpha ? 0xFFFFFFFF>>(32-bits) : (1<<(bits-1)); + if (big_endian != HAVE_BIGENDIAN) + v = av_bswap32(v); - for (i = 0; i < height; i++) { -#define FILL(wfunc) \ - for (j = 0; j < width; j++) {\ - wfunc(ptr+4*j, v);\ - } - if (big_endian) { - FILL(AV_WB32); - } else { - FILL(AV_WL32); - } + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) + AV_WN32(ptr + 4 * j, v); ptr += stride; } -#undef FILL } diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c index a5c991779..d403c953c 100644 --- a/libswscale/swscale_unscaled.c +++ b/libswscale/swscale_unscaled.c @@ -122,9 +122,9 @@ static void fillPlane(uint8_t *plane, int stride, int width, int height, int y, } } -static void copyPlane(const uint8_t *src, int srcStride, - int srcSliceY, int srcSliceH, int width, - uint8_t *dst, int dstStride) +void ff_copyPlane(const uint8_t *src, int srcStride, + int srcSliceY, int srcSliceH, int width, + uint8_t *dst, int dstStride) { dst += dstStride * srcSliceY; if (dstStride == srcStride && srcStride > 0) { @@ -146,8 +146,8 @@ static int planarToNv12Wrapper(SwsContext *c, const uint8_t *src[], { uint8_t *dst = dstParam[1] + dstStride[1] * srcSliceY / 2; - copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, - dstParam[0], dstStride[0]); + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dstParam[0], dstStride[0]); if (c->dstFormat == AV_PIX_FMT_NV12) interleaveBytes(src[1], src[2], dst, c->chrSrcW, (srcSliceH + 1) / 2, @@ -167,8 +167,8 @@ static int nv12ToPlanarWrapper(SwsContext *c, const uint8_t *src[], uint8_t *dst1 = dstParam[1] + dstStride[1] * srcSliceY / 2; uint8_t *dst2 = dstParam[2] + dstStride[2] * srcSliceY / 2; - copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, - dstParam[0], dstStride[0]); + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dstParam[0], dstStride[0]); if (c->srcFormat == AV_PIX_FMT_NV12) deinterleaveBytes(src[1], dst1, dst2, c->chrSrcW, (srcSliceH + 1) / 2, @@ -187,8 +187,8 @@ static int planarToNv24Wrapper(SwsContext *c, const uint8_t *src[], { uint8_t *dst = dstParam[1] + dstStride[1] * srcSliceY; - copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, - dstParam[0], dstStride[0]); + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dstParam[0], dstStride[0]); if (c->dstFormat == AV_PIX_FMT_NV24) interleaveBytes(src[1], src[2], dst, c->chrSrcW, srcSliceH, @@ -208,8 +208,8 @@ static int nv24ToPlanarWrapper(SwsContext *c, const uint8_t *src[], uint8_t *dst1 = dstParam[1] + dstStride[1] * srcSliceY; uint8_t *dst2 = dstParam[2] + dstStride[2] * srcSliceY; - copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, - dstParam[0], dstStride[0]); + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dstParam[0], dstStride[0]); if (c->srcFormat == AV_PIX_FMT_NV24) deinterleaveBytes(src[1], dst1, dst2, c->chrSrcW, srcSliceH, @@ -221,6 +221,50 @@ static int nv24ToPlanarWrapper(SwsContext *c, const uint8_t *src[], return srcSliceH; } +static void nv24_to_yuv420p_chroma(uint8_t *dst1, int dstStride1, + uint8_t *dst2, int dstStride2, + const uint8_t *src, int srcStride, + int w, int h) +{ + const uint8_t *src1 = src; + const uint8_t *src2 = src + srcStride; + // average 4 pixels into 1 (interleaved U and V) + for (int y = 0; y < h; y += 2) { + if (y + 1 == h) + src2 = src1; + for (int x = 0; x < w; x++) { + dst1[x] = (src1[4 * x + 0] + src1[4 * x + 2] + + src2[4 * x + 0] + src2[4 * x + 2]) >> 2; + dst2[x] = (src1[4 * x + 1] + src1[4 * x + 3] + + src2[4 * x + 1] + src2[4 * x + 3]) >> 2; + } + src1 += srcStride * 2; + src2 += srcStride * 2; + dst1 += dstStride1; + dst2 += dstStride2; + } +} + +static int nv24ToYuv420Wrapper(SwsContext *c, const uint8_t *src[], + int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *dstParam[], int dstStride[]) +{ + uint8_t *dst1 = dstParam[1] + dstStride[1] * srcSliceY / 2; + uint8_t *dst2 = dstParam[2] + dstStride[2] * srcSliceY / 2; + + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dstParam[0], dstStride[0]); + + if (c->srcFormat == AV_PIX_FMT_NV24) + nv24_to_yuv420p_chroma(dst1, dstStride[1], dst2, dstStride[2], + src[1], srcStride[1], c->srcW / 2, srcSliceH); + else + nv24_to_yuv420p_chroma(dst2, dstStride[2], dst1, dstStride[1], + src[1], srcStride[1], c->srcW / 2, srcSliceH); + + return srcSliceH; +} + static int planarToP01xWrapper(SwsContext *c, const uint8_t *src8[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t *dstParam8[], @@ -1131,12 +1175,12 @@ static int planarRgbToplanarRgbWrapper(SwsContext *c, int srcSliceY, int srcSliceH, uint8_t *dst[], int dstStride[]) { - copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, - dst[0], dstStride[0]); - copyPlane(src[1], srcStride[1], srcSliceY, srcSliceH, c->srcW, - dst[1], dstStride[1]); - copyPlane(src[2], srcStride[2], srcSliceY, srcSliceH, c->srcW, - dst[2], dstStride[2]); + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dst[0], dstStride[0]); + ff_copyPlane(src[1], srcStride[1], srcSliceY, srcSliceH, c->srcW, + dst[1], dstStride[1]); + ff_copyPlane(src[2], srcStride[2], srcSliceY, srcSliceH, c->srcW, + dst[2], dstStride[2]); if (dst[3]) fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255); @@ -1658,8 +1702,8 @@ static int yvu9ToYv12Wrapper(SwsContext *c, const uint8_t *src[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t *dst[], int dstStride[]) { - copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, - dst[0], dstStride[0]); + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dst[0], dstStride[0]); planar2x(src[1], dst[1] + dstStride[1] * (srcSliceY >> 1), c->chrSrcW, srcSliceH >> 2, srcStride[1], dstStride[1]); @@ -2206,6 +2250,9 @@ void ff_get_unscaled_swscale(SwsContext *c) c->convert_unscaled = yuyvToYuv422Wrapper; if (srcFormat == AV_PIX_FMT_UYVY422 && dstFormat == AV_PIX_FMT_YUV422P) c->convert_unscaled = uyvyToYuv422Wrapper; + if (dstFormat == AV_PIX_FMT_YUV420P && + (srcFormat == AV_PIX_FMT_NV24 || srcFormat == AV_PIX_FMT_NV42)) + c->convert_unscaled = nv24ToYuv420Wrapper; #define isPlanarGray(x) (isGray(x) && (x) != AV_PIX_FMT_YA8 && (x) != AV_PIX_FMT_YA16LE && (x) != AV_PIX_FMT_YA16BE) /* simple copy */ diff --git a/libswscale/utils.c b/libswscale/utils.c index 54bbd519a..c3154d82c 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -45,6 +45,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/libm.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/slicethread.h" @@ -269,6 +270,34 @@ static const FormatEntry format_entries[] = { [AV_PIX_FMT_XV36LE] = { 1, 1 }, }; +/** + * Allocate and return an SwsContext without performing initialization. + */ +static SwsContext *alloc_set_opts(int srcW, int srcH, enum AVPixelFormat srcFormat, + int dstW, int dstH, enum AVPixelFormat dstFormat, + int flags, const double *param) +{ + SwsContext *c = sws_alloc_context(); + + if (!c) + return NULL; + + c->flags = flags; + c->srcW = srcW; + c->srcH = srcH; + c->dstW = dstW; + c->dstH = dstH; + c->srcFormat = srcFormat; + c->dstFormat = dstFormat; + + if (param) { + c->param[0] = param[0]; + c->param[1] = param[1]; + } + + return c; +} + int ff_shuffle_filter_coefficients(SwsContext *c, int *filterPos, int filterSize, int16_t *filter, int dstW) @@ -1049,8 +1078,16 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], c->srcRange = srcRange; c->dstRange = dstRange; - if (need_reinit) + if (need_reinit) { ff_sws_init_range_convert(c); +#if ARCH_AARCH64 + ff_sws_init_range_convert_aarch64(c); +#elif ARCH_LOONGARCH64 + ff_sws_init_range_convert_loongarch(c); +#elif ARCH_X86 + ff_sws_init_range_convert_x86(c); +#endif + } c->dstFormatBpp = av_get_bits_per_pixel(desc_dst); c->srcFormatBpp = av_get_bits_per_pixel(desc_src); @@ -1101,9 +1138,9 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], if (ret < 0) return ret; - c->cascaded_context[0] = sws_alloc_set_opts(srcW, srcH, c->srcFormat, - tmp_width, tmp_height, tmp_format, - c->flags, c->param); + c->cascaded_context[0] = alloc_set_opts(srcW, srcH, c->srcFormat, + tmp_width, tmp_height, tmp_format, + c->flags, c->param); if (!c->cascaded_context[0]) return -1; @@ -1116,9 +1153,9 @@ int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4], srcRange, table, dstRange, brightness, contrast, saturation); - c->cascaded_context[1] = sws_alloc_set_opts(tmp_width, tmp_height, tmp_format, - dstW, dstH, c->dstFormat, - c->flags, c->param); + c->cascaded_context[1] = alloc_set_opts(tmp_width, tmp_height, tmp_format, + dstW, dstH, c->dstFormat, + c->flags, c->param); if (!c->cascaded_context[1]) return -1; c->cascaded_context[1]->srcRange = srcRange; @@ -1682,9 +1719,9 @@ static av_cold int sws_init_single_context(SwsContext *c, SwsFilter *srcFilter, if (ret < 0) return ret; - c->cascaded_context[0] = sws_alloc_set_opts(srcW, srcH, srcFormat, - srcW, srcH, tmpFormat, - flags, c->param); + c->cascaded_context[0] = alloc_set_opts(srcW, srcH, srcFormat, + srcW, srcH, tmpFormat, + flags, c->param); if (!c->cascaded_context[0]) return AVERROR(EINVAL); c->cascaded_context[0]->alphablend = c->alphablend; @@ -1692,9 +1729,9 @@ static av_cold int sws_init_single_context(SwsContext *c, SwsFilter *srcFilter, if (ret < 0) return ret; - c->cascaded_context[1] = sws_alloc_set_opts(srcW, srcH, tmpFormat, - dstW, dstH, dstFormat, - flags, c->param); + c->cascaded_context[1] = alloc_set_opts(srcW, srcH, tmpFormat, + dstW, dstH, dstFormat, + flags, c->param); if (!c->cascaded_context[1]) return AVERROR(EINVAL); @@ -1915,14 +1952,10 @@ static av_cold int sws_init_single_context(SwsContext *c, SwsFilter *srcFilter, av_log(c, AV_LOG_INFO, "%s scaler, from %s to %s%s ", scaler, av_get_pix_fmt_name(srcFormat), -#ifdef DITHER1XBPP dstFormat == AV_PIX_FMT_BGR555 || dstFormat == AV_PIX_FMT_BGR565 || dstFormat == AV_PIX_FMT_RGB444BE || dstFormat == AV_PIX_FMT_RGB444LE || dstFormat == AV_PIX_FMT_BGR444BE || dstFormat == AV_PIX_FMT_BGR444LE ? "dithered " : "", -#else - "", -#endif av_get_pix_fmt_name(dstFormat)); if (INLINE_MMXEXT(cpu_flags)) @@ -2009,6 +2042,7 @@ static int context_init_threaded(SwsContext *c, if (!c->slice_ctx[i]) return AVERROR(ENOMEM); + c->nb_slice_ctx++; c->slice_ctx[i]->parent = c; ret = av_opt_copy((void*)c->slice_ctx[i], (void*)c); @@ -2021,8 +2055,6 @@ static int context_init_threaded(SwsContext *c, if (ret < 0) return ret; - c->nb_slice_ctx++; - if (c->slice_ctx[i]->dither == SWS_DITHER_ED) { av_log(c, AV_LOG_VERBOSE, "Error-diffusion dither is in use, scaling will be single-threaded."); @@ -2066,31 +2098,6 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, return sws_init_single_context(c, srcFilter, dstFilter); } -SwsContext *sws_alloc_set_opts(int srcW, int srcH, enum AVPixelFormat srcFormat, - int dstW, int dstH, enum AVPixelFormat dstFormat, - int flags, const double *param) -{ - SwsContext *c; - - if (!(c = sws_alloc_context())) - return NULL; - - c->flags = flags; - c->srcW = srcW; - c->srcH = srcH; - c->dstW = dstW; - c->dstH = dstH; - c->srcFormat = srcFormat; - c->dstFormat = dstFormat; - - if (param) { - c->param[0] = param[0]; - c->param[1] = param[1]; - } - - return c; -} - SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, @@ -2098,9 +2105,9 @@ SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, { SwsContext *c; - c = sws_alloc_set_opts(srcW, srcH, srcFormat, - dstW, dstH, dstFormat, - flags, param); + c = alloc_set_opts(srcW, srcH, srcFormat, + dstW, dstH, dstFormat, + flags, param); if (!c) return NULL; diff --git a/libswscale/version.c b/libswscale/version.c index b165e2563..31135f9cb 100644 --- a/libswscale/version.c +++ b/libswscale/version.c @@ -18,14 +18,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "config.h" -#include "libavutil/avassert.h" #include "swscale.h" #include "version.h" unsigned swscale_version(void) { - av_assert0(LIBSWSCALE_VERSION_MICRO >= 100); + static_assert(LIBSWSCALE_VERSION_MICRO >= 100, "micro version starts at 100"); return LIBSWSCALE_VERSION_INT; } diff --git a/libswscale/version.h b/libswscale/version.h index 4e54701ab..51eb013a2 100644 --- a/libswscale/version.h +++ b/libswscale/version.h @@ -28,7 +28,7 @@ #include "version_major.h" -#define LIBSWSCALE_VERSION_MINOR 1 +#define LIBSWSCALE_VERSION_MINOR 3 #define LIBSWSCALE_VERSION_MICRO 100 #define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ diff --git a/libswscale/vscale.c b/libswscale/vscale.c index 9216112b8..5b3234198 100644 --- a/libswscale/vscale.c +++ b/libswscale/vscale.c @@ -17,6 +17,7 @@ * 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 "swscale_internal.h" typedef struct VScalerContext diff --git a/libswscale/x86/Makefile b/libswscale/x86/Makefile index 68391494b..f00154941 100644 --- a/libswscale/x86/Makefile +++ b/libswscale/x86/Makefile @@ -12,6 +12,7 @@ X86ASM-OBJS += x86/input.o \ x86/output.o \ x86/scale.o \ x86/scale_avx2.o \ + x86/range_convert.o \ x86/rgb_2_rgb.o \ x86/yuv_2_rgb.o \ x86/yuv2yuvX.o \ diff --git a/libswscale/x86/input.asm b/libswscale/x86/input.asm index a197183f1..516e4384b 100644 --- a/libswscale/x86/input.asm +++ b/libswscale/x86/input.asm @@ -23,7 +23,7 @@ %include "libavutil/x86/x86util.asm" -SECTION_RODATA +SECTION_RODATA 32 %define RY 0x20DE %define GY 0x4087 @@ -90,8 +90,12 @@ rgb_UVrnd: times 4 dd 0x400100 ; 128.5 << 15 ; rgba_Vcoeff_ag: times 4 dw 0, GV shuf_rgb_12x4: db 0, 0x80, 1, 0x80, 2, 0x80, 3, 0x80, \ + 6, 0x80, 7, 0x80, 8, 0x80, 9, 0x80, \ + 0, 0x80, 1, 0x80, 2, 0x80, 3, 0x80, \ 6, 0x80, 7, 0x80, 8, 0x80, 9, 0x80 shuf_rgb_3x56: db 2, 0x80, 3, 0x80, 4, 0x80, 5, 0x80, \ + 8, 0x80, 9, 0x80, 10, 0x80, 11, 0x80, \ + 2, 0x80, 3, 0x80, 4, 0x80, 5, 0x80, \ 8, 0x80, 9, 0x80, 10, 0x80, 11, 0x80 pd_65535f: times 8 dd 65535.0 pb_pack_shuffle16le: db 0, 1, 4, 5, \ @@ -134,8 +138,13 @@ SECTION .text %macro RGB24_TO_Y_FN 2-3 cglobal %2 %+ 24ToY, 6, 6, %1, dst, src, u1, u2, w, table %if ARCH_X86_64 +%if mmsize == 32 + vbroadcasti128 m8, [%2_Ycoeff_12x4] + vbroadcasti128 m9, [%2_Ycoeff_3x56] +%else mova m8, [%2_Ycoeff_12x4] mova m9, [%2_Ycoeff_3x56] +%endif %define coeff1 m8 %define coeff2 m9 %else ; x86-32 @@ -165,11 +174,19 @@ cglobal %2 %+ 24ToY, 6, 6, %1, dst, src, u1, u2, w, table %if notcpuflag(ssse3) pxor m7, m7 %endif ; !cpuflag(ssse3) +%if mmsize == 32 + vbroadcasti128 m4, [rgb_Yrnd] +%else mova m4, [rgb_Yrnd] +%endif .loop: %if cpuflag(ssse3) - movu m0, [srcq+0] ; (byte) { Bx, Gx, Rx }[0-3] - movu m2, [srcq+12] ; (byte) { Bx, Gx, Rx }[4-7] + movu xm0, [srcq+0] ; (byte) { Bx, Gx, Rx }[0-3] + movu xm2, [srcq+12] ; (byte) { Bx, Gx, Rx }[4-7] +%if mmsize == 32 + vinserti128 m0, m0, [srcq+24], 1 + vinserti128 m2, m2, [srcq+36], 1 +%endif pshufb m1, m0, shuf_rgb2 ; (word) { R0, B1, G1, R1, R2, B3, G3, R3 } pshufb m0, shuf_rgb1 ; (word) { B0, G0, R0, B1, B2, G2, R2, B3 } pshufb m3, m2, shuf_rgb2 ; (word) { R4, B5, G5, R5, R6, B7, G7, R7 } @@ -212,27 +229,35 @@ cglobal %2 %+ 24ToY, 6, 6, %1, dst, src, u1, u2, w, table %endmacro ; %1 = nr. of XMM registers -; %2 = rgb or bgr -%macro RGB24_TO_UV_FN 2-3 -cglobal %2 %+ 24ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table +; %2 = aligned/unaligned output argument +; %3-4 = rgb or bgr +%macro RGB24_TO_UV_FN 3-4 +cglobal %3 %+ 24ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table %if ARCH_X86_64 - mova m8, [%2_Ucoeff_12x4] - mova m9, [%2_Ucoeff_3x56] - mova m10, [%2_Vcoeff_12x4] - mova m11, [%2_Vcoeff_3x56] +%if mmsize == 32 + vbroadcasti128 m8, [%3_Ucoeff_12x4] + vbroadcasti128 m9, [%3_Ucoeff_3x56] + vbroadcasti128 m10, [%3_Vcoeff_12x4] + vbroadcasti128 m11, [%3_Vcoeff_3x56] +%else + mova m8, [%3_Ucoeff_12x4] + mova m9, [%3_Ucoeff_3x56] + mova m10, [%3_Vcoeff_12x4] + mova m11, [%3_Vcoeff_3x56] +%endif %define coeffU1 m8 %define coeffU2 m9 %define coeffV1 m10 %define coeffV2 m11 %else ; x86-32 -%define coeffU1 [%2_Ucoeff_12x4] -%define coeffU2 [%2_Ucoeff_3x56] -%define coeffV1 [%2_Vcoeff_12x4] -%define coeffV2 [%2_Vcoeff_3x56] +%define coeffU1 [%3_Ucoeff_12x4] +%define coeffU2 [%3_Ucoeff_3x56] +%define coeffV1 [%3_Vcoeff_12x4] +%define coeffV2 [%3_Vcoeff_3x56] %endif ; x86-32/64 -%if ARCH_X86_64 && %0 == 3 - jmp mangle(private_prefix %+ _ %+ %3 %+ 24ToUV %+ SUFFIX).body -%else ; ARCH_X86_64 && %0 == 3 +%if ARCH_X86_64 && %0 == 4 + jmp mangle(private_prefix %+ _ %+ %4 %+ 24ToUV %+ SUFFIX).body +%else ; ARCH_X86_64 && %0 == 4 .body: %if cpuflag(ssse3) mova m7, [shuf_rgb_12x4] @@ -253,14 +278,22 @@ cglobal %2 %+ 24ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table add dstUq, wq add dstVq, wq neg wq +%if mmsize == 32 + vbroadcasti128 m6, [rgb_UVrnd] +%else mova m6, [rgb_UVrnd] +%endif %if notcpuflag(ssse3) pxor m7, m7 %endif .loop: %if cpuflag(ssse3) - movu m0, [srcq+0] ; (byte) { Bx, Gx, Rx }[0-3] - movu m4, [srcq+12] ; (byte) { Bx, Gx, Rx }[4-7] + movu xm0, [srcq+0] ; (byte) { Bx, Gx, Rx }[0-3] + movu xm4, [srcq+12] ; (byte) { Bx, Gx, Rx }[4-7] +%if mmsize == 32 + vinserti128 m0, m0, [srcq+24], 1 + vinserti128 m4, m4, [srcq+36], 1 +%endif pshufb m1, m0, shuf_rgb2 ; (word) { R0, B1, G1, R1, R2, B3, G3, R3 } pshufb m0, shuf_rgb1 ; (word) { B0, G0, R0, B1, B2, G2, R2, B3 } %else ; !cpuflag(ssse3) @@ -309,40 +342,53 @@ cglobal %2 %+ 24ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table psrad m4, 9 packssdw m0, m1 ; (word) { U[0-7] } packssdw m2, m4 ; (word) { V[0-7] } - mova [dstUq+wq], m0 - mova [dstVq+wq], m2 + mov%2 [dstUq+wq], m0 + mov%2 [dstVq+wq], m2 add wq, mmsize jl .loop RET -%endif ; ARCH_X86_64 && %0 == 3 +%endif ; ARCH_X86_64 && %0 == 4 %endmacro ; %1 = nr. of XMM registers for rgb-to-Y func ; %2 = nr. of XMM registers for rgb-to-UV func -%macro RGB24_FUNCS 2 +; %3 = aligned/unaligned output argument +%macro RGB24_FUNCS 3 RGB24_TO_Y_FN %1, rgb RGB24_TO_Y_FN %1, bgr, rgb -RGB24_TO_UV_FN %2, rgb -RGB24_TO_UV_FN %2, bgr, rgb +RGB24_TO_UV_FN %2, %3, rgb +RGB24_TO_UV_FN %2, %3, bgr, rgb %endmacro INIT_XMM sse2 -RGB24_FUNCS 10, 12 +RGB24_FUNCS 10, 12, a INIT_XMM ssse3 -RGB24_FUNCS 11, 13 +RGB24_FUNCS 11, 13, a %if HAVE_AVX_EXTERNAL INIT_XMM avx -RGB24_FUNCS 11, 13 +RGB24_FUNCS 11, 13, a +%endif + +%if ARCH_X86_64 +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +RGB24_FUNCS 11, 13, u +%endif %endif ; %1 = nr. of XMM registers ; %2-5 = rgba, bgra, argb or abgr (in individual characters) %macro RGB32_TO_Y_FN 5-6 cglobal %2%3%4%5 %+ ToY, 6, 6, %1, dst, src, u1, u2, w, table +%if mmsize == 32 + vbroadcasti128 m5, [rgba_Ycoeff_%2%4] + vbroadcasti128 m6, [rgba_Ycoeff_%3%5] +%else mova m5, [rgba_Ycoeff_%2%4] mova m6, [rgba_Ycoeff_%3%5] +%endif %if %0 == 6 jmp mangle(private_prefix %+ _ %+ %6 %+ ToY %+ SUFFIX).body %else ; %0 == 6 @@ -355,13 +401,21 @@ cglobal %2%3%4%5 %+ ToY, 6, 6, %1, dst, src, u1, u2, w, table lea srcq, [srcq+wq*2] add dstq, wq neg wq +%if mmsize == 32 + vbroadcasti128 m4, [rgb_Yrnd] +%else mova m4, [rgb_Yrnd] +%endif pcmpeqb m7, m7 psrlw m7, 8 ; (word) { 0x00ff } x4 .loop: ; FIXME check alignment and use mova - movu m0, [srcq+wq*2+0] ; (byte) { Bx, Gx, Rx, xx }[0-3] - movu m2, [srcq+wq*2+mmsize] ; (byte) { Bx, Gx, Rx, xx }[4-7] + movu xm0, [srcq+wq*2+0] ; (byte) { Bx, Gx, Rx, xx }[0-3] + movu xm2, [srcq+wq*2+16] ; (byte) { Bx, Gx, Rx, xx }[4-7] +%if mmsize == 32 + vinserti128 m0, m0, [srcq+wq*2+32], 1 + vinserti128 m2, m2, [srcq+wq*2+48], 1 +%endif DEINTB 1, 0, 3, 2, 7 ; (word) { Gx, xx (m0/m2) or Bx, Rx (m1/m3) }[0-3]/[4-7] pmaddwd m1, m5 ; (dword) { Bx*BY + Rx*RY }[0-3] pmaddwd m0, m6 ; (dword) { Gx*GY }[0-3] @@ -382,6 +436,7 @@ cglobal %2%3%4%5 %+ ToY, 6, 6, %1, dst, src, u1, u2, w, table add srcq, 2*mmsize - 2 add dstq, mmsize - 1 .loop2: +INIT_XMM cpuname movd m0, [srcq+wq*2+0] ; (byte) { Bx, Gx, Rx, xx }[0-3] DEINTB 1, 0, 3, 2, 7 ; (word) { Gx, xx (m0/m2) or Bx, Rx (m1/m3) }[0-3]/[4-7] pmaddwd m1, m5 ; (dword) { Bx*BY + Rx*RY }[0-3] @@ -394,32 +449,43 @@ cglobal %2%3%4%5 %+ ToY, 6, 6, %1, dst, src, u1, u2, w, table add wq, 2 jl .loop2 .end: +%if cpuflag(avx2) +INIT_YMM cpuname +%endif RET %endif ; %0 == 3 %endmacro ; %1 = nr. of XMM registers -; %2-5 = rgba, bgra, argb or abgr (in individual characters) -%macro RGB32_TO_UV_FN 5-6 -cglobal %2%3%4%5 %+ ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table +; %2 = aligned/unaligned output argument +; %3-6 = rgba, bgra, argb or abgr (in individual characters) +%macro RGB32_TO_UV_FN 6-7 +cglobal %3%4%5%6 %+ ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table %if ARCH_X86_64 - mova m8, [rgba_Ucoeff_%2%4] - mova m9, [rgba_Ucoeff_%3%5] - mova m10, [rgba_Vcoeff_%2%4] - mova m11, [rgba_Vcoeff_%3%5] +%if mmsize == 32 + vbroadcasti128 m8, [rgba_Ucoeff_%3%5] + vbroadcasti128 m9, [rgba_Ucoeff_%4%6] + vbroadcasti128 m10, [rgba_Vcoeff_%3%5] + vbroadcasti128 m11, [rgba_Vcoeff_%4%6] +%else + mova m8, [rgba_Ucoeff_%3%5] + mova m9, [rgba_Ucoeff_%4%6] + mova m10, [rgba_Vcoeff_%3%5] + mova m11, [rgba_Vcoeff_%4%6] +%endif %define coeffU1 m8 %define coeffU2 m9 %define coeffV1 m10 %define coeffV2 m11 %else ; x86-32 -%define coeffU1 [rgba_Ucoeff_%2%4] -%define coeffU2 [rgba_Ucoeff_%3%5] -%define coeffV1 [rgba_Vcoeff_%2%4] -%define coeffV2 [rgba_Vcoeff_%3%5] +%define coeffU1 [rgba_Ucoeff_%3%5] +%define coeffU2 [rgba_Ucoeff_%4%6] +%define coeffV1 [rgba_Vcoeff_%3%5] +%define coeffV2 [rgba_Vcoeff_%4%6] %endif ; x86-64/32 -%if ARCH_X86_64 && %0 == 6 - jmp mangle(private_prefix %+ _ %+ %6 %+ ToUV %+ SUFFIX).body -%else ; ARCH_X86_64 && %0 == 6 +%if ARCH_X86_64 && %0 == 7 + jmp mangle(private_prefix %+ _ %+ %7 %+ ToUV %+ SUFFIX).body +%else ; ARCH_X86_64 && %0 == 7 .body: %if ARCH_X86_64 movsxd wq, dword r5m @@ -434,11 +500,19 @@ cglobal %2%3%4%5 %+ ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table neg wq pcmpeqb m7, m7 psrlw m7, 8 ; (word) { 0x00ff } x4 +%if mmsize == 32 + vbroadcasti128 m6, [rgb_UVrnd] +%else mova m6, [rgb_UVrnd] +%endif .loop: ; FIXME check alignment and use mova - movu m0, [srcq+wq*2+0] ; (byte) { Bx, Gx, Rx, xx }[0-3] - movu m4, [srcq+wq*2+mmsize] ; (byte) { Bx, Gx, Rx, xx }[4-7] + movu xm0, [srcq+wq*2+0] ; (byte) { Bx, Gx, Rx, xx }[0-3] + movu xm4, [srcq+wq*2+16] ; (byte) { Bx, Gx, Rx, xx }[4-7] +%if mmsize == 32 + vinserti128 m0, m0, [srcq+wq*2+32], 1 + vinserti128 m4, m4, [srcq+wq*2+48], 1 +%endif DEINTB 1, 0, 5, 4, 7 ; (word) { Gx, xx (m0/m4) or Bx, Rx (m1/m5) }[0-3]/[4-7] pmaddwd m3, m1, coeffV1 ; (dword) { Bx*BV + Rx*RV }[0-3] pmaddwd m2, m0, coeffV2 ; (dword) { Gx*GV }[0-3] @@ -462,8 +536,9 @@ cglobal %2%3%4%5 %+ ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table psrad m1, 9 packssdw m0, m4 ; (word) { U[0-7] } packssdw m2, m1 ; (word) { V[0-7] } - mova [dstUq+wq], m0 - mova [dstVq+wq], m2 + ; FIXME check alignment and use mova + mov%2 [dstUq+wq], m0 + mov%2 [dstVq+wq], m2 add wq, mmsize jl .loop sub wq, mmsize - 1 @@ -472,6 +547,7 @@ cglobal %2%3%4%5 %+ ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table add dstUq, mmsize - 1 add dstVq, mmsize - 1 .loop2: +INIT_XMM cpuname movd m0, [srcq+wq*2] ; (byte) { Bx, Gx, Rx, xx }[0-3] DEINTB 1, 0, 5, 4, 7 ; (word) { Gx, xx (m0/m4) or Bx, Rx (m1/m5) }[0-3]/[4-7] pmaddwd m3, m1, coeffV1 ; (dword) { Bx*BV + Rx*RV }[0-3] @@ -491,30 +567,41 @@ cglobal %2%3%4%5 %+ ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table add wq, 2 jl .loop2 .end: +%if cpuflag(avx2) +INIT_YMM cpuname +%endif RET -%endif ; ARCH_X86_64 && %0 == 3 +%endif ; ARCH_X86_64 && %0 == 7 %endmacro ; %1 = nr. of XMM registers for rgb-to-Y func ; %2 = nr. of XMM registers for rgb-to-UV func -%macro RGB32_FUNCS 2 +; %3 = aligned/unaligned output argument +%macro RGB32_FUNCS 3 RGB32_TO_Y_FN %1, r, g, b, a RGB32_TO_Y_FN %1, b, g, r, a, rgba RGB32_TO_Y_FN %1, a, r, g, b, rgba RGB32_TO_Y_FN %1, a, b, g, r, rgba -RGB32_TO_UV_FN %2, r, g, b, a -RGB32_TO_UV_FN %2, b, g, r, a, rgba -RGB32_TO_UV_FN %2, a, r, g, b, rgba -RGB32_TO_UV_FN %2, a, b, g, r, rgba +RGB32_TO_UV_FN %2, %3, r, g, b, a +RGB32_TO_UV_FN %2, %3, b, g, r, a, rgba +RGB32_TO_UV_FN %2, %3, a, r, g, b, rgba +RGB32_TO_UV_FN %2, %3, a, b, g, r, rgba %endmacro INIT_XMM sse2 -RGB32_FUNCS 8, 12 +RGB32_FUNCS 8, 12, a %if HAVE_AVX_EXTERNAL INIT_XMM avx -RGB32_FUNCS 8, 12 +RGB32_FUNCS 8, 12, a +%endif + +%if ARCH_X86_64 +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +RGB32_FUNCS 8, 12, u +%endif %endif ;----------------------------------------------------------------------------- @@ -649,11 +736,11 @@ cglobal %2ToUV, 4, 5, %1, dstU, dstV, unused, src, w packuswb m2, m3 ; (byte) { U0, ..., U15 } packuswb m0, m1 ; (byte) { V0, ..., V15 } %ifidn %2, nv12 - mova [dstUq+wq], m2 - mova [dstVq+wq], m0 + mov%1 [dstUq+wq], m2 + mov%1 [dstVq+wq], m0 %else ; nv21 - mova [dstVq+wq], m2 - mova [dstUq+wq], m0 + mov%1 [dstVq+wq], m2 + mov%1 [dstUq+wq], m0 %endif ; nv12/21 add wq, mmsize jl .loop_%1 @@ -663,15 +750,18 @@ cglobal %2ToUV, 4, 5, %1, dstU, dstV, unused, src, w ; %1 = nr. of XMM registers ; %2 = nv12 or nv21 %macro NVXX_TO_UV_FN 2 -cglobal %2ToUV, 4, 5, %1, dstU, dstV, unused, src, w +cglobal %2ToUV, 4, 5, %1, dstU, dstV, tmp, src, w %if ARCH_X86_64 movsxd wq, dword r5m %else ; x86-32 mov wq, r5m %endif + mov tmpq, srcq + or tmpq, dstUq + or tmpq, dstVq add dstUq, wq add dstVq, wq - test srcq, 15 + test tmpq, 15 lea srcq, [srcq+wq*2] pcmpeqb m5, m5 ; (byte) { 0xff } x 16 psrlw m5, 8 ; (word) { 0x00ff } x 8 diff --git a/libswscale/x86/range_convert.asm b/libswscale/x86/range_convert.asm new file mode 100644 index 000000000..97c752544 --- /dev/null +++ b/libswscale/x86/range_convert.asm @@ -0,0 +1,136 @@ +;****************************************************************************** +;* Copyright (c) 2024 Ramiro Polla +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General 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 + +chr_to_mult: times 4 dw 4663, 0 +chr_to_offset: times 4 dd -9289992 +%define chr_to_shift 12 + +chr_from_mult: times 4 dw 1799, 0 +chr_from_offset: times 4 dd 4081085 +%define chr_from_shift 11 + +lum_to_mult: times 4 dw 19077, 0 +lum_to_offset: times 4 dd -39057361 +%define lum_to_shift 14 + +lum_from_mult: times 4 dw 14071, 0 +lum_from_offset: times 4 dd 33561947 +%define lum_from_shift 14 + +SECTION .text + +; NOTE: there is no need to clamp the input when converting to jpeg range +; (like we do in the C code) because packssdw will saturate the output. + +;----------------------------------------------------------------------------- +; lumConvertRange +; +; void ff_lumRangeToJpeg_(int16_t *dst, int width); +; void ff_lumRangeFromJpeg_(int16_t *dst, int width); +; +;----------------------------------------------------------------------------- + +%macro LUMCONVERTRANGE 4 +cglobal %1, 2, 2, 5, dst, width + shl widthd, 1 + VBROADCASTI128 m2, [%2] + VBROADCASTI128 m3, [%3] + pxor m4, m4 + add dstq, widthq + neg widthq +.loop: + movu m0, [dstq+widthq] + punpckhwd m1, m0, m4 + punpcklwd m0, m4 + pmaddwd m0, m2 + pmaddwd m1, m2 + paddd m0, m3 + paddd m1, m3 + psrad m0, %4 + psrad m1, %4 + packssdw m0, m1 + movu [dstq+widthq], m0 + add widthq, mmsize + jl .loop + RET +%endmacro + +;----------------------------------------------------------------------------- +; chrConvertRange +; +; void ff_chrRangeToJpeg_(int16_t *dstU, int16_t *dstV, int width); +; void ff_chrRangeFromJpeg_(int16_t *dstU, int16_t *dstV, int width); +; +;----------------------------------------------------------------------------- + +%macro CHRCONVERTRANGE 4 +cglobal %1, 3, 3, 7, dstU, dstV, width + shl widthd, 1 + VBROADCASTI128 m4, [%2] + VBROADCASTI128 m5, [%3] + pxor m6, m6 + add dstUq, widthq + add dstVq, widthq + neg widthq +.loop: + movu m0, [dstUq+widthq] + movu m2, [dstVq+widthq] + punpckhwd m1, m0, m6 + punpckhwd m3, m2, m6 + punpcklwd m0, m6 + punpcklwd m2, m6 + pmaddwd m0, m4 + pmaddwd m1, m4 + pmaddwd m2, m4 + pmaddwd m3, m4 + paddd m0, m5 + paddd m1, m5 + paddd m2, m5 + paddd m3, m5 + psrad m0, %4 + psrad m1, %4 + psrad m2, %4 + psrad m3, %4 + packssdw m0, m1 + packssdw m2, m3 + movu [dstUq+widthq], m0 + movu [dstVq+widthq], m2 + add widthq, mmsize + jl .loop + RET +%endmacro + +INIT_XMM sse2 +LUMCONVERTRANGE lumRangeToJpeg, lum_to_mult, lum_to_offset, lum_to_shift +CHRCONVERTRANGE chrRangeToJpeg, chr_to_mult, chr_to_offset, chr_to_shift +LUMCONVERTRANGE lumRangeFromJpeg, lum_from_mult, lum_from_offset, lum_from_shift +CHRCONVERTRANGE chrRangeFromJpeg, chr_from_mult, chr_from_offset, chr_from_shift + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +LUMCONVERTRANGE lumRangeToJpeg, lum_to_mult, lum_to_offset, lum_to_shift +CHRCONVERTRANGE chrRangeToJpeg, chr_to_mult, chr_to_offset, chr_to_shift +LUMCONVERTRANGE lumRangeFromJpeg, lum_from_mult, lum_from_offset, lum_from_shift +CHRCONVERTRANGE chrRangeFromJpeg, chr_from_mult, chr_from_offset, chr_from_shift +%endif diff --git a/libswscale/x86/rgb2rgb.c b/libswscale/x86/rgb2rgb.c index b325e5dbd..494302334 100644 --- a/libswscale/x86/rgb2rgb.c +++ b/libswscale/x86/rgb2rgb.c @@ -37,6 +37,7 @@ #include "libswscale/swscale_internal.h" #if HAVE_INLINE_ASM +#include "libavutil/x86/asm.h" DECLARE_ASM_CONST(8, uint64_t, mmx_ff) = 0x00000000000000FFULL; DECLARE_ASM_CONST(8, uint64_t, mmx_null) = 0x0000000000000000ULL; @@ -83,29 +84,2255 @@ DECLARE_ALIGNED(8, extern const uint64_t, ff_bgr2UVOffset); #define RV ((int)( 0.439*(1<>1)&0x7FE07FE0) | (x&0x001F001F); + s+=4; + d+=4; + } + if (s < end) { + register uint16_t x= *((const uint16_t*)s); + *((uint16_t *)d) = ((x>>1)&0x7FE0) | (x&0x001F); + } +} + +static inline void rgb32to16_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint8_t *s = src; + const uint8_t *end; + const uint8_t *mm_end; + uint16_t *d = (uint16_t *)dst; + end = s + src_size; + mm_end = end - 15; + __asm__ volatile( + "movq %3, %%mm5 \n\t" + "movq %4, %%mm6 \n\t" + "movq %5, %%mm7 \n\t" + "jmp 2f \n\t" + ".p2align 4 \n\t" + "1: \n\t" + PREFETCH" 32(%1) \n\t" + "movd (%1), %%mm0 \n\t" + "movd 4(%1), %%mm3 \n\t" + "punpckldq 8(%1), %%mm0 \n\t" + "punpckldq 12(%1), %%mm3 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm3, %%mm4 \n\t" + "pand %%mm6, %%mm0 \n\t" + "pand %%mm6, %%mm3 \n\t" + "pmaddwd %%mm7, %%mm0 \n\t" + "pmaddwd %%mm7, %%mm3 \n\t" + "pand %%mm5, %%mm1 \n\t" + "pand %%mm5, %%mm4 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm4, %%mm3 \n\t" + "psrld $5, %%mm0 \n\t" + "pslld $11, %%mm3 \n\t" + "por %%mm3, %%mm0 \n\t" + MOVNTQ" %%mm0, (%0) \n\t" + "add $16, %1 \n\t" + "add $8, %0 \n\t" + "2: \n\t" + "cmp %2, %1 \n\t" + " jb 1b \n\t" + : "+r" (d), "+r"(s) + : "r" (mm_end), "m" (mask3216g), "m" (mask3216br), "m" (mul3216) + ); + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + register int rgb = *(const uint32_t*)s; s += 4; + *d++ = ((rgb&0xFF)>>3) + ((rgb&0xFC00)>>5) + ((rgb&0xF80000)>>8); + } +} + +static inline void rgb32tobgr16_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint8_t *s = src; + const uint8_t *end; + const uint8_t *mm_end; + uint16_t *d = (uint16_t *)dst; + end = s + src_size; + __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); + __asm__ volatile( + "movq %0, %%mm7 \n\t" + "movq %1, %%mm6 \n\t" + ::"m"(red_16mask),"m"(green_16mask)); + mm_end = end - 15; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movd (%1), %%mm0 \n\t" + "movd 4(%1), %%mm3 \n\t" + "punpckldq 8(%1), %%mm0 \n\t" + "punpckldq 12(%1), %%mm3 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm0, %%mm2 \n\t" + "movq %%mm3, %%mm4 \n\t" + "movq %%mm3, %%mm5 \n\t" + "psllq $8, %%mm0 \n\t" + "psllq $8, %%mm3 \n\t" + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm3 \n\t" + "psrlq $5, %%mm1 \n\t" + "psrlq $5, %%mm4 \n\t" + "pand %%mm6, %%mm1 \n\t" + "pand %%mm6, %%mm4 \n\t" + "psrlq $19, %%mm2 \n\t" + "psrlq $19, %%mm5 \n\t" + "pand %2, %%mm2 \n\t" + "pand %2, %%mm5 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm2, %%mm0 \n\t" + "por %%mm5, %%mm3 \n\t" + "psllq $16, %%mm3 \n\t" + "por %%mm3, %%mm0 \n\t" + MOVNTQ" %%mm0, (%0) \n\t" + :: "r"(d),"r"(s),"m"(blue_16mask):"memory"); + d += 4; + s += 16; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + register int rgb = *(const uint32_t*)s; s += 4; + *d++ = ((rgb&0xF8)<<8) + ((rgb&0xFC00)>>5) + ((rgb&0xF80000)>>19); + } +} + +static inline void rgb32to15_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint8_t *s = src; + const uint8_t *end; + const uint8_t *mm_end; + uint16_t *d = (uint16_t *)dst; + end = s + src_size; + mm_end = end - 15; + __asm__ volatile( + "movq %3, %%mm5 \n\t" + "movq %4, %%mm6 \n\t" + "movq %5, %%mm7 \n\t" + "jmp 2f \n\t" + ".p2align 4 \n\t" + "1: \n\t" + PREFETCH" 32(%1) \n\t" + "movd (%1), %%mm0 \n\t" + "movd 4(%1), %%mm3 \n\t" + "punpckldq 8(%1), %%mm0 \n\t" + "punpckldq 12(%1), %%mm3 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm3, %%mm4 \n\t" + "pand %%mm6, %%mm0 \n\t" + "pand %%mm6, %%mm3 \n\t" + "pmaddwd %%mm7, %%mm0 \n\t" + "pmaddwd %%mm7, %%mm3 \n\t" + "pand %%mm5, %%mm1 \n\t" + "pand %%mm5, %%mm4 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm4, %%mm3 \n\t" + "psrld $6, %%mm0 \n\t" + "pslld $10, %%mm3 \n\t" + "por %%mm3, %%mm0 \n\t" + MOVNTQ" %%mm0, (%0) \n\t" + "add $16, %1 \n\t" + "add $8, %0 \n\t" + "2: \n\t" + "cmp %2, %1 \n\t" + " jb 1b \n\t" + : "+r" (d), "+r"(s) + : "r" (mm_end), "m" (mask3215g), "m" (mask3216br), "m" (mul3215) + ); + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + register int rgb = *(const uint32_t*)s; s += 4; + *d++ = ((rgb&0xFF)>>3) + ((rgb&0xF800)>>6) + ((rgb&0xF80000)>>9); + } +} + +static inline void rgb32tobgr15_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint8_t *s = src; + const uint8_t *end; + const uint8_t *mm_end; + uint16_t *d = (uint16_t *)dst; + end = s + src_size; + __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); + __asm__ volatile( + "movq %0, %%mm7 \n\t" + "movq %1, %%mm6 \n\t" + ::"m"(red_15mask),"m"(green_15mask)); + mm_end = end - 15; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movd (%1), %%mm0 \n\t" + "movd 4(%1), %%mm3 \n\t" + "punpckldq 8(%1), %%mm0 \n\t" + "punpckldq 12(%1), %%mm3 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm0, %%mm2 \n\t" + "movq %%mm3, %%mm4 \n\t" + "movq %%mm3, %%mm5 \n\t" + "psllq $7, %%mm0 \n\t" + "psllq $7, %%mm3 \n\t" + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm3 \n\t" + "psrlq $6, %%mm1 \n\t" + "psrlq $6, %%mm4 \n\t" + "pand %%mm6, %%mm1 \n\t" + "pand %%mm6, %%mm4 \n\t" + "psrlq $19, %%mm2 \n\t" + "psrlq $19, %%mm5 \n\t" + "pand %2, %%mm2 \n\t" + "pand %2, %%mm5 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm2, %%mm0 \n\t" + "por %%mm5, %%mm3 \n\t" + "psllq $16, %%mm3 \n\t" + "por %%mm3, %%mm0 \n\t" + MOVNTQ" %%mm0, (%0) \n\t" + ::"r"(d),"r"(s),"m"(blue_15mask):"memory"); + d += 4; + s += 16; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + register int rgb = *(const uint32_t*)s; s += 4; + *d++ = ((rgb&0xF8)<<7) + ((rgb&0xF800)>>6) + ((rgb&0xF80000)>>19); + } +} + +static inline void rgb24tobgr16_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint8_t *s = src; + const uint8_t *end; + const uint8_t *mm_end; + uint16_t *d = (uint16_t *)dst; + end = s + src_size; + __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); + __asm__ volatile( + "movq %0, %%mm7 \n\t" + "movq %1, %%mm6 \n\t" + ::"m"(red_16mask),"m"(green_16mask)); + mm_end = end - 11; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movd (%1), %%mm0 \n\t" + "movd 3(%1), %%mm3 \n\t" + "punpckldq 6(%1), %%mm0 \n\t" + "punpckldq 9(%1), %%mm3 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm0, %%mm2 \n\t" + "movq %%mm3, %%mm4 \n\t" + "movq %%mm3, %%mm5 \n\t" + "psrlq $3, %%mm0 \n\t" + "psrlq $3, %%mm3 \n\t" + "pand %2, %%mm0 \n\t" + "pand %2, %%mm3 \n\t" + "psrlq $5, %%mm1 \n\t" + "psrlq $5, %%mm4 \n\t" + "pand %%mm6, %%mm1 \n\t" + "pand %%mm6, %%mm4 \n\t" + "psrlq $8, %%mm2 \n\t" + "psrlq $8, %%mm5 \n\t" + "pand %%mm7, %%mm2 \n\t" + "pand %%mm7, %%mm5 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm2, %%mm0 \n\t" + "por %%mm5, %%mm3 \n\t" + "psllq $16, %%mm3 \n\t" + "por %%mm3, %%mm0 \n\t" + MOVNTQ" %%mm0, (%0) \n\t" + ::"r"(d),"r"(s),"m"(blue_16mask):"memory"); + d += 4; + s += 12; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + const int b = *s++; + const int g = *s++; + const int r = *s++; + *d++ = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8); + } +} + +static inline void rgb24to16_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint8_t *s = src; + const uint8_t *end; + const uint8_t *mm_end; + uint16_t *d = (uint16_t *)dst; + end = s + src_size; + __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); + __asm__ volatile( + "movq %0, %%mm7 \n\t" + "movq %1, %%mm6 \n\t" + ::"m"(red_16mask),"m"(green_16mask)); + mm_end = end - 15; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movd (%1), %%mm0 \n\t" + "movd 3(%1), %%mm3 \n\t" + "punpckldq 6(%1), %%mm0 \n\t" + "punpckldq 9(%1), %%mm3 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm0, %%mm2 \n\t" + "movq %%mm3, %%mm4 \n\t" + "movq %%mm3, %%mm5 \n\t" + "psllq $8, %%mm0 \n\t" + "psllq $8, %%mm3 \n\t" + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm3 \n\t" + "psrlq $5, %%mm1 \n\t" + "psrlq $5, %%mm4 \n\t" + "pand %%mm6, %%mm1 \n\t" + "pand %%mm6, %%mm4 \n\t" + "psrlq $19, %%mm2 \n\t" + "psrlq $19, %%mm5 \n\t" + "pand %2, %%mm2 \n\t" + "pand %2, %%mm5 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm2, %%mm0 \n\t" + "por %%mm5, %%mm3 \n\t" + "psllq $16, %%mm3 \n\t" + "por %%mm3, %%mm0 \n\t" + MOVNTQ" %%mm0, (%0) \n\t" + ::"r"(d),"r"(s),"m"(blue_16mask):"memory"); + d += 4; + s += 12; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + const int r = *s++; + const int g = *s++; + const int b = *s++; + *d++ = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8); + } +} + +static inline void rgb24tobgr15_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint8_t *s = src; + const uint8_t *end; + const uint8_t *mm_end; + uint16_t *d = (uint16_t *)dst; + end = s + src_size; + __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); + __asm__ volatile( + "movq %0, %%mm7 \n\t" + "movq %1, %%mm6 \n\t" + ::"m"(red_15mask),"m"(green_15mask)); + mm_end = end - 11; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movd (%1), %%mm0 \n\t" + "movd 3(%1), %%mm3 \n\t" + "punpckldq 6(%1), %%mm0 \n\t" + "punpckldq 9(%1), %%mm3 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm0, %%mm2 \n\t" + "movq %%mm3, %%mm4 \n\t" + "movq %%mm3, %%mm5 \n\t" + "psrlq $3, %%mm0 \n\t" + "psrlq $3, %%mm3 \n\t" + "pand %2, %%mm0 \n\t" + "pand %2, %%mm3 \n\t" + "psrlq $6, %%mm1 \n\t" + "psrlq $6, %%mm4 \n\t" + "pand %%mm6, %%mm1 \n\t" + "pand %%mm6, %%mm4 \n\t" + "psrlq $9, %%mm2 \n\t" + "psrlq $9, %%mm5 \n\t" + "pand %%mm7, %%mm2 \n\t" + "pand %%mm7, %%mm5 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm2, %%mm0 \n\t" + "por %%mm5, %%mm3 \n\t" + "psllq $16, %%mm3 \n\t" + "por %%mm3, %%mm0 \n\t" + MOVNTQ" %%mm0, (%0) \n\t" + ::"r"(d),"r"(s),"m"(blue_15mask):"memory"); + d += 4; + s += 12; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + const int b = *s++; + const int g = *s++; + const int r = *s++; + *d++ = (b>>3) | ((g&0xF8)<<2) | ((r&0xF8)<<7); + } +} + +static inline void rgb24to15_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint8_t *s = src; + const uint8_t *end; + const uint8_t *mm_end; + uint16_t *d = (uint16_t *)dst; + end = s + src_size; + __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); + __asm__ volatile( + "movq %0, %%mm7 \n\t" + "movq %1, %%mm6 \n\t" + ::"m"(red_15mask),"m"(green_15mask)); + mm_end = end - 15; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movd (%1), %%mm0 \n\t" + "movd 3(%1), %%mm3 \n\t" + "punpckldq 6(%1), %%mm0 \n\t" + "punpckldq 9(%1), %%mm3 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm0, %%mm2 \n\t" + "movq %%mm3, %%mm4 \n\t" + "movq %%mm3, %%mm5 \n\t" + "psllq $7, %%mm0 \n\t" + "psllq $7, %%mm3 \n\t" + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm3 \n\t" + "psrlq $6, %%mm1 \n\t" + "psrlq $6, %%mm4 \n\t" + "pand %%mm6, %%mm1 \n\t" + "pand %%mm6, %%mm4 \n\t" + "psrlq $19, %%mm2 \n\t" + "psrlq $19, %%mm5 \n\t" + "pand %2, %%mm2 \n\t" + "pand %2, %%mm5 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm2, %%mm0 \n\t" + "por %%mm5, %%mm3 \n\t" + "psllq $16, %%mm3 \n\t" + "por %%mm3, %%mm0 \n\t" + MOVNTQ" %%mm0, (%0) \n\t" + ::"r"(d),"r"(s),"m"(blue_15mask):"memory"); + d += 4; + s += 12; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + const int r = *s++; + const int g = *s++; + const int b = *s++; + *d++ = (b>>3) | ((g&0xF8)<<2) | ((r&0xF8)<<7); + } +} + +static inline void rgb15tobgr24_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint16_t *end; + const uint16_t *mm_end; + uint8_t *d = dst; + const uint16_t *s = (const uint16_t*)src; + end = s + src_size/2; + __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); + mm_end = end - 7; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movq (%1), %%mm0 \n\t" + "movq (%1), %%mm1 \n\t" + "movq (%1), %%mm2 \n\t" + "pand %2, %%mm0 \n\t" + "pand %3, %%mm1 \n\t" + "pand %4, %%mm2 \n\t" + "psllq $5, %%mm0 \n\t" + "pmulhw "MANGLE(mul15_mid)", %%mm0 \n\t" + "pmulhw "MANGLE(mul15_mid)", %%mm1 \n\t" + "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" + "movq %%mm0, %%mm3 \n\t" + "movq %%mm1, %%mm4 \n\t" + "movq %%mm2, %%mm5 \n\t" + "punpcklwd %5, %%mm0 \n\t" + "punpcklwd %5, %%mm1 \n\t" + "punpcklwd %5, %%mm2 \n\t" + "punpckhwd %5, %%mm3 \n\t" + "punpckhwd %5, %%mm4 \n\t" + "punpckhwd %5, %%mm5 \n\t" + "psllq $8, %%mm1 \n\t" + "psllq $16, %%mm2 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm2, %%mm0 \n\t" + "psllq $8, %%mm4 \n\t" + "psllq $16, %%mm5 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm5, %%mm3 \n\t" + + "movq %%mm0, %%mm6 \n\t" + "movq %%mm3, %%mm7 \n\t" + + "movq 8(%1), %%mm0 \n\t" + "movq 8(%1), %%mm1 \n\t" + "movq 8(%1), %%mm2 \n\t" + "pand %2, %%mm0 \n\t" + "pand %3, %%mm1 \n\t" + "pand %4, %%mm2 \n\t" + "psllq $5, %%mm0 \n\t" + "pmulhw "MANGLE(mul15_mid)", %%mm0 \n\t" + "pmulhw "MANGLE(mul15_mid)", %%mm1 \n\t" + "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" + "movq %%mm0, %%mm3 \n\t" + "movq %%mm1, %%mm4 \n\t" + "movq %%mm2, %%mm5 \n\t" + "punpcklwd %5, %%mm0 \n\t" + "punpcklwd %5, %%mm1 \n\t" + "punpcklwd %5, %%mm2 \n\t" + "punpckhwd %5, %%mm3 \n\t" + "punpckhwd %5, %%mm4 \n\t" + "punpckhwd %5, %%mm5 \n\t" + "psllq $8, %%mm1 \n\t" + "psllq $16, %%mm2 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm2, %%mm0 \n\t" + "psllq $8, %%mm4 \n\t" + "psllq $16, %%mm5 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm5, %%mm3 \n\t" + + :"=m"(*d) + :"r"(s),"m"(mask15b),"m"(mask15g),"m"(mask15r), "m"(mmx_null) + NAMED_CONSTRAINTS_ADD(mul15_mid,mul15_hi) + :"memory"); + /* borrowed 32 to 24 */ + __asm__ volatile( + "movq %%mm0, %%mm4 \n\t" + "movq %%mm3, %%mm5 \n\t" + "movq %%mm6, %%mm0 \n\t" + "movq %%mm7, %%mm1 \n\t" + + "movq %%mm4, %%mm6 \n\t" + "movq %%mm5, %%mm7 \n\t" + "movq %%mm0, %%mm2 \n\t" + "movq %%mm1, %%mm3 \n\t" + + STORE_BGR24_MMX + + :: "r"(d), "m"(*s) + NAMED_CONSTRAINTS_ADD(mask24l,mask24h) + :"memory"); + d += 24; + s += 8; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + register uint16_t bgr; + bgr = *s++; + *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2); + *d++ = ((bgr&0x3E0)>>2) | ((bgr&0x3E0)>>7); + *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); + } +} + +static inline void rgb16tobgr24_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint16_t *end; + const uint16_t *mm_end; + uint8_t *d = (uint8_t *)dst; + const uint16_t *s = (const uint16_t *)src; + end = s + src_size/2; + __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); + mm_end = end - 7; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movq (%1), %%mm0 \n\t" + "movq (%1), %%mm1 \n\t" + "movq (%1), %%mm2 \n\t" + "pand %2, %%mm0 \n\t" + "pand %3, %%mm1 \n\t" + "pand %4, %%mm2 \n\t" + "psllq $5, %%mm0 \n\t" + "psrlq $1, %%mm2 \n\t" + "pmulhw "MANGLE(mul15_mid)", %%mm0 \n\t" + "pmulhw "MANGLE(mul16_mid)", %%mm1 \n\t" + "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" + "movq %%mm0, %%mm3 \n\t" + "movq %%mm1, %%mm4 \n\t" + "movq %%mm2, %%mm5 \n\t" + "punpcklwd %5, %%mm0 \n\t" + "punpcklwd %5, %%mm1 \n\t" + "punpcklwd %5, %%mm2 \n\t" + "punpckhwd %5, %%mm3 \n\t" + "punpckhwd %5, %%mm4 \n\t" + "punpckhwd %5, %%mm5 \n\t" + "psllq $8, %%mm1 \n\t" + "psllq $16, %%mm2 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm2, %%mm0 \n\t" + "psllq $8, %%mm4 \n\t" + "psllq $16, %%mm5 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm5, %%mm3 \n\t" + + "movq %%mm0, %%mm6 \n\t" + "movq %%mm3, %%mm7 \n\t" + + "movq 8(%1), %%mm0 \n\t" + "movq 8(%1), %%mm1 \n\t" + "movq 8(%1), %%mm2 \n\t" + "pand %2, %%mm0 \n\t" + "pand %3, %%mm1 \n\t" + "pand %4, %%mm2 \n\t" + "psllq $5, %%mm0 \n\t" + "psrlq $1, %%mm2 \n\t" + "pmulhw "MANGLE(mul15_mid)", %%mm0 \n\t" + "pmulhw "MANGLE(mul16_mid)", %%mm1 \n\t" + "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" + "movq %%mm0, %%mm3 \n\t" + "movq %%mm1, %%mm4 \n\t" + "movq %%mm2, %%mm5 \n\t" + "punpcklwd %5, %%mm0 \n\t" + "punpcklwd %5, %%mm1 \n\t" + "punpcklwd %5, %%mm2 \n\t" + "punpckhwd %5, %%mm3 \n\t" + "punpckhwd %5, %%mm4 \n\t" + "punpckhwd %5, %%mm5 \n\t" + "psllq $8, %%mm1 \n\t" + "psllq $16, %%mm2 \n\t" + "por %%mm1, %%mm0 \n\t" + "por %%mm2, %%mm0 \n\t" + "psllq $8, %%mm4 \n\t" + "psllq $16, %%mm5 \n\t" + "por %%mm4, %%mm3 \n\t" + "por %%mm5, %%mm3 \n\t" + :"=m"(*d) + :"r"(s),"m"(mask16b),"m"(mask16g),"m"(mask16r),"m"(mmx_null) + NAMED_CONSTRAINTS_ADD(mul15_mid,mul16_mid,mul15_hi) + :"memory"); + /* borrowed 32 to 24 */ + __asm__ volatile( + "movq %%mm0, %%mm4 \n\t" + "movq %%mm3, %%mm5 \n\t" + "movq %%mm6, %%mm0 \n\t" + "movq %%mm7, %%mm1 \n\t" + + "movq %%mm4, %%mm6 \n\t" + "movq %%mm5, %%mm7 \n\t" + "movq %%mm0, %%mm2 \n\t" + "movq %%mm1, %%mm3 \n\t" + + STORE_BGR24_MMX + + :: "r"(d), "m"(*s) + NAMED_CONSTRAINTS_ADD(mask24l,mask24h) + :"memory"); + d += 24; + s += 8; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + register uint16_t bgr; + bgr = *s++; + *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2); + *d++ = ((bgr&0x7E0)>>3) | ((bgr&0x7E0)>>9); + *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); + } +} + +/* + * mm0 = 00 B3 00 B2 00 B1 00 B0 + * mm1 = 00 G3 00 G2 00 G1 00 G0 + * mm2 = 00 R3 00 R2 00 R1 00 R0 + * mm6 = FF FF FF FF FF FF FF FF + * mm7 = 00 00 00 00 00 00 00 00 + */ +#define PACK_RGB32 \ + "packuswb %%mm7, %%mm0 \n\t" /* 00 00 00 00 B3 B2 B1 B0 */ \ + "packuswb %%mm7, %%mm1 \n\t" /* 00 00 00 00 G3 G2 G1 G0 */ \ + "packuswb %%mm7, %%mm2 \n\t" /* 00 00 00 00 R3 R2 R1 R0 */ \ + "punpcklbw %%mm1, %%mm0 \n\t" /* G3 B3 G2 B2 G1 B1 G0 B0 */ \ + "punpcklbw %%mm6, %%mm2 \n\t" /* FF R3 FF R2 FF R1 FF R0 */ \ + "movq %%mm0, %%mm3 \n\t" \ + "punpcklwd %%mm2, %%mm0 \n\t" /* FF R1 G1 B1 FF R0 G0 B0 */ \ + "punpckhwd %%mm2, %%mm3 \n\t" /* FF R3 G3 B3 FF R2 G2 B2 */ \ + MOVNTQ" %%mm0, (%0) \n\t" \ + MOVNTQ" %%mm3, 8(%0) \n\t" \ + +static inline void rgb15to32_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint16_t *end; + const uint16_t *mm_end; + uint8_t *d = dst; + const uint16_t *s = (const uint16_t *)src; + end = s + src_size/2; + __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); + __asm__ volatile("pxor %%mm7,%%mm7 \n\t":::"memory"); + __asm__ volatile("pcmpeqd %%mm6,%%mm6 \n\t":::"memory"); + mm_end = end - 3; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movq (%1), %%mm0 \n\t" + "movq (%1), %%mm1 \n\t" + "movq (%1), %%mm2 \n\t" + "pand %2, %%mm0 \n\t" + "pand %3, %%mm1 \n\t" + "pand %4, %%mm2 \n\t" + "psllq $5, %%mm0 \n\t" + "pmulhw %5, %%mm0 \n\t" + "pmulhw %5, %%mm1 \n\t" + "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" + PACK_RGB32 + ::"r"(d),"r"(s),"m"(mask15b),"m"(mask15g),"m"(mask15r) ,"m"(mul15_mid) + NAMED_CONSTRAINTS_ADD(mul15_hi) + :"memory"); + d += 16; + s += 4; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + register uint16_t bgr; + bgr = *s++; + *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2); + *d++ = ((bgr&0x3E0)>>2) | ((bgr&0x3E0)>>7); + *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); + *d++ = 255; + } +} + +static inline void rgb16to32_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + const uint16_t *end; + const uint16_t *mm_end; + uint8_t *d = dst; + const uint16_t *s = (const uint16_t*)src; + end = s + src_size/2; + __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); + __asm__ volatile("pxor %%mm7,%%mm7 \n\t":::"memory"); + __asm__ volatile("pcmpeqd %%mm6,%%mm6 \n\t":::"memory"); + mm_end = end - 3; + while (s < mm_end) { + __asm__ volatile( + PREFETCH" 32(%1) \n\t" + "movq (%1), %%mm0 \n\t" + "movq (%1), %%mm1 \n\t" + "movq (%1), %%mm2 \n\t" + "pand %2, %%mm0 \n\t" + "pand %3, %%mm1 \n\t" + "pand %4, %%mm2 \n\t" + "psllq $5, %%mm0 \n\t" + "psrlq $1, %%mm2 \n\t" + "pmulhw %5, %%mm0 \n\t" + "pmulhw "MANGLE(mul16_mid)", %%mm1 \n\t" + "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" + PACK_RGB32 + ::"r"(d),"r"(s),"m"(mask16b),"m"(mask16g),"m"(mask16r),"m"(mul15_mid) + NAMED_CONSTRAINTS_ADD(mul16_mid,mul15_hi) + :"memory"); + d += 16; + s += 4; + } + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + while (s < end) { + register uint16_t bgr; + bgr = *s++; + *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2); + *d++ = ((bgr&0x7E0)>>3) | ((bgr&0x7E0)>>9); + *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); + *d++ = 255; + } +} + +static inline void rgb24tobgr24_mmxext(const uint8_t *src, uint8_t *dst, int src_size) +{ + x86_reg mmx_size= 23 - src_size; + __asm__ volatile ( + "test %%"FF_REG_a", %%"FF_REG_a" \n\t" + "jns 2f \n\t" + "movq "MANGLE(mask24r)", %%mm5 \n\t" + "movq "MANGLE(mask24g)", %%mm6 \n\t" + "movq "MANGLE(mask24b)", %%mm7 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + PREFETCH" 32(%1, %%"FF_REG_a") \n\t" + "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" // BGR BGR BG + "movq (%1, %%"FF_REG_a"), %%mm1 \n\t" // BGR BGR BG + "movq 2(%1, %%"FF_REG_a"), %%mm2 \n\t" // R BGR BGR B + "psllq $16, %%mm0 \n\t" // 00 BGR BGR + "pand %%mm5, %%mm0 \n\t" + "pand %%mm6, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + "por %%mm0, %%mm1 \n\t" + "por %%mm2, %%mm1 \n\t" + "movq 6(%1, %%"FF_REG_a"), %%mm0 \n\t" // BGR BGR BG + MOVNTQ" %%mm1,(%2, %%"FF_REG_a") \n\t" // RGB RGB RG + "movq 8(%1, %%"FF_REG_a"), %%mm1 \n\t" // R BGR BGR B + "movq 10(%1, %%"FF_REG_a"), %%mm2 \n\t" // GR BGR BGR + "pand %%mm7, %%mm0 \n\t" + "pand %%mm5, %%mm1 \n\t" + "pand %%mm6, %%mm2 \n\t" + "por %%mm0, %%mm1 \n\t" + "por %%mm2, %%mm1 \n\t" + "movq 14(%1, %%"FF_REG_a"), %%mm0 \n\t" // R BGR BGR B + MOVNTQ" %%mm1, 8(%2, %%"FF_REG_a")\n\t" // B RGB RGB R + "movq 16(%1, %%"FF_REG_a"), %%mm1 \n\t" // GR BGR BGR + "movq 18(%1, %%"FF_REG_a"), %%mm2 \n\t" // BGR BGR BG + "pand %%mm6, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm5, %%mm2 \n\t" + "por %%mm0, %%mm1 \n\t" + "por %%mm2, %%mm1 \n\t" + MOVNTQ" %%mm1, 16(%2, %%"FF_REG_a") \n\t" + "add $24, %%"FF_REG_a" \n\t" + " js 1b \n\t" + "2: \n\t" + : "+a" (mmx_size) + : "r" (src-mmx_size), "r"(dst-mmx_size) + NAMED_CONSTRAINTS_ADD(mask24r,mask24g,mask24b) + ); + + __asm__ volatile(SFENCE:::"memory"); + __asm__ volatile(EMMS:::"memory"); + + if (mmx_size==23) return; //finished, was multiple of 8 + + src+= src_size; + dst+= src_size; + src_size= 23-mmx_size; + src-= src_size; + dst-= src_size; + for (unsigned i = 0; i < src_size; i +=3) { + register uint8_t x; + x = src[i + 2]; + dst[i + 1] = src[i + 1]; + dst[i + 2] = src[i + 0]; + dst[i + 0] = x; + } +} + +static inline void yuvPlanartoyuy2_mmxext(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride, int vertLumPerChroma) +{ + const x86_reg chromWidth= width>>1; + for (int y = 0; y < height; y++) { + //FIXME handle 2 lines at once (fewer prefetches, reuse some chroma, but very likely memory-limited anyway) + __asm__ volatile( + "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" + ".p2align 4 \n\t" + "1: \n\t" + PREFETCH" 32(%1, %%"FF_REG_a", 2) \n\t" + PREFETCH" 32(%2, %%"FF_REG_a") \n\t" + PREFETCH" 32(%3, %%"FF_REG_a") \n\t" + "movq (%2, %%"FF_REG_a"), %%mm0 \n\t" // U(0) + "movq %%mm0, %%mm2 \n\t" // U(0) + "movq (%3, %%"FF_REG_a"), %%mm1 \n\t" // V(0) + "punpcklbw %%mm1, %%mm0 \n\t" // UVUV UVUV(0) + "punpckhbw %%mm1, %%mm2 \n\t" // UVUV UVUV(8) + + "movq (%1, %%"FF_REG_a",2), %%mm3 \n\t" // Y(0) + "movq 8(%1, %%"FF_REG_a",2), %%mm5 \n\t" // Y(8) + "movq %%mm3, %%mm4 \n\t" // Y(0) + "movq %%mm5, %%mm6 \n\t" // Y(8) + "punpcklbw %%mm0, %%mm3 \n\t" // YUYV YUYV(0) + "punpckhbw %%mm0, %%mm4 \n\t" // YUYV YUYV(4) + "punpcklbw %%mm2, %%mm5 \n\t" // YUYV YUYV(8) + "punpckhbw %%mm2, %%mm6 \n\t" // YUYV YUYV(12) + + MOVNTQ" %%mm3, (%0, %%"FF_REG_a", 4) \n\t" + MOVNTQ" %%mm4, 8(%0, %%"FF_REG_a", 4) \n\t" + MOVNTQ" %%mm5, 16(%0, %%"FF_REG_a", 4) \n\t" + MOVNTQ" %%mm6, 24(%0, %%"FF_REG_a", 4) \n\t" + + "add $8, %%"FF_REG_a" \n\t" + "cmp %4, %%"FF_REG_a" \n\t" + " jb 1b \n\t" + ::"r"(dst), "r"(ysrc), "r"(usrc), "r"(vsrc), "g" (chromWidth) + : "%"FF_REG_a + ); + if ((y&(vertLumPerChroma-1)) == vertLumPerChroma-1) { + usrc += chromStride; + vsrc += chromStride; + } + ysrc += lumStride; + dst += dstStride; + } + __asm__(EMMS" \n\t" + SFENCE" \n\t" + :::"memory"); +} + +/** + * Height should be a multiple of 2 and width should be a multiple of 16. + * (If this is a problem for anyone then tell me, and I will fix it.) + */ +static inline void yv12toyuy2_mmxext(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride) +{ + //FIXME interpolate chroma + yuvPlanartoyuy2_mmxext(ysrc, usrc, vsrc, dst, width, height, lumStride, chromStride, dstStride, 2); +} + +static inline void yuvPlanartouyvy_mmxext(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride, int vertLumPerChroma) +{ + const x86_reg chromWidth= width>>1; + for (int y = 0; y < height; y++) { + //FIXME handle 2 lines at once (fewer prefetches, reuse some chroma, but very likely memory-limited anyway) + __asm__ volatile( + "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" + ".p2align 4 \n\t" + "1: \n\t" + PREFETCH" 32(%1, %%"FF_REG_a", 2) \n\t" + PREFETCH" 32(%2, %%"FF_REG_a") \n\t" + PREFETCH" 32(%3, %%"FF_REG_a") \n\t" + "movq (%2, %%"FF_REG_a"), %%mm0 \n\t" // U(0) + "movq %%mm0, %%mm2 \n\t" // U(0) + "movq (%3, %%"FF_REG_a"), %%mm1 \n\t" // V(0) + "punpcklbw %%mm1, %%mm0 \n\t" // UVUV UVUV(0) + "punpckhbw %%mm1, %%mm2 \n\t" // UVUV UVUV(8) + + "movq (%1, %%"FF_REG_a",2), %%mm3 \n\t" // Y(0) + "movq 8(%1, %%"FF_REG_a",2), %%mm5 \n\t" // Y(8) + "movq %%mm0, %%mm4 \n\t" // Y(0) + "movq %%mm2, %%mm6 \n\t" // Y(8) + "punpcklbw %%mm3, %%mm0 \n\t" // YUYV YUYV(0) + "punpckhbw %%mm3, %%mm4 \n\t" // YUYV YUYV(4) + "punpcklbw %%mm5, %%mm2 \n\t" // YUYV YUYV(8) + "punpckhbw %%mm5, %%mm6 \n\t" // YUYV YUYV(12) + + MOVNTQ" %%mm0, (%0, %%"FF_REG_a", 4) \n\t" + MOVNTQ" %%mm4, 8(%0, %%"FF_REG_a", 4) \n\t" + MOVNTQ" %%mm2, 16(%0, %%"FF_REG_a", 4) \n\t" + MOVNTQ" %%mm6, 24(%0, %%"FF_REG_a", 4) \n\t" + + "add $8, %%"FF_REG_a" \n\t" + "cmp %4, %%"FF_REG_a" \n\t" + " jb 1b \n\t" + ::"r"(dst), "r"(ysrc), "r"(usrc), "r"(vsrc), "g" (chromWidth) + : "%"FF_REG_a + ); + if ((y&(vertLumPerChroma-1)) == vertLumPerChroma-1) { + usrc += chromStride; + vsrc += chromStride; + } + ysrc += lumStride; + dst += dstStride; + } + __asm__(EMMS" \n\t" + SFENCE" \n\t" + :::"memory"); +} + +/** + * Height should be a multiple of 2 and width should be a multiple of 16 + * (If this is a problem for anyone then tell me, and I will fix it.) + */ +static inline void yv12touyvy_mmxext(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride) +{ + //FIXME interpolate chroma + yuvPlanartouyvy_mmxext(ysrc, usrc, vsrc, dst, width, height, lumStride, chromStride, dstStride, 2); +} + +/** + * Width should be a multiple of 16. + */ +static inline void yuv422ptouyvy_mmxext(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride) +{ + yuvPlanartouyvy_mmxext(ysrc, usrc, vsrc, dst, width, height, lumStride, chromStride, dstStride, 1); +} + +/** + * Width should be a multiple of 16. + */ +static inline void yuv422ptoyuy2_mmxext(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride) +{ + yuvPlanartoyuy2_mmxext(ysrc, usrc, vsrc, dst, width, height, lumStride, chromStride, dstStride, 1); +} + +/** + * Height should be a multiple of 2 and width should be a multiple of 16. + * (If this is a problem for anyone then tell me, and I will fix it.) + */ +static inline void yuy2toyv12_mmxext(const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + int width, int height, + int lumStride, int chromStride, int srcStride) +{ + const x86_reg chromWidth= width>>1; + for (int y = 0; y < height; y += 2) { + __asm__ volatile( + "xor %%"FF_REG_a", %%"FF_REG_a"\n\t" + "pcmpeqw %%mm7, %%mm7 \n\t" + "psrlw $8, %%mm7 \n\t" // FF,00,FF,00... + ".p2align 4 \n\t" + "1: \n\t" + PREFETCH" 64(%0, %%"FF_REG_a", 4) \n\t" + "movq (%0, %%"FF_REG_a", 4), %%mm0 \n\t" // YUYV YUYV(0) + "movq 8(%0, %%"FF_REG_a", 4), %%mm1 \n\t" // YUYV YUYV(4) + "movq %%mm0, %%mm2 \n\t" // YUYV YUYV(0) + "movq %%mm1, %%mm3 \n\t" // YUYV YUYV(4) + "psrlw $8, %%mm0 \n\t" // U0V0 U0V0(0) + "psrlw $8, %%mm1 \n\t" // U0V0 U0V0(4) + "pand %%mm7, %%mm2 \n\t" // Y0Y0 Y0Y0(0) + "pand %%mm7, %%mm3 \n\t" // Y0Y0 Y0Y0(4) + "packuswb %%mm1, %%mm0 \n\t" // UVUV UVUV(0) + "packuswb %%mm3, %%mm2 \n\t" // YYYY YYYY(0) + + MOVNTQ" %%mm2, (%1, %%"FF_REG_a", 2) \n\t" + + "movq 16(%0, %%"FF_REG_a", 4), %%mm1 \n\t" // YUYV YUYV(8) + "movq 24(%0, %%"FF_REG_a", 4), %%mm2 \n\t" // YUYV YUYV(12) + "movq %%mm1, %%mm3 \n\t" // YUYV YUYV(8) + "movq %%mm2, %%mm4 \n\t" // YUYV YUYV(12) + "psrlw $8, %%mm1 \n\t" // U0V0 U0V0(8) + "psrlw $8, %%mm2 \n\t" // U0V0 U0V0(12) + "pand %%mm7, %%mm3 \n\t" // Y0Y0 Y0Y0(8) + "pand %%mm7, %%mm4 \n\t" // Y0Y0 Y0Y0(12) + "packuswb %%mm2, %%mm1 \n\t" // UVUV UVUV(8) + "packuswb %%mm4, %%mm3 \n\t" // YYYY YYYY(8) + + MOVNTQ" %%mm3, 8(%1, %%"FF_REG_a", 2) \n\t" + + "movq %%mm0, %%mm2 \n\t" // UVUV UVUV(0) + "movq %%mm1, %%mm3 \n\t" // UVUV UVUV(8) + "psrlw $8, %%mm0 \n\t" // V0V0 V0V0(0) + "psrlw $8, %%mm1 \n\t" // V0V0 V0V0(8) + "pand %%mm7, %%mm2 \n\t" // U0U0 U0U0(0) + "pand %%mm7, %%mm3 \n\t" // U0U0 U0U0(8) + "packuswb %%mm1, %%mm0 \n\t" // VVVV VVVV(0) + "packuswb %%mm3, %%mm2 \n\t" // UUUU UUUU(0) + + MOVNTQ" %%mm0, (%3, %%"FF_REG_a") \n\t" + MOVNTQ" %%mm2, (%2, %%"FF_REG_a") \n\t" + + "add $8, %%"FF_REG_a" \n\t" + "cmp %4, %%"FF_REG_a" \n\t" + " jb 1b \n\t" + ::"r"(src), "r"(ydst), "r"(udst), "r"(vdst), "g" (chromWidth) + : "memory", "%"FF_REG_a + ); + + ydst += lumStride; + src += srcStride; + + __asm__ volatile( + "xor %%"FF_REG_a", %%"FF_REG_a"\n\t" + ".p2align 4 \n\t" + "1: \n\t" + PREFETCH" 64(%0, %%"FF_REG_a", 4) \n\t" + "movq (%0, %%"FF_REG_a", 4), %%mm0 \n\t" // YUYV YUYV(0) + "movq 8(%0, %%"FF_REG_a", 4), %%mm1 \n\t" // YUYV YUYV(4) + "movq 16(%0, %%"FF_REG_a", 4), %%mm2 \n\t" // YUYV YUYV(8) + "movq 24(%0, %%"FF_REG_a", 4), %%mm3 \n\t" // YUYV YUYV(12) + "pand %%mm7, %%mm0 \n\t" // Y0Y0 Y0Y0(0) + "pand %%mm7, %%mm1 \n\t" // Y0Y0 Y0Y0(4) + "pand %%mm7, %%mm2 \n\t" // Y0Y0 Y0Y0(8) + "pand %%mm7, %%mm3 \n\t" // Y0Y0 Y0Y0(12) + "packuswb %%mm1, %%mm0 \n\t" // YYYY YYYY(0) + "packuswb %%mm3, %%mm2 \n\t" // YYYY YYYY(8) + + MOVNTQ" %%mm0, (%1, %%"FF_REG_a", 2) \n\t" + MOVNTQ" %%mm2, 8(%1, %%"FF_REG_a", 2) \n\t" + + "add $8, %%"FF_REG_a"\n\t" + "cmp %4, %%"FF_REG_a"\n\t" + " jb 1b \n\t" + + ::"r"(src), "r"(ydst), "r"(udst), "r"(vdst), "g" (chromWidth) + : "memory", "%"FF_REG_a + ); + udst += chromStride; + vdst += chromStride; + ydst += lumStride; + src += srcStride; + } + __asm__ volatile(EMMS" \n\t" + SFENCE" \n\t" + :::"memory"); +} + +static inline void planar2x_mmxext(const uint8_t *src, uint8_t *dst, int srcWidth, int srcHeight, int srcStride, int dstStride) +{ + dst[0]= src[0]; + + // first line + for (int x = 0; x < srcWidth - 1; x++) { + dst[2*x+1]= (3*src[x] + src[x+1])>>2; + dst[2*x+2]= ( src[x] + 3*src[x+1])>>2; + } + dst[2*srcWidth-1]= src[srcWidth-1]; + + dst+= dstStride; + + for (int y = 1; y < srcHeight; y++) { + x86_reg mmxSize= srcWidth&~15; + + if (mmxSize) { + __asm__ volatile( + "mov %4, %%"FF_REG_a" \n\t" + "movq "MANGLE(mmx_ff)", %%mm0 \n\t" + "movq (%0, %%"FF_REG_a"), %%mm4 \n\t" + "movq %%mm4, %%mm2 \n\t" + "psllq $8, %%mm4 \n\t" + "pand %%mm0, %%mm2 \n\t" + "por %%mm2, %%mm4 \n\t" + "movq (%1, %%"FF_REG_a"), %%mm5 \n\t" + "movq %%mm5, %%mm3 \n\t" + "psllq $8, %%mm5 \n\t" + "pand %%mm0, %%mm3 \n\t" + "por %%mm3, %%mm5 \n\t" + "1: \n\t" + "movq (%0, %%"FF_REG_a"), %%mm0 \n\t" + "movq (%1, %%"FF_REG_a"), %%mm1 \n\t" + "movq 1(%0, %%"FF_REG_a"), %%mm2 \n\t" + "movq 1(%1, %%"FF_REG_a"), %%mm3 \n\t" + PAVGB" %%mm0, %%mm5 \n\t" + PAVGB" %%mm0, %%mm3 \n\t" + PAVGB" %%mm0, %%mm5 \n\t" + PAVGB" %%mm0, %%mm3 \n\t" + PAVGB" %%mm1, %%mm4 \n\t" + PAVGB" %%mm1, %%mm2 \n\t" + PAVGB" %%mm1, %%mm4 \n\t" + PAVGB" %%mm1, %%mm2 \n\t" + "movq %%mm5, %%mm7 \n\t" + "movq %%mm4, %%mm6 \n\t" + "punpcklbw %%mm3, %%mm5 \n\t" + "punpckhbw %%mm3, %%mm7 \n\t" + "punpcklbw %%mm2, %%mm4 \n\t" + "punpckhbw %%mm2, %%mm6 \n\t" + MOVNTQ" %%mm5, (%2, %%"FF_REG_a", 2) \n\t" + MOVNTQ" %%mm7, 8(%2, %%"FF_REG_a", 2) \n\t" + MOVNTQ" %%mm4, (%3, %%"FF_REG_a", 2) \n\t" + MOVNTQ" %%mm6, 8(%3, %%"FF_REG_a", 2) \n\t" + "add $8, %%"FF_REG_a" \n\t" + "movq -1(%0, %%"FF_REG_a"), %%mm4 \n\t" + "movq -1(%1, %%"FF_REG_a"), %%mm5 \n\t" + " js 1b \n\t" + :: "r" (src + mmxSize ), "r" (src + srcStride + mmxSize ), + "r" (dst + mmxSize*2), "r" (dst + dstStride + mmxSize*2), + "g" (-mmxSize) + NAMED_CONSTRAINTS_ADD(mmx_ff) + : "%"FF_REG_a + ); + } else { + mmxSize = 1; + dst[0] = (src[0] * 3 + src[srcStride]) >> 2; + dst[dstStride] = (src[0] + 3 * src[srcStride]) >> 2; + } + + for (int x = mmxSize - 1; x < srcWidth - 1; x++) { + dst[2*x +1]= (3*src[x+0] + src[x+srcStride+1])>>2; + dst[2*x+dstStride+2]= ( src[x+0] + 3*src[x+srcStride+1])>>2; + dst[2*x+dstStride+1]= ( src[x+1] + 3*src[x+srcStride ])>>2; + dst[2*x +2]= (3*src[x+1] + src[x+srcStride ])>>2; + } + dst[srcWidth*2 -1 ]= (3*src[srcWidth-1] + src[srcWidth-1 + srcStride])>>2; + dst[srcWidth*2 -1 + dstStride]= ( src[srcWidth-1] + 3*src[srcWidth-1 + srcStride])>>2; + + dst+=dstStride*2; + src+=srcStride; + } + + // last line + dst[0]= src[0]; + + for (int x = 0; x < srcWidth - 1; x++) { + dst[2*x+1]= (3*src[x] + src[x+1])>>2; + dst[2*x+2]= ( src[x] + 3*src[x+1])>>2; + } + dst[2*srcWidth-1]= src[srcWidth-1]; + + __asm__ volatile(EMMS" \n\t" + SFENCE" \n\t" + :::"memory"); +} + +/** + * Height should be a multiple of 2 and width should be a multiple of 2. + * (If this is a problem for anyone then tell me, and I will fix it.) + * Chrominance data is only taken from every second line, + * others are ignored in the C version. + * FIXME: Write HQ version. + */ +#if ARCH_X86_32 && HAVE_7REGS +static inline void rgb24toyv12_mmxext(const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + int width, int height, + int lumStride, int chromStride, int srcStride, + int32_t *rgb2yuv) +{ +#define BGR2Y_IDX "16*4+16*32" +#define BGR2U_IDX "16*4+16*33" +#define BGR2V_IDX "16*4+16*34" + int y; + const x86_reg chromWidth= width>>1; + + if (height > 2) { + ff_rgb24toyv12_c(src, ydst, udst, vdst, width, 2, lumStride, chromStride, srcStride, rgb2yuv); + src += 2*srcStride; + ydst += 2*lumStride; + udst += chromStride; + vdst += chromStride; + height -= 2; + } + + for (y = 0; y < height - 2; y += 2) { + for (int i = 0; i < 2; i++) { + __asm__ volatile( + "mov %2, %%"FF_REG_a"\n\t" + "movq "BGR2Y_IDX"(%3), %%mm6 \n\t" + "movq "MANGLE(ff_w1111)", %%mm5 \n\t" + "pxor %%mm7, %%mm7 \n\t" + "lea (%%"FF_REG_a", %%"FF_REG_a", 2), %%"FF_REG_d" \n\t" + ".p2align 4 \n\t" + "1: \n\t" + PREFETCH" 64(%0, %%"FF_REG_d") \n\t" + "movd (%0, %%"FF_REG_d"), %%mm0 \n\t" + "movd 3(%0, %%"FF_REG_d"), %%mm1 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm1 \n\t" + "movd 6(%0, %%"FF_REG_d"), %%mm2 \n\t" + "movd 9(%0, %%"FF_REG_d"), %%mm3 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpcklbw %%mm7, %%mm3 \n\t" + "pmaddwd %%mm6, %%mm0 \n\t" + "pmaddwd %%mm6, %%mm1 \n\t" + "pmaddwd %%mm6, %%mm2 \n\t" + "pmaddwd %%mm6, %%mm3 \n\t" + "psrad $8, %%mm0 \n\t" + "psrad $8, %%mm1 \n\t" + "psrad $8, %%mm2 \n\t" + "psrad $8, %%mm3 \n\t" + "packssdw %%mm1, %%mm0 \n\t" + "packssdw %%mm3, %%mm2 \n\t" + "pmaddwd %%mm5, %%mm0 \n\t" + "pmaddwd %%mm5, %%mm2 \n\t" + "packssdw %%mm2, %%mm0 \n\t" + "psraw $7, %%mm0 \n\t" + + "movd 12(%0, %%"FF_REG_d"), %%mm4 \n\t" + "movd 15(%0, %%"FF_REG_d"), %%mm1 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "punpcklbw %%mm7, %%mm1 \n\t" + "movd 18(%0, %%"FF_REG_d"), %%mm2 \n\t" + "movd 21(%0, %%"FF_REG_d"), %%mm3 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpcklbw %%mm7, %%mm3 \n\t" + "pmaddwd %%mm6, %%mm4 \n\t" + "pmaddwd %%mm6, %%mm1 \n\t" + "pmaddwd %%mm6, %%mm2 \n\t" + "pmaddwd %%mm6, %%mm3 \n\t" + "psrad $8, %%mm4 \n\t" + "psrad $8, %%mm1 \n\t" + "psrad $8, %%mm2 \n\t" + "psrad $8, %%mm3 \n\t" + "packssdw %%mm1, %%mm4 \n\t" + "packssdw %%mm3, %%mm2 \n\t" + "pmaddwd %%mm5, %%mm4 \n\t" + "pmaddwd %%mm5, %%mm2 \n\t" + "add $24, %%"FF_REG_d"\n\t" + "packssdw %%mm2, %%mm4 \n\t" + "psraw $7, %%mm4 \n\t" + + "packuswb %%mm4, %%mm0 \n\t" + "paddusb "MANGLE(ff_bgr2YOffset)", %%mm0 \n\t" + + MOVNTQ" %%mm0, (%1, %%"FF_REG_a") \n\t" + "add $8, %%"FF_REG_a" \n\t" + " js 1b \n\t" + : : "r" (src+width*3), "r" (ydst+width), "g" ((x86_reg)-width), "r"(rgb2yuv) + NAMED_CONSTRAINTS_ADD(ff_w1111,ff_bgr2YOffset) + : "%"FF_REG_a, "%"FF_REG_d + ); + ydst += lumStride; + src += srcStride; + } + src -= srcStride*2; + __asm__ volatile( + "mov %4, %%"FF_REG_a"\n\t" + "movq "MANGLE(ff_w1111)", %%mm5 \n\t" + "movq "BGR2U_IDX"(%5), %%mm6 \n\t" + "pxor %%mm7, %%mm7 \n\t" + "lea (%%"FF_REG_a", %%"FF_REG_a", 2), %%"FF_REG_d" \n\t" + "add %%"FF_REG_d", %%"FF_REG_d"\n\t" + ".p2align 4 \n\t" + "1: \n\t" + PREFETCH" 64(%0, %%"FF_REG_d") \n\t" + PREFETCH" 64(%1, %%"FF_REG_d") \n\t" + "movq (%0, %%"FF_REG_d"), %%mm0 \n\t" + "movq (%1, %%"FF_REG_d"), %%mm1 \n\t" + "movq 6(%0, %%"FF_REG_d"), %%mm2 \n\t" + "movq 6(%1, %%"FF_REG_d"), %%mm3 \n\t" + PAVGB" %%mm1, %%mm0 \n\t" + PAVGB" %%mm3, %%mm2 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm2, %%mm3 \n\t" + "psrlq $24, %%mm0 \n\t" + "psrlq $24, %%mm2 \n\t" + PAVGB" %%mm1, %%mm0 \n\t" + PAVGB" %%mm3, %%mm2 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "movq "BGR2V_IDX"(%5), %%mm1 \n\t" + "movq "BGR2V_IDX"(%5), %%mm3 \n\t" + + "pmaddwd %%mm0, %%mm1 \n\t" + "pmaddwd %%mm2, %%mm3 \n\t" + "pmaddwd %%mm6, %%mm0 \n\t" + "pmaddwd %%mm6, %%mm2 \n\t" + "psrad $8, %%mm0 \n\t" + "psrad $8, %%mm1 \n\t" + "psrad $8, %%mm2 \n\t" + "psrad $8, %%mm3 \n\t" + "packssdw %%mm2, %%mm0 \n\t" + "packssdw %%mm3, %%mm1 \n\t" + "pmaddwd %%mm5, %%mm0 \n\t" + "pmaddwd %%mm5, %%mm1 \n\t" + "packssdw %%mm1, %%mm0 \n\t" // V1 V0 U1 U0 + "psraw $7, %%mm0 \n\t" + + "movq 12(%0, %%"FF_REG_d"), %%mm4 \n\t" + "movq 12(%1, %%"FF_REG_d"), %%mm1 \n\t" + "movq 18(%0, %%"FF_REG_d"), %%mm2 \n\t" + "movq 18(%1, %%"FF_REG_d"), %%mm3 \n\t" + PAVGB" %%mm1, %%mm4 \n\t" + PAVGB" %%mm3, %%mm2 \n\t" + "movq %%mm4, %%mm1 \n\t" + "movq %%mm2, %%mm3 \n\t" + "psrlq $24, %%mm4 \n\t" + "psrlq $24, %%mm2 \n\t" + PAVGB" %%mm1, %%mm4 \n\t" + PAVGB" %%mm3, %%mm2 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "movq "BGR2V_IDX"(%5), %%mm1 \n\t" + "movq "BGR2V_IDX"(%5), %%mm3 \n\t" + + "pmaddwd %%mm4, %%mm1 \n\t" + "pmaddwd %%mm2, %%mm3 \n\t" + "pmaddwd %%mm6, %%mm4 \n\t" + "pmaddwd %%mm6, %%mm2 \n\t" + "psrad $8, %%mm4 \n\t" + "psrad $8, %%mm1 \n\t" + "psrad $8, %%mm2 \n\t" + "psrad $8, %%mm3 \n\t" + "packssdw %%mm2, %%mm4 \n\t" + "packssdw %%mm3, %%mm1 \n\t" + "pmaddwd %%mm5, %%mm4 \n\t" + "pmaddwd %%mm5, %%mm1 \n\t" + "add $24, %%"FF_REG_d"\n\t" + "packssdw %%mm1, %%mm4 \n\t" // V3 V2 U3 U2 + "psraw $7, %%mm4 \n\t" + + "movq %%mm0, %%mm1 \n\t" + "punpckldq %%mm4, %%mm0 \n\t" + "punpckhdq %%mm4, %%mm1 \n\t" + "packsswb %%mm1, %%mm0 \n\t" + "paddb "MANGLE(ff_bgr2UVOffset)", %%mm0 \n\t" + "movd %%mm0, (%2, %%"FF_REG_a") \n\t" + "punpckhdq %%mm0, %%mm0 \n\t" + "movd %%mm0, (%3, %%"FF_REG_a") \n\t" + "add $4, %%"FF_REG_a" \n\t" + " js 1b \n\t" + : : "r" (src+chromWidth*6), "r" (src+srcStride+chromWidth*6), "r" (udst+chromWidth), "r" (vdst+chromWidth), "g" (-chromWidth), "r"(rgb2yuv) + NAMED_CONSTRAINTS_ADD(ff_w1111,ff_bgr2UVOffset) + : "%"FF_REG_a, "%"FF_REG_d + ); + + udst += chromStride; + vdst += chromStride; + src += srcStride*2; + } + + __asm__ volatile(EMMS" \n\t" + SFENCE" \n\t" + :::"memory"); + + ff_rgb24toyv12_c(src, ydst, udst, vdst, width, height-y, lumStride, chromStride, srcStride, rgb2yuv); +} +#endif /* HAVE_7REGS */ + +static inline void vu9_to_vu12_mmxext(const uint8_t *src1, const uint8_t *src2, + uint8_t *dst1, uint8_t *dst2, + int width, int height, + int srcStride1, int srcStride2, + int dstStride1, int dstStride2) +{ + int w,h; + w=width/2; h=height/2; + __asm__ volatile( + PREFETCH" %0 \n\t" + PREFETCH" %1 \n\t" + ::"m"(*(src1+srcStride1)),"m"(*(src2+srcStride2)):"memory"); + for (x86_reg y = 0; y < h; y++) { + const uint8_t* s1=src1+srcStride1*(y>>1); + uint8_t* d=dst1+dstStride1*y; + x86_reg x = 0; + for (;x>1); + uint8_t* d=dst2+dstStride2*y; + x86_reg x = 0; + for (;x>2); + const uint8_t* vp=src3+srcStride3*(y>>2); + uint8_t* d=dst+dstStride*y; + x86_reg x = 0; + for (;x>1; + dst1[count]= (src0[4*count+2]+src1[4*count+2])>>1; + count++; + } +} + +static void extract_odd2_mmxext(const uint8_t *src, uint8_t *dst0, uint8_t *dst1, x86_reg count) +{ + dst0+= count; + dst1+= count; + src += 4*count; + count= - count; + if(count <= -8) { + count += 7; + __asm__ volatile( + "pcmpeqw %%mm7, %%mm7 \n\t" + "psrlw $8, %%mm7 \n\t" + "1: \n\t" + "movq -28(%1, %0, 4), %%mm0 \n\t" + "movq -20(%1, %0, 4), %%mm1 \n\t" + "movq -12(%1, %0, 4), %%mm2 \n\t" + "movq -4(%1, %0, 4), %%mm3 \n\t" + "psrlw $8, %%mm0 \n\t" + "psrlw $8, %%mm1 \n\t" + "psrlw $8, %%mm2 \n\t" + "psrlw $8, %%mm3 \n\t" + "packuswb %%mm1, %%mm0 \n\t" + "packuswb %%mm3, %%mm2 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm2, %%mm3 \n\t" + "psrlw $8, %%mm0 \n\t" + "psrlw $8, %%mm2 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "packuswb %%mm2, %%mm0 \n\t" + "packuswb %%mm3, %%mm1 \n\t" + MOVNTQ" %%mm0,- 7(%3, %0) \n\t" + MOVNTQ" %%mm1,- 7(%2, %0) \n\t" + "add $8, %0 \n\t" + " js 1b \n\t" + : "+r"(count) + : "r"(src), "r"(dst0), "r"(dst1) + ); + count -= 7; + } + src++; + while(count<0) { + dst0[count]= src[4*count+0]; + dst1[count]= src[4*count+2]; + count++; + } +} + +static void extract_odd2avg_mmxext(const uint8_t *src0, const uint8_t *src1, uint8_t *dst0, uint8_t *dst1, x86_reg count) +{ + dst0 += count; + dst1 += count; + src0 += 4*count; + src1 += 4*count; + count= - count; +#ifdef PAVGB + if(count <= -8) { + count += 7; + __asm__ volatile( + "pcmpeqw %%mm7, %%mm7 \n\t" + "psrlw $8, %%mm7 \n\t" + "1: \n\t" + "movq -28(%1, %0, 4), %%mm0 \n\t" + "movq -20(%1, %0, 4), %%mm1 \n\t" + "movq -12(%1, %0, 4), %%mm2 \n\t" + "movq -4(%1, %0, 4), %%mm3 \n\t" + PAVGB" -28(%2, %0, 4), %%mm0 \n\t" + PAVGB" -20(%2, %0, 4), %%mm1 \n\t" + PAVGB" -12(%2, %0, 4), %%mm2 \n\t" + PAVGB" - 4(%2, %0, 4), %%mm3 \n\t" + "psrlw $8, %%mm0 \n\t" + "psrlw $8, %%mm1 \n\t" + "psrlw $8, %%mm2 \n\t" + "psrlw $8, %%mm3 \n\t" + "packuswb %%mm1, %%mm0 \n\t" + "packuswb %%mm3, %%mm2 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm2, %%mm3 \n\t" + "psrlw $8, %%mm0 \n\t" + "psrlw $8, %%mm2 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "packuswb %%mm2, %%mm0 \n\t" + "packuswb %%mm3, %%mm1 \n\t" + MOVNTQ" %%mm0,- 7(%4, %0) \n\t" + MOVNTQ" %%mm1,- 7(%3, %0) \n\t" + "add $8, %0 \n\t" + " js 1b \n\t" + : "+r"(count) + : "r"(src0), "r"(src1), "r"(dst0), "r"(dst1) + ); + count -= 7; + } +#endif + src0++; + src1++; + while(count<0) { + dst0[count]= (src0[4*count+0]+src1[4*count+0])>>1; + dst1[count]= (src0[4*count+2]+src1[4*count+2])>>1; + count++; + } +} + +static void yuyvtoyuv420_mmxext(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, + int width, int height, + int lumStride, int chromStride, int srcStride) +{ + const int chromWidth = AV_CEIL_RSHIFT(width, 1); + + for (int y = 0; y < height; y++) { + extract_even_mmxext(src, ydst, width); + if(y&1) { + extract_odd2avg_mmxext(src-srcStride, src, udst, vdst, chromWidth); + udst+= chromStride; + vdst+= chromStride; + } + + src += srcStride; + ydst+= lumStride; + } + __asm__( + EMMS" \n\t" + SFENCE" \n\t" + ::: "memory" + ); +} + +static void yuyvtoyuv422_mmxext(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, + int width, int height, + int lumStride, int chromStride, int srcStride) +{ + const int chromWidth = AV_CEIL_RSHIFT(width, 1); + + for (int y = 0; y < height; y++) { + extract_even_mmxext(src, ydst, width); + extract_odd2_mmxext(src, udst, vdst, chromWidth); + + src += srcStride; + ydst+= lumStride; + udst+= chromStride; + vdst+= chromStride; + } + __asm__( + EMMS" \n\t" + SFENCE" \n\t" + ::: "memory" + ); +} + +static void uyvytoyuv420_mmxext(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, + int width, int height, + int lumStride, int chromStride, int srcStride) +{ + const int chromWidth = AV_CEIL_RSHIFT(width, 1); + + for (int y = 0; y < height; y++) { + extract_odd_mmxext(src, ydst, width); + if(y&1) { + extract_even2avg_mmxext(src-srcStride, src, udst, vdst, chromWidth); + udst+= chromStride; + vdst+= chromStride; + } + + src += srcStride; + ydst+= lumStride; + } + __asm__( + EMMS" \n\t" + SFENCE" \n\t" + ::: "memory" + ); +} + +#if ARCH_X86_32 +static void uyvytoyuv422_mmxext(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, + int width, int height, + int lumStride, int chromStride, int srcStride) +{ + const int chromWidth = AV_CEIL_RSHIFT(width, 1); + + for (int y = 0; y < height; y++) { + extract_odd_mmxext(src, ydst, width); + extract_even2_mmxext(src, udst, vdst, chromWidth); + + src += srcStride; + ydst+= lumStride; + udst+= chromStride; + vdst+= chromStride; + } + __asm__( + EMMS" \n\t" + SFENCE" \n\t" + ::: "memory" + ); +} +#endif /* ARCH_X86_32 */ + +static av_cold void rgb2rgb_init_mmxext(void) +{ + rgb15to16 = rgb15to16_mmxext; + rgb15tobgr24 = rgb15tobgr24_mmxext; + rgb15to32 = rgb15to32_mmxext; + rgb16tobgr24 = rgb16tobgr24_mmxext; + rgb16to32 = rgb16to32_mmxext; + rgb16to15 = rgb16to15_mmxext; + rgb24tobgr16 = rgb24tobgr16_mmxext; + rgb24tobgr15 = rgb24tobgr15_mmxext; + rgb24tobgr32 = rgb24tobgr32_mmxext; + rgb32to16 = rgb32to16_mmxext; + rgb32to15 = rgb32to15_mmxext; + rgb32tobgr24 = rgb32tobgr24_mmxext; + rgb24to15 = rgb24to15_mmxext; + rgb24to16 = rgb24to16_mmxext; + rgb24tobgr24 = rgb24tobgr24_mmxext; + rgb32tobgr16 = rgb32tobgr16_mmxext; + rgb32tobgr15 = rgb32tobgr15_mmxext; + yv12toyuy2 = yv12toyuy2_mmxext; + yv12touyvy = yv12touyvy_mmxext; + yuv422ptoyuy2 = yuv422ptoyuy2_mmxext; + yuv422ptouyvy = yuv422ptouyvy_mmxext; + yuy2toyv12 = yuy2toyv12_mmxext; + vu9_to_vu12 = vu9_to_vu12_mmxext; + yvu9_to_yuy2 = yvu9_to_yuy2_mmxext; +#if ARCH_X86_32 + uyvytoyuv422 = uyvytoyuv422_mmxext; +#endif + yuyvtoyuv422 = yuyvtoyuv422_mmxext; + + planar2x = planar2x_mmxext; +#if ARCH_X86_32 && HAVE_7REGS + ff_rgb24toyv12 = rgb24toyv12_mmxext; +#endif /* ARCH_X86_32 && HAVE_7REGS */ + + yuyvtoyuv420 = yuyvtoyuv420_mmxext; + uyvytoyuv420 = uyvytoyuv420_mmxext; +} //SSE2 versions -#undef RENAME -#undef COMPILE_TEMPLATE_SSE2 -#define COMPILE_TEMPLATE_SSE2 1 -#define RENAME(a) a ## _sse2 -#include "rgb2rgb_template.c" +static void interleave_bytes_sse2(const uint8_t *src1, const uint8_t *src2, uint8_t *dest, + int width, int height, int src1Stride, + int src2Stride, int dstStride) +{ + for (int h = 0; h < height; h++) { + if (width >= 16) { + if (!((((intptr_t)src1) | ((intptr_t)src2) | ((intptr_t)dest))&15)) { + __asm__( + "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" + "1: \n\t" + PREFETCH" 64(%1, %%"FF_REG_a") \n\t" + PREFETCH" 64(%2, %%"FF_REG_a") \n\t" + "movdqa (%1, %%"FF_REG_a"), %%xmm0 \n\t" + "movdqa (%1, %%"FF_REG_a"), %%xmm1 \n\t" + "movdqa (%2, %%"FF_REG_a"), %%xmm2 \n\t" + "punpcklbw %%xmm2, %%xmm0 \n\t" + "punpckhbw %%xmm2, %%xmm1 \n\t" + "movntdq %%xmm0, (%0, %%"FF_REG_a", 2) \n\t" + "movntdq %%xmm1, 16(%0, %%"FF_REG_a", 2) \n\t" + "add $16, %%"FF_REG_a" \n\t" + "cmp %3, %%"FF_REG_a" \n\t" + " jb 1b \n\t" + ::"r"(dest), "r"(src1), "r"(src2), "r" ((x86_reg)width-15) + : "memory", XMM_CLOBBERS("xmm0", "xmm1", "xmm2",) "%"FF_REG_a + ); + } else + __asm__( + "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" + "1: \n\t" + PREFETCH" 64(%1, %%"FF_REG_a") \n\t" + PREFETCH" 64(%2, %%"FF_REG_a") \n\t" + "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" + "movq 8(%1, %%"FF_REG_a"), %%mm2 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm2, %%mm3 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm4 \n\t" + "movq 8(%2, %%"FF_REG_a"), %%mm5 \n\t" + "punpcklbw %%mm4, %%mm0 \n\t" + "punpckhbw %%mm4, %%mm1 \n\t" + "punpcklbw %%mm5, %%mm2 \n\t" + "punpckhbw %%mm5, %%mm3 \n\t" + MOVNTQ" %%mm0, (%0, %%"FF_REG_a", 2) \n\t" + MOVNTQ" %%mm1, 8(%0, %%"FF_REG_a", 2) \n\t" + MOVNTQ" %%mm2, 16(%0, %%"FF_REG_a", 2) \n\t" + MOVNTQ" %%mm3, 24(%0, %%"FF_REG_a", 2) \n\t" + "add $16, %%"FF_REG_a" \n\t" + "cmp %3, %%"FF_REG_a" \n\t" + " jb 1b \n\t" + ::"r"(dest), "r"(src1), "r"(src2), "r" ((x86_reg)width-15) + : "memory", "%"FF_REG_a + ); -//AVX versions -#undef RENAME -#undef COMPILE_TEMPLATE_AVX -#define COMPILE_TEMPLATE_AVX 1 -#define RENAME(a) a ## _avx -#include "rgb2rgb_template.c" + } + for (int w = (width & (~15)); w < width; w++) { + dest[2*w+0] = src1[w]; + dest[2*w+1] = src2[w]; + } + dest += dstStride; + src1 += src1Stride; + src2 += src2Stride; + } + __asm__( + EMMS" \n\t" + SFENCE" \n\t" + ::: "memory" + ); +} /* RGB15->RGB16 original by Strepto/Astral @@ -116,7 +2343,6 @@ DECLARE_ALIGNED(8, extern const uint64_t, ff_bgr2UVOffset); #endif /* HAVE_INLINE_ASM */ -void ff_shuffle_bytes_2103_mmxext(const uint8_t *src, uint8_t *dst, int src_size); void ff_shuffle_bytes_2103_ssse3(const uint8_t *src, uint8_t *dst, int src_size); void ff_shuffle_bytes_0321_ssse3(const uint8_t *src, uint8_t *dst, int src_size); void ff_shuffle_bytes_1230_ssse3(const uint8_t *src, uint8_t *dst, int src_size); @@ -136,6 +2362,41 @@ void ff_uyvytoyuv422_sse2(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, void ff_uyvytoyuv422_avx(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, int width, int height, int lumStride, int chromStride, int srcStride); +void ff_uyvytoyuv422_avx2(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride); +#endif + +#define DEINTERLEAVE_BYTES(cpuext) \ +void ff_nv12ToUV_ ## cpuext(uint8_t *dstU, uint8_t *dstV, \ + const uint8_t *unused, \ + const uint8_t *src1, \ + const uint8_t *src2, \ + int w, \ + uint32_t *unused2, \ + void *opq); \ +static void deinterleave_bytes_ ## cpuext(const uint8_t *src, uint8_t *dst1, uint8_t *dst2, \ + int width, int height, int srcStride, \ + int dst1Stride, int dst2Stride) \ +{ \ + for (int h = 0; h < height; h++) { \ + if (width >= 16) \ + ff_nv12ToUV_ ## cpuext(dst1, dst2, NULL, src, NULL, width - 15, NULL, NULL); \ + for (int w = (width & (~15)); w < width; w++) { \ + dst1[w] = src[2*w+0]; \ + dst2[w] = src[2*w+1]; \ + } \ + src += srcStride; \ + dst1 += dst1Stride; \ + dst2 += dst2Stride; \ + } \ +} + +#if HAVE_SSE2_EXTERNAL +DEINTERLEAVE_BYTES(sse2) +#endif +#if HAVE_AVX_EXTERNAL +DEINTERLEAVE_BYTES(avx) #endif av_cold void rgb2rgb_init_x86(void) @@ -146,19 +2407,17 @@ av_cold void rgb2rgb_init_x86(void) if (INLINE_MMXEXT(cpu_flags)) rgb2rgb_init_mmxext(); if (INLINE_SSE2(cpu_flags)) - rgb2rgb_init_sse2(); - if (INLINE_AVX(cpu_flags)) - rgb2rgb_init_avx(); + interleaveBytes = interleave_bytes_sse2; #endif /* HAVE_INLINE_ASM */ - if (EXTERNAL_MMXEXT(cpu_flags)) { - shuffle_bytes_2103 = ff_shuffle_bytes_2103_mmxext; - } +#if HAVE_SSE2_EXTERNAL if (EXTERNAL_SSE2(cpu_flags)) { #if ARCH_X86_64 uyvytoyuv422 = ff_uyvytoyuv422_sse2; #endif + deinterleaveBytes = deinterleave_bytes_sse2; } +#endif if (EXTERNAL_SSSE3(cpu_flags)) { shuffle_bytes_0321 = ff_shuffle_bytes_0321_ssse3; shuffle_bytes_2103 = ff_shuffle_bytes_2103_ssse3; @@ -166,7 +2425,12 @@ av_cold void rgb2rgb_init_x86(void) shuffle_bytes_3012 = ff_shuffle_bytes_3012_ssse3; shuffle_bytes_3210 = ff_shuffle_bytes_3210_ssse3; } +#if HAVE_AVX_EXTERNAL + if (EXTERNAL_AVX(cpu_flags)) { + deinterleaveBytes = deinterleave_bytes_avx; #if ARCH_X86_64 + uyvytoyuv422 = ff_uyvytoyuv422_avx; + } if (EXTERNAL_AVX2_FAST(cpu_flags)) { shuffle_bytes_0321 = ff_shuffle_bytes_0321_avx2; shuffle_bytes_2103 = ff_shuffle_bytes_2103_avx2; @@ -174,8 +2438,9 @@ av_cold void rgb2rgb_init_x86(void) shuffle_bytes_3012 = ff_shuffle_bytes_3012_avx2; shuffle_bytes_3210 = ff_shuffle_bytes_3210_avx2; } - if (EXTERNAL_AVX(cpu_flags)) { - uyvytoyuv422 = ff_uyvytoyuv422_avx; + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + uyvytoyuv422 = ff_uyvytoyuv422_avx2; +#endif } #endif } diff --git a/libswscale/x86/rgb2rgb_template.c b/libswscale/x86/rgb2rgb_template.c deleted file mode 100644 index edbacea78..000000000 --- a/libswscale/x86/rgb2rgb_template.c +++ /dev/null @@ -1,2453 +0,0 @@ -/* - * software RGB to RGB converter - * pluralize by software PAL8 to RGB converter - * software YUV to YUV converter - * software YUV to RGB converter - * Written by Nick Kurshev. - * palette & YUV & runtime CPU stuff by Michael (michaelni@gmx.at) - * lot of big-endian byte order fixes by Alex Beregszaszi - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -#include "libavutil/attributes.h" -#include "libavutil/x86/asm.h" - -#undef PREFETCH -#undef MOVNTQ -#undef EMMS -#undef SFENCE -#undef PAVGB - -#define PREFETCH "prefetchnta" -#define PAVGB "pavgb" -#define MOVNTQ "movntq" -#define SFENCE "sfence" - -#define EMMS "emms" - -#if !COMPILE_TEMPLATE_SSE2 - -static inline void RENAME(rgb24tobgr32)(const uint8_t *src, uint8_t *dst, int src_size) -{ - uint8_t *dest = dst; - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - end = s + src_size; - __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); - mm_end = end - 23; - __asm__ volatile("movq %0, %%mm7"::"m"(mask32a):"memory"); - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movd (%1), %%mm0 \n\t" - "punpckldq 3(%1), %%mm0 \n\t" - "movd 6(%1), %%mm1 \n\t" - "punpckldq 9(%1), %%mm1 \n\t" - "movd 12(%1), %%mm2 \n\t" - "punpckldq 15(%1), %%mm2 \n\t" - "movd 18(%1), %%mm3 \n\t" - "punpckldq 21(%1), %%mm3 \n\t" - "por %%mm7, %%mm0 \n\t" - "por %%mm7, %%mm1 \n\t" - "por %%mm7, %%mm2 \n\t" - "por %%mm7, %%mm3 \n\t" - MOVNTQ" %%mm0, (%0) \n\t" - MOVNTQ" %%mm1, 8(%0) \n\t" - MOVNTQ" %%mm2, 16(%0) \n\t" - MOVNTQ" %%mm3, 24(%0)" - :: "r"(dest), "r"(s) - :"memory"); - dest += 32; - s += 24; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - *dest++ = *s++; - *dest++ = *s++; - *dest++ = *s++; - *dest++ = 255; - } -} - -#define STORE_BGR24_MMX \ - "psrlq $8, %%mm2 \n\t" \ - "psrlq $8, %%mm3 \n\t" \ - "psrlq $8, %%mm6 \n\t" \ - "psrlq $8, %%mm7 \n\t" \ - "pand "MANGLE(mask24l)", %%mm0\n\t" \ - "pand "MANGLE(mask24l)", %%mm1\n\t" \ - "pand "MANGLE(mask24l)", %%mm4\n\t" \ - "pand "MANGLE(mask24l)", %%mm5\n\t" \ - "pand "MANGLE(mask24h)", %%mm2\n\t" \ - "pand "MANGLE(mask24h)", %%mm3\n\t" \ - "pand "MANGLE(mask24h)", %%mm6\n\t" \ - "pand "MANGLE(mask24h)", %%mm7\n\t" \ - "por %%mm2, %%mm0 \n\t" \ - "por %%mm3, %%mm1 \n\t" \ - "por %%mm6, %%mm4 \n\t" \ - "por %%mm7, %%mm5 \n\t" \ - \ - "movq %%mm1, %%mm2 \n\t" \ - "movq %%mm4, %%mm3 \n\t" \ - "psllq $48, %%mm2 \n\t" \ - "psllq $32, %%mm3 \n\t" \ - "por %%mm2, %%mm0 \n\t" \ - "psrlq $16, %%mm1 \n\t" \ - "psrlq $32, %%mm4 \n\t" \ - "psllq $16, %%mm5 \n\t" \ - "por %%mm3, %%mm1 \n\t" \ - "por %%mm5, %%mm4 \n\t" \ - \ - MOVNTQ" %%mm0, (%0) \n\t" \ - MOVNTQ" %%mm1, 8(%0) \n\t" \ - MOVNTQ" %%mm4, 16(%0)" - - -static inline void RENAME(rgb32tobgr24)(const uint8_t *src, uint8_t *dst, int src_size) -{ - uint8_t *dest = dst; - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - end = s + src_size; - __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); - mm_end = end - 31; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movq (%1), %%mm0 \n\t" - "movq 8(%1), %%mm1 \n\t" - "movq 16(%1), %%mm4 \n\t" - "movq 24(%1), %%mm5 \n\t" - "movq %%mm0, %%mm2 \n\t" - "movq %%mm1, %%mm3 \n\t" - "movq %%mm4, %%mm6 \n\t" - "movq %%mm5, %%mm7 \n\t" - STORE_BGR24_MMX - :: "r"(dest), "r"(s) - NAMED_CONSTRAINTS_ADD(mask24l,mask24h) - :"memory"); - dest += 24; - s += 32; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - *dest++ = *s++; - *dest++ = *s++; - *dest++ = *s++; - s++; - } -} - -/* - original by Strepto/Astral - ported to gcc & bugfixed: A'rpi - MMXEXT, 3DNOW optimization by Nick Kurshev - 32-bit C version, and and&add trick by Michael Niedermayer -*/ -static inline void RENAME(rgb15to16)(const uint8_t *src, uint8_t *dst, int src_size) -{ - register const uint8_t* s=src; - register uint8_t* d=dst; - register const uint8_t *end; - const uint8_t *mm_end; - end = s + src_size; - __asm__ volatile(PREFETCH" %0"::"m"(*s)); - __asm__ volatile("movq %0, %%mm4"::"m"(mask15s)); - mm_end = end - 15; - while (s>1)&0x7FE07FE0) | (x&0x001F001F); - s+=4; - d+=4; - } - if (s < end) { - register uint16_t x= *((const uint16_t*)s); - *((uint16_t *)d) = ((x>>1)&0x7FE0) | (x&0x001F); - } -} - -static inline void RENAME(rgb32to16)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - uint16_t *d = (uint16_t *)dst; - end = s + src_size; - mm_end = end - 15; - __asm__ volatile( - "movq %3, %%mm5 \n\t" - "movq %4, %%mm6 \n\t" - "movq %5, %%mm7 \n\t" - "jmp 2f \n\t" - ".p2align 4 \n\t" - "1: \n\t" - PREFETCH" 32(%1) \n\t" - "movd (%1), %%mm0 \n\t" - "movd 4(%1), %%mm3 \n\t" - "punpckldq 8(%1), %%mm0 \n\t" - "punpckldq 12(%1), %%mm3 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm3, %%mm4 \n\t" - "pand %%mm6, %%mm0 \n\t" - "pand %%mm6, %%mm3 \n\t" - "pmaddwd %%mm7, %%mm0 \n\t" - "pmaddwd %%mm7, %%mm3 \n\t" - "pand %%mm5, %%mm1 \n\t" - "pand %%mm5, %%mm4 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm4, %%mm3 \n\t" - "psrld $5, %%mm0 \n\t" - "pslld $11, %%mm3 \n\t" - "por %%mm3, %%mm0 \n\t" - MOVNTQ" %%mm0, (%0) \n\t" - "add $16, %1 \n\t" - "add $8, %0 \n\t" - "2: \n\t" - "cmp %2, %1 \n\t" - " jb 1b \n\t" - : "+r" (d), "+r"(s) - : "r" (mm_end), "m" (mask3216g), "m" (mask3216br), "m" (mul3216) - ); - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - register int rgb = *(const uint32_t*)s; s += 4; - *d++ = ((rgb&0xFF)>>3) + ((rgb&0xFC00)>>5) + ((rgb&0xF80000)>>8); - } -} - -static inline void RENAME(rgb32tobgr16)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - uint16_t *d = (uint16_t *)dst; - end = s + src_size; - __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); - __asm__ volatile( - "movq %0, %%mm7 \n\t" - "movq %1, %%mm6 \n\t" - ::"m"(red_16mask),"m"(green_16mask)); - mm_end = end - 15; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movd (%1), %%mm0 \n\t" - "movd 4(%1), %%mm3 \n\t" - "punpckldq 8(%1), %%mm0 \n\t" - "punpckldq 12(%1), %%mm3 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm0, %%mm2 \n\t" - "movq %%mm3, %%mm4 \n\t" - "movq %%mm3, %%mm5 \n\t" - "psllq $8, %%mm0 \n\t" - "psllq $8, %%mm3 \n\t" - "pand %%mm7, %%mm0 \n\t" - "pand %%mm7, %%mm3 \n\t" - "psrlq $5, %%mm1 \n\t" - "psrlq $5, %%mm4 \n\t" - "pand %%mm6, %%mm1 \n\t" - "pand %%mm6, %%mm4 \n\t" - "psrlq $19, %%mm2 \n\t" - "psrlq $19, %%mm5 \n\t" - "pand %2, %%mm2 \n\t" - "pand %2, %%mm5 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm2, %%mm0 \n\t" - "por %%mm5, %%mm3 \n\t" - "psllq $16, %%mm3 \n\t" - "por %%mm3, %%mm0 \n\t" - MOVNTQ" %%mm0, (%0) \n\t" - :: "r"(d),"r"(s),"m"(blue_16mask):"memory"); - d += 4; - s += 16; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - register int rgb = *(const uint32_t*)s; s += 4; - *d++ = ((rgb&0xF8)<<8) + ((rgb&0xFC00)>>5) + ((rgb&0xF80000)>>19); - } -} - -static inline void RENAME(rgb32to15)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - uint16_t *d = (uint16_t *)dst; - end = s + src_size; - mm_end = end - 15; - __asm__ volatile( - "movq %3, %%mm5 \n\t" - "movq %4, %%mm6 \n\t" - "movq %5, %%mm7 \n\t" - "jmp 2f \n\t" - ".p2align 4 \n\t" - "1: \n\t" - PREFETCH" 32(%1) \n\t" - "movd (%1), %%mm0 \n\t" - "movd 4(%1), %%mm3 \n\t" - "punpckldq 8(%1), %%mm0 \n\t" - "punpckldq 12(%1), %%mm3 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm3, %%mm4 \n\t" - "pand %%mm6, %%mm0 \n\t" - "pand %%mm6, %%mm3 \n\t" - "pmaddwd %%mm7, %%mm0 \n\t" - "pmaddwd %%mm7, %%mm3 \n\t" - "pand %%mm5, %%mm1 \n\t" - "pand %%mm5, %%mm4 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm4, %%mm3 \n\t" - "psrld $6, %%mm0 \n\t" - "pslld $10, %%mm3 \n\t" - "por %%mm3, %%mm0 \n\t" - MOVNTQ" %%mm0, (%0) \n\t" - "add $16, %1 \n\t" - "add $8, %0 \n\t" - "2: \n\t" - "cmp %2, %1 \n\t" - " jb 1b \n\t" - : "+r" (d), "+r"(s) - : "r" (mm_end), "m" (mask3215g), "m" (mask3216br), "m" (mul3215) - ); - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - register int rgb = *(const uint32_t*)s; s += 4; - *d++ = ((rgb&0xFF)>>3) + ((rgb&0xF800)>>6) + ((rgb&0xF80000)>>9); - } -} - -static inline void RENAME(rgb32tobgr15)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - uint16_t *d = (uint16_t *)dst; - end = s + src_size; - __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); - __asm__ volatile( - "movq %0, %%mm7 \n\t" - "movq %1, %%mm6 \n\t" - ::"m"(red_15mask),"m"(green_15mask)); - mm_end = end - 15; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movd (%1), %%mm0 \n\t" - "movd 4(%1), %%mm3 \n\t" - "punpckldq 8(%1), %%mm0 \n\t" - "punpckldq 12(%1), %%mm3 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm0, %%mm2 \n\t" - "movq %%mm3, %%mm4 \n\t" - "movq %%mm3, %%mm5 \n\t" - "psllq $7, %%mm0 \n\t" - "psllq $7, %%mm3 \n\t" - "pand %%mm7, %%mm0 \n\t" - "pand %%mm7, %%mm3 \n\t" - "psrlq $6, %%mm1 \n\t" - "psrlq $6, %%mm4 \n\t" - "pand %%mm6, %%mm1 \n\t" - "pand %%mm6, %%mm4 \n\t" - "psrlq $19, %%mm2 \n\t" - "psrlq $19, %%mm5 \n\t" - "pand %2, %%mm2 \n\t" - "pand %2, %%mm5 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm2, %%mm0 \n\t" - "por %%mm5, %%mm3 \n\t" - "psllq $16, %%mm3 \n\t" - "por %%mm3, %%mm0 \n\t" - MOVNTQ" %%mm0, (%0) \n\t" - ::"r"(d),"r"(s),"m"(blue_15mask):"memory"); - d += 4; - s += 16; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - register int rgb = *(const uint32_t*)s; s += 4; - *d++ = ((rgb&0xF8)<<7) + ((rgb&0xF800)>>6) + ((rgb&0xF80000)>>19); - } -} - -static inline void RENAME(rgb24tobgr16)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - uint16_t *d = (uint16_t *)dst; - end = s + src_size; - __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); - __asm__ volatile( - "movq %0, %%mm7 \n\t" - "movq %1, %%mm6 \n\t" - ::"m"(red_16mask),"m"(green_16mask)); - mm_end = end - 11; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movd (%1), %%mm0 \n\t" - "movd 3(%1), %%mm3 \n\t" - "punpckldq 6(%1), %%mm0 \n\t" - "punpckldq 9(%1), %%mm3 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm0, %%mm2 \n\t" - "movq %%mm3, %%mm4 \n\t" - "movq %%mm3, %%mm5 \n\t" - "psrlq $3, %%mm0 \n\t" - "psrlq $3, %%mm3 \n\t" - "pand %2, %%mm0 \n\t" - "pand %2, %%mm3 \n\t" - "psrlq $5, %%mm1 \n\t" - "psrlq $5, %%mm4 \n\t" - "pand %%mm6, %%mm1 \n\t" - "pand %%mm6, %%mm4 \n\t" - "psrlq $8, %%mm2 \n\t" - "psrlq $8, %%mm5 \n\t" - "pand %%mm7, %%mm2 \n\t" - "pand %%mm7, %%mm5 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm2, %%mm0 \n\t" - "por %%mm5, %%mm3 \n\t" - "psllq $16, %%mm3 \n\t" - "por %%mm3, %%mm0 \n\t" - MOVNTQ" %%mm0, (%0) \n\t" - ::"r"(d),"r"(s),"m"(blue_16mask):"memory"); - d += 4; - s += 12; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - const int b = *s++; - const int g = *s++; - const int r = *s++; - *d++ = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8); - } -} - -static inline void RENAME(rgb24to16)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - uint16_t *d = (uint16_t *)dst; - end = s + src_size; - __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); - __asm__ volatile( - "movq %0, %%mm7 \n\t" - "movq %1, %%mm6 \n\t" - ::"m"(red_16mask),"m"(green_16mask)); - mm_end = end - 15; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movd (%1), %%mm0 \n\t" - "movd 3(%1), %%mm3 \n\t" - "punpckldq 6(%1), %%mm0 \n\t" - "punpckldq 9(%1), %%mm3 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm0, %%mm2 \n\t" - "movq %%mm3, %%mm4 \n\t" - "movq %%mm3, %%mm5 \n\t" - "psllq $8, %%mm0 \n\t" - "psllq $8, %%mm3 \n\t" - "pand %%mm7, %%mm0 \n\t" - "pand %%mm7, %%mm3 \n\t" - "psrlq $5, %%mm1 \n\t" - "psrlq $5, %%mm4 \n\t" - "pand %%mm6, %%mm1 \n\t" - "pand %%mm6, %%mm4 \n\t" - "psrlq $19, %%mm2 \n\t" - "psrlq $19, %%mm5 \n\t" - "pand %2, %%mm2 \n\t" - "pand %2, %%mm5 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm2, %%mm0 \n\t" - "por %%mm5, %%mm3 \n\t" - "psllq $16, %%mm3 \n\t" - "por %%mm3, %%mm0 \n\t" - MOVNTQ" %%mm0, (%0) \n\t" - ::"r"(d),"r"(s),"m"(blue_16mask):"memory"); - d += 4; - s += 12; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - const int r = *s++; - const int g = *s++; - const int b = *s++; - *d++ = (b>>3) | ((g&0xFC)<<3) | ((r&0xF8)<<8); - } -} - -static inline void RENAME(rgb24tobgr15)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - uint16_t *d = (uint16_t *)dst; - end = s + src_size; - __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); - __asm__ volatile( - "movq %0, %%mm7 \n\t" - "movq %1, %%mm6 \n\t" - ::"m"(red_15mask),"m"(green_15mask)); - mm_end = end - 11; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movd (%1), %%mm0 \n\t" - "movd 3(%1), %%mm3 \n\t" - "punpckldq 6(%1), %%mm0 \n\t" - "punpckldq 9(%1), %%mm3 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm0, %%mm2 \n\t" - "movq %%mm3, %%mm4 \n\t" - "movq %%mm3, %%mm5 \n\t" - "psrlq $3, %%mm0 \n\t" - "psrlq $3, %%mm3 \n\t" - "pand %2, %%mm0 \n\t" - "pand %2, %%mm3 \n\t" - "psrlq $6, %%mm1 \n\t" - "psrlq $6, %%mm4 \n\t" - "pand %%mm6, %%mm1 \n\t" - "pand %%mm6, %%mm4 \n\t" - "psrlq $9, %%mm2 \n\t" - "psrlq $9, %%mm5 \n\t" - "pand %%mm7, %%mm2 \n\t" - "pand %%mm7, %%mm5 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm2, %%mm0 \n\t" - "por %%mm5, %%mm3 \n\t" - "psllq $16, %%mm3 \n\t" - "por %%mm3, %%mm0 \n\t" - MOVNTQ" %%mm0, (%0) \n\t" - ::"r"(d),"r"(s),"m"(blue_15mask):"memory"); - d += 4; - s += 12; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - const int b = *s++; - const int g = *s++; - const int r = *s++; - *d++ = (b>>3) | ((g&0xF8)<<2) | ((r&0xF8)<<7); - } -} - -static inline void RENAME(rgb24to15)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint8_t *s = src; - const uint8_t *end; - const uint8_t *mm_end; - uint16_t *d = (uint16_t *)dst; - end = s + src_size; - __asm__ volatile(PREFETCH" %0"::"m"(*src):"memory"); - __asm__ volatile( - "movq %0, %%mm7 \n\t" - "movq %1, %%mm6 \n\t" - ::"m"(red_15mask),"m"(green_15mask)); - mm_end = end - 15; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movd (%1), %%mm0 \n\t" - "movd 3(%1), %%mm3 \n\t" - "punpckldq 6(%1), %%mm0 \n\t" - "punpckldq 9(%1), %%mm3 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm0, %%mm2 \n\t" - "movq %%mm3, %%mm4 \n\t" - "movq %%mm3, %%mm5 \n\t" - "psllq $7, %%mm0 \n\t" - "psllq $7, %%mm3 \n\t" - "pand %%mm7, %%mm0 \n\t" - "pand %%mm7, %%mm3 \n\t" - "psrlq $6, %%mm1 \n\t" - "psrlq $6, %%mm4 \n\t" - "pand %%mm6, %%mm1 \n\t" - "pand %%mm6, %%mm4 \n\t" - "psrlq $19, %%mm2 \n\t" - "psrlq $19, %%mm5 \n\t" - "pand %2, %%mm2 \n\t" - "pand %2, %%mm5 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm2, %%mm0 \n\t" - "por %%mm5, %%mm3 \n\t" - "psllq $16, %%mm3 \n\t" - "por %%mm3, %%mm0 \n\t" - MOVNTQ" %%mm0, (%0) \n\t" - ::"r"(d),"r"(s),"m"(blue_15mask):"memory"); - d += 4; - s += 12; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - const int r = *s++; - const int g = *s++; - const int b = *s++; - *d++ = (b>>3) | ((g&0xF8)<<2) | ((r&0xF8)<<7); - } -} - -static inline void RENAME(rgb15tobgr24)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint16_t *end; - const uint16_t *mm_end; - uint8_t *d = dst; - const uint16_t *s = (const uint16_t*)src; - end = s + src_size/2; - __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); - mm_end = end - 7; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movq (%1), %%mm0 \n\t" - "movq (%1), %%mm1 \n\t" - "movq (%1), %%mm2 \n\t" - "pand %2, %%mm0 \n\t" - "pand %3, %%mm1 \n\t" - "pand %4, %%mm2 \n\t" - "psllq $5, %%mm0 \n\t" - "pmulhw "MANGLE(mul15_mid)", %%mm0 \n\t" - "pmulhw "MANGLE(mul15_mid)", %%mm1 \n\t" - "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" - "movq %%mm0, %%mm3 \n\t" - "movq %%mm1, %%mm4 \n\t" - "movq %%mm2, %%mm5 \n\t" - "punpcklwd %5, %%mm0 \n\t" - "punpcklwd %5, %%mm1 \n\t" - "punpcklwd %5, %%mm2 \n\t" - "punpckhwd %5, %%mm3 \n\t" - "punpckhwd %5, %%mm4 \n\t" - "punpckhwd %5, %%mm5 \n\t" - "psllq $8, %%mm1 \n\t" - "psllq $16, %%mm2 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm2, %%mm0 \n\t" - "psllq $8, %%mm4 \n\t" - "psllq $16, %%mm5 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm5, %%mm3 \n\t" - - "movq %%mm0, %%mm6 \n\t" - "movq %%mm3, %%mm7 \n\t" - - "movq 8(%1), %%mm0 \n\t" - "movq 8(%1), %%mm1 \n\t" - "movq 8(%1), %%mm2 \n\t" - "pand %2, %%mm0 \n\t" - "pand %3, %%mm1 \n\t" - "pand %4, %%mm2 \n\t" - "psllq $5, %%mm0 \n\t" - "pmulhw "MANGLE(mul15_mid)", %%mm0 \n\t" - "pmulhw "MANGLE(mul15_mid)", %%mm1 \n\t" - "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" - "movq %%mm0, %%mm3 \n\t" - "movq %%mm1, %%mm4 \n\t" - "movq %%mm2, %%mm5 \n\t" - "punpcklwd %5, %%mm0 \n\t" - "punpcklwd %5, %%mm1 \n\t" - "punpcklwd %5, %%mm2 \n\t" - "punpckhwd %5, %%mm3 \n\t" - "punpckhwd %5, %%mm4 \n\t" - "punpckhwd %5, %%mm5 \n\t" - "psllq $8, %%mm1 \n\t" - "psllq $16, %%mm2 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm2, %%mm0 \n\t" - "psllq $8, %%mm4 \n\t" - "psllq $16, %%mm5 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm5, %%mm3 \n\t" - - :"=m"(*d) - :"r"(s),"m"(mask15b),"m"(mask15g),"m"(mask15r), "m"(mmx_null) - NAMED_CONSTRAINTS_ADD(mul15_mid,mul15_hi) - :"memory"); - /* borrowed 32 to 24 */ - __asm__ volatile( - "movq %%mm0, %%mm4 \n\t" - "movq %%mm3, %%mm5 \n\t" - "movq %%mm6, %%mm0 \n\t" - "movq %%mm7, %%mm1 \n\t" - - "movq %%mm4, %%mm6 \n\t" - "movq %%mm5, %%mm7 \n\t" - "movq %%mm0, %%mm2 \n\t" - "movq %%mm1, %%mm3 \n\t" - - STORE_BGR24_MMX - - :: "r"(d), "m"(*s) - NAMED_CONSTRAINTS_ADD(mask24l,mask24h) - :"memory"); - d += 24; - s += 8; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - register uint16_t bgr; - bgr = *s++; - *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2); - *d++ = ((bgr&0x3E0)>>2) | ((bgr&0x3E0)>>7); - *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); - } -} - -static inline void RENAME(rgb16tobgr24)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint16_t *end; - const uint16_t *mm_end; - uint8_t *d = (uint8_t *)dst; - const uint16_t *s = (const uint16_t *)src; - end = s + src_size/2; - __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); - mm_end = end - 7; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movq (%1), %%mm0 \n\t" - "movq (%1), %%mm1 \n\t" - "movq (%1), %%mm2 \n\t" - "pand %2, %%mm0 \n\t" - "pand %3, %%mm1 \n\t" - "pand %4, %%mm2 \n\t" - "psllq $5, %%mm0 \n\t" - "psrlq $1, %%mm2 \n\t" - "pmulhw "MANGLE(mul15_mid)", %%mm0 \n\t" - "pmulhw "MANGLE(mul16_mid)", %%mm1 \n\t" - "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" - "movq %%mm0, %%mm3 \n\t" - "movq %%mm1, %%mm4 \n\t" - "movq %%mm2, %%mm5 \n\t" - "punpcklwd %5, %%mm0 \n\t" - "punpcklwd %5, %%mm1 \n\t" - "punpcklwd %5, %%mm2 \n\t" - "punpckhwd %5, %%mm3 \n\t" - "punpckhwd %5, %%mm4 \n\t" - "punpckhwd %5, %%mm5 \n\t" - "psllq $8, %%mm1 \n\t" - "psllq $16, %%mm2 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm2, %%mm0 \n\t" - "psllq $8, %%mm4 \n\t" - "psllq $16, %%mm5 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm5, %%mm3 \n\t" - - "movq %%mm0, %%mm6 \n\t" - "movq %%mm3, %%mm7 \n\t" - - "movq 8(%1), %%mm0 \n\t" - "movq 8(%1), %%mm1 \n\t" - "movq 8(%1), %%mm2 \n\t" - "pand %2, %%mm0 \n\t" - "pand %3, %%mm1 \n\t" - "pand %4, %%mm2 \n\t" - "psllq $5, %%mm0 \n\t" - "psrlq $1, %%mm2 \n\t" - "pmulhw "MANGLE(mul15_mid)", %%mm0 \n\t" - "pmulhw "MANGLE(mul16_mid)", %%mm1 \n\t" - "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" - "movq %%mm0, %%mm3 \n\t" - "movq %%mm1, %%mm4 \n\t" - "movq %%mm2, %%mm5 \n\t" - "punpcklwd %5, %%mm0 \n\t" - "punpcklwd %5, %%mm1 \n\t" - "punpcklwd %5, %%mm2 \n\t" - "punpckhwd %5, %%mm3 \n\t" - "punpckhwd %5, %%mm4 \n\t" - "punpckhwd %5, %%mm5 \n\t" - "psllq $8, %%mm1 \n\t" - "psllq $16, %%mm2 \n\t" - "por %%mm1, %%mm0 \n\t" - "por %%mm2, %%mm0 \n\t" - "psllq $8, %%mm4 \n\t" - "psllq $16, %%mm5 \n\t" - "por %%mm4, %%mm3 \n\t" - "por %%mm5, %%mm3 \n\t" - :"=m"(*d) - :"r"(s),"m"(mask16b),"m"(mask16g),"m"(mask16r),"m"(mmx_null) - NAMED_CONSTRAINTS_ADD(mul15_mid,mul16_mid,mul15_hi) - :"memory"); - /* borrowed 32 to 24 */ - __asm__ volatile( - "movq %%mm0, %%mm4 \n\t" - "movq %%mm3, %%mm5 \n\t" - "movq %%mm6, %%mm0 \n\t" - "movq %%mm7, %%mm1 \n\t" - - "movq %%mm4, %%mm6 \n\t" - "movq %%mm5, %%mm7 \n\t" - "movq %%mm0, %%mm2 \n\t" - "movq %%mm1, %%mm3 \n\t" - - STORE_BGR24_MMX - - :: "r"(d), "m"(*s) - NAMED_CONSTRAINTS_ADD(mask24l,mask24h) - :"memory"); - d += 24; - s += 8; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - register uint16_t bgr; - bgr = *s++; - *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2); - *d++ = ((bgr&0x7E0)>>3) | ((bgr&0x7E0)>>9); - *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); - } -} - -/* - * mm0 = 00 B3 00 B2 00 B1 00 B0 - * mm1 = 00 G3 00 G2 00 G1 00 G0 - * mm2 = 00 R3 00 R2 00 R1 00 R0 - * mm6 = FF FF FF FF FF FF FF FF - * mm7 = 00 00 00 00 00 00 00 00 - */ -#define PACK_RGB32 \ - "packuswb %%mm7, %%mm0 \n\t" /* 00 00 00 00 B3 B2 B1 B0 */ \ - "packuswb %%mm7, %%mm1 \n\t" /* 00 00 00 00 G3 G2 G1 G0 */ \ - "packuswb %%mm7, %%mm2 \n\t" /* 00 00 00 00 R3 R2 R1 R0 */ \ - "punpcklbw %%mm1, %%mm0 \n\t" /* G3 B3 G2 B2 G1 B1 G0 B0 */ \ - "punpcklbw %%mm6, %%mm2 \n\t" /* FF R3 FF R2 FF R1 FF R0 */ \ - "movq %%mm0, %%mm3 \n\t" \ - "punpcklwd %%mm2, %%mm0 \n\t" /* FF R1 G1 B1 FF R0 G0 B0 */ \ - "punpckhwd %%mm2, %%mm3 \n\t" /* FF R3 G3 B3 FF R2 G2 B2 */ \ - MOVNTQ" %%mm0, (%0) \n\t" \ - MOVNTQ" %%mm3, 8(%0) \n\t" \ - -static inline void RENAME(rgb15to32)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint16_t *end; - const uint16_t *mm_end; - uint8_t *d = dst; - const uint16_t *s = (const uint16_t *)src; - end = s + src_size/2; - __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); - __asm__ volatile("pxor %%mm7,%%mm7 \n\t":::"memory"); - __asm__ volatile("pcmpeqd %%mm6,%%mm6 \n\t":::"memory"); - mm_end = end - 3; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movq (%1), %%mm0 \n\t" - "movq (%1), %%mm1 \n\t" - "movq (%1), %%mm2 \n\t" - "pand %2, %%mm0 \n\t" - "pand %3, %%mm1 \n\t" - "pand %4, %%mm2 \n\t" - "psllq $5, %%mm0 \n\t" - "pmulhw %5, %%mm0 \n\t" - "pmulhw %5, %%mm1 \n\t" - "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" - PACK_RGB32 - ::"r"(d),"r"(s),"m"(mask15b),"m"(mask15g),"m"(mask15r) ,"m"(mul15_mid) - NAMED_CONSTRAINTS_ADD(mul15_hi) - :"memory"); - d += 16; - s += 4; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - register uint16_t bgr; - bgr = *s++; - *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2); - *d++ = ((bgr&0x3E0)>>2) | ((bgr&0x3E0)>>7); - *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); - *d++ = 255; - } -} - -static inline void RENAME(rgb16to32)(const uint8_t *src, uint8_t *dst, int src_size) -{ - const uint16_t *end; - const uint16_t *mm_end; - uint8_t *d = dst; - const uint16_t *s = (const uint16_t*)src; - end = s + src_size/2; - __asm__ volatile(PREFETCH" %0"::"m"(*s):"memory"); - __asm__ volatile("pxor %%mm7,%%mm7 \n\t":::"memory"); - __asm__ volatile("pcmpeqd %%mm6,%%mm6 \n\t":::"memory"); - mm_end = end - 3; - while (s < mm_end) { - __asm__ volatile( - PREFETCH" 32(%1) \n\t" - "movq (%1), %%mm0 \n\t" - "movq (%1), %%mm1 \n\t" - "movq (%1), %%mm2 \n\t" - "pand %2, %%mm0 \n\t" - "pand %3, %%mm1 \n\t" - "pand %4, %%mm2 \n\t" - "psllq $5, %%mm0 \n\t" - "psrlq $1, %%mm2 \n\t" - "pmulhw %5, %%mm0 \n\t" - "pmulhw "MANGLE(mul16_mid)", %%mm1 \n\t" - "pmulhw "MANGLE(mul15_hi)", %%mm2 \n\t" - PACK_RGB32 - ::"r"(d),"r"(s),"m"(mask16b),"m"(mask16g),"m"(mask16r),"m"(mul15_mid) - NAMED_CONSTRAINTS_ADD(mul16_mid,mul15_hi) - :"memory"); - d += 16; - s += 4; - } - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - while (s < end) { - register uint16_t bgr; - bgr = *s++; - *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2); - *d++ = ((bgr&0x7E0)>>3) | ((bgr&0x7E0)>>9); - *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); - *d++ = 255; - } -} - -static inline void RENAME(rgb24tobgr24)(const uint8_t *src, uint8_t *dst, int src_size) -{ - unsigned i; - x86_reg mmx_size= 23 - src_size; - __asm__ volatile ( - "test %%"FF_REG_a", %%"FF_REG_a" \n\t" - "jns 2f \n\t" - "movq "MANGLE(mask24r)", %%mm5 \n\t" - "movq "MANGLE(mask24g)", %%mm6 \n\t" - "movq "MANGLE(mask24b)", %%mm7 \n\t" - ".p2align 4 \n\t" - "1: \n\t" - PREFETCH" 32(%1, %%"FF_REG_a") \n\t" - "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" // BGR BGR BG - "movq (%1, %%"FF_REG_a"), %%mm1 \n\t" // BGR BGR BG - "movq 2(%1, %%"FF_REG_a"), %%mm2 \n\t" // R BGR BGR B - "psllq $16, %%mm0 \n\t" // 00 BGR BGR - "pand %%mm5, %%mm0 \n\t" - "pand %%mm6, %%mm1 \n\t" - "pand %%mm7, %%mm2 \n\t" - "por %%mm0, %%mm1 \n\t" - "por %%mm2, %%mm1 \n\t" - "movq 6(%1, %%"FF_REG_a"), %%mm0 \n\t" // BGR BGR BG - MOVNTQ" %%mm1,(%2, %%"FF_REG_a") \n\t" // RGB RGB RG - "movq 8(%1, %%"FF_REG_a"), %%mm1 \n\t" // R BGR BGR B - "movq 10(%1, %%"FF_REG_a"), %%mm2 \n\t" // GR BGR BGR - "pand %%mm7, %%mm0 \n\t" - "pand %%mm5, %%mm1 \n\t" - "pand %%mm6, %%mm2 \n\t" - "por %%mm0, %%mm1 \n\t" - "por %%mm2, %%mm1 \n\t" - "movq 14(%1, %%"FF_REG_a"), %%mm0 \n\t" // R BGR BGR B - MOVNTQ" %%mm1, 8(%2, %%"FF_REG_a")\n\t" // B RGB RGB R - "movq 16(%1, %%"FF_REG_a"), %%mm1 \n\t" // GR BGR BGR - "movq 18(%1, %%"FF_REG_a"), %%mm2 \n\t" // BGR BGR BG - "pand %%mm6, %%mm0 \n\t" - "pand %%mm7, %%mm1 \n\t" - "pand %%mm5, %%mm2 \n\t" - "por %%mm0, %%mm1 \n\t" - "por %%mm2, %%mm1 \n\t" - MOVNTQ" %%mm1, 16(%2, %%"FF_REG_a") \n\t" - "add $24, %%"FF_REG_a" \n\t" - " js 1b \n\t" - "2: \n\t" - : "+a" (mmx_size) - : "r" (src-mmx_size), "r"(dst-mmx_size) - NAMED_CONSTRAINTS_ADD(mask24r,mask24g,mask24b) - ); - - __asm__ volatile(SFENCE:::"memory"); - __asm__ volatile(EMMS:::"memory"); - - if (mmx_size==23) return; //finished, was multiple of 8 - - src+= src_size; - dst+= src_size; - src_size= 23-mmx_size; - src-= src_size; - dst-= src_size; - for (i=0; i>1; - for (y=0; y>1; - for (y=0; y>1; - for (y=0; y>2; - dst[2*x+2]= ( src[x] + 3*src[x+1])>>2; - } - dst[2*srcWidth-1]= src[srcWidth-1]; - - dst+= dstStride; - - for (y=1; y> 2; - dst[dstStride] = (src[0] + 3 * src[srcStride]) >> 2; - } - - for (x=mmxSize-1; x>2; - dst[2*x+dstStride+2]= ( src[x+0] + 3*src[x+srcStride+1])>>2; - dst[2*x+dstStride+1]= ( src[x+1] + 3*src[x+srcStride ])>>2; - dst[2*x +2]= (3*src[x+1] + src[x+srcStride ])>>2; - } - dst[srcWidth*2 -1 ]= (3*src[srcWidth-1] + src[srcWidth-1 + srcStride])>>2; - dst[srcWidth*2 -1 + dstStride]= ( src[srcWidth-1] + 3*src[srcWidth-1 + srcStride])>>2; - - dst+=dstStride*2; - src+=srcStride; - } - - // last line - dst[0]= src[0]; - - for (x=0; x>2; - dst[2*x+2]= ( src[x] + 3*src[x+1])>>2; - } - dst[2*srcWidth-1]= src[srcWidth-1]; - - __asm__ volatile(EMMS" \n\t" - SFENCE" \n\t" - :::"memory"); -} - -/** - * Height should be a multiple of 2 and width should be a multiple of 16. - * (If this is a problem for anyone then tell me, and I will fix it.) - * Chrominance data is only taken from every second line, others are ignored. - * FIXME: Write HQ version. - */ -static inline void RENAME(uyvytoyv12)(const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, - int width, int height, - int lumStride, int chromStride, int srcStride) -{ - int y; - const x86_reg chromWidth= width>>1; - for (y=0; y>1; - - if (height > 2) { - ff_rgb24toyv12_c(src, ydst, udst, vdst, width, 2, lumStride, chromStride, srcStride, rgb2yuv); - src += 2*srcStride; - ydst += 2*lumStride; - udst += chromStride; - vdst += chromStride; - height -= 2; - } - - for (y=0; y= 16) { - if (!((((intptr_t)src1) | ((intptr_t)src2) | ((intptr_t)dest))&15)) { - __asm__( - "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" - "1: \n\t" - PREFETCH" 64(%1, %%"FF_REG_a") \n\t" - PREFETCH" 64(%2, %%"FF_REG_a") \n\t" - "movdqa (%1, %%"FF_REG_a"), %%xmm0 \n\t" - "movdqa (%1, %%"FF_REG_a"), %%xmm1 \n\t" - "movdqa (%2, %%"FF_REG_a"), %%xmm2 \n\t" - "punpcklbw %%xmm2, %%xmm0 \n\t" - "punpckhbw %%xmm2, %%xmm1 \n\t" - "movntdq %%xmm0, (%0, %%"FF_REG_a", 2) \n\t" - "movntdq %%xmm1, 16(%0, %%"FF_REG_a", 2) \n\t" - "add $16, %%"FF_REG_a" \n\t" - "cmp %3, %%"FF_REG_a" \n\t" - " jb 1b \n\t" - ::"r"(dest), "r"(src1), "r"(src2), "r" ((x86_reg)width-15) - : "memory", XMM_CLOBBERS("xmm0", "xmm1", "xmm2",) "%"FF_REG_a - ); - } else - __asm__( - "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" - "1: \n\t" - PREFETCH" 64(%1, %%"FF_REG_a") \n\t" - PREFETCH" 64(%2, %%"FF_REG_a") \n\t" - "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" - "movq 8(%1, %%"FF_REG_a"), %%mm2 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm2, %%mm3 \n\t" - "movq (%2, %%"FF_REG_a"), %%mm4 \n\t" - "movq 8(%2, %%"FF_REG_a"), %%mm5 \n\t" - "punpcklbw %%mm4, %%mm0 \n\t" - "punpckhbw %%mm4, %%mm1 \n\t" - "punpcklbw %%mm5, %%mm2 \n\t" - "punpckhbw %%mm5, %%mm3 \n\t" - MOVNTQ" %%mm0, (%0, %%"FF_REG_a", 2) \n\t" - MOVNTQ" %%mm1, 8(%0, %%"FF_REG_a", 2) \n\t" - MOVNTQ" %%mm2, 16(%0, %%"FF_REG_a", 2) \n\t" - MOVNTQ" %%mm3, 24(%0, %%"FF_REG_a", 2) \n\t" - "add $16, %%"FF_REG_a" \n\t" - "cmp %3, %%"FF_REG_a" \n\t" - " jb 1b \n\t" - ::"r"(dest), "r"(src1), "r"(src2), "r" ((x86_reg)width-15) - : "memory", "%"FF_REG_a - ); - - } - for (w= (width&(~15)); w < width; w++) { - dest[2*w+0] = src1[w]; - dest[2*w+1] = src2[w]; - } - dest += dstStride; - src1 += src1Stride; - src2 += src2Stride; - } - __asm__( - EMMS" \n\t" - SFENCE" \n\t" - ::: "memory" - ); -} -#endif /* !COMPILE_TEMPLATE_AVX && COMPILE_TEMPLATE_SSE2 */ - -#if !COMPILE_TEMPLATE_AVX || HAVE_AVX_EXTERNAL -#if COMPILE_TEMPLATE_SSE2 && HAVE_X86ASM -void RENAME(ff_nv12ToUV)(uint8_t *dstU, uint8_t *dstV, - const uint8_t *unused, - const uint8_t *src1, - const uint8_t *src2, - int w, - uint32_t *unused2, - void *opq); -static void RENAME(deinterleaveBytes)(const uint8_t *src, uint8_t *dst1, uint8_t *dst2, - int width, int height, int srcStride, - int dst1Stride, int dst2Stride) -{ - int h; - - for (h = 0; h < height; h++) { - RENAME(ff_nv12ToUV)(dst1, dst2, NULL, src, NULL, width, NULL, NULL); - src += srcStride; - dst1 += dst1Stride; - dst2 += dst2Stride; - } - __asm__( - SFENCE" \n\t" - ::: "memory" - ); -} -#endif /* COMPILE_TEMPLATE_SSE2 && HAVE_X86ASM */ -#endif /* !COMPILE_TEMPLATE_AVX || HAVE_AVX_EXTERNAL */ - -#if !COMPILE_TEMPLATE_SSE2 -static inline void RENAME(vu9_to_vu12)(const uint8_t *src1, const uint8_t *src2, - uint8_t *dst1, uint8_t *dst2, - int width, int height, - int srcStride1, int srcStride2, - int dstStride1, int dstStride2) -{ - x86_reg x, y; - int w,h; - w=width/2; h=height/2; - __asm__ volatile( - PREFETCH" %0 \n\t" - PREFETCH" %1 \n\t" - ::"m"(*(src1+srcStride1)),"m"(*(src2+srcStride2)):"memory"); - for (y=0;y>1); - uint8_t* d=dst1+dstStride1*y; - x=0; - for (;x>1); - uint8_t* d=dst2+dstStride2*y; - x=0; - for (;x>2); - const uint8_t* vp=src3+srcStride3*(y>>2); - uint8_t* d=dst+dstStride*y; - x=0; - for (;x>1; - dst1[count]= (src0[4*count+2]+src1[4*count+2])>>1; - count++; - } -} - -static void RENAME(extract_odd2)(const uint8_t *src, uint8_t *dst0, uint8_t *dst1, x86_reg count) -{ - dst0+= count; - dst1+= count; - src += 4*count; - count= - count; - if(count <= -8) { - count += 7; - __asm__ volatile( - "pcmpeqw %%mm7, %%mm7 \n\t" - "psrlw $8, %%mm7 \n\t" - "1: \n\t" - "movq -28(%1, %0, 4), %%mm0 \n\t" - "movq -20(%1, %0, 4), %%mm1 \n\t" - "movq -12(%1, %0, 4), %%mm2 \n\t" - "movq -4(%1, %0, 4), %%mm3 \n\t" - "psrlw $8, %%mm0 \n\t" - "psrlw $8, %%mm1 \n\t" - "psrlw $8, %%mm2 \n\t" - "psrlw $8, %%mm3 \n\t" - "packuswb %%mm1, %%mm0 \n\t" - "packuswb %%mm3, %%mm2 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm2, %%mm3 \n\t" - "psrlw $8, %%mm0 \n\t" - "psrlw $8, %%mm2 \n\t" - "pand %%mm7, %%mm1 \n\t" - "pand %%mm7, %%mm3 \n\t" - "packuswb %%mm2, %%mm0 \n\t" - "packuswb %%mm3, %%mm1 \n\t" - MOVNTQ" %%mm0,- 7(%3, %0) \n\t" - MOVNTQ" %%mm1,- 7(%2, %0) \n\t" - "add $8, %0 \n\t" - " js 1b \n\t" - : "+r"(count) - : "r"(src), "r"(dst0), "r"(dst1) - ); - count -= 7; - } - src++; - while(count<0) { - dst0[count]= src[4*count+0]; - dst1[count]= src[4*count+2]; - count++; - } -} - -static void RENAME(extract_odd2avg)(const uint8_t *src0, const uint8_t *src1, uint8_t *dst0, uint8_t *dst1, x86_reg count) -{ - dst0 += count; - dst1 += count; - src0 += 4*count; - src1 += 4*count; - count= - count; -#ifdef PAVGB - if(count <= -8) { - count += 7; - __asm__ volatile( - "pcmpeqw %%mm7, %%mm7 \n\t" - "psrlw $8, %%mm7 \n\t" - "1: \n\t" - "movq -28(%1, %0, 4), %%mm0 \n\t" - "movq -20(%1, %0, 4), %%mm1 \n\t" - "movq -12(%1, %0, 4), %%mm2 \n\t" - "movq -4(%1, %0, 4), %%mm3 \n\t" - PAVGB" -28(%2, %0, 4), %%mm0 \n\t" - PAVGB" -20(%2, %0, 4), %%mm1 \n\t" - PAVGB" -12(%2, %0, 4), %%mm2 \n\t" - PAVGB" - 4(%2, %0, 4), %%mm3 \n\t" - "psrlw $8, %%mm0 \n\t" - "psrlw $8, %%mm1 \n\t" - "psrlw $8, %%mm2 \n\t" - "psrlw $8, %%mm3 \n\t" - "packuswb %%mm1, %%mm0 \n\t" - "packuswb %%mm3, %%mm2 \n\t" - "movq %%mm0, %%mm1 \n\t" - "movq %%mm2, %%mm3 \n\t" - "psrlw $8, %%mm0 \n\t" - "psrlw $8, %%mm2 \n\t" - "pand %%mm7, %%mm1 \n\t" - "pand %%mm7, %%mm3 \n\t" - "packuswb %%mm2, %%mm0 \n\t" - "packuswb %%mm3, %%mm1 \n\t" - MOVNTQ" %%mm0,- 7(%4, %0) \n\t" - MOVNTQ" %%mm1,- 7(%3, %0) \n\t" - "add $8, %0 \n\t" - " js 1b \n\t" - : "+r"(count) - : "r"(src0), "r"(src1), "r"(dst0), "r"(dst1) - ); - count -= 7; - } -#endif - src0++; - src1++; - while(count<0) { - dst0[count]= (src0[4*count+0]+src1[4*count+0])>>1; - dst1[count]= (src0[4*count+2]+src1[4*count+2])>>1; - count++; - } -} - -static void RENAME(yuyvtoyuv420)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, - int width, int height, - int lumStride, int chromStride, int srcStride) -{ - int y; - const int chromWidth = AV_CEIL_RSHIFT(width, 1); - - for (y=0; y YVYU YVY... + RSHIFT_COPY m6, m2, m4, 1, 0x20 ; UYVY UYVY -> YVYU YVY... pand m6, m1; YxYx YxYx... - RSHIFT_COPY m7, m3, 1 ; UYVY UYVY -> YVYU YVY... + RSHIFT_COPY m7, m3, m5, 1, 0x20 ; UYVY UYVY -> YVYU YVY... pand m7, m1 ; YxYx YxYx... packuswb m6, m7 ; YYYY YYYY... movu [ydstq + wq], m6 ; extract y part 2 - RSHIFT_COPY m6, m4, 1 ; UYVY UYVY -> YVYU YVY... + RSHIFT_COPY m6, m4, m2, 1, 0x13 ; UYVY UYVY -> YVYU YVY... pand m6, m1; YxYx YxYx... - RSHIFT_COPY m7, m5, 1 ; UYVY UYVY -> YVYU YVY... + RSHIFT_COPY m7, m5, m3, 1, 0x13 ; UYVY UYVY -> YVYU YVY... pand m7, m1 ; YxYx YxYx... packuswb m6, m7 ; YYYY YYYY... @@ -309,4 +259,8 @@ UYVY_TO_YUV422 INIT_XMM avx UYVY_TO_YUV422 +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +UYVY_TO_YUV422 +%endif %endif diff --git a/libswscale/x86/swscale.c b/libswscale/x86/swscale.c index fff8bb439..43319fd6b 100644 --- a/libswscale/x86/swscale.c +++ b/libswscale/x86/swscale.c @@ -40,8 +40,6 @@ const DECLARE_ALIGNED(8, uint64_t, ff_dither8)[2] = { #if HAVE_INLINE_ASM -#define DITHER1XBPP - DECLARE_ASM_CONST(8, uint64_t, bF8)= 0xF8F8F8F8F8F8F8F8LL; DECLARE_ASM_CONST(8, uint64_t, bFC)= 0xFCFCFCFCFCFCFCFCLL; @@ -321,6 +319,12 @@ void ff_ ## fmt ## ToUV_ ## opt(uint8_t *dstU, uint8_t *dstV, \ INPUT_FUNCS(sse2); INPUT_FUNCS(ssse3); INPUT_FUNCS(avx); +INPUT_FUNC(rgba, avx2); +INPUT_FUNC(bgra, avx2); +INPUT_FUNC(argb, avx2); +INPUT_FUNC(abgr, avx2); +INPUT_FUNC(rgb24, avx2); +INPUT_FUNC(bgr24, avx2); #if ARCH_X86_64 #define YUV2NV_DECL(fmt, opt) \ @@ -447,6 +451,39 @@ INPUT_PLANAR_RGB_UV_ALL_DECL(avx2); INPUT_PLANAR_RGB_A_ALL_DECL(avx2); #endif +#define RANGE_CONVERT_FUNCS(opt) do { \ + if (c->dstBpc <= 14) { \ + if (c->srcRange) { \ + c->lumConvertRange = ff_lumRangeFromJpeg_ ##opt; \ + c->chrConvertRange = ff_chrRangeFromJpeg_ ##opt; \ + } else { \ + c->lumConvertRange = ff_lumRangeToJpeg_ ##opt; \ + c->chrConvertRange = ff_chrRangeToJpeg_ ##opt; \ + } \ + } \ +} while (0) + +#define RANGE_CONVERT_FUNCS_DECL(opt) \ +void ff_lumRangeFromJpeg_ ##opt(int16_t *dst, int width); \ +void ff_chrRangeFromJpeg_ ##opt(int16_t *dstU, int16_t *dstV, int width); \ +void ff_lumRangeToJpeg_ ##opt(int16_t *dst, int width); \ +void ff_chrRangeToJpeg_ ##opt(int16_t *dstU, int16_t *dstV, int width); \ + +RANGE_CONVERT_FUNCS_DECL(sse2); +RANGE_CONVERT_FUNCS_DECL(avx2); + +av_cold void ff_sws_init_range_convert_x86(SwsContext *c) +{ + if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) { + int cpu_flags = av_get_cpu_flags(); + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + RANGE_CONVERT_FUNCS(avx2); + } else if (EXTERNAL_SSE2(cpu_flags)) { + RANGE_CONVERT_FUNCS(sse2); + } + } +} + av_cold void ff_sws_init_swscale_x86(SwsContext *c) { int cpu_flags = av_get_cpu_flags(); @@ -634,6 +671,15 @@ switch(c->dstBpc){ \ } if (EXTERNAL_AVX2_FAST(cpu_flags)) { + if (ARCH_X86_64) + switch (c->srcFormat) { + case_rgb(rgb24, RGB24, avx2); + case_rgb(bgr24, BGR24, avx2); + case_rgb(bgra, BGRA, avx2); + case_rgb(rgba, RGBA, avx2); + case_rgb(abgr, ABGR, avx2); + case_rgb(argb, ARGB, avx2); + } switch (c->dstFormat) { case AV_PIX_FMT_NV12: case AV_PIX_FMT_NV24: @@ -805,4 +851,6 @@ switch(c->dstBpc){ \ } #endif + + ff_sws_init_range_convert_x86(c); } diff --git a/libswscale/x86/swscale_template.c b/libswscale/x86/swscale_template.c index 6190fcb4f..6bff2a44a 100644 --- a/libswscale/x86/swscale_template.c +++ b/libswscale/x86/swscale_template.c @@ -384,11 +384,9 @@ static void RENAME(yuv2rgb565_X_ar)(SwsContext *c, const int16_t *lumFilter, YSCALEYUV2RGBX "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%0), %%mm2\n\t" "paddusb "GREEN_DITHER"(%0), %%mm4\n\t" "paddusb "RED_DITHER"(%0), %%mm5\n\t" -#endif WRITERGB16(%4, "%5", %%FF_REGa) YSCALEYUV2PACKEDX_END } @@ -408,11 +406,9 @@ static void RENAME(yuv2rgb565_X)(SwsContext *c, const int16_t *lumFilter, YSCALEYUV2RGBX "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%0), %%mm2 \n\t" "paddusb "GREEN_DITHER"(%0), %%mm4 \n\t" "paddusb "RED_DITHER"(%0), %%mm5 \n\t" -#endif WRITERGB16(%4, "%5", %%FF_REGa) YSCALEYUV2PACKEDX_END } @@ -461,11 +457,9 @@ static void RENAME(yuv2rgb555_X_ar)(SwsContext *c, const int16_t *lumFilter, YSCALEYUV2RGBX "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%0), %%mm2\n\t" "paddusb "GREEN_DITHER"(%0), %%mm4\n\t" "paddusb "RED_DITHER"(%0), %%mm5\n\t" -#endif WRITERGB15(%4, "%5", %%FF_REGa) YSCALEYUV2PACKEDX_END } @@ -485,11 +479,9 @@ static void RENAME(yuv2rgb555_X)(SwsContext *c, const int16_t *lumFilter, YSCALEYUV2RGBX "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%0), %%mm2 \n\t" "paddusb "GREEN_DITHER"(%0), %%mm4 \n\t" "paddusb "RED_DITHER"(%0), %%mm5 \n\t" -#endif WRITERGB15(%4, "%5", %%FF_REGa) YSCALEYUV2PACKEDX_END } @@ -891,11 +883,9 @@ static void RENAME(yuv2rgb555_2)(SwsContext *c, const int16_t *buf[2], YSCALEYUV2RGB(%%FF_REGBP, %5) "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%5), %%mm2 \n\t" "paddusb "GREEN_DITHER"(%5), %%mm4 \n\t" "paddusb "RED_DITHER"(%5), %%mm5 \n\t" -#endif WRITERGB15(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP) "pop %%"FF_REG_BP" \n\t" "mov "ESP_OFFSET"(%5), %%"FF_REG_b" \n\t" @@ -920,11 +910,9 @@ static void RENAME(yuv2rgb565_2)(SwsContext *c, const int16_t *buf[2], YSCALEYUV2RGB(%%FF_REGBP, %5) "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%5), %%mm2 \n\t" "paddusb "GREEN_DITHER"(%5), %%mm4 \n\t" "paddusb "RED_DITHER"(%5), %%mm5 \n\t" -#endif WRITERGB16(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP) "pop %%"FF_REG_BP" \n\t" "mov "ESP_OFFSET"(%5), %%"FF_REG_b" \n\t" @@ -1240,11 +1228,9 @@ static void RENAME(yuv2rgb555_1)(SwsContext *c, const int16_t *buf0, YSCALEYUV2RGB1(%%FF_REGBP, %5) "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%5), %%mm2 \n\t" "paddusb "GREEN_DITHER"(%5), %%mm4 \n\t" "paddusb "RED_DITHER"(%5), %%mm5 \n\t" -#endif WRITERGB15(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP) "pop %%"FF_REG_BP" \n\t" "mov "ESP_OFFSET"(%5), %%"FF_REG_b" \n\t" @@ -1261,11 +1247,9 @@ static void RENAME(yuv2rgb555_1)(SwsContext *c, const int16_t *buf0, YSCALEYUV2RGB1b(%%FF_REGBP, %5) "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%5), %%mm2 \n\t" "paddusb "GREEN_DITHER"(%5), %%mm4 \n\t" "paddusb "RED_DITHER"(%5), %%mm5 \n\t" -#endif WRITERGB15(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP) "pop %%"FF_REG_BP" \n\t" "mov "ESP_OFFSET"(%5), %%"FF_REG_b" \n\t" @@ -1293,11 +1277,9 @@ static void RENAME(yuv2rgb565_1)(SwsContext *c, const int16_t *buf0, YSCALEYUV2RGB1(%%FF_REGBP, %5) "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%5), %%mm2 \n\t" "paddusb "GREEN_DITHER"(%5), %%mm4 \n\t" "paddusb "RED_DITHER"(%5), %%mm5 \n\t" -#endif WRITERGB16(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP) "pop %%"FF_REG_BP" \n\t" "mov "ESP_OFFSET"(%5), %%"FF_REG_b" \n\t" @@ -1314,11 +1296,9 @@ static void RENAME(yuv2rgb565_1)(SwsContext *c, const int16_t *buf0, YSCALEYUV2RGB1b(%%FF_REGBP, %5) "pxor %%mm7, %%mm7 \n\t" /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */ -#ifdef DITHER1XBPP "paddusb "BLUE_DITHER"(%5), %%mm2 \n\t" "paddusb "GREEN_DITHER"(%5), %%mm4 \n\t" "paddusb "RED_DITHER"(%5), %%mm5 \n\t" -#endif WRITERGB16(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP) "pop %%"FF_REG_BP" \n\t" "mov "ESP_OFFSET"(%5), %%"FF_REG_b" \n\t" diff --git a/libswscale/x86/yuv2rgb.c b/libswscale/x86/yuv2rgb.c index 675406224..2a4505fa9 100644 --- a/libswscale/x86/yuv2rgb.c +++ b/libswscale/x86/yuv2rgb.c @@ -1,7 +1,8 @@ /* * software YUV to RGB converter * - * Copyright (C) 2009 Konstantin Shishkov + * Copyright (C) 2001-2007 Michael Niedermayer + * Copyright (C) 2009-2010 Konstantin Shishkov * * MMX/MMXEXT template stuff (needed for fast movntq support), * 1,4,8bpp support and context / deglobalize stuff @@ -39,29 +40,201 @@ #if HAVE_X86ASM -#define DITHER1XBPP // only for MMX +#define YUV2RGB_LOOP(depth) \ + h_size = (c->dstW + 7) & ~7; \ + if (h_size * depth > FFABS(dstStride[0])) \ + h_size -= 8; \ + \ + vshift = c->srcFormat != AV_PIX_FMT_YUV422P; \ + \ + for (y = 0; y < srcSliceH; y++) { \ + uint8_t *image = dst[0] + (y + srcSliceY) * dstStride[0]; \ + const uint8_t *py = src[0] + y * srcStride[0]; \ + const uint8_t *pu = src[1] + (y >> vshift) * srcStride[1]; \ + const uint8_t *pv = src[2] + (y >> vshift) * srcStride[2]; \ + x86_reg index = -h_size / 2; \ -//MMX versions -#if HAVE_MMX -#undef RENAME -#define COMPILE_TEMPLATE_MMX -#define RENAME(a) a ## _mmx -#include "yuv2rgb_template.c" -#undef COMPILE_TEMPLATE_MMX -#endif /* HAVE_MMX */ +extern void ff_yuv_420_rgb24_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index, + const uint8_t *pv_index, const uint64_t *pointer_c_dither, + const uint8_t *py_2index); +extern void ff_yuv_420_bgr24_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index, + const uint8_t *pv_index, const uint64_t *pointer_c_dither, + const uint8_t *py_2index); -// MMXEXT versions -#undef RENAME -#define COMPILE_TEMPLATE_MMXEXT -#define RENAME(a) a ## _mmxext -#include "yuv2rgb_template.c" -#undef COMPILE_TEMPLATE_MMXEXT +extern void ff_yuv_420_rgb15_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index, + const uint8_t *pv_index, const uint64_t *pointer_c_dither, + const uint8_t *py_2index); +extern void ff_yuv_420_rgb16_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index, + const uint8_t *pv_index, const uint64_t *pointer_c_dither, + const uint8_t *py_2index); +extern void ff_yuv_420_rgb32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index, + const uint8_t *pv_index, const uint64_t *pointer_c_dither, + const uint8_t *py_2index); +extern void ff_yuv_420_bgr32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index, + const uint8_t *pv_index, const uint64_t *pointer_c_dither, + const uint8_t *py_2index); +extern void ff_yuva_420_rgb32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index, + const uint8_t *pv_index, const uint64_t *pointer_c_dither, + const uint8_t *py_2index, const uint8_t *pa_2index); +extern void ff_yuva_420_bgr32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index, + const uint8_t *pv_index, const uint64_t *pointer_c_dither, + const uint8_t *py_2index, const uint8_t *pa_2index); +#if ARCH_X86_64 +extern void ff_yuv_420_gbrp24_ssse3(x86_reg index, uint8_t *image, uint8_t *dst_b, uint8_t *dst_r, + const uint8_t *pu_index, const uint8_t *pv_index, + const uint64_t *pointer_c_dither, + const uint8_t *py_2index); +#endif -//SSSE3 versions -#undef RENAME -#define COMPILE_TEMPLATE_SSSE3 -#define RENAME(a) a ## _ssse3 -#include "yuv2rgb_template.c" +static inline int yuv420_rgb15_ssse3(SwsContext *c, const uint8_t *src[], + int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int y, h_size, vshift; + + YUV2RGB_LOOP(2) + + c->blueDither = ff_dither8[y & 1]; + c->greenDither = ff_dither8[y & 1]; + c->redDither = ff_dither8[(y + 1) & 1]; + + ff_yuv_420_rgb15_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); + } + return srcSliceH; +} + +static inline int yuv420_rgb16_ssse3(SwsContext *c, const uint8_t *src[], + int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int y, h_size, vshift; + + YUV2RGB_LOOP(2) + + c->blueDither = ff_dither8[y & 1]; + c->greenDither = ff_dither4[y & 1]; + c->redDither = ff_dither8[(y + 1) & 1]; + + ff_yuv_420_rgb16_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); + } + return srcSliceH; +} + +static inline int yuv420_rgb32_ssse3(SwsContext *c, const uint8_t *src[], + int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int y, h_size, vshift; + + YUV2RGB_LOOP(4) + + ff_yuv_420_rgb32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); + } + return srcSliceH; +} + +static inline int yuv420_bgr32_ssse3(SwsContext *c, const uint8_t *src[], + int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int y, h_size, vshift; + + YUV2RGB_LOOP(4) + + ff_yuv_420_bgr32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); + } + return srcSliceH; +} + +static inline int yuva420_rgb32_ssse3(SwsContext *c, const uint8_t *src[], + int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int y, h_size, vshift; + YUV2RGB_LOOP(4) + + const uint8_t *pa = src[3] + y * srcStride[3]; + ff_yuva_420_rgb32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index, pa - 2 * index); + } + return srcSliceH; +} + +static inline int yuva420_bgr32_ssse3(SwsContext *c, const uint8_t *src[], + int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int y, h_size, vshift; + + YUV2RGB_LOOP(4) + + const uint8_t *pa = src[3] + y * srcStride[3]; + ff_yuva_420_bgr32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index, pa - 2 * index); + } + return srcSliceH; +} + +static inline int yuv420_rgb24_ssse3(SwsContext *c, const uint8_t *src[], + int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int y, h_size, vshift; + + YUV2RGB_LOOP(3) + + ff_yuv_420_rgb24_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); + } + return srcSliceH; +} + +static inline int yuv420_bgr24_ssse3(SwsContext *c, const uint8_t *src[], + int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int y, h_size, vshift; + + YUV2RGB_LOOP(3) + + ff_yuv_420_bgr24_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); + } + return srcSliceH; +} + +#if ARCH_X86_64 +static inline int yuv420_gbrp_ssse3(SwsContext *c, const uint8_t *src[], + int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int y, h_size, vshift; + + h_size = (c->dstW + 7) & ~7; + if (h_size * 3 > FFABS(dstStride[0])) + h_size -= 8; + + vshift = c->srcFormat != AV_PIX_FMT_YUV422P; + + for (y = 0; y < srcSliceH; y++) { + uint8_t *dst_g = dst[0] + (y + srcSliceY) * dstStride[0]; + uint8_t *dst_b = dst[1] + (y + srcSliceY) * dstStride[1]; + uint8_t *dst_r = dst[2] + (y + srcSliceY) * dstStride[2]; + const uint8_t *py = src[0] + y * srcStride[0]; + const uint8_t *pu = src[1] + (y >> vshift) * srcStride[1]; + const uint8_t *pv = src[2] + (y >> vshift) * srcStride[2]; + x86_reg index = -h_size / 2; + + ff_yuv_420_gbrp24_ssse3(index, dst_g, dst_b, dst_r, pu - index, pv - index, &(c->redDither), py - 2 * index); + } + return srcSliceH; +} +#endif #endif /* HAVE_X86ASM */ @@ -96,40 +269,10 @@ av_cold SwsFunc ff_yuv2rgb_init_x86(SwsContext *c) return yuv420_rgb16_ssse3; case AV_PIX_FMT_RGB555: return yuv420_rgb15_ssse3; - } - } - - if (EXTERNAL_MMXEXT(cpu_flags)) { - switch (c->dstFormat) { - case AV_PIX_FMT_RGB24: - return yuv420_rgb24_mmxext; - case AV_PIX_FMT_BGR24: - return yuv420_bgr24_mmxext; - } - } - - if (EXTERNAL_MMX(cpu_flags)) { - switch (c->dstFormat) { - case AV_PIX_FMT_RGB32: - if (c->srcFormat == AV_PIX_FMT_YUVA420P) { -#if CONFIG_SWSCALE_ALPHA - return yuva420_rgb32_mmx; +#if ARCH_X86_64 + case AV_PIX_FMT_GBRP: + return yuv420_gbrp_ssse3; #endif - break; - } else - return yuv420_rgb32_mmx; - case AV_PIX_FMT_BGR32: - if (c->srcFormat == AV_PIX_FMT_YUVA420P) { -#if CONFIG_SWSCALE_ALPHA - return yuva420_bgr32_mmx; -#endif - break; - } else - return yuv420_bgr32_mmx; - case AV_PIX_FMT_RGB565: - return yuv420_rgb16_mmx; - case AV_PIX_FMT_RGB555: - return yuv420_rgb15_mmx; } } diff --git a/libswscale/x86/yuv2rgb_template.c b/libswscale/x86/yuv2rgb_template.c deleted file mode 100644 index 596943bb7..000000000 --- a/libswscale/x86/yuv2rgb_template.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * software YUV to RGB converter - * - * Copyright (C) 2001-2007 Michael Niedermayer - * (c) 2010 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 - -#include "libavutil/x86/asm.h" -#include "libswscale/swscale_internal.h" - -#define YUV2RGB_LOOP(depth) \ - h_size = (c->dstW + 7) & ~7; \ - if (h_size * depth > FFABS(dstStride[0])) \ - h_size -= 8; \ - \ - vshift = c->srcFormat != AV_PIX_FMT_YUV422P; \ - \ - for (y = 0; y < srcSliceH; y++) { \ - uint8_t *image = dst[0] + (y + srcSliceY) * dstStride[0]; \ - const uint8_t *py = src[0] + y * srcStride[0]; \ - const uint8_t *pu = src[1] + (y >> vshift) * srcStride[1]; \ - const uint8_t *pv = src[2] + (y >> vshift) * srcStride[2]; \ - x86_reg index = -h_size / 2; \ - -extern void RENAME(ff_yuv_420_rgb24)(x86_reg index, uint8_t *image, const uint8_t *pu_index, - const uint8_t *pv_index, const uint64_t *pointer_c_dither, - const uint8_t *py_2index); -extern void RENAME(ff_yuv_420_bgr24)(x86_reg index, uint8_t *image, const uint8_t *pu_index, - const uint8_t *pv_index, const uint64_t *pointer_c_dither, - const uint8_t *py_2index); - -#ifndef COMPILE_TEMPLATE_MMXEXT -extern void RENAME(ff_yuv_420_rgb15)(x86_reg index, uint8_t *image, const uint8_t *pu_index, - const uint8_t *pv_index, const uint64_t *pointer_c_dither, - const uint8_t *py_2index); -extern void RENAME(ff_yuv_420_rgb16)(x86_reg index, uint8_t *image, const uint8_t *pu_index, - const uint8_t *pv_index, const uint64_t *pointer_c_dither, - const uint8_t *py_2index); -extern void RENAME(ff_yuv_420_rgb32)(x86_reg index, uint8_t *image, const uint8_t *pu_index, - const uint8_t *pv_index, const uint64_t *pointer_c_dither, - const uint8_t *py_2index); -extern void RENAME(ff_yuv_420_bgr32)(x86_reg index, uint8_t *image, const uint8_t *pu_index, - const uint8_t *pv_index, const uint64_t *pointer_c_dither, - const uint8_t *py_2index); -extern void RENAME(ff_yuva_420_rgb32)(x86_reg index, uint8_t *image, const uint8_t *pu_index, - const uint8_t *pv_index, const uint64_t *pointer_c_dither, - const uint8_t *py_2index, const uint8_t *pa_2index); -extern void RENAME(ff_yuva_420_bgr32)(x86_reg index, uint8_t *image, const uint8_t *pu_index, - const uint8_t *pv_index, const uint64_t *pointer_c_dither, - const uint8_t *py_2index, const uint8_t *pa_2index); - -static inline int RENAME(yuv420_rgb15)(SwsContext *c, const uint8_t *src[], - int srcStride[], - int srcSliceY, int srcSliceH, - uint8_t *dst[], int dstStride[]) -{ - int y, h_size, vshift; - - YUV2RGB_LOOP(2) - -#ifdef DITHER1XBPP - c->blueDither = ff_dither8[y & 1]; - c->greenDither = ff_dither8[y & 1]; - c->redDither = ff_dither8[(y + 1) & 1]; -#endif - - RENAME(ff_yuv_420_rgb15)(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); - } - return srcSliceH; -} - -static inline int RENAME(yuv420_rgb16)(SwsContext *c, const uint8_t *src[], - int srcStride[], - int srcSliceY, int srcSliceH, - uint8_t *dst[], int dstStride[]) -{ - int y, h_size, vshift; - - YUV2RGB_LOOP(2) - -#ifdef DITHER1XBPP - c->blueDither = ff_dither8[y & 1]; - c->greenDither = ff_dither4[y & 1]; - c->redDither = ff_dither8[(y + 1) & 1]; -#endif - - RENAME(ff_yuv_420_rgb16)(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); - } - return srcSliceH; -} - -static inline int RENAME(yuv420_rgb32)(SwsContext *c, const uint8_t *src[], - int srcStride[], - int srcSliceY, int srcSliceH, - uint8_t *dst[], int dstStride[]) -{ - int y, h_size, vshift; - - YUV2RGB_LOOP(4) - - RENAME(ff_yuv_420_rgb32)(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); - } - return srcSliceH; -} - -static inline int RENAME(yuv420_bgr32)(SwsContext *c, const uint8_t *src[], - int srcStride[], - int srcSliceY, int srcSliceH, - uint8_t *dst[], int dstStride[]) -{ - int y, h_size, vshift; - - YUV2RGB_LOOP(4) - - RENAME(ff_yuv_420_bgr32)(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); - } - return srcSliceH; -} - -static inline int RENAME(yuva420_rgb32)(SwsContext *c, const uint8_t *src[], - int srcStride[], - int srcSliceY, int srcSliceH, - uint8_t *dst[], int dstStride[]) -{ - int y, h_size, vshift; - YUV2RGB_LOOP(4) - - const uint8_t *pa = src[3] + y * srcStride[3]; - RENAME(ff_yuva_420_rgb32)(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index, pa - 2 * index); - } - return srcSliceH; -} - -static inline int RENAME(yuva420_bgr32)(SwsContext *c, const uint8_t *src[], - int srcStride[], - int srcSliceY, int srcSliceH, - uint8_t *dst[], int dstStride[]) -{ - int y, h_size, vshift; - - YUV2RGB_LOOP(4) - - const uint8_t *pa = src[3] + y * srcStride[3]; - RENAME(ff_yuva_420_bgr32)(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index, pa - 2 * index); - } - return srcSliceH; -} -#endif - -#if !defined(COMPILE_TEMPLATE_MMX) -static inline int RENAME(yuv420_rgb24)(SwsContext *c, const uint8_t *src[], - int srcStride[], - int srcSliceY, int srcSliceH, - uint8_t *dst[], int dstStride[]) -{ - int y, h_size, vshift; - - YUV2RGB_LOOP(3) - - RENAME(ff_yuv_420_rgb24)(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); - } - return srcSliceH; -} - -static inline int RENAME(yuv420_bgr24)(SwsContext *c, const uint8_t *src[], - int srcStride[], - int srcSliceY, int srcSliceH, - uint8_t *dst[], int dstStride[]) -{ - int y, h_size, vshift; - - YUV2RGB_LOOP(3) - - RENAME(ff_yuv_420_bgr24)(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index); - } - return srcSliceH; -} -#endif diff --git a/libswscale/x86/yuv_2_rgb.asm b/libswscale/x86/yuv_2_rgb.asm index e3470fd9a..eeb1d2594 100644 --- a/libswscale/x86/yuv_2_rgb.asm +++ b/libswscale/x86/yuv_2_rgb.asm @@ -32,18 +32,13 @@ mask_dw25 : db 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0 rgb24_shuf1: db 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11 rgb24_shuf2: db 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5 rgb24_shuf3: db 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15 +gbrp_shuf : db 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 pw_00ff: times 8 dw 255 pb_f8: times 16 db 248 pb_e0: times 16 db 224 pb_03: times 16 db 3 pb_07: times 16 db 7 -mask_1101: dw -1, -1, 0, -1 -mask_0010: dw 0, 0, -1, 0 -mask_0110: dw 0, -1, -1, 0 -mask_1001: dw -1, 0, 0, -1 -mask_0100: dw 0, -1, 0, 0 - SECTION .text ;----------------------------------------------------------------------------- @@ -55,14 +50,6 @@ SECTION .text ; ;----------------------------------------------------------------------------- -%macro MOV_H2L 1 -%if mmsize == 8 - psrlq %1, 32 -%else ; mmsize == 16 - psrldq %1, 8 -%endif -%endmacro - %macro yuv2rgb_fn 3 %if %3 == 32 @@ -74,8 +61,13 @@ SECTION .text %define GPR_num 6 %endif %else + %ifidn %2, gbrp + %define parameters index, image, dst_b, dst_r, pu_index, pv_index, pointer_c_dither, py_2index + %define GPR_num 8 + %else %define parameters index, image, pu_index, pv_index, pointer_c_dither, py_2index %define GPR_num 6 + %endif %endif %define m_green m2 @@ -91,18 +83,6 @@ SECTION .text %define m_blue m1 %endif -%if mmsize == 8 -%define time_num 1 -%define reg_num 8 -%define y_offset [pointer_c_ditherq + 8 * 8] -%define u_offset [pointer_c_ditherq + 9 * 8] -%define v_offset [pointer_c_ditherq + 10 * 8] -%define ug_coff [pointer_c_ditherq + 7 * 8] -%define vg_coff [pointer_c_ditherq + 6 * 8] -%define y_coff [pointer_c_ditherq + 3 * 8] -%define ub_coff [pointer_c_ditherq + 5 * 8] -%define vr_coff [pointer_c_ditherq + 4 * 8] -%elif mmsize == 16 %define time_num 2 %if ARCH_X86_32 %define reg_num 8 @@ -125,13 +105,11 @@ SECTION .text %define ub_coff m14 %define vr_coff m15 %endif ; ARCH_X86_32/64 -%endif ; coeff define mmsize == 8/16 cglobal %1_420_%2%3, GPR_num, GPR_num, reg_num, parameters %if ARCH_X86_64 movsxd indexq, indexd -%if mmsize == 16 VBROADCASTSD y_offset, [pointer_c_ditherq + 8 * 8] VBROADCASTSD u_offset, [pointer_c_ditherq + 9 * 8] VBROADCASTSD v_offset, [pointer_c_ditherq + 10 * 8] @@ -141,7 +119,6 @@ cglobal %1_420_%2%3, GPR_num, GPR_num, reg_num, parameters VBROADCASTSD ub_coff, [pointer_c_ditherq + 5 * 8] VBROADCASTSD vr_coff, [pointer_c_ditherq + 4 * 8] %endif -%endif .loop0: movu m_y, [py_2indexq + 2 * indexq] movh m_u, [pu_indexq + indexq] @@ -157,7 +134,7 @@ cglobal %1_420_%2%3, GPR_num, GPR_num, reg_num, parameters psllw m1, 3 psllw m6, 3 psllw m7, 3 -%if (ARCH_X86_32 && mmsize == 16) +%if ARCH_X86_32 VBROADCASTSD m2, mu_offset VBROADCASTSD m3, mv_offset VBROADCASTSD m4, my_offset @@ -176,7 +153,7 @@ cglobal %1_420_%2%3, GPR_num, GPR_num, reg_num, parameters pmulhw m0, m5 VBROADCASTSD m4, mvr_coff pmulhw m1, m4 -%else ; ARCH_X86_64 || mmsize == 8 +%else ; ARCH_X86_64 psubsw m0, u_offset ; U = U - 128 psubsw m1, v_offset ; V = V - 128 psubw m6, y_offset @@ -195,61 +172,34 @@ cglobal %1_420_%2%3, GPR_num, GPR_num, reg_num, parameters mova m5, m7 paddsw m3, m0 ; B1 B3 B5 B7 ... paddsw m5, m1 ; R1 R3 R5 R7 ... - paddsw m7, m2 ; G1 G3 G4 G7 ... + paddsw m7, m2 ; G1 G3 G5 G7 ... paddsw m0, m6 ; B0 B2 B4 B6 ... paddsw m1, m6 ; R0 R2 R4 R6 ... paddsw m2, m6 ; G0 G2 G4 G6 ... %if %3 == 24 ; PACK RGB24 -%define depth 3 - packuswb m0, m3 ; R0 R2 R4 R6 ... R1 R3 R5 R7 ... - packuswb m1, m5 ; B0 B2 B4 B6 ... B1 B3 B5 B7 ... + packuswb m0, m3 ; B0 B2 B4 B6 ... B1 B3 B5 B7 ... + packuswb m1, m5 ; R0 R2 R4 R6 ... R1 R3 R5 R7 ... packuswb m2, m7 ; G0 G2 G4 G6 ... G1 G3 G5 G7 ... +%ifidn %2, gbrp ; PLANAR GBRP +%define depth 1 + mova m4, [gbrp_shuf] + pshufb m0, m4 + pshufb m1, m4 + pshufb m2, m4 + movu [imageq], m2 + movu [dst_bq], m0 + movu [dst_rq], m1 + add dst_bq, 8 * depth * time_num + add dst_rq, 8 * depth * time_num +%else +%define depth 3 mova m3, m_red mova m6, m_blue - MOV_H2L m_red + psrldq m_red, 8 punpcklbw m3, m2 ; R0 G0 R2 G2 R4 G4 R6 G6 R8 G8 ... punpcklbw m6, m_red ; B0 R1 B2 R3 B4 R5 B6 R7 B8 R9 ... - mova m5, m3 punpckhbw m2, m_blue ; G1 B1 G3 B3 G5 B5 G7 B7 G9 B9 ... -%if mmsize == 8 - punpcklwd m3 ,m6 ; R0 G0 B0 R1 R2 G2 B2 R3 - punpckhwd m5, m6 ; R4 G4 B4 R5 R6 G6 B6 R7 -%if cpuflag(mmxext) - pshufw m1, m2, 0xc6 - pshufw m6, m3, 0x84 - pshufw m7, m5, 0x38 - pand m6, [mask_1101] ; R0 G0 B0 R1 -- -- R2 G2 - movq m0, m1 - pand m7, [mask_0110] ; -- -- R6 G6 B6 R7 -- -- - movq m2, m1 - pand m1, [mask_0100] ; -- -- G3 B3 -- -- -- -- - psrlq m3, 48 ; B2 R3 -- -- -- -- -- -- - pand m0, [mask_0010] ; -- -- -- -- G1 B1 -- -- - psllq m5, 32 ; -- -- -- -- R4 G4 B4 R5 - pand m2, [mask_1001] ; G5 B5 -- -- -- -- G7 B7 - por m1, m3 - por m0, m6 - por m1, m5 - por m2, m7 - movntq [imageq], m0 - movntq [imageq + 8], m1 - movntq [imageq + 16], m2 -%else ; cpuflag(mmx) - movd [imageq], m3 ; R0 G0 R2 G2 - movd [imageq + 4], m2 ; G1 B1 - psrlq m3, 32 - psrlq m2, 16 - movd [imageq + 6], m3 ; R2 G2 B2 R3 - movd [imageq + 10], m2 ; G3 B3 - psrlq m2, 16 - movd [imageq + 12], m5 ; R4 G4 B4 R5 - movd [imageq + 16], m2 ; G5 B5 - psrlq m5, 32 - movd [imageq + 20], m2 ; -- -- G7 B7 - movd [imageq + 18], m5 ; R6 G6 B6 R7 -%endif ; mmsize = 8 -%else ; mmsize == 16 pshufb m3, [rgb24_shuf1] ; r0 g0 r6 g6 r12 g12 r2 g2 r8 g8 r14 g14 r4 g4 r10 g10 pshufb m6, [rgb24_shuf2] ; b10 r11 b0 r1 b6 r7 b12 r13 b2 r3 b8 r9 b14 r15 b4 r5 pshufb m2, [rgb24_shuf3] ; g5 b5 g11 b11 g1 b1 g7 b7 g13 b13 g3 b3 g9 b9 g15 b15 @@ -274,7 +224,7 @@ cglobal %1_420_%2%3, GPR_num, GPR_num, reg_num, parameters movu [imageq], m0 movu [imageq + 16], m1 movu [imageq + 32], m2 -%endif ; mmsize = 16 +%endif ; PLANAR GBRP %else ; PACK RGB15/16/32 packuswb m0, m1 packuswb m3, m5 @@ -309,18 +259,12 @@ cglobal %1_420_%2%3, GPR_num, GPR_num, reg_num, parameters movu [imageq + 24 * time_num], m_alpha %else ; PACK RGB15/16 %define depth 2 -%if cpuflag(ssse3) %define red_dither m3 %define green_dither m4 %define blue_dither m5 VBROADCASTSD red_dither, [pointer_c_ditherq + 0 * 8] VBROADCASTSD green_dither, [pointer_c_ditherq + 1 * 8] VBROADCASTSD blue_dither, [pointer_c_ditherq + 2 * 8] -%else ; cpuflag(mmx/mmxext) -%define blue_dither [pointer_c_ditherq + 2 * 8] -%define green_dither [pointer_c_ditherq + 1 * 8] -%define red_dither [pointer_c_ditherq + 0 * 8] -%endif %if %3 == 15 %define gmask pb_03 %define isRGB15 1 @@ -358,18 +302,6 @@ RET %endmacro -INIT_MMX mmx -yuv2rgb_fn yuv, rgb, 32 -yuv2rgb_fn yuv, bgr, 32 -yuv2rgb_fn yuva, rgb, 32 -yuv2rgb_fn yuva, bgr, 32 -yuv2rgb_fn yuv, rgb, 15 -yuv2rgb_fn yuv, rgb, 16 - -INIT_MMX mmxext -yuv2rgb_fn yuv, rgb, 24 -yuv2rgb_fn yuv, bgr, 24 - INIT_XMM ssse3 yuv2rgb_fn yuv, rgb, 24 yuv2rgb_fn yuv, bgr, 24 @@ -379,3 +311,6 @@ yuv2rgb_fn yuva, rgb, 32 yuv2rgb_fn yuva, bgr, 32 yuv2rgb_fn yuv, rgb, 15 yuv2rgb_fn yuv, rgb, 16 +%if ARCH_X86_64 +yuv2rgb_fn yuv, gbrp, 24 +%endif diff --git a/libswscale/yuv2rgb.c b/libswscale/yuv2rgb.c index d57a87ce0..52fe2093e 100644 --- a/libswscale/yuv2rgb.c +++ b/libswscale/yuv2rgb.c @@ -23,13 +23,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include +#include +#include #include "libavutil/bswap.h" +#include "libavutil/mem.h" #include "config.h" -#include "rgb2rgb.h" #include "swscale.h" #include "swscale_internal.h" #include "libavutil/pixdesc.h" @@ -66,89 +65,107 @@ const int *sws_getCoefficients(int colorspace) return ff_yuv2rgb_coeffs[colorspace]; } -#define LOADCHROMA(i) \ - U = pu[i]; \ - V = pv[i]; \ +#define LOADCHROMA(l, i) \ + U = pu_##l[i]; \ + V = pv_##l[i]; \ r = (void *)c->table_rV[V+YUVRGB_TABLE_HEADROOM]; \ g = (void *)(c->table_gU[U+YUVRGB_TABLE_HEADROOM] + c->table_gV[V+YUVRGB_TABLE_HEADROOM]); \ b = (void *)c->table_bU[U+YUVRGB_TABLE_HEADROOM]; -#define PUTRGB(dst, src, i) \ - Y = src[2 * i]; \ - dst[2 * i] = r[Y] + g[Y] + b[Y]; \ - Y = src[2 * i + 1]; \ - dst[2 * i + 1] = r[Y] + g[Y] + b[Y]; +#define PUTRGB(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y] + g[Y] + b[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y] + g[Y] + b[Y]; -#define PUTRGB24(dst, src, i) \ - Y = src[2 * i]; \ - dst[6 * i + 0] = r[Y]; \ - dst[6 * i + 1] = g[Y]; \ - dst[6 * i + 2] = b[Y]; \ - Y = src[2 * i + 1]; \ - dst[6 * i + 3] = r[Y]; \ - dst[6 * i + 4] = g[Y]; \ - dst[6 * i + 5] = b[Y]; +#define PUTRGB24(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[6 * i + 0] = r[Y]; \ + dst_##l[6 * i + 1] = g[Y]; \ + dst_##l[6 * i + 2] = b[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[6 * i + 3] = r[Y]; \ + dst_##l[6 * i + 4] = g[Y]; \ + dst_##l[6 * i + 5] = b[Y]; -#define PUTBGR24(dst, src, i) \ - Y = src[2 * i]; \ - dst[6 * i + 0] = b[Y]; \ - dst[6 * i + 1] = g[Y]; \ - dst[6 * i + 2] = r[Y]; \ - Y = src[2 * i + 1]; \ - dst[6 * i + 3] = b[Y]; \ - dst[6 * i + 4] = g[Y]; \ - dst[6 * i + 5] = r[Y]; +#define PUTBGR24(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[6 * i + 0] = b[Y]; \ + dst_##l[6 * i + 1] = g[Y]; \ + dst_##l[6 * i + 2] = r[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[6 * i + 3] = b[Y]; \ + dst_##l[6 * i + 4] = g[Y]; \ + dst_##l[6 * i + 5] = r[Y]; -#define PUTRGBA(dst, ysrc, asrc, i, s) \ - Y = ysrc[2 * i]; \ - dst[2 * i] = r[Y] + g[Y] + b[Y] + (asrc[2 * i] << s); \ - Y = ysrc[2 * i + 1]; \ - dst[2 * i + 1] = r[Y] + g[Y] + b[Y] + (asrc[2 * i + 1] << s); +#define PUTRGBA(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y] + g[Y] + b[Y] + ((uint32_t)(pa_##l[2 * i]) << abase); \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y] + g[Y] + b[Y] + ((uint32_t)(pa_##l[2 * i + 1]) << abase); -#define PUTRGB48(dst, src, i) \ - Y = src[ 2 * i]; \ - dst[12 * i + 0] = dst[12 * i + 1] = r[Y]; \ - dst[12 * i + 2] = dst[12 * i + 3] = g[Y]; \ - dst[12 * i + 4] = dst[12 * i + 5] = b[Y]; \ - Y = src[ 2 * i + 1]; \ - dst[12 * i + 6] = dst[12 * i + 7] = r[Y]; \ - dst[12 * i + 8] = dst[12 * i + 9] = g[Y]; \ - dst[12 * i + 10] = dst[12 * i + 11] = b[Y]; +#define PUTRGB48(l, i, abase) \ + Y = py_##l[ 2 * i]; \ + dst_##l[12 * i + 0] = dst_##l[12 * i + 1] = r[Y]; \ + dst_##l[12 * i + 2] = dst_##l[12 * i + 3] = g[Y]; \ + dst_##l[12 * i + 4] = dst_##l[12 * i + 5] = b[Y]; \ + Y = py_##l[ 2 * i + 1]; \ + dst_##l[12 * i + 6] = dst_##l[12 * i + 7] = r[Y]; \ + dst_##l[12 * i + 8] = dst_##l[12 * i + 9] = g[Y]; \ + dst_##l[12 * i + 10] = dst_##l[12 * i + 11] = b[Y]; -#define PUTBGR48(dst, src, i) \ - Y = src[2 * i]; \ - dst[12 * i + 0] = dst[12 * i + 1] = b[Y]; \ - dst[12 * i + 2] = dst[12 * i + 3] = g[Y]; \ - dst[12 * i + 4] = dst[12 * i + 5] = r[Y]; \ - Y = src[2 * i + 1]; \ - dst[12 * i + 6] = dst[12 * i + 7] = b[Y]; \ - dst[12 * i + 8] = dst[12 * i + 9] = g[Y]; \ - dst[12 * i + 10] = dst[12 * i + 11] = r[Y]; +#define PUTBGR48(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[12 * i + 0] = dst_##l[12 * i + 1] = b[Y]; \ + dst_##l[12 * i + 2] = dst_##l[12 * i + 3] = g[Y]; \ + dst_##l[12 * i + 4] = dst_##l[12 * i + 5] = r[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[12 * i + 6] = dst_##l[12 * i + 7] = b[Y]; \ + dst_##l[12 * i + 8] = dst_##l[12 * i + 9] = g[Y]; \ + dst_##l[12 * i + 10] = dst_##l[12 * i + 11] = r[Y]; -#define YUV2RGBFUNC(func_name, dst_type, alpha) \ +#define PUTGBRP(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l [2 * i + 0] = g[Y]; \ + dst1_##l[2 * i + 0] = b[Y]; \ + dst2_##l[2 * i + 0] = r[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l [2 * i + 1] = g[Y]; \ + dst1_##l[2 * i + 1] = b[Y]; \ + dst2_##l[2 * i + 1] = r[Y]; + +#define YUV2RGBFUNC(func_name, dst_type, alpha, yuv422, nb_dst_planes) \ static int func_name(SwsContext *c, const uint8_t *src[], \ int srcStride[], int srcSliceY, int srcSliceH, \ uint8_t *dst[], int dstStride[]) \ { \ int y; \ \ - if (!alpha && c->srcFormat == AV_PIX_FMT_YUV422P) { \ - srcStride[1] *= 2; \ - srcStride[2] *= 2; \ - } \ for (y = 0; y < srcSliceH; y += 2) { \ int yd = y + srcSliceY; \ dst_type *dst_1 = \ (dst_type *)(dst[0] + (yd) * dstStride[0]); \ dst_type *dst_2 = \ (dst_type *)(dst[0] + (yd + 1) * dstStride[0]); \ + dst_type av_unused *dst1_1, *dst1_2, *dst2_1, *dst2_2; \ dst_type av_unused *r, *g, *b; \ const uint8_t *py_1 = src[0] + y * srcStride[0]; \ const uint8_t *py_2 = py_1 + srcStride[0]; \ - const uint8_t av_unused *pu = src[1] + (y >> 1) * srcStride[1]; \ - const uint8_t av_unused *pv = src[2] + (y >> 1) * srcStride[2]; \ + const uint8_t av_unused *pu_1 = src[1] + (y >> !yuv422) * srcStride[1]; \ + const uint8_t av_unused *pv_1 = src[2] + (y >> !yuv422) * srcStride[2]; \ + const uint8_t av_unused *pu_2, *pv_2; \ const uint8_t av_unused *pa_1, *pa_2; \ unsigned int h_size = c->dstW >> 3; \ + if (nb_dst_planes > 1) { \ + dst1_1 = (dst_type *)(dst[1] + (yd) * dstStride[1]); \ + dst1_2 = (dst_type *)(dst[1] + (yd + 1) * dstStride[1]); \ + dst2_1 = (dst_type *)(dst[2] + (yd) * dstStride[2]); \ + dst2_2 = (dst_type *)(dst[2] + (yd + 1) * dstStride[2]); \ + } \ + if (yuv422) { \ + pu_2 = pu_1 + srcStride[1]; \ + pv_2 = pv_1 + srcStride[2]; \ + } \ if (alpha) { \ pa_1 = src[3] + y * srcStride[3]; \ pa_2 = pa_1 + srcStride[3]; \ @@ -156,13 +173,27 @@ const int *sws_getCoefficients(int colorspace) while (h_size--) { \ int av_unused U, V, Y; \ -#define ENDYUV2RGBLINE(dst_delta, ss) \ - pu += 4 >> ss; \ - pv += 4 >> ss; \ +#define ENDYUV2RGBLINE(dst_delta, ss, alpha, yuv422, nb_dst_planes) \ + pu_1 += 4 >> ss; \ + pv_1 += 4 >> ss; \ + if (yuv422) { \ + pu_2 += 4 >> ss; \ + pv_2 += 4 >> ss; \ + } \ py_1 += 8 >> ss; \ py_2 += 8 >> ss; \ + if (alpha) { \ + pa_1 += 8 >> ss; \ + pa_2 += 8 >> ss; \ + } \ dst_1 += dst_delta >> ss; \ dst_2 += dst_delta >> ss; \ + if (nb_dst_planes > 1) { \ + dst1_1 += dst_delta >> ss; \ + dst1_2 += dst_delta >> ss; \ + dst2_1 += dst_delta >> ss; \ + dst2_2 += dst_delta >> ss; \ + } \ } \ if (c->dstW & (4 >> ss)) { \ int av_unused Y, U, V; \ @@ -173,482 +204,257 @@ const int *sws_getCoefficients(int colorspace) return srcSliceH; \ } -#define CLOSEYUV2RGBFUNC(dst_delta) \ - ENDYUV2RGBLINE(dst_delta, 0) \ +#define YUV420FUNC(func_name, dst_type, alpha, abase, PUTFUNC, dst_delta, nb_dst_planes) \ + YUV2RGBFUNC(func_name, dst_type, alpha, 0, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + PUTFUNC(2, 0, abase); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(2, 1, abase); \ + PUTFUNC(1, 1, abase); \ + \ + LOADCHROMA(1, 2); \ + PUTFUNC(1, 2, abase); \ + PUTFUNC(2, 2, abase); \ + \ + LOADCHROMA(1, 3); \ + PUTFUNC(2, 3, abase); \ + PUTFUNC(1, 3, abase); \ + ENDYUV2RGBLINE(dst_delta, 0, alpha, 0, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + PUTFUNC(2, 0, abase); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(2, 1, abase); \ + PUTFUNC(1, 1, abase); \ + ENDYUV2RGBLINE(dst_delta, 1, alpha, 0, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + PUTFUNC(2, 0, abase); \ ENDYUV2RGBFUNC() -YUV2RGBFUNC(yuv2rgb_c_48, uint8_t, 0) - LOADCHROMA(0); - PUTRGB48(dst_1, py_1, 0); - PUTRGB48(dst_2, py_2, 0); +#define YUV422FUNC(func_name, dst_type, alpha, abase, PUTFUNC, dst_delta, nb_dst_planes) \ + YUV2RGBFUNC(func_name, dst_type, alpha, 1, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, abase); \ + \ + LOADCHROMA(2, 1); \ + PUTFUNC(2, 1, abase); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(1, 1, abase); \ + \ + LOADCHROMA(1, 2); \ + PUTFUNC(1, 2, abase); \ + \ + LOADCHROMA(2, 2); \ + PUTFUNC(2, 2, abase); \ + \ + LOADCHROMA(2, 3); \ + PUTFUNC(2, 3, abase); \ + \ + LOADCHROMA(1, 3); \ + PUTFUNC(1, 3, abase); \ + ENDYUV2RGBLINE(dst_delta, 0, alpha, 1, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, abase); \ + \ + LOADCHROMA(2, 1); \ + PUTFUNC(2, 1, abase); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(1, 1, abase); \ + ENDYUV2RGBLINE(dst_delta, 1, alpha, 1, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, abase); \ + ENDYUV2RGBFUNC() - LOADCHROMA(1); - PUTRGB48(dst_2, py_2, 1); - PUTRGB48(dst_1, py_1, 1); +#define YUV420FUNC_DITHER(func_name, dst_type, LOADDITHER, PUTFUNC, dst_delta) \ + YUV2RGBFUNC(func_name, dst_type, 0, 0, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(2, 1, 2 + 8); \ + PUTFUNC(1, 1, 2); \ + \ + LOADCHROMA(1, 2); \ + PUTFUNC(1, 2, 4); \ + PUTFUNC(2, 2, 4 + 8); \ + \ + LOADCHROMA(1, 3); \ + PUTFUNC(2, 3, 6 + 8); \ + PUTFUNC(1, 3, 6); \ + ENDYUV2RGBLINE(dst_delta, 0, 0, 0, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(2, 1, 2 + 8); \ + PUTFUNC(1, 1, 2); \ + ENDYUV2RGBLINE(dst_delta, 1, 0, 0, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + ENDYUV2RGBFUNC() - LOADCHROMA(2); - PUTRGB48(dst_1, py_1, 2); - PUTRGB48(dst_2, py_2, 2); +#define YUV422FUNC_DITHER(func_name, dst_type, LOADDITHER, PUTFUNC, dst_delta) \ + YUV2RGBFUNC(func_name, dst_type, 0, 1, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + \ + LOADCHROMA(2, 1); \ + PUTFUNC(2, 1, 2 + 8); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(1, 1, 2); \ + \ + LOADCHROMA(1, 2); \ + PUTFUNC(1, 2, 4); \ + \ + LOADCHROMA(2, 2); \ + PUTFUNC(2, 2, 4 + 8); \ + \ + LOADCHROMA(2, 3); \ + PUTFUNC(2, 3, 6 + 8); \ + \ + LOADCHROMA(1, 3); \ + PUTFUNC(1, 3, 6); \ + ENDYUV2RGBLINE(dst_delta, 0, 0, 1, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + \ + LOADCHROMA(2, 1); \ + PUTFUNC(2, 1, 2 + 8); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(1, 1, 2); \ + ENDYUV2RGBLINE(dst_delta, 1, 0, 1, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + ENDYUV2RGBFUNC() - LOADCHROMA(3); - PUTRGB48(dst_2, py_2, 3); - PUTRGB48(dst_1, py_1, 3); -ENDYUV2RGBLINE(48, 0) - LOADCHROMA(0); - PUTRGB48(dst_1, py_1, 0); - PUTRGB48(dst_2, py_2, 0); - - LOADCHROMA(1); - PUTRGB48(dst_2, py_2, 1); - PUTRGB48(dst_1, py_1, 1); -ENDYUV2RGBLINE(48, 1) - LOADCHROMA(0); - PUTRGB48(dst_1, py_1, 0); - PUTRGB48(dst_2, py_2, 0); -ENDYUV2RGBFUNC() - -YUV2RGBFUNC(yuv2rgb_c_bgr48, uint8_t, 0) - LOADCHROMA(0); - PUTBGR48(dst_1, py_1, 0); - PUTBGR48(dst_2, py_2, 0); - - LOADCHROMA(1); - PUTBGR48(dst_2, py_2, 1); - PUTBGR48(dst_1, py_1, 1); - - LOADCHROMA(2); - PUTBGR48(dst_1, py_1, 2); - PUTBGR48(dst_2, py_2, 2); - - LOADCHROMA(3); - PUTBGR48(dst_2, py_2, 3); - PUTBGR48(dst_1, py_1, 3); -ENDYUV2RGBLINE(48, 0) - LOADCHROMA(0); - PUTBGR48(dst_1, py_1, 0); - PUTBGR48(dst_2, py_2, 0); - - LOADCHROMA(1); - PUTBGR48(dst_2, py_2, 1); - PUTBGR48(dst_1, py_1, 1); -ENDYUV2RGBLINE(48, 1) - LOADCHROMA(0); - PUTBGR48(dst_1, py_1, 0); - PUTBGR48(dst_2, py_2, 0); -ENDYUV2RGBFUNC() - -YUV2RGBFUNC(yuv2rgb_c_32, uint32_t, 0) - LOADCHROMA(0); - PUTRGB(dst_1, py_1, 0); - PUTRGB(dst_2, py_2, 0); - - LOADCHROMA(1); - PUTRGB(dst_2, py_2, 1); - PUTRGB(dst_1, py_1, 1); - - LOADCHROMA(2); - PUTRGB(dst_1, py_1, 2); - PUTRGB(dst_2, py_2, 2); - - LOADCHROMA(3); - PUTRGB(dst_2, py_2, 3); - PUTRGB(dst_1, py_1, 3); -ENDYUV2RGBLINE(8, 0) - LOADCHROMA(0); - PUTRGB(dst_1, py_1, 0); - PUTRGB(dst_2, py_2, 0); - - LOADCHROMA(1); - PUTRGB(dst_2, py_2, 1); - PUTRGB(dst_1, py_1, 1); -ENDYUV2RGBLINE(8, 1) - LOADCHROMA(0); - PUTRGB(dst_1, py_1, 0); - PUTRGB(dst_2, py_2, 0); -ENDYUV2RGBFUNC() - -#if HAVE_BIGENDIAN -YUV2RGBFUNC(yuva2argb_c, uint32_t, 1) -#else -YUV2RGBFUNC(yuva2rgba_c, uint32_t, 1) -#endif - LOADCHROMA(0); - PUTRGBA(dst_1, py_1, pa_1, 0, 24); - PUTRGBA(dst_2, py_2, pa_2, 0, 24); - - LOADCHROMA(1); - PUTRGBA(dst_2, py_2, pa_2, 1, 24); - PUTRGBA(dst_1, py_1, pa_1, 1, 24); - - LOADCHROMA(2); - PUTRGBA(dst_1, py_1, pa_1, 2, 24); - PUTRGBA(dst_2, py_2, pa_2, 2, 24); - - LOADCHROMA(3); - PUTRGBA(dst_2, py_2, pa_2, 3, 24); - PUTRGBA(dst_1, py_1, pa_1, 3, 24); - pa_1 += 8; - pa_2 += 8; -ENDYUV2RGBLINE(8, 0) - LOADCHROMA(0); - PUTRGBA(dst_1, py_1, pa_1, 0, 24); - PUTRGBA(dst_2, py_2, pa_2, 0, 24); - - LOADCHROMA(1); - PUTRGBA(dst_2, py_2, pa_2, 1, 24); - PUTRGBA(dst_1, py_1, pa_1, 1, 24); - pa_1 += 4; - pa_2 += 4; -ENDYUV2RGBLINE(8, 1) - LOADCHROMA(0); - PUTRGBA(dst_1, py_1, pa_1, 0, 24); - PUTRGBA(dst_2, py_2, pa_2, 0, 24); -ENDYUV2RGBFUNC() - -#if HAVE_BIGENDIAN -YUV2RGBFUNC(yuva2rgba_c, uint32_t, 1) -#else -YUV2RGBFUNC(yuva2argb_c, uint32_t, 1) -#endif - LOADCHROMA(0); - PUTRGBA(dst_1, py_1, pa_1, 0, 0); - PUTRGBA(dst_2, py_2, pa_2, 0, 0); - - LOADCHROMA(1); - PUTRGBA(dst_2, py_2, pa_2, 1, 0); - PUTRGBA(dst_1, py_1, pa_1, 1, 0); - - LOADCHROMA(2); - PUTRGBA(dst_1, py_1, pa_1, 2, 0); - PUTRGBA(dst_2, py_2, pa_2, 2, 0); - - LOADCHROMA(3); - PUTRGBA(dst_2, py_2, pa_2, 3, 0); - PUTRGBA(dst_1, py_1, pa_1, 3, 0); - pa_1 += 8; - pa_2 += 8; -ENDYUV2RGBLINE(8, 0) - LOADCHROMA(0); - PUTRGBA(dst_1, py_1, pa_1, 0, 0); - PUTRGBA(dst_2, py_2, pa_2, 0, 0); - - LOADCHROMA(1); - PUTRGBA(dst_2, py_2, pa_2, 1, 0); - PUTRGBA(dst_1, py_1, pa_1, 1, 0); - pa_1 += 4; - pa_2 += 4; -ENDYUV2RGBLINE(8, 1) - LOADCHROMA(0); - PUTRGBA(dst_1, py_1, pa_1, 0, 0); - PUTRGBA(dst_2, py_2, pa_2, 0, 0); -ENDYUV2RGBFUNC() - -YUV2RGBFUNC(yuv2rgb_c_24_rgb, uint8_t, 0) - LOADCHROMA(0); - PUTRGB24(dst_1, py_1, 0); - PUTRGB24(dst_2, py_2, 0); - - LOADCHROMA(1); - PUTRGB24(dst_2, py_2, 1); - PUTRGB24(dst_1, py_1, 1); - - LOADCHROMA(2); - PUTRGB24(dst_1, py_1, 2); - PUTRGB24(dst_2, py_2, 2); - - LOADCHROMA(3); - PUTRGB24(dst_2, py_2, 3); - PUTRGB24(dst_1, py_1, 3); -ENDYUV2RGBLINE(24, 0) - LOADCHROMA(0); - PUTRGB24(dst_1, py_1, 0); - PUTRGB24(dst_2, py_2, 0); - - LOADCHROMA(1); - PUTRGB24(dst_2, py_2, 1); - PUTRGB24(dst_1, py_1, 1); -ENDYUV2RGBLINE(24, 1) - LOADCHROMA(0); - PUTRGB24(dst_1, py_1, 0); - PUTRGB24(dst_2, py_2, 0); -ENDYUV2RGBFUNC() - -// only trivial mods from yuv2rgb_c_24_rgb -YUV2RGBFUNC(yuv2rgb_c_24_bgr, uint8_t, 0) - LOADCHROMA(0); - PUTBGR24(dst_1, py_1, 0); - PUTBGR24(dst_2, py_2, 0); - - LOADCHROMA(1); - PUTBGR24(dst_2, py_2, 1); - PUTBGR24(dst_1, py_1, 1); - - LOADCHROMA(2); - PUTBGR24(dst_1, py_1, 2); - PUTBGR24(dst_2, py_2, 2); - - LOADCHROMA(3); - PUTBGR24(dst_2, py_2, 3); - PUTBGR24(dst_1, py_1, 3); -ENDYUV2RGBLINE(24, 0) - LOADCHROMA(0); - PUTBGR24(dst_1, py_1, 0); - PUTBGR24(dst_2, py_2, 0); - - LOADCHROMA(1); - PUTBGR24(dst_2, py_2, 1); - PUTBGR24(dst_1, py_1, 1); -ENDYUV2RGBLINE(24, 1) - LOADCHROMA(0); - PUTBGR24(dst_1, py_1, 0); - PUTBGR24(dst_2, py_2, 0); -ENDYUV2RGBFUNC() - -YUV2RGBFUNC(yuv2rgb_c_16_ordered_dither, uint16_t, 0) - const uint8_t *d16 = ff_dither_2x2_8[y & 1]; - const uint8_t *e16 = ff_dither_2x2_4[y & 1]; +#define LOADDITHER16 \ + const uint8_t *d16 = ff_dither_2x2_8[y & 1]; \ + const uint8_t *e16 = ff_dither_2x2_4[y & 1]; \ const uint8_t *f16 = ff_dither_2x2_8[(y & 1)^1]; -#define PUTRGB16(dst, src, i, o) \ - Y = src[2 * i]; \ - dst[2 * i] = r[Y + d16[0 + o]] + \ - g[Y + e16[0 + o]] + \ - b[Y + f16[0 + o]]; \ - Y = src[2 * i + 1]; \ - dst[2 * i + 1] = r[Y + d16[1 + o]] + \ - g[Y + e16[1 + o]] + \ - b[Y + f16[1 + o]]; - LOADCHROMA(0); - PUTRGB16(dst_1, py_1, 0, 0); - PUTRGB16(dst_2, py_2, 0, 0 + 8); +#define PUTRGB16(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d16[0 + o]] + \ + g[Y + e16[0 + o]] + \ + b[Y + f16[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d16[1 + o]] + \ + g[Y + e16[1 + o]] + \ + b[Y + f16[1 + o]]; - LOADCHROMA(1); - PUTRGB16(dst_2, py_2, 1, 2 + 8); - PUTRGB16(dst_1, py_1, 1, 2); - - LOADCHROMA(2); - PUTRGB16(dst_1, py_1, 2, 4); - PUTRGB16(dst_2, py_2, 2, 4 + 8); - - LOADCHROMA(3); - PUTRGB16(dst_2, py_2, 3, 6 + 8); - PUTRGB16(dst_1, py_1, 3, 6); -CLOSEYUV2RGBFUNC(8) - -YUV2RGBFUNC(yuv2rgb_c_15_ordered_dither, uint16_t, 0) - const uint8_t *d16 = ff_dither_2x2_8[y & 1]; +#define LOADDITHER15 \ + const uint8_t *d16 = ff_dither_2x2_8[y & 1]; \ const uint8_t *e16 = ff_dither_2x2_8[(y & 1)^1]; -#define PUTRGB15(dst, src, i, o) \ - Y = src[2 * i]; \ - dst[2 * i] = r[Y + d16[0 + o]] + \ - g[Y + d16[1 + o]] + \ - b[Y + e16[0 + o]]; \ - Y = src[2 * i + 1]; \ - dst[2 * i + 1] = r[Y + d16[1 + o]] + \ - g[Y + d16[0 + o]] + \ - b[Y + e16[1 + o]]; - LOADCHROMA(0); - PUTRGB15(dst_1, py_1, 0, 0); - PUTRGB15(dst_2, py_2, 0, 0 + 8); +#define PUTRGB15(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d16[0 + o]] + \ + g[Y + d16[1 + o]] + \ + b[Y + e16[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d16[1 + o]] + \ + g[Y + d16[0 + o]] + \ + b[Y + e16[1 + o]]; - LOADCHROMA(1); - PUTRGB15(dst_2, py_2, 1, 2 + 8); - PUTRGB15(dst_1, py_1, 1, 2); - - LOADCHROMA(2); - PUTRGB15(dst_1, py_1, 2, 4); - PUTRGB15(dst_2, py_2, 2, 4 + 8); - - LOADCHROMA(3); - PUTRGB15(dst_2, py_2, 3, 6 + 8); - PUTRGB15(dst_1, py_1, 3, 6); -CLOSEYUV2RGBFUNC(8) - -// r, g, b, dst_1, dst_2 -YUV2RGBFUNC(yuv2rgb_c_12_ordered_dither, uint16_t, 0) +#define LOADDITHER12 \ const uint8_t *d16 = ff_dither_4x4_16[y & 3]; -#define PUTRGB12(dst, src, i, o) \ - Y = src[2 * i]; \ - dst[2 * i] = r[Y + d16[0 + o]] + \ - g[Y + d16[0 + o]] + \ - b[Y + d16[0 + o]]; \ - Y = src[2 * i + 1]; \ - dst[2 * i + 1] = r[Y + d16[1 + o]] + \ - g[Y + d16[1 + o]] + \ - b[Y + d16[1 + o]]; +#define PUTRGB12(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d16[0 + o]] + \ + g[Y + d16[0 + o]] + \ + b[Y + d16[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d16[1 + o]] + \ + g[Y + d16[1 + o]] + \ + b[Y + d16[1 + o]]; - LOADCHROMA(0); - PUTRGB12(dst_1, py_1, 0, 0); - PUTRGB12(dst_2, py_2, 0, 0 + 8); - - LOADCHROMA(1); - PUTRGB12(dst_2, py_2, 1, 2 + 8); - PUTRGB12(dst_1, py_1, 1, 2); - - LOADCHROMA(2); - PUTRGB12(dst_1, py_1, 2, 4); - PUTRGB12(dst_2, py_2, 2, 4 + 8); - - LOADCHROMA(3); - PUTRGB12(dst_2, py_2, 3, 6 + 8); - PUTRGB12(dst_1, py_1, 3, 6); -CLOSEYUV2RGBFUNC(8) - -// r, g, b, dst_1, dst_2 -YUV2RGBFUNC(yuv2rgb_c_8_ordered_dither, uint8_t, 0) - const uint8_t *d32 = ff_dither_8x8_32[yd & 7]; +#define LOADDITHER8 \ + const uint8_t *d32 = ff_dither_8x8_32[yd & 7]; \ const uint8_t *d64 = ff_dither_8x8_73[yd & 7]; -#define PUTRGB8(dst, src, i, o) \ - Y = src[2 * i]; \ - dst[2 * i] = r[Y + d32[0 + o]] + \ - g[Y + d32[0 + o]] + \ - b[Y + d64[0 + o]]; \ - Y = src[2 * i + 1]; \ - dst[2 * i + 1] = r[Y + d32[1 + o]] + \ - g[Y + d32[1 + o]] + \ - b[Y + d64[1 + o]]; +#define PUTRGB8(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d32[0 + o]] + \ + g[Y + d32[0 + o]] + \ + b[Y + d64[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d32[1 + o]] + \ + g[Y + d32[1 + o]] + \ + b[Y + d64[1 + o]]; - LOADCHROMA(0); - PUTRGB8(dst_1, py_1, 0, 0); - PUTRGB8(dst_2, py_2, 0, 0 + 8); - - LOADCHROMA(1); - PUTRGB8(dst_2, py_2, 1, 2 + 8); - PUTRGB8(dst_1, py_1, 1, 2); - - LOADCHROMA(2); - PUTRGB8(dst_1, py_1, 2, 4); - PUTRGB8(dst_2, py_2, 2, 4 + 8); - - LOADCHROMA(3); - PUTRGB8(dst_2, py_2, 3, 6 + 8); - PUTRGB8(dst_1, py_1, 3, 6); - -ENDYUV2RGBLINE(8, 0) - const uint8_t *d32 = ff_dither_8x8_32[yd & 7]; - const uint8_t *d64 = ff_dither_8x8_73[yd & 7]; - LOADCHROMA(0); - PUTRGB8(dst_1, py_1, 0, 0); - PUTRGB8(dst_2, py_2, 0, 0 + 8); - - LOADCHROMA(1); - PUTRGB8(dst_2, py_2, 1, 2 + 8); - PUTRGB8(dst_1, py_1, 1, 2); - -ENDYUV2RGBLINE(8, 1) - const uint8_t *d32 = ff_dither_8x8_32[yd & 7]; - const uint8_t *d64 = ff_dither_8x8_73[yd & 7]; - LOADCHROMA(0); - PUTRGB8(dst_1, py_1, 0, 0); - PUTRGB8(dst_2, py_2, 0, 0 + 8); - -ENDYUV2RGBFUNC() - - -YUV2RGBFUNC(yuv2rgb_c_4_ordered_dither, uint8_t, 0) - const uint8_t * d64 = ff_dither_8x8_73[yd & 7]; - const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; +#define LOADDITHER4D \ + const uint8_t * d64 = ff_dither_8x8_73[yd & 7]; \ + const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; \ int acc; -#define PUTRGB4D(dst, src, i, o) \ - Y = src[2 * i]; \ +#define PUTRGB4D(l, i, o) \ + Y = py_##l[2 * i]; \ acc = r[Y + d128[0 + o]] + \ g[Y + d64[0 + o]] + \ b[Y + d128[0 + o]]; \ - Y = src[2 * i + 1]; \ + Y = py_##l[2 * i + 1]; \ acc |= (r[Y + d128[1 + o]] + \ g[Y + d64[1 + o]] + \ b[Y + d128[1 + o]]) << 4; \ - dst[i] = acc; + dst_##l[i] = acc; - LOADCHROMA(0); - PUTRGB4D(dst_1, py_1, 0, 0); - PUTRGB4D(dst_2, py_2, 0, 0 + 8); - - LOADCHROMA(1); - PUTRGB4D(dst_2, py_2, 1, 2 + 8); - PUTRGB4D(dst_1, py_1, 1, 2); - - LOADCHROMA(2); - PUTRGB4D(dst_1, py_1, 2, 4); - PUTRGB4D(dst_2, py_2, 2, 4 + 8); - - LOADCHROMA(3); - PUTRGB4D(dst_2, py_2, 3, 6 + 8); - PUTRGB4D(dst_1, py_1, 3, 6); - -ENDYUV2RGBLINE(4, 0) - const uint8_t * d64 = ff_dither_8x8_73[yd & 7]; - const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; - int acc; - LOADCHROMA(0); - PUTRGB4D(dst_1, py_1, 0, 0); - PUTRGB4D(dst_2, py_2, 0, 0 + 8); - - LOADCHROMA(1); - PUTRGB4D(dst_2, py_2, 1, 2 + 8); - PUTRGB4D(dst_1, py_1, 1, 2); - -ENDYUV2RGBLINE(4, 1) - const uint8_t * d64 = ff_dither_8x8_73[yd & 7]; - const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; - int acc; - LOADCHROMA(0); - PUTRGB4D(dst_1, py_1, 0, 0); - PUTRGB4D(dst_2, py_2, 0, 0 + 8); -ENDYUV2RGBFUNC() - -YUV2RGBFUNC(yuv2rgb_c_4b_ordered_dither, uint8_t, 0) - const uint8_t *d64 = ff_dither_8x8_73[yd & 7]; +#define LOADDITHER4DB \ + const uint8_t *d64 = ff_dither_8x8_73[yd & 7]; \ const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; -#define PUTRGB4DB(dst, src, i, o) \ - Y = src[2 * i]; \ - dst[2 * i] = r[Y + d128[0 + o]] + \ - g[Y + d64[0 + o]] + \ - b[Y + d128[0 + o]]; \ - Y = src[2 * i + 1]; \ - dst[2 * i + 1] = r[Y + d128[1 + o]] + \ - g[Y + d64[1 + o]] + \ - b[Y + d128[1 + o]]; +#define PUTRGB4DB(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d128[0 + o]] + \ + g[Y + d64[0 + o]] + \ + b[Y + d128[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d128[1 + o]] + \ + g[Y + d64[1 + o]] + \ + b[Y + d128[1 + o]]; - LOADCHROMA(0); - PUTRGB4DB(dst_1, py_1, 0, 0); - PUTRGB4DB(dst_2, py_2, 0, 0 + 8); - - LOADCHROMA(1); - PUTRGB4DB(dst_2, py_2, 1, 2 + 8); - PUTRGB4DB(dst_1, py_1, 1, 2); - - LOADCHROMA(2); - PUTRGB4DB(dst_1, py_1, 2, 4); - PUTRGB4DB(dst_2, py_2, 2, 4 + 8); - - LOADCHROMA(3); - PUTRGB4DB(dst_2, py_2, 3, 6 + 8); - PUTRGB4DB(dst_1, py_1, 3, 6); -ENDYUV2RGBLINE(8, 0) - const uint8_t *d64 = ff_dither_8x8_73[yd & 7]; - const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; - LOADCHROMA(0); - PUTRGB4DB(dst_1, py_1, 0, 0); - PUTRGB4DB(dst_2, py_2, 0, 0 + 8); - - LOADCHROMA(1); - PUTRGB4DB(dst_2, py_2, 1, 2 + 8); - PUTRGB4DB(dst_1, py_1, 1, 2); -ENDYUV2RGBLINE(8, 1) - const uint8_t *d64 = ff_dither_8x8_73[yd & 7]; - const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; - LOADCHROMA(0); - PUTRGB4DB(dst_1, py_1, 0, 0); - PUTRGB4DB(dst_2, py_2, 0, 0 + 8); -ENDYUV2RGBFUNC() - -YUV2RGBFUNC(yuv2rgb_c_1_ordered_dither, uint8_t, 0) +YUV2RGBFUNC(yuv2rgb_c_1_ordered_dither, uint8_t, 0, 0, 1) const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; char out_1 = 0, out_2 = 0; g = c->table_gU[128 + YUVRGB_TABLE_HEADROOM] + c->table_gV[128 + YUVRGB_TABLE_HEADROOM]; @@ -673,7 +479,84 @@ YUV2RGBFUNC(yuv2rgb_c_1_ordered_dither, uint8_t, 0) dst_1[0] = out_1; dst_2[0] = out_2; -CLOSEYUV2RGBFUNC(1) + + py_1 += 8; + py_2 += 8; + dst_1 += 1; + dst_2 += 1; + } + if (c->dstW & 7) { + int av_unused Y, U, V; + int pixels_left = c->dstW & 7; + const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; + char out_1 = 0, out_2 = 0; + g = c->table_gU[128 + YUVRGB_TABLE_HEADROOM] + c->table_gV[128 + YUVRGB_TABLE_HEADROOM]; + +#define PUTRGB1_OR00(out, src, i, o) \ + if (pixels_left) { \ + PUTRGB1(out, src, i, o) \ + pixels_left--; \ + } else { \ + out <<= 2; \ + } + + PUTRGB1_OR00(out_1, py_1, 0, 0); + PUTRGB1_OR00(out_2, py_2, 0, 0 + 8); + + PUTRGB1_OR00(out_2, py_2, 1, 2 + 8); + PUTRGB1_OR00(out_1, py_1, 1, 2); + + PUTRGB1_OR00(out_1, py_1, 2, 4); + PUTRGB1_OR00(out_2, py_2, 2, 4 + 8); + + PUTRGB1_OR00(out_2, py_2, 3, 6 + 8); + PUTRGB1_OR00(out_1, py_1, 3, 6); + + dst_1[0] = out_1; + dst_2[0] = out_2; +ENDYUV2RGBFUNC() + +// YUV420 +YUV420FUNC(yuv2rgb_c_48, uint8_t, 0, 0, PUTRGB48, 48, 1) +YUV420FUNC(yuv2rgb_c_bgr48, uint8_t, 0, 0, PUTBGR48, 48, 1) +YUV420FUNC(yuv2rgb_c_32, uint32_t, 0, 0, PUTRGB, 8, 1) +#if HAVE_BIGENDIAN +YUV420FUNC(yuva2argb_c, uint32_t, 1, 24, PUTRGBA, 8, 1) +YUV420FUNC(yuva2rgba_c, uint32_t, 1, 0, PUTRGBA, 8, 1) +#else +YUV420FUNC(yuva2rgba_c, uint32_t, 1, 24, PUTRGBA, 8, 1) +YUV420FUNC(yuva2argb_c, uint32_t, 1, 0, PUTRGBA, 8, 1) +#endif +YUV420FUNC(yuv2rgb_c_24_rgb, uint8_t, 0, 0, PUTRGB24, 24, 1) +YUV420FUNC(yuv2rgb_c_24_bgr, uint8_t, 0, 0, PUTBGR24, 24, 1) +YUV420FUNC(yuv420p_gbrp_c, uint8_t, 0, 0, PUTGBRP, 8, 3) +YUV420FUNC_DITHER(yuv2rgb_c_16_ordered_dither, uint16_t, LOADDITHER16, PUTRGB16, 8) +YUV420FUNC_DITHER(yuv2rgb_c_15_ordered_dither, uint16_t, LOADDITHER15, PUTRGB15, 8) +YUV420FUNC_DITHER(yuv2rgb_c_12_ordered_dither, uint16_t, LOADDITHER12, PUTRGB12, 8) +YUV420FUNC_DITHER(yuv2rgb_c_8_ordered_dither, uint8_t, LOADDITHER8, PUTRGB8, 8) +YUV420FUNC_DITHER(yuv2rgb_c_4_ordered_dither, uint8_t, LOADDITHER4D, PUTRGB4D, 4) +YUV420FUNC_DITHER(yuv2rgb_c_4b_ordered_dither, uint8_t, LOADDITHER4DB, PUTRGB4DB, 8) + +// YUV422 +YUV422FUNC(yuv422p_rgb48_c, uint8_t, 0, 0, PUTRGB48, 48, 1) +YUV422FUNC(yuv422p_bgr48_c, uint8_t, 0, 0, PUTBGR48, 48, 1) +YUV422FUNC(yuv422p_rgb32_c, uint32_t, 0, 0, PUTRGB, 8, 1) +#if HAVE_BIGENDIAN +YUV422FUNC(yuva422p_argb_c, uint32_t, 1, 24, PUTRGBA, 8, 1) +YUV422FUNC(yuva422p_rgba_c, uint32_t, 1, 0, PUTRGBA, 8, 1) +#else +YUV422FUNC(yuva422p_rgba_c, uint32_t, 1, 24, PUTRGBA, 8, 1) +YUV422FUNC(yuva422p_argb_c, uint32_t, 1, 0, PUTRGBA, 8, 1) +#endif +YUV422FUNC(yuv422p_rgb24_c, uint8_t, 0, 0, PUTRGB24, 24, 1) +YUV422FUNC(yuv422p_bgr24_c, uint8_t, 0, 0, PUTBGR24, 24, 1) +YUV422FUNC(yuv422p_gbrp_c, uint8_t, 0, 0, PUTGBRP, 8, 3) +YUV422FUNC_DITHER(yuv422p_bgr16, uint16_t, LOADDITHER16, PUTRGB16, 8) +YUV422FUNC_DITHER(yuv422p_bgr15, uint16_t, LOADDITHER15, PUTRGB15, 8) +YUV422FUNC_DITHER(yuv422p_bgr12, uint16_t, LOADDITHER12, PUTRGB12, 8) +YUV422FUNC_DITHER(yuv422p_bgr8, uint8_t, LOADDITHER8, PUTRGB8, 8) +YUV422FUNC_DITHER(yuv422p_bgr4, uint8_t, LOADDITHER4D, PUTRGB4D, 4) +YUV422FUNC_DITHER(yuv422p_bgr4_byte, uint8_t, LOADDITHER4DB, PUTRGB4DB, 8) SwsFunc ff_yuv2rgb_get_func_ptr(SwsContext *c) { @@ -694,44 +577,90 @@ SwsFunc ff_yuv2rgb_get_func_ptr(SwsContext *c) "No accelerated colorspace conversion found from %s to %s.\n", av_get_pix_fmt_name(c->srcFormat), av_get_pix_fmt_name(c->dstFormat)); - switch (c->dstFormat) { - case AV_PIX_FMT_BGR48BE: - case AV_PIX_FMT_BGR48LE: - return yuv2rgb_c_bgr48; - case AV_PIX_FMT_RGB48BE: - case AV_PIX_FMT_RGB48LE: - return yuv2rgb_c_48; - case AV_PIX_FMT_ARGB: - case AV_PIX_FMT_ABGR: - if (CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat)) - return yuva2argb_c; - case AV_PIX_FMT_RGBA: - case AV_PIX_FMT_BGRA: - return (CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat)) ? yuva2rgba_c : yuv2rgb_c_32; - case AV_PIX_FMT_RGB24: - return yuv2rgb_c_24_rgb; - case AV_PIX_FMT_BGR24: - return yuv2rgb_c_24_bgr; - case AV_PIX_FMT_RGB565: - case AV_PIX_FMT_BGR565: - return yuv2rgb_c_16_ordered_dither; - case AV_PIX_FMT_RGB555: - case AV_PIX_FMT_BGR555: - return yuv2rgb_c_15_ordered_dither; - case AV_PIX_FMT_RGB444: - case AV_PIX_FMT_BGR444: - return yuv2rgb_c_12_ordered_dither; - case AV_PIX_FMT_RGB8: - case AV_PIX_FMT_BGR8: - return yuv2rgb_c_8_ordered_dither; - case AV_PIX_FMT_RGB4: - case AV_PIX_FMT_BGR4: - return yuv2rgb_c_4_ordered_dither; - case AV_PIX_FMT_RGB4_BYTE: - case AV_PIX_FMT_BGR4_BYTE: - return yuv2rgb_c_4b_ordered_dither; - case AV_PIX_FMT_MONOBLACK: - return yuv2rgb_c_1_ordered_dither; + if (c->srcFormat == AV_PIX_FMT_YUV422P) { + switch (c->dstFormat) { + case AV_PIX_FMT_BGR48BE: + case AV_PIX_FMT_BGR48LE: + return yuv422p_bgr48_c; + case AV_PIX_FMT_RGB48BE: + case AV_PIX_FMT_RGB48LE: + return yuv422p_rgb48_c; + case AV_PIX_FMT_ARGB: + case AV_PIX_FMT_ABGR: + if (CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat)) + return yuva422p_argb_c; + case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_BGRA: + return (CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat)) ? yuva422p_rgba_c : yuv422p_rgb32_c; + case AV_PIX_FMT_RGB24: + return yuv422p_rgb24_c; + case AV_PIX_FMT_BGR24: + return yuv422p_bgr24_c; + case AV_PIX_FMT_RGB565: + case AV_PIX_FMT_BGR565: + return yuv422p_bgr16; + case AV_PIX_FMT_RGB555: + case AV_PIX_FMT_BGR555: + return yuv422p_bgr15; + case AV_PIX_FMT_RGB444: + case AV_PIX_FMT_BGR444: + return yuv422p_bgr12; + case AV_PIX_FMT_RGB8: + case AV_PIX_FMT_BGR8: + return yuv422p_bgr8; + case AV_PIX_FMT_RGB4: + case AV_PIX_FMT_BGR4: + return yuv422p_bgr4; + case AV_PIX_FMT_RGB4_BYTE: + case AV_PIX_FMT_BGR4_BYTE: + return yuv422p_bgr4_byte; + case AV_PIX_FMT_MONOBLACK: + return yuv2rgb_c_1_ordered_dither; + case AV_PIX_FMT_GBRP: + return yuv422p_gbrp_c; + } + } else { + switch (c->dstFormat) { + case AV_PIX_FMT_BGR48BE: + case AV_PIX_FMT_BGR48LE: + return yuv2rgb_c_bgr48; + case AV_PIX_FMT_RGB48BE: + case AV_PIX_FMT_RGB48LE: + return yuv2rgb_c_48; + case AV_PIX_FMT_ARGB: + case AV_PIX_FMT_ABGR: + if (CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat)) + return yuva2argb_c; + case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_BGRA: + return (CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat)) ? yuva2rgba_c : yuv2rgb_c_32; + case AV_PIX_FMT_RGB24: + return yuv2rgb_c_24_rgb; + case AV_PIX_FMT_BGR24: + return yuv2rgb_c_24_bgr; + case AV_PIX_FMT_RGB565: + case AV_PIX_FMT_BGR565: + return yuv2rgb_c_16_ordered_dither; + case AV_PIX_FMT_RGB555: + case AV_PIX_FMT_BGR555: + return yuv2rgb_c_15_ordered_dither; + case AV_PIX_FMT_RGB444: + case AV_PIX_FMT_BGR444: + return yuv2rgb_c_12_ordered_dither; + case AV_PIX_FMT_RGB8: + case AV_PIX_FMT_BGR8: + return yuv2rgb_c_8_ordered_dither; + case AV_PIX_FMT_RGB4: + case AV_PIX_FMT_BGR4: + return yuv2rgb_c_4_ordered_dither; + case AV_PIX_FMT_RGB4_BYTE: + case AV_PIX_FMT_BGR4_BYTE: + return yuv2rgb_c_4b_ordered_dither; + case AV_PIX_FMT_MONOBLACK: + return yuv2rgb_c_1_ordered_dither; + case AV_PIX_FMT_GBRP: + return yuv420p_gbrp_c; + } } return NULL; } diff --git a/tests/Makefile b/tests/Makefile index ed6b1801a..9b7014501 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -253,6 +253,7 @@ include $(SRC_PATH)/tests/fate/xvid.mak FATE_FFMPEG += $(FATE_FFMPEG-yes) $(FATE_AVCONV) $(FATE_AVCONV-yes) FATE-$(CONFIG_FFMPEG) += $(FATE_FFMPEG) +FATE_FFPROBE += $(FATE_FFPROBE-yes) FATE-$(CONFIG_FFPROBE) += $(FATE_FFPROBE) FATE-$(call ALLYES, FFMPEG FFPROBE) += $(FATE_FFMPEG_FFPROBE) diff --git a/tests/api/api-band-test.c b/tests/api/api-band-test.c index b00e2927a..c3612bedb 100644 --- a/tests/api/api-band-test.c +++ b/tests/api/api-band-test.c @@ -25,12 +25,12 @@ */ #include "libavutil/adler32.h" +#include "libavutil/mem.h" #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavutil/imgutils.h" uint8_t *slice_byte_buffer; -uint8_t slice_byte_buffer_size; int draw_horiz_band_called; static void draw_horiz_band(AVCodecContext *ctx, const AVFrame *fr, int offset[4], @@ -106,6 +106,11 @@ static int video_decode(const char *input_filename) return -1; } + if (!(codec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)) { + av_log(NULL, AV_LOG_ERROR, "Codec does not support draw_horiz_band\n"); + return -1; + } + ctx = avcodec_alloc_context3(codec); if (!ctx) { av_log(NULL, AV_LOG_ERROR, "Can't allocate decoder context\n"); @@ -139,11 +144,6 @@ static int video_decode(const char *input_filename) return AVERROR(ENOMEM); } - if (strcmp(codec->name, "flv") && strcmp(codec->name, "mpeg4") && strcmp(codec->name, "huffyuv")) { - av_log(NULL, AV_LOG_ERROR, "Wrong codec\n"); - return -1; - } - byte_buffer_size = av_image_get_buffer_size(ctx->pix_fmt, ctx->width, ctx->height, 32); byte_buffer = av_malloc(byte_buffer_size); if (!byte_buffer) { @@ -157,7 +157,6 @@ static int video_decode(const char *input_filename) return AVERROR(ENOMEM); } memset(slice_byte_buffer, 0, byte_buffer_size); - slice_byte_buffer_size = byte_buffer_size; result = 0; while (result >= 0) { @@ -223,7 +222,7 @@ int main(int argc, char **argv) { if (argc < 2) { - av_log(NULL, AV_LOG_ERROR, "Incorrect input: expected %s \nNote that test works only for huffyuv, flv and mpeg4 decoders\n", argv[0]); + av_log(NULL, AV_LOG_ERROR, "Incorrect input: expected %s \n", argv[0]); return 1; } diff --git a/tests/api/api-flac-test.c b/tests/api/api-flac-test.c index d1e45acda..e65e261b9 100644 --- a/tests/api/api-flac-test.c +++ b/tests/api/api-flac-test.c @@ -30,6 +30,7 @@ #include "libavcodec/avcodec.h" #include "libavutil/channel_layout.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/samplefmt.h" #define NUMBER_OF_AUDIO_FRAMES 200 diff --git a/tests/api/api-h264-slice-test.c b/tests/api/api-h264-slice-test.c index b7aa405b0..f4a9c865c 100644 --- a/tests/api/api-h264-slice-test.c +++ b/tests/api/api-h264-slice-test.c @@ -39,6 +39,7 @@ #include #include "libavcodec/avcodec.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/hash.h" #include "libavutil/bswap.h" diff --git a/tests/api/api-h264-test.c b/tests/api/api-h264-test.c index c89f1ba41..e1e8803c1 100644 --- a/tests/api/api-h264-test.c +++ b/tests/api/api-h264-test.c @@ -25,6 +25,7 @@ */ #include "libavutil/adler32.h" +#include "libavutil/mem.h" #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavutil/imgutils.h" diff --git a/tests/api/api-seek-test.c b/tests/api/api-seek-test.c index e86908e28..1bf9a1bde 100644 --- a/tests/api/api-seek-test.c +++ b/tests/api/api-seek-test.c @@ -25,6 +25,7 @@ */ #include "libavutil/adler32.h" +#include "libavutil/mem.h" #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavutil/imgutils.h" diff --git a/tests/api/api-threadmessage-test.c b/tests/api/api-threadmessage-test.c index c96b473c4..b9a4bdca1 100644 --- a/tests/api/api-threadmessage-test.c +++ b/tests/api/api-threadmessage-test.c @@ -25,6 +25,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/frame.h" +#include "libavutil/mem.h" #include "libavutil/threadmessage.h" #include "libavutil/thread.h" // not public diff --git a/tests/audiogen.c b/tests/audiogen.c index c43bb70ff..df1dea675 100644 --- a/tests/audiogen.c +++ b/tests/audiogen.c @@ -109,7 +109,7 @@ static void put32(uint32_t v) fputc((v >> 24) & 0xff, outfile); } -#define HEADER_SIZE 46 +#define HEADER_SIZE 38 #define FMT_SIZE 18 #define SAMPLE_SIZE 2 #define WFORMAT_PCM 0x0001 diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile index 2673e1d09..ae324ced3 100644 --- a/tests/checkasm/Makefile +++ b/tests/checkasm/Makefile @@ -4,8 +4,10 @@ AVCODECOBJS-$(CONFIG_AC3DSP) += ac3dsp.o AVCODECOBJS-$(CONFIG_AUDIODSP) += audiodsp.o AVCODECOBJS-$(CONFIG_BLOCKDSP) += blockdsp.o AVCODECOBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o +AVCODECOBJS-$(CONFIG_FDCTDSP) += fdctdsp.o AVCODECOBJS-$(CONFIG_FMTCONVERT) += fmtconvert.o AVCODECOBJS-$(CONFIG_G722DSP) += g722dsp.o +AVCODECOBJS-$(CONFIG_H263DSP) += h263dsp.o AVCODECOBJS-$(CONFIG_H264CHROMA) += h264chroma.o AVCODECOBJS-$(CONFIG_H264DSP) += h264dsp.o AVCODECOBJS-$(CONFIG_H264PRED) += h264pred.o @@ -16,6 +18,7 @@ AVCODECOBJS-$(CONFIG_LLVIDDSP) += llviddsp.o AVCODECOBJS-$(CONFIG_LLVIDENCDSP) += llviddspenc.o AVCODECOBJS-$(CONFIG_LPC) += lpc.o AVCODECOBJS-$(CONFIG_ME_CMP) += motion.o +AVCODECOBJS-$(CONFIG_MPEGVIDEOENC) += mpegvideoencdsp.o AVCODECOBJS-$(CONFIG_VC1DSP) += vc1dsp.o AVCODECOBJS-$(CONFIG_VP8DSP) += vp8dsp.o AVCODECOBJS-$(CONFIG_VIDEODSP) += videodsp.o @@ -34,6 +37,7 @@ AVCODECOBJS-$(CONFIG_OPUS_DECODER) += opusdsp.o AVCODECOBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o AVCODECOBJS-$(CONFIG_HEVC_DECODER) += hevc_add_res.o hevc_deblock.o hevc_idct.o hevc_sao.o hevc_pel.o AVCODECOBJS-$(CONFIG_RV34DSP) += rv34dsp.o +AVCODECOBJS-$(CONFIG_RV40_DECODER) += rv40dsp.o AVCODECOBJS-$(CONFIG_SVQ1_ENCODER) += svq1enc.o AVCODECOBJS-$(CONFIG_TAK_DECODER) += takdsp.o AVCODECOBJS-$(CONFIG_UTVIDEO_DECODER) += utvideodsp.o @@ -41,7 +45,7 @@ AVCODECOBJS-$(CONFIG_V210_DECODER) += v210dec.o AVCODECOBJS-$(CONFIG_V210_ENCODER) += v210enc.o AVCODECOBJS-$(CONFIG_VORBIS_DECODER) += vorbisdsp.o AVCODECOBJS-$(CONFIG_VP9_DECODER) += vp9dsp.o -AVCODECOBJS-$(CONFIG_VVC_DECODER) += vvc_mc.o +AVCODECOBJS-$(CONFIG_VVC_DECODER) += vvc_alf.o vvc_mc.o CHECKASMOBJS-$(CONFIG_AVCODEC) += $(AVCODECOBJS-yes) @@ -60,7 +64,7 @@ AVFILTEROBJS-$(CONFIG_SOBEL_FILTER) += vf_convolution.o CHECKASMOBJS-$(CONFIG_AVFILTER) += $(AVFILTEROBJS-yes) # swscale tests -SWSCALEOBJS += sw_gbrp.o sw_rgb.o sw_scale.o +SWSCALEOBJS += sw_gbrp.o sw_range_convert.o sw_rgb.o sw_scale.o sw_yuv2rgb.o sw_yuv2yuv.o CHECKASMOBJS-$(CONFIG_SWSCALE) += $(SWSCALEOBJS) @@ -68,6 +72,7 @@ CHECKASMOBJS-$(CONFIG_SWSCALE) += $(SWSCALEOBJS) AVUTILOBJS += av_tx.o AVUTILOBJS += fixed_dsp.o AVUTILOBJS += float_dsp.o +AVUTILOBJS += lls.o CHECKASMOBJS-$(CONFIG_AVUTIL) += $(AVUTILOBJS) diff --git a/tests/checkasm/aacencdsp.c b/tests/checkasm/aacencdsp.c index 1756c4ecd..713284211 100644 --- a/tests/checkasm/aacencdsp.c +++ b/tests/checkasm/aacencdsp.c @@ -22,7 +22,9 @@ #include "libavutil/mem_internal.h" +#include "libavcodec/aacenc_utils.h" #include "libavcodec/aacencdsp.h" +#include "libavcodec/aactab.h" #include "checkasm.h" @@ -35,6 +37,8 @@ } \ } while (0) +#define randomize_elem(tab) (tab[rnd() % FF_ARRAY_ELEMS(tab)]) + static void test_abs_pow34(AACEncDSPContext *s) { #define BUF_SIZE 1024 @@ -60,6 +64,38 @@ static void test_abs_pow34(AACEncDSPContext *s) report("abs_pow34"); } +static void test_quant_bands(AACEncDSPContext *s) +{ + int maxval = randomize_elem(aac_cb_maxval); + float q34 = (float)rnd() / (UINT_MAX / 1024); + float rounding = (rnd() & 1) ? ROUND_TO_ZERO : ROUND_STANDARD; + LOCAL_ALIGNED_16(float, in, [BUF_SIZE]); + LOCAL_ALIGNED_16(float, scaled, [BUF_SIZE]); + + declare_func(void, int *, const float *, const float *, int, int, int, + const float, const float); + + randomize_float(in, BUF_SIZE); + randomize_float(scaled, BUF_SIZE); + + for (int sign = 0; sign <= 1; sign++) { + if (check_func(s->quant_bands, "quant_bands_%s", + sign ? "signed" : "unsigned")) { + LOCAL_ALIGNED_32(int, out, [BUF_SIZE]); + LOCAL_ALIGNED_32(int, out2, [BUF_SIZE]); + + call_ref(out, in, scaled, BUF_SIZE, sign, maxval, q34, rounding); + call_new(out2, in, scaled, BUF_SIZE, sign, maxval, q34, rounding); + + if (memcmp(out, out2, BUF_SIZE * sizeof (int))) + fail(); + + bench_new(out, in, scaled, BUF_SIZE, sign, maxval, q34, rounding); + } + } + + report("quant_bands"); +} void checkasm_check_aacencdsp(void) { @@ -67,4 +103,5 @@ void checkasm_check_aacencdsp(void) ff_aacenc_dsp_init(&s); test_abs_pow34(&s); + test_quant_bands(&s); } diff --git a/tests/checkasm/ac3dsp.c b/tests/checkasm/ac3dsp.c index 344e1fe5c..8c682d03c 100644 --- a/tests/checkasm/ac3dsp.c +++ b/tests/checkasm/ac3dsp.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Institue of Software Chinese Academy of Sciences (ISCAS). + * Copyright (c) 2024 Geoff Hill * * This file is part of FFmpeg. * @@ -18,6 +19,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include #include "libavutil/mem.h" @@ -27,6 +29,24 @@ #include "checkasm.h" +#define randomize_exp(buf, len) \ + do { \ + int i; \ + for (i = 0; i < len; i++) { \ + buf[i] = (uint8_t)rnd(); \ + } \ + } while (0) + +#define randomize_i24(buf, len) \ + do { \ + int i; \ + for (i = 0; i < len; i++) { \ + int32_t v = (int32_t)rnd(); \ + int32_t u = (v & 0xFFFFFF); \ + buf[i] = (v < 0) ? -u : u; \ + } \ + } while (0) + #define randomize_float(buf, len) \ do { \ int i; \ @@ -36,6 +56,64 @@ } \ } while (0) +static void check_ac3_exponent_min(AC3DSPContext *c) { +#define MAX_COEFS 256 +#define MAX_CTXT 6 +#define EXP_SIZE (MAX_CTXT * MAX_COEFS) + + LOCAL_ALIGNED_16(uint8_t, src, [EXP_SIZE]); + LOCAL_ALIGNED_16(uint8_t, v1, [EXP_SIZE]); + LOCAL_ALIGNED_16(uint8_t, v2, [EXP_SIZE]); + int n; + + declare_func(void, uint8_t *, int, int); + + for (n = 0; n < MAX_CTXT; ++n) { + if (check_func(c->ac3_exponent_min, "ac3_exponent_min_reuse%d", n)) { + randomize_exp(src, EXP_SIZE); + + memcpy(v1, src, EXP_SIZE); + memcpy(v2, src, EXP_SIZE); + + call_ref(v1, n, MAX_COEFS); + call_new(v2, n, MAX_COEFS); + + if (memcmp(v1, v2, EXP_SIZE) != 0) + fail(); + + bench_new(v2, n, MAX_COEFS); + } + } + + report("ac3_exponent_min"); +} + +static void check_ac3_extract_exponents(AC3DSPContext *c) { +#define MAX_EXPS 3072 + LOCAL_ALIGNED_16(int32_t, src, [MAX_EXPS]); + LOCAL_ALIGNED_16(uint8_t, v1, [MAX_EXPS]); + LOCAL_ALIGNED_16(uint8_t, v2, [MAX_EXPS]); + int n; + + declare_func(void, uint8_t *, int32_t *, int); + + for (n = 512; n <= MAX_EXPS; n += 256) { + if (check_func(c->extract_exponents, "ac3_extract_exponents_n%d", n)) { + randomize_i24(src, n); + + call_ref(v1, src, n); + call_new(v2, src, n); + + if (memcmp(v1, v2, n) != 0) + fail(); + + bench_new(v1, src, n); + } + } + + report("ac3_extract_exponents"); +} + static void check_float_to_fixed24(AC3DSPContext *c) { #define BUF_SIZE 1024 LOCAL_ALIGNED_32(float, src, [BUF_SIZE]); @@ -61,10 +139,65 @@ static void check_float_to_fixed24(AC3DSPContext *c) { report("float_to_fixed24"); } +static void check_ac3_sum_square_butterfly_int32(AC3DSPContext *c) { +#define ELEMS 240 + LOCAL_ALIGNED_16(int32_t, lt, [ELEMS]); + LOCAL_ALIGNED_16(int32_t, rt, [ELEMS]); + LOCAL_ALIGNED_16(uint64_t, v1, [4]); + LOCAL_ALIGNED_16(uint64_t, v2, [4]); + + declare_func(void, int64_t[4], const int32_t *, const int32_t *, int); + + randomize_i24(lt, ELEMS); + randomize_i24(rt, ELEMS); + + if (check_func(c->sum_square_butterfly_int32, + "ac3_sum_square_bufferfly_int32")) { + call_ref(v1, lt, rt, ELEMS); + call_new(v2, lt, rt, ELEMS); + + if (memcmp(v1, v2, sizeof(int64_t[4])) != 0) + fail(); + + bench_new(v2, lt, rt, ELEMS); + } + + report("ac3_sum_square_butterfly_int32"); +} + +static void check_ac3_sum_square_butterfly_float(AC3DSPContext *c) { + LOCAL_ALIGNED_32(float, lt, [ELEMS]); + LOCAL_ALIGNED_32(float, rt, [ELEMS]); + LOCAL_ALIGNED_16(float, v1, [4]); + LOCAL_ALIGNED_16(float, v2, [4]); + + declare_func(void, float[4], const float *, const float *, int); + + randomize_float(lt, ELEMS); + randomize_float(rt, ELEMS); + + if (check_func(c->sum_square_butterfly_float, + "ac3_sum_square_bufferfly_float")) { + call_ref(v1, lt, rt, ELEMS); + call_new(v2, lt, rt, ELEMS); + + if (!float_near_ulp_array(v1, v2, 11, 4)) + fail(); + + bench_new(v2, lt, rt, ELEMS); + } + + report("ac3_sum_square_butterfly_float"); +} + void checkasm_check_ac3dsp(void) { AC3DSPContext c; ff_ac3dsp_init(&c); + check_ac3_exponent_min(&c); + check_ac3_extract_exponents(&c); check_float_to_fixed24(&c); + check_ac3_sum_square_butterfly_int32(&c); + check_ac3_sum_square_butterfly_float(&c); } diff --git a/tests/checkasm/av_tx.c b/tests/checkasm/av_tx.c index aa8fc6b4e..2d7b4e662 100644 --- a/tests/checkasm/av_tx.c +++ b/tests/checkasm/av_tx.c @@ -16,6 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/tx.h" #include "libavutil/error.h" diff --git a/tests/checkasm/blockdsp.c b/tests/checkasm/blockdsp.c index 22a2f7945..5f4d46b8f 100644 --- a/tests/checkasm/blockdsp.c +++ b/tests/checkasm/blockdsp.c @@ -52,6 +52,29 @@ do { \ } \ } while (0) +static void check_fill(BlockDSPContext *h){ + LOCAL_ALIGNED_16(uint8_t, buf0_16, [16 * 16]); + LOCAL_ALIGNED_16(uint8_t, buf1_16, [16 * 16]); + + for (int t = 0; t < 2; ++t) { + uint8_t *buf0 = buf0_16 + t * /* force 8 byte alignment */ 8; + uint8_t *buf1 = buf1_16 + t * /* force 8 byte alignment */ 8; + int n = 16 - 8 * t; + declare_func(void, uint8_t *block, uint8_t value, + ptrdiff_t line_size, int h); + if (check_func(h->fill_block_tab[t], "blockdsp.fill_block_tab[%d]", t)) { + uint8_t value = rnd(); + memset(buf0, 0, sizeof(*buf0) * n * n); + memset(buf1, 0, sizeof(*buf1) * n * n); + call_ref(buf0, value, n, n); + call_new(buf1, value, n, n); + if (memcmp(buf0, buf1, sizeof(*buf0) * n * n)) + fail(); + bench_new(buf0, value, n, n); + } + } +} + void checkasm_check_blockdsp(void) { LOCAL_ALIGNED_32(uint16_t, buf0, [6 * 8 * 8]); @@ -64,5 +87,7 @@ void checkasm_check_blockdsp(void) check_clear(clear_block, 8 * 8); check_clear(clear_blocks, 8 * 8 * 6); + check_fill(&h); + report("blockdsp"); } diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index dcd2fd695..5b59cdf58 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -18,6 +18,31 @@ * You should have received a copy of the GNU General 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 © 2018, VideoLAN and dav1d authors + * Copyright © 2018, Two Orioles, LLC + * All rights reserved. + * + * 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 "config.h" @@ -41,6 +66,9 @@ #if HAVE_IO_H #include #endif +#if HAVE_PRCTL +#include +#endif #if defined(_WIN32) && !defined(SIGBUS) /* non-standard, use the same value as mingw-w64 */ @@ -72,6 +100,9 @@ void (*checkasm_checked_call)(void *func, int dummy, ...) = checkasm_checked_call_novfp; #endif +/* Trade-off between speed and accuracy */ +uint64_t bench_runs = 1U << 10; + /* List of tests to invoke */ static const struct { const char *name; @@ -106,6 +137,9 @@ static const struct { #if CONFIG_EXR_DECODER { "exrdsp", checkasm_check_exrdsp }, #endif + #if CONFIG_FDCTDSP + { "fdctdsp", checkasm_check_fdctdsp }, + #endif #if CONFIG_FLAC_DECODER { "flacdsp", checkasm_check_flacdsp }, #endif @@ -115,6 +149,9 @@ static const struct { #if CONFIG_G722DSP { "g722dsp", checkasm_check_g722dsp }, #endif + #if CONFIG_H263DSP + { "h263dsp", checkasm_check_h263dsp }, + #endif #if CONFIG_H264CHROMA { "h264chroma", checkasm_check_h264chroma }, #endif @@ -158,6 +195,9 @@ static const struct { #if CONFIG_ME_CMP { "motion", checkasm_check_motion }, #endif + #if CONFIG_MPEGVIDEOENC + { "mpegvideoencdsp", checkasm_check_mpegvideoencdsp }, + #endif #if CONFIG_OPUS_DECODER { "opusdsp", checkasm_check_opusdsp }, #endif @@ -167,6 +207,9 @@ static const struct { #if CONFIG_RV34DSP { "rv34dsp", checkasm_check_rv34dsp }, #endif + #if CONFIG_RV40_DECODER + { "rv40dsp", checkasm_check_rv40dsp }, + #endif #if CONFIG_SVQ1_ENCODER { "svq1enc", checkasm_check_svq1enc }, #endif @@ -198,7 +241,8 @@ static const struct { { "vorbisdsp", checkasm_check_vorbisdsp }, #endif #if CONFIG_VVC_DECODER - { "vvc_mc", checkasm_check_vvc_mc }, + { "vvc_alf", checkasm_check_vvc_alf }, + { "vvc_mc", checkasm_check_vvc_mc }, #endif #endif #if CONFIG_AVFILTER @@ -235,12 +279,16 @@ static const struct { #endif #if CONFIG_SWSCALE { "sw_gbrp", checkasm_check_sw_gbrp }, + { "sw_range_convert", checkasm_check_sw_range_convert }, { "sw_rgb", checkasm_check_sw_rgb }, { "sw_scale", checkasm_check_sw_scale }, + { "sw_yuv2rgb", checkasm_check_sw_yuv2rgb }, + { "sw_yuv2yuv", checkasm_check_sw_yuv2yuv }, #endif #if CONFIG_AVUTIL { "fixed_dsp", checkasm_check_fixed_dsp }, { "float_dsp", checkasm_check_float_dsp }, + { "lls", checkasm_check_lls }, { "av_tx", checkasm_check_av_tx }, #endif { NULL } @@ -271,14 +319,14 @@ static const struct { { "POWER8", "power8", AV_CPU_FLAG_POWER8 }, #elif ARCH_RISCV { "RVI", "rvi", AV_CPU_FLAG_RVI }, - { "RVF", "rvf", AV_CPU_FLAG_RVF }, - { "RVD", "rvd", AV_CPU_FLAG_RVD }, - { "RVBaddr", "rvb_a", AV_CPU_FLAG_RVB_ADDR }, - { "RVBbasic", "rvb_b", AV_CPU_FLAG_RVB_BASIC }, - { "RVVi32", "rvv_i32", AV_CPU_FLAG_RVV_I32 }, - { "RVVf32", "rvv_f32", AV_CPU_FLAG_RVV_F32 }, - { "RVVi64", "rvv_i64", AV_CPU_FLAG_RVV_I64 }, - { "RVVf64", "rvv_f64", AV_CPU_FLAG_RVV_F64 }, + { "misaligned", "misaligned", AV_CPU_FLAG_RV_MISALIGNED }, + { "RV_zbb", "rvb_b", AV_CPU_FLAG_RVB_BASIC }, + { "RVB", "rvb", AV_CPU_FLAG_RVB }, + { "RV_zve32x","rvv_i32", AV_CPU_FLAG_RVV_I32 }, + { "RV_zve32f","rvv_f32", AV_CPU_FLAG_RVV_F32 }, + { "RV_zve64x","rvv_i64", AV_CPU_FLAG_RVV_I64 }, + { "RV_zve64d","rvv_f64", AV_CPU_FLAG_RVV_F64 }, + { "RV_zvbb", "rv_zvbb", AV_CPU_FLAG_RV_ZVBB }, #elif ARCH_MIPS { "MMI", "mmi", AV_CPU_FLAG_MMI }, { "MSA", "msa", AV_CPU_FLAG_MSA }, @@ -341,8 +389,10 @@ static struct { int cpu_flag; const char *cpu_flag_name; - const char *test_name; + const char *test_pattern; int verbose; + int csv; + int tsv; volatile sig_atomic_t catch_signals; } state; @@ -554,23 +604,46 @@ static int measure_nop_time(void) return nop_sum / 500; } +static inline double avg_cycles_per_call(const CheckasmPerf *const p) +{ + if (p->iterations) { + const double cycles = (double)(10 * p->cycles) / p->iterations - state.nop_time; + if (cycles > 0.0) + return cycles / 4.0; /* 4 calls per iteration */ + } + return 0.0; +} + /* Print benchmark results */ static void print_benchs(CheckasmFunc *f) { if (f) { + CheckasmFuncVersion *v = &f->versions; + const CheckasmPerf *p = &v->perf; + const double baseline = avg_cycles_per_call(p); + double decicycles; + print_benchs(f->child[0]); - /* Only print functions with at least one assembly version */ - if (f->versions.cpu || f->versions.next) { - CheckasmFuncVersion *v = &f->versions; - do { - CheckasmPerf *p = &v->perf; - if (p->iterations) { - int decicycles = (10*p->cycles/p->iterations - state.nop_time) / 4; - printf("%s_%s: %d.%d\n", f->name, cpu_suffix(v->cpu), decicycles/10, decicycles%10); + do { + if (p->iterations) { + p = &v->perf; + decicycles = avg_cycles_per_call(p); + if (state.csv || state.tsv) { + const char sep = state.csv ? ',' : '\t'; + printf("%s%c%s%c%.1f\n", f->name, sep, + cpu_suffix(v->cpu), sep, + decicycles / 10.0); + } else { + const int pad_length = 10 + 50 - + printf("%s_%s:", f->name, cpu_suffix(v->cpu)); + const double ratio = decicycles ? + baseline / decicycles : 0.0; + printf("%*.1f (%5.2fx)\n", FFMAX(pad_length, 0), + decicycles / 10.0, ratio); } - } while ((v = v->next)); - } + } + } while ((v = v->next)); print_benchs(f->child[1]); } @@ -700,6 +773,22 @@ static void signal_handler(int s) { } #endif +/* Compares a string with a wildcard pattern. */ +static int wildstrcmp(const char *str, const char *pattern) +{ + const char *wild = strchr(pattern, '*'); + if (wild) { + const size_t len = wild - pattern; + if (strncmp(str, pattern, len)) return 1; + while (*++wild == '*'); + if (!*wild) return 0; + str += len; + while (*str && wildstrcmp(str, wild)) str++; + return !*str; + } + return strcmp(str, pattern); +} + /* Perform tests and benchmarks for the specified cpu flag if supported by the host */ static void check_cpu_flag(const char *name, int flag) { @@ -715,7 +804,7 @@ static void check_cpu_flag(const char *name, int flag) state.cpu_flag_name = name; for (i = 0; tests[i].func; i++) { - if (state.test_name && strcmp(tests[i].name, state.test_name)) + if (state.test_pattern && wildstrcmp(tests[i].name, state.test_pattern)) continue; state.current_test_name = tests[i].name; tests[i].func(); @@ -742,9 +831,12 @@ static int bench_init_linux(void) .disabled = 1, // start counting only on demand .exclude_kernel = 1, .exclude_hv = 1, +#if !ARCH_X86 + .exclude_guest = 1, +#endif }; - printf("benchmarking with Linux Perf Monitoring API\n"); + fprintf(stderr, "benchmarking with Linux Perf Monitoring API\n"); state.sysfd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); if (state.sysfd == -1) { @@ -771,7 +863,7 @@ static int bench_init_ffmpeg(void) fprintf(stderr, "checkasm: unable to execute platform specific timer\n"); return -1; } - printf("benchmarking with native FFmpeg timers\n"); + fprintf(stderr, "benchmarking with native FFmpeg timers\n"); return 0; #else fprintf(stderr, "checkasm: --bench is not supported on your system\n"); @@ -793,22 +885,26 @@ static int bench_init(void) return ret; state.nop_time = measure_nop_time(); - printf("nop: %d.%d\n", state.nop_time/10, state.nop_time%10); + fprintf(stderr, "nop: %d.%d\n", state.nop_time/10, state.nop_time%10); return 0; } static void bench_uninit(void) { #if CONFIG_LINUX_PERF - if (state.sysfd > 0) - close(state.sysfd); + close(state.sysfd); #endif } static int usage(const char *path) { fprintf(stderr, - "Usage: %s [--bench] [--test=] [--verbose] [seed]\n", + "Usage: %s [options...] [seed]\n" + " --test= Run specific test.\n" + " --bench Run benchmark.\n" + " --csv, --tsv Output results in rows of comma or tab separated values.\n" + " --runs= Manual number of benchmark iterations to run 2**.\n" + " --verbose Increase verbosity.\n", path); return 1; } @@ -828,6 +924,9 @@ int main(int argc, char *argv[]) sigaction(SIGILL, &signal_handler_act, NULL); sigaction(SIGSEGV, &signal_handler_act, NULL); #endif +#if HAVE_PRCTL && defined(PR_SET_UNALIGN) + prctl(PR_SET_UNALIGN, PR_UNALIGN_SIGBUS); +#endif #if ARCH_ARM && HAVE_ARMV5TE_EXTERNAL if (have_vfp(av_get_cpu_flags()) || have_neon(av_get_cpu_flags())) checkasm_checked_call = checkasm_checked_call_vfp; @@ -850,11 +949,26 @@ int main(int argc, char *argv[]) state.bench_pattern = arg + 8; state.bench_pattern_len = strlen(state.bench_pattern); } else - state.bench_pattern = ""; + state.bench_pattern = "*"; } else if (!strncmp(arg, "--test=", 7)) { - state.test_name = arg + 7; + state.test_pattern = arg + 7; + } else if (!strcmp(arg, "--csv")) { + state.csv = 1; state.tsv = 0; + } else if (!strcmp(arg, "--tsv")) { + state.csv = 0; state.tsv = 1; } else if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { state.verbose = 1; + } else if (!strncmp(arg, "--runs=", 7)) { + l = strtoul(arg + 7, &end, 10); + if (*end == '\0') { + if (l > 30) { + fprintf(stderr, "checkasm: error: runs exponent must be within the range 0 <= 30\n"); + usage(argv[0]); + } + bench_runs = 1U << l; + } else { + return usage(argv[0]); + } } else if ((l = strtoul(arg, &end, 10)) <= UINT_MAX && *end == '\0') { seed = l; @@ -866,6 +980,9 @@ int main(int argc, char *argv[]) fprintf(stderr, "checkasm: using random seed %u\n", seed); av_lfg_init(&checkasm_lfg, seed); + if (state.bench_pattern) + fprintf(stderr, "checkasm: bench runs %" PRIu64 " (1 << %i)\n", bench_runs, av_log2(bench_runs)); + check_cpu_flag(NULL, 0); for (i = 0; cpus[i].flag; i++) check_cpu_flag(cpus[i].name, cpus[i].flag); @@ -938,7 +1055,7 @@ void *checkasm_check_func(void *func, const char *name, ...) int checkasm_bench_func(void) { return !state.num_failed && state.bench_pattern && - !strncmp(state.current_func->name, state.bench_pattern, state.bench_pattern_len); + !wildstrcmp(state.current_func->name, state.bench_pattern); } /* Indicate that the current test has failed */ diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h index f90920dee..866eef01e 100644 --- a/tests/checkasm/checkasm.h +++ b/tests/checkasm/checkasm.h @@ -85,11 +85,13 @@ void checkasm_check_blockdsp(void); void checkasm_check_bswapdsp(void); void checkasm_check_colorspace(void); void checkasm_check_exrdsp(void); +void checkasm_check_fdctdsp(void); void checkasm_check_fixed_dsp(void); void checkasm_check_flacdsp(void); void checkasm_check_float_dsp(void); void checkasm_check_fmtconvert(void); void checkasm_check_g722dsp(void); +void checkasm_check_h263dsp(void); void checkasm_check_h264chroma(void); void checkasm_check_h264dsp(void); void checkasm_check_h264pred(void); @@ -103,20 +105,26 @@ void checkasm_check_huffyuvdsp(void); void checkasm_check_idctdsp(void); void checkasm_check_jpeg2000dsp(void); void checkasm_check_llauddsp(void); +void checkasm_check_lls(void); void checkasm_check_llviddsp(void); void checkasm_check_llviddspenc(void); void checkasm_check_lpc(void); void checkasm_check_motion(void); +void checkasm_check_mpegvideoencdsp(void); void checkasm_check_nlmeans(void); void checkasm_check_opusdsp(void); void checkasm_check_pixblockdsp(void); void checkasm_check_sbrdsp(void); void checkasm_check_rv34dsp(void); +void checkasm_check_rv40dsp(void); void checkasm_check_svq1enc(void); void checkasm_check_synth_filter(void); void checkasm_check_sw_gbrp(void); +void checkasm_check_sw_range_convert(void); void checkasm_check_sw_rgb(void); void checkasm_check_sw_scale(void); +void checkasm_check_sw_yuv2rgb(void); +void checkasm_check_sw_yuv2yuv(void); void checkasm_check_takdsp(void); void checkasm_check_utvideodsp(void); void checkasm_check_v210dec(void); @@ -132,6 +140,7 @@ void checkasm_check_vp8dsp(void); void checkasm_check_vp9dsp(void); void checkasm_check_videodsp(void); void checkasm_check_vorbisdsp(void); +void checkasm_check_vvc_alf(void); void checkasm_check_vvc_mc(void); struct CheckasmPerf; @@ -164,7 +173,7 @@ extern AVLFG checkasm_lfg; static av_unused void *func_ref, *func_new; -#define BENCH_RUNS 1000 /* Trade-off between accuracy and speed */ +extern uint64_t bench_runs; /* Decide whether or not the specified function needs to be tested */ #define check_func(func, ...) (checkasm_save_context(), func_ref = checkasm_check_func((func_new = func), __VA_ARGS__)) @@ -333,10 +342,11 @@ typedef struct CheckasmPerf { av_unused const int sysfd = perf->sysfd;\ func_type *tfunc = func_new;\ uint64_t tsum = 0;\ - int ti, tcount = 0;\ + uint64_t ti, tcount = 0;\ uint64_t t = 0; \ + const uint64_t truns = bench_runs;\ checkasm_set_signal_handler_state(1);\ - for (ti = 0; ti < BENCH_RUNS; ti++) {\ + for (ti = 0; ti < truns; ti++) {\ PERF_START(t);\ tfunc(__VA_ARGS__);\ tfunc(__VA_ARGS__);\ diff --git a/tests/checkasm/fdctdsp.c b/tests/checkasm/fdctdsp.c new file mode 100644 index 000000000..c640a0065 --- /dev/null +++ b/tests/checkasm/fdctdsp.c @@ -0,0 +1,71 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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 "checkasm.h" + +#include "libavcodec/avcodec.h" +#include "libavcodec/fdctdsp.h" + +#include "libavutil/common.h" +#include "libavutil/internal.h" +#include "libavutil/mem_internal.h" + +static int int16_cmp_off_by_n(const int16_t *ref, const int16_t *test, size_t n, int accuracy) +{ + for (size_t i = 0; i < n; i++) { + if (abs(ref[i] - test[i]) > accuracy) + return 1; + } + return 0; +} + +static void check_fdct(void) +{ + LOCAL_ALIGNED_16(int16_t, block0, [64]); + LOCAL_ALIGNED_16(int16_t, block1, [64]); + + AVCodecContext avctx = { + .bits_per_raw_sample = 8, + .dct_algo = FF_DCT_AUTO, + }; + FDCTDSPContext h; + + ff_fdctdsp_init(&h, &avctx); + + if (check_func(h.fdct, "fdct")) { + declare_func(void, int16_t *); + for (int i = 0; i < 64; i++) { + uint8_t r = rnd(); + block0[i] = r; + block1[i] = r; + } + call_ref(block0); + call_new(block1); + if (int16_cmp_off_by_n(block0, block1, 64, 2)) + fail(); + bench_new(block1); + } +} + +void checkasm_check_fdctdsp(void) +{ + check_fdct(); + report("fdctdsp"); +} diff --git a/tests/checkasm/flacdsp.c b/tests/checkasm/flacdsp.c index b308237db..6f8e8817b 100644 --- a/tests/checkasm/flacdsp.c +++ b/tests/checkasm/flacdsp.c @@ -21,6 +21,7 @@ #include #include "checkasm.h" #include "libavcodec/flacdsp.h" +#include "libavcodec/mathops.h" #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -54,26 +55,101 @@ static void check_decorrelate(uint8_t **ref_dst, uint8_t **ref_src, uint8_t **ne bench_new(new_dst, (int32_t **)new_src, channels, BUF_SIZE / sizeof(int32_t), 8); } -static void check_lpc(int pred_order) +static void check_lpc(int pred_order, int bps) { int qlevel = rnd() % 16; + int coeff_prec = (rnd() % 15) + 1; LOCAL_ALIGNED_16(int32_t, coeffs, [32]); + LOCAL_ALIGNED_16(int32_t, dst, [BUF_SIZE]); LOCAL_ALIGNED_16(int32_t, dst0, [BUF_SIZE]); LOCAL_ALIGNED_16(int32_t, dst1, [BUF_SIZE]); declare_func(void, int32_t *, const int[32], int, int, int); - for (int i = 0; i < 32; i++) - coeffs[i] = rnd(); - for (int i = 0; i < BUF_SIZE; i++) - dst0[i] = rnd(); + if (bps <= 16) + coeff_prec = av_clip(coeff_prec, 0, 32 - bps - av_log2(pred_order)); - memcpy(dst1, dst0, BUF_SIZE * sizeof (int32_t)); + for (int i = 0; i < 32; i++) + coeffs[i] = sign_extend(rnd(), coeff_prec); + for (int i = 0; i < BUF_SIZE; i++) + dst[i] = sign_extend(rnd(), bps); + + memcpy(dst0, dst, BUF_SIZE * sizeof (int32_t)); + memcpy(dst1, dst, BUF_SIZE * sizeof (int32_t)); call_ref(dst0, coeffs, pred_order, qlevel, BUF_SIZE); call_new(dst1, coeffs, pred_order, qlevel, BUF_SIZE); if (memcmp(dst0, dst1, BUF_SIZE * sizeof (int32_t)) != 0) fail(); - bench_new(dst1, coeffs, pred_order, qlevel, BUF_SIZE); + bench_new(dst, coeffs, pred_order, qlevel, BUF_SIZE); +} + +static void check_lpc33(int pred_order) +{ + int qlevel = rnd() % 16; + int coeff_prec = (rnd() % 15) + 1; + LOCAL_ALIGNED_16(int64_t, dst, [BUF_SIZE]); + LOCAL_ALIGNED_16(int64_t, dst0, [BUF_SIZE]); + LOCAL_ALIGNED_16(int64_t, dst1, [BUF_SIZE]); + LOCAL_ALIGNED_16(int32_t, residuals, [BUF_SIZE]); + LOCAL_ALIGNED_16(int32_t, coeffs, [32]); + + declare_func(void, int64_t *, const int32_t *, const int[32], int, int, int); + + for (int i = 0; i < 32; i++) + coeffs[i] = sign_extend(rnd(), coeff_prec); + + for (int i = 0; i < BUF_SIZE; i++) { + residuals[i] = sign_extend(rnd(), pred_order); + dst[i] = sign_extend64(((int64_t)rnd() << 1) | (rnd() & 1), 33); + } + + memcpy(dst0, dst, BUF_SIZE * sizeof (int64_t)); + memcpy(dst1, dst, BUF_SIZE * sizeof (int64_t)); + call_ref(dst0, residuals, coeffs, pred_order, qlevel, BUF_SIZE); + call_new(dst1, residuals, coeffs, pred_order, qlevel, BUF_SIZE); + if (memcmp(dst0, dst1, BUF_SIZE * sizeof (int64_t)) != 0) + fail(); + bench_new(dst, residuals, coeffs, pred_order, qlevel, BUF_SIZE); +} + +static void check_wasted32(void) +{ + int wasted = rnd() % 32; + LOCAL_ALIGNED_16(int32_t, dst, [BUF_SIZE]); + LOCAL_ALIGNED_16(int32_t, dst0, [BUF_SIZE]); + LOCAL_ALIGNED_16(int32_t, dst1, [BUF_SIZE]); + + declare_func(void, int32_t *, int, int); + + for (int i = 0; i < BUF_SIZE; i++) + dst[i] = rnd(); + + memcpy(dst0, dst, BUF_SIZE * sizeof (int32_t)); + memcpy(dst1, dst, BUF_SIZE * sizeof (int32_t)); + call_ref(dst0, wasted, BUF_SIZE); + call_new(dst1, wasted, BUF_SIZE); + if (memcmp(dst0, dst1, BUF_SIZE * sizeof (int32_t)) != 0) + fail(); + bench_new(dst, wasted, BUF_SIZE); +} + +static void check_wasted33(void) +{ + int wasted = rnd() % 33; + LOCAL_ALIGNED_16(int64_t, dst0, [BUF_SIZE]); + LOCAL_ALIGNED_16(int64_t, dst1, [BUF_SIZE]); + LOCAL_ALIGNED_16(int32_t, residuals, [BUF_SIZE]); + + declare_func(void, int64_t *, const int32_t *, int, int); + + for (int i = 0; i < BUF_SIZE; i++) + residuals[i] = rnd(); + + call_ref(dst0, residuals, wasted, BUF_SIZE); + call_new(dst1, residuals, wasted, BUF_SIZE); + if (memcmp(dst0, dst1, BUF_SIZE * sizeof (int64_t)) != 0) + fail(); + bench_new(dst0, residuals, wasted, BUF_SIZE); } void checkasm_check_flacdsp(void) @@ -114,10 +190,20 @@ void checkasm_check_flacdsp(void) for (i = 0; i < FF_ARRAY_ELEMS(pred_orders); i++) if (check_func(h.lpc16, "flac_lpc_16_%d", pred_orders[i])) - check_lpc(pred_orders[i]); + check_lpc(pred_orders[i], 16); for (i = 0; i < FF_ARRAY_ELEMS(pred_orders); i++) if (check_func(h.lpc32, "flac_lpc_32_%d", pred_orders[i])) - check_lpc(pred_orders[i]); + check_lpc(pred_orders[i], 32); + for (i = 0; i < FF_ARRAY_ELEMS(pred_orders); i++) + if (check_func(h.lpc33, "flac_lpc_33_%d", pred_orders[i])) + check_lpc33(pred_orders[i]); report("lpc"); + + if (check_func(h.wasted32, "flac_wasted_32")) + check_wasted32(); + if (check_func(h.wasted33, "flac_wasted_33")) + check_wasted33(); + + report("wasted"); } diff --git a/tests/checkasm/float_dsp.c b/tests/checkasm/float_dsp.c index a025117b6..296db1cff 100644 --- a/tests/checkasm/float_dsp.c +++ b/tests/checkasm/float_dsp.c @@ -21,6 +21,7 @@ #include "libavutil/float_dsp.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "checkasm.h" @@ -277,6 +278,22 @@ static void test_scalarproduct_float(const float *src0, const float *src1) bench_new(src0, src1, LEN); } +static void test_scalarproduct_double(const double *src0, const double *src1) +{ + double cprod, oprod; + + declare_func_float(double, const double *, const double *, size_t); + + cprod = call_ref(src0, src1, LEN); + oprod = call_new(src0, src1, LEN); + if (!double_near_abs_eps(cprod, oprod, ARBITRARY_SCALARPRODUCT_CONST)) { + fprintf(stderr, "%- .12f - %- .12f = % .12g\n", + cprod, oprod, cprod - oprod); + fail(); + } + bench_new(src0, src1, LEN); +} + void checkasm_check_float_dsp(void) { LOCAL_ALIGNED_32(float, src0, [LEN]); @@ -333,6 +350,9 @@ void checkasm_check_float_dsp(void) if (check_func(fdsp->scalarproduct_float, "scalarproduct_float")) test_scalarproduct_float(src3, src4); report("scalarproduct_float"); + if (check_func(fdsp->scalarproduct_double, "scalarproduct_double")) + test_scalarproduct_double(dbl_src0, dbl_src1); + report("scalarproduct_double"); av_freep(&fdsp); } diff --git a/tests/checkasm/h263dsp.c b/tests/checkasm/h263dsp.c new file mode 100644 index 000000000..2d0957a90 --- /dev/null +++ b/tests/checkasm/h263dsp.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 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 General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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 "checkasm.h" + +#include "libavcodec/h263dsp.h" +#include "libavutil/mem.h" +#include "libavutil/mem_internal.h" + +typedef void (*filter)(uint8_t *src, int stride, int qscale); + +static void check_loop_filter(char dim, filter func) +{ + LOCAL_ALIGNED_16(uint8_t, buf0, [32 * 32]); + LOCAL_ALIGNED_16(uint8_t, buf1, [32 * 32]); + int qscale = rnd() % 32; + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *, int, int); + + for (size_t y = 0; y < 32; y++) + for (size_t x = 0; x < 32; x++) + buf0[y * 32 + x] = buf1[y * 32 + x] = rnd(); + + if (check_func(func, "h263dsp.%c_loop_filter", dim)) { + call_ref(buf0 + 8 * 33, 32, qscale); + call_new(buf1 + 8 * 33, 32, qscale); + + if (memcmp(buf0, buf1, 32 * 32)) + fail(); + + bench_new(buf1 + 8 * 33, 32, 1); + } +} + +void checkasm_check_h263dsp(void) +{ + H263DSPContext ctx; + + ff_h263dsp_init(&ctx); + check_loop_filter('h', ctx.h263_h_loop_filter); + check_loop_filter('v', ctx.h263_v_loop_filter); + report("loop_filter"); +} diff --git a/tests/checkasm/h264chroma.c b/tests/checkasm/h264chroma.c index 1aa28c2ee..9579fceab 100644 --- a/tests/checkasm/h264chroma.c +++ b/tests/checkasm/h264chroma.c @@ -53,23 +53,23 @@ static void check_chroma_mc(void) randomize_buffers(bit_depth); for (int size = 0; size < 4; size++) { -#define CHECK_CHROMA_MC(name) \ - do { \ - if (check_func(h.name## _pixels_tab[size], #name "_mc%d_%d", 1 << size, bit_depth)) { \ - for (int x = 0; x < 2; x++) { \ - for (int y = 0; y < 2; y++) { \ - memcpy(dst0, src, 16 * 18 * SIZEOF_PIXEL); \ - memcpy(dst1, src, 16 * 18 * SIZEOF_PIXEL); \ - call_ref(dst0, src, 16 * SIZEOF_PIXEL, 16, x, y); \ - call_new(dst1, src, 16 * SIZEOF_PIXEL, 16, x, y); \ - if (memcmp(dst0, dst1, 16 * 16 * SIZEOF_PIXEL)) { \ - fprintf(stderr, #name ": x:%i, y:%i\n", x, y); \ - fail(); \ - } \ - bench_new(dst1, src, 16 * SIZEOF_PIXEL, 16, x, y); \ - } \ - } \ - } \ +#define CHECK_CHROMA_MC(name) \ + do { \ + if (check_func(h.name## _pixels_tab[size], #name "_mc%d_%d", 1 << (3-size), bit_depth)) { \ + for (int x = 0; x < 2; x++) { \ + for (int y = 0; y < 2; y++) { \ + memcpy(dst0, src, 16 * 18 * SIZEOF_PIXEL); \ + memcpy(dst1, src, 16 * 18 * SIZEOF_PIXEL); \ + call_ref(dst0, src, 16 * SIZEOF_PIXEL, 16, x, y); \ + call_new(dst1, src, 16 * SIZEOF_PIXEL, 16, x, y); \ + if (memcmp(dst0, dst1, 16 * 16 * SIZEOF_PIXEL)) { \ + fprintf(stderr, #name ": x:%i, y:%i\n", x, y); \ + fail(); \ + } \ + bench_new(dst1, src, 16 * SIZEOF_PIXEL, 16, x, y); \ + } \ + } \ + } \ } while (0) CHECK_CHROMA_MC(put_h264_chroma); diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index 0f484e3f4..d1228ed98 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -27,17 +27,17 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mem_internal.h" -static const uint32_t pixel_mask[3] = { 0xffffffff, 0x01ff01ff, 0x03ff03ff }; +static const uint32_t pixel_mask[5] = { 0xffffffff, 0x01ff01ff, 0x03ff03ff, 0x0fff0fff, 0x3fff3fff }; static const uint32_t pixel_mask_lf[3] = { 0xff0fff0f, 0x01ff000f, 0x03ff000f }; #define SIZEOF_PIXEL ((bit_depth + 7) / 8) #define SIZEOF_COEF (2 * ((bit_depth + 7) / 8)) #define PIXEL_STRIDE 16 -#define randomize_buffers() \ +#define randomize_buffers(idx) \ do { \ int x, y; \ - uint32_t mask = pixel_mask[bit_depth - 8]; \ + uint32_t mask = pixel_mask[(idx)]; \ for (y = 0; y < sz; y++) { \ for (x = 0; x < PIXEL_STRIDE; x += 4) { \ AV_WN32A(src + y * PIXEL_STRIDE + x, rnd() & mask); \ @@ -83,7 +83,7 @@ static void dct4x4_##size(dctcoef *coef) \ } \ for (y = 0; y < 4; y++) { \ for (x = 0; x < 4; x++) { \ - static const int scale[] = { 13107 * 10, 8066 * 13, 5243 * 16 }; \ + const int64_t scale[] = { 13107 * 10, 8066 * 13, 5243 * 16 }; \ const int idx = (y & 1) + (x & 1); \ coef[y*4 + x] = (coef[y*4 + x] * scale[idx] + (1 << 14)) >> 15; \ } \ @@ -173,6 +173,7 @@ static void dct8x8(int16_t *coef, int bit_depth) static void check_idct(void) { + static const int depths[5] = { 8, 9, 10, 12, 14 }; LOCAL_ALIGNED_16(uint8_t, src, [8 * 8 * 2]); LOCAL_ALIGNED_16(uint8_t, dst, [8 * 8 * 2]); LOCAL_ALIGNED_16(uint8_t, dst0, [8 * 8 * 2]); @@ -181,28 +182,38 @@ static void check_idct(void) LOCAL_ALIGNED_16(int16_t, subcoef0, [8 * 8 * 2]); LOCAL_ALIGNED_16(int16_t, subcoef1, [8 * 8 * 2]); H264DSPContext h; - int bit_depth, sz, align, dc; + int bit_depth, sz, align, dc, i; declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, int16_t *block, int stride); - for (bit_depth = 8; bit_depth <= 10; bit_depth++) { + for (i = 0; i < FF_ARRAY_ELEMS(depths); i++) { + bit_depth = depths[i]; ff_h264dsp_init(&h, bit_depth, 1); - for (sz = 4; sz <= 8; sz += 4) { - randomize_buffers(); - if (sz == 4) - dct4x4(coef, bit_depth); - else - dct8x8(coef, bit_depth); - - for (dc = 0; dc <= 1; dc++) { + for (dc = 0; dc <= 2; dc++) { + for (sz = 4; sz <= 8; sz += 4) { void (*idct)(uint8_t *, int16_t *, int) = NULL; - switch ((sz << 1) | dc) { - case (4 << 1) | 0: idct = h.h264_idct_add; break; - case (4 << 1) | 1: idct = h.h264_idct_dc_add; break; - case (8 << 1) | 0: idct = h.h264_idct8_add; break; - case (8 << 1) | 1: idct = h.h264_idct8_dc_add; break; + const char fmts[3][28] = { + "h264_idct%d_add_%dbpp", "h264_idct%d_dc_add_%dbpp", + "h264_add_pixels%d_%dbpp", + }; + + randomize_buffers(i); + + if (sz == 4) + dct4x4(coef, bit_depth); + else + dct8x8(coef, bit_depth); + + switch ((sz << 2) | dc) { + case (4 << 2) | 0: idct = h.h264_idct_add; break; + case (4 << 2) | 1: idct = h.h264_idct_dc_add; break; + case (4 << 2) | 2: idct = h.h264_add_pixels4_clear; break; + case (8 << 2) | 0: idct = h.h264_idct8_add; break; + case (8 << 2) | 1: idct = h.h264_idct8_dc_add; break; + case (8 << 2) | 2: idct = h.h264_add_pixels8_clear; break; } - if (check_func(idct, "h264_idct%d_add%s_%dbpp", sz, dc ? "_dc" : "", bit_depth)) { + + if (check_func(idct, fmts[dc], sz, bit_depth)) { for (align = 0; align < 16; align += sz * SIZEOF_PIXEL) { uint8_t *dst1 = dst1_base + align; if (dc) { @@ -275,7 +286,7 @@ static void check_idct_multiple(void) int offset = (block_y * 16 + block_x) * SIZEOF_PIXEL; int nnz = rnd() % 3; - randomize_buffers(); + randomize_buffers(bit_depth - 8); if (sz == 4) dct4x4(coef, bit_depth); else @@ -360,7 +371,7 @@ static void check_loop_filter(void) tc0[j][0], tc0[j][1], tc0[j][2], tc0[j][3]); \ fail(); \ } \ - bench_new(dst1, 32, alphas[j], betas[j], tc0[j]); \ + bench_new(dst1 + off, 32, alphas[j], betas[j], tc0[j]);\ } \ } \ } while (0) @@ -419,7 +430,7 @@ static void check_loop_filter_intra(void) j, alphas[j], betas[j]); \ fail(); \ } \ - bench_new(dst1, 32, alphas[j], betas[j]); \ + bench_new(dst1 + off, 32, alphas[j], betas[j]); \ } \ } \ } while (0) diff --git a/tests/checkasm/hevc_add_res.c b/tests/checkasm/hevc_add_res.c index f35e9fccd..6388d5b12 100644 --- a/tests/checkasm/hevc_add_res.c +++ b/tests/checkasm/hevc_add_res.c @@ -23,7 +23,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mem_internal.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #include "checkasm.h" @@ -50,7 +50,7 @@ static void compare_add_res(int size, ptrdiff_t stride, int overflow_test, int m LOCAL_ALIGNED_32(uint8_t, dst0, [32 * 32 * 2]); LOCAL_ALIGNED_32(uint8_t, dst1, [32 * 32 * 2]); - declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, int16_t *res, ptrdiff_t stride); + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, const int16_t *res, ptrdiff_t stride); randomize_buffers(res0, size); randomize_buffers2(dst0, size, mask); diff --git a/tests/checkasm/hevc_deblock.c b/tests/checkasm/hevc_deblock.c index 04cf9d87a..89dd8a308 100644 --- a/tests/checkasm/hevc_deblock.c +++ b/tests/checkasm/hevc_deblock.c @@ -22,7 +22,7 @@ #include "libavutil/macros.h" #include "libavutil/mem_internal.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #include "checkasm.h" @@ -57,7 +57,8 @@ static void check_deblock_chroma(HEVCDSPContext *h, int bit_depth, int c) LOCAL_ALIGNED_32(uint8_t, buf0, [BUF_SIZE]); LOCAL_ALIGNED_32(uint8_t, buf1, [BUF_SIZE]); - declare_func(void, uint8_t *pix, ptrdiff_t stride, int32_t *tc, uint8_t *no_p, uint8_t *no_q); + declare_func(void, uint8_t *pix, ptrdiff_t stride, + const int32_t *tc, const uint8_t *no_p, const uint8_t *no_q); if (check_func(c ? h->hevc_h_loop_filter_chroma_c : h->hevc_h_loop_filter_chroma, "hevc_h_loop_filter_chroma%d%s", bit_depth, c ? "_full" : "")) @@ -226,7 +227,8 @@ static void check_deblock_luma(HEVCDSPContext *h, int bit_depth, int c) uint8_t *ptr0 = buf0 + BUF_OFFSET, *ptr1 = buf1 + BUF_OFFSET; - declare_func(void, uint8_t *pix, ptrdiff_t stride, int beta, int32_t *tc, uint8_t *no_p, uint8_t *no_q); + declare_func(void, uint8_t *pix, ptrdiff_t stride, int beta, + const int32_t *tc, const uint8_t *no_p, const uint8_t *no_q); memset(buf0, 0, BUF_SIZE); for (int j = 0; j < 3; j++) { diff --git a/tests/checkasm/hevc_idct.c b/tests/checkasm/hevc_idct.c index 9da8b858a..2bd7ae940 100644 --- a/tests/checkasm/hevc_idct.c +++ b/tests/checkasm/hevc_idct.c @@ -23,7 +23,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mem_internal.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #include "checkasm.h" diff --git a/tests/checkasm/hevc_pel.c b/tests/checkasm/hevc_pel.c index ed22ec4f9..d9fa56d42 100644 --- a/tests/checkasm/hevc_pel.c +++ b/tests/checkasm/hevc_pel.c @@ -21,7 +21,7 @@ #include #include "checkasm.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -88,7 +88,7 @@ static void checkasm_check_hevc_qpel(void) HEVCDSPContext h; int size, bit_depth, i, j; - declare_func(void, int16_t *dst, uint8_t *src, ptrdiff_t srcstride, + declare_func(void, int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width); for (bit_depth = 8; bit_depth <= 12; bit_depth++) { @@ -132,7 +132,7 @@ static void checkasm_check_hevc_qpel_uni(void) HEVCDSPContext h; int size, bit_depth, i, j; - declare_func(void, uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, + declare_func(void, uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width); for (bit_depth = 8; bit_depth <= 12; bit_depth++) { @@ -182,7 +182,7 @@ static void checkasm_check_hevc_qpel_uni_w(void) HEVCDSPContext h; int size, bit_depth, i, j; const int *denom, *wx, *ox; - declare_func(void, uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, + declare_func(void, 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); for (bit_depth = 8; bit_depth <= 12; bit_depth++) { @@ -239,8 +239,8 @@ static void checkasm_check_hevc_qpel_bi(void) HEVCDSPContext h; int size, bit_depth, i, j; - declare_func(void, uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, - int16_t *src2, + declare_func(void, 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); for (bit_depth = 8; bit_depth <= 12; bit_depth++) { @@ -292,8 +292,8 @@ static void checkasm_check_hevc_qpel_bi_w(void) HEVCDSPContext h; int size, bit_depth, i, j; const int *denom, *wx, *ox; - declare_func(void, uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, - int16_t *src2, + declare_func(void, 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); @@ -352,7 +352,7 @@ static void checkasm_check_hevc_epel(void) HEVCDSPContext h; int size, bit_depth, i, j; - declare_func(void, int16_t *dst, uint8_t *src, ptrdiff_t srcstride, + declare_func(void, int16_t *dst, const uint8_t *src, ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width); for (bit_depth = 8; bit_depth <= 12; bit_depth++) { @@ -396,7 +396,7 @@ static void checkasm_check_hevc_epel_uni(void) HEVCDSPContext h; int size, bit_depth, i, j; - declare_func(void, uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, + declare_func(void, uint8_t *dst, ptrdiff_t dststride, const uint8_t *src, ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width); for (bit_depth = 8; bit_depth <= 12; bit_depth++) { @@ -446,7 +446,7 @@ static void checkasm_check_hevc_epel_uni_w(void) HEVCDSPContext h; int size, bit_depth, i, j; const int *denom, *wx, *ox; - declare_func(void, uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, + declare_func(void, 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); for (bit_depth = 8; bit_depth <= 12; bit_depth++) { @@ -503,8 +503,8 @@ static void checkasm_check_hevc_epel_bi(void) HEVCDSPContext h; int size, bit_depth, i, j; - declare_func(void, uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, - int16_t *src2, + declare_func(void, 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); for (bit_depth = 8; bit_depth <= 12; bit_depth++) { @@ -556,8 +556,8 @@ static void checkasm_check_hevc_epel_bi_w(void) HEVCDSPContext h; int size, bit_depth, i, j; const int *denom, *wx, *ox; - declare_func(void, uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, - int16_t *src2, + declare_func(void, 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); diff --git a/tests/checkasm/hevc_sao.c b/tests/checkasm/hevc_sao.c index d05af9ac7..ad47423f1 100644 --- a/tests/checkasm/hevc_sao.c +++ b/tests/checkasm/hevc_sao.c @@ -23,7 +23,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mem_internal.h" -#include "libavcodec/hevcdsp.h" +#include "libavcodec/hevc/dsp.h" #include "checkasm.h" @@ -78,8 +78,8 @@ static void check_sao_band(HEVCDSPContext *h, int bit_depth) int block_size = sao_size[i]; int prev_size = i > 0 ? sao_size[i - 1] : 0; ptrdiff_t stride = PIXEL_STRIDE*SIZEOF_PIXEL; - declare_func(void, uint8_t *dst, uint8_t *src, ptrdiff_t dst_stride, ptrdiff_t src_stride, - int16_t *sao_offset_val, int sao_left_class, int width, int height); + declare_func(void, uint8_t *dst, const uint8_t *src, ptrdiff_t dst_stride, ptrdiff_t src_stride, + const int16_t *sao_offset_val, int sao_left_class, int width, int height); if (check_func(h->sao_band_filter[i], "hevc_sao_band_%d_%d", block_size, bit_depth)) { @@ -116,8 +116,8 @@ static void check_sao_edge(HEVCDSPContext *h, int bit_depth) int prev_size = i > 0 ? sao_size[i - 1] : 0; ptrdiff_t stride = PIXEL_STRIDE*SIZEOF_PIXEL; int offset = (AV_INPUT_BUFFER_PADDING_SIZE + PIXEL_STRIDE)*SIZEOF_PIXEL; - declare_func(void, uint8_t *dst, uint8_t *src, ptrdiff_t stride_dst, - int16_t *sao_offset_val, int eo, int width, int height); + declare_func(void, uint8_t *dst, const uint8_t *src, ptrdiff_t stride_dst, + const int16_t *sao_offset_val, int eo, int width, int height); for (int w = prev_size + 4; w <= block_size; w += 4) { randomize_buffers(src0, src1, BUF_SIZE); diff --git a/tests/checkasm/huffyuvdsp.c b/tests/checkasm/huffyuvdsp.c index a08f5a839..7491a8f14 100644 --- a/tests/checkasm/huffyuvdsp.c +++ b/tests/checkasm/huffyuvdsp.c @@ -42,7 +42,7 @@ static void check_add_int16(HuffYUVDSPContext *c, unsigned mask, int width, cons uint16_t *dst0 = av_mallocz(width * sizeof(uint16_t)); uint16_t *dst1 = av_mallocz(width * sizeof(uint16_t)); - declare_func(void, uint16_t *dst, uint16_t *src, unsigned mask, int w); + declare_func(void, uint16_t *dst, const uint16_t *src, unsigned mask, int w); if (!src0 || !src1 || !dst0 || !dst1) fail(); diff --git a/tests/checkasm/llauddsp.c b/tests/checkasm/llauddsp.c index e6eab589b..969166bac 100644 --- a/tests/checkasm/llauddsp.c +++ b/tests/checkasm/llauddsp.c @@ -49,7 +49,7 @@ static void check_scalarproduct_and_madd_int16(LLAudDSPContext *c) randomize_buf(v1, BUF_SIZE); randomize_buf(v2, BUF_SIZE); randomize_buf(v3, BUF_SIZE); - mul = rnd(); + mul = (int16_t)rnd(); if (check_func(c->scalarproduct_and_madd_int16, "scalarproduct_and_madd_int16")) { @@ -84,7 +84,7 @@ static void check_scalarproduct_and_madd_int32(LLAudDSPContext *c) randomize_buf(v1, BUF_SIZE); randomize_buf(v2, BUF_SIZE); randomize_buf(v3, BUF_SIZE); - mul = rnd(); + mul = (int16_t)rnd(); if (check_func(c->scalarproduct_and_madd_int32, "scalarproduct_and_madd_int32")) { diff --git a/tests/checkasm/lls.c b/tests/checkasm/lls.c new file mode 100644 index 000000000..4251032e0 --- /dev/null +++ b/tests/checkasm/lls.c @@ -0,0 +1,105 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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/lls.h" +#include "checkasm.h" + +#define randomize_buffer(buf) \ +do { \ + double bmg[2], stddev = 10.0; \ + \ + for (size_t i = 0; i < MAX_VARS_ALIGN; i += 2) { \ + av_bmg_get(&checkasm_lfg, bmg); \ + buf[i] = bmg[0] * stddev; \ + buf[i + 1] = bmg[1] * stddev; \ + } \ +} while(0); + +static void test_update(LLSModel *lls, const double *var) +{ + double refcovar[MAX_VARS][MAX_VARS]; + declare_func(void, LLSModel *, const double *); + + call_ref(lls, var); + + for (size_t i = 0; i < MAX_VARS; i++) + for (size_t j = 0; j < MAX_VARS; j++) + refcovar[i][j] = lls->covariance[i][j]; + + memset(lls->covariance, 0, sizeof (lls->covariance)); + call_new(lls, var); + + for (size_t i = 0; i < lls->indep_count; i++) + for (size_t j = i; j < lls->indep_count; j++) { + double eps = FFMAX(2 * DBL_EPSILON * fabs(refcovar[i][j]), + 8 * DBL_EPSILON); + if (!double_near_abs_eps(refcovar[i][j], lls->covariance[i][j], + eps)) { + fprintf(stderr, "%zu, %zu: %- .12f - %- .12f = % .12g\n", i, j, + refcovar[i][j], lls->covariance[i][j], + refcovar[i][j] - lls->covariance[i][j]); + fail(); + } + } + + bench_new(lls, var); +} + +static void test_evaluate(LLSModel *lls, const double *param, int order) +{ + double refprod, newprod, eps; + declare_func_float(double, LLSModel *, const double *, int); + + refprod = call_ref(lls, param, order); + newprod = call_new(lls, param, order); + + eps = FFMAX(2 * DBL_EPSILON * fabs(refprod), 0.2); + + if (!double_near_abs_eps(refprod, newprod, eps)) { + fprintf(stderr, "%- .12f - %- .12f = % .12g\n", + refprod, newprod, refprod - newprod); + fail(); + } + + if (order == lls->indep_count) + bench_new(lls, param, order); +} + +void checkasm_check_lls(void) +{ + static const unsigned char counts[] = { 8, 12, MAX_VARS, }; + + for (size_t i = 0; i < FF_ARRAY_ELEMS(counts); i++) { + LOCAL_ALIGNED_32(double, var, [MAX_VARS_ALIGN]); + LOCAL_ALIGNED_32(double, param, [FFALIGN(MAX_VARS+2,4)]); + LLSModel lls; + + avpriv_init_lls(&lls, counts[i]); + randomize_buffer(var); + randomize_buffer(param); + + if (check_func(lls.update_lls, "update_lls_%d", counts[i])) + test_update(&lls, var); + for (size_t j = 0; j <= i; j++) + if (check_func(lls.evaluate_lls, "evaluate_lls_%d_%d", counts[i], + counts[j])) + test_evaluate(&lls, param + 1, counts[j]); + } + report("lls"); +} diff --git a/tests/checkasm/llviddsp.c b/tests/checkasm/llviddsp.c index 00ad21a7c..9f8de65df 100644 --- a/tests/checkasm/llviddsp.c +++ b/tests/checkasm/llviddsp.c @@ -71,7 +71,7 @@ static void check_add_bytes(LLVidDSPContext *c, int width) } static void check_add_median_pred(LLVidDSPContext *c, int width) { - int A0, A1, B0, B1; + int a0, a1, b0, b1; uint8_t *dst0 = av_mallocz(width); uint8_t *dst1 = av_mallocz(width); uint8_t *src0 = av_calloc(width, sizeof(*src0)); @@ -85,18 +85,18 @@ static void check_add_median_pred(LLVidDSPContext *c, int width) { init_buffer(src0, src1, uint8_t, width); init_buffer(diff0, diff1, uint8_t, width); - A0 = rnd() & 0xFF; - B0 = rnd() & 0xFF; - A1 = A0; - B1 = B0; + a0 = rnd() & 0xFF; + b0 = rnd() & 0xFF; + a1 = a0; + b1 = b0; if (check_func(c->add_median_pred, "add_median_pred")) { - call_ref(dst0, src0, diff0, width, &A0, &B0); - call_new(dst1, src1, diff1, width, &A1, &B1); - if (memcmp(dst0, dst1, width) || (A0 != A1) || (B0 != B1)) + call_ref(dst0, src0, diff0, width, &a0, &b0); + call_new(dst1, src1, diff1, width, &a1, &b1); + if (memcmp(dst0, dst1, width) || (a0 != a1) || (b0 != b1)) fail(); - bench_new(dst1, src1, diff1, width, &A1, &B1); + bench_new(dst1, src1, diff1, width, &a1, &b1); } av_free(src0); @@ -114,7 +114,7 @@ static void check_add_left_pred(LLVidDSPContext *c, int width, int acc, const ch uint8_t *dst1 = av_mallocz(width); uint8_t *src0 = av_calloc(width, sizeof(*src0)); uint8_t *src1 = av_calloc(width, sizeof(*src1)); - declare_func(int, uint8_t *dst, uint8_t *src, ptrdiff_t w, int acc); + declare_func(int, uint8_t *dst, const uint8_t *src, ptrdiff_t w, int acc); init_buffer(src0, src1, uint8_t, width); @@ -143,7 +143,7 @@ static void check_add_left_pred_16(LLVidDSPContext *c, unsigned mask, int width, uint16_t *dst1 = av_calloc(width, sizeof(*dst1)); uint16_t *src0 = av_calloc(width, sizeof(*src0)); uint16_t *src1 = av_calloc(width, sizeof(*src1)); - declare_func(int, uint16_t *dst, uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); + declare_func(int, uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); init_buffer(src0, src1, uint16_t, width); diff --git a/tests/checkasm/lpc.c b/tests/checkasm/lpc.c index 592e34c03..514a2cdb3 100644 --- a/tests/checkasm/lpc.c +++ b/tests/checkasm/lpc.c @@ -16,6 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "libavutil/avassert.h" #include "libavutil/mem_internal.h" #include "libavcodec/lpc.h" @@ -54,13 +55,50 @@ static void test_window(int len) } } - bench_new(src, len, dst1); + bench_new(src, 4608 + (len & 1), dst1); +} + +static void test_compute_autocorr(ptrdiff_t len, int lag) +{ + const double eps = EPS * (double)len; + LOCAL_ALIGNED(32, double, src, [5000 + 2 + MAX_LPC_ORDER]); + LOCAL_ALIGNED(16, double, dst0, [MAX_LPC_ORDER + 1]); + LOCAL_ALIGNED(16, double, dst1, [MAX_LPC_ORDER + 1]); + + declare_func(void, const double *in, ptrdiff_t len, int lag, double *out); + + av_assert0(lag >= 0 && lag <= MAX_LPC_ORDER); + + for (int i = 0; i < MAX_LPC_ORDER; i++) + src[i] = 0.; + + src += MAX_LPC_ORDER; + + for (int i = 0; i < 5000 + 2; i++) { + src[i] = (double)rnd() / (double)UINT_MAX; + } + + call_ref(src, len, lag, dst0); + call_new(src, len, lag, dst1); + + for (size_t i = 0; i <= lag; i++) { + if (!double_near_abs_eps(dst0[i], dst1[i], eps)) { + fprintf(stderr, "%zu: %- .12f - %- .12f = % .12g\n", + i, dst0[i], dst1[i], dst0[i] - dst1[i]); + fail(); + break; + } + } + + bench_new(src, 4608 + (len & 1), lag, dst1); } void checkasm_check_lpc(void) { LPCContext ctx; - int len = rnd() % 5000; + int len = 2000 + rnd() % 3000; + static const int lags[] = { 8, 12, }; + ff_lpc_init(&ctx, 32, 16, FF_LPC_TYPE_DEFAULT); if (check_func(ctx.lpc_apply_welch_window, "apply_welch_window_even")) { @@ -72,6 +110,17 @@ void checkasm_check_lpc(void) test_window(len | 1); } report("apply_welch_window_odd"); - ff_lpc_end(&ctx); + + for (size_t i = 0; i < FF_ARRAY_ELEMS(lags); i++) { + ff_lpc_init(&ctx, len, lags[i], FF_LPC_TYPE_DEFAULT); + if (check_func(ctx.lpc_compute_autocorr, "autocorr_%d_even", lags[i])) + test_compute_autocorr(len & ~1, lags[i]); +#if !ARCH_X86 + if (check_func(ctx.lpc_compute_autocorr, "autocorr_%d_odd", lags[i])) + test_compute_autocorr(len | 1, lags[i]); +#endif + ff_lpc_end(&ctx); + } + report("compute_autocorr"); } diff --git a/tests/checkasm/motion.c b/tests/checkasm/motion.c index 71a0ee3fc..7e322da0d 100644 --- a/tests/checkasm/motion.c +++ b/tests/checkasm/motion.c @@ -52,8 +52,8 @@ static void test_motion(const char *name, me_cmp_func test_func) LOCAL_ALIGNED_16(uint8_t, img2, [WIDTH * HEIGHT]); declare_func_emms(AV_CPU_FLAG_MMX, int, struct MpegEncContext *c, - uint8_t *blk1 /* align width (8 or 16) */, - uint8_t *blk2 /* align 1 */, ptrdiff_t stride, + const uint8_t *blk1 /* align width (8 or 16) */, + const uint8_t *blk2 /* align 1 */, ptrdiff_t stride, int h); if (test_func == NULL) { @@ -94,12 +94,6 @@ static void test_motion(const char *name, me_cmp_func test_func) XX(vsad) \ XX(vsse) \ XX(nsse) \ - XX(me_pre_cmp) \ - XX(me_cmp) \ - XX(me_sub_cmp) \ - XX(mb_cmp) \ - XX(ildct_cmp) \ - XX(frame_skip_cmp) \ XX(median_sad) // tests for functions not yet implemented @@ -122,9 +116,6 @@ static void check_motion(void) AVCodecContext av_ctx = { .codec_id = AV_CODEC_ID_NONE, .flags = AV_CODEC_FLAG_BITEXACT }; MECmpContext me_ctx; - memset(&me_ctx, 0, sizeof(me_ctx)); - - ff_me_cmp_init(&me_ctx, &av_ctx); for (int i = 0; i < FF_ARRAY_ELEMS(me_ctx.pix_abs); i++) { diff --git a/tests/checkasm/mpegvideoencdsp.c b/tests/checkasm/mpegvideoencdsp.c new file mode 100644 index 000000000..24791d113 --- /dev/null +++ b/tests/checkasm/mpegvideoencdsp.c @@ -0,0 +1,147 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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.h" +#include "libavutil/mem_internal.h" + +#include "libavcodec/mpegvideoencdsp.h" + +#include "checkasm.h" + +#define randomize_buffers(buf, size) \ + do { \ + for (int j = 0; j < size; j += 4) \ + AV_WN32(buf + j, rnd()); \ + } while (0) + +static void check_pix_sum(MpegvideoEncDSPContext *c) +{ + LOCAL_ALIGNED_16(uint8_t, src, [16 * 16]); + + declare_func(int, const uint8_t *pix, ptrdiff_t line_size); + + randomize_buffers(src, 16 * 16); + + for (int n = 0; n < 2; n++) { + const char *negstride_str = n ? "_negstride" : ""; + if (check_func(c->pix_sum, "pix_sum%s", negstride_str)) { + int sum0, sum1; + const uint8_t *pix = src + (n ? (15 * 16) : 0); + ptrdiff_t line_size = 16 * (n ? -1 : 1); + sum0 = call_ref(pix, line_size); + sum1 = call_new(pix, line_size); + if (sum0 != sum1) + fail(); + bench_new(pix, line_size); + } + } +} + +static void check_pix_norm1(MpegvideoEncDSPContext *c) +{ + LOCAL_ALIGNED_16(uint8_t, src, [16 * 16]); + + declare_func(int, const uint8_t *pix, ptrdiff_t line_size); + + randomize_buffers(src, 16 * 16); + + for (int n = 0; n < 2; n++) { + const char *negstride_str = n ? "_negstride" : ""; + if (check_func(c->pix_norm1, "pix_norm1%s", negstride_str)) { + int sum0, sum1; + const uint8_t *pix = src + (n ? (15 * 16) : 0); + ptrdiff_t line_size = 16 * (n ? -1 : 1); + sum0 = call_ref(pix, line_size); + sum1 = call_new(pix, line_size); + if (sum0 != sum1) + fail(); + bench_new(pix, line_size); + } + } +} + +#define NUM_LINES 4 +#define MAX_LINE_SIZE 1920 +#define EDGE_WIDTH 16 +#define LINESIZE (EDGE_WIDTH + MAX_LINE_SIZE + EDGE_WIDTH) +#define BUFSIZE ((EDGE_WIDTH + NUM_LINES + EDGE_WIDTH) * LINESIZE) + +static void check_draw_edges(MpegvideoEncDSPContext *c) +{ + static const int input_sizes[] = {8, 128, 1080, MAX_LINE_SIZE, -MAX_LINE_SIZE}; + LOCAL_ALIGNED_16(uint8_t, buf0, [BUFSIZE]); + LOCAL_ALIGNED_16(uint8_t, buf1, [BUFSIZE]); + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *buf, ptrdiff_t wrap, int width, int height, + int w, int h, int sides); + + for (int isi = 0; isi < FF_ARRAY_ELEMS(input_sizes); isi++) { + int input_size = input_sizes[isi]; + int negstride = input_size < 0; + const char *negstride_str = negstride ? "_negstride" : ""; + int width = FFABS(input_size); + ptrdiff_t linesize = EDGE_WIDTH + width + EDGE_WIDTH; + /* calculate height based on specified width to use the entire buffer. */ + int height = (BUFSIZE / linesize) - (2 * EDGE_WIDTH); + uint8_t *dst0 = buf0 + EDGE_WIDTH * linesize + EDGE_WIDTH; + uint8_t *dst1 = buf1 + EDGE_WIDTH * linesize + EDGE_WIDTH; + + if (negstride) { + dst0 += (height - 1) * linesize; + dst1 += (height - 1) * linesize; + linesize *= -1; + } + + for (int shift = 0; shift < 3; shift++) { + int edge = EDGE_WIDTH >> shift; + if (check_func(c->draw_edges, "draw_edges_%d_%d_%d%s", width, height, edge, negstride_str)) { + randomize_buffers(buf0, BUFSIZE); + memcpy(buf1, buf0, BUFSIZE); + call_ref(dst0, linesize, width, height, edge, edge, EDGE_BOTTOM | EDGE_TOP); + call_new(dst1, linesize, width, height, edge, edge, EDGE_BOTTOM | EDGE_TOP); + if (memcmp(buf0, buf1, BUFSIZE)) + fail(); + bench_new(dst1, linesize, width, height, edge, edge, EDGE_BOTTOM | EDGE_TOP); + } + } + } +} + +#undef NUM_LINES +#undef MAX_LINE_SIZE +#undef EDGE_WIDTH +#undef LINESIZE +#undef BUFSIZE + +void checkasm_check_mpegvideoencdsp(void) +{ + AVCodecContext avctx = { + .bits_per_raw_sample = 8, + }; + MpegvideoEncDSPContext c = { 0 }; + + ff_mpegvideoencdsp_init(&c, &avctx); + + check_pix_sum(&c); + report("pix_sum"); + check_pix_norm1(&c); + report("pix_norm1"); + check_draw_edges(&c); + report("draw_edges"); +} diff --git a/tests/checkasm/opusdsp.c b/tests/checkasm/opusdsp.c index 34ee5a4ed..76fb97653 100644 --- a/tests/checkasm/opusdsp.c +++ b/tests/checkasm/opusdsp.c @@ -18,7 +18,8 @@ #include "libavutil/mem_internal.h" -#include "libavcodec/opusdsp.h" +#include "libavcodec/opus/dsp.h" +#include "libavcodec/opus/tab.h" #include "checkasm.h" @@ -69,17 +70,17 @@ static void test_deemphasis(void) LOCAL_ALIGNED(16, float, dst1, [FFALIGN(MAX_SIZE, 4)]); float coeff0 = (float)rnd() / (UINT_MAX >> 5) - 16.0f, coeff1 = coeff0; - declare_func_float(float, float *out, float *in, float coeff, int len); + declare_func_float(float, float *out, float *in, float coeff, const float *weights, int len); randomize_float(src, MAX_SIZE); - coeff0 = call_ref(dst0, src, coeff0, MAX_SIZE); - coeff1 = call_new(dst1, src, coeff1, MAX_SIZE); + coeff0 = call_ref(dst0, src, coeff0, ff_opus_deemph_weights, MAX_SIZE); + coeff1 = call_new(dst1, src, coeff1, ff_opus_deemph_weights, MAX_SIZE); if (!float_near_abs_eps(coeff0, coeff1, EPS) || !float_near_abs_eps_array(dst0, dst1, EPS, MAX_SIZE)) fail(); - bench_new(dst1, src, coeff1, MAX_SIZE); + bench_new(dst1, src, coeff1, ff_opus_deemph_weights, MAX_SIZE); } void checkasm_check_opusdsp(void) diff --git a/tests/checkasm/riscv/checkasm.S b/tests/checkasm/riscv/checkasm.S index 73ca85f34..c4b034ae2 100644 --- a/tests/checkasm/riscv/checkasm.S +++ b/tests/checkasm/riscv/checkasm.S @@ -49,6 +49,7 @@ saved_regs: .endr func checkasm_set_function + lpad 0 la.tls.ie t0, checked_func add t0, tp, t0 sd a0, (t0) @@ -56,6 +57,7 @@ func checkasm_set_function endfunc func checkasm_get_wrapper, v + lpad 0 addi sp, sp, -16 sd fp, (sp) sd ra, 8(sp) @@ -73,7 +75,10 @@ func checkasm_get_wrapper, v addi sp, sp, 16 ret + .option norvc + .align 2 2: /* <-- Entry point with the Vector extension --> */ + lpad 0 /* Clobber the vectors */ vsetvli t0, zero, e32, m8, ta, ma li t0, 0xdeadbeef @@ -84,12 +89,14 @@ func checkasm_get_wrapper, v /* Clobber the vector configuration */ li t0, 0 /* Vector length: zero */ - li t1, -1 << 31 /* Vector type: illegal */ - vsetvl zero, t0, t1 + li t2, -4 /* Vector type: illegal */ + vsetvl zero, t0, t2 csrwi vxrm, 3 /* Rounding mode: round-to-odd */ csrwi vxsat, 1 /* Saturation: encountered */ + .align 2 3: /* <-- Entry point without the Vector extension --> */ + lpad 0 /* Save RA, unallocatable and callee-saved registers */ la.tls.ie t0, saved_regs add t0, tp, t0 @@ -113,7 +120,7 @@ func checkasm_get_wrapper, v /* Clobber the saved and temporary registers */ .irp n, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 - .if (\n > 0 && \n < 7) + .if (\n > 1 && \n < 7) mv t\n, t0 .endif fmv.d.x ft\n, t0 @@ -124,9 +131,9 @@ func checkasm_get_wrapper, v /* Call the tested function */ la.tls.ie t0, checked_func add t0, tp, t0 - ld t1, (t0) + ld t3, (t0) sd zero, (t0) - jalr t1 + jalr t3 /* Check special register values */ la.tls.ie t0, saved_regs diff --git a/tests/checkasm/rv40dsp.c b/tests/checkasm/rv40dsp.c new file mode 100644 index 000000000..a1a873d43 --- /dev/null +++ b/tests/checkasm/rv40dsp.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 Institue 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 General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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 "checkasm.h" +#include "libavcodec/rv40dsp.c" +#include "libavutil/mem_internal.h" + +#define randomize_buffers() \ + do { \ + for (int i = 0; i < 16*18*2; i++) \ + src[i] = rnd() & 0x3; \ + } while (0) + +static void check_chroma_mc(void) +{ + RV34DSPContext h; + LOCAL_ALIGNED_32(uint8_t, src, [16 * 18 * 2]); + LOCAL_ALIGNED_32(uint8_t, dst0, [16 * 18 * 2]); + LOCAL_ALIGNED_32(uint8_t, dst1, [16 * 18 * 2]); + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, const uint8_t *src, + ptrdiff_t stride, int h, int x, int y); + + ff_rv40dsp_init(&h); + randomize_buffers(); + for (int size = 0; size < 2; size++) { + +#define CHECK_CHROMA_MC(name) \ + do { \ + if (check_func(h.name## _pixels_tab[size], #name "_mc%d", 1 << (3 - size))) { \ + for (int x = 0; x < 2; x++) { \ + for (int y = 0; y < 2; y++) { \ + memcpy(dst0, src, 16 * 18); \ + memcpy(dst1, src, 16 * 18); \ + call_ref(dst0, src, 16, 16, x, y); \ + call_new(dst1, src, 16, 16, x, y); \ + if (memcmp(dst0, dst1, 16 * 16)) { \ + fprintf(stderr, #name ": x:%i, y:%i\n", x, y); \ + fail(); \ + } \ + bench_new(dst1, src, 16, 16, x, y); \ + } \ + } \ + } \ + } while (0) + + CHECK_CHROMA_MC(put_chroma); + CHECK_CHROMA_MC(avg_chroma); + } +} + +void checkasm_check_rv40dsp(void) +{ + check_chroma_mc(); + report("chroma_mc"); +} diff --git a/tests/checkasm/svq1enc.c b/tests/checkasm/svq1enc.c index 1a6f53114..f9abdcbff 100644 --- a/tests/checkasm/svq1enc.c +++ b/tests/checkasm/svq1enc.c @@ -18,7 +18,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavcodec/svq1encdsp.h" @@ -26,11 +25,13 @@ #include "checkasm.h" #define BUF_SIZE 1024 +#define MIN_VAL (-255 - 5 * 127) +#define MAX_VAL ( 255 + 5 * 128) #define randomize(buf, len) \ do { \ for (int i = 0; i < len; i++) \ - buf[i] = ((rnd() % 65281) - 32641); \ + buf[i] = ((rnd() % (MAX_VAL - MIN_VAL + 1)) + MIN_VAL); \ } while (0) static void test_ssd_int8_vs_int16(SVQ1EncDSPContext *s) { diff --git a/tests/checkasm/sw_gbrp.c b/tests/checkasm/sw_gbrp.c index 848e5366a..d843730f3 100644 --- a/tests/checkasm/sw_gbrp.c +++ b/tests/checkasm/sw_gbrp.c @@ -76,7 +76,7 @@ static void check_output_yuv2gbrp(void) uint8_t *dst0[4]; uint8_t *dst1[4]; - declare_func(void, void *c, const int16_t *lumFilter, + declare_func(void, struct SwsContext *c, const int16_t *lumFilter, const int16_t **lumSrcx, int lumFilterSize, const int16_t *chrFilter, const int16_t **chrUSrcx, const int16_t **chrVSrcx, int chrFilterSize, @@ -135,12 +135,6 @@ static void check_output_yuv2gbrp(void) fail(); ctx->flags |= SWS_FULL_CHR_H_INT; - ctx->yuv2rgb_y_offset = rnd(); - ctx->yuv2rgb_y_coeff = rnd(); - ctx->yuv2rgb_v2r_coeff = rnd(); - ctx->yuv2rgb_v2g_coeff = rnd(); - ctx->yuv2rgb_u2g_coeff = rnd(); - ctx->yuv2rgb_u2b_coeff = rnd(); for (fmi = 0; fmi < FF_ARRAY_ELEMS(planar_fmts); fmi++) { for (fsi = 0; fsi < FILTER_SIZES; fsi++) { @@ -202,10 +196,11 @@ static void check_input_planar_rgb_to_y(void) #define LARGEST_INPUT_SIZE 512 #define INPUT_SIZES 6 static const int input_sizes[] = {8, 24, 128, 144, 256, 512}; - uint8_t *src[4]; + const uint8_t *src[4]; int32_t rgb2yuv[9] = {0}; - declare_func(void, uint8_t *dst, uint8_t *src[4], int w, int32_t *rgb2yuv); + declare_func(void, uint8_t *dst, const uint8_t *src[4], + int w, int32_t *rgb2yuv, void *opaque); LOCAL_ALIGNED_8(int32_t, src_r, [LARGEST_INPUT_SIZE]); LOCAL_ALIGNED_8(int32_t, src_g, [LARGEST_INPUT_SIZE]); @@ -243,13 +238,13 @@ static void check_input_planar_rgb_to_y(void) memset(dst0_y, 0xFF, LARGEST_INPUT_SIZE * sizeof(int32_t)); memset(dst1_y, 0xFF, LARGEST_INPUT_SIZE * sizeof(int32_t)); - call_ref(dst0_y, src, dstW, rgb2yuv); - call_new(dst1_y, src, dstW, rgb2yuv); + call_ref(dst0_y, src, dstW, rgb2yuv, NULL); + call_new(dst1_y, src, dstW, rgb2yuv, NULL); if (memcmp(dst0_y, dst1_y, dstW * byte_size)) fail(); - bench_new(dst1_y, src, dstW, rgb2yuv); + bench_new(dst1_y, src, dstW, rgb2yuv, NULL); } } @@ -269,11 +264,11 @@ static void check_input_planar_rgb_to_uv(void) #define LARGEST_INPUT_SIZE 512 #define INPUT_SIZES 6 static const int input_sizes[] = {8, 24, 128, 144, 256, 512}; - uint8_t *src[4]; + const uint8_t *src[4]; int32_t rgb2yuv[9] = {0}; declare_func(void, uint8_t *dstU, uint8_t *dstV, - uint8_t *src[4], int w, int32_t *rgb2yuv); + const uint8_t *src[4], int w, int32_t *rgb2yuv, void *opaque); LOCAL_ALIGNED_8(int32_t, src_r, [LARGEST_INPUT_SIZE]); LOCAL_ALIGNED_8(int32_t, src_g, [LARGEST_INPUT_SIZE]); @@ -316,14 +311,14 @@ static void check_input_planar_rgb_to_uv(void) memset(dst1_u, 0xFF, LARGEST_INPUT_SIZE * sizeof(int32_t)); memset(dst1_v, 0xFF, LARGEST_INPUT_SIZE * sizeof(int32_t)); - call_ref(dst0_u, dst0_v, src, dstW, rgb2yuv); - call_new(dst1_u, dst1_v, src, dstW, rgb2yuv); + call_ref(dst0_u, dst0_v, src, dstW, rgb2yuv, NULL); + call_new(dst1_u, dst1_v, src, dstW, rgb2yuv, NULL); if (memcmp(dst0_u, dst1_u, dstW * byte_size) || memcmp(dst0_v, dst1_v, dstW * byte_size)) fail(); - bench_new(dst1_u, dst1_v, src, dstW, rgb2yuv); + bench_new(dst1_u, dst1_v, src, dstW, rgb2yuv, NULL); } } } @@ -342,10 +337,11 @@ static void check_input_planar_rgb_to_a(void) #define LARGEST_INPUT_SIZE 512 #define INPUT_SIZES 6 static const int input_sizes[] = {8, 24, 128, 144, 256, 512}; - uint8_t *src[4]; + const uint8_t *src[4]; int32_t rgb2yuv[9] = {0}; - declare_func(void, uint8_t *dst, uint8_t *src[4], int w, int32_t *rgb2yuv); + declare_func(void, uint8_t *dst, const uint8_t *src[4], + int w, int32_t *rgb2yuv, void *opaque); LOCAL_ALIGNED_8(int32_t, src_r, [LARGEST_INPUT_SIZE]); LOCAL_ALIGNED_8(int32_t, src_g, [LARGEST_INPUT_SIZE]); @@ -386,12 +382,12 @@ static void check_input_planar_rgb_to_a(void) memset(dst0_a, 0x00, LARGEST_INPUT_SIZE * sizeof(int32_t)); memset(dst1_a, 0x00, LARGEST_INPUT_SIZE * sizeof(int32_t)); - call_ref(dst0_a, src, dstW, rgb2yuv); - call_new(dst1_a, src, dstW, rgb2yuv); + call_ref(dst0_a, src, dstW, rgb2yuv, NULL); + call_new(dst1_a, src, dstW, rgb2yuv, NULL); if (memcmp(dst0_a, dst1_a, dstW * byte_size)) fail(); - bench_new(dst1_a, src, dstW, rgb2yuv); + bench_new(dst1_a, src, dstW, rgb2yuv, NULL); } } } diff --git a/tests/checkasm/sw_range_convert.c b/tests/checkasm/sw_range_convert.c new file mode 100644 index 000000000..08029103d --- /dev/null +++ b/tests/checkasm/sw_range_convert.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 General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" +#include "libavutil/mem_internal.h" + +#include "libswscale/swscale.h" +#include "libswscale/swscale_internal.h" + +#include "checkasm.h" + +static void check_lumConvertRange(int from) +{ + const char *func_str = from ? "lumRangeFromJpeg" : "lumRangeToJpeg"; +#define LARGEST_INPUT_SIZE 512 +#define INPUT_SIZES 6 + static const int input_sizes[] = {8, 24, 128, 144, 256, 512}; + struct SwsContext *ctx; + + LOCAL_ALIGNED_32(int16_t, dst0, [LARGEST_INPUT_SIZE]); + LOCAL_ALIGNED_32(int16_t, dst1, [LARGEST_INPUT_SIZE]); + + declare_func(void, int16_t *dst, int width); + + ctx = sws_alloc_context(); + if (sws_init_context(ctx, NULL, NULL) < 0) + fail(); + + ctx->srcFormat = from ? AV_PIX_FMT_YUVJ444P : AV_PIX_FMT_YUV444P; + ctx->dstFormat = from ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; + ctx->srcRange = from; + ctx->dstRange = !from; + + for (int dstWi = 0; dstWi < INPUT_SIZES; dstWi++) { + int width = input_sizes[dstWi]; + for (int i = 0; i < width; i++) { + uint8_t r = rnd(); + dst0[i] = (int16_t) r << 7; + dst1[i] = (int16_t) r << 7; + } + ff_sws_init_scale(ctx); + if (check_func(ctx->lumConvertRange, "%s_%d", func_str, width)) { + call_ref(dst0, width); + call_new(dst1, width); + if (memcmp(dst0, dst1, width * sizeof(int16_t))) + fail(); + bench_new(dst1, width); + } + } + + sws_freeContext(ctx); +} +#undef LARGEST_INPUT_SIZE +#undef INPUT_SIZES + +static void check_chrConvertRange(int from) +{ + const char *func_str = from ? "chrRangeFromJpeg" : "chrRangeToJpeg"; +#define LARGEST_INPUT_SIZE 512 +#define INPUT_SIZES 6 + static const int input_sizes[] = {8, 24, 128, 144, 256, 512}; + struct SwsContext *ctx; + + LOCAL_ALIGNED_32(int16_t, dstU0, [LARGEST_INPUT_SIZE]); + LOCAL_ALIGNED_32(int16_t, dstV0, [LARGEST_INPUT_SIZE]); + LOCAL_ALIGNED_32(int16_t, dstU1, [LARGEST_INPUT_SIZE]); + LOCAL_ALIGNED_32(int16_t, dstV1, [LARGEST_INPUT_SIZE]); + + declare_func(void, int16_t *dstU, int16_t *dstV, int width); + + ctx = sws_alloc_context(); + if (sws_init_context(ctx, NULL, NULL) < 0) + fail(); + + ctx->srcFormat = from ? AV_PIX_FMT_YUVJ444P : AV_PIX_FMT_YUV444P; + ctx->dstFormat = from ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; + ctx->srcRange = from; + ctx->dstRange = !from; + + for (int dstWi = 0; dstWi < INPUT_SIZES; dstWi++) { + int width = input_sizes[dstWi]; + for (int i = 0; i < width; i++) { + uint8_t r = rnd(); + dstU0[i] = (int16_t) r << 7; + dstV0[i] = (int16_t) r << 7; + dstU1[i] = (int16_t) r << 7; + dstV1[i] = (int16_t) r << 7; + } + ff_sws_init_scale(ctx); + if (check_func(ctx->chrConvertRange, "%s_%d", func_str, width)) { + call_ref(dstU0, dstV0, width); + call_new(dstU1, dstV1, width); + if (memcmp(dstU0, dstU1, width * sizeof(int16_t)) || + memcmp(dstV0, dstV1, width * sizeof(int16_t))) + fail(); + bench_new(dstU1, dstV1, width); + } + } + + sws_freeContext(ctx); +} +#undef LARGEST_INPUT_SIZE +#undef INPUT_SIZES + +void checkasm_check_sw_range_convert(void) +{ + check_lumConvertRange(1); + report("lumRangeFromJpeg"); + check_chrConvertRange(1); + report("chrRangeFromJpeg"); + check_lumConvertRange(0); + report("lumRangeToJpeg"); + check_chrConvertRange(0); + report("chrRangeToJpeg"); +} diff --git a/tests/checkasm/sw_rgb.c b/tests/checkasm/sw_rgb.c index 7cd815e5b..af9434073 100644 --- a/tests/checkasm/sw_rgb.c +++ b/tests/checkasm/sw_rgb.c @@ -22,8 +22,11 @@ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "libavutil/mem_internal.h" +#include "libavutil/pixdesc.h" #include "libswscale/rgb2rgb.h" +#include "libswscale/swscale.h" +#include "libswscale/swscale_internal.h" #include "checkasm.h" @@ -50,7 +53,7 @@ static void check_shuffle_bytes(void * func, const char * report) LOCAL_ALIGNED_32(uint8_t, dst0, [MAX_STRIDE]); LOCAL_ALIGNED_32(uint8_t, dst1, [MAX_STRIDE]); - declare_func_emms(AV_CPU_FLAG_MMX, void, const uint8_t *src, uint8_t *dst, int src_size); + declare_func(void, const uint8_t *src, uint8_t *dst, int src_size); memset(dst0, 0, MAX_STRIDE); memset(dst1, 0, MAX_STRIDE); @@ -81,9 +84,9 @@ static void check_uyvy_to_422p(void) LOCAL_ALIGNED_32(uint8_t, dst_v_0, [(MAX_STRIDE/2) * MAX_HEIGHT]); LOCAL_ALIGNED_32(uint8_t, dst_v_1, [(MAX_STRIDE/2) * MAX_HEIGHT]); - declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, - const uint8_t *src, int width, int height, - int lumStride, int chromStride, int srcStride); + declare_func(void, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride); randomize_buffers(src0, MAX_STRIDE * MAX_HEIGHT * 2); memcpy(src1, src0, MAX_STRIDE * MAX_HEIGHT * 2); @@ -111,6 +114,92 @@ static void check_uyvy_to_422p(void) } } +#define NUM_LINES 5 +#define MAX_LINE_SIZE 1920 +#define BUFSIZE (NUM_LINES * MAX_LINE_SIZE) + +static int cmp_off_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy) +{ + for (size_t i = 0; i < n; i++) { + if (abs(ref[i] - test[i]) > accuracy) + return 1; + } + return 0; +} + +static void check_rgb24toyv12(struct SwsContext *ctx) +{ + static const int input_sizes[] = {16, 128, 512, MAX_LINE_SIZE, -MAX_LINE_SIZE}; + + LOCAL_ALIGNED_32(uint8_t, src, [BUFSIZE * 3]); + LOCAL_ALIGNED_32(uint8_t, buf_y_0, [BUFSIZE]); + LOCAL_ALIGNED_32(uint8_t, buf_y_1, [BUFSIZE]); + LOCAL_ALIGNED_32(uint8_t, buf_u_0, [BUFSIZE / 4]); + LOCAL_ALIGNED_32(uint8_t, buf_u_1, [BUFSIZE / 4]); + LOCAL_ALIGNED_32(uint8_t, buf_v_0, [BUFSIZE / 4]); + LOCAL_ALIGNED_32(uint8_t, buf_v_1, [BUFSIZE / 4]); + + declare_func(void, const uint8_t *src, uint8_t *ydst, uint8_t *udst, + uint8_t *vdst, int width, int height, int lumStride, + int chromStride, int srcStride, int32_t *rgb2yuv); + + randomize_buffers(src, BUFSIZE * 3); + + for (int isi = 0; isi < FF_ARRAY_ELEMS(input_sizes); isi++) { + int input_size = input_sizes[isi]; + int negstride = input_size < 0; + const char *negstride_str = negstride ? "_negstride" : ""; + int width = FFABS(input_size); + int linesize = width + 32; + /* calculate height based on specified width to use the entire buffer. */ + int height = (BUFSIZE / linesize) & ~1; + uint8_t *src0 = src; + uint8_t *src1 = src; + uint8_t *dst_y_0 = buf_y_0; + uint8_t *dst_y_1 = buf_y_1; + uint8_t *dst_u_0 = buf_u_0; + uint8_t *dst_u_1 = buf_u_1; + uint8_t *dst_v_0 = buf_v_0; + uint8_t *dst_v_1 = buf_v_1; + + if (negstride) { + src0 += (height - 1) * (linesize * 3); + src1 += (height - 1) * (linesize * 3); + dst_y_0 += (height - 1) * linesize; + dst_y_1 += (height - 1) * linesize; + dst_u_0 += ((height / 2) - 1) * (linesize / 2); + dst_u_1 += ((height / 2) - 1) * (linesize / 2); + dst_v_0 += ((height / 2) - 1) * (linesize / 2); + dst_v_1 += ((height / 2) - 1) * (linesize / 2); + linesize *= -1; + } + + if (check_func(ff_rgb24toyv12, "rgb24toyv12_%d_%d%s", width, height, negstride_str)) { + memset(buf_y_0, 0xFF, BUFSIZE); + memset(buf_y_1, 0xFF, BUFSIZE); + memset(buf_u_0, 0xFF, BUFSIZE / 4); + memset(buf_u_1, 0xFF, BUFSIZE / 4); + memset(buf_v_0, 0xFF, BUFSIZE / 4); + memset(buf_v_1, 0xFF, BUFSIZE / 4); + + call_ref(src0, dst_y_0, dst_u_0, dst_v_0, width, height, + linesize, linesize / 2, linesize * 3, ctx->input_rgb2yuv_table); + call_new(src1, dst_y_1, dst_u_1, dst_v_1, width, height, + linesize, linesize / 2, linesize * 3, ctx->input_rgb2yuv_table); + if (cmp_off_by_n(buf_y_0, buf_y_1, BUFSIZE, 1) || + cmp_off_by_n(buf_u_0, buf_u_1, BUFSIZE / 4, 1) || + cmp_off_by_n(buf_v_0, buf_v_1, BUFSIZE / 4, 1)) + fail(); + bench_new(src1, dst_y_1, dst_u_1, dst_v_1, width, height, + linesize, linesize / 2, linesize * 3, ctx->input_rgb2yuv_table); + } + } +} + +#undef NUM_LINES +#undef MAX_LINE_SIZE +#undef BUFSIZE + static void check_interleave_bytes(void) { LOCAL_ALIGNED_16(uint8_t, src0_buf, [MAX_STRIDE*MAX_HEIGHT+1]); @@ -124,8 +213,8 @@ static void check_interleave_bytes(void) uint8_t *dst0 = dst0_buf + 2; uint8_t *dst1 = dst1_buf + 2; - declare_func_emms(AV_CPU_FLAG_MMX, void, const uint8_t *, const uint8_t *, - uint8_t *, int, int, int, int, int); + declare_func(void, const uint8_t *, const uint8_t *, + uint8_t *, int, int, int, int, int); randomize_buffers(src0, MAX_STRIDE * MAX_HEIGHT); randomize_buffers(src1, MAX_STRIDE * MAX_HEIGHT); @@ -179,8 +268,190 @@ static void check_interleave_bytes(void) } } +static void check_deinterleave_bytes(void) +{ + LOCAL_ALIGNED_16(uint8_t, src_buf, [2*MAX_STRIDE*MAX_HEIGHT+2]); + LOCAL_ALIGNED_16(uint8_t, dst0_u_buf, [MAX_STRIDE*MAX_HEIGHT+1]); + LOCAL_ALIGNED_16(uint8_t, dst0_v_buf, [MAX_STRIDE*MAX_HEIGHT+1]); + LOCAL_ALIGNED_16(uint8_t, dst1_u_buf, [MAX_STRIDE*MAX_HEIGHT+1]); + LOCAL_ALIGNED_16(uint8_t, dst1_v_buf, [MAX_STRIDE*MAX_HEIGHT+1]); + // Intentionally using unaligned buffers, as this function doesn't have + // any alignment requirements. + uint8_t *src = src_buf + 2; + uint8_t *dst0_u = dst0_u_buf + 1; + uint8_t *dst0_v = dst0_v_buf + 1; + uint8_t *dst1_u = dst1_u_buf + 1; + uint8_t *dst1_v = dst1_v_buf + 1; + + declare_func(void, const uint8_t *src, uint8_t *dst1, uint8_t *dst2, + int width, int height, int srcStride, + int dst1Stride, int dst2Stride); + + randomize_buffers(src, 2*MAX_STRIDE*MAX_HEIGHT+2); + + if (check_func(deinterleaveBytes, "deinterleave_bytes")) { + for (int i = 0; i <= 16; i++) { + // Try all widths [1,16], and try one random width. + + int w = i > 0 ? i : (1 + (rnd() % (MAX_STRIDE-2))); + int h = 1 + (rnd() % (MAX_HEIGHT-2)); + + int src_offset = 0, src_stride = 2 * MAX_STRIDE; + int dst_u_offset = 0, dst_u_stride = MAX_STRIDE; + int dst_v_offset = 0, dst_v_stride = MAX_STRIDE; + + memset(dst0_u, 0, MAX_STRIDE * MAX_HEIGHT); + memset(dst0_v, 0, MAX_STRIDE * MAX_HEIGHT); + memset(dst1_u, 0, MAX_STRIDE * MAX_HEIGHT); + memset(dst1_v, 0, MAX_STRIDE * MAX_HEIGHT); + + // Try different combinations of negative strides + if (i & 1) { + src_offset = (h-1)*src_stride; + src_stride = -src_stride; + } + if (i & 2) { + dst_u_offset = (h-1)*dst_u_stride; + dst_u_stride = -dst_u_stride; + } + if (i & 4) { + dst_v_offset = (h-1)*dst_v_stride; + dst_v_stride = -dst_v_stride; + } + + call_ref(src + src_offset, dst0_u + dst_u_offset, dst0_v + dst_v_offset, + w, h, src_stride, dst_u_stride, dst_v_stride); + call_new(src + src_offset, dst1_u + dst_u_offset, dst1_v + dst_v_offset, + w, h, src_stride, dst_u_stride, dst_v_stride); + // Check a one pixel-pair edge around the destination area, + // to catch overwrites past the end. + checkasm_check(uint8_t, dst0_u, MAX_STRIDE, dst1_u, MAX_STRIDE, + w + 1, h + 1, "dst_u"); + checkasm_check(uint8_t, dst0_v, MAX_STRIDE, dst1_v, MAX_STRIDE, + w + 1, h + 1, "dst_v"); + } + + bench_new(src, dst1_u, dst1_v, 127, MAX_HEIGHT, + 2*MAX_STRIDE, MAX_STRIDE, MAX_STRIDE); + } + if (check_func(deinterleaveBytes, "deinterleave_bytes_aligned")) { + // Bench the function in a more typical case, with aligned + // buffers and widths. + bench_new(src_buf, dst1_u_buf, dst1_v_buf, 128, MAX_HEIGHT, + 2*MAX_STRIDE, MAX_STRIDE, MAX_STRIDE); + } +} + +#define MAX_LINE_SIZE 1920 +static const int input_sizes[] = {8, 128, 1080, MAX_LINE_SIZE}; +static const enum AVPixelFormat rgb_formats[] = { + AV_PIX_FMT_RGB24, + AV_PIX_FMT_BGR24, + AV_PIX_FMT_RGBA, + AV_PIX_FMT_BGRA, + AV_PIX_FMT_ABGR, + AV_PIX_FMT_ARGB, +}; + +static void check_rgb_to_y(struct SwsContext *ctx) +{ + LOCAL_ALIGNED_16(uint8_t, src24, [MAX_LINE_SIZE * 3]); + LOCAL_ALIGNED_16(uint8_t, src32, [MAX_LINE_SIZE * 4]); + LOCAL_ALIGNED_32(uint8_t, dst0_y, [MAX_LINE_SIZE * 2]); + LOCAL_ALIGNED_32(uint8_t, dst1_y, [MAX_LINE_SIZE * 2]); + + declare_func(void, uint8_t *dst, const uint8_t *src, + const uint8_t *unused1, const uint8_t *unused2, int width, + uint32_t *rgb2yuv, void *opq); + + randomize_buffers(src24, MAX_LINE_SIZE * 3); + randomize_buffers(src32, MAX_LINE_SIZE * 4); + + for (int i = 0; i < FF_ARRAY_ELEMS(rgb_formats); i++) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(rgb_formats[i]); + + ctx->srcFormat = rgb_formats[i]; + ff_sws_init_scale(ctx); + + for (int j = 0; j < FF_ARRAY_ELEMS(input_sizes); j++) { + int w = input_sizes[j]; + + if (check_func(ctx->lumToYV12, "%s_to_y_%d", desc->name, w)) { + const uint8_t *src = desc->nb_components == 3 ? src24 : src32; + memset(dst0_y, 0xFA, MAX_LINE_SIZE * 2); + memset(dst1_y, 0xFA, MAX_LINE_SIZE * 2); + + call_ref(dst0_y, src, NULL, NULL, w, ctx->input_rgb2yuv_table, NULL); + call_new(dst1_y, src, NULL, NULL, w, ctx->input_rgb2yuv_table, NULL); + + if (memcmp(dst0_y, dst1_y, w * 2)) + fail(); + + if (desc->nb_components == 3 || + // only bench native endian formats + (ctx->srcFormat == AV_PIX_FMT_RGB32 || ctx->srcFormat == AV_PIX_FMT_RGB32_1)) + bench_new(dst1_y, src, NULL, NULL, w, ctx->input_rgb2yuv_table, NULL); + } + } + } +} + +static void check_rgb_to_uv(struct SwsContext *ctx) +{ + LOCAL_ALIGNED_16(uint8_t, src24, [MAX_LINE_SIZE * 3]); + LOCAL_ALIGNED_16(uint8_t, src32, [MAX_LINE_SIZE * 4]); + LOCAL_ALIGNED_16(uint8_t, dst0_u, [MAX_LINE_SIZE * 2]); + LOCAL_ALIGNED_16(uint8_t, dst0_v, [MAX_LINE_SIZE * 2]); + LOCAL_ALIGNED_16(uint8_t, dst1_u, [MAX_LINE_SIZE * 2]); + LOCAL_ALIGNED_16(uint8_t, dst1_v, [MAX_LINE_SIZE * 2]); + + declare_func(void, uint8_t *dstU, uint8_t *dstV, + const uint8_t *src1, const uint8_t *src2, const uint8_t *src3, + int width, uint32_t *pal, void *opq); + + randomize_buffers(src24, MAX_LINE_SIZE * 3); + randomize_buffers(src32, MAX_LINE_SIZE * 4); + + for (int i = 0; i < 2 * FF_ARRAY_ELEMS(rgb_formats); i++) { + enum AVPixelFormat src_fmt = rgb_formats[i / 2]; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(src_fmt); + + ctx->chrSrcHSubSample = (i % 2) ? 0 : 1; + ctx->srcFormat = src_fmt; + ctx->dstFormat = ctx->chrSrcHSubSample ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUV444P; + ff_sws_init_scale(ctx); + + for (int j = 0; j < FF_ARRAY_ELEMS(input_sizes); j++) { + int w = input_sizes[j] >> ctx->chrSrcHSubSample; + + if (check_func(ctx->chrToYV12, "%s_to_uv%s_%d", desc->name, + ctx->chrSrcHSubSample ? "_half" : "", + input_sizes[j])) { + const uint8_t *src = desc->nb_components == 3 ? src24 : src32; + memset(dst0_u, 0xFF, MAX_LINE_SIZE * 2); + memset(dst0_v, 0xFF, MAX_LINE_SIZE * 2); + memset(dst1_u, 0xFF, MAX_LINE_SIZE * 2); + memset(dst1_v, 0xFF, MAX_LINE_SIZE * 2); + + call_ref(dst0_u, dst0_v, NULL, src, src, w, ctx->input_rgb2yuv_table, NULL); + call_new(dst1_u, dst1_v, NULL, src, src, w, ctx->input_rgb2yuv_table, NULL); + + if (memcmp(dst0_u, dst1_u, w * 2) || memcmp(dst0_v, dst1_v, w * 2)) + fail(); + + if (desc->nb_components == 3 || + // only bench native endian formats + (ctx->srcFormat == AV_PIX_FMT_RGB32 || ctx->srcFormat == AV_PIX_FMT_RGB32_1)) + bench_new(dst1_u, dst1_v, NULL, src, src, w, ctx->input_rgb2yuv_table, NULL); + } + } + } +} + void checkasm_check_sw_rgb(void) { + struct SwsContext *ctx; + ff_sws_rgb2rgb_init(); check_shuffle_bytes(shuffle_bytes_2103, "shuffle_bytes_2103"); @@ -203,4 +474,24 @@ void checkasm_check_sw_rgb(void) check_interleave_bytes(); report("interleave_bytes"); + + check_deinterleave_bytes(); + report("deinterleave_bytes"); + + ctx = sws_getContext(MAX_LINE_SIZE, MAX_LINE_SIZE, AV_PIX_FMT_RGB24, + MAX_LINE_SIZE, MAX_LINE_SIZE, AV_PIX_FMT_YUV420P, + SWS_ACCURATE_RND | SWS_BITEXACT, NULL, NULL, NULL); + if (!ctx) + fail(); + + check_rgb_to_y(ctx); + report("rgb_to_y"); + + check_rgb_to_uv(ctx); + report("rgb_to_uv"); + + check_rgb24toyv12(ctx); + report("rgb24toyv12"); + + sws_freeContext(ctx); } diff --git a/tests/checkasm/sw_scale.c b/tests/checkasm/sw_scale.c index 1305b3874..32a5d1c1a 100644 --- a/tests/checkasm/sw_scale.c +++ b/tests/checkasm/sw_scale.c @@ -21,6 +21,7 @@ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libswscale/swscale.h" diff --git a/tests/checkasm/sw_yuv2rgb.c b/tests/checkasm/sw_yuv2rgb.c new file mode 100644 index 000000000..5125f8396 --- /dev/null +++ b/tests/checkasm/sw_yuv2rgb.c @@ -0,0 +1,239 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixdesc.h" + +#include "libswscale/swscale.h" +#include "libswscale/swscale_internal.h" + +#include "checkasm.h" + +#define randomize_buffers(buf, size) \ + do { \ + for (int j = 0; j < size; j += 4) \ + AV_WN32(buf + j, rnd()); \ + } while (0) + +static const int dst_fmts[] = { +// AV_PIX_FMT_BGR48BE, +// AV_PIX_FMT_BGR48LE, +// AV_PIX_FMT_RGB48BE, +// AV_PIX_FMT_RGB48LE, + AV_PIX_FMT_ARGB, + AV_PIX_FMT_ABGR, + AV_PIX_FMT_RGBA, + AV_PIX_FMT_BGRA, + AV_PIX_FMT_RGB24, + AV_PIX_FMT_BGR24, + AV_PIX_FMT_RGB565, + AV_PIX_FMT_BGR565, + AV_PIX_FMT_RGB555, + AV_PIX_FMT_BGR555, +// AV_PIX_FMT_RGB444, +// AV_PIX_FMT_BGR444, +// AV_PIX_FMT_RGB8, +// AV_PIX_FMT_BGR8, +// AV_PIX_FMT_RGB4, +// AV_PIX_FMT_BGR4, +// AV_PIX_FMT_RGB4_BYTE, +// AV_PIX_FMT_BGR4_BYTE, +// AV_PIX_FMT_MONOBLACK, + AV_PIX_FMT_GBRP, +}; + +static int cmp_off_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy) +{ + for (size_t i = 0; i < n; i++) { + if (abs(ref[i] - test[i]) > accuracy) + return 1; + } + return 0; +} + +static int cmp_555_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy) +{ + const uint16_t *ref16 = (const uint16_t *) ref; + const uint16_t *test16 = (const uint16_t *) test; + for (size_t i = 0; i < n; i++) { + if (abs(( ref16[i] & 0x1f) - ( test16[i] & 0x1f)) > accuracy) + return 1; + if (abs(((ref16[i] >> 5) & 0x1f) - ((test16[i] >> 5) & 0x1f)) > accuracy) + return 1; + if (abs(((ref16[i] >> 10) & 0x1f) - ((test16[i] >> 10) & 0x1f)) > accuracy) + return 1; + } + return 0; +} + +static int cmp_565_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy) +{ + const uint16_t *ref16 = (const uint16_t *) ref; + const uint16_t *test16 = (const uint16_t *) test; + for (size_t i = 0; i < n; i++) { + if (abs(( ref16[i] & 0x1f) - ( test16[i] & 0x1f)) > accuracy) + return 1; + if (abs(((ref16[i] >> 5) & 0x3f) - ((test16[i] >> 5) & 0x3f)) > accuracy) + return 1; + if (abs(((ref16[i] >> 11) & 0x1f) - ((test16[i] >> 11) & 0x1f)) > accuracy) + return 1; + } + return 0; +} + +static void check_yuv2rgb(int src_pix_fmt) +{ + const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt); +#define MAX_LINE_SIZE 1920 + static const int input_sizes[] = {8, 128, 1080, MAX_LINE_SIZE}; + + declare_func_emms(AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMXEXT, + int, SwsContext *c, const uint8_t *src[], + int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]); + + LOCAL_ALIGNED_8(uint8_t, src_y, [MAX_LINE_SIZE * 2]); + LOCAL_ALIGNED_8(uint8_t, src_u, [MAX_LINE_SIZE]); + LOCAL_ALIGNED_8(uint8_t, src_v, [MAX_LINE_SIZE]); + LOCAL_ALIGNED_8(uint8_t, src_a, [MAX_LINE_SIZE * 2]); + const uint8_t *src[4] = { src_y, src_u, src_v, src_a }; + + LOCAL_ALIGNED_8(uint8_t, dst0_0, [2 * MAX_LINE_SIZE * 6]); + LOCAL_ALIGNED_8(uint8_t, dst0_1, [2 * MAX_LINE_SIZE]); + LOCAL_ALIGNED_8(uint8_t, dst0_2, [2 * MAX_LINE_SIZE]); + uint8_t *dst0[4] = { dst0_0, dst0_1, dst0_2 }; + uint8_t *lines0[4][2] = { + { dst0_0, dst0_0 + MAX_LINE_SIZE * 6 }, + { dst0_1, dst0_1 + MAX_LINE_SIZE }, + { dst0_2, dst0_2 + MAX_LINE_SIZE } + }; + + LOCAL_ALIGNED_8(uint8_t, dst1_0, [2 * MAX_LINE_SIZE * 6]); + LOCAL_ALIGNED_8(uint8_t, dst1_1, [2 * MAX_LINE_SIZE]); + LOCAL_ALIGNED_8(uint8_t, dst1_2, [2 * MAX_LINE_SIZE]); + uint8_t *dst1[4] = { dst1_0, dst1_1, dst1_2 }; + uint8_t *lines1[4][2] = { + { dst1_0, dst1_0 + MAX_LINE_SIZE * 6 }, + { dst1_1, dst1_1 + MAX_LINE_SIZE }, + { dst1_2, dst1_2 + MAX_LINE_SIZE } + }; + + randomize_buffers(src_y, MAX_LINE_SIZE * 2); + randomize_buffers(src_u, MAX_LINE_SIZE); + randomize_buffers(src_v, MAX_LINE_SIZE); + randomize_buffers(src_a, MAX_LINE_SIZE * 2); + + for (int dfi = 0; dfi < FF_ARRAY_ELEMS(dst_fmts); dfi++) { + int dst_pix_fmt = dst_fmts[dfi]; + const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt); + int sample_size = av_get_padded_bits_per_pixel(dst_desc) >> 3; + for (int isi = 0; isi < FF_ARRAY_ELEMS(input_sizes); isi++) { + struct SwsContext *ctx; + int log_level; + int width = input_sizes[isi]; + int srcSliceY = 0; + int srcSliceH = 2; + int srcStride[4] = { + width, + width >> src_desc->log2_chroma_w, + width >> src_desc->log2_chroma_w, + width, + }; + int dstStride[4] = { + MAX_LINE_SIZE * 6, + MAX_LINE_SIZE, + MAX_LINE_SIZE, + }; + + // override log level to prevent spamming of the message + // "No accelerated colorspace conversion found from %s to %s" + log_level = av_log_get_level(); + av_log_set_level(AV_LOG_ERROR); + ctx = sws_getContext(width, srcSliceH, src_pix_fmt, + width, srcSliceH, dst_pix_fmt, + 0, NULL, NULL, NULL); + av_log_set_level(log_level); + if (!ctx) + fail(); + + if (check_func(ctx->convert_unscaled, "%s_%s_%d", src_desc->name, dst_desc->name, width)) { + memset(dst0_0, 0xFF, 2 * MAX_LINE_SIZE * 6); + memset(dst1_0, 0xFF, 2 * MAX_LINE_SIZE * 6); + if (dst_pix_fmt == AV_PIX_FMT_GBRP) { + memset(dst0_1, 0xFF, MAX_LINE_SIZE); + memset(dst0_2, 0xFF, MAX_LINE_SIZE); + memset(dst1_1, 0xFF, MAX_LINE_SIZE); + memset(dst1_2, 0xFF, MAX_LINE_SIZE); + } + + call_ref(ctx, src, srcStride, srcSliceY, + srcSliceH, dst0, dstStride); + call_new(ctx, src, srcStride, srcSliceY, + srcSliceH, dst1, dstStride); + + if (dst_pix_fmt == AV_PIX_FMT_ARGB || + dst_pix_fmt == AV_PIX_FMT_ABGR || + dst_pix_fmt == AV_PIX_FMT_RGBA || + dst_pix_fmt == AV_PIX_FMT_BGRA || + dst_pix_fmt == AV_PIX_FMT_RGB24 || + dst_pix_fmt == AV_PIX_FMT_BGR24) { + if (cmp_off_by_n(lines0[0][0], lines1[0][0], width * sample_size, 3) || + cmp_off_by_n(lines0[0][1], lines1[0][1], width * sample_size, 3)) + fail(); + } else if (dst_pix_fmt == AV_PIX_FMT_RGB565 || + dst_pix_fmt == AV_PIX_FMT_BGR565) { + if (cmp_565_by_n(lines0[0][0], lines1[0][0], width, 2) || + cmp_565_by_n(lines0[0][1], lines1[0][1], width, 2)) + fail(); + } else if (dst_pix_fmt == AV_PIX_FMT_RGB555 || + dst_pix_fmt == AV_PIX_FMT_BGR555) { + if (cmp_555_by_n(lines0[0][0], lines1[0][0], width, 2) || + cmp_555_by_n(lines0[0][1], lines1[0][1], width, 2)) + fail(); + } else if (dst_pix_fmt == AV_PIX_FMT_GBRP) { + for (int p = 0; p < 3; p++) + for (int l = 0; l < 2; l++) + if (cmp_off_by_n(lines0[p][l], lines1[p][l], width, 3)) + fail(); + } else { + fail(); + } + + bench_new(ctx, src, srcStride, srcSliceY, + srcSliceH, dst0, dstStride); + } + sws_freeContext(ctx); + } + } +} + +#undef MAX_LINE_SIZE + +void checkasm_check_sw_yuv2rgb(void) +{ + check_yuv2rgb(AV_PIX_FMT_YUV420P); + report("yuv420p"); + check_yuv2rgb(AV_PIX_FMT_YUV422P); + report("yuv422p"); + check_yuv2rgb(AV_PIX_FMT_YUVA420P); + report("yuva420p"); +} diff --git a/tests/checkasm/sw_yuv2yuv.c b/tests/checkasm/sw_yuv2yuv.c new file mode 100644 index 000000000..90a51601e --- /dev/null +++ b/tests/checkasm/sw_yuv2yuv.c @@ -0,0 +1,133 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixdesc.h" + +#include "libswscale/swscale.h" +#include "libswscale/swscale_internal.h" + +#include "checkasm.h" + +#define randomize_buffers(buf, size) \ + do { \ + for (int j = 0; j < size; j += 4) \ + AV_WN32(buf + j, rnd()); \ + } while (0) + +static void check_semiplanar(int dst_pix_fmt) +{ + static const int src_fmts[] = { + AV_PIX_FMT_NV24, + AV_PIX_FMT_NV42, + }; + const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt); +#define NUM_LINES 4 +#define MAX_LINE_SIZE 1920 + static const int input_sizes[] = {8, 128, 1080, MAX_LINE_SIZE}; + + declare_func_emms(AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMXEXT, + int, SwsContext *c, const uint8_t *src[], + int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]); + + LOCAL_ALIGNED_8(uint8_t, src_y, [MAX_LINE_SIZE * NUM_LINES]); + LOCAL_ALIGNED_8(uint8_t, src_uv, [MAX_LINE_SIZE * NUM_LINES * 2]); + const uint8_t *src[4] = { src_y, src_uv }; + + LOCAL_ALIGNED_8(uint8_t, dst0_y, [MAX_LINE_SIZE * NUM_LINES]); + LOCAL_ALIGNED_8(uint8_t, dst0_u, [MAX_LINE_SIZE * NUM_LINES / 2]); + LOCAL_ALIGNED_8(uint8_t, dst0_v, [MAX_LINE_SIZE * NUM_LINES / 2]); + uint8_t *dst0[4] = { dst0_y, dst0_u, dst0_v }; + + LOCAL_ALIGNED_8(uint8_t, dst1_y, [MAX_LINE_SIZE * NUM_LINES]); + LOCAL_ALIGNED_8(uint8_t, dst1_u, [MAX_LINE_SIZE * NUM_LINES / 2]); + LOCAL_ALIGNED_8(uint8_t, dst1_v, [MAX_LINE_SIZE * NUM_LINES / 2]); + uint8_t *dst1[4] = { dst1_y, dst1_u, dst1_v }; + + randomize_buffers(src_y, MAX_LINE_SIZE * NUM_LINES); + randomize_buffers(src_uv, MAX_LINE_SIZE * NUM_LINES * 2); + + for (int sfi = 0; sfi < FF_ARRAY_ELEMS(src_fmts); sfi++) { + int src_pix_fmt = src_fmts[sfi]; + const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt); + for (int isi = 0; isi < FF_ARRAY_ELEMS(input_sizes); isi++) { + struct SwsContext *ctx; + int log_level; + int width = input_sizes[isi]; + int srcSliceY = 0; + int srcSliceH = NUM_LINES; + int srcStride[4] = { + MAX_LINE_SIZE, + MAX_LINE_SIZE * 2, + }; + int dstStride[4] = { + MAX_LINE_SIZE, + MAX_LINE_SIZE >> dst_desc->log2_chroma_w, + MAX_LINE_SIZE >> dst_desc->log2_chroma_w, + }; + + // override log level to prevent spamming of the message + // "No accelerated colorspace conversion found from %s to %s" + log_level = av_log_get_level(); + av_log_set_level(AV_LOG_ERROR); + ctx = sws_getContext(width, srcSliceH, src_pix_fmt, + width, srcSliceH, dst_pix_fmt, + 0, NULL, NULL, NULL); + av_log_set_level(log_level); + if (!ctx) + fail(); + + if (check_func(ctx->convert_unscaled, "%s_%s_%d", src_desc->name, dst_desc->name, width)) { + memset(dst0_y, 0xFF, MAX_LINE_SIZE * NUM_LINES); + memset(dst0_u, 0xFF, MAX_LINE_SIZE * NUM_LINES / 2); + memset(dst0_v, 0xFF, MAX_LINE_SIZE * NUM_LINES / 2); + memset(dst1_y, 0xFF, MAX_LINE_SIZE * NUM_LINES); + memset(dst1_u, 0xFF, MAX_LINE_SIZE * NUM_LINES / 2); + memset(dst1_v, 0xFF, MAX_LINE_SIZE * NUM_LINES / 2); + + call_ref(ctx, src, srcStride, srcSliceY, + srcSliceH, dst0, dstStride); + call_new(ctx, src, srcStride, srcSliceY, + srcSliceH, dst1, dstStride); + + if (memcmp(dst0_y, dst1_y, MAX_LINE_SIZE * NUM_LINES) || + memcmp(dst0_u, dst1_u, MAX_LINE_SIZE * NUM_LINES / 2) || + memcmp(dst0_v, dst1_v, MAX_LINE_SIZE * NUM_LINES / 2)) + fail(); + + bench_new(ctx, src, srcStride, srcSliceY, + srcSliceH, dst0, dstStride); + } + sws_freeContext(ctx); + } + } +} + +#undef NUM_LINES +#undef MAX_LINE_SIZE + +void checkasm_check_sw_yuv2yuv(void) +{ + check_semiplanar(AV_PIX_FMT_YUV420P); + report("yuv420p"); +} diff --git a/tests/checkasm/vc1dsp.c b/tests/checkasm/vc1dsp.c index 570785776..f18f0f825 100644 --- a/tests/checkasm/vc1dsp.c +++ b/tests/checkasm/vc1dsp.c @@ -27,6 +27,7 @@ #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #define VC1DSP_TEST(func) { #func, offsetof(VC1DSPContext, func) }, @@ -438,6 +439,40 @@ static void check_unescape(void) } } +static void check_mspel_pixels(void) +{ + LOCAL_ALIGNED_16(uint8_t, src0, [32 * 32]); + LOCAL_ALIGNED_16(uint8_t, src1, [32 * 32]); + LOCAL_ALIGNED_16(uint8_t, dst0, [32 * 32]); + LOCAL_ALIGNED_16(uint8_t, dst1, [32 * 32]); + + VC1DSPContext h; + + const test tests[] = { + VC1DSP_SIZED_TEST(put_vc1_mspel_pixels_tab[0][0], 16, 16) + VC1DSP_SIZED_TEST(put_vc1_mspel_pixels_tab[1][0], 8, 8) + VC1DSP_SIZED_TEST(avg_vc1_mspel_pixels_tab[0][0], 16, 16) + VC1DSP_SIZED_TEST(avg_vc1_mspel_pixels_tab[1][0], 8, 8) + }; + + ff_vc1dsp_init(&h); + + for (size_t t = 0; t < FF_ARRAY_ELEMS(tests); ++t) { + void (*func)(uint8_t *, const uint8_t*, ptrdiff_t, int) = *(void **)((intptr_t) &h + tests[t].offset); + if (check_func(func, "vc1dsp.%s", tests[t].name)) { + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *, const uint8_t*, ptrdiff_t, int); + RANDOMIZE_BUFFER8(dst, 32 * 32); + RANDOMIZE_BUFFER8(src, 32 * 32); + call_ref(dst0, src0, 32, 0); + call_new(dst1, src1, 32, 0); + if (memcmp(dst0, dst1, 32 * 32)) { + fail(); + } + bench_new(dst1, src0, 32, 0); + } + } +} + void checkasm_check_vc1dsp(void) { check_inv_trans_inplace(); @@ -449,4 +484,7 @@ void checkasm_check_vc1dsp(void) check_unescape(); report("unescape_buffer"); + + check_mspel_pixels(); + report("mspel_pixels"); } diff --git a/tests/checkasm/vf_blend.c b/tests/checkasm/vf_blend.c index 484ed0b1d..c387d3681 100644 --- a/tests/checkasm/vf_blend.c +++ b/tests/checkasm/vf_blend.c @@ -24,6 +24,7 @@ #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #define WIDTH 256 #define HEIGHT 256 @@ -67,7 +68,7 @@ const uint8_t *bottom, ptrdiff_t bottom_linesize, \ uint8_t *dst, ptrdiff_t dst_linesize, \ ptrdiff_t width, ptrdiff_t height, \ - struct FilterParams *param, double *values); \ + struct FilterParams *param, struct SliceParams *sliceparam); \ w = WIDTH / depth; \ \ for (i = 0; i < BUF_UNITS - 1; i++) { \ diff --git a/tests/checkasm/vf_bwdif.c b/tests/checkasm/vf_bwdif.c index fae61b62e..222e6aa4f 100644 --- a/tests/checkasm/vf_bwdif.c +++ b/tests/checkasm/vf_bwdif.c @@ -40,7 +40,7 @@ const int stride = WIDTH; \ const int mask = (1< #include #include "checkasm.h" +#include "libavutil/mem.h" #include "libavfilter/vf_gblur_init.h" #define WIDTH 256 diff --git a/tests/checkasm/vf_nlmeans.c b/tests/checkasm/vf_nlmeans.c index 0f1f9fd40..e61a2efae 100644 --- a/tests/checkasm/vf_nlmeans.c +++ b/tests/checkasm/vf_nlmeans.c @@ -21,6 +21,7 @@ #include "checkasm.h" #include "libavfilter/vf_nlmeans_init.h" #include "libavutil/avassert.h" +#include "libavutil/mem.h" #define randomize_buffer(buf, size) do { \ int i; \ diff --git a/tests/checkasm/vp8dsp.c b/tests/checkasm/vp8dsp.c index 4cd0f8ac4..e448fe89f 100644 --- a/tests/checkasm/vp8dsp.c +++ b/tests/checkasm/vp8dsp.c @@ -18,8 +18,10 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include +#include "config_components.h" #include "libavcodec/vp8dsp.h" #include "libavutil/common.h" @@ -108,7 +110,7 @@ static void wht4x4(int16_t *coef) } } -static void check_idct(void) +static void check_idct(VP8DSPContext *d, bool is_vp7) { LOCAL_ALIGNED_16(uint8_t, src, [4 * 4]); LOCAL_ALIGNED_16(uint8_t, dst, [4 * 4]); @@ -117,19 +119,17 @@ static void check_idct(void) LOCAL_ALIGNED_16(int16_t, coef, [4 * 4]); LOCAL_ALIGNED_16(int16_t, subcoef0, [4 * 4]); LOCAL_ALIGNED_16(int16_t, subcoef1, [4 * 4]); - VP8DSPContext d; int dc; declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, int16_t *block, ptrdiff_t stride); - ff_vp8dsp_init(&d); randomize_buffers(src, dst, 4, coef); dct4x4(coef); for (dc = 0; dc <= 1; dc++) { - void (*idct)(uint8_t *, int16_t *, ptrdiff_t) = dc ? d.vp8_idct_dc_add : d.vp8_idct_add; + void (*idct)(uint8_t *, int16_t *, ptrdiff_t) = dc ? d->vp8_idct_dc_add : d->vp8_idct_add; - if (check_func(idct, "vp8_idct_%sadd", dc ? "dc_" : "")) { + if (check_func(idct, "vp%d_idct_%sadd", 8 - is_vp7, dc ? "dc_" : "")) { if (dc) { memset(subcoef0, 0, 4 * 4 * sizeof(int16_t)); subcoef0[0] = coef[0]; @@ -153,7 +153,7 @@ static void check_idct(void) } } -static void check_idct_dc4(void) +static void check_idct_dc4(VP8DSPContext *d, bool is_vp7) { LOCAL_ALIGNED_16(uint8_t, src, [4 * 4 * 4]); LOCAL_ALIGNED_16(uint8_t, dst, [4 * 4 * 4]); @@ -162,15 +162,12 @@ static void check_idct_dc4(void) LOCAL_ALIGNED_16(int16_t, coef, [4], [4 * 4]); LOCAL_ALIGNED_16(int16_t, subcoef0, [4], [4 * 4]); LOCAL_ALIGNED_16(int16_t, subcoef1, [4], [4 * 4]); - VP8DSPContext d; int i, chroma; declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, int16_t block[4][16], ptrdiff_t stride); - ff_vp8dsp_init(&d); - for (chroma = 0; chroma <= 1; chroma++) { - void (*idct4dc)(uint8_t *, int16_t[4][16], ptrdiff_t) = chroma ? d.vp8_idct_dc_add4uv : d.vp8_idct_dc_add4y; - if (check_func(idct4dc, "vp8_idct_dc_add4%s", chroma ? "uv" : "y")) { + void (*idct4dc)(uint8_t *, int16_t[4][16], ptrdiff_t) = chroma ? d->vp8_idct_dc_add4uv : d->vp8_idct_dc_add4y; + if (check_func(idct4dc, "vp%d_idct_dc_add4%s", 8 - is_vp7, chroma ? "uv" : "y")) { ptrdiff_t stride = chroma ? 8 : 16; int w = chroma ? 2 : 4; for (i = 0; i < 4; i++) { @@ -196,7 +193,7 @@ static void check_idct_dc4(void) } -static void check_luma_dc_wht(void) +static void check_luma_dc_wht(VP8DSPContext *d, bool is_vp7) { LOCAL_ALIGNED_16(int16_t, dc, [4 * 4]); LOCAL_ALIGNED_16(int16_t, dc0, [4 * 4]); @@ -204,13 +201,10 @@ static void check_luma_dc_wht(void) int16_t block[4][4][16]; LOCAL_ALIGNED_16(int16_t, block0, [4], [4][16]); LOCAL_ALIGNED_16(int16_t, block1, [4], [4][16]); - VP8DSPContext d; int dc_only; int blockx, blocky; declare_func_emms(AV_CPU_FLAG_MMX, void, int16_t block[4][4][16], int16_t dc[16]); - ff_vp8dsp_init(&d); - for (blocky = 0; blocky < 4; blocky++) { for (blockx = 0; blockx < 4; blockx++) { uint8_t src[16], dst[16]; @@ -224,9 +218,9 @@ static void check_luma_dc_wht(void) wht4x4(dc); for (dc_only = 0; dc_only <= 1; dc_only++) { - void (*idct)(int16_t [4][4][16], int16_t [16]) = dc_only ? d.vp8_luma_dc_wht_dc : d.vp8_luma_dc_wht; + void (*idct)(int16_t [4][4][16], int16_t [16]) = dc_only ? d->vp8_luma_dc_wht_dc : d->vp8_luma_dc_wht; - if (check_func(idct, "vp8_luma_dc_wht%s", dc_only ? "_dc" : "")) { + if (check_func(idct, "vp%d_luma_dc_wht%s", 8 - is_vp7, dc_only ? "_dc" : "")) { if (dc_only) { memset(dc0, 0, 16 * sizeof(int16_t)); dc0[0] = dc[0]; @@ -262,19 +256,16 @@ static void check_luma_dc_wht(void) } \ } while (0) -static void check_mc(void) +static void check_mc(VP8DSPContext *d) { LOCAL_ALIGNED_16(uint8_t, buf, [32 * 32]); LOCAL_ALIGNED_16(uint8_t, dst0, [16 * 16]); LOCAL_ALIGNED_16(uint8_t, dst1, [16 * 16]); - VP8DSPContext d; int type, k, dx, dy; - declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *, ptrdiff_t, uint8_t *, ptrdiff_t, int, int, int); - - ff_vp78dsp_init(&d); + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *, ptrdiff_t, + const uint8_t *, ptrdiff_t, int, int, int); for (type = 0; type < 2; type++) { - vp8_mc_func (*tab)[3][3] = type ? d.put_vp8_bilinear_pixels_tab : d.put_vp8_epel_pixels_tab; for (k = 1; k < 8; k++) { int hsize = k / 3; int size = 16 >> hsize; @@ -282,6 +273,8 @@ static void check_mc(void) for (dy = 0; dy < 3; dy++) { for (dx = 0; dx < 3; dx++) { char str[100]; + vp8_mc_func func = (type ? d->put_vp8_bilinear_pixels_tab : d->put_vp8_epel_pixels_tab)[hsize][dy][dx]; + if (dx || dy) { if (type == 0) { static const char *dx_names[] = { "", "h4", "h6" }; @@ -293,7 +286,8 @@ static void check_mc(void) } else { snprintf(str, sizeof(str), "pixels%d", size); } - if (check_func(tab[hsize][dy][dx], "vp8_put_%s", str)) { + + if (check_func(func, "vp8_put_%s", str)) { int mx, my; int i; if (type == 0) { @@ -376,17 +370,14 @@ static void fill_loopfilter_buffers(uint8_t *buf, ptrdiff_t stride, int w, int h #define randomize_buffers(buf, lineoff, str, force_hev) \ randomize_loopfilter_buffers(lineoff, str, dir, flim_E, flim_I, hev_thresh, buf, force_hev) -static void check_loopfilter_16y(void) +static void check_loopfilter_16y(VP8DSPContext *d, bool is_vp7) { LOCAL_ALIGNED_16(uint8_t, base0, [32 + 16 * 16]); LOCAL_ALIGNED_16(uint8_t, base1, [32 + 16 * 16]); - VP8DSPContext d; int dir, edge, force_hev; int flim_E = 20, flim_I = 10, hev_thresh = 7; declare_func(void, uint8_t *, ptrdiff_t, int, int, int); - ff_vp8dsp_init(&d); - for (dir = 0; dir < 2; dir++) { int midoff = dir ? 4 * 16 : 4; int midoff_aligned = dir ? 4 * 16 : 16; @@ -395,12 +386,12 @@ static void check_loopfilter_16y(void) for (edge = 0; edge < 2; edge++) { void (*func)(uint8_t *, ptrdiff_t, int, int, int) = NULL; switch (dir << 1 | edge) { - case (0 << 1) | 0: func = d.vp8_h_loop_filter16y; break; - case (1 << 1) | 0: func = d.vp8_v_loop_filter16y; break; - case (0 << 1) | 1: func = d.vp8_h_loop_filter16y_inner; break; - case (1 << 1) | 1: func = d.vp8_v_loop_filter16y_inner; break; + case (0 << 1) | 0: func = d->vp8_h_loop_filter16y; break; + case (1 << 1) | 0: func = d->vp8_v_loop_filter16y; break; + case (0 << 1) | 1: func = d->vp8_h_loop_filter16y_inner; break; + case (1 << 1) | 1: func = d->vp8_v_loop_filter16y_inner; break; } - if (check_func(func, "vp8_loop_filter16y%s_%s", edge ? "_inner" : "", dir ? "v" : "h")) { + if (check_func(func, "vp%d_loop_filter16y%s_%s", 8 - is_vp7, edge ? "_inner" : "", dir ? "v" : "h")) { for (force_hev = -1; force_hev <= 1; force_hev++) { fill_loopfilter_buffers(buf0 - midoff, 16, 16, 16); randomize_buffers(buf0, 0, 16, force_hev); @@ -420,19 +411,16 @@ static void check_loopfilter_16y(void) } } -static void check_loopfilter_8uv(void) +static void check_loopfilter_8uv(VP8DSPContext *d, bool is_vp7) { LOCAL_ALIGNED_16(uint8_t, base0u, [32 + 16 * 16]); LOCAL_ALIGNED_16(uint8_t, base0v, [32 + 16 * 16]); LOCAL_ALIGNED_16(uint8_t, base1u, [32 + 16 * 16]); LOCAL_ALIGNED_16(uint8_t, base1v, [32 + 16 * 16]); - VP8DSPContext d; int dir, edge, force_hev; int flim_E = 20, flim_I = 10, hev_thresh = 7; declare_func(void, uint8_t *, uint8_t *, ptrdiff_t, int, int, int); - ff_vp8dsp_init(&d); - for (dir = 0; dir < 2; dir++) { int midoff = dir ? 4 * 16 : 4; int midoff_aligned = dir ? 4 * 16 : 16; @@ -443,12 +431,12 @@ static void check_loopfilter_8uv(void) for (edge = 0; edge < 2; edge++) { void (*func)(uint8_t *, uint8_t *, ptrdiff_t, int, int, int) = NULL; switch (dir << 1 | edge) { - case (0 << 1) | 0: func = d.vp8_h_loop_filter8uv; break; - case (1 << 1) | 0: func = d.vp8_v_loop_filter8uv; break; - case (0 << 1) | 1: func = d.vp8_h_loop_filter8uv_inner; break; - case (1 << 1) | 1: func = d.vp8_v_loop_filter8uv_inner; break; + case (0 << 1) | 0: func = d->vp8_h_loop_filter8uv; break; + case (1 << 1) | 0: func = d->vp8_v_loop_filter8uv; break; + case (0 << 1) | 1: func = d->vp8_h_loop_filter8uv_inner; break; + case (1 << 1) | 1: func = d->vp8_v_loop_filter8uv_inner; break; } - if (check_func(func, "vp8_loop_filter8uv%s_%s", edge ? "_inner" : "", dir ? "v" : "h")) { + if (check_func(func, "vp%d_loop_filter8uv%s_%s", 8 - is_vp7, edge ? "_inner" : "", dir ? "v" : "h")) { for (force_hev = -1; force_hev <= 1; force_hev++) { fill_loopfilter_buffers(buf0u - midoff, 16, 16, 16); fill_loopfilter_buffers(buf0v - midoff, 16, 16, 16); @@ -473,24 +461,21 @@ static void check_loopfilter_8uv(void) } } -static void check_loopfilter_simple(void) +static void check_loopfilter_simple(VP8DSPContext *d, bool is_vp7) { LOCAL_ALIGNED_16(uint8_t, base0, [32 + 16 * 16]); LOCAL_ALIGNED_16(uint8_t, base1, [32 + 16 * 16]); - VP8DSPContext d; int dir; int flim_E = 20, flim_I = 30, hev_thresh = 0; declare_func(void, uint8_t *, ptrdiff_t, int); - ff_vp8dsp_init(&d); - for (dir = 0; dir < 2; dir++) { int midoff = dir ? 4 * 16 : 4; int midoff_aligned = dir ? 4 * 16 : 16; uint8_t *buf0 = base0 + midoff_aligned; uint8_t *buf1 = base1 + midoff_aligned; - void (*func)(uint8_t *, ptrdiff_t, int) = dir ? d.vp8_v_loop_filter_simple : d.vp8_h_loop_filter_simple; - if (check_func(func, "vp8_loop_filter_simple_%s", dir ? "v" : "h")) { + void (*func)(uint8_t *, ptrdiff_t, int) = dir ? d->vp8_v_loop_filter_simple : d->vp8_h_loop_filter_simple; + if (check_func(func, "vp%d_loop_filter_simple_%s", 8 - is_vp7, dir ? "v" : "h")) { fill_loopfilter_buffers(buf0 - midoff, 16, 16, 16); randomize_buffers(buf0, 0, 16, -1); randomize_buffers(buf0, 8, 16, -1); @@ -504,16 +489,33 @@ static void check_loopfilter_simple(void) } } -void checkasm_check_vp8dsp(void) +static void checkasm_check_vp78dsp(VP8DSPContext *d, bool is_vp7) { - check_idct(); - check_idct_dc4(); - check_luma_dc_wht(); +#if CONFIG_VP7_DECODER + if (is_vp7) + ff_vp7dsp_init(d); + else +#endif + ff_vp8dsp_init(d); + check_idct(d, is_vp7); + check_idct_dc4(d, is_vp7); + check_luma_dc_wht(d, is_vp7); report("idct"); - check_mc(); - report("mc"); - check_loopfilter_16y(); - check_loopfilter_8uv(); - check_loopfilter_simple(); + check_loopfilter_16y(d, is_vp7); + check_loopfilter_8uv(d, is_vp7); + check_loopfilter_simple(d, is_vp7); report("loopfilter"); } + +void checkasm_check_vp8dsp(void) +{ + VP8DSPContext d; + + ff_vp78dsp_init(&d); + check_mc(&d); + report("mc"); + checkasm_check_vp78dsp(&d, false); +#if CONFIG_VP7_DECODER + checkasm_check_vp78dsp(&d, true); +#endif +} diff --git a/tests/checkasm/vvc_alf.c b/tests/checkasm/vvc_alf.c new file mode 100644 index 000000000..15e79289c --- /dev/null +++ b/tests/checkasm/vvc_alf.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2023-2024 Nuo Mi + * Copyright (c) 2023-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 General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General 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 "checkasm.h" +#include "libavcodec/vvc/ctu.h" +#include "libavcodec/vvc/data.h" +#include "libavcodec/vvc/dsp.h" + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem_internal.h" + +static const uint32_t pixel_mask[3] = { 0xffffffff, 0x03ff03ff, 0x0fff0fff }; + +#define SIZEOF_PIXEL ((bit_depth + 7) / 8) +#define SRC_PIXEL_STRIDE (MAX_CTU_SIZE + 2 * ALF_PADDING_SIZE) +#define DST_PIXEL_STRIDE (SRC_PIXEL_STRIDE + 4) +#define SRC_BUF_SIZE (SRC_PIXEL_STRIDE * (MAX_CTU_SIZE + 3 * 2) * 2) //+3 * 2 for top and bottom row, *2 for high bit depth +#define DST_BUF_SIZE (DST_PIXEL_STRIDE * (MAX_CTU_SIZE + 3 * 2) * 2) +#define LUMA_PARAMS_SIZE (MAX_CTU_SIZE * MAX_CTU_SIZE / ALF_BLOCK_SIZE / ALF_BLOCK_SIZE * ALF_NUM_COEFF_LUMA) + +#define randomize_buffers(buf0, buf1, size) \ + do { \ + uint32_t mask = pixel_mask[(bit_depth - 8) >> 1]; \ + int k; \ + for (k = 0; k < size; k += 4) { \ + uint32_t r = rnd() & mask; \ + AV_WN32A(buf0 + k, r); \ + AV_WN32A(buf1 + k, r); \ + } \ + } while (0) + +#define randomize_buffers2(buf, size, filter) \ + do { \ + int k; \ + if (filter) { \ + for (k = 0; k < size; k++) { \ + int8_t r = rnd(); \ + buf[k] = r; \ + } \ + } else { \ + for (k = 0; k < size; k++) { \ + int r = rnd() % FF_ARRAY_ELEMS(clip_set); \ + buf[k] = clip_set[r]; \ + } \ + } \ + } while (0) + +static int get_alf_vb_pos(const int h, const int vb_pos_above) +{ + if (h == MAX_CTU_SIZE) + return MAX_CTU_SIZE - vb_pos_above; + // If h < MAX_CTU_SIZE and picture virtual boundaries are involved, ALF virtual boundaries can either be within or outside this ALF block. + return ((rnd() & 1) ? h : MAX_CTU_SIZE) - vb_pos_above; +} + +static void check_alf_filter(VVCDSPContext *c, const int bit_depth) +{ + LOCAL_ALIGNED_32(uint8_t, dst0, [DST_BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, dst1, [DST_BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src0, [SRC_BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src1, [SRC_BUF_SIZE]); + int16_t filter[LUMA_PARAMS_SIZE]; + int16_t clip[LUMA_PARAMS_SIZE]; + + const int16_t clip_set[] = { + 1 << bit_depth, 1 << (bit_depth - 3), 1 << (bit_depth - 5), 1 << (bit_depth - 7) + }; + + ptrdiff_t src_stride = SRC_PIXEL_STRIDE * SIZEOF_PIXEL; + ptrdiff_t dst_stride = DST_PIXEL_STRIDE * SIZEOF_PIXEL; + int offset = (3 * SRC_PIXEL_STRIDE + 3) * SIZEOF_PIXEL; + + declare_func(void, 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); + + randomize_buffers(src0, src1, SRC_BUF_SIZE); + randomize_buffers2(filter, LUMA_PARAMS_SIZE, 1); + randomize_buffers2(clip, LUMA_PARAMS_SIZE, 0); + + for (int h = 4; h <= MAX_CTU_SIZE; h += 4) { + for (int w = 4; w <= MAX_CTU_SIZE; w += 4) { + //Both picture size and virtual boundaries are 8-aligned. For luma, we only need to check 8-aligned sizes. + if (!(w % 8) && !(h % 8)) { + if (check_func(c->alf.filter[LUMA], "vvc_alf_filter_luma_%dx%d_%d", w, h, bit_depth)) { + const int vb_pos = get_alf_vb_pos(h, ALF_VB_POS_ABOVE_LUMA); + memset(dst0, 0, DST_BUF_SIZE); + memset(dst1, 0, DST_BUF_SIZE); + call_ref(dst0, dst_stride, src0 + offset, src_stride, w, h, filter, clip, vb_pos); + call_new(dst1, dst_stride, src1 + offset, src_stride, w, h, filter, clip, vb_pos); + for (int i = 0; i < (h + 1); i++) { + if (memcmp(dst0 + i * dst_stride, dst1 + i * dst_stride, (w + 1) * SIZEOF_PIXEL)) + fail(); + } + // Bench only square sizes, and ones with dimensions being a power of two. + if (w == h && (w & (w - 1)) == 0) + bench_new(dst1, dst_stride, src1 + offset, src_stride, w, h, filter, clip, vb_pos); + } + } + //For chroma, once it exceeds 64, it's not a 4:2:0 format, so we only need to check 8-aligned sizes as well. + if ((w <= 64 || !(w % 8)) && (h <= 64 || !(h % 8))) { + if (check_func(c->alf.filter[CHROMA], "vvc_alf_filter_chroma_%dx%d_%d", w, h, bit_depth)) { + const int vb_pos = get_alf_vb_pos(h, ALF_VB_POS_ABOVE_CHROMA); + memset(dst0, 0, DST_BUF_SIZE); + memset(dst1, 0, DST_BUF_SIZE); + call_ref(dst0, dst_stride, src0 + offset, src_stride, w, h, filter, clip, vb_pos); + call_new(dst1, dst_stride, src1 + offset, src_stride, w, h, filter, clip, vb_pos); + for (int i = 0; i < (h + 1); i++) { + if (memcmp(dst0 + i * dst_stride, dst1 + i * dst_stride, (w + 1) * SIZEOF_PIXEL)) + fail(); + } + if (w == h && (w & (w - 1)) == 0) + bench_new(dst1, dst_stride, src1 + offset, src_stride, w, h, filter, clip, vb_pos); + } + } + } + } +} + +static void check_alf_classify(VVCDSPContext *c, const int bit_depth) +{ + LOCAL_ALIGNED_32(int, class_idx0, [SRC_BUF_SIZE]); + LOCAL_ALIGNED_32(int, transpose_idx0, [SRC_BUF_SIZE]); + LOCAL_ALIGNED_32(int, class_idx1, [SRC_BUF_SIZE]); + LOCAL_ALIGNED_32(int, transpose_idx1, [SRC_BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src0, [SRC_BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src1, [SRC_BUF_SIZE]); + LOCAL_ALIGNED_32(int32_t, alf_gradient_tmp, [ALF_GRADIENT_SIZE * ALF_GRADIENT_SIZE * ALF_NUM_DIR]); + + ptrdiff_t stride = SRC_PIXEL_STRIDE * SIZEOF_PIXEL; + int offset = (3 * SRC_PIXEL_STRIDE + 3) * SIZEOF_PIXEL; + + declare_func(void, int *class_idx, int *transpose_idx, + const uint8_t *src, ptrdiff_t src_stride, int width, int height, int vb_pos, int *gradient_tmp); + + randomize_buffers(src0, src1, SRC_BUF_SIZE); + + //Both picture size and virtual boundaries are 8-aligned. Classify is luma only, we only need to check 8-aligned sizes. + for (int h = 8; h <= MAX_CTU_SIZE; h += 8) { + for (int w = 8; w <= MAX_CTU_SIZE; w += 8) { + const int id_size = w * h / ALF_BLOCK_SIZE / ALF_BLOCK_SIZE * sizeof(int); + const int vb_pos = get_alf_vb_pos(h, ALF_VB_POS_ABOVE_LUMA); + if (check_func(c->alf.classify, "vvc_alf_classify_%dx%d_%d", w, h, bit_depth)) { + memset(class_idx0, 0, id_size); + memset(class_idx1, 0, id_size); + memset(transpose_idx0, 0, id_size); + memset(transpose_idx1, 0, id_size); + call_ref(class_idx0, transpose_idx0, src0 + offset, stride, w, h, vb_pos, alf_gradient_tmp); + + call_new(class_idx1, transpose_idx1, src1 + offset, stride, w, h, vb_pos, alf_gradient_tmp); + + if (memcmp(class_idx0, class_idx1, id_size)) + fail(); + if (memcmp(transpose_idx0, transpose_idx1, id_size)) + fail(); + // Bench only square sizes, and ones with dimensions being a power of two. + if (w == h && (w & (w - 1)) == 0) + bench_new(class_idx1, transpose_idx1, src1 + offset, stride, w, h, vb_pos, alf_gradient_tmp); + } + } + } +} + +void checkasm_check_vvc_alf(void) +{ + int bit_depth; + VVCDSPContext h; + for (bit_depth = 8; bit_depth <= 12; bit_depth += 2) { + ff_vvc_dsp_init(&h, bit_depth); + check_alf_filter(&h, bit_depth); + } + report("alf_filter"); + + for (bit_depth = 8; bit_depth <= 12; bit_depth += 2) { + ff_vvc_dsp_init(&h, bit_depth); + check_alf_classify(&h, bit_depth); + } + report("alf_classify"); +} diff --git a/tests/checkasm/vvc_mc.c b/tests/checkasm/vvc_mc.c index d102e2ac9..754cf1906 100644 --- a/tests/checkasm/vvc_mc.c +++ b/tests/checkasm/vvc_mc.c @@ -22,9 +22,9 @@ #include #include "checkasm.h" -#include "libavcodec/vvc/vvc_ctu.h" -#include "libavcodec/vvc/vvc_data.h" -#include "libavcodec/vvc/vvcdsp.h" +#include "libavcodec/vvc/ctu.h" +#include "libavcodec/vvc/data.h" +#include "libavcodec/vvc/dsp.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" @@ -45,7 +45,7 @@ static const int sizes[] = { 2, 4, 8, 16, 32, 64, 128 }; #define randomize_buffers(buf0, buf1, size, mask) \ do { \ int k; \ - for (k = 0; k < size; k += 4) { \ + for (k = 0; k < size; k += 4 / sizeof(*buf0)) { \ uint32_t r = rnd() & mask; \ AV_WN32A(buf0 + k, r); \ AV_WN32A(buf1 + k, r); \ @@ -64,6 +64,14 @@ static const int sizes[] = { 2, 4, 8, 16, 32, 64, 128 }; randomize_buffers(buf0, buf1, size, mask); \ } while (0) +#define randomize_prof_src(buf0, buf1, size) \ + do { \ + const int shift = 14 - bit_depth; \ + const int mask16 = 0x3fff >> shift << shift; \ + uint32_t mask = (mask16 << 16) | mask16; \ + randomize_buffers(buf0, buf1, size, mask); \ + } while (0) + static void check_put_vvc_luma(void) { LOCAL_ALIGNED_32(int16_t, dst0, [DST_BUF_SIZE / 2]); @@ -121,7 +129,8 @@ static void check_put_vvc_luma_uni(void) VVCDSPContext c; declare_func(void, uint8_t *dst, ptrdiff_t dststride, - uint8_t *src, ptrdiff_t srcstride, int height, const int8_t *hf, const int8_t *vf, int width); + const uint8_t *src, ptrdiff_t srcstride, int height, + const int8_t *hf, const int8_t *vf, int width); for (int bit_depth = 8; bit_depth <= 12; bit_depth += 2) { ff_vvc_dsp_init(&c, bit_depth); @@ -133,8 +142,8 @@ static void check_put_vvc_luma_uni(void) const int idx = av_log2(w) - 1; const int mx = rnd() % VVC_INTER_LUMA_FACTS; const int my = rnd() % VVC_INTER_LUMA_FACTS; - const int8_t *hf = ff_vvc_inter_luma_filters[rnd() % VVC_INTER_FILTER_TYPES][mx]; - const int8_t *vf = ff_vvc_inter_luma_filters[rnd() % VVC_INTER_FILTER_TYPES][my]; + const int8_t *hf = ff_vvc_inter_luma_filters[rnd() % VVC_INTER_LUMA_FILTER_TYPES][mx]; + const int8_t *vf = ff_vvc_inter_luma_filters[rnd() % VVC_INTER_LUMA_FILTER_TYPES][my]; const char *type; switch ((j << 1) | i) { @@ -183,8 +192,8 @@ static void check_put_vvc_chroma(void) const int idx = av_log2(w) - 1; const int mx = rnd() % VVC_INTER_CHROMA_FACTS; const int my = rnd() % VVC_INTER_CHROMA_FACTS; - const int8_t *hf = ff_vvc_inter_chroma_filters[rnd() % VVC_INTER_FILTER_TYPES][mx]; - const int8_t *vf = ff_vvc_inter_chroma_filters[rnd() % VVC_INTER_FILTER_TYPES][my]; + const int8_t *hf = ff_vvc_inter_chroma_filters[rnd() % VVC_INTER_CHROMA_FILTER_TYPES][mx]; + const int8_t *vf = ff_vvc_inter_chroma_filters[rnd() % VVC_INTER_CHROMA_FILTER_TYPES][my]; const char *type; switch ((j << 1) | i) { case 0: type = "put_chroma_pixels"; break; // 0 0 @@ -219,7 +228,8 @@ static void check_put_vvc_chroma_uni(void) VVCDSPContext c; declare_func(void, uint8_t *dst, ptrdiff_t dststride, - uint8_t *src, ptrdiff_t srcstride, int height, const int8_t *hf, const int8_t *vf, int width); + const uint8_t *src, ptrdiff_t srcstride, int height, + const int8_t *hf, const int8_t *vf, int width); for (int bit_depth = 8; bit_depth <= 12; bit_depth += 2) { ff_vvc_dsp_init(&c, bit_depth); @@ -231,8 +241,8 @@ static void check_put_vvc_chroma_uni(void) const int idx = av_log2(w) - 1; const int mx = rnd() % VVC_INTER_CHROMA_FACTS; const int my = rnd() % VVC_INTER_CHROMA_FACTS; - const int8_t *hf = ff_vvc_inter_chroma_filters[rnd() % VVC_INTER_FILTER_TYPES][mx]; - const int8_t *vf = ff_vvc_inter_chroma_filters[rnd() % VVC_INTER_FILTER_TYPES][my]; + const int8_t *hf = ff_vvc_inter_chroma_filters[rnd() % VVC_INTER_CHROMA_FILTER_TYPES][mx]; + const int8_t *vf = ff_vvc_inter_chroma_filters[rnd() % VVC_INTER_CHROMA_FILTER_TYPES][my]; const char *type; switch ((j << 1) | i) { @@ -322,8 +332,147 @@ static void check_avg(void) report("avg"); } +#define SR_RANGE 2 +static void check_dmvr(void) +{ + LOCAL_ALIGNED_32(uint16_t, dst0, [DST_BUF_SIZE]); + LOCAL_ALIGNED_32(uint16_t, dst1, [DST_BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src0, [SRC_BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src1, [SRC_BUF_SIZE]); + const int dst_stride = MAX_PB_SIZE * sizeof(int16_t); + + VVCDSPContext c; + declare_func(void, int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, int height, + intptr_t mx, intptr_t my, int width); + + for (int bit_depth = 8; bit_depth <= 12; bit_depth += 2) { + ff_vvc_dsp_init(&c, bit_depth); + randomize_pixels(src0, src1, SRC_BUF_SIZE); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int h = 8; h <= 16; h *= 2) { + for (int w = 8; w <= 16; w *= 2) { + const int pred_w = w + 2 * SR_RANGE; + const int pred_h = h + 2 * SR_RANGE; + const int mx = rnd() % VVC_INTER_LUMA_DMVR_FACTS; + const int my = rnd() % VVC_INTER_LUMA_DMVR_FACTS; + const char *type; + + if (w * h < 128) + continue; + + switch ((j << 1) | i) { + case 0: type = "dmvr"; break; // 0 0 + case 1: type = "dmvr_h"; break; // 0 1 + case 2: type = "dmvr_v"; break; // 1 0 + case 3: type = "dmvr_hv"; break; // 1 1 + } + + if (check_func(c.inter.dmvr[j][i], "%s_%d_%dx%d", type, bit_depth, pred_w, pred_h)) { + memset(dst0, 0, DST_BUF_SIZE); + memset(dst1, 0, DST_BUF_SIZE); + call_ref(dst0, src0 + SRC_OFFSET, PIXEL_STRIDE, pred_h, mx, my, pred_w); + call_new(dst1, src1 + SRC_OFFSET, PIXEL_STRIDE, pred_h, mx, my, pred_w); + for (int k = 0; k < pred_h; k++) { + if (memcmp(dst0 + k * dst_stride, dst1 + k * dst_stride, pred_w * sizeof(int16_t))) { + fail(); + break; + } + } + + bench_new(dst1, src1 + SRC_OFFSET, PIXEL_STRIDE, pred_h, mx, my, pred_w); + } + } + } + } + } + } + report("dmvr"); +} + +#define BDOF_BLOCK_SIZE 16 +#define BDOF_SRC_SIZE (MAX_PB_SIZE* (BDOF_BLOCK_SIZE + 2)) +#define BDOF_SRC_OFFSET (MAX_PB_SIZE + 1) +#define BDOF_DST_SIZE (BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE * 2) +static void check_bdof(void) +{ + LOCAL_ALIGNED_32(uint8_t, dst0, [BDOF_DST_SIZE]); + LOCAL_ALIGNED_32(uint8_t, dst1, [BDOF_DST_SIZE]); + LOCAL_ALIGNED_32(uint16_t, src00, [BDOF_SRC_SIZE]); + LOCAL_ALIGNED_32(uint16_t, src01, [BDOF_SRC_SIZE]); + LOCAL_ALIGNED_32(uint16_t, src10, [BDOF_SRC_SIZE]); + LOCAL_ALIGNED_32(uint16_t, src11, [BDOF_SRC_SIZE]); + + VVCDSPContext c; + declare_func(void, uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1, int block_w, int block_h); + + for (int bit_depth = 8; bit_depth <= 12; bit_depth += 2) { + const int dst_stride = BDOF_BLOCK_SIZE * SIZEOF_PIXEL; + + ff_vvc_dsp_init(&c, bit_depth); + randomize_prof_src(src00, src10, BDOF_SRC_SIZE); + randomize_prof_src(src01, src11, BDOF_SRC_SIZE); + for (int h = 8; h <= 16; h *= 2) { + for (int w = 8; w <= 16; w *= 2) { + if (w * h < 128) + continue; + if (check_func(c.inter.apply_bdof, "apply_bdof_%d_%dx%d", bit_depth, w, h)) { + memset(dst0, 0, BDOF_DST_SIZE); + memset(dst1, 0, BDOF_DST_SIZE); + call_ref(dst0, dst_stride, src00 + BDOF_SRC_OFFSET, src01 + BDOF_SRC_OFFSET, w, h); + call_new(dst1, dst_stride, src10 + BDOF_SRC_OFFSET, src11 + BDOF_SRC_OFFSET, w, h); + if (memcmp(dst0, dst1, BDOF_DST_SIZE)) + fail(); + bench_new(dst0, dst_stride, src00 + BDOF_SRC_OFFSET, src01 + BDOF_SRC_OFFSET, w, h); + } + } + } + } + report("apply_bdof"); +} + +static void check_vvc_sad(void) +{ + const int bit_depth = 10; + VVCDSPContext c; + LOCAL_ALIGNED_32(uint16_t, src0, [MAX_CTU_SIZE * MAX_CTU_SIZE * 4]); + LOCAL_ALIGNED_32(uint16_t, src1, [MAX_CTU_SIZE * MAX_CTU_SIZE * 4]); + declare_func(int, const int16_t *src0, const int16_t *src1, int dx, int dy, int block_w, int block_h); + + ff_vvc_dsp_init(&c, bit_depth); + randomize_pixels(src0, src1, MAX_CTU_SIZE * MAX_CTU_SIZE * 4); + for (int h = 8; h <= 16; h *= 2) { + for (int w = 8; w <= 16; w *= 2) { + for(int offy = 0; offy <= 4; offy++) { + for(int offx = 0; offx <= 4; offx++) { + if (w * h < 128) + continue; + + if (check_func(c.inter.sad, "sad_%dx%d", w, h)) { + int result0; + int result1; + + result0 = call_ref(src0 + PIXEL_STRIDE * 2 + 2, src1 + PIXEL_STRIDE * 2 + 2, offx, offy, w, h); + result1 = call_new(src0 + PIXEL_STRIDE * 2 + 2, src1 + PIXEL_STRIDE * 2 + 2, offx, offy, w, h); + + if (result1 != result0) + fail(); + if(offx == 0 && offy == 0) + bench_new(src0 + PIXEL_STRIDE * 2 + 2, src1 + PIXEL_STRIDE * 2 + 2, offx, offy, w, h); + } + } + } + } + } + + report("sad"); +} + void checkasm_check_vvc_mc(void) { + check_dmvr(); + check_bdof(); + check_vvc_sad(); check_put_vvc_luma(); check_put_vvc_luma_uni(); check_put_vvc_chroma(); diff --git a/tests/fate-run.sh b/tests/fate-run.sh index 9863e4f2d..309ab8513 100755 --- a/tests/fate-run.sh +++ b/tests/fate-run.sh @@ -1,4 +1,4 @@ -#! /bin/sh +#!/bin/sh export LC_ALL=C @@ -500,7 +500,7 @@ pixfmt_conversion(){ run_avconv $DEC_OPTS -r 1 -f image2 -c:v pgmyuv -i $raw_src \ $ENC_OPTS -f rawvideo -t 1 -s 352x288 -pix_fmt $conversion $target_path/$raw_dst || return do_avconv $file $DEC_OPTS -f rawvideo -s 352x288 -pix_fmt $conversion -i $target_path/$raw_dst \ - $ENC_OPTS -f rawvideo -s 352x288 -pix_fmt yuv444p + $ENC_OPTS -f rawvideo -s 352x288 -pix_fmt yuv444p -color_range mpeg } video_filter(){ diff --git a/tests/fate.sh b/tests/fate.sh index 07908be3a..4081e865a 100755 --- a/tests/fate.sh +++ b/tests/fate.sh @@ -1,4 +1,4 @@ -#! /bin/sh +#!/bin/sh config=$1 @@ -30,14 +30,14 @@ lock(){ checkout(){ case "$repo" in file:*|/*) src="${repo#file:}" ;; - git:*) git clone --quiet --branch "$branch" "$repo" "$src" ;; + git:*|https:*) git clone --quiet --branch "$branch" "$repo" "$src" ;; esac } update()( cd ${src} || return case "$repo" in - git:*) git fetch --quiet --force && git reset --quiet --hard "origin/$branch" ;; + git:*|https:*) git fetch --quiet --force && git reset --quiet --hard "origin/$branch" ;; esac ) diff --git a/tests/fate/aac.mak b/tests/fate/aac.mak index 817944773..ff58392ad 100644 --- a/tests/fate/aac.mak +++ b/tests/fate/aac.mak @@ -62,6 +62,14 @@ FATE_AAC += fate-aac-ap05_48 fate-aac-ap05_48: CMD = pcm -i $(TARGET_SAMPLES)/aac/ap05_48.mp4 fate-aac-ap05_48: REF = $(SAMPLES)/aac/ap05_48.s16 +FATE_AAC += fate-aac-fd_2_c1_ms_0x01 +fate-aac-fd_2_c1_ms_0x01: CMD = pcm -i $(TARGET_SAMPLES)/aac/Fd_2_c1_Ms_0x01.mp4 +fate-aac-fd_2_c1_ms_0x01: REF = $(SAMPLES)/aac/Fd_2_c1_Ms_0x01.s16 + +FATE_AAC += fate-aac-fd_2_c1_ms_0x04 +fate-aac-fd_2_c1_ms_0x04: CMD = pcm -i $(TARGET_SAMPLES)/aac/Fd_2_c1_Ms_0x04.mp4 +fate-aac-fd_2_c1_ms_0x04: REF = $(SAMPLES)/aac/Fd_2_c1_Ms_0x04.s16 + FATE_AAC += fate-aac-er_ad6000np_44_ep0 fate-aac-er_ad6000np_44_ep0: CMD = pcm -i $(TARGET_SAMPLES)/aac/er_ad6000np_44_ep0.mp4 fate-aac-er_ad6000np_44_ep0: REF = $(SAMPLES)/aac/er_ad6000np_44.s16 diff --git a/tests/fate/api.mak b/tests/fate/api.mak index 688fc0f9b..d2868e57a 100644 --- a/tests/fate/api.mak +++ b/tests/fate/api.mak @@ -16,7 +16,7 @@ FATE_API_SAMPLES_LIBAVFORMAT-$(call DEMDEC, H264, H264) += fate-api-h264-slice fate-api-h264-slice: $(APITESTSDIR)/api-h264-slice-test$(EXESUF) fate-api-h264-slice: CMD = run $(APITESTSDIR)/api-h264-slice-test$(EXESUF) 2 $(TARGET_SAMPLES)/h264/crew_cif.nal -FATE_API_LIBAVFORMAT-$(call DEMDEC, FLV, FLV) += fate-api-seek +FATE_API_LIBAVFORMAT-yes += $(if $(findstring fate-lavf-flv,$(FATE_LAVF_CONTAINER)),fate-api-seek) fate-api-seek: $(APITESTSDIR)/api-seek-test$(EXESUF) fate-lavf-flv fate-lavf-flv: KEEP_FILES ?= 1 fate-api-seek: CMD = run $(APITESTSDIR)/api-seek-test$(EXESUF) $(TARGET_PATH)/tests/data/lavf/lavf.flv 0 720 diff --git a/tests/fate/audio.mak b/tests/fate/audio.mak index cfac90424..6e091760e 100644 --- a/tests/fate/audio.mak +++ b/tests/fate/audio.mak @@ -82,11 +82,12 @@ fate-smacker-audio: CMD = framecrc -i $(TARGET_SAMPLES)/smacker/wetlogo.smk -vn FATE_SAMPLES_AUDIO-$(call DEMDEC, WSVQA, WS_SND1, ARESAMPLE_FILTER) += fate-ws_snd fate-ws_snd: CMD = md5 -i $(TARGET_SAMPLES)/vqa/ws_snd.vqa -f s16le -af aresample +FATE_SAMPLES_AUDIO_FFPROBE-$(call DEMDEC, WAV, WMAV2, FILE_PROTOCOL) += fate-flcl1905 fate-flcl1905: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_frames -show_packets -print_format compact $(TARGET_SAMPLES)/wav/FLCL_Ending_My-short.wav FATE_SAMPLES_AUDIO += $(FATE_SAMPLES_AUDIO-yes) - -FATE_SAMPLES_FFPROBE += fate-flcl1905 +FATE_SAMPLES_AUDIO_FFPROBE += $(FATE_SAMPLES_AUDIO_FFPROBE-yes) FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_AUDIO) -fate-audio: $(FATE_SAMPLES_AUDIO) fate-flcl1905 +FATE_SAMPLES_FFPROBE += $(FATE_SAMPLES_AUDIO_FFPROBE) +fate-audio: $(FATE_SAMPLES_AUDIO) $(FATE_SAMPLES_AUDIO_FFPROBE) diff --git a/tests/fate/cbs.mak b/tests/fate/cbs.mak index 802b0351a..dfd9e7d93 100644 --- a/tests/fate/cbs.mak +++ b/tests/fate/cbs.mak @@ -5,7 +5,7 @@ fate-cbs: fate-cbs-av1 fate-cbs-h264 fate-cbs-hevc fate-cbs-mpeg2 fate-cbs-vp9 fate-cbs-vvc FATE_CBS_DEPS = $(call ALLYES, $(1)_DEMUXER $(2)_PARSER $(3)_METADATA_BSF $(4)_DECODER $(5)_MUXER) -FATE_CBS_NO_DEC_DEPS = $(call ALLYES, $(1)_DEMUXER $(2)_PARSER $(3)_METADATA_BSF $(4)_MUXER) +FATE_CBS_NO_DEC_DEPS = $(call ALLYES, $(1)_DEMUXER $(1)_PARSER $(1)_METADATA_BSF $(1)_MUXER) define FATE_CBS_TEST # (codec, test_name, sample_file, output_format) @@ -88,7 +88,7 @@ FATE_CBS_DISCARD_TYPES = \ $(foreach N,$(FATE_CBS_DISCARD_TYPES),$(eval $(call FATE_CBS_DISCARD_TEST,h264,$(N),h264/interlaced_crop.mp4,h264))) -FATE_CBS_H264-$(call ALLYES, MOV_DEMUXER, H264_MUXER, H264_PARSER, FILTER_UNITS_BSF) += $(FATE_CBS_h264_DISCARD) +FATE_CBS_H264-$(call ALLYES, MOV_DEMUXER H264_MUXER H264_PARSER FILTER_UNITS_BSF H264_METADATA_BSF FILE_PROTOCOL) += $(FATE_CBS_h264_DISCARD) FATE_H264_REDUNDANT_PPS-$(call REMUX, H264, MOV_DEMUXER H264_REDUNDANT_PPS_BSF \ @@ -159,7 +159,7 @@ FATE_CBS_HEVC-$(call FATE_CBS_DEPS, HEVC, HEVC, HEVC, HEVC, HEVC) = $(FATE_CBS_h $(foreach N,$(FATE_CBS_DISCARD_TYPES),$(eval $(call FATE_CBS_DISCARD_TEST,hevc,$(N),hevc-conformance/WPP_A_ericsson_MAIN10_2.bit,hevc))) -FATE_CBS_HEVC-$(call ALLYES, HEVC_DEMUXER, HEVC_MUXER, HEVC_PARSER, FILTER_UNITS_BSF) += $(FATE_CBS_hevc_DISCARD) +FATE_CBS_HEVC-$(call ALLYES, HEVC_DEMUXER HEVC_MUXER HEVC_PARSER FILTER_UNITS_BSF HEVC_METADATA_BSF FILE_PROTOCOL) += $(FATE_CBS_hevc_DISCARD) FATE_SAMPLES_AVCONV += $(FATE_CBS_HEVC-yes) fate-cbs-hevc: $(FATE_CBS_HEVC-yes) @@ -197,7 +197,7 @@ FATE_CBS_VVC_SAMPLES = \ $(foreach N,$(FATE_CBS_VVC_SAMPLES),$(eval $(call FATE_CBS_NO_DEC_TEST,vvc,$(basename $(N)),vvc-conformance/$(N),vvc))) -FATE_CBS_VVC-$(call FATE_CBS_NO_DEC_DEPS, HEVC, HEVC, HEVC, HEVC) = $(FATE_CBS_vvc) +FATE_CBS_VVC-$(call FATE_CBS_NO_DEC_DEPS, VVC) = $(FATE_CBS_vvc) FATE_SAMPLES_AVCONV += $(FATE_CBS_VVC-yes) fate-cbs-vvc: $(FATE_CBS_VVC-yes) diff --git a/tests/fate/checkasm.mak b/tests/fate/checkasm.mak index 3b5b867a9..d1396cb64 100644 --- a/tests/fate/checkasm.mak +++ b/tests/fate/checkasm.mak @@ -8,11 +8,13 @@ FATE_CHECKASM = fate-checkasm-aacencdsp \ fate-checkasm-blockdsp \ fate-checkasm-bswapdsp \ fate-checkasm-exrdsp \ + fate-checkasm-fdctdsp \ fate-checkasm-fixed_dsp \ fate-checkasm-flacdsp \ fate-checkasm-float_dsp \ fate-checkasm-fmtconvert \ fate-checkasm-g722dsp \ + fate-checkasm-h263dsp \ fate-checkasm-h264chroma \ fate-checkasm-h264dsp \ fate-checkasm-h264pred \ @@ -26,19 +28,25 @@ FATE_CHECKASM = fate-checkasm-aacencdsp \ fate-checkasm-idctdsp \ fate-checkasm-jpeg2000dsp \ fate-checkasm-llauddsp \ + fate-checkasm-lls \ fate-checkasm-llviddsp \ fate-checkasm-llviddspenc \ fate-checkasm-lpc \ fate-checkasm-motion \ + fate-checkasm-mpegvideoencdsp \ fate-checkasm-opusdsp \ fate-checkasm-pixblockdsp \ fate-checkasm-sbrdsp \ fate-checkasm-rv34dsp \ + fate-checkasm-rv40dsp \ fate-checkasm-svq1enc \ fate-checkasm-synth_filter \ fate-checkasm-sw_gbrp \ + fate-checkasm-sw_range_convert \ fate-checkasm-sw_rgb \ fate-checkasm-sw_scale \ + fate-checkasm-sw_yuv2rgb \ + fate-checkasm-sw_yuv2yuv \ fate-checkasm-takdsp \ fate-checkasm-utvideodsp \ fate-checkasm-v210dec \ @@ -57,6 +65,7 @@ FATE_CHECKASM = fate-checkasm-aacencdsp \ fate-checkasm-vorbisdsp \ fate-checkasm-vp8dsp \ fate-checkasm-vp9dsp \ + fate-checkasm-vvc_alf \ fate-checkasm-vvc_mc \ $(FATE_CHECKASM): tests/checkasm/checkasm$(EXESUF) diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak index d9b9045f0..e0d1fccc8 100644 --- a/tests/fate/demux.mak +++ b/tests/fate/demux.mak @@ -76,7 +76,7 @@ fate-mkv-1242: CMD = framecrc -i $(TARGET_SAMPLES)/mkv/1242-small.mkv -c copy -f FATE_SAMPLES_DEMUX-$(CONFIG_MLV_DEMUXER) += fate-mlv-demux fate-mlv-demux: CMD = crc -i $(TARGET_SAMPLES)/mlv/M19-0333-cut.MLV -c copy -FATE_SAMPLES_DEMUX-$(CONFIG_MOV_DEMUXER) += fate-mov-mp3-demux +FATE_SAMPLES_DEMUX-$(call ALLYES, MOV_DEMUXER FRAMECRC_MUXER FILE_PROTOCOL PIPE_PROTOCOL) += fate-mov-mp3-demux fate-mov-mp3-demux: CMD = framecrc -i $(TARGET_SAMPLES)/mpegaudio/packed_maindata.mp3.mp4 -c copy FATE_FFPROBE_DEMUX-$(call ALLYES, MPEGTS_DEMUXER ARESAMPLE_FILTER) += fate-ts-opus-demux diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak index 077104c71..d9348ee83 100644 --- a/tests/fate/ffmpeg.mak +++ b/tests/fate/ffmpeg.mak @@ -62,6 +62,7 @@ fate-sub2video: CMD = framecrc -auto_conversion_filters \ FATE_SAMPLES_FFMPEG-$(call FRAMECRC, VOBSUB, DVDSUB, SCALE_FILTER) += fate-sub2video_basic fate-sub2video_basic: CMD = framecrc -auto_conversion_filters \ -i $(TARGET_SAMPLES)/sub/vobsub.idx \ + -pix_fmt bgra \ -fps_mode passthrough -copyts \ -filter_complex "sws_flags=+accurate_rnd+bitexact\;[0:s:0]scale" \ -c:v rawvideo -threads 1 @@ -71,6 +72,7 @@ fate-sub2video_basic: CMD = framecrc -auto_conversion_filters \ FATE_SAMPLES_FFMPEG-$(call FRAMECRC, SUP, PGSSUB, SCALE_FILTER RAWVIDEO_ENCODER) += fate-sub2video_time_limited fate-sub2video_time_limited: CMD = framecrc -auto_conversion_filters \ -i $(TARGET_SAMPLES)/sub/pgs_sub.sup \ + -pix_fmt bgra \ -fps_mode passthrough -copyts \ -t 15 \ -filter_complex "sws_flags=+accurate_rnd+bitexact\;[0:s:0]scale" \ @@ -218,7 +220,7 @@ FATE_SAMPLES_FFMPEG-$(call DEMMUX, APNG, FRAMECRC, SETTS_BSF PIPE_PROTOCOL) += f fate-ffmpeg-setts-bsf: CMD = framecrc -i $(TARGET_SAMPLES)/apng/clock.png -c:v copy -bsf:v "setts=duration=if(eq(NEXT_PTS\,NOPTS)\,PREV_OUTDURATION\,(NEXT_PTS-PTS)/2):ts=PTS/2" -fflags +bitexact FATE_TIME_BASE-$(call PARSERDEMDEC, MPEGVIDEO, MPEGPS, MPEG2VIDEO, MPEGVIDEO_DEMUXER MXF_MUXER) += fate-time_base -fate-time_base: CMD = md5 -i $(TARGET_SAMPLES)/mpeg2/dvd_single_frame.vob -an -sn -c:v copy -r 25 -time_base 1001:30000 -fflags +bitexact -f mxf +fate-time_base: CMD = md5 -i $(TARGET_SAMPLES)/mpeg2/dvd_single_frame.vob -an -sn -c:v copy -r 25 -fflags +bitexact -f mxf FATE_SAMPLES_FFMPEG-yes += $(FATE_TIME_BASE-yes) @@ -261,3 +263,7 @@ fate-ffmpeg-loopback-decoding: CMD = transcode \ "rawvideo -s 352x288 -pix_fmt yuv420p" $(TARGET_PATH)/tests/data/vsynth1.yuv nut \ "-map 0:v:0 -c:v mpeg2video -f null - -flags +bitexact -idct simple -threads $$threads -dec 0:0 -filter_complex '[0:v][dec:0]hstack[stack]' -map '[stack]' -c:v ffv1" "" FATE_FFMPEG-$(call ENCDEC2, MPEG2VIDEO, FFV1, NUT, HSTACK_FILTER PIPE_PROTOCOL FRAMECRC_MUXER) += fate-ffmpeg-loopback-decoding + +# test matching by stream disposition +fate-ffmpeg-spec-disposition: CMD = framecrc -i $(TARGET_SAMPLES)/mpegts/pmtchange.ts -map '0:disp:visual_impaired+descriptions:1' -c copy +FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MPEGTS,,) += fate-ffmpeg-spec-disposition diff --git a/tests/fate/ffprobe.mak b/tests/fate/ffprobe.mak index f30cc2d4b..23c6d3550 100644 --- a/tests/fate/ffprobe.mak +++ b/tests/fate/ffprobe.mak @@ -10,41 +10,19 @@ tests/data/ffprobe-test.nut: ffmpeg$(PROGSSUF)$(EXESUF) tests/test_copy.ffmeta | FFPROBE_TEST_FILE=tests/data/ffprobe-test.nut FFPROBE_COMMAND=ffprobe$(PROGSSUF)$(EXESUF) -show_streams -show_packets -show_format -show_frames -bitexact $(TARGET_PATH)/$(FFPROBE_TEST_FILE) -print_filename $(FFPROBE_TEST_FILE) -FATE_FFPROBE-$(call ALLYES, AVDEVICE ARESAMPLE_FILTER) += fate-ffprobe_compact -fate-ffprobe_compact: $(FFPROBE_TEST_FILE) -fate-ffprobe_compact: CMD = run $(FFPROBE_COMMAND) -of compact +FFPROBE_OUTPUT_MODES_TESTS = $(addprefix fate-ffprobe_, compact csv default flat ini json xml) +$(FFPROBE_OUTPUT_MODES_TESTS): $(FFPROBE_TEST_FILE) +$(FFPROBE_OUTPUT_MODES_TESTS): CMD = run $(FFPROBE_COMMAND) -of $(@:fate-ffprobe_%=%) +FFPROBE_TEST_FILE_TESTS-yes += $(FFPROBE_OUTPUT_MODES_TESTS) -FATE_FFPROBE-$(call ALLYES, AVDEVICE ARESAMPLE_FILTER) += fate-ffprobe_csv -fate-ffprobe_csv: $(FFPROBE_TEST_FILE) -fate-ffprobe_csv: CMD = run $(FFPROBE_COMMAND) -of csv - -FATE_FFPROBE-$(call ALLYES, AVDEVICE ARESAMPLE_FILTER) += fate-ffprobe_default -fate-ffprobe_default: $(FFPROBE_TEST_FILE) -fate-ffprobe_default: CMD = run $(FFPROBE_COMMAND) -of default - -FATE_FFPROBE-$(call ALLYES, AVDEVICE ARESAMPLE_FILTER) += fate-ffprobe_flat -fate-ffprobe_flat: $(FFPROBE_TEST_FILE) -fate-ffprobe_flat: CMD = run $(FFPROBE_COMMAND) -of flat - -FATE_FFPROBE-$(call ALLYES, AVDEVICE ARESAMPLE_FILTER) += fate-ffprobe_ini -fate-ffprobe_ini: $(FFPROBE_TEST_FILE) -fate-ffprobe_ini: CMD = run $(FFPROBE_COMMAND) -of ini - -FATE_FFPROBE-$(call ALLYES, AVDEVICE ARESAMPLE_FILTER) += fate-ffprobe_json -fate-ffprobe_json: $(FFPROBE_TEST_FILE) -fate-ffprobe_json: CMD = run $(FFPROBE_COMMAND) -of json - -FATE_FFPROBE-$(call ALLYES, AVDEVICE ARESAMPLE_FILTER) += fate-ffprobe_xml -fate-ffprobe_xml: $(FFPROBE_TEST_FILE) -fate-ffprobe_xml: CMD = run $(FFPROBE_COMMAND) -of xml - -FATE_FFPROBE_SCHEMA-$(call ALLYES, AVDEVICE ARESAMPLE_FILTER) += fate-ffprobe_xsd +FFPROBE_TEST_FILE_TESTS-$(HAVE_XMLLINT) += fate-ffprobe_xsd fate-ffprobe_xsd: $(FFPROBE_TEST_FILE) fate-ffprobe_xsd: CMD = run $(FFPROBE_COMMAND) -noprivate -of xml=q=1:x=1 | \ xmllint --schema $(SRC_PATH)/doc/ffprobe.xsd - -FATE_FFPROBE-$(HAVE_XMLLINT) += $(FATE_FFPROBE_SCHEMA-yes) -FATE_FFPROBE += $(FATE_FFPROBE-yes) +FATE_FFPROBE-$(call FILTERDEMDECENCMUX, AEVALSRC TESTSRC ARESAMPLE, FFMETADATA, WRAPPED_AVFRAME, RAWVIDEO, NUT, \ + FFMPEG LAVFI_INDEV PCM_F64BE_DECODER PCM_F64LE_DECODER PCM_S16LE_ENCODER) \ + += $(FFPROBE_TEST_FILE_TESTS-yes) -fate-ffprobe: $(FATE_FFPROBE) +fate-ffprobe: $(FATE_FFPROBE-yes) diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index 3f22db1e0..eb8582ab3 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -412,6 +412,16 @@ fate-filter-hdcd-s32p: CMD = md5 -i $(SRC) -af hdcd -f s32le fate-filter-hdcd-s32p: CMP = oneline fate-filter-hdcd-s32p: REF = 0c5513e83eedaa10ab6fac9ddc173cf5 +FATE_AFILTER_SAMPLES-$(call FILTERDEMDECENCMUX, ATEMPO, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-atempo +fate-filter-atempo: tests/data/asynth-44100-1.wav +fate-filter-atempo: CMD = pcm -i $(TARGET_PATH)/tests/data/asynth-44100-1.wav -af "atempo=2.0" +fate-filter-atempo: CMP = oneoff +fate-filter-atempo: REF = $(SAMPLES)/filter-reference/atempo.pcm + +fate-filter-crazychannels: tests/data/filtergraphs/crazychannels +fate-filter-crazychannels: CMD = framecrc -auto_conversion_filters -/filter_complex $(TARGET_PATH)/tests/data/filtergraphs/crazychannels +FATE_AFILTER-$(call FILTERFRAMECRC, SINE JOIN ATRIM CHANNELMAP CHANNELSPLIT) += fate-filter-crazychannels + FATE_AFILTER-yes += fate-filter-formats fate-filter-formats: libavfilter/tests/formats$(EXESUF) fate-filter-formats: CMD = run libavfilter/tests/formats$(EXESUF) diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak index ee9f0f5e4..5b8a294af 100644 --- a/tests/fate/filter-video.mak +++ b/tests/fate/filter-video.mak @@ -2,7 +2,7 @@ VIDEO_FILTER = $(call ALLYES, $(1:%=%_FILTER) $(2) FILE_PROTOCOL IMAGE2_DEMUXER PGMYUV_DECODER RAWVIDEO_ENCODER NUT_MUXER MD5_PROTOCOL) FATE_FILTER_SAMPLES-$(call FILTERDEMDECENCMUX, PERMS OWDENOISE TRIM SCALE, SMJPEG, MJPEG, RAWVIDEO, RAWVIDEO, PIPE_PROTOCOL) += fate-filter-owdenoise-sample -fate-filter-owdenoise-sample: CMD = ffmpeg -auto_conversion_filters -idct simple -i $(TARGET_SAMPLES)/smjpeg/scenwin.mjpg -vf "trim=duration=0.5,perms=random,owdenoise=10:20:20:enable=not(between(t\,0.2\,1.2))" -an -f rawvideo - +fate-filter-owdenoise-sample: CMD = ffmpeg -auto_conversion_filters -idct simple -i $(TARGET_SAMPLES)/smjpeg/scenwin.mjpg -vf "trim=duration=0.5,perms=random,owdenoise=10:20:20:enable=not(between(t\,0.2\,1.2))" -an -f rawvideo -color_range mpeg - fate-filter-owdenoise-sample: REF = $(SAMPLES)/filter-reference/owdenoise-scenwin.raw fate-filter-owdenoise-sample: CMP_TARGET = 1 fate-filter-owdenoise-sample: FUZZ = 3539 @@ -16,7 +16,7 @@ fate-filter-bwdif-mode0: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $( fate-filter-bwdif-mode1: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -frames:v 59 -vf bwdif=send_field FATE_BWDIF-$(call FILTERDEMDEC, BWDIF SCALE, MPEGTS, MPEG2VIDEO) += fate-filter-bwdif10 -fate-filter-bwdif10: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -flags bitexact -pix_fmt yuv420p10le -frames:v 30 -vf scale,bwdif=0 +fate-filter-bwdif10: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -flags bitexact -pix_fmt yuv420p10le -frames:v 30 -vf scale,format=yuv420p10,bwdif=0,scale FATE_FILTER_SAMPLES-yes += $(FATE_BWDIF-yes) @@ -25,8 +25,8 @@ fate-filter-yadif-mode0: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $( fate-filter-yadif-mode1: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -frames:v 59 -vf yadif=1 FATE_YADIF-$(call FILTERDEMDEC, YADIF SCALE, MPEGTS, MPEG2VIDEO) += fate-filter-yadif10 fate-filter-yadif16 -fate-filter-yadif10: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -flags bitexact -pix_fmt yuv420p10le -frames:v 30 -vf scale,yadif=0 -fate-filter-yadif16: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -flags bitexact -pix_fmt yuv420p16le -frames:v 30 -vf scale,yadif=0 +fate-filter-yadif10: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -flags bitexact -pix_fmt yuv420p10le -frames:v 30 -vf scale,format=yuv420p10,yadif=0,scale +fate-filter-yadif16: CMD = framecrc -ec 0 -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -flags bitexact -pix_fmt yuv420p16le -frames:v 30 -vf scale,format=yuv420p16,yadif=0,scale FATE_FILTER_SAMPLES-yes += $(FATE_YADIF-yes) @@ -433,7 +433,7 @@ fate-filter-scale2ref_keep_aspect: CMD = framemd5 -frames:v 5 -/filter_complex $ FATE_FILTER_VSYNTH-$(call FILTERDEMDEC, SCALE, RAWVIDEO, RAWVIDEO) += fate-filter-scalechroma fate-filter-scalechroma: tests/data/vsynth1.yuv -fate-filter-scalechroma: CMD = framecrc -flags bitexact -s 352x288 -pix_fmt yuv444p -i $(TARGET_PATH)/tests/data/vsynth1.yuv -pix_fmt yuv420p -sws_flags +bitexact -vf scale=out_v_chr_pos=33:out_h_chr_pos=151 +fate-filter-scalechroma: CMD = framecrc -flags bitexact -s 352x288 -pix_fmt yuv444p -i $(TARGET_PATH)/tests/data/vsynth1.yuv -pix_fmt yuv420p -sws_flags +bitexact -vf scale=out_chroma_loc=bottomleft FATE_FILTER_VSYNTH_VIDEO_FILTER-$(CONFIG_VFLIP_FILTER) += fate-filter-vflip fate-filter-vflip: CMD = video_filter "vflip" @@ -551,7 +551,11 @@ FATE_FILTER_VSYNTH_VIDEO_FILTER-$(CONFIG_PIXELIZE_FILTER) += fate-filter-pixeliz fate-filter-pixelize-max: CMD = video_filter "pixelize=mode=max" FATE_FILTER_VSYNTH_VIDEO_FILTER-$(CONFIG_TILTANDSHIFT_FILTER) += fate-filter-tiltandshift +FATE_FILTER_VSYNTH_VIDEO_FILTER-$(call ALLYES, SCALE_FILTER TILTANDSHIFT_FILTER) += fate-filter-tiltandshift-410 fate-filter-tiltandshift-422 fate-filter-tiltandshift-444 fate-filter-tiltandshift: CMD = framecrc -c:v pgmyuv -i $(SRC) -flags +bitexact -vf tiltandshift +fate-filter-tiltandshift-410: CMD = framecrc -c:v pgmyuv -i $(SRC) -flags +bitexact -vf scale=sws_flags=+accurate_rnd+bitexact,format=yuv410p,tiltandshift +fate-filter-tiltandshift-422: CMD = framecrc -c:v pgmyuv -i $(SRC) -flags +bitexact -vf scale=sws_flags=+accurate_rnd+bitexact,format=yuv422p,tiltandshift +fate-filter-tiltandshift-444: CMD = framecrc -c:v pgmyuv -i $(SRC) -flags +bitexact -vf scale=sws_flags=+accurate_rnd+bitexact,format=yuv444p,tiltandshift tests/pixfmts.mak: TAG = GEN tests/pixfmts.mak: ffmpeg$(PROGSSUF)$(EXESUF) | tests @@ -692,7 +696,7 @@ fate-filter-metadata-freezedetect: CMD = run $(FILTER_METADATA_COMMAND) "sws_fla SIGNALSTATS_DEPS = LAVFI_INDEV COLOR_FILTER SCALE_FILTER SIGNALSTATS_FILTER FATE_METADATA_FILTER-$(call ALLYES, $(SIGNALSTATS_DEPS)) += fate-filter-metadata-signalstats-yuv420p fate-filter-metadata-signalstats-yuv420p10 fate-filter-metadata-signalstats-yuv420p: CMD = run $(FILTER_METADATA_COMMAND) "sws_flags=+accurate_rnd+bitexact;color=white:duration=1:r=1,signalstats" -fate-filter-metadata-signalstats-yuv420p10: CMD = run $(FILTER_METADATA_COMMAND) "sws_flags=+accurate_rnd+bitexact;color=white:duration=1:r=1,format=yuv420p10,signalstats" +fate-filter-metadata-signalstats-yuv420p10: CMD = run $(FILTER_METADATA_COMMAND) "sws_flags=+accurate_rnd+bitexact;color=white:duration=1:r=1,format=yuv420p10le,signalstats" SILENCEDETECT_DEPS = LAVFI_INDEV FILE_PROTOCOL AMOVIE_FILTER TTA_DEMUXER TTA_DECODER SILENCEDETECT_FILTER FATE_METADATA_FILTER-$(call ALLYES, $(SILENCEDETECT_DEPS)) += fate-filter-metadata-silencedetect @@ -749,6 +753,12 @@ fate-filter-refcmp-ssim-rgb: CMD = refcmp_metadata ssim rgb24 0.015 FATE_FILTER_REFCMP_METADATA-$(CONFIG_SSIM_FILTER) += fate-filter-refcmp-ssim-yuv fate-filter-refcmp-ssim-yuv: CMD = refcmp_metadata ssim yuv422p 0.015 +FATE_FILTER_REFCMP_METADATA-$(call ALLYES, XPSNR_FILTER SCALE_FILTER) += fate-filter-refcmp-xpsnr-rgb +fate-filter-refcmp-xpsnr-rgb: CMD = refcmp_metadata xpsnr rgb24 0.002 + +FATE_FILTER_REFCMP_METADATA-$(CONFIG_XPSNR_FILTER) += fate-filter-refcmp-xpsnr-yuv +fate-filter-refcmp-xpsnr-yuv: CMD = refcmp_metadata xpsnr yuv422p 0.0015 + FATE_FILTER-$(call ALLYES, TESTSRC2_FILTER SPLIT_FILTER AVGBLUR_FILTER \ METADATA_FILTER WRAPPED_AVFRAME_ENCODER NULL_MUXER \ PIPE_PROTOCOL) += $(FATE_FILTER_REFCMP_METADATA-yes) diff --git a/tests/fate/fits.mak b/tests/fate/fits.mak index d85946bc1..b83900aae 100644 --- a/tests/fate/fits.mak +++ b/tests/fate/fits.mak @@ -28,7 +28,7 @@ fate-fitsdec-multi: tests/data/fits-multi.fits fate-fitsdec-multi: CMD = framecrc -i $(TARGET_PATH)/tests/data/fits-multi.fits -pix_fmt gbrap fate-fitsdec%: PIXFMT = $(word 3, $(subst -, ,$(@))) -fate-fitsdec%: CMD = transcode image2 $(TARGET_SAMPLES)/png1/lena-$(fits-png-map-$(PIXFMT)).png fits "-vf scale -pix_fmt $(PIXFMT)" +fate-fitsdec%: CMD = transcode image2 $(TARGET_SAMPLES)/png1/lena-$(fits-png-map-$(PIXFMT)).png fits "-vf scale -pix_fmt $(PIXFMT)" "-vf scale -pix_fmt $(PIXFMT)" FATE_FITS_DEC_PIXFMT = gray gbrp gbrp16be gbrap16be FATE_FITS_DEC-$(call TRANSCODE, FITS, FITS, IMAGE2_DEMUXER PNG_DECODER SCALE_FILTER) += $(FATE_FITS_DEC_PIXFMT:%=fate-fitsdec-%) diff --git a/tests/fate/h264.mak b/tests/fate/h264.mak index 674054560..e7038387e 100644 --- a/tests/fate/h264.mak +++ b/tests/fate/h264.mak @@ -231,6 +231,8 @@ FATE_H264-$(call DEMMUX, MOV, H264, H264_MP4TOANNEXB_BSF) += fate-h264-bsf-mp4to fate-h264_mp4toannexb_ticket5927 \ fate-h264_mp4toannexb_ticket5927_2 \ +FATE_H264-$(call DEMMUX, H264, MOV, DTS2PTS_BSF) += fate-h264-bsf-dts2pts + FATE_H264-$(call FRAMECRC, MATROSKA, H264) += fate-h264-direct-bff FATE_H264-$(call FRAMECRC, FLV, H264, SCALE_FILTER) += fate-h264-brokensps-2580 FATE_H264-$(call FRAMECRC, MXF, H264, PCM_S24LE_DECODER SCALE_FILTER ARESAMPLE_FILTER) += fate-h264-xavc-4389 @@ -312,7 +314,7 @@ fate-h264-conformance-ci1_ft_b: CMD = framecrc -i $(TARGET_SAM fate-h264-conformance-ci_mw_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CI_MW_D.264 fate-h264-conformance-cvbs3_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVBS3_Sony_C.jsv fate-h264-conformance-cvcanlma2_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVCANLMA2_Sony_C.jsv -fate-h264-conformance-cvfc1_sony_c: CMD = framecrc -flags unaligned -i $(TARGET_SAMPLES)/h264-conformance/CVFC1_Sony_C.jsv +fate-h264-conformance-cvfc1_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVFC1_Sony_C.jsv fate-h264-conformance-cvfi1_sony_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVFI1_Sony_D.jsv fate-h264-conformance-cvfi1_sva_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVFI1_SVA_C.264 fate-h264-conformance-cvfi2_sony_h: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVFI2_Sony_H.jsv @@ -437,6 +439,8 @@ fate-h264-bsf-mp4toannexb-2: CMD = md5 -i $(TARGET_SAMPLES) fate-h264-bsf-mp4toannexb-2: CMP = oneline fate-h264-bsf-mp4toannexb-2: REF = cffcfa6a2d0b58c9de1f5785f099f41d fate-h264-bsf-mp4toannexb-new-extradata: CMD = stream_remux mov $(TARGET_SAMPLES)/h264/extradata-reload-multi-stsd.mov "" h264 "-map 0:v" +fate-h264-bsf-dts2pts: CMD = transcode "h264" $(TARGET_SAMPLES)/h264-conformance/CAPAMA3_Sand_F.264 \ + mov "-c:v copy -bsf:v dts2pts -frames:v 50" "-c:v copy" fate-h264_mp4toannexb_ticket5927: CMD = transcode "mp4" $(TARGET_SAMPLES)/h264/thezerotheorem-cut.mp4 \ h264 "-c:v copy -bsf:v h264_mp4toannexb -an" "-c:v copy" fate-h264_mp4toannexb_ticket5927_2: CMD = transcode "mp4" $(TARGET_SAMPLES)/h264/thezerotheorem-cut.mp4 \ diff --git a/tests/fate/hevc.mak b/tests/fate/hevc.mak index 4889ee823..7f7ec4390 100644 --- a/tests/fate/hevc.mak +++ b/tests/fate/hevc.mak @@ -178,7 +178,14 @@ HEVC_SAMPLES_444_12BIT = \ PERSIST_RPARAM_A_RExt_Sony_3\ $(if $(CONFIG_LARGE_TESTS), $(HEVC_SAMPLES_444_12BIT_LARGE)) -FATE_HEVC_VARS := 8BIT 10BIT 422_10BIT 422_10BIN 444_8BIT 444_12BIT +HEVC_SAMPLES_MULTIVIEW = \ + MVHEVCS_A \ + MVHEVCS_B \ + MVHEVCS_E \ + MVHEVCS_F \ + + +FATE_HEVC_VARS := 8BIT 10BIT 422_10BIT 422_10BIN 444_8BIT 444_12BIT MULTIVIEW $(foreach VAR,$(FATE_HEVC_VARS), $(eval HEVC_TESTS_$(VAR) := $(addprefix fate-hevc-conformance-, $(HEVC_SAMPLES_$(VAR))))) # equivalent bitstreams @@ -200,8 +207,10 @@ $(HEVC_TESTS_444_8BIT): SCALE_OPTS := -pix_fmt yuv444p $(HEVC_TESTS_10BIT): SCALE_OPTS := -pix_fmt yuv420p10le -vf scale $(HEVC_TESTS_422_10BIT) $(HEVC_TESTS_422_10BIN): SCALE_OPTS := -pix_fmt yuv422p10le -vf scale $(HEVC_TESTS_444_12BIT): SCALE_OPTS := -pix_fmt yuv444p12le -vf scale -fate-hevc-conformance-%: CMD = framecrc -flags unaligned -i $(TARGET_SAMPLES)/hevc-conformance/$(subst fate-hevc-conformance-,,$(@)).bit $(SCALE_OPTS) -$(HEVC_TESTS_422_10BIN): CMD = framecrc -flags unaligned -i $(TARGET_SAMPLES)/hevc-conformance/$(subst fate-hevc-conformance-,,$(@)).bin $(SCALE_OPTS) +fate-hevc-conformance-%: CMD = framecrc -i $(TARGET_SAMPLES)/hevc-conformance/$(subst fate-hevc-conformance-,,$(@)).bit $(SCALE_OPTS) +$(HEVC_TESTS_422_10BIN): CMD = framecrc -i $(TARGET_SAMPLES)/hevc-conformance/$(subst fate-hevc-conformance-,,$(@)).bin $(SCALE_OPTS) +$(HEVC_TESTS_MULTIVIEW): CMD = framecrc -i $(TARGET_SAMPLES)/hevc-conformance/$(subst fate-hevc-conformance-,,$(@)).bit \ + -pix_fmt yuv420p -map "0:view:0" -map "0:view:1" -vf setpts=N FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_PARSER) += $(HEVC_TESTS_8BIT) $(HEVC_TESTS_444_8BIT) FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_PARSER SCALE_FILTER) += \ @@ -210,6 +219,8 @@ FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_PARSER SCALE_FILTER) += \ $(HEVC_TESTS_422_10BIN) \ $(HEVC_TESTS_444_12BIT) \ +FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_PARSER SCALE_FILTER) += $(HEVC_TESTS_MULTIVIEW) + fate-hevc-paramchange-yuv420p-yuv420p10: CMD = framecrc -i $(TARGET_SAMPLES)/hevc/paramchange_yuv420p_yuv420p10.hevc -fps_mode passthrough -sws_flags area+accurate_rnd+bitexact FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_PARSER SCALE_FILTER LARGE_TESTS) += fate-hevc-paramchange-yuv420p-yuv420p10 @@ -252,12 +263,34 @@ FATE_HEVC_FFPROBE-$(call DEMDEC, MOV, HEVC) += fate-hevc-dv-rpu fate-hevc-two-first-slice: CMD = threads=2 framemd5 -i $(TARGET_SAMPLES)/hevc/two_first_slice.mp4 -sws_flags bitexact -t 00:02.00 -an FATE_HEVC-$(call FRAMEMD5, MOV, HEVC) += fate-hevc-two-first-slice -fate-hevc-cabac-tudepth: CMD = framecrc -flags unaligned -i $(TARGET_SAMPLES)/hevc/cbf_cr_cb_TUDepth_4_circle.h265 -pix_fmt yuv444p +fate-hevc-cabac-tudepth: CMD = framecrc -i $(TARGET_SAMPLES)/hevc/cbf_cr_cb_TUDepth_4_circle.h265 -pix_fmt yuv444p FATE_HEVC-$(call FRAMECRC, HEVC, HEVC) += fate-hevc-cabac-tudepth -fate-hevc-small422chroma: CMD = framecrc -flags unaligned -i $(TARGET_SAMPLES)/hevc/food.hevc -pix_fmt yuv422p10le -vf scale +fate-hevc-small422chroma: CMD = framecrc -i $(TARGET_SAMPLES)/hevc/food.hevc -pix_fmt yuv422p10le -vf scale FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_PARSER SCALE_FILTER) += fate-hevc-small422chroma +fate-hevc-pir: CMD = framecrc -i $(TARGET_SAMPLES)/hevc/pir.hevc +FATE_HEVC-$(call FRAMECRC, HEVC, HEVC) += fate-hevc-pir + +# multiview stream, where the secondary layer has a nontrivial nuh_layer_id=6 +fate-hevc-mv-nuh-layer-id: CMD = framecrc -i $(TARGET_SAMPLES)/hevc/mv_nuh_layer_id.bit -map 0:view:all +FATE_HEVC-$(call FRAMECRC, HEVC, HEVC) += fate-hevc-mv-nuh-layer-id + +# NB: $\ at the end of line joins lines without adding whitespace; +# this trick is recommended by GNU make manual +fate-hevc-mv-switch: INPUT = \ +$(TARGET_SAMPLES)/hevc-conformance/LS_A_Orange_2.bit|$\ +$(TARGET_SAMPLES)/hevc/mv_nuh_layer_id.bit|$\ +$(TARGET_SAMPLES)/hevc-conformance/NoOutPrior_B_Qualcomm_1.bit|$\ +$(TARGET_SAMPLES)/hevc-conformance/MVHEVCS_A.bit +fate-hevc-mv-switch: CMD = framecrc -i "concat:$(INPUT)" -fps_mode passthrough -map 0:vidx:0 -map 0:vidx:1 -sws_flags +accurate_rnd+bitexact +FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, CONCAT_PROTOCOL) += fate-hevc-mv-switch + +# multiview stream, select view by position +# (depends on Three Dimensional Reference Displays Information SEI) +fate-hevc-mv-position: CMD = framecrc -i $(TARGET_SAMPLES)/hevc/multiview.mov -map 0:v:vpos:left -map 0:v:vpos:right +FATE_HEVC-$(call FRAMECRC, MOV, HEVC) += fate-hevc-mv-position + FATE_SAMPLES_AVCONV += $(FATE_HEVC-yes) FATE_SAMPLES_FFPROBE += $(FATE_HEVC_FFPROBE-yes) diff --git a/tests/fate/iamf.mak b/tests/fate/iamf.mak index cf56a67e6..e42117da6 100644 --- a/tests/fate/iamf.mak +++ b/tests/fate/iamf.mak @@ -37,8 +37,25 @@ fate-iamf-ambisonic_1: CMD = transcode wav $(SRC) iamf "-auto_conversion_filters -streamid 0:0 -streamid 1:1 -streamid 2:2 -streamid 3:3 -map [MONO0] -map [MONO1] -map [MONO2] -map [MONO3] -c:a flac -t 1" "-c:a copy -map 0" \ "-show_entries stream_group=index,id,nb_streams,type:stream_group_components:stream_group_stream=index,id:stream_group_stream_disposition" +FATE_IAMF_SAMPLES-$(call FRAMECRC, IAMF, OPUS) += fate-iamf-stereo-demux +fate-iamf-stereo-demux: CMD = stream_demux iamf $(TARGET_SAMPLES)/iamf/test_000076.iamf "" \ + "-c:a copy -frames:a 0 -map 0:g:\#42" \ + "-show_entries stream_group=index,id,nb_streams,type:stream_group_components:stream_group_stream=index,id:stream_group_stream_disposition" + +FATE_IAMF_SAMPLES-$(call FRAMECRC, IAMF, OPUS) += fate-iamf-5_1-demux +fate-iamf-5_1-demux: CMD = stream_demux iamf $(TARGET_SAMPLES)/iamf/test_000059.iamf "" \ + "-c:a copy -frames:a 0 -map 0:g:\#42" \ + "-show_entries stream_group=index,id,nb_streams,type:stream_group_components:stream_group_stream=index,id:stream_group_stream_disposition" + +FATE_IAMF_SAMPLES-$(call REMUX, IAMF, OPUS_DECODER) += fate-iamf-5_1-copy +fate-iamf-5_1-copy: CMD = stream_remux iamf $(TARGET_SAMPLES)/iamf/test_000059.iamf "" iamf \ + "-map 0 -stream_group map=0=0:st=0:st=1:st=2:st=3 -stream_group map=0=1:stg=0 -streamid 0:0 -streamid 1:1 -streamid 2:2 -streamid 3:3" "" "-c:a copy -frames:a 0 -map 0:g:i:42" \ + "-show_entries stream_group=index,id,nb_streams,type:stream_group_components:stream_group_stream=index,id:stream_group_stream_disposition" + FATE_IAMF += $(FATE_IAMF-yes) +FATE_IAMF_SAMPLES += $(FATE_IAMF_SAMPLES-yes) FATE_FFMPEG_FFPROBE += $(FATE_IAMF) +FATE_SAMPLES_FFMPEG_FFPROBE += $(FATE_IAMF_SAMPLES) -fate-iamf: $(FATE_IAMF) +fate-iamf: $(FATE_IAMF) $(FATE_IAMF_SAMPLES) diff --git a/tests/fate/image.mak b/tests/fate/image.mak index 7c0e0fec0..042cf6438 100644 --- a/tests/fate/image.mak +++ b/tests/fate/image.mak @@ -104,229 +104,229 @@ FATE_IMAGE_PROBE-$(call DEMDEC, IMAGE2, DPX) += fate-dpx-probe fate-dpx-probe: CMD = probeframes -show_entries frame=color_transfer,color_range,color_space,color_primaries,sample_aspect_ratio $(TARGET_SAMPLES)/dpx/cyan.dpx FATE_EXR += fate-exr-slice-raw -fate-exr-slice-raw: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_raw.exr -pix_fmt gbrapf32le +fate-exr-slice-raw: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_raw.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-slice-rle -fate-exr-slice-rle: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_rle.exr -pix_fmt gbrapf32le +fate-exr-slice-rle: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_rle.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-slice-zip1 -fate-exr-slice-zip1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_zip1.exr -pix_fmt gbrapf32le +fate-exr-slice-zip1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_zip1.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-slice-zip16 -fate-exr-slice-zip16: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_zip16.exr -pix_fmt gbrapf32le +fate-exr-slice-zip16: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_zip16.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-slice-pxr24 -fate-exr-slice-pxr24: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_slice_pxr24.exr -pix_fmt gbrpf32le +fate-exr-slice-pxr24: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_slice_pxr24.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-pxr24-float-12x8 -fate-exr-rgb-scanline-pxr24-float-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_float_12x8.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-pxr24-float-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_float_12x8.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgba-multiscanline-half-b44 -fate-exr-rgba-multiscanline-half-b44: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_multiscanline_half_b44.exr -pix_fmt gbrapf32le +fate-exr-rgba-multiscanline-half-b44: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_multiscanline_half_b44.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-scanline-float-b44 -fate-exr-rgb-scanline-float-b44: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_float_b44.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-float-b44: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_float_b44.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-half-b44-12x8 -fate-exr-rgb-scanline-half-b44-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_b44_12x8.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-half-b44-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_b44_12x8.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-half-b44-13x9 -fate-exr-rgb-scanline-half-b44-13x9: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_b44_13x9.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-half-b44-13x9: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_b44_13x9.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-float-raw-12x8 -fate-exr-rgb-tile-float-raw-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_float_raw_12x8.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-float-raw-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_float_raw_12x8.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-float-raw-150x130 -fate-exr-rgb-tile-float-raw-150x130: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_float_raw_150x130.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-float-raw-150x130: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_float_raw_150x130.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-half-raw-12x8 -fate-exr-rgb-tile-half-raw-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_raw_12x8.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-half-raw-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_raw_12x8.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgba-scanline-float-half-b44-13x9-l1 -fate-exr-rgba-scanline-float-half-b44-13x9-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44_13x9.exr -pix_fmt gbrapf32le +fate-exr-rgba-scanline-float-half-b44-13x9-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44_13x9.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgba-scanline-float-half-b44-13x9-l2 -fate-exr-rgba-scanline-float-half-b44-13x9-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44_13x9.exr -pix_fmt gbrapf32le +fate-exr-rgba-scanline-float-half-b44-13x9-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44_13x9.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgba-scanline-float-half-b44-12x8-l1 -fate-exr-rgba-scanline-float-half-b44-12x8-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44_12x8.exr -pix_fmt gbrapf32le +fate-exr-rgba-scanline-float-half-b44-12x8-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44_12x8.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgba-scanline-float-half-b44-12x8-l2 -fate-exr-rgba-scanline-float-half-b44-12x8-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44_12x8.exr -pix_fmt gbrapf32le +fate-exr-rgba-scanline-float-half-b44-12x8-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44_12x8.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgba-scanline-float-half-b44a-12x8-l1 -fate-exr-rgba-scanline-float-half-b44a-12x8-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44a_12x8.exr -pix_fmt gbrapf32le +fate-exr-rgba-scanline-float-half-b44a-12x8-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44a_12x8.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgba-scanline-float-half-b44a-12x8-l2 -fate-exr-rgba-scanline-float-half-b44a-12x8-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44a_12x8.exr -pix_fmt gbrapf32le +fate-exr-rgba-scanline-float-half-b44a-12x8-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44a_12x8.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgba-scanline-float-half-b44a-13x9-l1 -fate-exr-rgba-scanline-float-half-b44a-13x9-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44a_13x9.exr -pix_fmt gbrapf32le +fate-exr-rgba-scanline-float-half-b44a-13x9-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44a_13x9.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgba-scanline-float-half-b44a-13x9-l2 -fate-exr-rgba-scanline-float-half-b44a-13x9-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44a_13x9.exr -pix_fmt gbrapf32le +fate-exr-rgba-scanline-float-half-b44a-13x9-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgba_scanline_float_half_b44a_13x9.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-tile-pxr24-float-half-l1 -fate-exr-rgb-tile-pxr24-float-half-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_pxr24_float_half.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-pxr24-float-half-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_pxr24_float_half.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-pxr24-float-half-l2 -fate-exr-rgb-tile-pxr24-float-half-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_pxr24_float_half.exr -pix_fmt gbrapf32le +fate-exr-rgb-tile-pxr24-float-half-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_pxr24_float_half.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-tile-pxr24-half-float-l1 -fate-exr-rgb-tile-pxr24-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_pxr24_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-pxr24-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_pxr24_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-pxr24-half-float-l2 -fate-exr-rgb-tile-pxr24-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_pxr24_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-tile-pxr24-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_pxr24_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-tile-half-float-b44-12x8-l1 -fate-exr-rgb-tile-half-float-b44-12x8-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_float_b44_12x8.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-half-float-b44-12x8-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_float_b44_12x8.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-half-float-b44-12x8-l2 -fate-exr-rgb-tile-half-float-b44-12x8-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_half_float_b44_12x8.exr -pix_fmt gbrapf32le +fate-exr-rgb-tile-half-float-b44-12x8-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_half_float_b44_12x8.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-tile-zip-half-float-l1 -fate-exr-rgb-tile-zip-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_zip_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-zip-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_zip_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-zip-half-float-l2 -fate-exr-rgb-tile-zip-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_zip_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-tile-zip-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_zip_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-tile-zip1-half-float-l1 -fate-exr-rgb-tile-zip1-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_zip1_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-zip1-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_zip1_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-zip1-half-float-l2 -fate-exr-rgb-tile-zip1-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_zip1_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-tile-zip1-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_zip1_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-tile-rle-half-float-l1 -fate-exr-rgb-tile-rle-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_rle_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-rle-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_rle_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-rle-half-float-l2 -fate-exr-rgb-tile-rle-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_rle_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-tile-rle-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_rle_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-tile-raw-half-float-l1 -fate-exr-rgb-tile-raw-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_raw_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-raw-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_raw_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-raw-half-float-l2 -fate-exr-rgb-tile-raw-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_raw_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-tile-raw-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_tile_raw_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-scanline-b44-half-float-12x8-l1 -fate-exr-rgb-scanline-b44-half-float-12x8-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_b44_half_float_12x8.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-b44-half-float-12x8-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_b44_half_float_12x8.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-b44-half-float-12x8-l2 -fate-exr-rgb-scanline-b44-half-float-12x8-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_b44_half_float_12x8.exr -pix_fmt gbrapf32le +fate-exr-rgb-scanline-b44-half-float-12x8-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_b44_half_float_12x8.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-scanline-pxr24-half-float-l1 -fate-exr-rgb-scanline-pxr24-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-pxr24-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-pxr24-half-float-l2 -fate-exr-rgb-scanline-pxr24-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-scanline-pxr24-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-scanline-pxr24-float-half-l1 -fate-exr-rgb-scanline-pxr24-float-half-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_float_half.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-pxr24-float-half-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_float_half.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-pxr24-float-half-l2 -fate-exr-rgb-scanline-pxr24-float-half-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_float_half.exr -pix_fmt gbrapf32le +fate-exr-rgb-scanline-pxr24-float-half-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_float_half.exr -vf scale -pix_fmt gbrapf32le -FATE_EXR-$(call DEMDEC, IMAGE2, EXR, SCALE_FILTER) += fate-exr-rgb-scanline-pxr24-half-uint32-13x9 +FATE_EXR += fate-exr-rgb-scanline-pxr24-half-uint32-13x9 fate-exr-rgb-scanline-pxr24-half-uint32-13x9: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_half_uint32_13x9.exr -pix_fmt rgb48le -vf scale FATE_EXR += fate-exr-rgb-scanline-zip-half-float-l1 -fate-exr-rgb-scanline-zip-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-zip-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-zip-half-float-l2 -fate-exr-rgb-scanline-zip-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-scanline-zip-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-scanline-zip1-half-float-l1 -fate-exr-rgb-scanline-zip1-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip1_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-zip1-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip1_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-zip1-half-float-l2 -fate-exr-rgb-scanline-zip1-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip1_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-scanline-zip1-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip1_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-scanline-rle-half-float-l1 -fate-exr-rgb-scanline-rle-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_rle_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-rle-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_rle_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-rle-half-float-l2 -fate-exr-rgb-scanline-rle-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_rle_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-scanline-rle-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_rle_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-scanline-raw-half-float-l1 -fate-exr-rgb-scanline-raw-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_raw_half_float.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-raw-half-float-l1: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_raw_half_float.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-raw-half-float-l2 -fate-exr-rgb-scanline-raw-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_raw_half_float.exr -pix_fmt gbrapf32le +fate-exr-rgb-scanline-raw-half-float-l2: CMD = framecrc -layer "VRaySamplerInfo" -i $(TARGET_SAMPLES)/exr/rgb_scanline_raw_half_float.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-scanline-b44-uint32 -fate-exr-rgb-scanline-b44-uint32: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_b44_uint32.exr -pix_fmt rgb48le +fate-exr-rgb-scanline-b44-uint32: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_b44_uint32.exr -vf scale -pix_fmt rgb48le FATE_EXR += fate-exr-rgb-scanline-pxr24-uint32 -fate-exr-rgb-scanline-pxr24-uint32: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_uint32.exr -pix_fmt rgb48le +fate-exr-rgb-scanline-pxr24-uint32: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_pxr24_uint32.exr -vf scale -pix_fmt rgb48le FATE_EXR += fate-exr-rgb-scanline-zip1-half-float-l1-zero-offsets -fate-exr-rgb-scanline-zip1-half-float-l1-zero-offsets: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip1_half_float_zero_offsets.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-zip1-half-float-l1-zero-offsets: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip1_half_float_zero_offsets.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-half-piz-bw -fate-exr-rgb-scanline-half-piz-bw: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_bw.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-half-piz-bw: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_bw.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-half-piz-color -fate-exr-rgb-scanline-half-piz-color: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_color.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-half-piz-color: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_color.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-half-piz-dw-t01 -fate-exr-rgb-scanline-half-piz-dw-t01: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_dw_t01.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-half-piz-dw-t01: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_dw_t01.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-float-piz-48x32 -fate-exr-rgb-scanline-float-piz-48x32: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_float_piz_48x32.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-float-piz-48x32: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_float_piz_48x32.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-none-negative-red -fate-exr-rgb-scanline-none-negative-red: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_none_negative_red.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-none-negative-red: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_none_negative_red.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-b44a-half-negative-4x4 -fate-exr-rgb-b44a-half-negative-4x4: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_b44a_half_negative_4x4.exr -pix_fmt gbrpf32le +fate-exr-rgb-b44a-half-negative-4x4: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_b44a_half_negative_4x4.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-y-tile-zip-half-12x8 -fate-exr-y-tile-zip-half-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/y_tile_zip_half_12x8.exr -pix_fmt grayf32le +fate-exr-y-tile-zip-half-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/y_tile_zip_half_12x8.exr -vf scale -pix_fmt grayf32le FATE_EXR += fate-exr-y-scanline-zip-half-12x8 -fate-exr-y-scanline-zip-half-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/y_scanline_zip_half_12x8.exr -pix_fmt grayf32le +fate-exr-y-scanline-zip-half-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/y_scanline_zip_half_12x8.exr -vf scale -pix_fmt grayf32le FATE_EXR += fate-exr-rgb-scanline-half-piz-dw-t08 -fate-exr-rgb-scanline-half-piz-dw-t08: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_dw_t08.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-half-piz-dw-t08: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_dw_t08.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgba-zip16-16x32-flag4 -fate-exr-rgba-zip16-16x32-flag4: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_zip16_16x32_flag4.exr -pix_fmt gbrapf32le +fate-exr-rgba-zip16-16x32-flag4: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_zip16_16x32_flag4.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-ya-scanline-zip-half-12x8 -fate-exr-ya-scanline-zip-half-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/ya_scanline_zip_half_12x8.exr -pix_fmt gbrapf32le +fate-exr-ya-scanline-zip-half-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/ya_scanline_zip_half_12x8.exr -vf scale -pix_fmt gbrapf32le FATE_EXR += fate-exr-rgb-tile-half-zip -fate-exr-rgb-tile-half-zip: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_zip.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-half-zip: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_zip.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-float-zip-dw-large -fate-exr-rgb-scanline-float-zip-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_float_zip_dw_large.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-float-zip-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_float_zip_dw_large.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-half-piz-dw-large -fate-exr-rgb-scanline-half-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_dw_large.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-half-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_dw_large.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-half-zip-dw-large -fate-exr-rgb-scanline-half-zip-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_zip_dw_large.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-half-zip-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_zip_dw_large.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-uint32-piz-dw-large -fate-exr-rgb-scanline-uint32-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_uint32_piz_dw_large.exr -pix_fmt rgb48le +fate-exr-rgb-scanline-uint32-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_uint32_piz_dw_large.exr -vf scale -pix_fmt rgb48le FATE_EXR += fate-exr-rgb-tile-half-piz-dw-large -fate-exr-rgb-tile-half-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_piz_dw_large.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-half-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_piz_dw_large.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-uint32-piz-dw-large -fate-exr-rgb-tile-uint32-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_uint32_piz_dw_large.exr -pix_fmt rgb48le +fate-exr-rgb-tile-uint32-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_uint32_piz_dw_large.exr -vf scale -pix_fmt rgb48le FATE_EXR += fate-exr-rgb-scanline-half-zip-dw-outside -fate-exr-rgb-scanline-half-zip-dw-outside: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_zip_dw_outside.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-half-zip-dw-outside: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_zip_dw_outside.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-tile-half-zip-dw-outside -fate-exr-rgb-tile-half-zip-dw-outside: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_zip_dw_outside.exr -pix_fmt gbrpf32le +fate-exr-rgb-tile-half-zip-dw-outside: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_zip_dw_outside.exr -vf scale -pix_fmt gbrpf32le FATE_EXR += fate-exr-rgb-scanline-zip-half-0x0-0xFFFF -fate-exr-rgb-scanline-zip-half-0x0-0xFFFF: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip_half_float_0x0_to_0xFFFF.exr -pix_fmt gbrpf32le +fate-exr-rgb-scanline-zip-half-0x0-0xFFFF: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_zip_half_float_0x0_to_0xFFFF.exr -vf scale -pix_fmt gbrpf32le -FATE_EXR-$(call DEMDEC, IMAGE2, EXR) += $(FATE_EXR) +FATE_EXR-$(call DEMDEC, IMAGE2, EXR, SCALE_FILTER) += $(FATE_EXR) FATE_IMAGE_FRAMECRC += $(FATE_EXR-yes) fate-exr: $(FATE_EXR-yes) @@ -416,6 +416,12 @@ FATE_PNG_PROBE-$(call ALLYES, LCMS2) += fate-png-icc-parse fate-png-icc-parse: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_frames \ -flags2 icc_profiles $(TARGET_SAMPLES)/png1/lena-int_rgb24.png +FATE_PNG_TRANSCODE-$(call TRANSCODE, PNG HEVC, IMAGE2PIPE HEVC, \ + IMAGE_PNG_PIPE_DEMUXER HEVC_PARSER PNG_DECODER SCALE_FILTER) += fate-png-mdcv +fate-png-mdcv: CMD = transcode hevc $(TARGET_SAMPLES)/hevc/hdr10_plus_h265_sample.hevc image2pipe \ + "-pix_fmt rgb24 -vf scale -c png" "" \ + "-show_frames -show_entries frame=side_data_list -of flat" + FATE_PNG-$(call DEMDEC, IMAGE2, PNG) += $(FATE_PNG) FATE_PNG_PROBE-$(call DEMDEC, IMAGE2, PNG) += $(FATE_PNG_PROBE) FATE_IMAGE_FRAMECRC += $(FATE_PNG-yes) diff --git a/tests/fate/jpeg2000.mak b/tests/fate/jpeg2000.mak index 2969d2cf0..a99b0c4e0 100644 --- a/tests/fate/jpeg2000.mak +++ b/tests/fate/jpeg2000.mak @@ -42,6 +42,9 @@ fate-jpeg2000dec-p0_08: CMD = framecrc -flags +bitexact -auto_conversion_filters FATE_JPEG2000DEC += fate-jpeg2000dec-p0_09 fate-jpeg2000dec-p0_09: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/jpeg2000/itu-iso/codestreams_profile0/p0_09.j2k +FATE_JPEG2000DEC += fate-jpeg2000dec-p0_10 +fate-jpeg2000dec-p0_10: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/jpeg2000/itu-iso/codestreams_profile0/p0_10.j2k + FATE_JPEG2000DEC += fate-jpeg2000dec-p0_11 fate-jpeg2000dec-p0_11: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/jpeg2000/itu-iso/codestreams_profile0/p0_11.j2k diff --git a/tests/fate/lavf-container.mak b/tests/fate/lavf-container.mak index 7a925117c..bc202ee5f 100644 --- a/tests/fate/lavf-container.mak +++ b/tests/fate/lavf-container.mak @@ -5,7 +5,7 @@ FATE_LAVF_CONTAINER-$(call ENCDEC, FLV, FLV) + FATE_LAVF_CONTAINER-$(call ENCDEC, RAWVIDEO, FILMSTRIP) += flm FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf gxf_pal gxf_ntsc FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG4, MP2, MATROSKA) += mkv mkv_attachment -FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG4, PCM_ALAW, MOV) += mov mov_rtphint ismv +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG4, PCM_ALAW, MOV) += mov mov_rtphint mov_hybrid_frag ismv FATE_LAVF_CONTAINER-$(call ENCDEC, MPEG4, MOV) += mp4 FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG1VIDEO, MP2, MPEG1SYSTEM MPEGPS) += mpg FATE_LAVF_CONTAINER-$(call ENCDEC , FFV1, MXF) += mxf_ffv1 @@ -30,7 +30,7 @@ FATE_LAVF_CONTAINER_SCALE := dv dv_pal dv_ntsc flm gxf gxf_pal gxf_ntsc \ FATE_LAVF_CONTAINER-$(!CONFIG_SCALE_FILTER) := $(filter-out $(FATE_LAVF_CONTAINER_SCALE),$(FATE_LAVF_CONTAINER-yes)) FATE_LAVF_CONTAINER = $(FATE_LAVF_CONTAINER-yes:%=fate-lavf-%) -FATE_LAVF_CONTAINER := $(if $(call ENCDEC2, RAWVIDEO PGMYUV, PCM_S16LE, CRC IMAGE2, PCM_S16LE_DEMUXER PIPE_PROTOCOL), $(FATE_LAVF_CONTAINER)) +FATE_LAVF_CONTAINER := $(if $(call ENCDEC2, RAWVIDEO PGMYUV, PCM_S16LE, CRC IMAGE2, PCM_S16LE_DEMUXER PIPE_PROTOCOL FFMPEG), $(FATE_LAVF_CONTAINER)) $(FATE_LAVF_CONTAINER): CMD = lavf_container $(FATE_LAVF_CONTAINER): REF = $(SRC_PATH)/tests/ref/lavf/$(@:fate-lavf-%=%) @@ -51,6 +51,7 @@ fate-lavf-mkv: CMD = lavf_container "" "-c:a mp2 -c:v mpeg4 -ar 44100 -threads 1 fate-lavf-mkv_attachment: CMD = lavf_container_attach "-c:a mp2 -c:v mpeg4 -threads 1 -f matroska" fate-lavf-mov: CMD = lavf_container_timecode "-movflags +faststart -c:a pcm_alaw -c:v mpeg4 -threads 1" fate-lavf-mov_rtphint: CMD = lavf_container "" "-movflags +rtphint -c:a pcm_alaw -c:v mpeg4 -threads 1 -f mov" +fate-lavf-mov_hybrid_frag: CMD = lavf_container "" "-movflags +hybrid_fragmented -c:a pcm_alaw -c:v mpeg4 -threads 1 -f mov" fate-lavf-mp4: CMD = lavf_container_timecode "-c:v mpeg4 -an -threads 1" fate-lavf-mpg: CMD = lavf_container_timecode "-ar 44100 -threads 1" fate-lavf-mxf: CMD = lavf_container_timecode "-af aresample=48000:tsf=s16p -bf 2 -threads 1" @@ -74,6 +75,9 @@ FATE_LAVF_CONTAINER_FATE-$(call ALLYES, IVF_DEMUXER AV1_DECODER AV1_PARSER MOV_M FATE_LAVF_CONTAINER_FATE-$(call ALLYES, IVF_DEMUXER AV1_DECODER AV1_PARSER MATROSKA_MUXER) += av1.mkv FATE_LAVF_CONTAINER_FATE-$(call ALLYES, EVC_DEMUXER EVC_PARSER MOV_MUXER) += evc.mp4 FATE_LAVF_CONTAINER_FATE-$(call ALLYES, H264_DEMUXER H264_PARSER MOV_MUXER) += h264.mp4 +FATE_LAVF_CONTAINER_FATE-$(call ALLYES, HEVC_DEMUXER HEVC_PARSER EXTRACT_EXTRADATA_BSF MOV_MUXER) += hevc.mp4 +FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MOV_DEMUXER MOV_MUXER) += mv_hevc.mov +FATE_LAVF_CONTAINER_FATE-$(call ALLYES, VVC_DEMUXER VVC_PARSER MOV_MUXER) += vvc.mp4 FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MATROSKA_DEMUXER OGG_MUXER) += vp3.ogg FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MATROSKA_DEMUXER OGV_MUXER) += vp8.ogg FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MOV_DEMUXER LATM_MUXER) += latm @@ -91,9 +95,12 @@ fate-lavf-fate-av1.mp4: CMD = lavf_container_fate "av1-test-vectors/av1-1-b8-05- fate-lavf-fate-av1.mkv: CMD = lavf_container_fate "av1-test-vectors/av1-1-b8-05-mv.ivf" "-c:v av1" "-c:v copy" fate-lavf-fate-evc.mp4: CMD = lavf_container_fate "evc/akiyo_cif.evc" "" "-c:v copy" fate-lavf-fate-h264.mp4: CMD = lavf_container_fate "h264/intra_refresh.h264" "" "-c:v copy" +fate-lavf-fate-hevc.mp4: CMD = lavf_container_fate "hevc-conformance/HRD_A_Fujitsu_2.bit" "" "-c:v copy" +fate-lavf-fate-vvc.mp4: CMD = lavf_container_fate "vvc-conformance/VPS_A_3.bit" "" "-c:v copy" fate-lavf-fate-vp3.ogg: CMD = lavf_container_fate "vp3/coeff_level64.mkv" "-idct auto" fate-lavf-fate-vp8.ogg: CMD = lavf_container_fate "vp8/RRSF49-short.webm" "" "-acodec copy" fate-lavf-fate-latm: CMD = lavf_container_fate "aac/al04_44.mp4" "" "-acodec copy" +fate-lavf-fate-mv_hevc.mov: CMD = lavf_container_fate "hevc/multiview.mov" "" "-c:v copy" fate-lavf-fate-mp3: CMD = lavf_container_fate "mp3-conformance/he_32khz.bit" "" "-acodec copy" fate-lavf-fate-qtrle_mace6.mov: CMD = lavf_container_fate "qtrle/Animation-16Greys.mov" "-idct auto" fate-lavf-fate-cram.avi: CMD = lavf_container_fate "cram/toon.avi" "-idct auto" diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak index 1a5694fa5..ef6e6ec40 100644 --- a/tests/fate/libavcodec.mak +++ b/tests/fate/libavcodec.mak @@ -99,7 +99,7 @@ fate-libavcodec-avcodec: libavcodec/tests/avcodec$(EXESUF) fate-libavcodec-avcodec: CMD = run libavcodec/tests/avcodec$(EXESUF) fate-libavcodec-avcodec: CMP = null -FATE_LIBAVCODEC-yes += fate-libavcodec-huffman +FATE_LIBAVCODEC-$(call ALLYES, MJPEG_ENCODER) += fate-libavcodec-huffman fate-libavcodec-huffman: libavcodec/tests/mjpegenc_huffman$(EXESUF) fate-libavcodec-huffman: CMD = run libavcodec/tests/mjpegenc_huffman$(EXESUF) fate-libavcodec-huffman: CMP = null diff --git a/tests/fate/libswscale.mak b/tests/fate/libswscale.mak index f8572f9c3..4c29220e6 100644 --- a/tests/fate/libswscale.mak +++ b/tests/fate/libswscale.mak @@ -17,17 +17,15 @@ $(SWS_SLICE_TEST-yes): tools/scale_slice_test$(EXESUF) $(SWS_SLICE_TEST-yes): REF = /dev/null FATE_LIBSWSCALE_SAMPLES += $(SWS_SLICE_TEST-yes) -FATE_LIBSWSCALE-$(CONFIG_RAWVIDEO_DEMUXER) += fate-sws-yuv-colorspace +FATE_LIBSWSCALE_FFMPEG-$(call FRAMECRC, RAWVIDEO, RAWVIDEO, SCALE_FILTER) += fate-sws-yuv-colorspace \ + fate-sws-yuv-range fate-sws-yuv-colorspace: tests/data/vsynth1.yuv -fate-sws-yuv-colorspace: ffmpeg$(PROGSSUF)$(EXESUF) fate-sws-yuv-colorspace: CMD = framecrc \ -f rawvideo -s 352x288 -pix_fmt yuv420p -i $(TARGET_PATH)/tests/data/vsynth1.yuv \ -frames 1 \ -vf scale=in_color_matrix=bt709:in_range=limited:out_color_matrix=bt601:out_range=full:flags=+accurate_rnd+bitexact -FATE_LIBSWSCALE-$(CONFIG_RAWVIDEO_DEMUXER) += fate-sws-yuv-range fate-sws-yuv-range: tests/data/vsynth1.yuv -fate-sws-yuv-range: ffmpeg$(PROGSSUF)$(EXESUF) fate-sws-yuv-range: CMD = framecrc \ -f rawvideo -s 352x288 -pix_fmt yuv420p -i $(TARGET_PATH)/tests/data/vsynth1.yuv \ -frames 1 \ @@ -36,5 +34,6 @@ fate-sws-yuv-range: CMD = framecrc \ FATE_LIBSWSCALE += $(FATE_LIBSWSCALE-yes) FATE_LIBSWSCALE_SAMPLES += $(FATE_LIBSWSCALE_SAMPLES-yes) FATE-$(CONFIG_SWSCALE) += $(FATE_LIBSWSCALE) +FATE_FFMPEG += $(FATE_LIBSWSCALE_FFMPEG-yes) FATE_EXTERN-$(CONFIG_SWSCALE) += $(FATE_LIBSWSCALE_SAMPLES) -fate-libswscale: $(FATE_LIBSWSCALE) $(FATE_LIBSWSCALE_SAMPLES) +fate-libswscale: $(FATE_LIBSWSCALE) $(FATE_LIBSWSCALE_SAMPLES) $(FATE_LIBSWSCALE_FFMPEG-yes) diff --git a/tests/fate/matroska.mak b/tests/fate/matroska.mak index 738c7fe30..563d75648 100644 --- a/tests/fate/matroska.mak +++ b/tests/fate/matroska.mak @@ -268,7 +268,7 @@ fate-matroska-side-data-pref-codec: CMD = run ffprobe$(PROGSSUF)$(EXESUF) $(TARG -select_streams v:0 -show_streams -show_frames -show_entries stream=stream_side_data:frame=frame_side_data_list fate-matroska-side-data-pref-packet: CMD = run ffprobe$(PROGSSUF)$(EXESUF) $(TARGET_SAMPLES)/mkv/hdr10tags-both.mkv \ -select_streams v:0 -show_streams -show_frames -show_entries stream=stream_side_data:frame=frame_side_data_list -side_data_prefer_packet mastering_display_metadata,content_light_level -FATE_MATROSKA_FFPROBE-$(call ALLYES MATROSKA_DEMUXER HEVC_DECODER) += fate-matroska-side-data-pref-codec fate-matroska-side-data-pref-packet +FATE_MATROSKA_FFPROBE-$(call ALLYES, MATROSKA_DEMUXER HEVC_DECODER) += fate-matroska-side-data-pref-codec fate-matroska-side-data-pref-packet FATE_SAMPLES_AVCONV += $(FATE_MATROSKA-yes) FATE_SAMPLES_FFPROBE += $(FATE_MATROSKA_FFPROBE-yes) diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak index b54fe1962..1200c7756 100644 --- a/tests/fate/mov.mak +++ b/tests/fate/mov.mak @@ -1,4 +1,4 @@ -FATE_MOV = fate-mov-3elist \ +FATE_MOV-$(call FRAMEMD5, MOV) = fate-mov-3elist \ fate-mov-3elist-1ctts \ fate-mov-1elist-1ctts \ fate-mov-1elist-noctts \ @@ -17,7 +17,7 @@ FATE_MOV = fate-mov-3elist \ fate-mov-stream-shorter-than-movie \ fate-mov-pcm-remux \ -FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \ +FATE_MOV_FFPROBE-$(call FRAMEMD5, MOV) = fate-mov-neg-firstpts-discard \ fate-mov-neg-firstpts-discard-vorbis \ fate-mov-aac-2048-priming \ fate-mov-zombie \ @@ -33,8 +33,8 @@ FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \ FATE_MOV_FASTSTART = fate-mov-faststart-4gb-overflow \ -FATE_SAMPLES_AVCONV += $(FATE_MOV) -FATE_SAMPLES_FFPROBE += $(FATE_MOV_FFPROBE) +FATE_SAMPLES_FFMPEG += $(FATE_MOV-yes) +FATE_SAMPLES_FFPROBE += $(FATE_MOV_FFPROBE-yes) FATE_SAMPLES_FASTSTART += $(FATE_MOV_FASTSTART) # Make sure we handle edit lists correctly in normal cases. @@ -218,6 +218,11 @@ fate-mov-pcm-remux: CMD = md5 -i $(TARGET_PATH)/tests/data/asynth-44100-1.wav -m fate-mov-pcm-remux: CMP = oneline fate-mov-pcm-remux: REF = e76115bc392d702da38f523216bba165 +FATE_MOV_FFMPEG-$(call TRANSCODE, RAWVIDEO, MOV, TESTSRC_FILTER SETPTS_FILTER) += fate-mov-vfr +fate-mov-vfr: CMD = md5 -filter_complex testsrc=size=2x2:duration=1,setpts=N*N -c rawvideo -fflags +bitexact -f mov +fate-mov-vfr: CMP = oneline +fate-mov-vfr: REF = 1558b4a9398d8635783c93f84eb5a60d + FATE_MOV_FFMPEG_FFPROBE-$(call TRANSCODE, FLAC, MOV, WAV_DEMUXER PCM_S16LE_DECODER) += fate-mov-mp4-iamf-stereo fate-mov-mp4-iamf-stereo: tests/data/asynth-44100-2.wav tests/data/streamgroups/audio_element-stereo tests/data/streamgroups/mix_presentation-stereo fate-mov-mp4-iamf-stereo: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav @@ -237,15 +242,31 @@ fate-mov-mp4-iamf-5_1_4: CMD = transcode wav $(SRC) mp4 "-auto_conversion_filter -streamid 0:0 -streamid 1:1 -streamid 2:2 -streamid 3:3 -streamid 4:4 -streamid 5:5 -map [FRONT] -map [BACK] -map [CENTER] -map [LFE] -map [TOP_FRONT] -map [TOP_BACK] -c:a flac -t 1" "-c:a copy -map 0" \ "-show_entries stream_group=index,id,nb_streams,type:stream_group_components:stream_group_disposition:stream_group_tags:stream_group_stream=index,id:stream_group_stream_disposition" -FATE_MOV_FFMPEG_FFPROBE-$(call TRANSCODE, FLAC, MOV, WAV_DEMUXER PCM_S16LE_DECODER ARESAMPLE_FILTER) += fate-mov-mp4-iamf-7_1_4 -fate-mov-mp4-iamf-7_1_4: tests/data/asynth-44100-12.wav tests/data/filtergraphs/iamf_7_1_4 tests/data/streamgroups/audio_element-7_1_4 tests/data/streamgroups/mix_presentation-7_1_4 -fate-mov-mp4-iamf-7_1_4: SRC = $(TARGET_PATH)/tests/data/asynth-44100-12.wav -fate-mov-mp4-iamf-7_1_4: CMD = transcode wav $(SRC) mp4 "-auto_conversion_filters \ +# Test muxing an IAMF track alongside a video one, with video as the first track. +FATE_MOV_FFMPEG_FFPROBE-$(call TRANSCODE, MPEG4 FLAC, MOV, WAV_DEMUXER RAWVIDEO_DEMUXER PCM_S16LE_DECODER ARESAMPLE_FILTER) += fate-mov-mp4-iamf-7_1_4-video-first +fate-mov-mp4-iamf-7_1_4-video-first: tests/data/asynth-44100-12.wav tests/data/vsynth1.yuv tests/data/filtergraphs/iamf_7_1_4 tests/data/streamgroups/audio_element-7_1_4-2 tests/data/streamgroups/mix_presentation-7_1_4 +fate-mov-mp4-iamf-7_1_4-video-first: SRC = $(TARGET_PATH)/tests/data/asynth-44100-12.wav +fate-mov-mp4-iamf-7_1_4-video-first: SRC2 = $(TARGET_PATH)/tests/data/vsynth1.yuv +fate-mov-mp4-iamf-7_1_4-video-first: CMD = transcode wav $(SRC) mp4 "-auto_conversion_filters \ + -/filter_complex $(TARGET_PATH)/tests/data/filtergraphs/iamf_7_1_4 \ + -/stream_group $(TARGET_PATH)/tests/data/streamgroups/audio_element-7_1_4-2 \ + -/stream_group $(TARGET_PATH)/tests/data/streamgroups/mix_presentation-7_1_4 \ + -streamid 0:1 -streamid 1:2 -streamid 2:3 -streamid 3:4 -streamid 4:5 -streamid 5:6 -streamid 6:7 -streamid 7:8 -map 1:v:0 -map [FRONT] -map [BACK] -map [CENTER] -map [LFE] -map [SIDE] -map [TOP_FRONT] -map [TOP_BACK] -c:a flac -c:v mpeg4 -t 1" "-c:a copy -c:v copy -map 0" \ + "-show_entries stream_group=index,id,nb_streams,type:stream_group_components:stream_group_disposition:stream_group_tags:stream_group_stream=index,id:stream_group_stream_disposition:stream=index,id" \ + "-f rawvideo -s 352x288 -pix_fmt yuv420p -i $(SRC2)" + +# Test muxing an IAMF track alongside a video one, with video as the last track. Also, use stream ids as track ids. +FATE_MOV_FFMPEG_FFPROBE-$(call TRANSCODE, MPEG4 FLAC, MOV, WAV_DEMUXER RAWVIDEO_DEMUXER PCM_S16LE_DECODER ARESAMPLE_FILTER) += fate-mov-mp4-iamf-7_1_4-video-last +fate-mov-mp4-iamf-7_1_4-video-last: tests/data/asynth-44100-12.wav tests/data/vsynth1.yuv tests/data/filtergraphs/iamf_7_1_4 tests/data/streamgroups/audio_element-7_1_4 tests/data/streamgroups/mix_presentation-7_1_4 +fate-mov-mp4-iamf-7_1_4-video-last: SRC = $(TARGET_PATH)/tests/data/asynth-44100-12.wav +fate-mov-mp4-iamf-7_1_4-video-last: SRC2 = $(TARGET_PATH)/tests/data/vsynth1.yuv +fate-mov-mp4-iamf-7_1_4-video-last: CMD = transcode wav $(SRC) mp4 "-auto_conversion_filters \ -/filter_complex $(TARGET_PATH)/tests/data/filtergraphs/iamf_7_1_4 \ -/stream_group $(TARGET_PATH)/tests/data/streamgroups/audio_element-7_1_4 \ -/stream_group $(TARGET_PATH)/tests/data/streamgroups/mix_presentation-7_1_4 \ - -streamid 0:0 -streamid 1:1 -streamid 2:2 -streamid 3:3 -streamid 4:4 -streamid 5:5 -streamid 6:6 -map [FRONT] -map [BACK] -map [CENTER] -map [LFE] -map [SIDE] -map [TOP_FRONT] -map [TOP_BACK] -c:a flac -t 1" "-c:a copy -map 0" \ - "-show_entries stream_group=index,id,nb_streams,type:stream_group_components:stream_group_disposition:stream_group_tags:stream_group_stream=index,id:stream_group_stream_disposition" + -streamid 0:1 -streamid 1:2 -streamid 2:3 -streamid 3:4 -streamid 4:5 -streamid 5:6 -streamid 6:7 -streamid 7:8 -map [FRONT] -map [BACK] -map [CENTER] -map [LFE] -map [SIDE] -map [TOP_FRONT] -map [TOP_BACK] -map 1:v:0 -use_stream_ids_as_track_ids true -c:a flac -c:v mpeg4 -t 1" "-c:a copy -c:v copy -map 0" \ + "-show_entries stream_group=index,id,nb_streams,type:stream_group_components:stream_group_disposition:stream_group_tags:stream_group_stream=index,id:stream_group_stream_disposition:stream=index,id" \ + "-f rawvideo -s 352x288 -pix_fmt yuv420p -i $(SRC2)" FATE_MOV_FFMPEG_FFPROBE-$(call TRANSCODE, FLAC, MOV, WAV_DEMUXER PCM_S16LE_DECODER ARESAMPLE_FILTER) += fate-mov-mp4-iamf-ambisonic_1 fate-mov-mp4-iamf-ambisonic_1: tests/data/asynth-44100-4.wav tests/data/filtergraphs/iamf_ambisonic_1 tests/data/streamgroups/audio_element-ambisonic_1 tests/data/streamgroups/mix_presentation-ambisonic_1 @@ -260,4 +281,4 @@ fate-mov-mp4-iamf-ambisonic_1: CMD = transcode wav $(SRC) mp4 "-auto_conversion_ FATE_FFMPEG += $(FATE_MOV_FFMPEG-yes) FATE_FFMPEG_FFPROBE += $(FATE_MOV_FFMPEG_FFPROBE-yes) -fate-mov: $(FATE_MOV) $(FATE_MOV_FFMPEG-yes) $(FATE_MOV_FFMPEG_FFPROBE-yes) $(FATE_MOV_FFPROBE) $(FATE_MOV_FASTSTART) $(FATE_MOV_FFMPEG_SAMPLES-yes) $(FATE_MOV_FFMPEG_FFPROBE_SAMPLES-yes) +fate-mov: $(FATE_MOV-yes) $(FATE_MOV_FFMPEG-yes) $(FATE_MOV_FFMPEG_FFPROBE-yes) $(FATE_MOV_FFPROBE-yes) $(FATE_MOV_FASTSTART) $(FATE_MOV_FFMPEG_SAMPLES-yes) $(FATE_MOV_FFMPEG_FFPROBE_SAMPLES-yes) diff --git a/tests/fate/seek.mak b/tests/fate/seek.mak index dfc2fa6a9..8751ffa86 100644 --- a/tests/fate/seek.mak +++ b/tests/fate/seek.mak @@ -183,10 +183,10 @@ FATE_SEEK += $(FATE_SEEK_LAVF_IMAGE2PIPE) FATE_SEEK_EXTRA-$(CONFIG_MP3_DEMUXER) += fate-seek-extra-mp3 FATE_SEEK_EXTRA-$(call ALLYES, CACHE_PROTOCOL PIPE_PROTOCOL MP3_DEMUXER) += fate-seek-cache-pipe FATE_SEEK_EXTRA-$(CONFIG_MATROSKA_DEMUXER) += fate-seek-mkv-codec-delay -FATE_SEEK_EXTRA-$(CONFIG_MOV_DEMUXER) += fate-seek-extra-mp4 -FATE_SEEK_EXTRA-$(CONFIG_MOV_DEMUXER) += fate-seek-empty-edit-mp4 -FATE_SEEK_EXTRA-$(CONFIG_MOV_DEMUXER) += fate-seek-test-iibbibb-mp4 -FATE_SEEK_EXTRA-$(CONFIG_MOV_DEMUXER) += fate-seek-test-iibbibb-neg-ctts-mp4 +FATE_SEEK_EXTRA-$(call ALLYES, MOV_DEMUXER FILE_PROTOCOL) += fate-seek-extra-mp4 +FATE_SEEK_EXTRA-$(call ALLYES, MOV_DEMUXER FILE_PROTOCOL) += fate-seek-empty-edit-mp4 +FATE_SEEK_EXTRA-$(call ALLYES, MOV_DEMUXER FILE_PROTOCOL) += fate-seek-test-iibbibb-mp4 +FATE_SEEK_EXTRA-$(call ALLYES, MOV_DEMUXER FILE_PROTOCOL) += fate-seek-test-iibbibb-neg-ctts-mp4 fate-seek-extra-mp3: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/gapless/gapless.mp3 -fastseek 1 fate-seek-extra-mp4: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/mov/buck480p30_na.mp4 -duration 180 -frames 4 diff --git a/tests/fate/source-check.sh b/tests/fate/source-check.sh index 658823fc0..4d7e17578 100755 --- a/tests/fate/source-check.sh +++ b/tests/fate/source-check.sh @@ -11,7 +11,7 @@ git grep -L -E "This file is part of FFmpeg|This file is part of libswresample|" "Permission is hereby granted to use, copy, modify, and distribute this|"\ "Permission is granted to anyone to use this software for any purpose|"\ "This work is licensed under the terms of the GNU GPL|"\ -"Redistribution and use in source and binary forms, with or without modification|"\ +"Redistribution and use in source and binary forms, with or without|"\ "This library is free software; you can redistribute it and/or|"\ "This program is free software; you can redistribute it and/or modify|"\ "Licensed under the Apache License|"\ diff --git a/tests/fate/vcodec.mak b/tests/fate/vcodec.mak index abdc481f8..463e9e34e 100644 --- a/tests/fate/vcodec.mak +++ b/tests/fate/vcodec.mak @@ -6,7 +6,7 @@ fate-vsynth%: CODEC = $(word 3, $(subst -, ,$(@))) fate-vsynth%: FMT = avi fate-vsynth%: DEFAULT_SIZE = -s 352x288 fate-vsynth3-%: DEFAULT_SIZE = -s $(FATEW)x$(FATEH) -fate-vsynth%: CMD = enc_dec "rawvideo $(DEFAULT_SIZE) -pix_fmt yuv420p $(RAWDECOPTS)" $(SRC) $(FMT) "-c $(CODEC) $(ENCOPTS)" rawvideo "-pix_fmt yuv420p -fps_mode passthrough $(DECOPTS)" "" "" ${TWOPASS} +fate-vsynth%: CMD = enc_dec "rawvideo $(DEFAULT_SIZE) -color_range mpeg -pix_fmt yuv420p $(RAWDECOPTS)" $(SRC) $(FMT) "-c $(CODEC) $(ENCOPTS)" rawvideo "-pix_fmt yuv420p -color_range mpeg -fps_mode passthrough $(DECOPTS)" "" "" ${TWOPASS} fate-vsynth%: CMP_UNIT = 1 fate-vsynth%: REF = $(SRC_PATH)/tests/ref/vsynth/$(@:fate-%=%) @@ -154,13 +154,14 @@ $(FATE_VCODEC_DV:%=fate-vsynth\%-%): CODEC = dvvideo $(FATE_VCODEC_DV:%=fate-vsynth\%-%): FMT = dv $(FATE_VCODEC_DV:%=fate-vsynth\%-%): DECOPTS += $(DEFAULT_SIZE) -FATE_VCODEC-$(call ENCDEC, FFV1, AVI) += ffv1 ffv1-v0 \ +FATE_VCODEC-$(call ENCDEC, FFV1, AVI) += ffv1 ffv1-v0 ffv1-v2 \ ffv1-v3-yuv420p \ ffv1-2pass FATE_VCODEC_SCALE-$(call ENCDEC, FFV1, AVI) += ffv1-v3-yuv422p10 ffv1-v3-yuv444p16 \ ffv1-v3-bgr0 ffv1-v3-rgb48 fate-vsynth%-ffv1: ENCOPTS = -slices 4 fate-vsynth%-ffv1-v0: CODEC = ffv1 +fate-vsynth%-ffv1-v2: ENCOPTS = -level 2 -strict experimental fate-vsynth%-ffv1-v3-yuv420p: ENCOPTS = -level 3 -pix_fmt yuv420p fate-vsynth%-ffv1-v3-yuv422p10: ENCOPTS = -level 3 -pix_fmt yuv422p10 \ -sws_flags neighbor+bitexact diff --git a/tests/fate/video.mak b/tests/fate/video.mak index 8f51a4207..9ad39e21e 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -48,7 +48,7 @@ FATE_VIDEO-$(call FRAMECRC, AVI, AVRN) += fate-avid-interlaced fate-avid-interlaced: CMD = framecrc -i $(TARGET_SAMPLES)/avid/avid_ntsc_interlaced.avi FATE_VIDEO-$(call FRAMECRC, MOV, MJPEG) += fate-avid-meridian -fate-avid-meridian: CMD = framecrc -i $(TARGET_SAMPLES)/avid/avidmeridianntsc.mov +fate-avid-meridian: CMD = framecrc -bitexact -i $(TARGET_SAMPLES)/avid/avidmeridianntsc.mov FATE_VIDEO-$(call FRAMECRC, BETHSOFTVID, BETHSOFTVID, ARESAMPLE_FILTER SCALE_FILTER) += fate-bethsoft-vid fate-bethsoft-vid: CMD = framecrc -i $(TARGET_SAMPLES)/bethsoft-vid/ANIM0001.VID -t 5 -pix_fmt rgb24 -vf scale -af aresample diff --git a/tests/fate/vvc.mak b/tests/fate/vvc.mak index d1bc8ef93..533546026 100644 --- a/tests/fate/vvc.mak +++ b/tests/fate/vvc.mak @@ -9,16 +9,19 @@ VVC_SAMPLES_10BIT = \ BUMP_A_2 \ DCI_A_3 \ HRD_A_3 \ + IBC_B_Tencent_2 \ PHSH_B_1 \ POC_A_1 \ PPS_B_1 \ RAP_A_1 \ + RPR_A_4 \ SAO_A_3 \ SCALING_A_1 \ SLICES_A_3 \ SPS_B_1 \ STILL_B_1 \ SUBPIC_A_3 \ + SUBPIC_C_ERICSSON_1 \ TILE_A_2 \ WP_A_3 \ WPP_A_3 \ @@ -38,7 +41,7 @@ $(foreach VAR,$(FATE_VVC_VARS), $(eval VVC_TESTS_$(VAR) := $(addprefix fate-vvc- $(VVC_TESTS_8BIT): SCALE_OPTS := -pix_fmt yuv420p $(VVC_TESTS_10BIT): SCALE_OPTS := -pix_fmt yuv420p10le -vf scale $(VVC_TESTS_444_10BIT): SCALE_OPTS := -pix_fmt yuv444p10le -vf scale -fate-vvc-conformance-%: CMD = framecrc -flags unaligned -c:v vvc -strict experimental -i $(TARGET_SAMPLES)/vvc-conformance/$(subst fate-vvc-conformance-,,$(@)).bit $(SCALE_OPTS) +fate-vvc-conformance-%: CMD = framecrc -c:v vvc -i $(TARGET_SAMPLES)/vvc-conformance/$(subst fate-vvc-conformance-,,$(@)).bit $(SCALE_OPTS) FATE_VVC-$(call FRAMECRC, VVC, VVC, VVC_PARSER) += $(VVC_TESTS_8BIT) FATE_VVC-$(call FRAMECRC, VVC, VVC, VVC_PARSER SCALE_FILTER) += \ diff --git a/tests/fate/wavpack.mak b/tests/fate/wavpack.mak index c684d93f9..41e1b0afa 100644 --- a/tests/fate/wavpack.mak +++ b/tests/fate/wavpack.mak @@ -18,6 +18,9 @@ fate-wavpack-lossless-32bit: CMD = md5pipe -i $(TARGET_SAMPLES)/wavpack/lossless FATE_WAVPACK_F32 += fate-wavpack-lossless-float fate-wavpack-lossless-float: CMD = md5pipe -i $(TARGET_SAMPLES)/wavpack/lossless/32bit_float-partial.wv -f f32le -af aresample +FATE_WAVPACK_F32 += fate-wavpack-lossless-dsd +fate-wavpack-lossless-dsd: CMD = md5pipe -i $(TARGET_SAMPLES)/wavpack/lossless/dsd.wv -f f32le -af aresample + # lossy FATE_WAVPACK_S8 += fate-wavpack-lossy-8bit diff --git a/tests/filtergraphs/crazychannels b/tests/filtergraphs/crazychannels new file mode 100644 index 000000000..e48da7267 --- /dev/null +++ b/tests/filtergraphs/crazychannels @@ -0,0 +1,79 @@ +sine=frequency=400 * 0x0 [s0]; +sine=frequency=400 * 0x1 [s1]; +sine=frequency=400 * 0x2 [s2]; +sine=frequency=400 * 0x3 [s3]; +sine=frequency=400 * 0x4 [s4]; +sine=frequency=400 * 0x5 [s5]; +sine=frequency=400 * 0x6 [s6]; +sine=frequency=400 * 0x7 [s7]; +sine=frequency=400 * 0x8 [s8]; +sine=frequency=400 * 0x9 [s9]; +sine=frequency=400 * 0xa [sa]; +sine=frequency=400 * 0xb [sb]; +sine=frequency=400 * 0xc [sc]; +sine=frequency=400 * 0xd [sd]; +sine=frequency=400 * 0xe [se]; +sine=frequency=400 * 0xf [sf]; + +sine=frequency=400 * 0x10 [s10]; +sine=frequency=400 * 0x11 [s11]; +sine=frequency=400 * 0x12 [s12]; +sine=frequency=400 * 0x13 [s13]; +sine=frequency=400 * 0x14 [s14]; +sine=frequency=400 * 0x15 [s15]; +sine=frequency=400 * 0x16 [s16]; +sine=frequency=400 * 0x17 [s17]; +sine=frequency=400 * 0x18 [s18]; +sine=frequency=400 * 0x19 [s19]; +sine=frequency=400 * 0x1a [s1a]; +sine=frequency=400 * 0x1b [s1b]; +sine=frequency=400 * 0x1c [s1c]; +sine=frequency=400 * 0x1d [s1d]; +sine=frequency=400 * 0x1e [s1e]; +sine=frequency=400 * 0x1f [s1f]; + +sine=frequency=400 * 0x20 [s20]; +sine=frequency=400 * 0x21 [s21]; +sine=frequency=400 * 0x22 [s22]; +sine=frequency=400 * 0x23 [s23]; +sine=frequency=400 * 0x24 [s24]; +sine=frequency=400 * 0x25 [s25]; +sine=frequency=400 * 0x26 [s26]; +sine=frequency=400 * 0x27 [s27]; +sine=frequency=400 * 0x28 [s28]; +sine=frequency=400 * 0x29 [s29]; +sine=frequency=400 * 0x2a [s2a]; +sine=frequency=400 * 0x2b [s2b]; +sine=frequency=400 * 0x2c [s2c]; +sine=frequency=400 * 0x2d [s2d]; +sine=frequency=400 * 0x2e [s2e]; +sine=frequency=400 * 0x2f [s2f]; + +sine=frequency=400 * 0x30 [s30]; +sine=frequency=400 * 0x31 [s31]; +sine=frequency=400 * 0x32 [s32]; +sine=frequency=400 * 0x33 [s33]; +sine=frequency=400 * 0x34 [s34]; +sine=frequency=400 * 0x35 [s35]; +sine=frequency=400 * 0x36 [s36]; +sine=frequency=400 * 0x37 [s37]; +sine=frequency=400 * 0x38 [s38]; +sine=frequency=400 * 0x39 [s39]; +sine=frequency=400 * 0x3a [s3a]; +sine=frequency=400 * 0x3b [s3b]; +sine=frequency=400 * 0x3c [s3c]; +sine=frequency=400 * 0x3d [s3d]; +sine=frequency=400 * 0x3e [s3e]; +sine=frequency=400 * 0x3f [s3f]; + +sine=frequency=400 * 0x40 [s40]; +sine=frequency=400 * 0x41 [s41]; + +[s0] [s1] [s2] [s3] [s4] [s5] [s6] [s7] [s8] [s9] [sa] [sb] [sc] [sd] [se] [sf] +[s10][s11][s12][s13][s14][s15][s16][s17] [s18][s19][s1a][s1b][s1c][s1d][s1e][s1f] +[s20][s21][s22][s23][s24][s25][s26][s27] [s28][s29][s2a][s2b][s2c][s2d][s2e][s2f] +[s30][s31][s32][s33][s34][s35][s36][s37] [s38][s39][s3a][s3b][s3c][s3d][s3e][s3f] +[s40][s41] join=inputs=0x42:channel_layout=ambisonic 7+stereo, +atrim=end_sample=1024, +channelmap=channel_layout=ambisonic 7+stereo:map=AMBI0-AMBI1|AMBI1-AMBI2|AMBI2-AMBI3|AMBI3-AMBI4|AMBI4-AMBI5|AMBI5-AMBI6|AMBI6-AMBI7|AMBI7-AMBI8|AMBI8-AMBI9|AMBI9-AMBI10|AMBI10-AMBI11|AMBI11-AMBI12|AMBI12-AMBI13|AMBI13-AMBI14|AMBI14-AMBI15|AMBI15-AMBI16|AMBI16-AMBI17|AMBI17-AMBI18|AMBI18-AMBI19|AMBI19-AMBI20|AMBI20-AMBI21|AMBI21-AMBI22|AMBI22-AMBI23|AMBI23-AMBI24|AMBI24-AMBI25|AMBI25-AMBI26|AMBI26-AMBI27|AMBI27-AMBI28|AMBI28-AMBI29|AMBI29-AMBI30|AMBI30-AMBI31|AMBI31-AMBI32|AMBI32-AMBI33|AMBI33-AMBI34|AMBI34-AMBI35|AMBI35-AMBI36|AMBI36-AMBI37|AMBI37-AMBI38|AMBI38-AMBI39|AMBI39-AMBI40|AMBI40-AMBI41|AMBI41-AMBI42|AMBI42-AMBI43|AMBI43-AMBI44|AMBI44-AMBI45|AMBI45-AMBI46|AMBI46-AMBI47|AMBI47-AMBI48|AMBI48-AMBI49|AMBI49-AMBI50|AMBI50-AMBI51|AMBI51-AMBI52|AMBI52-AMBI53|AMBI53-AMBI54|AMBI54-AMBI55|AMBI55-AMBI56|AMBI56-AMBI57|AMBI57-AMBI58|AMBI58-AMBI59|AMBI59-AMBI60|AMBI60-AMBI61|AMBI61-AMBI62|AMBI62-AMBI63|AMBI63-FL|FL-FR|FR-AMBI0, +channelsplit=channel_layout=ambisonic 7+stereo diff --git a/tests/filtergraphs/scale2ref_keep_aspect b/tests/filtergraphs/scale2ref_keep_aspect index f407460ec..00b04fc3d 100644 --- a/tests/filtergraphs/scale2ref_keep_aspect +++ b/tests/filtergraphs/scale2ref_keep_aspect @@ -1,5 +1,4 @@ sws_flags=+accurate_rnd+bitexact; testsrc=size=320x240 [main]; testsrc=size=640x360 [ref]; -[main][ref] scale2ref=iw/4:ow/mdar [main][ref]; -[ref] nullsink +[main][ref] scale=rw/4:ow/dar [main] diff --git a/tests/ref/fate/aic b/tests/ref/fate/aic index 244ea2596..30197129f 100644 --- a/tests/ref/fate/aic +++ b/tests/ref/fate/aic @@ -1,20 +1,20 @@ #tb 0: 100/2997 #media_type 0: video #codec_id 0: rawvideo -#dimensions 0: 1440x1080 +#dimensions 0: 1416x1062 #sar 0: 4/3 -0, 0, 0, 1, 2332800, 0xc22b8485 -0, 1, 1, 1, 2332800, 0xc22b8485 -0, 2, 2, 1, 2332800, 0xe0c21bd8 -0, 3, 3, 1, 2332800, 0x3e1a8fa0 -0, 4, 4, 1, 2332800, 0xbcb3f235 -0, 5, 5, 1, 2332800, 0x1a7cabd6 -0, 6, 6, 1, 2332800, 0xc0136ba8 -0, 7, 7, 1, 2332800, 0x295e59a6 -0, 8, 8, 1, 2332800, 0xf9c09288 -0, 9, 9, 1, 2332800, 0x0518cc8f -0, 10, 10, 1, 2332800, 0x9ad3068e -0, 11, 11, 1, 2332800, 0x5a8b7af1 -0, 12, 12, 1, 2332800, 0x7b35a8fa -0, 13, 13, 1, 2332800, 0xbe5801eb -0, 14, 14, 1, 2332800, 0x31ca019f +0, 0, 0, 1, 2255688, 0x48f3973d +0, 1, 1, 1, 2255688, 0x48f3973d +0, 2, 2, 1, 2255688, 0x8c9f3c83 +0, 3, 3, 1, 2255688, 0xb89c02e3 +0, 4, 4, 1, 2255688, 0x185b1a84 +0, 5, 5, 1, 2255688, 0x82167715 +0, 6, 6, 1, 2255688, 0xe675971e +0, 7, 7, 1, 2255688, 0x623759db +0, 8, 8, 1, 2255688, 0x910274ad +0, 9, 9, 1, 2255688, 0x0eafce15 +0, 10, 10, 1, 2255688, 0x4457b006 +0, 11, 11, 1, 2255688, 0x48f70e0b +0, 12, 12, 1, 2255688, 0xfd269c3d +0, 13, 13, 1, 2255688, 0x4c6258ad +0, 14, 14, 1, 2255688, 0xb131c4af diff --git a/tests/ref/fate/cavs-demux b/tests/ref/fate/cavs-demux index 016e40e78..059c8bd04 100644 --- a/tests/ref/fate/cavs-demux +++ b/tests/ref/fate/cavs-demux @@ -58,5 +58,5 @@ packet|codec_type=video|stream_index=0|pts=2280000|pts_time=1.900000|dts=2280000 packet|codec_type=video|stream_index=0|pts=2320000|pts_time=1.933333|dts=2320000|dts_time=1.933333|duration=40000|duration_time=0.033333|size=67|pos=172185|flags=K__|data_hash=CRC32:42484449 packet|codec_type=video|stream_index=0|pts=2360000|pts_time=1.966667|dts=2360000|dts_time=1.966667|duration=40000|duration_time=0.033333|size=83|pos=172252|flags=K__|data_hash=CRC32:a941bdf0 packet|codec_type=video|stream_index=0|pts=2400000|pts_time=2.000000|dts=2400000|dts_time=2.000000|duration=40000|duration_time=0.033333|size=5417|pos=172335|flags=K__|data_hash=CRC32:9d0d503b -stream|index=0|codec_name=cavs|profile=unknown|codec_type=video|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|width=1280|height=720|coded_width=1280|coded_height=720|closed_captions=0|film_grain=0|has_b_frames=0|sample_aspect_ratio=N/A|display_aspect_ratio=N/A|pix_fmt=yuv420p|level=-99|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|field_order=unknown|refs=1|id=N/A|r_frame_rate=30/1|avg_frame_rate=25/1|time_base=1/1200000|start_pts=N/A|start_time=N/A|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=60|extradata_size=18|extradata_hash=CRC32:1255d52e|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0 +stream|index=0|codec_name=cavs|profile=unknown|codec_type=video|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|width=1280|height=720|coded_width=1280|coded_height=720|closed_captions=0|film_grain=0|has_b_frames=0|sample_aspect_ratio=N/A|display_aspect_ratio=N/A|pix_fmt=yuv420p|level=-99|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|field_order=unknown|refs=1|id=N/A|r_frame_rate=30/1|avg_frame_rate=25/1|time_base=1/1200000|start_pts=N/A|start_time=N/A|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=60|extradata_size=18|extradata_hash=CRC32:1255d52e|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0 format|filename=bunny.mp4|nb_streams=1|nb_programs=0|nb_stream_groups=0|format_name=cavsvideo|start_time=N/A|duration=N/A|size=177752|bit_rate=N/A|probe_score=51 diff --git a/tests/ref/fate/concat-demuxer-extended-lavf-mxf b/tests/ref/fate/concat-demuxer-extended-lavf-mxf index 1f1b45444..1644c7ebd 100644 --- a/tests/ref/fate/concat-demuxer-extended-lavf-mxf +++ b/tests/ref/fate/concat-demuxer-extended-lavf-mxf @@ -1 +1 @@ -6a6f9fb967044be939c345268cadd7bb *tests/data/fate/concat-demuxer-extended-lavf-mxf.ffprobe +0e6abc213a400c770c68a32e2144e89a *tests/data/fate/concat-demuxer-extended-lavf-mxf.ffprobe diff --git a/tests/ref/fate/concat-demuxer-extended-lavf-mxf_d10 b/tests/ref/fate/concat-demuxer-extended-lavf-mxf_d10 index 93e484612..ad7db04d4 100644 --- a/tests/ref/fate/concat-demuxer-extended-lavf-mxf_d10 +++ b/tests/ref/fate/concat-demuxer-extended-lavf-mxf_d10 @@ -1 +1 @@ -05f815e1f45f85456d87030a5c36ebad *tests/data/fate/concat-demuxer-extended-lavf-mxf_d10.ffprobe +c2477f9b9682ff679e0aba4135da321e *tests/data/fate/concat-demuxer-extended-lavf-mxf_d10.ffprobe diff --git a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf index c1afcf71e..4c9fad3bc 100644 --- a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf +++ b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf @@ -99,5 +99,5 @@ audio|1|63360|1.320000|63360|1.320000|1920|0.040000|3840|190464|K__|1|Strings Me video|0|33|1.320000|33|1.320000|1|0.040000|12362|195072|___|1|Strings Metadata audio|1|65280|1.360000|65280|1.360000|1920|0.040000|3840|207872|K__|1|Strings Metadata video|0|37|1.480000|34|1.360000|1|0.040000|24786|212480|K__|1|Strings Metadata -0|mpeg2video|4|video|[0][0][0][0]|0x0000|352|288|0|0|0|0|1|1:1|11:9|yuv420p|8|tv|unknown|unknown|unknown|left|progressive|1|N/A|25/1|25/1|1/25|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|51|22|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001|CPB properties|0|0|0|49152|-1 -1|pcm_s16le|unknown|audio|[0][0][0][0]|0x0000|s16|48000|1|unknown|16|0|N/A|0/0|0/0|1/48000|0|0.000000|N/A|N/A|768000|N/A|N/A|N/A|N/A|50|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001 +0|mpeg2video|4|video|[0][0][0][0]|0x0000|352|288|0|0|0|0|1|1:1|11:9|yuv420p|8|tv|unknown|unknown|unknown|left|progressive|1|N/A|25/1|25/1|1/25|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|51|22|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001|CPB properties|0|0|0|49152|-1 +1|pcm_s16le|unknown|audio|[0][0][0][0]|0x0000|s16|48000|1|unknown|16|0|N/A|0/0|0/0|1/48000|0|0.000000|N/A|N/A|768000|N/A|N/A|N/A|N/A|50|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001 diff --git a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10 b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10 index a8f2dfe3f..74c32e9dc 100644 --- a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10 +++ b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10 @@ -68,5 +68,5 @@ video|0|33|1.320000|33|1.320000|1|0.040000|150000|1711104|K__|1|Strings Metadata audio|1|63360|1.320000|63360|1.320000|1920|0.040000|7680|1861632|K__|1|Strings Metadata video|0|34|1.360000|34|1.360000|1|0.040000|150000|1924096|K__|1|Strings Metadata audio|1|65280|1.360000|65280|1.360000|1920|0.040000|7680|2074624|K__|1|Strings Metadata -0|mpeg2video|0|video|[0][0][0][0]|0x0000|720|608|0|0|0|0|0|1:1|45:38|yuv422p|5|tv|unknown|unknown|unknown|topleft|tt|1|N/A|25/1|25/1|1/25|0|0.000000|N/A|N/A|30000000|N/A|N/A|N/A|N/A|35|22|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001|CPB properties|30000000|0|0|1212416|-1 -1|pcm_s16le|unknown|audio|[0][0][0][0]|0x0000|s16|48000|2|unknown|16|0|N/A|0/0|0/0|1/48000|0|0.000000|N/A|N/A|1536000|N/A|N/A|N/A|N/A|35|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001 +0|mpeg2video|0|video|[0][0][0][0]|0x0000|720|608|0|0|0|0|0|1:1|45:38|yuv422p|5|tv|unknown|unknown|unknown|topleft|tt|1|N/A|25/1|25/1|1/25|0|0.000000|N/A|N/A|30000000|N/A|N/A|N/A|N/A|35|22|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001|CPB properties|30000000|0|0|1212416|-1 +1|pcm_s16le|unknown|audio|[0][0][0][0]|0x0000|s16|48000|2|unknown|16|0|N/A|0/0|0/0|1/48000|0|0.000000|N/A|N/A|1536000|N/A|N/A|N/A|N/A|35|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001 diff --git a/tests/ref/fate/concat-demuxer-simple2-lavf-ts b/tests/ref/fate/concat-demuxer-simple2-lavf-ts index 548cab01c..30447f7fc 100644 --- a/tests/ref/fate/concat-demuxer-simple2-lavf-ts +++ b/tests/ref/fate/concat-demuxer-simple2-lavf-ts @@ -147,5 +147,5 @@ video|1|164782|1.830911|161182|1.790911|3600|0.040000|12282|168448|___|MPEGTS St video|1|168382|1.870911|164782|1.830911|3600|0.040000|24786|181420|K__|MPEGTS Stream ID|224 video|1|171982|1.910911|168382|1.870911|3600|0.040000|17440|206988|___|MPEGTS Stream ID|224 video|1|175582|1.950911|171982|1.910911|3600|0.040000|15019|224848|___|MPEGTS Stream ID|224 -0|mp2|unknown|audio|[3][0][0][0]|0x0003|s16p|44100|1|mono|0|0|N/A|0/0|0/0|1/90000|0|0.000000|N/A|N/A|64000|N/A|N/A|N/A|N/A|89|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|this is stream 0 -1|mpeg2video|4|video|[2][0][0][0]|0x0002|352|288|0|0|0|0|1|1:1|11:9|yuv420p|8|tv|unknown|unknown|unknown|left|progressive|1|N/A|25/1|25/1|1/90000|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|60|22|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|this is stream 1|CPB properties|0|0|0|49152|-1 +0|mp2|unknown|audio|[3][0][0][0]|0x0003|s16p|44100|1|mono|0|0|N/A|0/0|0/0|1/90000|0|0.000000|N/A|N/A|64000|N/A|N/A|N/A|N/A|89|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|this is stream 0 +1|mpeg2video|4|video|[2][0][0][0]|0x0002|352|288|0|0|0|0|1|1:1|11:9|yuv420p|8|tv|unknown|unknown|unknown|left|progressive|1|N/A|25/1|25/1|1/90000|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|60|22|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|this is stream 1|CPB properties|0|0|0|49152|-1 diff --git a/tests/ref/fate/copy-trac236 b/tests/ref/fate/copy-trac236 index 5a9e08ad0..c89649e95 100644 --- a/tests/ref/fate/copy-trac236 +++ b/tests/ref/fate/copy-trac236 @@ -1,24 +1,24 @@ -34b0ad38518b0eb8464aff04e6d0e143 *tests/data/fate/copy-trac236.mov -630878 tests/data/fate/copy-trac236.mov +ca4068319c6586de757c1f6a592b31e5 *tests/data/fate/copy-trac236.mov +630918 tests/data/fate/copy-trac236.mov #tb 0: 100/2997 #media_type 0: video #codec_id 0: rawvideo -#dimensions 0: 720x480 +#dimensions 0: 704x480 #sar 0: 10/11 #tb 1: 1/48000 #media_type 1: audio #codec_id 1: pcm_s16le #sample_rate 1: 48000 #channel_layout_name 1: stereo -0, 0, 0, 1, 518400, 0x81ab2140 +0, 0, 0, 1, 506880, 0xc4d654e3 1, 0, 0, 1024, 4096, 0x67dc99a3 1, 1024, 1024, 1024, 4096, 0xf115a681 -0, 1, 1, 1, 518400, 0x81ab2140 +0, 1, 1, 1, 506880, 0xc4d654e3 1, 2048, 2048, 1024, 4096, 0xf455b597 1, 3072, 3072, 1024, 4096, 0x67dc99a3 -0, 2, 2, 1, 518400, 0x81ab2140 +0, 2, 2, 1, 506880, 0xc4d654e3 1, 4096, 4096, 1024, 4096, 0xf115a681 -0, 3, 3, 1, 518400, 0x81ab2140 +0, 3, 3, 1, 506880, 0xc4d654e3 1, 5120, 5120, 1024, 4096, 0xf455b597 1, 6144, 6144, 759, 3036, 0xa291a36d -0, 4, 4, 1, 518400, 0x81ab2140 +0, 4, 4, 1, 506880, 0xc4d654e3 diff --git a/tests/ref/fate/copy-trac4914-avi b/tests/ref/fate/copy-trac4914-avi index 20006ea05..d598e0aa6 100644 --- a/tests/ref/fate/copy-trac4914-avi +++ b/tests/ref/fate/copy-trac4914-avi @@ -1,5 +1,5 @@ -26e4202638bc384b82d2b5eb4d33a5f0 *tests/data/fate/copy-trac4914-avi.avi -479494 tests/data/fate/copy-trac4914-avi.avi +3b6f31b806ef421652a066f239536b0d *tests/data/fate/copy-trac4914-avi.avi +492046 tests/data/fate/copy-trac4914-avi.avi #tb 0: 1001/30000 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/fate/enhanced-flv-hevc b/tests/ref/fate/enhanced-flv-hevc index f011d38a3..f04905d06 100644 --- a/tests/ref/fate/enhanced-flv-hevc +++ b/tests/ref/fate/enhanced-flv-hevc @@ -1,6 +1,6 @@ -0da54607064548fa1aae5695751f189c *tests/data/fate/enhanced-flv-hevc.flv +565cf155790db391137f81f619448477 *tests/data/fate/enhanced-flv-hevc.flv 3603038 tests/data/fate/enhanced-flv-hevc.flv -#extradata 0: 551, 0xa18acf66 +#extradata 0: 551, 0xb1ddcd66 #extradata 1: 2, 0x00340022 #tb 0: 1/1000 #media_type 0: video diff --git a/tests/ref/fate/exif-image-tiff b/tests/ref/fate/exif-image-tiff index 887c039df..f5ff4dc16 100644 --- a/tests/ref/fate/exif-image-tiff +++ b/tests/ref/fate/exif-image-tiff @@ -20,7 +20,7 @@ crop_left=0 crop_right=0 pix_fmt=rgb24 sample_aspect_ratio=1:1 -pict_type=? +pict_type=I interlaced_frame=0 top_field_first=0 repeat_pict=0 diff --git a/tests/ref/fate/ffmpeg-spec-disposition b/tests/ref/fate/ffmpeg-spec-disposition new file mode 100644 index 000000000..4f24619d2 --- /dev/null +++ b/tests/ref/fate/ffmpeg-spec-disposition @@ -0,0 +1,7 @@ +#tb 0: 1/90000 +#media_type 0: audio +#codec_id 0: ac3 +#sample_rate 0: 48000 +#channel_layout_name 0: stereo +0, 0, 0, 2880, 768, 0x72b37931, F=0x3, S=1, 1 +0, 2880, 2880, 2880, 690, 0xa84a4ea2 diff --git a/tests/ref/fate/ffprobe_compact b/tests/ref/fate/ffprobe_compact index 3cda8550d..25632fd17 100644 --- a/tests/ref/fate/ffprobe_compact +++ b/tests/ref/fate/ffprobe_compact @@ -26,7 +26,7 @@ packet|codec_type=video|stream_index=1|pts=6144|pts_time=0.120000|dts=6144|dts_t frame|media_type=video|stream_index=1|key_frame=1|pts=6144|pts_time=0.120000|pkt_dts=6144|pkt_dts_time=0.120000|best_effort_timestamp=6144|best_effort_timestamp_time=0.120000|duration=2048|duration_time=0.040000|pkt_pos=793142|pkt_size=230400|width=320|height=240|crop_top=0|crop_bottom=0|crop_left=0|crop_right=0|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=unknown|color_space=unknown|color_primaries=unknown|color_transfer=unknown|chroma_location=unspecified packet|codec_type=video|stream_index=2|pts=6144|pts_time=0.120000|dts=6144|dts_time=0.120000|duration=2048|duration_time=0.040000|size=30000|pos=1023566|flags=K__ frame|media_type=video|stream_index=2|key_frame=1|pts=6144|pts_time=0.120000|pkt_dts=6144|pkt_dts_time=0.120000|best_effort_timestamp=6144|best_effort_timestamp_time=0.120000|duration=2048|duration_time=0.040000|pkt_pos=1023566|pkt_size=30000|width=100|height=100|crop_top=0|crop_bottom=0|crop_left=0|crop_right=0|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=unknown|color_space=unknown|color_primaries=unknown|color_transfer=unknown|chroma_location=unspecified -stream|index=0|codec_name=pcm_s16le|profile=unknown|codec_type=audio|codec_tag_string=PSD[16]|codec_tag=0x10445350|sample_fmt=s16|sample_rate=44100|channels=1|channel_layout=unknown|bits_per_sample=16|initial_padding=0|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/44100|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=705600|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=6|nb_read_packets=6|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|tag:E=mc²|tag:encoder=Lavc pcm_s16le -stream|index=1|codec_name=rawvideo|profile=unknown|codec_type=video|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=320|height=240|coded_width=320|coded_height=240|closed_captions=0|film_grain=0|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=4:3|pix_fmt=rgb24|level=-99|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|field_order=unknown|refs=1|id=N/A|r_frame_rate=25/1|avg_frame_rate=25/1|time_base=1/51200|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=4|nb_read_packets=4|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|tag:title=foobar|tag:duration_ts=field-and-tags-conflict-attempt|tag:encoder=Lavc rawvideo -stream|index=2|codec_name=rawvideo|profile=unknown|codec_type=video|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=100|height=100|coded_width=100|coded_height=100|closed_captions=0|film_grain=0|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=1:1|pix_fmt=rgb24|level=-99|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|field_order=unknown|refs=1|id=N/A|r_frame_rate=25/1|avg_frame_rate=25/1|time_base=1/51200|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=4|nb_read_packets=4|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|tag:encoder=Lavc rawvideo +stream|index=0|codec_name=pcm_s16le|profile=unknown|codec_type=audio|codec_tag_string=PSD[16]|codec_tag=0x10445350|sample_fmt=s16|sample_rate=44100|channels=1|channel_layout=unknown|bits_per_sample=16|initial_padding=0|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/44100|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=705600|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=6|nb_read_packets=6|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:E=mc²|tag:encoder=Lavc pcm_s16le +stream|index=1|codec_name=rawvideo|profile=unknown|codec_type=video|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=320|height=240|coded_width=320|coded_height=240|closed_captions=0|film_grain=0|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=4:3|pix_fmt=rgb24|level=-99|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|field_order=unknown|refs=1|id=N/A|r_frame_rate=25/1|avg_frame_rate=25/1|time_base=1/51200|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=4|nb_read_packets=4|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:title=foobar|tag:duration_ts=field-and-tags-conflict-attempt|tag:encoder=Lavc rawvideo +stream|index=2|codec_name=rawvideo|profile=unknown|codec_type=video|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=100|height=100|coded_width=100|coded_height=100|closed_captions=0|film_grain=0|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=1:1|pix_fmt=rgb24|level=-99|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|field_order=unknown|refs=1|id=N/A|r_frame_rate=25/1|avg_frame_rate=25/1|time_base=1/51200|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=4|nb_read_packets=4|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:encoder=Lavc rawvideo format|filename=tests/data/ffprobe-test.nut|nb_streams=3|nb_programs=0|nb_stream_groups=0|format_name=nut|start_time=0.000000|duration=0.120000|size=1053646|bit_rate=70243066|probe_score=100|tag:title=ffprobe test file|tag:comment='A comment with CSV, XML & JSON special chars': |tag:comment2=I ♥ Üñîçød€ diff --git a/tests/ref/fate/ffprobe_csv b/tests/ref/fate/ffprobe_csv index 5dcb40315..defe72d4c 100644 --- a/tests/ref/fate/ffprobe_csv +++ b/tests/ref/fate/ffprobe_csv @@ -26,7 +26,7 @@ packet,video,1,6144,0.120000,6144,0.120000,2048,0.040000,230400,793142,K__ frame,video,1,1,6144,0.120000,6144,0.120000,6144,0.120000,2048,0.040000,793142,230400,320,240,0,0,0,0,rgb24,1:1,I,0,0,0,unknown,unknown,unknown,unknown,unspecified packet,video,2,6144,0.120000,6144,0.120000,2048,0.040000,30000,1023566,K__ frame,video,2,1,6144,0.120000,6144,0.120000,6144,0.120000,2048,0.040000,1023566,30000,100,100,0,0,0,0,rgb24,1:1,I,0,0,0,unknown,unknown,unknown,unknown,unspecified -stream,0,pcm_s16le,unknown,audio,PSD[16],0x10445350,s16,44100,1,unknown,16,0,N/A,0/0,0/0,1/44100,0,0.000000,N/A,N/A,705600,N/A,N/A,N/A,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,mc²,Lavc pcm_s16le -stream,1,rawvideo,unknown,video,RGB[24],0x18424752,320,240,320,240,0,0,0,1:1,4:3,rgb24,-99,unknown,unknown,unknown,unknown,unspecified,unknown,1,N/A,25/1,25/1,1/51200,0,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,4,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,foobar,field-and-tags-conflict-attempt,Lavc rawvideo -stream,2,rawvideo,unknown,video,RGB[24],0x18424752,100,100,100,100,0,0,0,1:1,1:1,rgb24,-99,unknown,unknown,unknown,unknown,unspecified,unknown,1,N/A,25/1,25/1,1/51200,0,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Lavc rawvideo +stream,0,pcm_s16le,unknown,audio,PSD[16],0x10445350,s16,44100,1,unknown,16,0,N/A,0/0,0/0,1/44100,0,0.000000,N/A,N/A,705600,N/A,N/A,N/A,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,mc²,Lavc pcm_s16le +stream,1,rawvideo,unknown,video,RGB[24],0x18424752,320,240,320,240,0,0,0,1:1,4:3,rgb24,-99,unknown,unknown,unknown,unknown,unspecified,unknown,1,N/A,25/1,25/1,1/51200,0,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,4,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,foobar,field-and-tags-conflict-attempt,Lavc rawvideo +stream,2,rawvideo,unknown,video,RGB[24],0x18424752,100,100,100,100,0,0,0,1:1,1:1,rgb24,-99,unknown,unknown,unknown,unknown,unspecified,unknown,1,N/A,25/1,25/1,1/51200,0,0.000000,N/A,N/A,N/A,N/A,N/A,N/A,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Lavc rawvideo format,tests/data/ffprobe-test.nut,3,0,0,nut,0.000000,0.120000,1053646,70243066,100,ffprobe test file,"'A comment with CSV, XML & JSON special chars': ",I ♥ Üñîçød€ diff --git a/tests/ref/fate/ffprobe_default b/tests/ref/fate/ffprobe_default index 74c70e55d..ac5574929 100644 --- a/tests/ref/fate/ffprobe_default +++ b/tests/ref/fate/ffprobe_default @@ -595,6 +595,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:E=mc² TAG:encoder=Lavc pcm_s16le [/STREAM] @@ -655,6 +656,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:title=foobar TAG:duration_ts=field-and-tags-conflict-attempt TAG:encoder=Lavc rawvideo @@ -716,6 +718,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:encoder=Lavc rawvideo [/STREAM] [FORMAT] diff --git a/tests/ref/fate/ffprobe_flat b/tests/ref/fate/ffprobe_flat index 5a858aab8..e1aefe6af 100644 --- a/tests/ref/fate/ffprobe_flat +++ b/tests/ref/fate/ffprobe_flat @@ -538,6 +538,7 @@ streams.stream.0.disposition.descriptions=0 streams.stream.0.disposition.metadata=0 streams.stream.0.disposition.dependent=0 streams.stream.0.disposition.still_image=0 +streams.stream.0.disposition.multilayer=0 streams.stream.0.tags.E="mc²" streams.stream.0.tags.encoder="Lavc pcm_s16le" streams.stream.1.index=1 @@ -596,6 +597,7 @@ streams.stream.1.disposition.descriptions=0 streams.stream.1.disposition.metadata=0 streams.stream.1.disposition.dependent=0 streams.stream.1.disposition.still_image=0 +streams.stream.1.disposition.multilayer=0 streams.stream.1.tags.title="foobar" streams.stream.1.tags.duration_ts="field-and-tags-conflict-attempt" streams.stream.1.tags.encoder="Lavc rawvideo" @@ -655,6 +657,7 @@ streams.stream.2.disposition.descriptions=0 streams.stream.2.disposition.metadata=0 streams.stream.2.disposition.dependent=0 streams.stream.2.disposition.still_image=0 +streams.stream.2.disposition.multilayer=0 streams.stream.2.tags.encoder="Lavc rawvideo" format.filename="tests/data/ffprobe-test.nut" format.nb_streams=3 diff --git a/tests/ref/fate/ffprobe_ini b/tests/ref/fate/ffprobe_ini index 674077595..4d046539d 100644 --- a/tests/ref/fate/ffprobe_ini +++ b/tests/ref/fate/ffprobe_ini @@ -599,6 +599,7 @@ descriptions=0 metadata=0 dependent=0 still_image=0 +multilayer=0 [streams.stream.0.tags] E=mc² @@ -663,6 +664,7 @@ descriptions=0 metadata=0 dependent=0 still_image=0 +multilayer=0 [streams.stream.1.tags] title=foobar @@ -728,6 +730,7 @@ descriptions=0 metadata=0 dependent=0 still_image=0 +multilayer=0 [streams.stream.2.tags] encoder=Lavc rawvideo diff --git a/tests/ref/fate/ffprobe_json b/tests/ref/fate/ffprobe_json index 9de2f646e..5583063eb 100644 --- a/tests/ref/fate/ffprobe_json +++ b/tests/ref/fate/ffprobe_json @@ -573,7 +573,8 @@ "descriptions": 0, "metadata": 0, "dependent": 0, - "still_image": 0 + "still_image": 0, + "multilayer": 0 }, "tags": { "E": "mc²", @@ -623,7 +624,8 @@ "descriptions": 0, "metadata": 0, "dependent": 0, - "still_image": 0 + "still_image": 0, + "multilayer": 0 }, "tags": { "title": "foobar", @@ -674,7 +676,8 @@ "descriptions": 0, "metadata": 0, "dependent": 0, - "still_image": 0 + "still_image": 0, + "multilayer": 0 }, "tags": { "encoder": "Lavc rawvideo" diff --git a/tests/ref/fate/ffprobe_xml b/tests/ref/fate/ffprobe_xml index 988cfe5f3..3b4112190 100644 --- a/tests/ref/fate/ffprobe_xml +++ b/tests/ref/fate/ffprobe_xml @@ -33,14 +33,14 @@ - + - + @@ -48,7 +48,7 @@ - + diff --git a/tests/ref/fate/ffprobe_xsd b/tests/ref/fate/ffprobe_xsd index c37bb8a22..d5eb0a3a4 100644 --- a/tests/ref/fate/ffprobe_xsd +++ b/tests/ref/fate/ffprobe_xsd @@ -33,14 +33,14 @@ - + - + @@ -48,7 +48,7 @@ - + diff --git a/tests/ref/fate/filter-atempo b/tests/ref/fate/filter-atempo new file mode 100644 index 000000000..abedfcd61 --- /dev/null +++ b/tests/ref/fate/filter-atempo @@ -0,0 +1,70 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout_name 0: mono +0, 0, 0, 2048, 4096, 0x9c4dffa9 +0, 2048, 2048, 2048, 4096, 0x3a11f3f6 +0, 4096, 4096, 2048, 4096, 0x9835f5a5 +0, 6144, 6144, 2048, 4096, 0x7fe7e8ab +0, 8192, 8192, 2048, 4096, 0x9450f26b +0, 10240, 10240, 2048, 4096, 0x8f95ff6a +0, 12288, 12288, 2048, 4096, 0xc9deebab +0, 14336, 14336, 2048, 4096, 0x0229ec6c +0, 16384, 16384, 2048, 4096, 0xb1b00a8c +0, 18432, 18432, 2048, 4096, 0x43e7f197 +0, 20480, 20480, 2048, 4096, 0x60580ec1 +0, 22528, 22528, 2048, 4096, 0x1a4f084c +0, 24576, 24576, 2048, 4096, 0x70d20213 +0, 26624, 26624, 2048, 4096, 0xaf9afc70 +0, 28672, 28672, 2048, 4096, 0x1212df6f +0, 30720, 30720, 2048, 4096, 0x37a8f35a +0, 32768, 32768, 2048, 4096, 0x4730f0ee +0, 34816, 34816, 2048, 4096, 0x1fe1efd8 +0, 36864, 36864, 2048, 4096, 0xdfc4149e +0, 38912, 38912, 2048, 4096, 0xe288ffd1 +0, 40960, 40960, 2048, 4096, 0xee7b0829 +0, 43008, 43008, 2048, 4096, 0xb20df4aa +0, 45056, 45056, 2048, 4096, 0x0564f254 +0, 47104, 47104, 2048, 4096, 0x92daf362 +0, 49152, 49152, 2048, 4096, 0xaab3f18b +0, 51200, 51200, 2048, 4096, 0xe2bdfcb4 +0, 53248, 53248, 2048, 4096, 0x706adab4 +0, 55296, 55296, 2048, 4096, 0x141a075b +0, 57344, 57344, 2048, 4096, 0x87aad71f +0, 59392, 59392, 2048, 4096, 0xfafd0233 +0, 61440, 61440, 2048, 4096, 0x74b1cb64 +0, 63488, 63488, 2048, 4096, 0x9ffee659 +0, 65536, 65536, 2048, 4096, 0x50dde96c +0, 67584, 67584, 2048, 4096, 0xa4f5fc36 +0, 69632, 69632, 2048, 4096, 0xd40ff139 +0, 71680, 71680, 2048, 4096, 0xe93fe12a +0, 73728, 73728, 2048, 4096, 0x747f05da +0, 75776, 75776, 2048, 4096, 0x902601d7 +0, 77824, 77824, 2048, 4096, 0xee871089 +0, 79872, 79872, 2048, 4096, 0x8fba09ee +0, 81920, 81920, 2048, 4096, 0x832afdea +0, 83968, 83968, 2048, 4096, 0x7224ec15 +0, 86016, 86016, 2048, 4096, 0xf7def9f4 +0, 88064, 88064, 2048, 4096, 0x3c8af149 +0, 90112, 90112, 2048, 4096, 0x1dc1dfcf +0, 92160, 92160, 2048, 4096, 0x8ef51140 +0, 94208, 94208, 2048, 4096, 0x4b200588 +0, 96256, 96256, 2048, 4096, 0x29e9be20 +0, 98304, 98304, 2048, 4096, 0x8298f08a +0, 100352, 100352, 2048, 4096, 0xae5ef3b3 +0, 102400, 102400, 2048, 4096, 0xa76cfbe3 +0, 104448, 104448, 2048, 4096, 0xf784fdb0 +0, 106496, 106496, 2048, 4096, 0xea70f93e +0, 108544, 108544, 2048, 4096, 0xea5ffc00 +0, 110592, 110592, 2048, 4096, 0x6c2f0350 +0, 112640, 112640, 2048, 4096, 0x5f94cf81 +0, 114688, 114688, 2048, 4096, 0x2f28fda2 +0, 116736, 116736, 2048, 4096, 0x3db0fc68 +0, 118784, 118784, 2048, 4096, 0x15bc0c1f +0, 120832, 120832, 2048, 4096, 0x48840656 +0, 122880, 122880, 2048, 4096, 0xdf70ee6e +0, 124928, 124928, 2048, 4096, 0x2dece83a +0, 126976, 126976, 2048, 4096, 0x1e52cdf5 +0, 129024, 129024, 2048, 4096, 0x27ebc5af +0, 131072, 131072, 1368, 2736, 0xebfc5933 diff --git a/tests/ref/fate/filter-crazychannels b/tests/ref/fate/filter-crazychannels new file mode 100644 index 000000000..db4e63a83 --- /dev/null +++ b/tests/ref/fate/filter-crazychannels @@ -0,0 +1,396 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout_name 0: ambisonic 0 +#tb 1: 1/44100 +#media_type 1: audio +#codec_id 1: pcm_s16le +#sample_rate 1: 44100 +#channel_layout_name 1: 1 channels (AMBI1) +#tb 2: 1/44100 +#media_type 2: audio +#codec_id 2: pcm_s16le +#sample_rate 2: 44100 +#channel_layout_name 2: 1 channels (AMBI2) +#tb 3: 1/44100 +#media_type 3: audio +#codec_id 3: pcm_s16le +#sample_rate 3: 44100 +#channel_layout_name 3: 1 channels (AMBI3) +#tb 4: 1/44100 +#media_type 4: audio +#codec_id 4: pcm_s16le +#sample_rate 4: 44100 +#channel_layout_name 4: 1 channels (AMBI4) +#tb 5: 1/44100 +#media_type 5: audio +#codec_id 5: pcm_s16le +#sample_rate 5: 44100 +#channel_layout_name 5: 1 channels (AMBI5) +#tb 6: 1/44100 +#media_type 6: audio +#codec_id 6: pcm_s16le +#sample_rate 6: 44100 +#channel_layout_name 6: 1 channels (AMBI6) +#tb 7: 1/44100 +#media_type 7: audio +#codec_id 7: pcm_s16le +#sample_rate 7: 44100 +#channel_layout_name 7: 1 channels (AMBI7) +#tb 8: 1/44100 +#media_type 8: audio +#codec_id 8: pcm_s16le +#sample_rate 8: 44100 +#channel_layout_name 8: 1 channels (AMBI8) +#tb 9: 1/44100 +#media_type 9: audio +#codec_id 9: pcm_s16le +#sample_rate 9: 44100 +#channel_layout_name 9: 1 channels (AMBI9) +#tb 10: 1/44100 +#media_type 10: audio +#codec_id 10: pcm_s16le +#sample_rate 10: 44100 +#channel_layout_name 10: 1 channels (AMBI10) +#tb 11: 1/44100 +#media_type 11: audio +#codec_id 11: pcm_s16le +#sample_rate 11: 44100 +#channel_layout_name 11: 1 channels (AMBI11) +#tb 12: 1/44100 +#media_type 12: audio +#codec_id 12: pcm_s16le +#sample_rate 12: 44100 +#channel_layout_name 12: 1 channels (AMBI12) +#tb 13: 1/44100 +#media_type 13: audio +#codec_id 13: pcm_s16le +#sample_rate 13: 44100 +#channel_layout_name 13: 1 channels (AMBI13) +#tb 14: 1/44100 +#media_type 14: audio +#codec_id 14: pcm_s16le +#sample_rate 14: 44100 +#channel_layout_name 14: 1 channels (AMBI14) +#tb 15: 1/44100 +#media_type 15: audio +#codec_id 15: pcm_s16le +#sample_rate 15: 44100 +#channel_layout_name 15: 1 channels (AMBI15) +#tb 16: 1/44100 +#media_type 16: audio +#codec_id 16: pcm_s16le +#sample_rate 16: 44100 +#channel_layout_name 16: 1 channels (AMBI16) +#tb 17: 1/44100 +#media_type 17: audio +#codec_id 17: pcm_s16le +#sample_rate 17: 44100 +#channel_layout_name 17: 1 channels (AMBI17) +#tb 18: 1/44100 +#media_type 18: audio +#codec_id 18: pcm_s16le +#sample_rate 18: 44100 +#channel_layout_name 18: 1 channels (AMBI18) +#tb 19: 1/44100 +#media_type 19: audio +#codec_id 19: pcm_s16le +#sample_rate 19: 44100 +#channel_layout_name 19: 1 channels (AMBI19) +#tb 20: 1/44100 +#media_type 20: audio +#codec_id 20: pcm_s16le +#sample_rate 20: 44100 +#channel_layout_name 20: 1 channels (AMBI20) +#tb 21: 1/44100 +#media_type 21: audio +#codec_id 21: pcm_s16le +#sample_rate 21: 44100 +#channel_layout_name 21: 1 channels (AMBI21) +#tb 22: 1/44100 +#media_type 22: audio +#codec_id 22: pcm_s16le +#sample_rate 22: 44100 +#channel_layout_name 22: 1 channels (AMBI22) +#tb 23: 1/44100 +#media_type 23: audio +#codec_id 23: pcm_s16le +#sample_rate 23: 44100 +#channel_layout_name 23: 1 channels (AMBI23) +#tb 24: 1/44100 +#media_type 24: audio +#codec_id 24: pcm_s16le +#sample_rate 24: 44100 +#channel_layout_name 24: 1 channels (AMBI24) +#tb 25: 1/44100 +#media_type 25: audio +#codec_id 25: pcm_s16le +#sample_rate 25: 44100 +#channel_layout_name 25: 1 channels (AMBI25) +#tb 26: 1/44100 +#media_type 26: audio +#codec_id 26: pcm_s16le +#sample_rate 26: 44100 +#channel_layout_name 26: 1 channels (AMBI26) +#tb 27: 1/44100 +#media_type 27: audio +#codec_id 27: pcm_s16le +#sample_rate 27: 44100 +#channel_layout_name 27: 1 channels (AMBI27) +#tb 28: 1/44100 +#media_type 28: audio +#codec_id 28: pcm_s16le +#sample_rate 28: 44100 +#channel_layout_name 28: 1 channels (AMBI28) +#tb 29: 1/44100 +#media_type 29: audio +#codec_id 29: pcm_s16le +#sample_rate 29: 44100 +#channel_layout_name 29: 1 channels (AMBI29) +#tb 30: 1/44100 +#media_type 30: audio +#codec_id 30: pcm_s16le +#sample_rate 30: 44100 +#channel_layout_name 30: 1 channels (AMBI30) +#tb 31: 1/44100 +#media_type 31: audio +#codec_id 31: pcm_s16le +#sample_rate 31: 44100 +#channel_layout_name 31: 1 channels (AMBI31) +#tb 32: 1/44100 +#media_type 32: audio +#codec_id 32: pcm_s16le +#sample_rate 32: 44100 +#channel_layout_name 32: 1 channels (AMBI32) +#tb 33: 1/44100 +#media_type 33: audio +#codec_id 33: pcm_s16le +#sample_rate 33: 44100 +#channel_layout_name 33: 1 channels (AMBI33) +#tb 34: 1/44100 +#media_type 34: audio +#codec_id 34: pcm_s16le +#sample_rate 34: 44100 +#channel_layout_name 34: 1 channels (AMBI34) +#tb 35: 1/44100 +#media_type 35: audio +#codec_id 35: pcm_s16le +#sample_rate 35: 44100 +#channel_layout_name 35: 1 channels (AMBI35) +#tb 36: 1/44100 +#media_type 36: audio +#codec_id 36: pcm_s16le +#sample_rate 36: 44100 +#channel_layout_name 36: 1 channels (AMBI36) +#tb 37: 1/44100 +#media_type 37: audio +#codec_id 37: pcm_s16le +#sample_rate 37: 44100 +#channel_layout_name 37: 1 channels (AMBI37) +#tb 38: 1/44100 +#media_type 38: audio +#codec_id 38: pcm_s16le +#sample_rate 38: 44100 +#channel_layout_name 38: 1 channels (AMBI38) +#tb 39: 1/44100 +#media_type 39: audio +#codec_id 39: pcm_s16le +#sample_rate 39: 44100 +#channel_layout_name 39: 1 channels (AMBI39) +#tb 40: 1/44100 +#media_type 40: audio +#codec_id 40: pcm_s16le +#sample_rate 40: 44100 +#channel_layout_name 40: 1 channels (AMBI40) +#tb 41: 1/44100 +#media_type 41: audio +#codec_id 41: pcm_s16le +#sample_rate 41: 44100 +#channel_layout_name 41: 1 channels (AMBI41) +#tb 42: 1/44100 +#media_type 42: audio +#codec_id 42: pcm_s16le +#sample_rate 42: 44100 +#channel_layout_name 42: 1 channels (AMBI42) +#tb 43: 1/44100 +#media_type 43: audio +#codec_id 43: pcm_s16le +#sample_rate 43: 44100 +#channel_layout_name 43: 1 channels (AMBI43) +#tb 44: 1/44100 +#media_type 44: audio +#codec_id 44: pcm_s16le +#sample_rate 44: 44100 +#channel_layout_name 44: 1 channels (AMBI44) +#tb 45: 1/44100 +#media_type 45: audio +#codec_id 45: pcm_s16le +#sample_rate 45: 44100 +#channel_layout_name 45: 1 channels (AMBI45) +#tb 46: 1/44100 +#media_type 46: audio +#codec_id 46: pcm_s16le +#sample_rate 46: 44100 +#channel_layout_name 46: 1 channels (AMBI46) +#tb 47: 1/44100 +#media_type 47: audio +#codec_id 47: pcm_s16le +#sample_rate 47: 44100 +#channel_layout_name 47: 1 channels (AMBI47) +#tb 48: 1/44100 +#media_type 48: audio +#codec_id 48: pcm_s16le +#sample_rate 48: 44100 +#channel_layout_name 48: 1 channels (AMBI48) +#tb 49: 1/44100 +#media_type 49: audio +#codec_id 49: pcm_s16le +#sample_rate 49: 44100 +#channel_layout_name 49: 1 channels (AMBI49) +#tb 50: 1/44100 +#media_type 50: audio +#codec_id 50: pcm_s16le +#sample_rate 50: 44100 +#channel_layout_name 50: 1 channels (AMBI50) +#tb 51: 1/44100 +#media_type 51: audio +#codec_id 51: pcm_s16le +#sample_rate 51: 44100 +#channel_layout_name 51: 1 channels (AMBI51) +#tb 52: 1/44100 +#media_type 52: audio +#codec_id 52: pcm_s16le +#sample_rate 52: 44100 +#channel_layout_name 52: 1 channels (AMBI52) +#tb 53: 1/44100 +#media_type 53: audio +#codec_id 53: pcm_s16le +#sample_rate 53: 44100 +#channel_layout_name 53: 1 channels (AMBI53) +#tb 54: 1/44100 +#media_type 54: audio +#codec_id 54: pcm_s16le +#sample_rate 54: 44100 +#channel_layout_name 54: 1 channels (AMBI54) +#tb 55: 1/44100 +#media_type 55: audio +#codec_id 55: pcm_s16le +#sample_rate 55: 44100 +#channel_layout_name 55: 1 channels (AMBI55) +#tb 56: 1/44100 +#media_type 56: audio +#codec_id 56: pcm_s16le +#sample_rate 56: 44100 +#channel_layout_name 56: 1 channels (AMBI56) +#tb 57: 1/44100 +#media_type 57: audio +#codec_id 57: pcm_s16le +#sample_rate 57: 44100 +#channel_layout_name 57: 1 channels (AMBI57) +#tb 58: 1/44100 +#media_type 58: audio +#codec_id 58: pcm_s16le +#sample_rate 58: 44100 +#channel_layout_name 58: 1 channels (AMBI58) +#tb 59: 1/44100 +#media_type 59: audio +#codec_id 59: pcm_s16le +#sample_rate 59: 44100 +#channel_layout_name 59: 1 channels (AMBI59) +#tb 60: 1/44100 +#media_type 60: audio +#codec_id 60: pcm_s16le +#sample_rate 60: 44100 +#channel_layout_name 60: 1 channels (AMBI60) +#tb 61: 1/44100 +#media_type 61: audio +#codec_id 61: pcm_s16le +#sample_rate 61: 44100 +#channel_layout_name 61: 1 channels (AMBI61) +#tb 62: 1/44100 +#media_type 62: audio +#codec_id 62: pcm_s16le +#sample_rate 62: 44100 +#channel_layout_name 62: 1 channels (AMBI62) +#tb 63: 1/44100 +#media_type 63: audio +#codec_id 63: pcm_s16le +#sample_rate 63: 44100 +#channel_layout_name 63: 1 channels (AMBI63) +#tb 64: 1/44100 +#media_type 64: audio +#codec_id 64: pcm_s16le +#sample_rate 64: 44100 +#channel_layout_name 64: 1 channels (FL) +#tb 65: 1/44100 +#media_type 65: audio +#codec_id 65: pcm_s16le +#sample_rate 65: 44100 +#channel_layout_name 65: 1 channels (FR) +0, 0, 0, 1024, 2048, 0xd782fb56 +1, 0, 0, 1024, 2048, 0x00000000 +2, 0, 0, 1024, 2048, 0xd501f2b4 +3, 0, 0, 1024, 2048, 0x3281ecb5 +4, 0, 0, 1024, 2048, 0xffb00086 +5, 0, 0, 1024, 2048, 0xe9b7f252 +6, 0, 0, 1024, 2048, 0x53e6f849 +7, 0, 0, 1024, 2048, 0xacb9f526 +8, 0, 0, 1024, 2048, 0xa79b0dcb +9, 0, 0, 1024, 2048, 0xa4eaf5c8 +10, 0, 0, 1024, 2048, 0x31010ff1 +11, 0, 0, 1024, 2048, 0xdfaa053a +12, 0, 0, 1024, 2048, 0x7321fac9 +13, 0, 0, 1024, 2048, 0x0786f54d +14, 0, 0, 1024, 2048, 0x32c7fcb7 +15, 0, 0, 1024, 2048, 0x23e8ee40 +16, 0, 0, 1024, 2048, 0xaddef714 +17, 0, 0, 1024, 2048, 0x1c6ffa69 +18, 0, 0, 1024, 2048, 0x493bfb48 +19, 0, 0, 1024, 2048, 0x8e26106e +20, 0, 0, 1024, 2048, 0x0d47f953 +21, 0, 0, 1024, 2048, 0x49a90415 +22, 0, 0, 1024, 2048, 0x5349cdcf +23, 0, 0, 1024, 2048, 0x20410430 +24, 0, 0, 1024, 2048, 0xd3f7ffbe +25, 0, 0, 1024, 2048, 0xca8902f8 +26, 0, 0, 1024, 2048, 0xfe9ffcff +27, 0, 0, 1024, 2048, 0xf1c0fd21 +28, 0, 0, 1024, 2048, 0x6007e947 +29, 0, 0, 1024, 2048, 0x33310ce6 +30, 0, 0, 1024, 2048, 0x04f103a1 +31, 0, 0, 1024, 2048, 0xf84bf6df +32, 0, 0, 1024, 2048, 0xc597027d +33, 0, 0, 1024, 2048, 0x7391ff47 +34, 0, 0, 1024, 2048, 0xd6ab0226 +35, 0, 0, 1024, 2048, 0x4b98fd12 +36, 0, 0, 1024, 2048, 0xb2510d31 +37, 0, 0, 1024, 2048, 0x11e0e994 +38, 0, 0, 1024, 2048, 0xfa5cfa07 +39, 0, 0, 1024, 2048, 0x494cf951 +40, 0, 0, 1024, 2048, 0xf87401ca +41, 0, 0, 1024, 2048, 0x188ffd8f +42, 0, 0, 1024, 2048, 0xc673f7fd +43, 0, 0, 1024, 2048, 0x3020cead +44, 0, 0, 1024, 2048, 0x0f34f9ec +45, 0, 0, 1024, 2048, 0x2f15053e +46, 0, 0, 1024, 2048, 0x4cc9e880 +47, 0, 0, 1024, 2048, 0xa7d0015a +48, 0, 0, 1024, 2048, 0x20c3fcb7 +49, 0, 0, 1024, 2048, 0xb6f80160 +50, 0, 0, 1024, 2048, 0x28f88d75 +51, 0, 0, 1024, 2048, 0xf20502a2 +52, 0, 0, 1024, 2048, 0x7f88f6f8 +53, 0, 0, 1024, 2048, 0x02690489 +54, 0, 0, 1024, 2048, 0x306af8c2 +55, 0, 0, 1024, 2048, 0xbe9a1052 +56, 0, 0, 1024, 2048, 0x344bfc0b +57, 0, 0, 1024, 2048, 0xb2a00b99 +58, 0, 0, 1024, 2048, 0x0cbe045d +59, 0, 0, 1024, 2048, 0x5830fd09 +60, 0, 0, 1024, 2048, 0x8c7900bd +61, 0, 0, 1024, 2048, 0x4a20f705 +62, 0, 0, 1024, 2048, 0x282201f6 +63, 0, 0, 1024, 2048, 0xfbb2fafa +64, 0, 0, 1024, 2048, 0x308b8f8f +65, 0, 0, 1024, 2048, 0x187bfced diff --git a/tests/ref/fate/filter-pixfmts-copy b/tests/ref/fate/filter-pixfmts-copy index eb3e61b4f..120129dc1 100644 --- a/tests/ref/fate/filter-pixfmts-copy +++ b/tests/ref/fate/filter-pixfmts-copy @@ -98,11 +98,11 @@ rgba64be ae2ae04b5efedca3505f47c4dd6ea6ea rgba64le b91e1d77f799eb92241a2d2d28437b15 uyvy422 3bcf3c80047592f2211fae3260b1b65d vuya 3d5e934651cae1ce334001cb1829ad22 -vuyx 3f68ea6ec492b30d867cb5401562264e +vuyx 0af13a42f9d0932c5a9bb6a8a5d1c5ee x2bgr10le 550c0d190cf695afa4eaacb644db6b75 x2rgb10le c1e3ac21be04a16bb157b22784524520 xv30le c14b5a953bf3be56346f66ca174a5b1b -xv36le 3f8ced42a081639a39ec5929dd77b017 +xv36le 6b8e46832aa8537a774e93dd7503c700 xyz12be a1ef56bf746d71f59669c28e48fc8450 xyz12le 831ff03c1ba4ef19374686f16a064d8c y210le 0736b017e0814daf38d3350c42796f7a diff --git a/tests/ref/fate/filter-pixfmts-crop b/tests/ref/fate/filter-pixfmts-crop index 01cb88bc5..4731e96fc 100644 --- a/tests/ref/fate/filter-pixfmts-crop +++ b/tests/ref/fate/filter-pixfmts-crop @@ -95,11 +95,11 @@ rgba 9488ac85abceaf99a9309eac5a87697e rgba64be 89910046972ab3c68e2a348302cc8ca9 rgba64le fea8ebfc869b52adf353778f29eac7a7 vuya 76578a705ff3a37559653c1289bd03dd -vuyx 5d2bae51a2f4892bd5f177f190cc323b +vuyx 615241c5406eb556fca0ad8606c23a02 x2bgr10le 84de725b85662c362862820dc4a309aa x2rgb10le f4265aca7a67dbfa9354370098ca6f33 xv30le a9edb820819b900a4a897fee4562a4fb -xv36le 90a187adf00a1b15c33d064ae2582804 +xv36le 567af630bf0209e026e0909b3ca9c436 xyz12be cb4571f9aaa7b59f999ef327276104b7 xyz12le cd6aae8d26b18bdb4b9d068586276d91 ya16be a3d18014454942a96f15a49947c0c55d diff --git a/tests/ref/fate/filter-pixfmts-field b/tests/ref/fate/filter-pixfmts-field index c7d9b8f13..0727d733f 100644 --- a/tests/ref/fate/filter-pixfmts-field +++ b/tests/ref/fate/filter-pixfmts-field @@ -98,11 +98,11 @@ rgba64be 23c8c0edaabe3eaec89ce69633fb0048 rgba64le dfdba4de4a7cac9abf08852666c341d3 uyvy422 1c49e44ab3f060e85fc4a3a9464f045e vuya f72bcf29d75cd143d0c565f7cc49119a -vuyx 6257cd1ce11330660e9fa9c675acbdcc +vuyx 3d02eeab336d0a8106f6fdd91be61073 x2bgr10le dbe21538d7cb1744914f6bd46ec09b55 x2rgb10le a18bc4ae5274e0a8cca9137ecd50c677 xv30le e940366c78efc9e292e9de28cf04dba9 -xv36le aa5a867879a70e1040dfafe3e03167d5 +xv36le e05a99fc3edc8f26cb2dbd287c0a0fcf xyz12be d2fa69ec91d3ed862f2dac3f8e7a3437 xyz12le 02bccd5e0b6824779a1f848b0ea3e3b5 y210le 025beb25f047a762e3788dbea4b60864 diff --git a/tests/ref/fate/filter-pixfmts-fieldorder b/tests/ref/fate/filter-pixfmts-fieldorder index 2f64bd3b1..1d7a98ce1 100644 --- a/tests/ref/fate/filter-pixfmts-fieldorder +++ b/tests/ref/fate/filter-pixfmts-fieldorder @@ -87,11 +87,11 @@ rgba64be 5598f44514d122b9a57c5c92c20bbc61 rgba64le b34e6e30621ae579519a2d91a96a0acf uyvy422 75de70e31c435dde878002d3f22b238a vuya a3891d4168ff208948fd0b3ba0910495 -vuyx d7a900e970c9a69ed41f8b220114b9fa +vuyx 9e4480c5fcb7c091ec3e517420764ef3 x2bgr10le 86474d84f26c5c51d6f75bf7e1de8da8 x2rgb10le cdf6a9e8a8d081aa768c6ae2e6221676 xv30le 25aac48128d94010a3660839500caee5 -xv36le 1bde4bee8b938d7bf20e75bc848e4765 +xv36le 1f054a1ba4c8f8875ffd15d3d1baccba xyz12be 15f5cda71de5fef9cec5e75e3833b6bc xyz12le 7be6c8781f38c21a6b8f602f62ca31e6 y210le ee45acfb1386288af98af5313162ff3e diff --git a/tests/ref/fate/filter-pixfmts-hflip b/tests/ref/fate/filter-pixfmts-hflip index 66274890a..43404db15 100644 --- a/tests/ref/fate/filter-pixfmts-hflip +++ b/tests/ref/fate/filter-pixfmts-hflip @@ -95,11 +95,11 @@ rgba 51961c723ea6707e0a410cd3f21f15d3 rgba64be c910444019f4cfbf4d995227af55da8d rgba64le 0c810d8b3a6bca10321788e1cb145340 vuya 7e530261e7ac4eae4fd616fd7572d0b8 -vuyx 3ce9890363cad3984521293be1eb679c +vuyx f1d087284fb1556d76e6def5f94bf273 x2bgr10le 827cc659f29378e00c5a7d2c0ada8f9a x2rgb10le d4a8189b65395a88d0a38a7053f3359f xv30le 072aa2b61ce1e764f9d1957e8abee9a9 -xv36le cc569285784e38a489f4a286598f05da +xv36le 6e9c3d2334f9fe2a0e6156615e53e272 xyz12be 25f90259ff8a226befdaec3dfe82996e xyz12le 926c0791d59aaff61b2778e8ada3316d ya16be d5b342355bdd9e3197e01b13b7c6301e diff --git a/tests/ref/fate/filter-pixfmts-il b/tests/ref/fate/filter-pixfmts-il index 03519f2a9..4a6f15f07 100644 --- a/tests/ref/fate/filter-pixfmts-il +++ b/tests/ref/fate/filter-pixfmts-il @@ -97,11 +97,11 @@ rgba64be db70d33aa6c06f3e0a1c77bd11284261 rgba64le a8a2daae04374a27219bc1c890204007 uyvy422 d6ee3ca43356d08c392382b24b22cda5 vuya b9deab5ba249dd608b709c09255a4932 -vuyx 49cc92fcc002ec0f312017014dd68c0c +vuyx 4251d94ee49e6a3cc1c10c09cd331308 x2bgr10le 135acaff8318cf9861bb0f7849a9e5e9 x2rgb10le 517fb186f523dc7cdc5c5c6967cfbe94 xv30le 7f6414a3fc700380025c29812e8376a9 -xv36le 066378fad80e34bc3edd22f657be6ff8 +xv36le cfebfdccb16087207bab0b1909c9d85c xyz12be 7c7d54c55f136cbbc50b18029f3be0b3 xyz12le 090ba6b1170baf2b1358b43b971d33b0 y210le 306ec4238b49dbc8625a97b678ea1c5f diff --git a/tests/ref/fate/filter-pixfmts-null b/tests/ref/fate/filter-pixfmts-null index eb3e61b4f..120129dc1 100644 --- a/tests/ref/fate/filter-pixfmts-null +++ b/tests/ref/fate/filter-pixfmts-null @@ -98,11 +98,11 @@ rgba64be ae2ae04b5efedca3505f47c4dd6ea6ea rgba64le b91e1d77f799eb92241a2d2d28437b15 uyvy422 3bcf3c80047592f2211fae3260b1b65d vuya 3d5e934651cae1ce334001cb1829ad22 -vuyx 3f68ea6ec492b30d867cb5401562264e +vuyx 0af13a42f9d0932c5a9bb6a8a5d1c5ee x2bgr10le 550c0d190cf695afa4eaacb644db6b75 x2rgb10le c1e3ac21be04a16bb157b22784524520 xv30le c14b5a953bf3be56346f66ca174a5b1b -xv36le 3f8ced42a081639a39ec5929dd77b017 +xv36le 6b8e46832aa8537a774e93dd7503c700 xyz12be a1ef56bf746d71f59669c28e48fc8450 xyz12le 831ff03c1ba4ef19374686f16a064d8c y210le 0736b017e0814daf38d3350c42796f7a diff --git a/tests/ref/fate/filter-pixfmts-pad b/tests/ref/fate/filter-pixfmts-pad index 73ae9d0f9..abf4fceb4 100644 --- a/tests/ref/fate/filter-pixfmts-pad +++ b/tests/ref/fate/filter-pixfmts-pad @@ -42,7 +42,7 @@ rgb24 17f9e2e0c609009acaf2175c42d4a2a5 rgb48le ed08db9b1aa50d69b8c3d73db93e390e rgba b157c90191463d34fb3ce77b36c96386 vuya 44368c0a758ee68e24ce976e3b1b8535 -vuyx bc7c4f693a22cd1ac95e33d473086474 +vuyx ff637b205b78ee581e393124d0f44f5d ya16le dfc900a8130a7c5e64201557cbaef50a ya8 5d25e9a7975805d3f0dac516a6132b6e yuv410p cb871dcc1e84a7ef1d21f9237b88cf6e diff --git a/tests/ref/fate/filter-pixfmts-scale b/tests/ref/fate/filter-pixfmts-scale index b11384068..2052d3f2f 100644 --- a/tests/ref/fate/filter-pixfmts-scale +++ b/tests/ref/fate/filter-pixfmts-scale @@ -98,11 +98,11 @@ rgba64be ee73e57923af984b31cc7795d13929da rgba64le 783d2779adfafe3548bdb671ec0de69e uyvy422 aeb4ba4f9f003ae21f6d18089198244f vuya ffa817e283bf6a0b6fba21b07523ccaa -vuyx ba182200e20e0c82765eba15217848d3 +vuyx a6ff68f46c6b4b7595ec91b2a497df8e x2bgr10le d57b9a99033cc7b65ddd111578f2d385 x2rgb10le d56bdb23fa6a8e12a0b4394987f89935 xv30le afe68d8a47e8460e0164970b1da0c5be -xv36le eaf5fbd9d5ea04aeefb40f3d7c2ea289 +xv36le 4242e35b87fcdfbc3f17370c591577c7 xyz12be c7ba8345998c0141ddc079cdd29b1a40 xyz12le 95f5d3a0de834cc495c9032a14987cde y210le 1c2708a520477f955d1fedf6ca7a41bd diff --git a/tests/ref/fate/filter-pixfmts-transpose b/tests/ref/fate/filter-pixfmts-transpose index ec157dee0..0a395f7e7 100644 --- a/tests/ref/fate/filter-pixfmts-transpose +++ b/tests/ref/fate/filter-pixfmts-transpose @@ -87,11 +87,11 @@ rgba 4d76a9542143752a4ac30f82f88f68f1 rgba64be a60041217f4c0cd796d19d3940a12a41 rgba64le ad47197774858858ae7b0c177dffa459 vuya 9ece18a345beb17cd19e09e443eca4bf -vuyx 4c2929cd1c6e5512f62e802f482f0ef2 +vuyx 46b5b821d7ee6ddedb3ddafd1e5b007c x2bgr10le 4aa774b6d8f6d446a64f1f288e5c97eb x2rgb10le 09cb1d98fe17ad8a6d9d3bec97ddc845 xv30le b1ac5a12f46d32c70acb63f89838ab76 -xv36le f15a1d1af2a2967ec6a5efebc87e1ef1 +xv36le a819ca57db4187a3effe2bd5e374e932 xyz12be 68e5cba640f6e4ef72dff950e88b5342 xyz12le 8b6b6a6db4d7561e80db88ccaecce7a9 ya16be 3e161cb5f225922a80fefdc9cc02a4f9 diff --git a/tests/ref/fate/filter-pixfmts-vflip b/tests/ref/fate/filter-pixfmts-vflip index 9a7972d6c..5ba28917a 100644 --- a/tests/ref/fate/filter-pixfmts-vflip +++ b/tests/ref/fate/filter-pixfmts-vflip @@ -98,11 +98,11 @@ rgba64be 17e6273323b5779b5f3f775f150c1011 rgba64le 48f45b10503b7dd140329c3dd0d54c98 uyvy422 3a237e8376264e0cfa78f8a3fdadec8a vuya fb849f76e56181e005c31fce75d7038c -vuyx 7a8079a97610e2c1c97aa8832b58a102 +vuyx ed7de87da324b39090a8961dfd56ca5a x2bgr10le 795b66a5fc83cd2cf300aae51c230f80 x2rgb10le 262c502230cf3724f8e2cf4737f18a42 xv30le 7e29ee107a1fabf3c7251f337d4b9fe5 -xv36le aad3c6b5799b4e46a9c9ac27ee7db9bd +xv36le bf1cbef0745f90881e15f5c5db3c5949 xyz12be 810644e008deb231850d779aaa27cc7e xyz12le 829701db461b43533cf9241e0743bc61 y210le 9544c81f8e1fc95e9fa4009dbecfea25 diff --git a/tests/ref/fate/filter-refcmp-xpsnr-rgb b/tests/ref/fate/filter-refcmp-xpsnr-rgb new file mode 100644 index 000000000..981d4fcd8 --- /dev/null +++ b/tests/ref/fate/filter-refcmp-xpsnr-rgb @@ -0,0 +1,20 @@ +frame:0 pts:0 pts_time:0 +lavfi.xpsnr.xpsnr.r=10.844733 +lavfi.xpsnr.xpsnr.g=18.610714 +lavfi.xpsnr.xpsnr.b=25.113884 +frame:1 pts:1 pts_time:1 +lavfi.xpsnr.xpsnr.r=5.962447 +lavfi.xpsnr.xpsnr.g=10.468726 +lavfi.xpsnr.xpsnr.b=14.122101 +frame:2 pts:2 pts_time:2 +lavfi.xpsnr.xpsnr.r=5.907167 +lavfi.xpsnr.xpsnr.g=10.561430 +lavfi.xpsnr.xpsnr.b=13.334916 +frame:3 pts:3 pts_time:3 +lavfi.xpsnr.xpsnr.r=5.866307 +lavfi.xpsnr.xpsnr.g=10.523605 +lavfi.xpsnr.xpsnr.b=12.099272 +frame:4 pts:4 pts_time:4 +lavfi.xpsnr.xpsnr.r=6.047683 +lavfi.xpsnr.xpsnr.g=10.493720 +lavfi.xpsnr.xpsnr.b=11.922785 diff --git a/tests/ref/fate/filter-refcmp-xpsnr-yuv b/tests/ref/fate/filter-refcmp-xpsnr-yuv new file mode 100644 index 000000000..f88612fe2 --- /dev/null +++ b/tests/ref/fate/filter-refcmp-xpsnr-yuv @@ -0,0 +1,20 @@ +frame:0 pts:0 pts_time:0 +lavfi.xpsnr.xpsnr.y=25.999813 +lavfi.xpsnr.xpsnr.u=24.721392 +lavfi.xpsnr.xpsnr.v=21.412033 +frame:1 pts:1 pts_time:1 +lavfi.xpsnr.xpsnr.y=14.228159 +lavfi.xpsnr.xpsnr.u=12.051848 +lavfi.xpsnr.xpsnr.v=6.540133 +frame:2 pts:2 pts_time:2 +lavfi.xpsnr.xpsnr.y=13.754443 +lavfi.xpsnr.xpsnr.u=11.545194 +lavfi.xpsnr.xpsnr.v=6.961101 +frame:3 pts:3 pts_time:3 +lavfi.xpsnr.xpsnr.y=13.846706 +lavfi.xpsnr.xpsnr.u=11.725706 +lavfi.xpsnr.xpsnr.v=6.759900 +frame:4 pts:4 pts_time:4 +lavfi.xpsnr.xpsnr.y=14.077765 +lavfi.xpsnr.xpsnr.u=11.305364 +lavfi.xpsnr.xpsnr.v=6.276692 diff --git a/tests/ref/fate/filter-scalechroma b/tests/ref/fate/filter-scalechroma index 842769c2d..dbe08600a 100644 --- a/tests/ref/fate/filter-scalechroma +++ b/tests/ref/fate/filter-scalechroma @@ -3,28 +3,28 @@ #codec_id 0: rawvideo #dimensions 0: 352x288 #sar 0: 0/1 -0, 0, 0, 1, 152064, 0xdcab783a -0, 1, 1, 1, 152064, 0x79c7f1f6 -0, 2, 2, 1, 152064, 0x3b810afb -0, 3, 3, 1, 152064, 0x892aca1d -0, 4, 4, 1, 152064, 0x52fdd093 -0, 5, 5, 1, 152064, 0xaa643426 -0, 6, 6, 1, 152064, 0x9ad020ed -0, 7, 7, 1, 152064, 0x5c179057 -0, 8, 8, 1, 152064, 0xa56bf155 -0, 9, 9, 1, 152064, 0x61dcffca -0, 10, 10, 1, 152064, 0x0d51a1d3 -0, 11, 11, 1, 152064, 0x652f9e8d -0, 12, 12, 1, 152064, 0xdc0bb4d8 -0, 13, 13, 1, 152064, 0x561437cf -0, 14, 14, 1, 152064, 0x69ef8e4f -0, 15, 15, 1, 152064, 0xe7244350 -0, 16, 16, 1, 152064, 0xe65651cf -0, 17, 17, 1, 152064, 0xfc9ff646 -0, 18, 18, 1, 152064, 0x6ae10bc4 -0, 19, 19, 1, 152064, 0xd3d1898a -0, 20, 20, 1, 152064, 0xf3f8b139 -0, 21, 21, 1, 152064, 0x68c129be -0, 22, 22, 1, 152064, 0xc3922593 -0, 23, 23, 1, 152064, 0x2b14d96e -0, 24, 24, 1, 152064, 0xab119489 +0, 0, 0, 1, 152064, 0x77bb80f8 +0, 1, 1, 1, 152064, 0x3a21f6e8 +0, 2, 2, 1, 152064, 0xcc0907b0 +0, 3, 3, 1, 152064, 0xaa5cd87b +0, 4, 4, 1, 152064, 0x410bd74d +0, 5, 5, 1, 152064, 0x7a763b14 +0, 6, 6, 1, 152064, 0x3e4020d4 +0, 7, 7, 1, 152064, 0x46be8b5d +0, 8, 8, 1, 152064, 0x8021f16c +0, 9, 9, 1, 152064, 0x82ca033d +0, 10, 10, 1, 152064, 0xa76ca6ca +0, 11, 11, 1, 152064, 0x49019bb7 +0, 12, 12, 1, 152064, 0x3590adf5 +0, 13, 13, 1, 152064, 0xf21235dc +0, 14, 14, 1, 152064, 0x6b5f93a9 +0, 15, 15, 1, 152064, 0x4b8c5137 +0, 16, 16, 1, 152064, 0x698b67cc +0, 17, 17, 1, 152064, 0x3cebef62 +0, 18, 18, 1, 152064, 0x77770da1 +0, 19, 19, 1, 152064, 0xecdd84d4 +0, 20, 20, 1, 152064, 0x873fbc32 +0, 21, 21, 1, 152064, 0x55043c82 +0, 22, 22, 1, 152064, 0xee2b3669 +0, 23, 23, 1, 152064, 0xa64ae990 +0, 24, 24, 1, 152064, 0xb3499e12 diff --git a/tests/ref/fate/filter-tiltandshift-410 b/tests/ref/fate/filter-tiltandshift-410 new file mode 100644 index 000000000..6322957ae --- /dev/null +++ b/tests/ref/fate/filter-tiltandshift-410 @@ -0,0 +1,55 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +0, 0, 0, 1, 114048, 0x6baa7c6d +0, 1, 1, 1, 114048, 0xc3642fac +0, 2, 2, 1, 114048, 0x98f9732e +0, 3, 3, 1, 114048, 0x6ca6d4a3 +0, 4, 4, 1, 114048, 0x84ad8041 +0, 5, 5, 1, 114048, 0x0703ca6b +0, 6, 6, 1, 114048, 0xca6c50eb +0, 7, 7, 1, 114048, 0x4c08d4d3 +0, 8, 8, 1, 114048, 0x4dd55b2a +0, 9, 9, 1, 114048, 0xfad0c5ef +0, 10, 10, 1, 114048, 0x5efb4a94 +0, 11, 11, 1, 114048, 0xa78acf53 +0, 12, 12, 1, 114048, 0xe7aa76da +0, 13, 13, 1, 114048, 0xa080f010 +0, 14, 14, 1, 114048, 0xa1345566 +0, 15, 15, 1, 114048, 0x7621b83d +0, 16, 16, 1, 114048, 0x89542578 +0, 17, 17, 1, 114048, 0x433188b4 +0, 18, 18, 1, 114048, 0xb505109d +0, 19, 19, 1, 114048, 0x92588ee4 +0, 20, 20, 1, 114048, 0x9a9a1c62 +0, 21, 21, 1, 114048, 0xc4838f79 +0, 22, 22, 1, 114048, 0x0d4cff5b +0, 23, 23, 1, 114048, 0xe8d19a47 +0, 24, 24, 1, 114048, 0x3b7d3a5c +0, 25, 25, 1, 114048, 0x91dca592 +0, 26, 26, 1, 114048, 0x959023d0 +0, 27, 27, 1, 114048, 0x2affd380 +0, 28, 28, 1, 114048, 0x098a6ea9 +0, 29, 29, 1, 114048, 0x5f880cd2 +0, 30, 30, 1, 114048, 0xff9f6b9a +0, 31, 31, 1, 114048, 0x189b13c9 +0, 32, 32, 1, 114048, 0xae5790c4 +0, 33, 33, 1, 114048, 0xbbe22e70 +0, 34, 34, 1, 114048, 0xdf8dd06e +0, 35, 35, 1, 114048, 0xcf792136 +0, 36, 36, 1, 114048, 0xe8ab98de +0, 37, 37, 1, 114048, 0x7b6f0eee +0, 38, 38, 1, 114048, 0x8b997e3a +0, 39, 39, 1, 114048, 0x6388008e +0, 40, 40, 1, 114048, 0xbe8f8e6d +0, 41, 41, 1, 114048, 0xb2b3170f +0, 42, 42, 1, 114048, 0xa6da9c1c +0, 43, 43, 1, 114048, 0xd27814e8 +0, 44, 44, 1, 114048, 0x0ff09559 +0, 45, 45, 1, 114048, 0x9d21155c +0, 46, 46, 1, 114048, 0xc56d93d7 +0, 47, 47, 1, 114048, 0x6c160b33 +0, 48, 48, 1, 114048, 0x75cb8824 +0, 49, 49, 1, 114048, 0x7a1a05a7 diff --git a/tests/ref/fate/filter-tiltandshift-422 b/tests/ref/fate/filter-tiltandshift-422 new file mode 100644 index 000000000..b74207b65 --- /dev/null +++ b/tests/ref/fate/filter-tiltandshift-422 @@ -0,0 +1,55 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +0, 0, 0, 1, 202752, 0x3ed465a5 +0, 1, 1, 1, 202752, 0x9bda6504 +0, 2, 2, 1, 202752, 0xf10ada35 +0, 3, 3, 1, 202752, 0x48e2ac92 +0, 4, 4, 1, 202752, 0x8953305a +0, 5, 5, 1, 202752, 0xa2e115d4 +0, 6, 6, 1, 202752, 0xfe2e24b3 +0, 7, 7, 1, 202752, 0x77877934 +0, 8, 8, 1, 202752, 0x5d59d490 +0, 9, 9, 1, 202752, 0x921255a8 +0, 10, 10, 1, 202752, 0x435ab5d4 +0, 11, 11, 1, 202752, 0xe9b55fe0 +0, 12, 12, 1, 202752, 0x9f5274af +0, 13, 13, 1, 202752, 0x4cbaab10 +0, 14, 14, 1, 202752, 0xefa4b683 +0, 15, 15, 1, 202752, 0x61d1faec +0, 16, 16, 1, 202752, 0x6f3b9de5 +0, 17, 17, 1, 202752, 0xaa96b38a +0, 18, 18, 1, 202752, 0x0fa436f4 +0, 19, 19, 1, 202752, 0x8b3dce57 +0, 20, 20, 1, 202752, 0x36d7060c +0, 21, 21, 1, 202752, 0x81d0dc5b +0, 22, 22, 1, 202752, 0x55a4f122 +0, 23, 23, 1, 202752, 0x12edb3ae +0, 24, 24, 1, 202752, 0x31d99dad +0, 25, 25, 1, 202752, 0x9325a9dc +0, 26, 26, 1, 202752, 0x2caf6c84 +0, 27, 27, 1, 202752, 0x27e74cec +0, 28, 28, 1, 202752, 0xdcf0b81a +0, 29, 29, 1, 202752, 0x8159988c +0, 30, 30, 1, 202752, 0x0bcadc35 +0, 31, 31, 1, 202752, 0xd90afc33 +0, 32, 32, 1, 202752, 0x7951059f +0, 33, 33, 1, 202752, 0x44fbddf1 +0, 34, 34, 1, 202752, 0x955eb48d +0, 35, 35, 1, 202752, 0x6126bb75 +0, 36, 36, 1, 202752, 0xa99d5db2 +0, 37, 37, 1, 202752, 0x3db258da +0, 38, 38, 1, 202752, 0xaa86f004 +0, 39, 39, 1, 202752, 0x326b71f8 +0, 40, 40, 1, 202752, 0x8e3e1986 +0, 41, 41, 1, 202752, 0x78738f9a +0, 42, 42, 1, 202752, 0x8b552527 +0, 43, 43, 1, 202752, 0x804490e9 +0, 44, 44, 1, 202752, 0x39fa1b5b +0, 45, 45, 1, 202752, 0xfc118248 +0, 46, 46, 1, 202752, 0xa7db058a +0, 47, 47, 1, 202752, 0xfa3b6ad9 +0, 48, 48, 1, 202752, 0x7d1be927 +0, 49, 49, 1, 202752, 0x3bfd4fca diff --git a/tests/ref/fate/filter-tiltandshift-444 b/tests/ref/fate/filter-tiltandshift-444 new file mode 100644 index 000000000..7815ebc23 --- /dev/null +++ b/tests/ref/fate/filter-tiltandshift-444 @@ -0,0 +1,55 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +0, 0, 0, 1, 304128, 0xb3aa278e +0, 1, 1, 1, 304128, 0x61ead61b +0, 2, 2, 1, 304128, 0xa13ff73f +0, 3, 3, 1, 304128, 0x21e60ac9 +0, 4, 4, 1, 304128, 0x3fba8d77 +0, 5, 5, 1, 304128, 0x1d0ec25c +0, 6, 6, 1, 304128, 0xce244c19 +0, 7, 7, 1, 304128, 0x3677eb76 +0, 8, 8, 1, 304128, 0x075a566a +0, 9, 9, 1, 304128, 0x198997c0 +0, 10, 10, 1, 304128, 0x1d590633 +0, 11, 11, 1, 304128, 0xf314bd3c +0, 12, 12, 1, 304128, 0x4632c7d3 +0, 13, 13, 1, 304128, 0x30006871 +0, 14, 14, 1, 304128, 0x0efa3508 +0, 15, 15, 1, 304128, 0x99f83d90 +0, 16, 16, 1, 304128, 0x215595d3 +0, 17, 17, 1, 304128, 0xb9bddce7 +0, 18, 18, 1, 304128, 0x736e35a9 +0, 19, 19, 1, 304128, 0x17068e09 +0, 20, 20, 1, 304128, 0xf46f19a6 +0, 21, 21, 1, 304128, 0x2d507f26 +0, 22, 22, 1, 304128, 0x66eee1b4 +0, 23, 23, 1, 304128, 0x4bce85ff +0, 24, 24, 1, 304128, 0x518c506d +0, 25, 25, 1, 304128, 0x2633cd90 +0, 26, 26, 1, 304128, 0xcbd34def +0, 27, 27, 1, 304128, 0x32723151 +0, 28, 28, 1, 304128, 0x70a307b0 +0, 29, 29, 1, 304128, 0xff92b107 +0, 30, 30, 1, 304128, 0xd0b64bf5 +0, 31, 31, 1, 304128, 0xb98c1d08 +0, 32, 32, 1, 304128, 0xc4a7a6b5 +0, 33, 33, 1, 304128, 0x8b46507e +0, 34, 34, 1, 304128, 0x6c851d4c +0, 35, 35, 1, 304128, 0xb9818a3d +0, 36, 36, 1, 304128, 0xf8e1b84f +0, 37, 37, 1, 304128, 0x50fae0f2 +0, 38, 38, 1, 304128, 0xd57601b7 +0, 39, 39, 1, 304128, 0x465daf8f +0, 40, 40, 1, 304128, 0xf75f50a3 +0, 41, 41, 1, 304128, 0x0ac8e29a +0, 42, 42, 1, 304128, 0x2a586993 +0, 43, 43, 1, 304128, 0xae56e5fc +0, 44, 44, 1, 304128, 0xfa2f5d29 +0, 45, 45, 1, 304128, 0xac09cdd9 +0, 46, 46, 1, 304128, 0x22683a28 +0, 47, 47, 1, 304128, 0x2a7da356 +0, 48, 48, 1, 304128, 0x824b0ac4 +0, 49, 49, 1, 304128, 0x09a171fd diff --git a/tests/ref/fate/fitsdec-gbrap16be b/tests/ref/fate/fitsdec-gbrap16be index 1174a0f1d..e57a87884 100644 --- a/tests/ref/fate/fitsdec-gbrap16be +++ b/tests/ref/fate/fitsdec-gbrap16be @@ -5,4 +5,4 @@ #codec_id 0: rawvideo #dimensions 0: 128x128 #sar 0: 0/1 -0, 0, 0, 1, 131072, 0x487894b2 +0, 0, 0, 1, 131072, 0xebb194b2 diff --git a/tests/ref/fate/flv-demux b/tests/ref/fate/flv-demux index a9cbcc46e..4e959e091 100644 --- a/tests/ref/fate/flv-demux +++ b/tests/ref/fate/flv-demux @@ -601,6 +601,6 @@ packet|codec_type=video|stream_index=0|pts=11612|pts_time=11.612000|dts=11612|dt packet|codec_type=video|stream_index=0|pts=11645|pts_time=11.645000|dts=11645|dts_time=11.645000|duration=33|duration_time=0.033000|size=2600|pos=507811|flags=___|data_hash=CRC32:d35f9e6f packet|codec_type=audio|stream_index=1|pts=11656|pts_time=11.656000|dts=11656|dts_time=11.656000|duration=46|duration_time=0.046000|size=346|pos=510431|flags=K__|data_hash=CRC32:4e6b44cb packet|codec_type=video|stream_index=0|pts=11678|pts_time=11.678000|dts=11678|dts_time=11.678000|duration=33|duration_time=0.033000|size=1190|pos=510794|flags=__C|data_hash=CRC32:a0206c90 -stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|width=426|height=240|coded_width=426|coded_height=240|closed_captions=0|film_grain=0|has_b_frames=1|sample_aspect_ratio=1:1|display_aspect_ratio=71:40|pix_fmt=yuv420p|level=21|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|is_avc=true|nal_length_size=4|missing_streams=0|id=N/A|r_frame_rate=30000/1001|avg_frame_rate=30/1|time_base=1/1000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=393929|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=351|extradata_size=39|extradata_hash=CRC32:07b85ca9|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0 -stream|index=1|codec_name=aac|profile=1|codec_type=audio|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|sample_fmt=fltp|sample_rate=22050|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=0|missing_streams=0|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/1000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=67874|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=252|extradata_size=2|extradata_hash=CRC32:d039c029|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0 +stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|width=426|height=240|coded_width=426|coded_height=240|closed_captions=0|film_grain=0|has_b_frames=1|sample_aspect_ratio=1:1|display_aspect_ratio=71:40|pix_fmt=yuv420p|level=21|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|is_avc=true|nal_length_size=4|missing_streams=0|id=N/A|r_frame_rate=30000/1001|avg_frame_rate=30/1|time_base=1/1000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=393929|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=351|extradata_size=39|extradata_hash=CRC32:07b85ca9|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0 +stream|index=1|codec_name=aac|profile=1|codec_type=audio|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|sample_fmt=fltp|sample_rate=22050|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=0|missing_streams=0|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/1000|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=67874|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=252|extradata_size=2|extradata_hash=CRC32:d039c029|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0 format|filename=Enigma_Principles_of_Lust-part.flv|nb_streams=2|nb_programs=0|nb_stream_groups=0|format_name=flv|start_time=0.000000|duration=210.209999|size=512000|bit_rate=19485|probe_score=100|tag:hasKeyframes=true|tag:hasMetadata=true|tag:datasize=11970544|tag:hasVideo=true|tag:canSeekToEnd=false|tag:lasttimestamp=210|tag:lastkeyframetimestamp=210|tag:audiosize=1791332|tag:hasAudio=true|tag:audiodelay=0|tag:videosize=10176110|tag:metadatadate=2011-02-27T11:00:33.125000Z|tag:metadatacreator=inlet media FLVTool2 v1.0.6 - http://www.inlet-media.de/flvtool2|tag:hasCuePoints=false diff --git a/tests/ref/fate/gapless-mp3-side-data b/tests/ref/fate/gapless-mp3-side-data index 87a99661f..49ebc32dc 100644 --- a/tests/ref/fate/gapless-mp3-side-data +++ b/tests/ref/fate/gapless-mp3-side-data @@ -593,5 +593,5 @@ packet|codec_type=audio|stream_index=0|pts=217866240|pts_time=15.438367|dts=2178 packet|codec_type=audio|stream_index=0|pts=218234880|pts_time=15.464490|dts=218234880|dts_time=15.464490|duration=368640|duration_time=0.026122|size=418|pos=248882|flags=K__|data_hash=CRC32:fbc83c3c packet|codec_type=audio|stream_index=0|pts=218603520|pts_time=15.490612|dts=218603520|dts_time=15.490612|duration=368640|duration_time=0.026122|size=418|pos=249300|flags=K__|data_hash=CRC32:d5fb5f9c|side_datum/skip_samples:side_data_type=Skip Samples|side_datum/skip_samples:skip_samples=0|side_datum/skip_samples:discard_padding=303|side_datum/skip_samples:skip_reason=0|side_datum/skip_samples:discard_reason=0 packet|codec_type=audio|stream_index=0|pts=218972160|pts_time=15.516735|dts=218972160|dts_time=15.516735|duration=368640|duration_time=0.026122|size=418|pos=249718|flags=K__|data_hash=CRC32:3789f3cf|side_datum/skip_samples:side_data_type=Skip Samples|side_datum/skip_samples:skip_samples=0|side_datum/skip_samples:discard_padding=1152|side_datum/skip_samples:skip_reason=0|side_datum/skip_samples:discard_reason=0 -stream|index=0|codec_name=mp3|profile=unknown|codec_type=audio|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|sample_fmt=fltp|sample_rate=44100|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=0|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/14112000|start_pts=353600|start_time=0.025057|duration_ts=219340800|duration=15.542857|bit_rate=128000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=595|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|tag:encoder=LAME3.93 +stream|index=0|codec_name=mp3|profile=unknown|codec_type=audio|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|sample_fmt=fltp|sample_rate=44100|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=0|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/14112000|start_pts=353600|start_time=0.025057|duration_ts=219340800|duration=15.542857|bit_rate=128000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=595|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:encoder=LAME3.93 format|filename=gapless.mp3|nb_streams=1|nb_programs=0|nb_stream_groups=0|format_name=mp3|start_time=0.025057|duration=15.542857|size=250264|bit_rate=128812|probe_score=51|tag:title=test diff --git a/tests/ref/fate/h264-bsf-dts2pts b/tests/ref/fate/h264-bsf-dts2pts new file mode 100644 index 000000000..f908bb44f --- /dev/null +++ b/tests/ref/fate/h264-bsf-dts2pts @@ -0,0 +1,58 @@ +219edd347ce3151f5b5579d300cd7179 *tests/data/fate/h264-bsf-dts2pts.mov +243937 tests/data/fate/h264-bsf-dts2pts.mov +#extradata 0: 26, 0x75e2093d +#tb 0: 1/1200000 +#media_type 0: video +#codec_id 0: h264 +#dimensions 0: 352x288 +#sar 0: 0/1 +0, -48000, 0, 48000, 13686, 0x5ee9bd4c +0, 0, 240000, 48000, 9320, 0x17224db1, F=0x0 +0, 48000, 288000, 48000, 8903, 0xe394918b, F=0x0 +0, 96000, 96000, 48000, 10108, 0x98418e7e, F=0x0 +0, 144000, 144000, 48000, 2937, 0x49dccb76, F=0x0 +0, 192000, 192000, 48000, 2604, 0xfc8013cd, F=0x0 +0, 240000, 480000, 48000, 7420, 0xcb4155cd, F=0x0 +0, 288000, 528000, 48000, 5664, 0x060bc948, F=0x0 +0, 336000, 336000, 48000, 4859, 0x0a5a8368, F=0x0 +0, 384000, 384000, 48000, 2883, 0xb9639a19, F=0x0 +0, 432000, 432000, 48000, 2547, 0xba95e99d, F=0x0 +0, 480000, 672000, 48000, 4659, 0x19203a0d, F=0x0 +0, 528000, 696000, 48000, 9719, 0xb500c328, F=0x0 +0, 576000, 576000, 48000, 5078, 0x5359c6b8, F=0x0 +0, 624000, 624000, 48000, 5041, 0x88dfcdf1, F=0x0 +0, 672000, 864000, 48000, 9494, 0x29297319, F=0x0 +0, 720000, 720000, 48000, 4772, 0x80273a60, F=0x0 +0, 768000, 768000, 48000, 3237, 0xd99e742c, F=0x0 +0, 816000, 816000, 48000, 2650, 0xc7cc378a, F=0x0 +0, 864000, 1152000, 48000, 6519, 0x142aa357, F=0x0 +0, 912000, 1176000, 48000, 5878, 0xe70d7e21, F=0x0 +0, 960000, 960000, 48000, 2648, 0xe58b1c4b, F=0x0 +0, 1008000, 1008000, 48000, 4522, 0x33ad0882, F=0x0 +0, 1056000, 1056000, 48000, 3246, 0xdbfa539f, F=0x0 +0, 1104000, 1104000, 48000, 3027, 0xdb5bf675, F=0x0 +0, 1152000, 1392000, 48000, 9282, 0x07973603, F=0x0 +0, 1200000, 1200000, 48000, 2786, 0x14824d92, F=0x0 +0, 1248000, 1248000, 48000, 2719, 0x00614eef, F=0x0 +0, 1296000, 1296000, 48000, 2627, 0xe8e91216, F=0x0 +0, 1344000, 1344000, 48000, 2720, 0xbe974fcc, F=0x0 +0, 1392000, 1584000, 48000, 7687, 0x0de01895, F=0x0 +0, 1440000, 1440000, 48000, 5464, 0x113f954d, F=0x0 +0, 1488000, 1488000, 48000, 3482, 0x5c90cdae, F=0x0 +0, 1536000, 1536000, 48000, 2791, 0x4acb702a, F=0x0 +0, 1584000, 1872000, 48000, 11362, 0x13363bdb, F=0x0 +0, 1632000, 1920000, 48000, 2975, 0x99b1e813, F=0x0 +0, 1680000, 1680000, 48000, 2342, 0xe9587867, F=0x0 +0, 1728000, 1728000, 48000, 2634, 0x8d9814fc, F=0x0 +0, 1776000, 1776000, 48000, 2419, 0x033cbb5f, F=0x0 +0, 1824000, 1824000, 48000, 2498, 0x7dd9e476, F=0x0 +0, 1872000, 2112000, 48000, 2668, 0x358e2bd8, F=0x0 +0, 1920000, 2136000, 48000, 9068, 0x3a639927, F=0x0 +0, 1968000, 1968000, 48000, 4939, 0xa5309a8c, F=0x0 +0, 2016000, 2016000, 48000, 2650, 0x2ab82b97, F=0x0 +0, 2064000, 2064000, 48000, 2503, 0xfd97cd4c, F=0x0 +0, 2112000, 2352000, 48000, 5121, 0xaf88e5b8, F=0x0 +0, 2160000, 2160000, 48000, 2643, 0xa1791db0, F=0x0 +0, 2208000, 2208000, 48000, 2637, 0xe1a42510, F=0x0 +0, 2256000, 2256000, 48000, 2633, 0x08430f15, F=0x0 +0, 2304000, 2304000, 48000, 2721, 0xe6756990, F=0x0 diff --git a/tests/ref/fate/h264-bsf-mp4toannexb b/tests/ref/fate/h264-bsf-mp4toannexb index 2049f3970..81ff568f3 100644 --- a/tests/ref/fate/h264-bsf-mp4toannexb +++ b/tests/ref/fate/h264-bsf-mp4toannexb @@ -1 +1 @@ -5f04c27cc6ee8625fe2405fb0f7da9a3 +ff2551123909f54c382294baa1bb4364 diff --git a/tests/ref/fate/h264_mp4toannexb_ticket2991 b/tests/ref/fate/h264_mp4toannexb_ticket2991 index f8e3e920d..9a1fbf2f8 100644 --- a/tests/ref/fate/h264_mp4toannexb_ticket2991 +++ b/tests/ref/fate/h264_mp4toannexb_ticket2991 @@ -1,4 +1,4 @@ -05d66e60ab22ee004720e0051af0fe74 *tests/data/fate/h264_mp4toannexb_ticket2991.h264 +b6ff5910928ad0b2a7eec481dcc41594 *tests/data/fate/h264_mp4toannexb_ticket2991.h264 1985815 tests/data/fate/h264_mp4toannexb_ticket2991.h264 #extradata 0: 47, 0x3a590d55 #tb 0: 1/1200000 @@ -6,7 +6,7 @@ #codec_id 0: h264 #dimensions 0: 1280x720 #sar 0: 3/4 -0, 0, 0, 40040, 37126, 0xb020184c +0, 0, 0, 40040, 37126, 0x515c184c 0, 40040, 40040, 40040, 6920, 0x8512361a, F=0x0 0, 80081, 80081, 40040, 7550, 0x1bc56ed4, F=0x0 0, 120121, 120121, 40040, 8752, 0xb8c6f0a1, F=0x0 @@ -21,7 +21,7 @@ 0, 480485, 480485, 40040, 11234, 0x83cbd9fd, F=0x0 0, 520525, 520525, 40040, 17616, 0xfdf95104, F=0x0 0, 560566, 560566, 40040, 10689, 0x9633d32b, F=0x0 -0, 600606, 600606, 40040, 45291, 0x543c2cf6 +0, 600606, 600606, 40040, 45291, 0xa8292cf6 0, 640646, 640646, 40040, 20837, 0x051abfab, F=0x0 0, 680687, 680687, 40040, 21418, 0xe2a59d70, F=0x0 0, 720727, 720727, 40040, 15643, 0x15cf2cec, F=0x0 @@ -36,7 +36,7 @@ 0, 1081091, 1081091, 40040, 13130, 0xcbb6bb8e, F=0x0 0, 1121131, 1121131, 40040, 16180, 0x5d188a7a, F=0x0 0, 1161172, 1161172, 40040, 14961, 0x9ff2f463, F=0x0 -0, 1201212, 1201212, 40040, 54296, 0xe6ec30ed +0, 1201212, 1201212, 40040, 54296, 0x3ae830ed 0, 1241252, 1241252, 40040, 11500, 0x8c4852c9, F=0x0 0, 1281293, 1281293, 40040, 12065, 0xfb7954c3, F=0x0 0, 1321333, 1321333, 40040, 12532, 0xf0a935d3, F=0x0 @@ -51,7 +51,7 @@ 0, 1681697, 1681697, 40040, 13250, 0xfed0deb8, F=0x0 0, 1721737, 1721737, 40040, 13360, 0xbf92d476, F=0x0 0, 1761778, 1761778, 40040, 11749, 0x3041eaf1, F=0x0 -0, 1801818, 1801818, 40040, 23997, 0xdbe6d5c4 +0, 1801818, 1801818, 40040, 23997, 0x2fe2d5c4 0, 1841858, 1841858, 40040, 16065, 0xe8f715b7, F=0x0 0, 1881899, 1881899, 40040, 16441, 0x0a4e060f, F=0x0 0, 1921939, 1921939, 40040, 17395, 0xa8edecc2, F=0x0 @@ -66,7 +66,7 @@ 0, 2282303, 2282303, 40040, 13748, 0xed26aeb4, F=0x0 0, 2322343, 2322343, 40040, 15092, 0x3c983538, F=0x0 0, 2362384, 2362384, 40040, 14636, 0x9b278a6c, F=0x0 -0, 2402424, 2402424, 40040, 29134, 0xf784be18 +0, 2402424, 2402424, 40040, 29134, 0x4b80be18 0, 2442464, 2442464, 40040, 10232, 0x5408e15b, F=0x0 0, 2482505, 2482505, 40040, 9769, 0xc93cb7f9, F=0x0 0, 2522545, 2522545, 40040, 14454, 0x45230dbe, F=0x0 @@ -81,7 +81,7 @@ 0, 2882909, 2882909, 40040, 14801, 0x40bae016, F=0x0 0, 2922949, 2922949, 40040, 17303, 0x9ce1fd31, F=0x0 0, 2962990, 2962990, 40040, 17678, 0x9bd66141, F=0x0 -0, 3003030, 3003030, 40040, 48672, 0x3215ce46 +0, 3003030, 3003030, 40040, 48672, 0x8602ce46 0, 3043070, 3043070, 40040, 11894, 0x12e1fece, F=0x0 0, 3083111, 3083111, 40040, 16514, 0xc57aed05, F=0x0 0, 3123151, 3123151, 40040, 13044, 0x61914fa0, F=0x0 @@ -96,7 +96,7 @@ 0, 3483515, 3483515, 40040, 12208, 0x81a587c0, F=0x0 0, 3523555, 3523555, 40040, 14709, 0x5dffbe04, F=0x0 0, 3563596, 3563596, 40040, 14390, 0xbfd1e041, F=0x0 -0, 3603636, 3603636, 40040, 37236, 0xe7f924b1 +0, 3603636, 3603636, 40040, 37236, 0x3bf524b1 0, 3643676, 3643676, 40040, 14056, 0x24714c7c, F=0x0 0, 3683717, 3683717, 40040, 19438, 0x0c50dcd5, F=0x0 0, 3723757, 3723757, 40040, 21728, 0x7eea4a11, F=0x0 @@ -111,7 +111,7 @@ 0, 4084121, 4084121, 40040, 16878, 0x98efbae2, F=0x0 0, 4124161, 4124161, 40040, 14685, 0x1bf78d65, F=0x0 0, 4164202, 4164202, 40040, 13127, 0x0b91881d, F=0x0 -0, 4204242, 4204242, 40040, 29390, 0xf6a5ed6b +0, 4204242, 4204242, 40040, 29390, 0x4aa1ed6b 0, 4244282, 4244282, 40040, 12576, 0xe9845ded, F=0x0 0, 4284323, 4284323, 40040, 12599, 0x96a79ab8, F=0x0 0, 4324363, 4324363, 40040, 16134, 0xb4c36d3f, F=0x0 diff --git a/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov b/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov index 50dfed6e4..7ecba80e0 100644 --- a/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov +++ b/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov @@ -69,6 +69,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=eng TAG:handler_name=Module de gestion video TAG:vendor_id=FFMP diff --git a/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov b/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov index 79e3731a3..24369cce2 100644 --- a/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov +++ b/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov @@ -69,6 +69,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=eng TAG:handler_name=Module de gestion video TAG:vendor_id=FFMP diff --git a/tests/ref/fate/hevc-afd-tc-sei b/tests/ref/fate/hevc-afd-tc-sei index 27eb3fc8d..735226745 100644 --- a/tests/ref/fate/hevc-afd-tc-sei +++ b/tests/ref/fate/hevc-afd-tc-sei @@ -202,3 +202,39 @@ value=00:00:00:00 [/TIMECODE] [/SIDE_DATA] [/FRAME] +[FRAME] +[SIDE_DATA] +side_data_type=Active format description +active_format=8 +[/SIDE_DATA] +[SIDE_DATA] +side_data_type=SMPTE 12-1 timecode +[TIMECODE] +value=00:00:00:00 +[/TIMECODE] +[/SIDE_DATA] +[/FRAME] +[FRAME] +[SIDE_DATA] +side_data_type=Active format description +active_format=8 +[/SIDE_DATA] +[SIDE_DATA] +side_data_type=SMPTE 12-1 timecode +[TIMECODE] +value=00:00:00:00 +[/TIMECODE] +[/SIDE_DATA] +[/FRAME] +[FRAME] +[SIDE_DATA] +side_data_type=Active format description +active_format=8 +[/SIDE_DATA] +[SIDE_DATA] +side_data_type=SMPTE 12-1 timecode +[TIMECODE] +value=00:00:00:00 +[/TIMECODE] +[/SIDE_DATA] +[/FRAME] diff --git a/tests/ref/fate/hevc-conformance-MVHEVCS_A b/tests/ref/fate/hevc-conformance-MVHEVCS_A new file mode 100644 index 000000000..c91988920 --- /dev/null +++ b/tests/ref/fate/hevc-conformance-MVHEVCS_A @@ -0,0 +1,106 @@ +#tb 0: 1/1200000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1024x768 +#sar 0: 0/1 +#tb 1: 1/1200000 +#media_type 1: video +#codec_id 1: rawvideo +#dimensions 1: 1024x768 +#sar 1: 0/1 +0, 0, 0, 0, 1179648, 0x4a15620e +1, 0, 0, 0, 1179648, 0x5b752453 +0, 1, 1, 0, 1179648, 0xb33277fe +1, 1, 1, 0, 1179648, 0xacf4376d +0, 2, 2, 0, 1179648, 0x97b969bd +1, 2, 2, 0, 1179648, 0xa9d6e75d +0, 3, 3, 0, 1179648, 0x3c6b7b81 +1, 3, 3, 0, 1179648, 0x2142cc59 +0, 4, 4, 0, 1179648, 0xdf83fe63 +1, 4, 4, 0, 1179648, 0x838d4f0a +0, 5, 5, 0, 1179648, 0x93fc3bdf +1, 5, 5, 0, 1179648, 0x29bc71c2 +0, 6, 6, 0, 1179648, 0x18f90aa3 +1, 6, 6, 0, 1179648, 0x3b25ee18 +0, 7, 7, 0, 1179648, 0x84c730c5 +1, 7, 7, 0, 1179648, 0x60ecae5b +0, 8, 8, 0, 1179648, 0x7b49f2b1 +1, 8, 8, 0, 1179648, 0x8c3c635e +0, 9, 9, 0, 1179648, 0x71f1b862 +1, 9, 9, 0, 1179648, 0x16c2a6fc +0, 10, 10, 0, 1179648, 0x92be991a +1, 10, 10, 0, 1179648, 0x092d6378 +0, 11, 11, 0, 1179648, 0xa948322d +1, 11, 11, 0, 1179648, 0x5d977eec +0, 12, 12, 0, 1179648, 0x54838c22 +1, 12, 12, 0, 1179648, 0x66fc891e +0, 13, 13, 0, 1179648, 0xc2682668 +1, 13, 13, 0, 1179648, 0x0b60bd06 +0, 14, 14, 0, 1179648, 0x1fa22020 +1, 14, 14, 0, 1179648, 0x201706e2 +0, 15, 15, 0, 1179648, 0x3a686683 +1, 15, 15, 0, 1179648, 0x9c59849c +0, 16, 16, 0, 1179648, 0x991431ab +1, 16, 16, 0, 1179648, 0xb495ba09 +0, 17, 17, 0, 1179648, 0xd394e067 +1, 17, 17, 0, 1179648, 0x1d1db0c6 +0, 18, 18, 0, 1179648, 0xbe694632 +1, 18, 18, 0, 1179648, 0x22beec67 +0, 19, 19, 0, 1179648, 0x8a48c7a7 +1, 19, 19, 0, 1179648, 0x3515ac62 +0, 20, 20, 0, 1179648, 0x8d7e9e6d +1, 20, 20, 0, 1179648, 0x3b73015b +0, 21, 21, 0, 1179648, 0x14f28d47 +1, 21, 21, 0, 1179648, 0x4e01fdb7 +0, 22, 22, 0, 1179648, 0x1885631b +1, 22, 22, 0, 1179648, 0xca33f8de +0, 23, 23, 0, 1179648, 0x29c795f1 +1, 23, 23, 0, 1179648, 0x925517c1 +0, 24, 24, 0, 1179648, 0xee23fd91 +1, 24, 24, 0, 1179648, 0x0894bf6a +0, 25, 25, 0, 1179648, 0xa57dce94 +1, 25, 25, 0, 1179648, 0xebfe296d +0, 26, 26, 0, 1179648, 0x6c3b16d8 +1, 26, 26, 0, 1179648, 0x62acb3e0 +0, 27, 27, 0, 1179648, 0xbf5a112f +1, 27, 27, 0, 1179648, 0x72f6ae90 +0, 28, 28, 0, 1179648, 0x5e7ce2a7 +1, 28, 28, 0, 1179648, 0xb4c6bcbc +0, 29, 29, 0, 1179648, 0x0529ad59 +1, 29, 29, 0, 1179648, 0x438c8160 +0, 30, 30, 0, 1179648, 0xc94d561d +1, 30, 30, 0, 1179648, 0x1b3a02af +0, 31, 31, 0, 1179648, 0x7079bbc0 +1, 31, 31, 0, 1179648, 0x6034d275 +0, 32, 32, 0, 1179648, 0x6c8e1265 +1, 32, 32, 0, 1179648, 0x9e688ee2 +0, 33, 33, 0, 1179648, 0x5e1494ee +1, 33, 33, 0, 1179648, 0xe39cab5d +0, 34, 34, 0, 1179648, 0xe3654994 +1, 34, 34, 0, 1179648, 0xeefe533b +0, 35, 35, 0, 1179648, 0x329510fa +1, 35, 35, 0, 1179648, 0x48ed2162 +0, 36, 36, 0, 1179648, 0x92120a9f +1, 36, 36, 0, 1179648, 0xb0fb26b3 +0, 37, 37, 0, 1179648, 0x6f279a56 +1, 37, 37, 0, 1179648, 0xc4185523 +0, 38, 38, 0, 1179648, 0xd2ad5c1d +1, 38, 38, 0, 1179648, 0x8124687d +0, 39, 39, 0, 1179648, 0xd7e5bbaa +1, 39, 39, 0, 1179648, 0x39f1b702 +0, 40, 40, 0, 1179648, 0xb5628743 +1, 40, 40, 0, 1179648, 0xee5802d7 +0, 41, 41, 0, 1179648, 0x2760515e +1, 41, 41, 0, 1179648, 0xdeac4fbd +0, 42, 42, 0, 1179648, 0x11a2f57a +1, 42, 42, 0, 1179648, 0xb1c7977f +0, 43, 43, 0, 1179648, 0x2c47dd8f +1, 43, 43, 0, 1179648, 0xaaaddace +0, 44, 44, 0, 1179648, 0x890fe8c2 +1, 44, 44, 0, 1179648, 0x7ff8e81e +0, 45, 45, 0, 1179648, 0x65e9f9ac +1, 45, 45, 0, 1179648, 0xf9b1b99c +0, 46, 46, 0, 1179648, 0x3e4fa8d9 +1, 46, 46, 0, 1179648, 0xfc3659e6 +0, 47, 47, 0, 1179648, 0x356e13ee +1, 47, 47, 0, 1179648, 0xff8bfa3f diff --git a/tests/ref/fate/hevc-conformance-MVHEVCS_B b/tests/ref/fate/hevc-conformance-MVHEVCS_B new file mode 100644 index 000000000..07155c50e --- /dev/null +++ b/tests/ref/fate/hevc-conformance-MVHEVCS_B @@ -0,0 +1,138 @@ +#tb 0: 1/1200000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1024x768 +#sar 0: 0/1 +#tb 1: 1/1200000 +#media_type 1: video +#codec_id 1: rawvideo +#dimensions 1: 1024x768 +#sar 1: 0/1 +0, 0, 0, 0, 1179648, 0x4b39cdfe +1, 0, 0, 0, 1179648, 0x1afcd2a3 +0, 1, 1, 0, 1179648, 0xef0da64e +1, 1, 1, 0, 1179648, 0x2bb1d07b +0, 2, 2, 0, 1179648, 0x9dd9e5a7 +1, 2, 2, 0, 1179648, 0xcc0547f2 +0, 3, 3, 0, 1179648, 0xee948285 +1, 3, 3, 0, 1179648, 0x3375f14b +0, 4, 4, 0, 1179648, 0x75117927 +1, 4, 4, 0, 1179648, 0x1e059655 +0, 5, 5, 0, 1179648, 0xad9fec31 +1, 5, 5, 0, 1179648, 0xfed7ef37 +0, 6, 6, 0, 1179648, 0x53cd0f53 +1, 6, 6, 0, 1179648, 0xa725f316 +0, 7, 7, 0, 1179648, 0xcbda04b5 +1, 7, 7, 0, 1179648, 0xd13b99db +0, 8, 8, 0, 1179648, 0x71861302 +1, 8, 8, 0, 1179648, 0x911d2c79 +0, 9, 9, 0, 1179648, 0x5d2564dd +1, 9, 9, 0, 1179648, 0x70fa087a +0, 10, 10, 0, 1179648, 0xcfa6d394 +1, 10, 10, 0, 1179648, 0x69a27b84 +0, 11, 11, 0, 1179648, 0x18fe7393 +1, 11, 11, 0, 1179648, 0xcc665fd1 +0, 12, 12, 0, 1179648, 0xb329d489 +1, 12, 12, 0, 1179648, 0xf8d93bbf +0, 13, 13, 0, 1179648, 0x3b029004 +1, 13, 13, 0, 1179648, 0x39655020 +0, 14, 14, 0, 1179648, 0x6c81bf8e +1, 14, 14, 0, 1179648, 0x13da6f67 +0, 15, 15, 0, 1179648, 0x25e3e0a9 +1, 15, 15, 0, 1179648, 0xdc372a0f +0, 16, 16, 0, 1179648, 0x8f2c789f +1, 16, 16, 0, 1179648, 0xba8a3e23 +0, 17, 17, 0, 1179648, 0x372b866f +1, 17, 17, 0, 1179648, 0x27d31b48 +0, 18, 18, 0, 1179648, 0x5cfc8119 +1, 18, 18, 0, 1179648, 0x50aca559 +0, 19, 19, 0, 1179648, 0x593af76c +1, 19, 19, 0, 1179648, 0x27c0e522 +0, 20, 20, 0, 1179648, 0x852864b7 +1, 20, 20, 0, 1179648, 0xa8739c77 +0, 21, 21, 0, 1179648, 0x71f4b961 +1, 21, 21, 0, 1179648, 0x27c16037 +0, 22, 22, 0, 1179648, 0x6c5ebb84 +1, 22, 22, 0, 1179648, 0x74a6ede9 +0, 23, 23, 0, 1179648, 0xb5467da9 +1, 23, 23, 0, 1179648, 0x1ea455b9 +0, 24, 24, 0, 1179648, 0x92d58478 +1, 24, 24, 0, 1179648, 0x9e464f3a +0, 25, 25, 0, 1179648, 0xa6181655 +1, 25, 25, 0, 1179648, 0x8af4fd5b +0, 26, 26, 0, 1179648, 0x15e9ee9a +1, 26, 26, 0, 1179648, 0xa6ed4580 +0, 27, 27, 0, 1179648, 0x4782abf9 +1, 27, 27, 0, 1179648, 0x73fc62e6 +0, 28, 28, 0, 1179648, 0x8c06f337 +1, 28, 28, 0, 1179648, 0xb2d3dfbf +0, 29, 29, 0, 1179648, 0x2e6b1a88 +1, 29, 29, 0, 1179648, 0x2066f08e +0, 30, 30, 0, 1179648, 0x584eac3e +1, 30, 30, 0, 1179648, 0xa0bfb75b +0, 31, 31, 0, 1179648, 0x9a2dae49 +1, 31, 31, 0, 1179648, 0x89445161 +0, 32, 32, 0, 1179648, 0x3a50c6f4 +1, 32, 32, 0, 1179648, 0x9befaa17 +0, 33, 33, 0, 1179648, 0x1afcbfd6 +1, 33, 33, 0, 1179648, 0xb243de65 +0, 34, 34, 0, 1179648, 0xfdda4e8c +1, 34, 34, 0, 1179648, 0xf945451a +0, 35, 35, 0, 1179648, 0x8fffa546 +1, 35, 35, 0, 1179648, 0x06b20109 +0, 36, 36, 0, 1179648, 0xbc2c9dfc +1, 36, 36, 0, 1179648, 0x344c1ed8 +0, 37, 37, 0, 1179648, 0xb2d08414 +1, 37, 37, 0, 1179648, 0xccd35195 +0, 38, 38, 0, 1179648, 0x54886d31 +1, 38, 38, 0, 1179648, 0x653ed9df +0, 39, 39, 0, 1179648, 0x07c3b249 +1, 39, 39, 0, 1179648, 0xf92b9e88 +0, 40, 40, 0, 1179648, 0x073b9491 +1, 40, 40, 0, 1179648, 0x4ed7ee12 +0, 41, 41, 0, 1179648, 0xcd669799 +1, 41, 41, 0, 1179648, 0xa7faed20 +0, 42, 42, 0, 1179648, 0xd21b0a28 +1, 42, 42, 0, 1179648, 0xb34d0f7f +0, 43, 43, 0, 1179648, 0xb4b820c9 +1, 43, 43, 0, 1179648, 0xf496d13d +0, 44, 44, 0, 1179648, 0x2d2940d0 +1, 44, 44, 0, 1179648, 0x985d67f5 +0, 45, 45, 0, 1179648, 0x919c554a +1, 45, 45, 0, 1179648, 0x697d0b66 +0, 46, 46, 0, 1179648, 0x7dd28f61 +1, 46, 46, 0, 1179648, 0x504d6971 +0, 47, 47, 0, 1179648, 0x51af9760 +1, 47, 47, 0, 1179648, 0x956d7fb1 +0, 48, 48, 0, 1179648, 0x8801beba +1, 48, 48, 0, 1179648, 0xec62570e +0, 49, 49, 0, 1179648, 0x80b37318 +1, 49, 49, 0, 1179648, 0x48284486 +0, 50, 50, 0, 1179648, 0x91c52522 +1, 50, 50, 0, 1179648, 0xe3a72477 +0, 51, 51, 0, 1179648, 0x6721373b +1, 51, 51, 0, 1179648, 0x9fb05dfa +0, 52, 52, 0, 1179648, 0xd2a250ca +1, 52, 52, 0, 1179648, 0xbd294daf +0, 53, 53, 0, 1179648, 0x6005c976 +1, 53, 53, 0, 1179648, 0x7f311bbb +0, 54, 54, 0, 1179648, 0x2d42f334 +1, 54, 54, 0, 1179648, 0x3bea1741 +0, 55, 55, 0, 1179648, 0xd696879d +1, 55, 55, 0, 1179648, 0x9b3259fd +0, 56, 56, 0, 1179648, 0x3324c463 +1, 56, 56, 0, 1179648, 0xc90f475d +0, 57, 57, 0, 1179648, 0x824c47df +1, 57, 57, 0, 1179648, 0x0effe63f +0, 58, 58, 0, 1179648, 0x06abf15f +1, 58, 58, 0, 1179648, 0x646ee426 +0, 59, 59, 0, 1179648, 0x34ef0c34 +1, 59, 59, 0, 1179648, 0x0fe901c7 +0, 60, 60, 0, 1179648, 0x54a6ef58 +1, 60, 60, 0, 1179648, 0xb726f458 +0, 61, 61, 0, 1179648, 0x4e9c7db9 +1, 61, 61, 0, 1179648, 0xf28adc7e +0, 62, 62, 0, 1179648, 0x70887af9 +1, 62, 62, 0, 1179648, 0x00258e2f +0, 63, 63, 0, 1179648, 0x661779d7 +1, 63, 63, 0, 1179648, 0x4598b8f7 diff --git a/tests/ref/fate/hevc-conformance-MVHEVCS_E b/tests/ref/fate/hevc-conformance-MVHEVCS_E new file mode 100644 index 000000000..19a4a3e86 --- /dev/null +++ b/tests/ref/fate/hevc-conformance-MVHEVCS_E @@ -0,0 +1,106 @@ +#tb 0: 1/1200000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1024x768 +#sar 0: 0/1 +#tb 1: 1/1200000 +#media_type 1: video +#codec_id 1: rawvideo +#dimensions 1: 1024x768 +#sar 1: 0/1 +0, 0, 0, 0, 1179648, 0x4a15620e +1, 0, 0, 0, 1179648, 0x5b752453 +0, 1, 1, 0, 1179648, 0xb33277fe +1, 1, 1, 0, 1179648, 0xacf4376d +0, 2, 2, 0, 1179648, 0x97b969bd +1, 2, 2, 0, 1179648, 0xa9d6e75d +0, 3, 3, 0, 1179648, 0x3c6b7b81 +1, 3, 3, 0, 1179648, 0x2142cc59 +0, 4, 4, 0, 1179648, 0xdf83fe63 +1, 4, 4, 0, 1179648, 0x838d4f0a +0, 5, 5, 0, 1179648, 0x93fc3bdf +1, 5, 5, 0, 1179648, 0x29bc71c2 +0, 6, 6, 0, 1179648, 0x18f90aa3 +1, 6, 6, 0, 1179648, 0x3b25ee18 +0, 7, 7, 0, 1179648, 0x84c730c5 +1, 7, 7, 0, 1179648, 0x60ecae5b +0, 8, 8, 0, 1179648, 0x7b49f2b1 +1, 8, 8, 0, 1179648, 0x8c3c635e +0, 9, 9, 0, 1179648, 0x60956482 +1, 9, 9, 0, 1179648, 0x8f4cb379 +0, 10, 10, 0, 1179648, 0x7af31124 +1, 10, 10, 0, 1179648, 0x398fec3c +0, 11, 11, 0, 1179648, 0xf56c7994 +1, 11, 11, 0, 1179648, 0xced70ad2 +0, 12, 12, 0, 1179648, 0x1fbd6730 +1, 12, 12, 0, 1179648, 0x4d85d789 +0, 13, 13, 0, 1179648, 0xf986b387 +1, 13, 13, 0, 1179648, 0xca3a70ea +0, 14, 14, 0, 1179648, 0xe3d5f7c5 +1, 14, 14, 0, 1179648, 0xcda13236 +0, 15, 15, 0, 1179648, 0xc646c7d1 +1, 15, 15, 0, 1179648, 0xe64a93c3 +0, 16, 16, 0, 1179648, 0xed69e4bc +1, 16, 16, 0, 1179648, 0x4426cbae +0, 17, 17, 0, 1179648, 0xaea6e7da +1, 17, 17, 0, 1179648, 0x544d045f +0, 18, 18, 0, 1179648, 0xbde3196f +1, 18, 18, 0, 1179648, 0x62b07e2a +0, 19, 19, 0, 1179648, 0x86beaf83 +1, 19, 19, 0, 1179648, 0x4ae8ac0e +0, 20, 20, 0, 1179648, 0xe162f75d +1, 20, 20, 0, 1179648, 0x092cad19 +0, 21, 21, 0, 1179648, 0xee24e674 +1, 21, 21, 0, 1179648, 0x8eab2b13 +0, 22, 22, 0, 1179648, 0xe887594a +1, 22, 22, 0, 1179648, 0x71fa0330 +0, 23, 23, 0, 1179648, 0x34a281d4 +1, 23, 23, 0, 1179648, 0xb0924dbb +0, 24, 24, 0, 1179648, 0x7ec4e840 +1, 24, 24, 0, 1179648, 0x895d98be +0, 25, 25, 0, 1179648, 0xd89577ca +1, 25, 25, 0, 1179648, 0xd91c1ea6 +0, 26, 26, 0, 1179648, 0xdc6e9c96 +1, 26, 26, 0, 1179648, 0x1b4c5dee +0, 27, 27, 0, 1179648, 0x51add2ea +1, 27, 27, 0, 1179648, 0x88c1a214 +0, 28, 28, 0, 1179648, 0x2fc19963 +1, 28, 28, 0, 1179648, 0x5861006d +0, 29, 29, 0, 1179648, 0x32243191 +1, 29, 29, 0, 1179648, 0xd4ed787c +0, 30, 30, 0, 1179648, 0xb7e2a2d8 +1, 30, 30, 0, 1179648, 0x1911a0e0 +0, 31, 31, 0, 1179648, 0x81662c81 +1, 31, 31, 0, 1179648, 0x5a37d3db +0, 32, 32, 0, 1179648, 0x4e12d459 +1, 32, 32, 0, 1179648, 0x05d5a5a9 +0, 33, 33, 0, 1179648, 0x1dc706da +1, 33, 33, 0, 1179648, 0x59f898f8 +0, 34, 34, 0, 1179648, 0x585dd375 +1, 34, 34, 0, 1179648, 0x7aa2fa66 +0, 35, 35, 0, 1179648, 0x24f7efb1 +1, 35, 35, 0, 1179648, 0x868149ad +0, 36, 36, 0, 1179648, 0xf56aa128 +1, 36, 36, 0, 1179648, 0x4c0a3019 +0, 37, 37, 0, 1179648, 0x1b87470b +1, 37, 37, 0, 1179648, 0x94bea701 +0, 38, 38, 0, 1179648, 0x368f745f +1, 38, 38, 0, 1179648, 0xf6c2b923 +0, 39, 39, 0, 1179648, 0xf0e62ce7 +1, 39, 39, 0, 1179648, 0xcc7c08c4 +0, 40, 40, 0, 1179648, 0xfc66a8a2 +1, 40, 40, 0, 1179648, 0x21afffac +0, 41, 41, 0, 1179648, 0xd136f02f +1, 41, 41, 0, 1179648, 0x0339f774 +0, 42, 42, 0, 1179648, 0x370dec8e +1, 42, 42, 0, 1179648, 0x6a66793e +0, 43, 43, 0, 1179648, 0x5e4de669 +1, 43, 43, 0, 1179648, 0x17f5ae53 +0, 44, 44, 0, 1179648, 0xc0f0e971 +1, 44, 44, 0, 1179648, 0xa741e3bf +0, 45, 45, 0, 1179648, 0x88315d92 +1, 45, 45, 0, 1179648, 0xa7895cc1 +0, 46, 46, 0, 1179648, 0x1c4eb46c +1, 46, 46, 0, 1179648, 0x0228cf31 +0, 47, 47, 0, 1179648, 0x30384288 +1, 47, 47, 0, 1179648, 0x870f2d06 diff --git a/tests/ref/fate/hevc-conformance-MVHEVCS_F b/tests/ref/fate/hevc-conformance-MVHEVCS_F new file mode 100644 index 000000000..377035441 --- /dev/null +++ b/tests/ref/fate/hevc-conformance-MVHEVCS_F @@ -0,0 +1,106 @@ +#tb 0: 1/1200000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1024x768 +#sar 0: 0/1 +#tb 1: 1/1200000 +#media_type 1: video +#codec_id 1: rawvideo +#dimensions 1: 1024x768 +#sar 1: 0/1 +0, 0, 0, 0, 1179648, 0x4a15620e +1, 0, 0, 0, 1179648, 0x5b752453 +0, 1, 1, 0, 1179648, 0x568f99cf +1, 1, 1, 0, 1179648, 0xacf4376d +0, 2, 2, 0, 1179648, 0xea67491c +1, 2, 2, 0, 1179648, 0xa9d6e75d +0, 3, 3, 0, 1179648, 0x57ed0a7f +1, 3, 3, 0, 1179648, 0x2142cc59 +0, 4, 4, 0, 1179648, 0x5b218d68 +1, 4, 4, 0, 1179648, 0x838d4f0a +0, 5, 5, 0, 1179648, 0x8075c0c0 +1, 5, 5, 0, 1179648, 0x29bc71c2 +0, 6, 6, 0, 1179648, 0x75e0bb9f +1, 6, 6, 0, 1179648, 0x3b25ee18 +0, 7, 7, 0, 1179648, 0xaef237d0 +1, 7, 7, 0, 1179648, 0x60ecae5b +0, 8, 8, 0, 1179648, 0x9943126a +1, 8, 8, 0, 1179648, 0x8c3c635e +0, 9, 9, 0, 1179648, 0x3c8bbac8 +1, 9, 9, 0, 1179648, 0x8f4cb379 +0, 10, 10, 0, 1179648, 0xad824cae +1, 10, 10, 0, 1179648, 0x398fec3c +0, 11, 11, 0, 1179648, 0x3c156c58 +1, 11, 11, 0, 1179648, 0xced70ad2 +0, 12, 12, 0, 1179648, 0x18261259 +1, 12, 12, 0, 1179648, 0x4d85d789 +0, 13, 13, 0, 1179648, 0xd481dafa +1, 13, 13, 0, 1179648, 0xca3a70ea +0, 14, 14, 0, 1179648, 0x6a0d3af8 +1, 14, 14, 0, 1179648, 0xcda13236 +0, 15, 15, 0, 1179648, 0xaa355e8f +1, 15, 15, 0, 1179648, 0xe64a93c3 +0, 16, 16, 0, 1179648, 0xed69e4bc +1, 16, 16, 0, 1179648, 0x4426cbae +0, 17, 17, 0, 1179648, 0x340d6c4a +1, 17, 17, 0, 1179648, 0x544d045f +0, 18, 18, 0, 1179648, 0xd52398d0 +1, 18, 18, 0, 1179648, 0x62b07e2a +0, 19, 19, 0, 1179648, 0x39d92b93 +1, 19, 19, 0, 1179648, 0x4ae8ac0e +0, 20, 20, 0, 1179648, 0x364fd94f +1, 20, 20, 0, 1179648, 0x092cad19 +0, 21, 21, 0, 1179648, 0x977cabf5 +1, 21, 21, 0, 1179648, 0x8eab2b13 +0, 22, 22, 0, 1179648, 0x23febfaf +1, 22, 22, 0, 1179648, 0x71fa0330 +0, 23, 23, 0, 1179648, 0xd7e5afa0 +1, 23, 23, 0, 1179648, 0xb0924dbb +0, 24, 24, 0, 1179648, 0x83799fed +1, 24, 24, 0, 1179648, 0x895d98be +0, 25, 25, 0, 1179648, 0xaec7466c +1, 25, 25, 0, 1179648, 0xd91c1ea6 +0, 26, 26, 0, 1179648, 0x4c4de340 +1, 26, 26, 0, 1179648, 0x1b4c5dee +0, 27, 27, 0, 1179648, 0x1c8c5bf6 +1, 27, 27, 0, 1179648, 0x88c1a214 +0, 28, 28, 0, 1179648, 0xc980311c +1, 28, 28, 0, 1179648, 0x5861006d +0, 29, 29, 0, 1179648, 0xb55dbf43 +1, 29, 29, 0, 1179648, 0xd4ed787c +0, 30, 30, 0, 1179648, 0xbc29868a +1, 30, 30, 0, 1179648, 0x1911a0e0 +0, 31, 31, 0, 1179648, 0x3d1dfc87 +1, 31, 31, 0, 1179648, 0x5a37d3db +0, 32, 32, 0, 1179648, 0x4e12d459 +1, 32, 32, 0, 1179648, 0x05d5a5a9 +0, 33, 33, 0, 1179648, 0xb4eb0d99 +1, 33, 33, 0, 1179648, 0x59f898f8 +0, 34, 34, 0, 1179648, 0x1d91ae23 +1, 34, 34, 0, 1179648, 0x7aa2fa66 +0, 35, 35, 0, 1179648, 0x0adf2e05 +1, 35, 35, 0, 1179648, 0x868149ad +0, 36, 36, 0, 1179648, 0x947e48dd +1, 36, 36, 0, 1179648, 0x4c0a3019 +0, 37, 37, 0, 1179648, 0xb7dddffd +1, 37, 37, 0, 1179648, 0x94bea701 +0, 38, 38, 0, 1179648, 0x027f1113 +1, 38, 38, 0, 1179648, 0xf6c2b923 +0, 39, 39, 0, 1179648, 0xc2a0afa2 +1, 39, 39, 0, 1179648, 0xcc7c08c4 +0, 40, 40, 0, 1179648, 0xd12a6bc0 +1, 40, 40, 0, 1179648, 0x21afffac +0, 41, 41, 0, 1179648, 0xf8f5d7ee +1, 41, 41, 0, 1179648, 0x0339f774 +0, 42, 42, 0, 1179648, 0xa7e5fd01 +1, 42, 42, 0, 1179648, 0x6a66793e +0, 43, 43, 0, 1179648, 0xe9aee64d +1, 43, 43, 0, 1179648, 0x17f5ae53 +0, 44, 44, 0, 1179648, 0x989fc660 +1, 44, 44, 0, 1179648, 0xa741e3bf +0, 45, 45, 0, 1179648, 0x43e1d4d0 +1, 45, 45, 0, 1179648, 0xa7895cc1 +0, 46, 46, 0, 1179648, 0x38be7f17 +1, 46, 46, 0, 1179648, 0x0228cf31 +0, 47, 47, 0, 1179648, 0xd867c854 +1, 47, 47, 0, 1179648, 0x870f2d06 diff --git a/tests/ref/fate/hevc-mv-nuh-layer-id b/tests/ref/fate/hevc-mv-nuh-layer-id new file mode 100644 index 000000000..3cbefe17f --- /dev/null +++ b/tests/ref/fate/hevc-mv-nuh-layer-id @@ -0,0 +1,15 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x128 +#sar 0: 0/1 +0, 0, 0, 1, 24576, 0xdfd350a6 +0, 1, 1, 1, 24576, 0xf8f638da +0, 2, 2, 1, 24576, 0x8ac574d5 +0, 3, 3, 1, 24576, 0xd22675a4 +0, 4, 4, 1, 24576, 0xdd0f4704 +0, 5, 5, 1, 24576, 0x60da42e6 +0, 6, 6, 1, 24576, 0x8bf28fdd +0, 7, 7, 1, 24576, 0xe0577f6e +0, 8, 8, 1, 24576, 0x8b3e3c29 +0, 9, 9, 1, 24576, 0x8d9944bd diff --git a/tests/ref/fate/hevc-mv-position b/tests/ref/fate/hevc-mv-position new file mode 100644 index 000000000..660789557 --- /dev/null +++ b/tests/ref/fate/hevc-mv-position @@ -0,0 +1,32 @@ +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 0/1 +#tb 1: 1/30 +#media_type 1: video +#codec_id 1: rawvideo +#dimensions 1: 1920x1080 +#sar 1: 0/1 +0, 0, 0, 1, 3110400, 0xd0ce90de +1, 0, 0, 1, 3110400, 0x1859a3ba +0, 1, 1, 1, 3110400, 0x5ce1bc1a +1, 1, 1, 1, 3110400, 0x43cf57e5 +0, 2, 2, 1, 3110400, 0x14cf9f7f +1, 2, 2, 1, 3110400, 0x4ffc98ea +0, 3, 3, 1, 3110400, 0x9a6bb93c +1, 3, 3, 1, 3110400, 0x96a2bcfb +0, 4, 4, 1, 3110400, 0x69e5377d +1, 4, 4, 1, 3110400, 0xec4561f0 +0, 5, 5, 1, 3110400, 0x66b3bd5d +1, 5, 5, 1, 3110400, 0x633f23f5 +0, 6, 6, 1, 3110400, 0x83a2ada2 +1, 6, 6, 1, 3110400, 0xe10a2fe7 +0, 7, 7, 1, 3110400, 0x503bbe42 +1, 7, 7, 1, 3110400, 0x8ecd5c39 +0, 8, 8, 1, 3110400, 0xaeb27981 +1, 8, 8, 1, 3110400, 0xe571a478 +0, 9, 9, 1, 3110400, 0xbe14bf1e +1, 9, 9, 1, 3110400, 0x87d4dbe3 +0, 10, 10, 1, 3110400, 0xbd329d79 +1, 10, 10, 1, 3110400, 0xc78097f4 diff --git a/tests/ref/fate/hevc-mv-switch b/tests/ref/fate/hevc-mv-switch new file mode 100644 index 000000000..40d7f29ad --- /dev/null +++ b/tests/ref/fate/hevc-mv-switch @@ -0,0 +1,172 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 416x240 +#sar 0: 0/1 +#tb 1: 1/25 +#media_type 1: video +#codec_id 1: rawvideo +#dimensions 1: 128x128 +#sar 1: 0/1 +0, 0, 0, 1, 149760, 0x94a51701 +0, 1, 1, 1, 149760, 0x67c71885 +0, 2, 2, 1, 149760, 0x218f1751 +0, 3, 3, 1, 149760, 0x56951bef +0, 4, 4, 1, 149760, 0x76aec81e +0, 5, 5, 1, 149760, 0x20df61ac +0, 6, 6, 1, 149760, 0x2eacf616 +0, 7, 7, 1, 149760, 0x06322ce2 +0, 8, 8, 1, 149760, 0xf14aa104 +0, 9, 9, 1, 149760, 0x9e1cf00a +1, 10, 10, 1, 24576, 0xf8f638da +0, 11, 11, 1, 149760, 0x6d584d2c +1, 12, 12, 1, 24576, 0xd22675a4 +0, 13, 13, 1, 149760, 0x8b21be89 +1, 14, 14, 1, 24576, 0x60da42e6 +0, 15, 15, 1, 149760, 0x3946d0ec +1, 16, 16, 1, 24576, 0xe0577f6e +0, 17, 17, 1, 149760, 0x70859214 +1, 18, 18, 1, 24576, 0x8d9944bd +0, 19, 19, 1, 149760, 0xd60e93f1 +0, 20, 20, 1, 149760, 0xb07cc873 +0, 21, 21, 1, 149760, 0x86eacff5 +0, 22, 22, 1, 149760, 0x259afb24 +0, 23, 23, 1, 149760, 0x225dd819 +0, 24, 24, 1, 149760, 0xfc47134c +0, 25, 25, 1, 149760, 0x15da1ece +0, 26, 26, 1, 149760, 0xb2ec5b6f +0, 27, 27, 1, 149760, 0xa18f35c6 +0, 28, 28, 1, 149760, 0x8fa8970f +0, 29, 29, 1, 149760, 0x25a87e60 +0, 30, 30, 1, 149760, 0x77c88c93 +0, 31, 31, 1, 149760, 0xcb673be3 +0, 32, 32, 1, 149760, 0x219f51e6 +0, 33, 33, 1, 149760, 0x59ea3783 +0, 34, 34, 1, 149760, 0x837644b5 +0, 35, 35, 1, 149760, 0x9b62bc7c +0, 36, 36, 1, 149760, 0xbb32efa8 +0, 37, 37, 1, 149760, 0x1a1bcf3f +0, 38, 38, 1, 149760, 0x9673c0e1 +0, 39, 39, 1, 149760, 0x7c6461e2 +0, 40, 40, 1, 149760, 0x0551768c +0, 41, 41, 1, 149760, 0xa5ce5d3a +0, 42, 42, 1, 149760, 0xe9caa587 +0, 43, 43, 1, 149760, 0xf38613ea +0, 44, 44, 1, 149760, 0x02083cce +0, 45, 45, 1, 149760, 0xd5f0ce4e +0, 46, 46, 1, 149760, 0xb9ed49cd +0, 47, 47, 1, 149760, 0xdbe0d518 +0, 48, 48, 1, 149760, 0x80f607ca +0, 49, 49, 1, 149760, 0x9f7e3d36 +0, 50, 50, 1, 149760, 0x7f73121f +0, 51, 51, 1, 149760, 0x4cff0e8b +0, 52, 52, 1, 149760, 0x638dd91d +0, 53, 53, 1, 149760, 0xe28dd86b +0, 54, 54, 1, 149760, 0xc2b89e3a +0, 55, 55, 1, 149760, 0xe8b67842 +0, 56, 56, 1, 149760, 0xc69fe16f +0, 57, 57, 1, 149760, 0xb8b5f913 +0, 58, 58, 1, 149760, 0x5fac972a +0, 59, 59, 1, 149760, 0x0306ed25 +0, 60, 60, 1, 149760, 0x94271af0 +0, 61, 61, 1, 149760, 0x11b795df +0, 62, 62, 1, 149760, 0x8f651e3e +0, 63, 63, 1, 149760, 0xdfb452f9 +0, 64, 64, 1, 149760, 0x686e83ff +0, 65, 65, 1, 149760, 0x56ced1b4 +0, 66, 66, 1, 149760, 0x8df69755 +1, 67, 67, 1, 24576, 0xa82c4bc6 +0, 68, 68, 1, 149760, 0x5245b9f0 +1, 69, 69, 1, 24576, 0x2d9451db +0, 70, 70, 1, 149760, 0x957cd0e6 +1, 71, 71, 1, 24576, 0x8b4b56c9 +0, 72, 72, 1, 149760, 0x1b01adc7 +1, 73, 73, 1, 24576, 0x4664573a +0, 74, 74, 1, 149760, 0xea035d18 +1, 75, 75, 1, 24576, 0x3f3d4f5a +0, 76, 76, 1, 149760, 0x965affa4 +1, 77, 77, 1, 24576, 0xaf034600 +0, 78, 78, 1, 149760, 0xa1456bd2 +1, 79, 79, 1, 24576, 0x7f5d3504 +0, 80, 80, 1, 149760, 0x5291e254 +1, 81, 81, 1, 24576, 0x59562099 +0, 82, 82, 1, 149760, 0xd97f564a +1, 83, 83, 1, 24576, 0xd8a609de +0, 84, 84, 1, 149760, 0x91a61e7f +1, 85, 85, 1, 24576, 0xcf5008ca +0, 86, 86, 1, 149760, 0xa268b503 +1, 87, 87, 1, 24576, 0x2c4af809 +0, 88, 88, 1, 149760, 0xd01c152d +1, 89, 89, 1, 24576, 0x8366e0e1 +0, 90, 90, 1, 149760, 0xbe51742d +1, 91, 91, 1, 24576, 0x381cc7e9 +0, 92, 92, 1, 149760, 0x15d4f93b +1, 93, 93, 1, 24576, 0x576bbadd +0, 94, 94, 1, 149760, 0x4a755f1b +1, 95, 95, 1, 24576, 0x3516a052 +0, 96, 96, 1, 149760, 0x630d2e54 +1, 97, 97, 1, 24576, 0xd9489703 +0, 98, 98, 1, 149760, 0x1c4c14cd +1, 99, 99, 1, 24576, 0xa84f8afa +0, 100, 100, 1, 149760, 0x831a7510 +1, 101, 101, 1, 24576, 0x4d32945c +0, 102, 102, 1, 149760, 0x9aac3ee7 +1, 103, 103, 1, 24576, 0x6b14b0d7 +0, 104, 104, 1, 149760, 0xd50d3baa +1, 105, 105, 1, 24576, 0xb05dd8b6 +0, 106, 106, 1, 149760, 0x92d549c6 +1, 107, 107, 1, 24576, 0xfd9a02ca +0, 108, 108, 1, 149760, 0x2232ec60 +1, 109, 109, 1, 24576, 0xa5b92802 +0, 110, 110, 1, 149760, 0x78092c24 +1, 111, 111, 1, 24576, 0x385e36de +0, 112, 112, 1, 149760, 0xe5c7cead +1, 113, 113, 1, 24576, 0xd4072d1a +0, 114, 114, 1, 149760, 0x1bf8dfd0 +1, 115, 115, 1, 24576, 0x43b30476 +0, 116, 116, 1, 149760, 0x117aa880 +1, 117, 117, 1, 24576, 0x79afd3bf +0, 118, 118, 1, 149760, 0xf4ee5505 +1, 119, 119, 1, 24576, 0x8d538ff9 +0, 120, 120, 1, 149760, 0x7b2bd220 +1, 121, 121, 1, 24576, 0x187a8509 +0, 122, 122, 1, 149760, 0xdbaf519b +1, 123, 123, 1, 24576, 0xd97f6ec7 +0, 124, 124, 1, 149760, 0x1a386b01 +1, 125, 125, 1, 24576, 0x13e16de1 +0, 126, 126, 1, 149760, 0xf0bc3e7d +1, 127, 127, 1, 24576, 0x27628c3b +0, 128, 128, 1, 149760, 0xb2ba417b +1, 129, 129, 1, 24576, 0x260eddf8 +0, 130, 130, 1, 149760, 0xb18ebdb9 +1, 131, 131, 1, 24576, 0x47291ff7 +0, 132, 132, 1, 149760, 0x57c7e50f +1, 133, 133, 1, 24576, 0x6ed4630e +0, 134, 134, 1, 149760, 0xc0d53c18 +1, 135, 135, 1, 24576, 0x56f98141 +0, 136, 136, 1, 149760, 0x94fb35f1 +1, 137, 137, 1, 24576, 0x62c48555 +0, 138, 138, 1, 149760, 0x0cc9b521 +1, 139, 139, 1, 24576, 0x059a7505 +0, 140, 140, 1, 149760, 0xd618f78f +1, 141, 141, 1, 24576, 0x99c752c9 +0, 142, 142, 1, 149760, 0x12d119cb +1, 143, 143, 1, 24576, 0x84c94c61 +0, 144, 144, 1, 149760, 0x479a07b2 +1, 145, 145, 1, 24576, 0xdac16dba +0, 146, 146, 1, 149760, 0x5009d4fe +1, 147, 147, 1, 24576, 0xc3c98ceb +0, 148, 148, 1, 149760, 0x31ce0337 +1, 149, 149, 1, 24576, 0x44afbc11 +0, 150, 150, 1, 149760, 0x72e850bb +1, 151, 151, 1, 24576, 0x1ed6f485 +0, 152, 152, 1, 149760, 0x25cd1c68 +1, 153, 153, 1, 24576, 0x14a91968 +0, 154, 154, 1, 149760, 0x6f0e7fa8 +1, 155, 155, 1, 24576, 0x398a29a7 +0, 156, 156, 1, 149760, 0x12b61c36 +1, 157, 157, 1, 24576, 0xe7c43a2d +0, 158, 158, 1, 149760, 0xcfd5918d +1, 159, 159, 1, 24576, 0x417c42a9 +0, 160, 160, 1, 149760, 0x08b1c6f2 +1, 161, 161, 1, 24576, 0x1a273fff diff --git a/tests/ref/fate/hevc-pir b/tests/ref/fate/hevc-pir new file mode 100644 index 000000000..ff9a51ec4 --- /dev/null +++ b/tests/ref/fate/hevc-pir @@ -0,0 +1,15 @@ +#tb 0: 1/50 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 1/1 +0, 0, 0, 1, 3110400, 0x7f744ab9 +0, 1, 1, 1, 3110400, 0x5f077ff0 +0, 2, 2, 1, 3110400, 0x25932fe2 +0, 3, 3, 1, 3110400, 0x5b2cd739 +0, 4, 4, 1, 3110400, 0xbbfe65ec +0, 5, 5, 1, 3110400, 0xb53eab5f +0, 6, 6, 1, 3110400, 0x9f318977 +0, 7, 7, 1, 3110400, 0x205cc30c +0, 8, 8, 1, 3110400, 0x06ea7dfc +0, 9, 9, 1, 3110400, 0x7597691a diff --git a/tests/ref/fate/iamf-5_1-copy b/tests/ref/fate/iamf-5_1-copy new file mode 100644 index 000000000..ed2046fe3 --- /dev/null +++ b/tests/ref/fate/iamf-5_1-copy @@ -0,0 +1,313 @@ +#extradata 0: 19, 0x3a0e0490 +#extradata 1: 19, 0x3a0e0490 +#extradata 2: 19, 0x3a04048f +#extradata 3: 19, 0x3a04048f +#tb 0: 1/48000 +#media_type 0: audio +#codec_id 0: opus +#sample_rate 0: 48000 +#channel_layout_name 0: stereo +#tb 1: 1/48000 +#media_type 1: audio +#codec_id 1: opus +#sample_rate 1: 48000 +#channel_layout_name 1: stereo +#tb 2: 1/48000 +#media_type 2: audio +#codec_id 2: opus +#sample_rate 2: 48000 +#channel_layout_name 2: mono +#tb 3: 1/48000 +#media_type 3: audio +#codec_id 3: opus +#sample_rate 3: 48000 +#channel_layout_name 3: mono +[STREAM_GROUP] +index=0 +id=0x12c +nb_streams=4 +type=IAMF Audio Element +[COMPONENT] +nb_layers=2 +audio_element_type=0 +default_w=0 +[SUBCOMPONENT] +channel_layout=stereo +output_gain_flags=0 +output_gain=0/1 +[/SUBCOMPONENT] +[SUBCOMPONENT] +channel_layout=5.1 +output_gain_flags=0 +output_gain=0/1 +[/SUBCOMPONENT] +[SUBCOMPONENT] +name=demixing_info +nb_subblocks=1 +type=1 +parameter_id=998 +parameter_rate=48000 +duration=960 +constant_subblock_duration=960 +[PIECE] +subblock_duration=960 +dmixp_mode=1 +[/PIECE] +[/SUBCOMPONENT] +[SUBCOMPONENT] +name=recon_gain_info +nb_subblocks=1 +type=2 +parameter_id=101 +parameter_rate=48000 +duration=960 +constant_subblock_duration=960 +[PIECE] +subblock_duration=960 +[/PIECE] +[/SUBCOMPONENT] +[/COMPONENT] +[STREAM] +index=0 +id=0x0 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=1 +id=0x1 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=2 +id=0x2 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=3 +id=0x3 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[/STREAM_GROUP] +[STREAM_GROUP] +index=1 +id=0x2a +nb_streams=4 +type=IAMF Mix Presentation +[COMPONENT] +nb_submixes=1 +[SUBCOMPONENT] +en-us=test_mix_pres +[/SUBCOMPONENT] +[SUBCOMPONENT] +nb_elements=1 +nb_layouts=2 +default_mix_gain=0/256 +[PIECE] +stream_id=300 +default_mix_gain=0/256 +headphones_rendering_mode=0 +[SUBPIECE] +en-us=test_sub_mix_0_audio_element_0 +[/SUBPIECE] +[SUBPIECE] +name=element_mix_config +nb_subblocks=0 +type=0 +parameter_id=100 +parameter_rate=48000 +duration=0 +constant_subblock_duration=0 +[/SUBPIECE] +[/PIECE] +[PIECE] +name=output_mix_config +nb_subblocks=0 +type=0 +parameter_id=100 +parameter_rate=48000 +duration=0 +constant_subblock_duration=0 +[/PIECE] +[PIECE] +sound_system=stereo +integrated_loudness=-5273/256 +digital_peak=-2197/256 +true_peak=0/1 +dialogue_anchored_loudness=0/1 +album_anchored_loudness=0/1 +[/PIECE] +[PIECE] +sound_system=5.1 +integrated_loudness=-5886/256 +digital_peak=-2845/256 +true_peak=0/1 +dialogue_anchored_loudness=0/1 +album_anchored_loudness=0/1 +[/PIECE] +[/SUBCOMPONENT] +[/COMPONENT] +[STREAM] +index=0 +id=0x0 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=1 +id=0x1 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=2 +id=0x2 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=3 +id=0x3 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[/STREAM_GROUP] diff --git a/tests/ref/fate/iamf-5_1-demux b/tests/ref/fate/iamf-5_1-demux new file mode 100644 index 000000000..ed2046fe3 --- /dev/null +++ b/tests/ref/fate/iamf-5_1-demux @@ -0,0 +1,313 @@ +#extradata 0: 19, 0x3a0e0490 +#extradata 1: 19, 0x3a0e0490 +#extradata 2: 19, 0x3a04048f +#extradata 3: 19, 0x3a04048f +#tb 0: 1/48000 +#media_type 0: audio +#codec_id 0: opus +#sample_rate 0: 48000 +#channel_layout_name 0: stereo +#tb 1: 1/48000 +#media_type 1: audio +#codec_id 1: opus +#sample_rate 1: 48000 +#channel_layout_name 1: stereo +#tb 2: 1/48000 +#media_type 2: audio +#codec_id 2: opus +#sample_rate 2: 48000 +#channel_layout_name 2: mono +#tb 3: 1/48000 +#media_type 3: audio +#codec_id 3: opus +#sample_rate 3: 48000 +#channel_layout_name 3: mono +[STREAM_GROUP] +index=0 +id=0x12c +nb_streams=4 +type=IAMF Audio Element +[COMPONENT] +nb_layers=2 +audio_element_type=0 +default_w=0 +[SUBCOMPONENT] +channel_layout=stereo +output_gain_flags=0 +output_gain=0/1 +[/SUBCOMPONENT] +[SUBCOMPONENT] +channel_layout=5.1 +output_gain_flags=0 +output_gain=0/1 +[/SUBCOMPONENT] +[SUBCOMPONENT] +name=demixing_info +nb_subblocks=1 +type=1 +parameter_id=998 +parameter_rate=48000 +duration=960 +constant_subblock_duration=960 +[PIECE] +subblock_duration=960 +dmixp_mode=1 +[/PIECE] +[/SUBCOMPONENT] +[SUBCOMPONENT] +name=recon_gain_info +nb_subblocks=1 +type=2 +parameter_id=101 +parameter_rate=48000 +duration=960 +constant_subblock_duration=960 +[PIECE] +subblock_duration=960 +[/PIECE] +[/SUBCOMPONENT] +[/COMPONENT] +[STREAM] +index=0 +id=0x0 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=1 +id=0x1 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=2 +id=0x2 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=3 +id=0x3 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[/STREAM_GROUP] +[STREAM_GROUP] +index=1 +id=0x2a +nb_streams=4 +type=IAMF Mix Presentation +[COMPONENT] +nb_submixes=1 +[SUBCOMPONENT] +en-us=test_mix_pres +[/SUBCOMPONENT] +[SUBCOMPONENT] +nb_elements=1 +nb_layouts=2 +default_mix_gain=0/256 +[PIECE] +stream_id=300 +default_mix_gain=0/256 +headphones_rendering_mode=0 +[SUBPIECE] +en-us=test_sub_mix_0_audio_element_0 +[/SUBPIECE] +[SUBPIECE] +name=element_mix_config +nb_subblocks=0 +type=0 +parameter_id=100 +parameter_rate=48000 +duration=0 +constant_subblock_duration=0 +[/SUBPIECE] +[/PIECE] +[PIECE] +name=output_mix_config +nb_subblocks=0 +type=0 +parameter_id=100 +parameter_rate=48000 +duration=0 +constant_subblock_duration=0 +[/PIECE] +[PIECE] +sound_system=stereo +integrated_loudness=-5273/256 +digital_peak=-2197/256 +true_peak=0/1 +dialogue_anchored_loudness=0/1 +album_anchored_loudness=0/1 +[/PIECE] +[PIECE] +sound_system=5.1 +integrated_loudness=-5886/256 +digital_peak=-2845/256 +true_peak=0/1 +dialogue_anchored_loudness=0/1 +album_anchored_loudness=0/1 +[/PIECE] +[/SUBCOMPONENT] +[/COMPONENT] +[STREAM] +index=0 +id=0x0 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=1 +id=0x1 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=2 +id=0x2 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=3 +id=0x3 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[/STREAM_GROUP] diff --git a/tests/ref/fate/iamf-5_1_4 b/tests/ref/fate/iamf-5_1_4 index d516429d5..fdee50b8e 100644 --- a/tests/ref/fate/iamf-5_1_4 +++ b/tests/ref/fate/iamf-5_1_4 @@ -160,6 +160,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -182,6 +183,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -204,6 +206,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -226,6 +229,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=4 @@ -248,6 +252,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=5 @@ -270,6 +275,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] [STREAM_GROUP] @@ -367,6 +373,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -389,6 +396,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -411,6 +419,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -433,6 +442,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=4 @@ -455,6 +465,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=5 @@ -477,5 +488,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/iamf-7_1_4 b/tests/ref/fate/iamf-7_1_4 index 4e6e62bbe..ccce96ea8 100644 --- a/tests/ref/fate/iamf-7_1_4 +++ b/tests/ref/fate/iamf-7_1_4 @@ -176,6 +176,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -198,6 +199,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -220,6 +222,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -242,6 +245,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=4 @@ -264,6 +268,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=5 @@ -286,6 +291,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=6 @@ -308,6 +314,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] [STREAM_GROUP] @@ -405,6 +412,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -427,6 +435,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -449,6 +458,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -471,6 +481,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=4 @@ -493,6 +504,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=5 @@ -515,6 +527,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=6 @@ -537,5 +550,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/iamf-ambisonic_1 b/tests/ref/fate/iamf-ambisonic_1 index 84683b6ce..e43f89159 100644 --- a/tests/ref/fate/iamf-ambisonic_1 +++ b/tests/ref/fate/iamf-ambisonic_1 @@ -99,6 +99,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -121,6 +122,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -143,6 +145,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -165,6 +168,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] [STREAM_GROUP] @@ -238,6 +242,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -260,6 +265,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -282,6 +288,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -304,5 +311,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/iamf-stereo b/tests/ref/fate/iamf-stereo index 32fe47bf9..9b3f7e0a7 100644 --- a/tests/ref/fate/iamf-stereo +++ b/tests/ref/fate/iamf-stereo @@ -52,6 +52,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] [STREAM_GROUP] @@ -164,5 +165,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/iamf-stereo-demux b/tests/ref/fate/iamf-stereo-demux new file mode 100644 index 000000000..8c72f6d10 --- /dev/null +++ b/tests/ref/fate/iamf-stereo-demux @@ -0,0 +1,119 @@ +#extradata 0: 2, 0x00b200a1 +#tb 0: 1/48000 +#media_type 0: audio +#codec_id 0: aac +#sample_rate 0: 48000 +#channel_layout_name 0: stereo +[STREAM_GROUP] +index=0 +id=0x12c +nb_streams=1 +type=IAMF Audio Element +[COMPONENT] +nb_layers=1 +audio_element_type=0 +default_w=0 +[SUBCOMPONENT] +channel_layout=stereo +output_gain_flags=0 +output_gain=0/1 +[/SUBCOMPONENT] +[/COMPONENT] +[STREAM] +index=0 +id=0x0 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[/STREAM_GROUP] +[STREAM_GROUP] +index=1 +id=0x2a +nb_streams=1 +type=IAMF Mix Presentation +[COMPONENT] +nb_submixes=1 +[SUBCOMPONENT] +en-us=test_mix_pres +[/SUBCOMPONENT] +[SUBCOMPONENT] +nb_elements=1 +nb_layouts=1 +default_mix_gain=0/256 +[PIECE] +stream_id=300 +default_mix_gain=0/256 +headphones_rendering_mode=0 +[SUBPIECE] +en-us=test_sub_mix_0_audio_element_0 +[/SUBPIECE] +[SUBPIECE] +name=element_mix_config +nb_subblocks=0 +type=0 +parameter_id=100 +parameter_rate=48000 +duration=0 +constant_subblock_duration=0 +[/SUBPIECE] +[/PIECE] +[PIECE] +name=output_mix_config +nb_subblocks=0 +type=0 +parameter_id=100 +parameter_rate=48000 +duration=0 +constant_subblock_duration=0 +[/PIECE] +[PIECE] +sound_system=stereo +integrated_loudness=-5393/256 +digital_peak=-5394/256 +true_peak=0/1 +dialogue_anchored_loudness=0/1 +album_anchored_loudness=0/1 +[/PIECE] +[/SUBCOMPONENT] +[/COMPONENT] +[STREAM] +index=0 +id=0x0 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[/STREAM_GROUP] diff --git a/tests/ref/fate/jpeg2000dec-ds0_ht_01_b11 b/tests/ref/fate/jpeg2000dec-ds0_ht_01_b11 index af3eaa086..d923cc210 100644 --- a/tests/ref/fate/jpeg2000dec-ds0_ht_01_b11 +++ b/tests/ref/fate/jpeg2000dec-ds0_ht_01_b11 @@ -3,4 +3,4 @@ #codec_id 0: rawvideo #dimensions 0: 128x128 #sar 0: 0/1 -0, 0, 0, 1, 16384, 0x44426324 +0, 0, 0, 1, 16384, 0x04a3647e diff --git a/tests/ref/fate/jpeg2000dec-p0_10 b/tests/ref/fate/jpeg2000dec-p0_10 new file mode 100644 index 000000000..16c4e5e39 --- /dev/null +++ b/tests/ref/fate/jpeg2000dec-p0_10 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x64 +#sar 0: 0/1 +0, 0, 0, 1, 12288, 0x68638483 diff --git a/tests/ref/fate/jpg-12bpp b/tests/ref/fate/jpg-12bpp index b3c662d58..9b039a92c 100644 --- a/tests/ref/fate/jpg-12bpp +++ b/tests/ref/fate/jpg-12bpp @@ -3,4 +3,4 @@ #codec_id 0: rawvideo #dimensions 0: 999x749 #sar 0: 1/1 -0, 0, 0, 1, 1496502, 0xd91deb4b +0, 0, 0, 1, 1496502, 0x44efc0af diff --git a/tests/ref/fate/jv-demux b/tests/ref/fate/jv-demux index b5d3196cf..22a9217e2 100644 --- a/tests/ref/fate/jv-demux +++ b/tests/ref/fate/jv-demux @@ -11,13 +11,13 @@ 0, 0, 0, 1, 6, 0x000a0003 1, 0, 0, 131072, 131072, 0x14c664d6 0, 1, 1, 1, 773, 0x11802a51 -0, 2, 2, 1, 12974, 0xc2e466b7 -0, 3, 3, 1, 12200, 0x3c0eeb31 -0, 4, 4, 1, 13339, 0x91d82488 -0, 5, 5, 1, 13940, 0x064c350a -0, 6, 6, 1, 14418, 0x078d2dd2 -0, 7, 7, 1, 14539, 0x145167ed -0, 8, 8, 1, 2552, 0xcf2b1db7, F=0x3 +0, 2, 2, 1, 12974, 0xc2e466b7, F=0x0 +0, 3, 3, 1, 12200, 0x3c0eeb31, F=0x0 +0, 4, 4, 1, 13339, 0x91d82488, F=0x0 +0, 5, 5, 1, 13940, 0x064c350a, F=0x0 +0, 6, 6, 1, 14418, 0x078d2dd2, F=0x0 +0, 7, 7, 1, 14539, 0x145167ed, F=0x0 +0, 8, 8, 1, 2552, 0xcf2b1db7, F=0x2 1, 131072, 131072, 1764, 1764, 0x30be734d 1, 132836, 132836, 1764, 1764, 0xa4c873a7 1, 134600, 134600, 1764, 1764, 0xd5f17443 diff --git a/tests/ref/fate/matroska-alac-remux b/tests/ref/fate/matroska-alac-remux index 1c27c625a..9b73263ac 100644 --- a/tests/ref/fate/matroska-alac-remux +++ b/tests/ref/fate/matroska-alac-remux @@ -153,6 +153,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [FORMAT] TAG:title=Inside diff --git a/tests/ref/fate/matroska-dovi-write-config7 b/tests/ref/fate/matroska-dovi-write-config7 index dc5b73a44..5f3e00027 100644 --- a/tests/ref/fate/matroska-dovi-write-config7 +++ b/tests/ref/fate/matroska-dovi-write-config7 @@ -45,5 +45,6 @@ rpu_present_flag=1 el_present_flag=1 bl_present_flag=0 dv_bl_signal_compatibility_id=6 +dv_md_compression=none [/SIDE_DATA] [/STREAM] diff --git a/tests/ref/fate/matroska-dovi-write-config8 b/tests/ref/fate/matroska-dovi-write-config8 index 472cbed70..85899d5f6 100644 --- a/tests/ref/fate/matroska-dovi-write-config8 +++ b/tests/ref/fate/matroska-dovi-write-config8 @@ -1,6 +1,6 @@ -0730145aa317d800cb4bde0e3a38bb8d *tests/data/fate/matroska-dovi-write-config8.matroska +3bd4b07d5af6153516e4c0e66a71c8c9 *tests/data/fate/matroska-dovi-write-config8.matroska 3600607 tests/data/fate/matroska-dovi-write-config8.matroska -#extradata 0: 551, 0xa18acf66 +#extradata 0: 551, 0xb1ddcd66 #extradata 1: 2, 0x00340022 #tb 0: 1/1000 #media_type 0: video @@ -64,5 +64,6 @@ rpu_present_flag=1 el_present_flag=0 bl_present_flag=1 dv_bl_signal_compatibility_id=4 +dv_md_compression=none [/SIDE_DATA] [/STREAM] diff --git a/tests/ref/fate/matroska-mpegts-remux b/tests/ref/fate/matroska-mpegts-remux index 24fdf8f3f..491e255d7 100644 --- a/tests/ref/fate/matroska-mpegts-remux +++ b/tests/ref/fate/matroska-mpegts-remux @@ -38,6 +38,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -59,4 +60,5 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] diff --git a/tests/ref/fate/matroska-side-data-pref-codec b/tests/ref/fate/matroska-side-data-pref-codec index 128ecdd42..2b67c0191 100644 --- a/tests/ref/fate/matroska-side-data-pref-codec +++ b/tests/ref/fate/matroska-side-data-pref-codec @@ -310,6 +310,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=spa TAG:BPS-eng=216040 TAG:DURATION-eng=00:00:00.400000000 diff --git a/tests/ref/fate/matroska-side-data-pref-packet b/tests/ref/fate/matroska-side-data-pref-packet index a433ece6f..b3b942786 100644 --- a/tests/ref/fate/matroska-side-data-pref-packet +++ b/tests/ref/fate/matroska-side-data-pref-packet @@ -310,6 +310,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=spa TAG:BPS-eng=216040 TAG:DURATION-eng=00:00:00.400000000 diff --git a/tests/ref/fate/matroska-spherical-mono b/tests/ref/fate/matroska-spherical-mono index bd57d9451..065b109a4 100644 --- a/tests/ref/fate/matroska-spherical-mono +++ b/tests/ref/fate/matroska-spherical-mono @@ -3,6 +3,11 @@ side_data_type=Stereo 3D type=2D inverted=0 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 [/SIDE_DATA] [SIDE_DATA] side_data_type=Spherical Mapping diff --git a/tests/ref/fate/matroska-spherical-mono-remux b/tests/ref/fate/matroska-spherical-mono-remux index 6fcda1482..3ee7fd2d1 100644 --- a/tests/ref/fate/matroska-spherical-mono-remux +++ b/tests/ref/fate/matroska-spherical-mono-remux @@ -27,6 +27,11 @@ DISPOSITION:forced=1 side_data_type=Stereo 3D type=2D inverted=0 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 [/SIDE_DATA] [SIDE_DATA] side_data_type=Spherical Mapping @@ -51,6 +56,11 @@ DISPOSITION:forced=0 side_data_type=Stereo 3D type=2D inverted=0 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 [/SIDE_DATA] [SIDE_DATA] side_data_type=Spherical Mapping diff --git a/tests/ref/fate/matroska-stereo_mode b/tests/ref/fate/matroska-stereo_mode index 739b789fe..3382a60f5 100644 --- a/tests/ref/fate/matroska-stereo_mode +++ b/tests/ref/fate/matroska-stereo_mode @@ -132,6 +132,11 @@ TAG:DURATION=00:00:10.000000000 side_data_type=Stereo 3D type=side by side inverted=0 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 [/SIDE_DATA] [/STREAM] [STREAM] @@ -147,6 +152,11 @@ TAG:DURATION=00:00:10.000000000 side_data_type=Stereo 3D type=top and bottom inverted=1 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 [/SIDE_DATA] [/STREAM] [STREAM] @@ -160,6 +170,11 @@ TAG:DURATION=00:00:10.000000000 side_data_type=Stereo 3D type=interleaved lines inverted=1 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 [/SIDE_DATA] [/STREAM] [STREAM] @@ -174,6 +189,11 @@ TAG:DURATION=00:00:10.000000000 side_data_type=Stereo 3D type=interleaved columns inverted=1 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 [/SIDE_DATA] [/STREAM] [STREAM] diff --git a/tests/ref/fate/matroska-vp8-alpha-remux b/tests/ref/fate/matroska-vp8-alpha-remux index f6c24dead..03bb01fdb 100644 --- a/tests/ref/fate/matroska-vp8-alpha-remux +++ b/tests/ref/fate/matroska-vp8-alpha-remux @@ -31,9 +31,15 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [SIDE_DATA] side_data_type=Stereo 3D type=2D inverted=0 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 [/SIDE_DATA] [/STREAM] diff --git a/tests/ref/fate/mov-heic-demux-still-image-grid b/tests/ref/fate/mov-heic-demux-still-image-grid index d8dfccea8..f7d0b178e 100644 --- a/tests/ref/fate/mov-heic-demux-still-image-grid +++ b/tests/ref/fate/mov-heic-demux-still-image-grid @@ -78,6 +78,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:title=Derived image [STREAM] index=0 @@ -100,6 +101,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -122,6 +124,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -144,6 +147,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -166,5 +170,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/mov-heic-demux-still-image-iovl b/tests/ref/fate/mov-heic-demux-still-image-iovl index 2b211267a..4a90220c3 100644 --- a/tests/ref/fate/mov-heic-demux-still-image-iovl +++ b/tests/ref/fate/mov-heic-demux-still-image-iovl @@ -54,6 +54,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:title=Derived image [STREAM] index=0 @@ -76,6 +77,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -98,5 +100,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/mov-heic-demux-still-image-iovl-2 b/tests/ref/fate/mov-heic-demux-still-image-iovl-2 index 492f404a3..3ee119ff6 100644 --- a/tests/ref/fate/mov-heic-demux-still-image-iovl-2 +++ b/tests/ref/fate/mov-heic-demux-still-image-iovl-2 @@ -47,6 +47,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:title=Derived image [STREAM] index=0 @@ -69,5 +70,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/mov-mp4-disposition-mpegts-remux b/tests/ref/fate/mov-mp4-disposition-mpegts-remux index 3d103c98c..a06ef7cef 100644 --- a/tests/ref/fate/mov-mp4-disposition-mpegts-remux +++ b/tests/ref/fate/mov-mp4-disposition-mpegts-remux @@ -44,7 +44,8 @@ adb3b95c07a5f3e0c86641dd62f01dae *tests/data/fate/mov-mp4-disposition-mpegts-rem "descriptions": 0, "metadata": 0, "dependent": 0, - "still_image": 0 + "still_image": 0, + "multilayer": 0 }, "side_data_list": [ { @@ -72,7 +73,8 @@ adb3b95c07a5f3e0c86641dd62f01dae *tests/data/fate/mov-mp4-disposition-mpegts-rem "descriptions": 1, "metadata": 0, "dependent": 0, - "still_image": 0 + "still_image": 0, + "multilayer": 0 }, "side_data_list": [ { diff --git a/tests/ref/fate/mov-mp4-iamf-5_1_4 b/tests/ref/fate/mov-mp4-iamf-5_1_4 index a6d5a76b0..36106528a 100644 --- a/tests/ref/fate/mov-mp4-iamf-5_1_4 +++ b/tests/ref/fate/mov-mp4-iamf-5_1_4 @@ -157,6 +157,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler TAG:vendor_id=[0][0][0][0] @@ -181,6 +182,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -203,6 +205,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -225,6 +228,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -247,6 +251,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=4 @@ -269,6 +274,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=5 @@ -291,6 +297,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] [STREAM_GROUP] @@ -385,6 +392,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler TAG:vendor_id=[0][0][0][0] @@ -409,6 +417,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -431,6 +440,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -453,6 +463,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -475,6 +486,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=4 @@ -497,6 +509,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=5 @@ -519,5 +532,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/mov-mp4-iamf-7_1_4-video-first b/tests/ref/fate/mov-mp4-iamf-7_1_4-video-first new file mode 100644 index 000000000..d3b37896b --- /dev/null +++ b/tests/ref/fate/mov-mp4-iamf-7_1_4-video-first @@ -0,0 +1,662 @@ +f92a589b00c2ba98b78ae77e6edffa23 *tests/data/fate/mov-mp4-iamf-7_1_4-video-first.mp4 +416657 tests/data/fate/mov-mp4-iamf-7_1_4-video-first.mp4 +#extradata 0: 30, 0x47ab0576 +#extradata 1: 34, 0xafa70d5e +#extradata 2: 34, 0xafa70d5e +#extradata 3: 34, 0xaf7b0d5c +#extradata 4: 34, 0xaf7b0d5c +#extradata 5: 34, 0xafa70d5e +#extradata 6: 34, 0xafa70d5e +#extradata 7: 34, 0xafa70d5e +#tb 0: 1/12800 +#media_type 0: video +#codec_id 0: mpeg4 +#dimensions 0: 352x288 +#sar 0: 1/1 +#tb 1: 1/44100 +#media_type 1: audio +#codec_id 1: flac +#sample_rate 1: 44100 +#channel_layout_name 1: stereo +#tb 2: 1/44100 +#media_type 2: audio +#codec_id 2: flac +#sample_rate 2: 44100 +#channel_layout_name 2: stereo +#tb 3: 1/44100 +#media_type 3: audio +#codec_id 3: flac +#sample_rate 3: 44100 +#channel_layout_name 3: mono +#tb 4: 1/44100 +#media_type 4: audio +#codec_id 4: flac +#sample_rate 4: 44100 +#channel_layout_name 4: mono +#tb 5: 1/44100 +#media_type 5: audio +#codec_id 5: flac +#sample_rate 5: 44100 +#channel_layout_name 5: stereo +#tb 6: 1/44100 +#media_type 6: audio +#codec_id 6: flac +#sample_rate 6: 44100 +#channel_layout_name 6: stereo +#tb 7: 1/44100 +#media_type 7: audio +#codec_id 7: flac +#sample_rate 7: 44100 +#channel_layout_name 7: stereo +0, 0, 0, 512, 42002, 0xef0e5124 +1, 0, 0, 4608, 1399, 0x6e89566e +2, 0, 0, 4608, 1399, 0x6e89566e +3, 0, 0, 4608, 1396, 0x0dcb5677 +4, 0, 0, 4608, 1396, 0x0dcb5677 +5, 0, 0, 4608, 1399, 0x6e89566e +6, 0, 0, 4608, 1399, 0x6e89566e +7, 0, 0, 4608, 1399, 0x6e89566e +0, 512, 512, 512, 52619, 0xc794e830, F=0x0 +0, 1024, 1024, 512, 51242, 0xf2f6be7f, F=0x0 +1, 4608, 4608, 4608, 1442, 0x6c3c5b13 +2, 4608, 4608, 4608, 1442, 0x6c3c5b13 +3, 4608, 4608, 4608, 1439, 0xc46b5ac5 +4, 4608, 4608, 4608, 1439, 0xc46b5ac5 +5, 4608, 4608, 4608, 1442, 0x6c3c5b13 +6, 4608, 4608, 4608, 1442, 0x6c3c5b13 +7, 4608, 4608, 4608, 1442, 0x6c3c5b13 +0, 1536, 1536, 512, 49320, 0xe87a921f, F=0x0 +0, 2048, 2048, 512, 22461, 0xc858a20b, F=0x0 +0, 2560, 2560, 512, 16731, 0x04beb863, F=0x0 +1, 9216, 9216, 4608, 1380, 0xc497571b +2, 9216, 9216, 4608, 1380, 0xc497571b +3, 9216, 9216, 4608, 1377, 0x5b2a55fe +4, 9216, 9216, 4608, 1377, 0x5b2a55fe +5, 9216, 9216, 4608, 1380, 0xc497571b +6, 9216, 9216, 4608, 1380, 0xc497571b +7, 9216, 9216, 4608, 1380, 0xc497571b +0, 3072, 3072, 512, 9983, 0x091aa8e8, F=0x0 +0, 3584, 3584, 512, 6991, 0xa0385313, F=0x0 +1, 13824, 13824, 4608, 1383, 0x48e9510f +2, 13824, 13824, 4608, 1383, 0x48e9510f +3, 13824, 13824, 4608, 1380, 0x045550d3 +4, 13824, 13824, 4608, 1380, 0x045550d3 +5, 13824, 13824, 4608, 1383, 0x48e9510f +6, 13824, 13824, 4608, 1383, 0x48e9510f +7, 13824, 13824, 4608, 1383, 0x48e9510f +0, 4096, 4096, 512, 5825, 0x3c97cfbc, F=0x0 +0, 4608, 4608, 512, 4331, 0xbaf5f982, F=0x0 +0, 5120, 5120, 512, 2541, 0xe018c3cb, F=0x0 +1, 18432, 18432, 4608, 1572, 0x9a514719 +2, 18432, 18432, 4608, 1572, 0x9a514719 +3, 18432, 18432, 4608, 1568, 0xa2bc45f4 +4, 18432, 18432, 4608, 1568, 0xa2bc45f4 +5, 18432, 18432, 4608, 1572, 0x9a514719 +6, 18432, 18432, 4608, 1572, 0x9a514719 +7, 18432, 18432, 4608, 1572, 0x9a514719 +0, 5632, 5632, 512, 2655, 0xf98af7a1, F=0x0 +0, 6144, 6144, 512, 13464, 0x33e5196f +0, 6656, 6656, 512, 2587, 0x90e198aa, F=0x0 +1, 23040, 23040, 4608, 1391, 0x74ac5014 +2, 23040, 23040, 4608, 1391, 0x74ac5014 +3, 23040, 23040, 4608, 1388, 0x96c85007 +4, 23040, 23040, 4608, 1388, 0x96c85007 +5, 23040, 23040, 4608, 1391, 0x74ac5014 +6, 23040, 23040, 4608, 1391, 0x74ac5014 +7, 23040, 23040, 4608, 1391, 0x74ac5014 +0, 7168, 7168, 512, 2313, 0x698c429b, F=0x0 +0, 7680, 7680, 512, 2123, 0x63a3f034, F=0x0 +1, 27648, 27648, 4608, 1422, 0x2f9d47c5 +2, 27648, 27648, 4608, 1422, 0x2f9d47c5 +3, 27648, 27648, 4608, 1419, 0x4d4d466a +4, 27648, 27648, 4608, 1419, 0x4d4d466a +5, 27648, 27648, 4608, 1422, 0x2f9d47c5 +6, 27648, 27648, 4608, 1422, 0x2f9d47c5 +7, 27648, 27648, 4608, 1422, 0x2f9d47c5 +0, 8192, 8192, 512, 2222, 0x442b233d, F=0x0 +0, 8704, 8704, 512, 2332, 0x24c75b04, F=0x0 +0, 9216, 9216, 512, 2302, 0xa0fa2ee7, F=0x0 +1, 32256, 32256, 4608, 1768, 0x2a044b99 +2, 32256, 32256, 4608, 1768, 0x2a044b99 +3, 32256, 32256, 4608, 1765, 0xacb84b24 +4, 32256, 32256, 4608, 1765, 0xacb84b24 +5, 32256, 32256, 4608, 1768, 0x2a044b99 +6, 32256, 32256, 4608, 1768, 0x2a044b99 +7, 32256, 32256, 4608, 1768, 0x2a044b99 +0, 9728, 9728, 512, 1740, 0xdf772eb3, F=0x0 +0, 10240, 10240, 512, 1994, 0x8830ad23, F=0x0 +1, 36864, 36864, 4608, 1534, 0xb0b35a3f +2, 36864, 36864, 4608, 1534, 0xb0b35a3f +3, 36864, 36864, 4608, 1531, 0x996458aa +4, 36864, 36864, 4608, 1531, 0x996458aa +5, 36864, 36864, 4608, 1534, 0xb0b35a3f +6, 36864, 36864, 4608, 1534, 0xb0b35a3f +7, 36864, 36864, 4608, 1534, 0xb0b35a3f +0, 10752, 10752, 512, 1884, 0x2c567db6, F=0x0 +0, 11264, 11264, 512, 1880, 0x72237c52, F=0x0 +0, 11776, 11776, 512, 1970, 0x60708ff8, F=0x0 +1, 41472, 41472, 2628, 926, 0xc26a5eae +2, 41472, 41472, 2628, 926, 0xc26a5eae +3, 41472, 41472, 2628, 923, 0xa7225edf +4, 41472, 41472, 2628, 923, 0xa7225edf +5, 41472, 41472, 2628, 926, 0xc26a5eae +6, 41472, 41472, 2628, 926, 0xc26a5eae +7, 41472, 41472, 2628, 926, 0xc26a5eae +0, 12288, 12288, 512, 11659, 0x6bcb830e +[STREAM_GROUP] +index=0 +id=0x1 +nb_streams=7 +type=IAMF Audio Element +[COMPONENT] +nb_layers=4 +audio_element_type=0 +default_w=10 +[SUBCOMPONENT] +channel_layout=stereo +output_gain_flags=0 +output_gain=0/1 +[/SUBCOMPONENT] +[SUBCOMPONENT] +channel_layout=3.1.2 +output_gain_flags=0 +output_gain=0/1 +[/SUBCOMPONENT] +[SUBCOMPONENT] +channel_layout=7.1.2 +output_gain_flags=0 +output_gain=0/1 +[/SUBCOMPONENT] +[SUBCOMPONENT] +channel_layout=7.1.4 +output_gain_flags=0 +output_gain=0/1 +[/SUBCOMPONENT] +[SUBCOMPONENT] +name=demixing_info +nb_subblocks=1 +type=1 +parameter_id=998 +parameter_rate=44100 +duration=4608 +constant_subblock_duration=4608 +[PIECE] +subblock_duration=4608 +dmixp_mode=1 +[/PIECE] +[/SUBCOMPONENT] +[/COMPONENT] +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +TAG:language=und +TAG:handler_name=SoundHandler +TAG:vendor_id=[0][0][0][0] +[STREAM] +index=1 +id=0x2 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=2 +id=0x3 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=3 +id=0x4 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=4 +id=0x5 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=5 +id=0x6 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=6 +id=0x7 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=7 +id=0x8 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[/STREAM_GROUP] +[STREAM_GROUP] +index=1 +id=0x2 +nb_streams=7 +type=IAMF Mix Presentation +[COMPONENT] +nb_submixes=1 +[SUBCOMPONENT] +en-us=Mix_Presentation +[/SUBCOMPONENT] +[SUBCOMPONENT] +nb_elements=1 +nb_layouts=4 +default_mix_gain=256/256 +[PIECE] +stream_id=1 +default_mix_gain=0/256 +headphones_rendering_mode=0 +[SUBPIECE] +en-us=Scalable_Submix +[/SUBPIECE] +[SUBPIECE] +name=element_mix_config +nb_subblocks=0 +type=0 +parameter_id=100 +parameter_rate=48000 +duration=0 +constant_subblock_duration=0 +[/SUBPIECE] +[/PIECE] +[PIECE] +name=output_mix_config +nb_subblocks=0 +type=0 +parameter_id=100 +parameter_rate=48000 +duration=0 +constant_subblock_duration=0 +[/PIECE] +[PIECE] +sound_system=stereo +integrated_loudness=256/256 +digital_peak=0/256 +true_peak=0/1 +dialogue_anchored_loudness=0/1 +album_anchored_loudness=0/1 +[/PIECE] +[PIECE] +sound_system=3.1.2 +integrated_loudness=0/256 +digital_peak=0/256 +true_peak=0/1 +dialogue_anchored_loudness=0/1 +album_anchored_loudness=0/1 +[/PIECE] +[PIECE] +sound_system=7.1.2 +integrated_loudness=0/256 +digital_peak=0/256 +true_peak=0/1 +dialogue_anchored_loudness=0/1 +album_anchored_loudness=0/1 +[/PIECE] +[PIECE] +sound_system=7.1.4 +integrated_loudness=0/256 +digital_peak=0/256 +true_peak=0/1 +dialogue_anchored_loudness=0/1 +album_anchored_loudness=0/1 +[/PIECE] +[/SUBCOMPONENT] +[/COMPONENT] +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +TAG:language=und +TAG:handler_name=SoundHandler +TAG:vendor_id=[0][0][0][0] +[STREAM] +index=1 +id=0x2 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=0 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=2 +id=0x3 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=3 +id=0x4 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=4 +id=0x5 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=5 +id=0x6 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=6 +id=0x7 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=7 +id=0x8 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[/STREAM_GROUP] +[STREAM] +index=0 +id=0x1 +[/STREAM] +[STREAM] +index=1 +id=0x2 +[/STREAM] +[STREAM] +index=2 +id=0x3 +[/STREAM] +[STREAM] +index=3 +id=0x4 +[/STREAM] +[STREAM] +index=4 +id=0x5 +[/STREAM] +[STREAM] +index=5 +id=0x6 +[/STREAM] +[STREAM] +index=6 +id=0x7 +[/STREAM] +[STREAM] +index=7 +id=0x8 +[/STREAM] diff --git a/tests/ref/fate/mov-mp4-iamf-7_1_4 b/tests/ref/fate/mov-mp4-iamf-7_1_4-video-last similarity index 85% rename from tests/ref/fate/mov-mp4-iamf-7_1_4 rename to tests/ref/fate/mov-mp4-iamf-7_1_4-video-last index 0641cb0c3..35e8b9b0a 100644 --- a/tests/ref/fate/mov-mp4-iamf-7_1_4 +++ b/tests/ref/fate/mov-mp4-iamf-7_1_4-video-last @@ -1,5 +1,5 @@ -d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 -100588 tests/data/fate/mov-mp4-iamf-7_1_4.mp4 +d398cd7938efbe3dc570b407fe543a31 *tests/data/fate/mov-mp4-iamf-7_1_4-video-last.mp4 +416629 tests/data/fate/mov-mp4-iamf-7_1_4-video-last.mp4 #extradata 0: 34, 0xafa70d5e #extradata 1: 34, 0xafa70d5e #extradata 2: 34, 0xaf7b0d5c @@ -7,6 +7,7 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 #extradata 4: 34, 0xafa70d5e #extradata 5: 34, 0xafa70d5e #extradata 6: 34, 0xafa70d5e +#extradata 7: 30, 0x47ab0576 #tb 0: 1/44100 #media_type 0: audio #codec_id 0: flac @@ -42,6 +43,11 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 #codec_id 6: flac #sample_rate 6: 44100 #channel_layout_name 6: stereo +#tb 7: 1/12800 +#media_type 7: video +#codec_id 7: mpeg4 +#dimensions 7: 352x288 +#sar 7: 1/1 0, 0, 0, 4608, 1399, 0x6e89566e 1, 0, 0, 4608, 1399, 0x6e89566e 2, 0, 0, 4608, 1396, 0x0dcb5677 @@ -49,6 +55,9 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 0, 0, 4608, 1399, 0x6e89566e 5, 0, 0, 4608, 1399, 0x6e89566e 6, 0, 0, 4608, 1399, 0x6e89566e +7, 0, 0, 512, 42002, 0xef0e5124 +7, 512, 512, 512, 52619, 0xc794e830, F=0x0 +7, 1024, 1024, 512, 51242, 0xf2f6be7f, F=0x0 0, 4608, 4608, 4608, 1442, 0x6c3c5b13 1, 4608, 4608, 4608, 1442, 0x6c3c5b13 2, 4608, 4608, 4608, 1439, 0xc46b5ac5 @@ -56,6 +65,9 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 4608, 4608, 4608, 1442, 0x6c3c5b13 5, 4608, 4608, 4608, 1442, 0x6c3c5b13 6, 4608, 4608, 4608, 1442, 0x6c3c5b13 +7, 1536, 1536, 512, 49320, 0xe87a921f, F=0x0 +7, 2048, 2048, 512, 22461, 0xc858a20b, F=0x0 +7, 2560, 2560, 512, 16731, 0x04beb863, F=0x0 0, 9216, 9216, 4608, 1380, 0xc497571b 1, 9216, 9216, 4608, 1380, 0xc497571b 2, 9216, 9216, 4608, 1377, 0x5b2a55fe @@ -63,6 +75,8 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 9216, 9216, 4608, 1380, 0xc497571b 5, 9216, 9216, 4608, 1380, 0xc497571b 6, 9216, 9216, 4608, 1380, 0xc497571b +7, 3072, 3072, 512, 9983, 0x091aa8e8, F=0x0 +7, 3584, 3584, 512, 6991, 0xa0385313, F=0x0 0, 13824, 13824, 4608, 1383, 0x48e9510f 1, 13824, 13824, 4608, 1383, 0x48e9510f 2, 13824, 13824, 4608, 1380, 0x045550d3 @@ -70,6 +84,9 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 13824, 13824, 4608, 1383, 0x48e9510f 5, 13824, 13824, 4608, 1383, 0x48e9510f 6, 13824, 13824, 4608, 1383, 0x48e9510f +7, 4096, 4096, 512, 5825, 0x3c97cfbc, F=0x0 +7, 4608, 4608, 512, 4331, 0xbaf5f982, F=0x0 +7, 5120, 5120, 512, 2541, 0xe018c3cb, F=0x0 0, 18432, 18432, 4608, 1572, 0x9a514719 1, 18432, 18432, 4608, 1572, 0x9a514719 2, 18432, 18432, 4608, 1568, 0xa2bc45f4 @@ -77,6 +94,9 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 18432, 18432, 4608, 1572, 0x9a514719 5, 18432, 18432, 4608, 1572, 0x9a514719 6, 18432, 18432, 4608, 1572, 0x9a514719 +7, 5632, 5632, 512, 2655, 0xf98af7a1, F=0x0 +7, 6144, 6144, 512, 13464, 0x33e5196f +7, 6656, 6656, 512, 2587, 0x90e198aa, F=0x0 0, 23040, 23040, 4608, 1391, 0x74ac5014 1, 23040, 23040, 4608, 1391, 0x74ac5014 2, 23040, 23040, 4608, 1388, 0x96c85007 @@ -84,6 +104,8 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 23040, 23040, 4608, 1391, 0x74ac5014 5, 23040, 23040, 4608, 1391, 0x74ac5014 6, 23040, 23040, 4608, 1391, 0x74ac5014 +7, 7168, 7168, 512, 2313, 0x698c429b, F=0x0 +7, 7680, 7680, 512, 2123, 0x63a3f034, F=0x0 0, 27648, 27648, 4608, 1422, 0x2f9d47c5 1, 27648, 27648, 4608, 1422, 0x2f9d47c5 2, 27648, 27648, 4608, 1419, 0x4d4d466a @@ -91,6 +113,9 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 27648, 27648, 4608, 1422, 0x2f9d47c5 5, 27648, 27648, 4608, 1422, 0x2f9d47c5 6, 27648, 27648, 4608, 1422, 0x2f9d47c5 +7, 8192, 8192, 512, 2222, 0x442b233d, F=0x0 +7, 8704, 8704, 512, 2332, 0x24c75b04, F=0x0 +7, 9216, 9216, 512, 2302, 0xa0fa2ee7, F=0x0 0, 32256, 32256, 4608, 1768, 0x2a044b99 1, 32256, 32256, 4608, 1768, 0x2a044b99 2, 32256, 32256, 4608, 1765, 0xacb84b24 @@ -98,6 +123,8 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 32256, 32256, 4608, 1768, 0x2a044b99 5, 32256, 32256, 4608, 1768, 0x2a044b99 6, 32256, 32256, 4608, 1768, 0x2a044b99 +7, 9728, 9728, 512, 1740, 0xdf772eb3, F=0x0 +7, 10240, 10240, 512, 1994, 0x8830ad23, F=0x0 0, 36864, 36864, 4608, 1534, 0xb0b35a3f 1, 36864, 36864, 4608, 1534, 0xb0b35a3f 2, 36864, 36864, 4608, 1531, 0x996458aa @@ -105,6 +132,9 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 36864, 36864, 4608, 1534, 0xb0b35a3f 5, 36864, 36864, 4608, 1534, 0xb0b35a3f 6, 36864, 36864, 4608, 1534, 0xb0b35a3f +7, 10752, 10752, 512, 1884, 0x2c567db6, F=0x0 +7, 11264, 11264, 512, 1880, 0x72237c52, F=0x0 +7, 11776, 11776, 512, 1970, 0x60708ff8, F=0x0 0, 41472, 41472, 2628, 926, 0xc26a5eae 1, 41472, 41472, 2628, 926, 0xc26a5eae 2, 41472, 41472, 2628, 923, 0xa7225edf @@ -112,6 +142,7 @@ d9ef5d14bbd37c5a06c1494cacdb8f29 *tests/data/fate/mov-mp4-iamf-7_1_4.mp4 4, 41472, 41472, 2628, 926, 0xc26a5eae 5, 41472, 41472, 2628, 926, 0xc26a5eae 6, 41472, 41472, 2628, 926, 0xc26a5eae +7, 12288, 12288, 512, 11659, 0x6bcb830e [STREAM_GROUP] index=0 id=0x1 @@ -173,12 +204,13 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler TAG:vendor_id=[0][0][0][0] [STREAM] index=0 -id=0x0 +id=0x1 DISPOSITION:default=1 DISPOSITION:dub=0 DISPOSITION:original=0 @@ -197,31 +229,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 -id=0x1 -DISPOSITION:default=0 -DISPOSITION:dub=0 -DISPOSITION:original=0 -DISPOSITION:comment=0 -DISPOSITION:lyrics=0 -DISPOSITION:karaoke=0 -DISPOSITION:forced=0 -DISPOSITION:hearing_impaired=0 -DISPOSITION:visual_impaired=0 -DISPOSITION:clean_effects=0 -DISPOSITION:attached_pic=0 -DISPOSITION:timed_thumbnails=0 -DISPOSITION:non_diegetic=0 -DISPOSITION:captions=0 -DISPOSITION:descriptions=0 -DISPOSITION:metadata=0 -DISPOSITION:dependent=1 -DISPOSITION:still_image=0 -[/STREAM] -[STREAM] -index=2 id=0x2 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -241,9 +252,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] -index=3 +index=2 id=0x3 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -263,9 +275,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] -index=4 +index=3 id=0x4 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -285,9 +298,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] -index=5 +index=4 id=0x5 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -307,9 +321,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] -index=6 +index=5 id=0x6 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -329,6 +344,30 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=6 +id=0x7 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] [STREAM_GROUP] @@ -423,12 +462,13 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler TAG:vendor_id=[0][0][0][0] [STREAM] index=0 -id=0x0 +id=0x1 DISPOSITION:default=1 DISPOSITION:dub=0 DISPOSITION:original=0 @@ -447,31 +487,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 -id=0x1 -DISPOSITION:default=0 -DISPOSITION:dub=0 -DISPOSITION:original=0 -DISPOSITION:comment=0 -DISPOSITION:lyrics=0 -DISPOSITION:karaoke=0 -DISPOSITION:forced=0 -DISPOSITION:hearing_impaired=0 -DISPOSITION:visual_impaired=0 -DISPOSITION:clean_effects=0 -DISPOSITION:attached_pic=0 -DISPOSITION:timed_thumbnails=0 -DISPOSITION:non_diegetic=0 -DISPOSITION:captions=0 -DISPOSITION:descriptions=0 -DISPOSITION:metadata=0 -DISPOSITION:dependent=1 -DISPOSITION:still_image=0 -[/STREAM] -[STREAM] -index=2 id=0x2 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -491,9 +510,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] -index=3 +index=2 id=0x3 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -513,9 +533,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] -index=4 +index=3 id=0x4 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -535,9 +556,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] -index=5 +index=4 id=0x5 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -557,9 +579,10 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] -index=6 +index=5 id=0x6 DISPOSITION:default=0 DISPOSITION:dub=0 @@ -579,5 +602,61 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 +[/STREAM] +[STREAM] +index=6 +id=0x7 +DISPOSITION:default=0 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +DISPOSITION:non_diegetic=0 +DISPOSITION:captions=0 +DISPOSITION:descriptions=0 +DISPOSITION:metadata=0 +DISPOSITION:dependent=1 +DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] +[STREAM] +index=0 +id=0x1 +[/STREAM] +[STREAM] +index=1 +id=0x2 +[/STREAM] +[STREAM] +index=2 +id=0x3 +[/STREAM] +[STREAM] +index=3 +id=0x4 +[/STREAM] +[STREAM] +index=4 +id=0x5 +[/STREAM] +[STREAM] +index=5 +id=0x6 +[/STREAM] +[STREAM] +index=6 +id=0x7 +[/STREAM] +[STREAM] +index=7 +id=0x8 +[/STREAM] diff --git a/tests/ref/fate/mov-mp4-iamf-ambisonic_1 b/tests/ref/fate/mov-mp4-iamf-ambisonic_1 index a5b358112..d0877f73c 100644 --- a/tests/ref/fate/mov-mp4-iamf-ambisonic_1 +++ b/tests/ref/fate/mov-mp4-iamf-ambisonic_1 @@ -96,6 +96,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler TAG:vendor_id=[0][0][0][0] @@ -120,6 +121,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -142,6 +144,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -164,6 +167,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -186,6 +190,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] [STREAM_GROUP] @@ -256,6 +261,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler TAG:vendor_id=[0][0][0][0] @@ -280,6 +286,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -302,6 +309,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -324,6 +332,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -346,5 +355,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=1 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/mov-mp4-iamf-stereo b/tests/ref/fate/mov-mp4-iamf-stereo index 6526a7bcf..e40d164fc 100644 --- a/tests/ref/fate/mov-mp4-iamf-stereo +++ b/tests/ref/fate/mov-mp4-iamf-stereo @@ -49,6 +49,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler TAG:vendor_id=[0][0][0][0] @@ -73,6 +74,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] [STREAM_GROUP] @@ -182,6 +184,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler TAG:vendor_id=[0][0][0][0] @@ -206,5 +209,6 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [/STREAM_GROUP] diff --git a/tests/ref/fate/mov-mp4-pcm b/tests/ref/fate/mov-mp4-pcm index 6bae8f800..7cdca8629 100644 --- a/tests/ref/fate/mov-mp4-pcm +++ b/tests/ref/fate/mov-mp4-pcm @@ -1,4 +1,4 @@ -99ad26b4054794e84bd962a1124cdccf *tests/data/fate/mov-mp4-pcm.mp4 +0c6802135e9eb442201c0c1b001259d6 *tests/data/fate/mov-mp4-pcm.mp4 10587977 tests/data/fate/mov-mp4-pcm.mp4 #tb 0: 1/44100 #media_type 0: audio diff --git a/tests/ref/fate/mov-spherical-mono b/tests/ref/fate/mov-spherical-mono index bd57d9451..065b109a4 100644 --- a/tests/ref/fate/mov-spherical-mono +++ b/tests/ref/fate/mov-spherical-mono @@ -3,6 +3,11 @@ side_data_type=Stereo 3D type=2D inverted=0 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 [/SIDE_DATA] [SIDE_DATA] side_data_type=Spherical Mapping diff --git a/tests/ref/fate/mov-zombie b/tests/ref/fate/mov-zombie index 0ff447ef4..10476bc49 100644 --- a/tests/ref/fate/mov-zombie +++ b/tests/ref/fate/mov-zombie @@ -129,4 +129,4 @@ packet|codec_type=video|stream_index=0|pts=188623|pts_time=2.095811|dts=188622|d frame|media_type=video|stream_index=0|key_frame=0|pts=188623|pts_time=2.095811|pkt_dts=188622|pkt_dts_time=2.095800|best_effort_timestamp=188623|best_effort_timestamp_time=2.095811|duration=3003|duration_time=0.033367|pkt_pos=100846|pkt_size=974|width=160|height=240|crop_top=0|crop_bottom=0|crop_left=0|crop_right=0|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=B|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft|side_datum/3x3_displaymatrix:side_data_type=3x3 displaymatrix|side_datum/3x3_displaymatrix:displaymatrix=\n00000000: 131072 0 0\n00000001: 0 65536 0\n00000002: 0 0 1073741824\n|side_datum/3x3_displaymatrix:rotation=0|side_datum/h_26_45__user_data_unregistered_sei_message:side_data_type=H.26[45] User Data Unregistered SEI message packet|codec_type=video|stream_index=0|pts=197632|pts_time=2.195911|dts=191625|dts_time=2.129167|duration=3003|duration_time=0.033367|size=580|pos=101820|flags=__C frame|media_type=video|stream_index=0|key_frame=0|pts=191626|pts_time=2.129178|pkt_dts=N/A|pkt_dts_time=N/A|best_effort_timestamp=191626|best_effort_timestamp_time=2.129178|duration=3003|duration_time=0.033367|pkt_pos=99180|pkt_size=1666|width=160|height=240|crop_top=0|crop_bottom=0|crop_left=0|crop_right=0|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=P|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft|side_datum/3x3_displaymatrix:side_data_type=3x3 displaymatrix|side_datum/3x3_displaymatrix:displaymatrix=\n00000000: 131072 0 0\n00000001: 0 65536 0\n00000002: 0 0 1073741824\n|side_datum/3x3_displaymatrix:rotation=0|side_datum/h_26_45__user_data_unregistered_sei_message:side_data_type=H.26[45] User Data Unregistered SEI message -stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_tag_string=avc1|codec_tag=0x31637661|width=160|height=240|coded_width=160|coded_height=240|closed_captions=0|film_grain=0|has_b_frames=1|sample_aspect_ratio=2:1|display_aspect_ratio=4:3|pix_fmt=yuv420p|level=12|color_range=tv|color_space=smpte170m|color_transfer=bt709|color_primaries=smpte170m|chroma_location=topleft|field_order=progressive|refs=2|is_avc=true|nal_length_size=4|id=0x1|r_frame_rate=30000/1001|avg_frame_rate=6372000/212521|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=2125200|duration=23.613333|bit_rate=333874|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=708|nb_read_frames=65|nb_read_packets=66|extradata_size=34|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|tag:creation_time=2008-05-12T20:59:27.000000Z|tag:language=eng|tag:handler_name=Apple Video Media Handler|tag:vendor_id=appl|tag:encoder=H.264|side_datum/display_matrix:side_data_type=Display Matrix|side_datum/display_matrix:displaymatrix=\n00000000: 131072 0 0\n00000001: 0 65536 0\n00000002: 0 0 1073741824\n|side_datum/display_matrix:rotation=0 +stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_tag_string=avc1|codec_tag=0x31637661|width=160|height=240|coded_width=160|coded_height=240|closed_captions=0|film_grain=0|has_b_frames=1|sample_aspect_ratio=2:1|display_aspect_ratio=4:3|pix_fmt=yuv420p|level=12|color_range=tv|color_space=smpte170m|color_transfer=bt709|color_primaries=smpte170m|chroma_location=topleft|field_order=progressive|refs=2|is_avc=true|nal_length_size=4|id=0x1|r_frame_rate=30000/1001|avg_frame_rate=6372000/212521|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=2125200|duration=23.613333|bit_rate=333874|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=708|nb_read_frames=65|nb_read_packets=66|extradata_size=34|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:creation_time=2008-05-12T20:59:27.000000Z|tag:language=eng|tag:handler_name=Apple Video Media Handler|tag:vendor_id=appl|tag:encoder=H.264|side_datum/display_matrix:side_data_type=Display Matrix|side_datum/display_matrix:displaymatrix=\n00000000: 131072 0 0\n00000001: 0 65536 0\n00000002: 0 0 1073741824\n|side_datum/display_matrix:rotation=0 diff --git a/tests/ref/fate/movenc b/tests/ref/fate/movenc index 968a3d27f..5c12aeb29 100644 --- a/tests/ref/fate/movenc +++ b/tests/ref/fate/movenc @@ -20,7 +20,7 @@ write_data len 828, time nopts, type unknown atom - write_data len 728, time 999999, type sync atom moof write_data len 812, time nopts, type unknown atom - write_data len 148, time nopts, type trailer atom - -92ce825ff40505ec8676191705adb7e7 4439 ismv +d2df24d323f4a8896441cd91203ac5f8 4439 ismv write_data len 36, time nopts, type header atom ftyp write_data len 1123, time nopts, type header atom - write_data len 796, time 0, type sync atom moof @@ -151,3 +151,11 @@ write_data len 900, time 0, type sync atom moof write_data len 908, time 1000000, type sync atom moof write_data len 148, time nopts, type trailer atom - 3be575022e446855bca1e45b7942cc0c 3115 empty-moov-neg-cts +write_data len 28, time nopts, type header atom ftyp +write_data len 1123, time nopts, type header atom - +write_data len 70, time 0, type boundary atom emsg +write_data len 1832, time 0, type sync atom moof +write_data len 70, time 2000000, type boundary atom emsg +write_data len 1840, time 2000000, type sync atom moof +write_data len 148, time nopts, type trailer atom - +b72c56c795693820b156f452354a51ff 5111 emsg diff --git a/tests/ref/fate/mxf-probe-applehdr10 b/tests/ref/fate/mxf-probe-applehdr10 index e322b592f..e138dad3c 100644 --- a/tests/ref/fate/mxf-probe-applehdr10 +++ b/tests/ref/fate/mxf-probe-applehdr10 @@ -55,6 +55,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010501010D201300000040ECCE167353449C92D6F2693A9F1D75 [SIDE_DATA] side_data_type=Mastering display metadata @@ -120,6 +121,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010501010D201300000040ECCE167353449C92D6F2693A9F1D75 [/STREAM] [STREAM] @@ -167,6 +169,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010501010D201300000040ECCE167353449C92D6F2693A9F1D75 [/STREAM] [FORMAT] diff --git a/tests/ref/fate/mxf-probe-d10 b/tests/ref/fate/mxf-probe-d10 index 130de39a5..1e73c1522 100644 --- a/tests/ref/fate/mxf-probe-d10 +++ b/tests/ref/fate/mxf-probe-d10 @@ -56,6 +56,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010501010D1313000000AE86B200913105800000080046A54011 [SIDE_DATA] side_data_type=CPB properties @@ -111,6 +112,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010501010D1313000000AE86B200913105800000080046A54011 [/STREAM] [FORMAT] diff --git a/tests/ref/fate/mxf-probe-dnxhd b/tests/ref/fate/mxf-probe-dnxhd index c6e719a50..bd0939701 100644 --- a/tests/ref/fate/mxf-probe-dnxhd +++ b/tests/ref/fate/mxf-probe-dnxhd @@ -37,6 +37,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010101010F001300000057DEEA25B7D80C94060E2B347F7F2A80 TAG:data_type=audio [/STREAM] @@ -79,6 +80,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010101010F001300000057DEEA25B7F40C94060E2B347F7F2A80 TAG:data_type=audio [/STREAM] @@ -121,6 +123,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010101010F001300000057DEEA25B8050C94060E2B347F7F2A80 TAG:data_type=video [/STREAM] @@ -181,6 +184,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010101010F001300000057DEEA25B84D0C94060E2B347F7F2A80 TAG:file_package_name=dnxhr_export.aaf TAG:reel_umid=0x060A2B340101010101010F001300000057DEEA1570895313060E2B347F7F2A80 diff --git a/tests/ref/fate/mxf-probe-dv25 b/tests/ref/fate/mxf-probe-dv25 index dcf13e79f..ae23dbbe8 100644 --- a/tests/ref/fate/mxf-probe-dv25 +++ b/tests/ref/fate/mxf-probe-dv25 @@ -55,6 +55,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010501010D4313000000F2E2FCE98722F14F947F08DE1EF7A8DA [/STREAM] [STREAM] @@ -102,6 +103,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010501010D4313000000F2E2FCE98722F14F947F08DE1EF7A8DA [/STREAM] [STREAM] @@ -149,6 +151,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010501010D4313000000F2E2FCE98722F14F947F08DE1EF7A8DA [/STREAM] [FORMAT] diff --git a/tests/ref/fate/mxf-probe-j2k b/tests/ref/fate/mxf-probe-j2k index 517fbb99a..f1dadf420 100644 --- a/tests/ref/fate/mxf-probe-j2k +++ b/tests/ref/fate/mxf-probe-j2k @@ -55,6 +55,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 TAG:file_package_umid=0x060A2B340101010501010F201300000035E05073878E4B2FB69D2369F25ADFC9 TAG:file_package_name=File Package: SMPTE ST 422 / ST 2067-5 frame wrapping of JPEG 2000 codestreams TAG:track_name=Image Track diff --git a/tests/ref/fate/oggopus-demux b/tests/ref/fate/oggopus-demux index 05cdd94f4..03b7b76cf 100644 --- a/tests/ref/fate/oggopus-demux +++ b/tests/ref/fate/oggopus-demux @@ -39,5 +39,5 @@ packet|codec_type=audio|stream_index=0|pts=35164|pts_time=0.732583|dts=35164|dts packet|codec_type=audio|stream_index=0|pts=36124|pts_time=0.752583|dts=36124|dts_time=0.752583|duration=960|duration_time=0.020000|size=217|pos=841|flags=K__|data_hash=CRC32:b04fe85a packet|codec_type=audio|stream_index=0|pts=37084|pts_time=0.772583|dts=37084|dts_time=0.772583|duration=960|duration_time=0.020000|size=217|pos=841|flags=K__|data_hash=CRC32:06797ece packet|codec_type=audio|stream_index=0|pts=38044|pts_time=0.792583|dts=38044|dts_time=0.792583|duration=356|duration_time=0.007417|size=359|pos=841|flags=K__|data_hash=CRC32:01ca3f8f|side_datum/skip_samples:side_data_type=Skip Samples|side_datum/skip_samples:skip_samples=0|side_datum/skip_samples:discard_padding=604|side_datum/skip_samples:skip_reason=0|side_datum/skip_samples:discard_reason=0 -stream|index=0|codec_name=opus|profile=unknown|codec_type=audio|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|sample_fmt=fltp|sample_rate=48000|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=356|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/48000|start_pts=0|start_time=0.000000|duration_ts=38756|duration=0.807417|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=41|extradata_size=19|extradata_hash=CRC32:58ba5ff3|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|tag:ENCODER=opusenc from opus-tools 0.1.9|tag:ENCODER_OPTIONS=--discard-comments +stream|index=0|codec_name=opus|profile=unknown|codec_type=audio|codec_tag_string=[0][0][0][0]|codec_tag=0x0000|sample_fmt=fltp|sample_rate=48000|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=356|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/48000|start_pts=0|start_time=0.000000|duration_ts=38756|duration=0.807417|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=41|extradata_size=19|extradata_hash=CRC32:58ba5ff3|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:ENCODER=opusenc from opus-tools 0.1.9|tag:ENCODER_OPTIONS=--discard-comments format|filename=intro-partial.opus|nb_streams=1|nb_programs=0|nb_stream_groups=0|format_name=ogg|start_time=0.000000|duration=0.807417|size=10250|bit_rate=101558|probe_score=100 diff --git a/tests/ref/fate/opt b/tests/ref/fate/opt index f4fce1bd4..b8812e3ef 100644 --- a/tests/ref/fate/opt +++ b/tests/ref/fate/opt @@ -1,5 +1,6 @@ Testing default values num=0 +unum=2147483648 toggle=1 string=default escape=\=, @@ -14,7 +15,7 @@ color=255 192 203 255 channel_layout=311=311 binary=62 69 6e 0 binary_size=4 -num64=1 +num64=4294967296 flt=0.333333 dbl=0.333333 array_str[0]=str0 @@ -24,7 +25,8 @@ array_dict[0]: k00 v\00 array_dict[0]: k01 v,01 array_dict[1]: k10 v=1:0 TestContext AVOptions: - -num E.......... set num (from 0 to 100) (default 0) + -num E.......... set num (from -1 to 100) (default 0) + -unum E.......... set unum (from 0 to 2.14748e+09) (default 2147483648) -toggle E.......... set toggle (from 0 to 1) (default 1) -rational E.......... set rational (from 0 to 10) (default 1/1) -string E.......... set string (default "default") @@ -43,7 +45,7 @@ TestContext AVOptions: -bin E.......... set binary value -bin1 E.......... set binary value -bin2 E.......... set binary value - -num64 E.......... set num 64bit (from 0 to 100) (default 1) + -num64 E.......... set num 64bit (from -1 to 4.29497e+09) (default 4294967296) -flt E.......... set float (from 0 to 100) (default 0.333333) -dbl E.......... set double (from 0 to 100) (default 0.333333) -bool1 E.......... set boolean value (default auto) @@ -57,6 +59,7 @@ TestContext AVOptions: Testing av_opt_is_set_to_default() name: num default:1 error: +name: unum default:0 error: name: toggle default:0 error: name: rational default:0 error: name: string default:0 error: @@ -87,6 +90,7 @@ name: array_int default:0 error: name: array_str default:0 error: name:array_dict default:0 error: name: num default:1 error: +name: unum default:1 error: name: toggle default:1 error: name: rational default:1 error: name: string default:1 error: @@ -119,6 +123,7 @@ name:array_dict default:1 error: Testing av_opt_get/av_opt_set() name: num get: 0 set: OK get: 0 OK +name: unum get: 2147483648 set: OK get: 2147483648 OK name: toggle get: 1 set: OK get: 1 OK name: rational get: 1/1 set: OK get: 1/1 OK name: string get: default set: OK get: default OK @@ -134,7 +139,7 @@ name: cl get: hexagonal set: OK get: hexagonal name: bin get: 62696E00 set: OK get: 62696E00 OK name: bin1 get: set: OK get: OK name: bin2 get: set: OK get: OK -name: num64 get: 1 set: OK get: 1 OK +name: num64 get: 4294967296 set: OK get: 4294967296 OK name: flt get: 0.333333 set: OK get: 0.333333 OK name: dbl get: 0.333333 set: OK get: 0.333333 OK name: bool1 get: auto set: OK get: auto OK @@ -149,9 +154,16 @@ av_opt_set("array_dict", NULL) -> 0 array_dict=NULL; nb_array_dict=0 av_opt_get("array_dict") -> NULL +Testing av_opt_get_array() +av_opt_get_array("array_int", 1, 3, INT)=0 -> [ 0, 42, 137 ] +av_opt_get_array("array_int", 3, 2, DOUBLE)=0 -> [ 137.00, 2147483647.00 ] +av_opt_get_array("array_int", 0, 5, STRING)=0 -> [ 5, 0, 42, 137, 2147483647 ] +av_opt_get_array("array_dict", 0, 2, DICT)=0 + Test av_opt_serialize() -num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-),array_int=,array_str=str0|str\\|1|str\\\\2,array_dict=k00\=v\\\\\\\\00:k01\=v\\\,01\,k10\=v\\\\\=1\\\\:0 +num=0,unum=2147483648,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=4294967296,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-),array_int=,array_str=str0|str\\|1|str\\\\2,array_dict=k00\=v\\\\\\\\00:k01\=v\\\,01\,k10\=v\\\\\=1\\\\:0 Setting entry with key 'num' to value '0' +Setting entry with key 'unum' to value '2147483648' Setting entry with key 'toggle' to value '1' Setting entry with key 'rational' to value '1/1' Setting entry with key 'string' to value 'default' @@ -167,7 +179,7 @@ Setting entry with key 'cl' to value 'hexagonal' Setting entry with key 'bin' to value '62696E00' Setting entry with key 'bin1' to value '' Setting entry with key 'bin2' to value '' -Setting entry with key 'num64' to value '1' +Setting entry with key 'num64' to value '4294967296' Setting entry with key 'flt' to value '0.333333' Setting entry with key 'dbl' to value '0.333333' Setting entry with key 'bool1' to value 'auto' @@ -178,7 +190,8 @@ Setting entry with key 'dict2' to value 'happy=\:-)' Setting entry with key 'array_int' to value '' Setting entry with key 'array_str' to value 'str0|str\|1|str\\2' Setting entry with key 'array_dict' to value 'k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0' -num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-),array_int=,array_str=str0|str\\|1|str\\\\2,array_dict=k00\=v\\\\\\\\00:k01\=v\\\,01\,k10\=v\\\\\=1\\\\:0 +num=0,unum=2147483648,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=4294967296,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-),array_int=,array_str=str0|str\\|1|str\\\\2,array_dict=k00\=v\\\\\\\\00:k01\=v\\\,01\,k10\=v\\\\\=1\\\\:0 +child_num=0,flt=0.333333,dbl=0.333333,array_int= Testing av_set_options_string() Setting options string '' @@ -336,6 +349,50 @@ Error 'bin=111' Setting options string 'bin=ffff' Setting entry with key 'bin' to value 'ffff' OK 'bin=ffff' +Setting options string 'num=bogus' +Setting entry with key 'num' to value 'bogus' +Undefined constant or missing '(' in 'bogus' +Unable to parse option value "bogus" +Error 'num=bogus' +Setting options string 'num=44' +Setting entry with key 'num' to value '44' +OK 'num=44' +Setting options string 'num=44.4' +Setting entry with key 'num' to value '44.4' +OK 'num=44.4' +Setting options string 'num=-1' +Setting entry with key 'num' to value '-1' +OK 'num=-1' +Setting options string 'num=-2' +Setting entry with key 'num' to value '-2' +Value -2.000000 for parameter 'num' out of range [-1 - 100] +Error 'num=-2' +Setting options string 'num=101' +Setting entry with key 'num' to value '101' +Value 101.000000 for parameter 'num' out of range [-1 - 100] +Error 'num=101' +Setting options string 'unum=bogus' +Setting entry with key 'unum' to value 'bogus' +Undefined constant or missing '(' in 'bogus' +Unable to parse option value "bogus" +Error 'unum=bogus' +Setting options string 'unum=44' +Setting entry with key 'unum' to value '44' +OK 'unum=44' +Setting options string 'unum=44.4' +Setting entry with key 'unum' to value '44.4' +OK 'unum=44.4' +Setting options string 'unum=-1' +Setting entry with key 'unum' to value '-1' +Value -1.000000 for parameter 'unum' out of range [0 - 2.14748e+09] +Error 'unum=-1' +Setting options string 'unum=2147483648' +Setting entry with key 'unum' to value '2147483648' +OK 'unum=2147483648' +Setting options string 'unum=2147483649' +Setting entry with key 'unum' to value '2147483649' +Value 2147483649.000000 for parameter 'unum' out of range [0 - 2.14748e+09] +Error 'unum=2147483649' Setting options string 'num64=bogus' Setting entry with key 'num64' to value 'bogus' Undefined constant or missing '(' in 'bogus' @@ -349,12 +406,18 @@ Setting entry with key 'num64' to value '44.4' OK 'num64=44.4' Setting options string 'num64=-1' Setting entry with key 'num64' to value '-1' -Value -1.000000 for parameter 'num64' out of range [0 - 100] -Error 'num64=-1' -Setting options string 'num64=101' -Setting entry with key 'num64' to value '101' -Value 101.000000 for parameter 'num64' out of range [0 - 100] -Error 'num64=101' +OK 'num64=-1' +Setting options string 'num64=-2' +Setting entry with key 'num64' to value '-2' +Value -2.000000 for parameter 'num64' out of range [-1 - 4.29497e+09] +Error 'num64=-2' +Setting options string 'num64=4294967296' +Setting entry with key 'num64' to value '4294967296' +OK 'num64=4294967296' +Setting options string 'num64=4294967297' +Setting entry with key 'num64' to value '4294967297' +Value 4294967297.000000 for parameter 'num64' out of range [-1 - 4.29497e+09] +Error 'num64=4294967297' Setting options string 'flt=bogus' Setting entry with key 'flt' to value 'bogus' Undefined constant or missing '(' in 'bogus' @@ -448,3 +511,10 @@ Setting options string 'a_very_long_option_name_that_will_need_to_be_ellipsized_ Setting 'a_very_long_option_name_that_will_need_to_be_ellipsized_around_here' to value '42' Option 'a_very_long_option_name_that_will_need_to_be_ellipsized_around_here' not found Error 'a_very_long_option_name_that_will_need_to_be_ellipsized_around_here=42' + +Testing av_opt_find2() +OK 'num' +Error 'num64' +Error 'child_num' +OK 'child_num' +Error 'foo' diff --git a/tests/ref/fate/png-mdcv b/tests/ref/fate/png-mdcv new file mode 100644 index 000000000..c524a94de --- /dev/null +++ b/tests/ref/fate/png-mdcv @@ -0,0 +1,22 @@ +fc68fe6c8c72343b96d2695f6913995b *tests/data/fate/png-mdcv.image2pipe +439248 tests/data/fate/png-mdcv.image2pipe +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1280x720 +#sar 0: 0/1 +0, 0, 0, 1, 2764800, 0x2bfc7b42 +frames.frame.0.side_data_list.side_data.0.side_data_type="Content light level metadata" +frames.frame.0.side_data_list.side_data.0.max_content=1000 +frames.frame.0.side_data_list.side_data.0.max_average=200 +frames.frame.0.side_data_list.side_data.1.side_data_type="Mastering display metadata" +frames.frame.0.side_data_list.side_data.1.red_x="13250/50000" +frames.frame.0.side_data_list.side_data.1.red_y="7500/50000" +frames.frame.0.side_data_list.side_data.1.green_x="34000/50000" +frames.frame.0.side_data_list.side_data.1.green_y="16000/50000" +frames.frame.0.side_data_list.side_data.1.blue_x="2/50000" +frames.frame.0.side_data_list.side_data.1.blue_y="0/50000" +frames.frame.0.side_data_list.side_data.1.white_point_x="15635/50000" +frames.frame.0.side_data_list.side_data.1.white_point_y="16450/50000" +frames.frame.0.side_data_list.side_data.1.min_luminance="50/10000" +frames.frame.0.side_data_list.side_data.1.max_luminance="10000000/10000" diff --git a/tests/ref/fate/prores-transparency b/tests/ref/fate/prores-transparency index 246e0b26a..a4452e733 100644 --- a/tests/ref/fate/prores-transparency +++ b/tests/ref/fate/prores-transparency @@ -1,13 +1,13 @@ #tb 0: 1/25 #media_type 0: video #codec_id 0: rawvideo -#dimensions 0: 1920x1080 +#dimensions 0: 1888x1062 #sar 0: 1/1 #tb 1: 1/48000 #media_type 1: audio #codec_id 1: pcm_s16le #sample_rate 1: 48000 #channel_layout_name 1: stereo -0, 0, 0, 1, 16588800, 0xcfb3d806 +0, 0, 0, 1, 16040448, 0x74480f47 1, 0, 0, 1024, 4096, 0x00000000 1, 1024, 1024, 896, 3584, 0x00000000 diff --git a/tests/ref/fate/prores-transparency_skip b/tests/ref/fate/prores-transparency_skip index 3f5fa0a13..3e99a3de9 100644 --- a/tests/ref/fate/prores-transparency_skip +++ b/tests/ref/fate/prores-transparency_skip @@ -1,13 +1,13 @@ #tb 0: 1/25 #media_type 0: video #codec_id 0: rawvideo -#dimensions 0: 1920x1080 +#dimensions 0: 1888x1062 #sar 0: 1/1 #tb 1: 1/48000 #media_type 1: audio #codec_id 1: pcm_s16le #sample_rate 1: 48000 #channel_layout_name 1: stereo -0, 0, 0, 1, 12441600, 0x74f53304 +0, 0, 0, 1, 12030336, 0x088e6a36 1, 0, 0, 1024, 4096, 0x00000000 1, 1024, 1024, 896, 3584, 0x00000000 diff --git a/tests/ref/fate/segment-mp4-to-ts b/tests/ref/fate/segment-mp4-to-ts index 299441627..54b59a09c 100644 --- a/tests/ref/fate/segment-mp4-to-ts +++ b/tests/ref/fate/segment-mp4-to-ts @@ -4,7 +4,7 @@ #codec_id 0: h264 #dimensions 0: 640x360 #sar 0: 1/1 -0, -7200, 0, 3600, 22630, 0x9b109541, S=1, 1 +0, -7200, 0, 3600, 22630, 0xee579541, S=1, 1 0, -3600, 14400, 3600, 4021, 0xbf7cdb02, F=0x0, S=1, 1 0, 0, 7200, 3600, 1096, 0x4f162690, F=0x0, S=1, 1 0, 3600, 3600, 3600, 687, 0x00394b95, F=0x0, S=1, 1 @@ -25,7 +25,7 @@ 0, 57600, 64800, 3600, 1182, 0xbe1a4847, F=0x0, S=1, 1 0, 61200, 61200, 3600, 809, 0x8d948a4e, F=0x0, S=1, 1 0, 64800, 68400, 3600, 656, 0x4fa03c2b, F=0x0, S=1, 1 -0, 68400, 86400, 3600, 26555, 0x5629b584, S=1, 1 +0, 68400, 86400, 3600, 26606, 0x0f75c37d, S=1, 1 0, 72000, 79200, 3600, 1141, 0x761b31e8, F=0x0, S=1, 1 0, 75600, 75600, 3600, 717, 0x57746351, F=0x0, S=1, 1 0, 79200, 82800, 3600, 693, 0x78b24263, F=0x0, S=1, 1 @@ -49,7 +49,7 @@ 0, 144000, 151200, 3600, 1271, 0x46006870, F=0x0, S=1, 1 0, 147600, 147600, 3600, 849, 0x94dc99c7, F=0x2, S=1, 1 0, 151200, 154800, 3600, 753, 0xf4236cab, F=0x0, S=1, 1 -0, 154800, 172800, 3600, 25825, 0xd5464dee, S=1, 1 +0, 154800, 172800, 3600, 25876, 0xb4305be7, S=1, 1 0, 158400, 165600, 3600, 1206, 0x8ce84344, F=0x0, S=1, 1 0, 162000, 162000, 3600, 867, 0x312fa07d, F=0x0, S=1, 1 0, 165600, 169200, 3600, 719, 0x810666d1, F=0x0, S=1, 1 @@ -73,7 +73,7 @@ 0, 230400, 237600, 3600, 1545, 0x0099fc98, F=0x0, S=1, 1 0, 234000, 234000, 3600, 929, 0xfd72d049, F=0x2, S=1, 1 0, 237600, 241200, 3600, 829, 0xcfda9e96, F=0x0, S=1, 1 -0, 241200, 259200, 3600, 24220, 0x5ca21d71, S=1, 1 +0, 241200, 259200, 3600, 24271, 0x9c472b6a, S=1, 1 0, 244800, 252000, 3600, 1422, 0xcde6cc34, F=0x0, S=1, 1 0, 248400, 248400, 3600, 883, 0xedacbe25, F=0x0, S=1, 1 0, 252000, 255600, 3600, 768, 0x89d774bc, F=0x0, S=1, 1 @@ -97,7 +97,7 @@ 0, 316800, 324000, 3600, 1501, 0xb3b8f001, F=0x0, S=1, 1 0, 320400, 320400, 3600, 941, 0x92b0cb18, F=0x2, S=1, 1 0, 324000, 327600, 3600, 823, 0x3d548355, F=0x0, S=1, 1 -0, 327600, 345600, 3600, 24042, 0x441e94fb, S=1, 1 +0, 327600, 345600, 3600, 24093, 0xcc0ba2f4, S=1, 1 0, 331200, 338400, 3600, 1582, 0x4f5d1049, F=0x0, S=1, 1 0, 334800, 334800, 3600, 945, 0x4f3cc9e8, F=0x0, S=1, 1 0, 338400, 342000, 3600, 815, 0x0ca790a4, F=0x0, S=1, 1 @@ -121,7 +121,7 @@ 0, 403200, 410400, 3600, 359, 0x11bdae52, F=0x0, S=1, 1 0, 406800, 406800, 3600, 235, 0xbec26964, F=0x2, S=1, 1 0, 410400, 414000, 3600, 221, 0x8380682c, F=0x0, S=1, 1 -0, 414000, 432000, 3600, 22588, 0xf0ecf072, S=1, 1 +0, 414000, 432000, 3600, 22639, 0x1809fe6b, S=1, 1 0, 417600, 424800, 3600, 383, 0x4f3bb571, F=0x0, S=1, 1 0, 421200, 421200, 3600, 257, 0x22e87802, F=0x0, S=1, 1 0, 424800, 428400, 3600, 261, 0xdb988134, F=0x0, S=1, 1 diff --git a/tests/ref/fate/side_data_array b/tests/ref/fate/side_data_array index 7d8c684d8..c1d77b044 100644 --- a/tests/ref/fate/side_data_array +++ b/tests/ref/fate/side_data_array @@ -1,14 +1,14 @@ Initial addition results with duplicates: -sd 0, Ambient viewing environment -sd 1, Content light level metadata: MaxCLL: 1 -sd 2, Content light level metadata: MaxCLL: 2 -sd 3, Content light level metadata: MaxCLL: 3 -sd 4, Spherical Mapping -sd 5, Content light level metadata: MaxCLL: 4 -sd 6, Content light level metadata: MaxCLL: 5 -sd 7, Content light level metadata: MaxCLL: 6 +sd 0 (size 4), Content light level metadata +sd 1 (size 4), H.26[45] User Data Unregistered SEI message: 1 +sd 2 (size 4), H.26[45] User Data Unregistered SEI message: 2 +sd 3 (size 4), H.26[45] User Data Unregistered SEI message: 3 +sd 4 (size 4), Spherical Mapping +sd 5 (size 4), H.26[45] User Data Unregistered SEI message: 4 +sd 6 (size 4), H.26[45] User Data Unregistered SEI message: 5 +sd 7 (size 4), H.26[45] User Data Unregistered SEI message: 6 Final state after a single 'no-duplicates' addition: -sd 0, Ambient viewing environment -sd 1, Spherical Mapping -sd 2, Content light level metadata: MaxCLL: 1337 +sd 0 (size 4), Content light level metadata +sd 1 (size 4), Spherical Mapping +sd 2 (size 4), H.26[45] User Data Unregistered SEI message: 1337 diff --git a/tests/ref/fate/source b/tests/ref/fate/source index d8d422414..78d3a2e0f 100644 --- a/tests/ref/fate/source +++ b/tests/ref/fate/source @@ -1,28 +1,30 @@ Files without standard license headers: libavcodec/file_open.c -libavcodec/ilbcdata.h -libavcodec/ilbcdec.c libavcodec/interplayacm.c libavcodec/log2_tab.c libavcodec/reverse.c +libavcodec/riscv/cpu_common.c libavdevice/file_open.c libavdevice/reverse.c -libavfilter/af_arnndn.c +libavdevice/riscv/cpu_common.c libavfilter/file_open.c libavfilter/log2_tab.c -libavformat/bitstream.c +libavfilter/riscv/cpu_common.c libavformat/file_open.c libavformat/golomb_tab.c libavformat/log2_tab.c libavformat/rangecoder_dec.c +libavformat/riscv/cpu_common.c libswresample/log2_tab.c libswscale/log2_tab.c +libswscale/riscv/cpu_common.c tools/uncoded_frame.c tools/yuvcmp.c Headers without standard inclusion guards: compat/djgpp/math.h compat/float/float.h compat/float/limits.h +compat/stdbit/stdbit.h libavcodec/bitstream_template.h tools/decode_simple.h Use of av_clip() where av_clip_uintp2() could be used: diff --git a/tests/ref/fate/spdif-dca-core-remux b/tests/ref/fate/spdif-dca-core-remux index a74b8a41a..4fcbf8c5d 100644 --- a/tests/ref/fate/spdif-dca-core-remux +++ b/tests/ref/fate/spdif-dca-core-remux @@ -5,10 +5,10 @@ a4e739ebe07c75dd569156d5038696a9 *tests/data/fate/spdif-dca-core-remux.spdif #codec_id 0: dts #sample_rate 0: 48000 #channel_layout_name 0: 5.1(side) -0, 0, 0, 0, 1024, 0x07b79d2a -0, 0, 0, 0, 1024, 0x7eaaba77 -0, 0, 0, 0, 1024, 0xbed65c1d -0, 0, 0, 0, 1024, 0x10bc6792 -0, 0, 0, 0, 1024, 0xf8436f6e -0, 0, 0, 0, 1024, 0x4454a681 -0, 0, 0, 0, 1024, 0xda3ba189 +0, 0, 0, 960, 1024, 0x07b79d2a +0, 960, 960, 960, 1024, 0x7eaaba77 +0, 1920, 1920, 960, 1024, 0xbed65c1d +0, 2880, 2880, 960, 1024, 0x10bc6792 +0, 3840, 3840, 960, 1024, 0xf8436f6e +0, 4800, 4800, 960, 1024, 0x4454a681 +0, 5760, 5760, 960, 1024, 0xda3ba189 diff --git a/tests/ref/fate/spdif-dca-master-core-remux b/tests/ref/fate/spdif-dca-master-core-remux index de6f12818..d6cfeefb5 100644 --- a/tests/ref/fate/spdif-dca-master-core-remux +++ b/tests/ref/fate/spdif-dca-master-core-remux @@ -5,1175 +5,1175 @@ c4f3f3c6ca73fcb7beac137105dadab4 *tests/data/fate/spdif-dca-master-core-remux.sp #codec_id 0: dts #sample_rate 0: 48000 #channel_layout_name 0: 5.1(side) -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xbe7b9e5e -0, 0, 0, 0, 2012, 0x671dc73a -0, 0, 0, 0, 2012, 0x7fd5b1d2 -0, 0, 0, 0, 2012, 0xa9259df1 -0, 0, 0, 0, 2012, 0x3e8c2b92 -0, 0, 0, 0, 2012, 0x4876a9ff -0, 0, 0, 0, 2012, 0x7e469182 -0, 0, 0, 0, 2012, 0x10eba401 -0, 0, 0, 0, 2012, 0x51c68ed3 -0, 0, 0, 0, 2012, 0x3f52901b -0, 0, 0, 0, 2012, 0x7bebacce -0, 0, 0, 0, 2012, 0xcb94898d -0, 0, 0, 0, 2012, 0x14e3ae70 -0, 0, 0, 0, 2012, 0x016893cb -0, 0, 0, 0, 2012, 0x00739f0a -0, 0, 0, 0, 2012, 0x834aba41 -0, 0, 0, 0, 2012, 0x6a92ac08 -0, 0, 0, 0, 2012, 0x09eda257 -0, 0, 0, 0, 2012, 0x81449e3f -0, 0, 0, 0, 2012, 0xe6eb91d4 -0, 0, 0, 0, 2012, 0x51158c0e -0, 0, 0, 0, 2012, 0x84e4a013 -0, 0, 0, 0, 2012, 0x4c48a0e6 -0, 0, 0, 0, 2012, 0xf54c9811 -0, 0, 0, 0, 2012, 0x62778edb -0, 0, 0, 0, 2012, 0x7226a51b -0, 0, 0, 0, 2012, 0x44b9aad8 -0, 0, 0, 0, 2012, 0x8aa6b380 -0, 0, 0, 0, 2012, 0xc88c99e6 -0, 0, 0, 0, 2012, 0xed5e93e2 -0, 0, 0, 0, 2012, 0xeb0b9755 -0, 0, 0, 0, 2012, 0xe5ba8ca9 -0, 0, 0, 0, 2012, 0x2fef9bcf -0, 0, 0, 0, 2012, 0xf19c8749 -0, 0, 0, 0, 2012, 0x0feb94d0 -0, 0, 0, 0, 2012, 0x1f9194d1 -0, 0, 0, 0, 2012, 0x0cad9822 -0, 0, 0, 0, 2012, 0xe6f79152 -0, 0, 0, 0, 2012, 0x69e78955 -0, 0, 0, 0, 2012, 0x91dd8a1b -0, 0, 0, 0, 2012, 0x63fe8eea -0, 0, 0, 0, 2012, 0x8f6d90a2 -0, 0, 0, 0, 2012, 0xe3bf8626 -0, 0, 0, 0, 2012, 0xd08599db -0, 0, 0, 0, 2012, 0xf556a282 -0, 0, 0, 0, 2012, 0x7f8c8f90 -0, 0, 0, 0, 2012, 0xa04493b9 -0, 0, 0, 0, 2012, 0x21a19b3a -0, 0, 0, 0, 2012, 0x6ead9244 -0, 0, 0, 0, 2012, 0xe65290d7 -0, 0, 0, 0, 2012, 0x8ff58a8e -0, 0, 0, 0, 2012, 0x24ada603 -0, 0, 0, 0, 2012, 0x79cb85c7 -0, 0, 0, 0, 2012, 0x63c0ac54 -0, 0, 0, 0, 2012, 0x7f719f83 -0, 0, 0, 0, 2012, 0x2eb69654 -0, 0, 0, 0, 2012, 0xf5149bc0 -0, 0, 0, 0, 2012, 0xd0d6a414 -0, 0, 0, 0, 2012, 0x4f4a8ed3 -0, 0, 0, 0, 2012, 0x20888cb5 -0, 0, 0, 0, 2012, 0x13439c86 -0, 0, 0, 0, 2012, 0xc8fc98e1 -0, 0, 0, 0, 2012, 0x14689766 -0, 0, 0, 0, 2012, 0x830293e4 -0, 0, 0, 0, 2012, 0xdd5bb8ce -0, 0, 0, 0, 2012, 0x005ea280 -0, 0, 0, 0, 2012, 0x9b0581e2 -0, 0, 0, 0, 2012, 0x210f89b8 -0, 0, 0, 0, 2012, 0xb7c180bd -0, 0, 0, 0, 2012, 0xe53c85e4 -0, 0, 0, 0, 2012, 0x1f689207 -0, 0, 0, 0, 2012, 0x5653813b -0, 0, 0, 0, 2012, 0x1d278d66 -0, 0, 0, 0, 2012, 0xd94c9a83 -0, 0, 0, 0, 2012, 0x7af48548 -0, 0, 0, 0, 2012, 0x86209c99 -0, 0, 0, 0, 2012, 0x6e3b7fc9 -0, 0, 0, 0, 2012, 0x41c289e7 -0, 0, 0, 0, 2012, 0x8bea85db -0, 0, 0, 0, 2012, 0x45c98c39 -0, 0, 0, 0, 2012, 0xee098755 -0, 0, 0, 0, 2012, 0x485d9ec1 -0, 0, 0, 0, 2012, 0x78819023 -0, 0, 0, 0, 2012, 0xf43377bd -0, 0, 0, 0, 2012, 0x43fc9439 -0, 0, 0, 0, 2012, 0x045e9bf3 -0, 0, 0, 0, 2012, 0x0fc09f0c -0, 0, 0, 0, 2012, 0x7ba69bf5 -0, 0, 0, 0, 2012, 0x4aa7aaf0 -0, 0, 0, 0, 2012, 0x620c85bf -0, 0, 0, 0, 2012, 0xa6bb8a30 -0, 0, 0, 0, 2012, 0xfd10883c -0, 0, 0, 0, 2012, 0x32037e17 -0, 0, 0, 0, 2012, 0xb18c9e01 -0, 0, 0, 0, 2012, 0xd8206ee5 -0, 0, 0, 0, 2012, 0xdbc49136 -0, 0, 0, 0, 2012, 0x650a785d -0, 0, 0, 0, 2012, 0x9e107d61 -0, 0, 0, 0, 2012, 0xbf4eac50 -0, 0, 0, 0, 2012, 0x9d8f79b2 -0, 0, 0, 0, 2012, 0x252d8e8a -0, 0, 0, 0, 2012, 0x00af8fd6 -0, 0, 0, 0, 2012, 0x9e388d3b -0, 0, 0, 0, 2012, 0x75de7f56 -0, 0, 0, 0, 2012, 0xd502839c -0, 0, 0, 0, 2012, 0x66709e03 -0, 0, 0, 0, 2012, 0x3e0a96ba -0, 0, 0, 0, 2012, 0x0813ad4e -0, 0, 0, 0, 2012, 0x799c90c5 -0, 0, 0, 0, 2012, 0x98a18bed -0, 0, 0, 0, 2012, 0x8cd197d7 -0, 0, 0, 0, 2012, 0xf9ea8b22 -0, 0, 0, 0, 2012, 0x674f7cd2 -0, 0, 0, 0, 2012, 0xa5c39136 -0, 0, 0, 0, 2012, 0xe064ac30 -0, 0, 0, 0, 2012, 0x2af78c75 -0, 0, 0, 0, 2012, 0x43df9b19 -0, 0, 0, 0, 2012, 0x8d1a87d5 -0, 0, 0, 0, 2012, 0xd5be8d29 -0, 0, 0, 0, 2012, 0x43448bd4 -0, 0, 0, 0, 2012, 0xa128a30b -0, 0, 0, 0, 2012, 0x6fc29902 -0, 0, 0, 0, 2012, 0x5854a24b -0, 0, 0, 0, 2012, 0xb222958a -0, 0, 0, 0, 2012, 0xfca39cce -0, 0, 0, 0, 2012, 0xee0087f0 -0, 0, 0, 0, 2012, 0xd2d69b8c -0, 0, 0, 0, 2012, 0xe2308f8d -0, 0, 0, 0, 2012, 0x8dc4b09a -0, 0, 0, 0, 2012, 0x14489aef -0, 0, 0, 0, 2012, 0x900f9835 -0, 0, 0, 0, 2012, 0x0092a95f -0, 0, 0, 0, 2012, 0xfd90b1bf -0, 0, 0, 0, 2012, 0xb11ab5d5 -0, 0, 0, 0, 2012, 0xc802b908 -0, 0, 0, 0, 2012, 0xb12aa91e -0, 0, 0, 0, 2012, 0xd173c2a9 -0, 0, 0, 0, 2012, 0xaeafb887 -0, 0, 0, 0, 2012, 0xeb7eb0d7 -0, 0, 0, 0, 2012, 0x9afbc56a -0, 0, 0, 0, 2012, 0x2d78bc34 -0, 0, 0, 0, 2012, 0x6550aed1 -0, 0, 0, 0, 2012, 0xd514a55d -0, 0, 0, 0, 2012, 0x9058c263 -0, 0, 0, 0, 2012, 0xf819b66a -0, 0, 0, 0, 2012, 0x16a5c902 -0, 0, 0, 0, 2012, 0x602fc11b -0, 0, 0, 0, 2012, 0xe3c6b177 -0, 0, 0, 0, 2012, 0xacc4cd06 -0, 0, 0, 0, 2012, 0xeb96addb -0, 0, 0, 0, 2012, 0x1195cad3 -0, 0, 0, 0, 2012, 0x8e96ad7f -0, 0, 0, 0, 2012, 0x31e592b7 -0, 0, 0, 0, 2012, 0xa0c5ccf0 -0, 0, 0, 0, 2012, 0x6e77c92b -0, 0, 0, 0, 2012, 0xe87fa928 -0, 0, 0, 0, 2012, 0x4923bcdb -0, 0, 0, 0, 2012, 0x3260b452 -0, 0, 0, 0, 2012, 0x62beafa0 -0, 0, 0, 0, 2012, 0x5a6fc18a -0, 0, 0, 0, 2012, 0x9d05ae87 -0, 0, 0, 0, 2012, 0xb577a54e -0, 0, 0, 0, 2012, 0xd66bc5ef -0, 0, 0, 0, 2012, 0x40bec7bb -0, 0, 0, 0, 2012, 0xedd3a1b9 -0, 0, 0, 0, 2012, 0xf6f49f83 -0, 0, 0, 0, 2012, 0x316fb06d -0, 0, 0, 0, 2012, 0xc3f3a874 -0, 0, 0, 0, 2012, 0x3a96b3bd -0, 0, 0, 0, 2012, 0x825aba30 -0, 0, 0, 0, 2012, 0x5b58ce66 -0, 0, 0, 0, 2012, 0x412dc092 -0, 0, 0, 0, 2012, 0xcb47bfa3 -0, 0, 0, 0, 2012, 0xe025bb79 -0, 0, 0, 0, 2012, 0x0042ba53 -0, 0, 0, 0, 2012, 0x7e9bba1d -0, 0, 0, 0, 2012, 0x0058c99d -0, 0, 0, 0, 2012, 0x47d2b590 -0, 0, 0, 0, 2012, 0xdf4ba9c6 -0, 0, 0, 0, 2012, 0xe671987c -0, 0, 0, 0, 2012, 0x90dccc89 -0, 0, 0, 0, 2012, 0x012ccae9 -0, 0, 0, 0, 2012, 0x2eb5b83e -0, 0, 0, 0, 2012, 0x3fecb7f4 -0, 0, 0, 0, 2012, 0x7955a464 -0, 0, 0, 0, 2012, 0xfe9eb3c3 -0, 0, 0, 0, 2012, 0x7457c904 -0, 0, 0, 0, 2012, 0xd23ea69d -0, 0, 0, 0, 2012, 0xc497bf82 -0, 0, 0, 0, 2012, 0x15e5c241 -0, 0, 0, 0, 2012, 0x3dfea71f -0, 0, 0, 0, 2012, 0x1e59c9c0 -0, 0, 0, 0, 2012, 0x1a34b927 -0, 0, 0, 0, 2012, 0xbf42b430 -0, 0, 0, 0, 2012, 0xf084c29f -0, 0, 0, 0, 2012, 0x6443c44a -0, 0, 0, 0, 2012, 0x7985a4a5 -0, 0, 0, 0, 2012, 0x27add059 -0, 0, 0, 0, 2012, 0x7f1faea4 -0, 0, 0, 0, 2012, 0x8d9dc732 -0, 0, 0, 0, 2012, 0xf272c32e -0, 0, 0, 0, 2012, 0x4fa3ab11 -0, 0, 0, 0, 2012, 0x512e9887 -0, 0, 0, 0, 2012, 0xd478d55b -0, 0, 0, 0, 2012, 0xa94a9d93 -0, 0, 0, 0, 2012, 0xff73d812 -0, 0, 0, 0, 2012, 0xd3a6b9ef -0, 0, 0, 0, 2012, 0x7b4ebc1e -0, 0, 0, 0, 2012, 0xcc7bba1a -0, 0, 0, 0, 2012, 0x1aa7cd1a -0, 0, 0, 0, 2012, 0xd707c202 -0, 0, 0, 0, 2012, 0xcb6ac18b -0, 0, 0, 0, 2012, 0x1ccdcbd6 -0, 0, 0, 0, 2012, 0x700cb51e -0, 0, 0, 0, 2012, 0x27b6a3e7 -0, 0, 0, 0, 2012, 0x8570b8cd -0, 0, 0, 0, 2012, 0x22f2b2ed -0, 0, 0, 0, 2012, 0x75edb63e -0, 0, 0, 0, 2012, 0x8145b53f -0, 0, 0, 0, 2012, 0x15efb8bc -0, 0, 0, 0, 2012, 0x200bb5e6 -0, 0, 0, 0, 2012, 0xfa79b178 -0, 0, 0, 0, 2012, 0xbd39cdf4 -0, 0, 0, 0, 2012, 0x0970b0b2 -0, 0, 0, 0, 2012, 0x1acebe72 -0, 0, 0, 0, 2012, 0x1a26aa71 -0, 0, 0, 0, 2012, 0x8f71aa54 -0, 0, 0, 0, 2012, 0x0265c523 -0, 0, 0, 0, 2012, 0x2df0a53b -0, 0, 0, 0, 2012, 0x59a7a37a -0, 0, 0, 0, 2012, 0x9ad9acda -0, 0, 0, 0, 2012, 0x738cbc6f -0, 0, 0, 0, 2012, 0xc646a7ad -0, 0, 0, 0, 2012, 0x7f25c19b -0, 0, 0, 0, 2012, 0x1439bdb0 -0, 0, 0, 0, 2012, 0xa40cbef0 -0, 0, 0, 0, 2012, 0x9b09b99a -0, 0, 0, 0, 2012, 0x5ff0bbde -0, 0, 0, 0, 2012, 0x3981c2d6 -0, 0, 0, 0, 2012, 0xfa89b40d -0, 0, 0, 0, 2012, 0x12e9a7b9 -0, 0, 0, 0, 2012, 0xc5faaac3 -0, 0, 0, 0, 2012, 0xe12bc3a9 -0, 0, 0, 0, 2012, 0x9c57b8f3 -0, 0, 0, 0, 2012, 0x4fd4b6c0 -0, 0, 0, 0, 2012, 0xb72cca50 -0, 0, 0, 0, 2012, 0xb4d4cbbb -0, 0, 0, 0, 2012, 0x9399bfa1 -0, 0, 0, 0, 2012, 0x0abfb708 -0, 0, 0, 0, 2012, 0xd1d9acc0 -0, 0, 0, 0, 2012, 0x079ab5b2 -0, 0, 0, 0, 2012, 0x05a0be32 -0, 0, 0, 0, 2012, 0x445cc8db -0, 0, 0, 0, 2012, 0xf9a3aa71 -0, 0, 0, 0, 2012, 0xd2e29eac -0, 0, 0, 0, 2012, 0x391a9f20 -0, 0, 0, 0, 2012, 0x571eab4e -0, 0, 0, 0, 2012, 0x6962bc96 -0, 0, 0, 0, 2012, 0x2f04b495 -0, 0, 0, 0, 2012, 0x7b66bab7 -0, 0, 0, 0, 2012, 0xa718b8c9 -0, 0, 0, 0, 2012, 0xb069a54e -0, 0, 0, 0, 2012, 0xc052a1d2 -0, 0, 0, 0, 2012, 0x661ac62e -0, 0, 0, 0, 2012, 0xc4ebb529 -0, 0, 0, 0, 2012, 0xf998b251 -0, 0, 0, 0, 2012, 0x0ee8bffa -0, 0, 0, 0, 2012, 0x6e3fd984 -0, 0, 0, 0, 2012, 0x5825b63f -0, 0, 0, 0, 2012, 0x9c79c561 -0, 0, 0, 0, 2012, 0x3470beb7 -0, 0, 0, 0, 2012, 0x9135bd9d -0, 0, 0, 0, 2012, 0xd8e8bb7f -0, 0, 0, 0, 2012, 0x322ea448 -0, 0, 0, 0, 2012, 0xe974b3ab -0, 0, 0, 0, 2012, 0x4151c32d -0, 0, 0, 0, 2012, 0x2b05bf7d -0, 0, 0, 0, 2012, 0x4111c0d8 -0, 0, 0, 0, 2012, 0xff9ad574 -0, 0, 0, 0, 2012, 0xa55dced2 -0, 0, 0, 0, 2012, 0x11e6c0cb -0, 0, 0, 0, 2012, 0x2478b998 -0, 0, 0, 0, 2012, 0xdc8abb54 -0, 0, 0, 0, 2012, 0xe16da510 -0, 0, 0, 0, 2012, 0xfc18b3db -0, 0, 0, 0, 2012, 0x1426cd42 -0, 0, 0, 0, 2012, 0xb560a661 -0, 0, 0, 0, 2012, 0xc200aa4b -0, 0, 0, 0, 2012, 0xea00af2a -0, 0, 0, 0, 2012, 0x32bcbf84 -0, 0, 0, 0, 2012, 0x4c29cb2a -0, 0, 0, 0, 2012, 0xe8a2aabc -0, 0, 0, 0, 2012, 0x64bdb6cd -0, 0, 0, 0, 2012, 0x3a80adbc -0, 0, 0, 0, 2012, 0xa012b2c4 -0, 0, 0, 0, 2012, 0xac3ebce7 -0, 0, 0, 0, 2012, 0xfae1b2a7 -0, 0, 0, 0, 2012, 0x37b4ddae -0, 0, 0, 0, 2012, 0x8ff9bd55 -0, 0, 0, 0, 2012, 0x16f6abeb -0, 0, 0, 0, 2012, 0x5820badf -0, 0, 0, 0, 2012, 0x7183b45e -0, 0, 0, 0, 2012, 0xc0a6c826 -0, 0, 0, 0, 2012, 0x4c36bb02 -0, 0, 0, 0, 2012, 0xda46b854 -0, 0, 0, 0, 2012, 0xcc8accb6 -0, 0, 0, 0, 2012, 0xa6b2c3a2 -0, 0, 0, 0, 2012, 0x1c91cc00 -0, 0, 0, 0, 2012, 0xf33cd721 -0, 0, 0, 0, 2012, 0x7f86d2ed -0, 0, 0, 0, 2012, 0x9fdabb1d -0, 0, 0, 0, 2012, 0x33ebbbc4 -0, 0, 0, 0, 2012, 0x2741ba4f -0, 0, 0, 0, 2012, 0x0d0dd107 -0, 0, 0, 0, 2012, 0xf1d5b551 -0, 0, 0, 0, 2012, 0xf47dbebc -0, 0, 0, 0, 2012, 0xa955cea3 -0, 0, 0, 0, 2012, 0x51d6b407 -0, 0, 0, 0, 2012, 0xb7d3c2c0 -0, 0, 0, 0, 2012, 0xce3cc6ae -0, 0, 0, 0, 2012, 0x782cc184 -0, 0, 0, 0, 2012, 0xf4cec2af -0, 0, 0, 0, 2012, 0xa43eb295 -0, 0, 0, 0, 2012, 0xc74aa62d -0, 0, 0, 0, 2012, 0xf9dfc11f -0, 0, 0, 0, 2012, 0x3da1a319 -0, 0, 0, 0, 2012, 0xf613bd75 -0, 0, 0, 0, 2012, 0x10d9cda4 -0, 0, 0, 0, 2012, 0x08c9bcb3 -0, 0, 0, 0, 2012, 0x43b9d170 -0, 0, 0, 0, 2012, 0x1f0db940 -0, 0, 0, 0, 2012, 0x3c4ec614 -0, 0, 0, 0, 2012, 0xa94abaaa -0, 0, 0, 0, 2012, 0x2557a922 -0, 0, 0, 0, 2012, 0x4245c4b4 -0, 0, 0, 0, 2012, 0x0cb1b06f -0, 0, 0, 0, 2012, 0x778bbeab -0, 0, 0, 0, 2012, 0x5ce4ca3b -0, 0, 0, 0, 2012, 0xe70e9fd3 -0, 0, 0, 0, 2012, 0x28afbcbf -0, 0, 0, 0, 2012, 0xc41fb9b2 -0, 0, 0, 0, 2012, 0xd60cbfae -0, 0, 0, 0, 2012, 0x1087cb26 -0, 0, 0, 0, 2012, 0xc9face3b -0, 0, 0, 0, 2012, 0x7403b314 -0, 0, 0, 0, 2012, 0xe034ba97 -0, 0, 0, 0, 2012, 0x15dcbc67 -0, 0, 0, 0, 2012, 0x20d3bcff -0, 0, 0, 0, 2012, 0xc136a2ce -0, 0, 0, 0, 2012, 0x038bb025 -0, 0, 0, 0, 2012, 0xd655cf84 -0, 0, 0, 0, 2012, 0xcf54c656 -0, 0, 0, 0, 2012, 0x3c77bb0d -0, 0, 0, 0, 2012, 0xd765d7a7 -0, 0, 0, 0, 2012, 0x1a60b020 -0, 0, 0, 0, 2012, 0x83c8c2e9 -0, 0, 0, 0, 2012, 0x9b97c6e7 -0, 0, 0, 0, 2012, 0x3870ad63 -0, 0, 0, 0, 2012, 0x0e3ac67d -0, 0, 0, 0, 2012, 0xeb53c935 -0, 0, 0, 0, 2012, 0xeeb0c3e1 -0, 0, 0, 0, 2012, 0x9cb5bdb9 -0, 0, 0, 0, 2012, 0x64b1afec -0, 0, 0, 0, 2012, 0x57dcadbc -0, 0, 0, 0, 2012, 0xed76c5fd -0, 0, 0, 0, 2012, 0x0cb4cac5 -0, 0, 0, 0, 2012, 0xd30bbd06 -0, 0, 0, 0, 2012, 0xaee9c6c3 -0, 0, 0, 0, 2012, 0xe845c9b3 -0, 0, 0, 0, 2012, 0xc09cc7fc -0, 0, 0, 0, 2012, 0xfdebaacb -0, 0, 0, 0, 2012, 0x6f2db89f -0, 0, 0, 0, 2012, 0x7d89bee7 -0, 0, 0, 0, 2012, 0x8699b8be -0, 0, 0, 0, 2012, 0x57d6cc8a -0, 0, 0, 0, 2012, 0xcdbcd246 -0, 0, 0, 0, 2012, 0x9057b285 -0, 0, 0, 0, 2012, 0x2ac9cc87 -0, 0, 0, 0, 2012, 0xeb20c421 -0, 0, 0, 0, 2012, 0x4789d11f -0, 0, 0, 0, 2012, 0x55e7c9fe -0, 0, 0, 0, 2012, 0xd81cb4c6 -0, 0, 0, 0, 2012, 0x2af0a88e -0, 0, 0, 0, 2012, 0x7d96a4ee -0, 0, 0, 0, 2012, 0xff7cc3ea -0, 0, 0, 0, 2012, 0x2514d2a8 -0, 0, 0, 0, 2012, 0x7d2cccc3 -0, 0, 0, 0, 2012, 0x98dccbbf -0, 0, 0, 0, 2012, 0x55f2bd3e -0, 0, 0, 0, 2012, 0x0e58bbd7 -0, 0, 0, 0, 2012, 0x1520c45d -0, 0, 0, 0, 2012, 0x3c60cede -0, 0, 0, 0, 2012, 0xbfb2be6b -0, 0, 0, 0, 2012, 0xa839c2d5 -0, 0, 0, 0, 2012, 0x7713bdba -0, 0, 0, 0, 2012, 0xf16c9e95 -0, 0, 0, 0, 2012, 0x8e94caf1 -0, 0, 0, 0, 2012, 0x3915c673 -0, 0, 0, 0, 2012, 0x69afc76f -0, 0, 0, 0, 2012, 0x3ebec514 -0, 0, 0, 0, 2012, 0x70c5dd9b -0, 0, 0, 0, 2012, 0x6868b7d9 -0, 0, 0, 0, 2012, 0x9a31c801 -0, 0, 0, 0, 2012, 0x93c4b6ac -0, 0, 0, 0, 2012, 0xb1aaca39 -0, 0, 0, 0, 2012, 0x8f67b9ed -0, 0, 0, 0, 2012, 0x09adcf1f -0, 0, 0, 0, 2012, 0xe172cb3c -0, 0, 0, 0, 2012, 0x044bbdc5 -0, 0, 0, 0, 2012, 0x391cb3d9 -0, 0, 0, 0, 2012, 0x3bd1bc29 -0, 0, 0, 0, 2012, 0x8a78c5d2 -0, 0, 0, 0, 2012, 0xa46fce11 -0, 0, 0, 0, 2012, 0x4c13d9bc -0, 0, 0, 0, 2012, 0x7f47ce4f -0, 0, 0, 0, 2012, 0xa03ebcae -0, 0, 0, 0, 2012, 0xf6f2b2c8 -0, 0, 0, 0, 2012, 0x7995be2a -0, 0, 0, 0, 2012, 0x22d7b94a -0, 0, 0, 0, 2012, 0x07bcc06a -0, 0, 0, 0, 2012, 0x04adcb6d -0, 0, 0, 0, 2012, 0x4aecc135 -0, 0, 0, 0, 2012, 0x8442dc6a -0, 0, 0, 0, 2012, 0x9e67b826 -0, 0, 0, 0, 2012, 0xb1c4b235 -0, 0, 0, 0, 2012, 0x565ecaae -0, 0, 0, 0, 2012, 0x34a2c877 -0, 0, 0, 0, 2012, 0x815eb148 -0, 0, 0, 0, 2012, 0x354eb4ce -0, 0, 0, 0, 2012, 0xf74db8b1 -0, 0, 0, 0, 2012, 0x56f3b430 -0, 0, 0, 0, 2012, 0x39f9c72f -0, 0, 0, 0, 2012, 0x83d1bfde -0, 0, 0, 0, 2012, 0x2da1bf57 -0, 0, 0, 0, 2012, 0xd97fc933 -0, 0, 0, 0, 2012, 0x4b3edbfe -0, 0, 0, 0, 2012, 0xb975d346 -0, 0, 0, 0, 2012, 0x856ac304 -0, 0, 0, 0, 2012, 0xb38dba2e -0, 0, 0, 0, 2012, 0xbe14c822 -0, 0, 0, 0, 2012, 0xb848c927 -0, 0, 0, 0, 2012, 0x0a89c0e6 -0, 0, 0, 0, 2012, 0x44a3c3d5 -0, 0, 0, 0, 2012, 0x7af1c30c -0, 0, 0, 0, 2012, 0xe928b619 -0, 0, 0, 0, 2012, 0xc9aeb012 -0, 0, 0, 0, 2012, 0xae02cfde -0, 0, 0, 0, 2012, 0x0b42c3d9 -0, 0, 0, 0, 2012, 0xa5b7c1ed -0, 0, 0, 0, 2012, 0xd2dcbcdc -0, 0, 0, 0, 2012, 0x18cfbf55 -0, 0, 0, 0, 2012, 0x34f0c800 -0, 0, 0, 0, 2012, 0x2a80bdba -0, 0, 0, 0, 2012, 0x5ef2b3a7 -0, 0, 0, 0, 2012, 0x35a6ba33 -0, 0, 0, 0, 2012, 0x1088bbf5 -0, 0, 0, 0, 2012, 0xaec0bedf -0, 0, 0, 0, 2012, 0x769fb535 -0, 0, 0, 0, 2012, 0xfe11b979 -0, 0, 0, 0, 2012, 0xe856b37e -0, 0, 0, 0, 2012, 0x36c3cffd -0, 0, 0, 0, 2012, 0x4771db58 -0, 0, 0, 0, 2012, 0x5467d13e -0, 0, 0, 0, 2012, 0xb405c1b5 -0, 0, 0, 0, 2012, 0x3cbdc145 -0, 0, 0, 0, 2012, 0xbb9ccdd7 -0, 0, 0, 0, 2012, 0xac25ce9e -0, 0, 0, 0, 2012, 0x6d2ac82a -0, 0, 0, 0, 2012, 0x1661ba50 -0, 0, 0, 0, 2012, 0xbc7ac82a -0, 0, 0, 0, 2012, 0x020bb4de -0, 0, 0, 0, 2012, 0x4e10cb93 -0, 0, 0, 0, 2012, 0x3dabc15f -0, 0, 0, 0, 2012, 0x12acc64b -0, 0, 0, 0, 2012, 0x9cecb51a -0, 0, 0, 0, 2012, 0x959acb39 -0, 0, 0, 0, 2012, 0x3ee7c0e8 -0, 0, 0, 0, 2012, 0xde18c1df -0, 0, 0, 0, 2012, 0x3c72c3cd -0, 0, 0, 0, 2012, 0x1ac4bb5d -0, 0, 0, 0, 2012, 0xb155c741 -0, 0, 0, 0, 2012, 0x5069c8aa -0, 0, 0, 0, 2012, 0x610db0bc -0, 0, 0, 0, 2012, 0xb82bc329 -0, 0, 0, 0, 2012, 0x8bd4c522 -0, 0, 0, 0, 2012, 0xd44bb865 -0, 0, 0, 0, 2012, 0xb51ac7dc -0, 0, 0, 0, 2012, 0xfe2bc799 -0, 0, 0, 0, 2012, 0x8cd1bb53 -0, 0, 0, 0, 2012, 0xba13ca97 -0, 0, 0, 0, 2012, 0xf107bd51 -0, 0, 0, 0, 2012, 0xa04ece95 -0, 0, 0, 0, 2012, 0x4f4faa54 -0, 0, 0, 0, 2012, 0x5a74bfe1 -0, 0, 0, 0, 2012, 0xdafade5b -0, 0, 0, 0, 2012, 0x738fba51 -0, 0, 0, 0, 2012, 0xe7b2b78e -0, 0, 0, 0, 2012, 0x7685b6ce -0, 0, 0, 0, 2012, 0xae45bd8a -0, 0, 0, 0, 2012, 0xd52cc84e -0, 0, 0, 0, 2012, 0x04abd773 -0, 0, 0, 0, 2012, 0x2badb0ff -0, 0, 0, 0, 2012, 0x0eaec6b2 -0, 0, 0, 0, 2012, 0x7c1ec33f -0, 0, 0, 0, 2012, 0x8773b925 -0, 0, 0, 0, 2012, 0x40bbc36d -0, 0, 0, 0, 2012, 0x330bc288 -0, 0, 0, 0, 2012, 0x1659b6f5 -0, 0, 0, 0, 2012, 0x66eac162 -0, 0, 0, 0, 2012, 0xf3acdb3d -0, 0, 0, 0, 2012, 0x465abb87 -0, 0, 0, 0, 2012, 0xe8e9bc16 -0, 0, 0, 0, 2012, 0x71eebbd9 -0, 0, 0, 0, 2012, 0x1f59cb2a -0, 0, 0, 0, 2012, 0x53e3c9e7 -0, 0, 0, 0, 2012, 0xf410b939 -0, 0, 0, 0, 2012, 0xdb13d1b3 -0, 0, 0, 0, 2012, 0xcd26bf27 -0, 0, 0, 0, 2012, 0x707ecc9c -0, 0, 0, 0, 2012, 0x3483b6bf -0, 0, 0, 0, 2012, 0x4184d451 -0, 0, 0, 0, 2012, 0xcf6abfae -0, 0, 0, 0, 2012, 0x5c9eb4ca -0, 0, 0, 0, 2012, 0xf396be01 -0, 0, 0, 0, 2012, 0x06bfda38 -0, 0, 0, 0, 2012, 0x0e92bcf4 -0, 0, 0, 0, 2012, 0xaaa2b99d -0, 0, 0, 0, 2012, 0xf112a9a9 -0, 0, 0, 0, 2012, 0x2844bdf1 -0, 0, 0, 0, 2012, 0xb96baf39 -0, 0, 0, 0, 2012, 0xd4f2d157 -0, 0, 0, 0, 2012, 0x7c74b149 -0, 0, 0, 0, 2012, 0xbd43d5f2 -0, 0, 0, 0, 2012, 0xaa10b2ba -0, 0, 0, 0, 2012, 0x66e9b95f -0, 0, 0, 0, 2012, 0x6f01abef -0, 0, 0, 0, 2012, 0x1cb5c664 -0, 0, 0, 0, 2012, 0x5ee2afc5 -0, 0, 0, 0, 2012, 0xeb39d213 -0, 0, 0, 0, 2012, 0x1ffeaafc -0, 0, 0, 0, 2012, 0x6bb4d548 -0, 0, 0, 0, 2012, 0xa045b23a -0, 0, 0, 0, 2012, 0x17c3aa49 -0, 0, 0, 0, 2012, 0x2d47db7c -0, 0, 0, 0, 2012, 0x07ddc9ac -0, 0, 0, 0, 2012, 0xa386c99e -0, 0, 0, 0, 2012, 0x0e0bae8a -0, 0, 0, 0, 2012, 0x7d6fc419 -0, 0, 0, 0, 2012, 0x34a3c5a2 -0, 0, 0, 0, 2012, 0xda81c8e9 -0, 0, 0, 0, 2012, 0xde53bcd8 -0, 0, 0, 0, 2012, 0x372ac065 -0, 0, 0, 0, 2012, 0x6d07a95c -0, 0, 0, 0, 2012, 0x296eb47f -0, 0, 0, 0, 2012, 0x0f47be2a -0, 0, 0, 0, 2012, 0x389ebaf6 -0, 0, 0, 0, 2012, 0x9746ba3b -0, 0, 0, 0, 2012, 0x070e9aed -0, 0, 0, 0, 2012, 0xa4abc798 -0, 0, 0, 0, 2012, 0xe55cac7b -0, 0, 0, 0, 2012, 0x0c71ba45 -0, 0, 0, 0, 2012, 0x70fbb3c5 -0, 0, 0, 0, 2012, 0xa35ec30a -0, 0, 0, 0, 2012, 0xf30ab935 -0, 0, 0, 0, 2012, 0x2cbb9b99 -0, 0, 0, 0, 2012, 0x6606c1bf -0, 0, 0, 0, 2012, 0x41ccad5c -0, 0, 0, 0, 2012, 0x352fc002 -0, 0, 0, 0, 2012, 0x1763bd10 -0, 0, 0, 0, 2012, 0xb54bcae6 -0, 0, 0, 0, 2012, 0x7374ab92 -0, 0, 0, 0, 2012, 0x2895a99a -0, 0, 0, 0, 2012, 0x9f68b02f -0, 0, 0, 0, 2012, 0xdfabbb76 -0, 0, 0, 0, 2012, 0x764ea6c5 -0, 0, 0, 0, 2012, 0x4e83c5a5 -0, 0, 0, 0, 2012, 0xf0e8c76a -0, 0, 0, 0, 2012, 0xdc80b4ea -0, 0, 0, 0, 2012, 0xcc53b0a5 -0, 0, 0, 0, 2012, 0x7893bc7f -0, 0, 0, 0, 2012, 0x6965b355 -0, 0, 0, 0, 2012, 0x7f8fac00 -0, 0, 0, 0, 2012, 0x6c71c7b8 -0, 0, 0, 0, 2012, 0xa00ec367 -0, 0, 0, 0, 2012, 0x5f0fc50e -0, 0, 0, 0, 2012, 0x1bd2ad87 -0, 0, 0, 0, 2012, 0xd054ba2d -0, 0, 0, 0, 2012, 0xaf80a0d5 -0, 0, 0, 0, 2012, 0x2acac873 -0, 0, 0, 0, 2012, 0x260ca584 -0, 0, 0, 0, 2012, 0x4f98aa7c -0, 0, 0, 0, 2012, 0x0254aa36 -0, 0, 0, 0, 2012, 0xe3c7c33a -0, 0, 0, 0, 2012, 0x3b9ea70f -0, 0, 0, 0, 2012, 0xe829b7e6 -0, 0, 0, 0, 2012, 0x9317a8d1 -0, 0, 0, 0, 2012, 0x88b3a98f -0, 0, 0, 0, 2012, 0xa4a8c3bc -0, 0, 0, 0, 2012, 0x95c9a869 -0, 0, 0, 0, 2012, 0x7f889fed -0, 0, 0, 0, 2012, 0x5438c408 -0, 0, 0, 0, 2012, 0x3455a366 -0, 0, 0, 0, 2012, 0x5319b33d -0, 0, 0, 0, 2012, 0xb19dc4f0 -0, 0, 0, 0, 2012, 0xf080b109 -0, 0, 0, 0, 2012, 0xef83d8e7 -0, 0, 0, 0, 2012, 0x237ac69c -0, 0, 0, 0, 2012, 0xbb30b714 -0, 0, 0, 0, 2012, 0x8745ba54 -0, 0, 0, 0, 2012, 0x8588bd6c -0, 0, 0, 0, 2012, 0xc580bdde -0, 0, 0, 0, 2012, 0xb062baf1 -0, 0, 0, 0, 2012, 0xe014b082 -0, 0, 0, 0, 2012, 0x148bcb87 -0, 0, 0, 0, 2012, 0x554bc13d -0, 0, 0, 0, 2012, 0xc410c270 -0, 0, 0, 0, 2012, 0xb2c8b65b -0, 0, 0, 0, 2012, 0xa412b3f4 -0, 0, 0, 0, 2012, 0xbb52aa9a -0, 0, 0, 0, 2012, 0x4005b527 -0, 0, 0, 0, 2012, 0x8c5eb055 -0, 0, 0, 0, 2012, 0x8622c142 -0, 0, 0, 0, 2012, 0x05a3b861 -0, 0, 0, 0, 2012, 0x9f6dbb4d -0, 0, 0, 0, 2012, 0x033fb867 -0, 0, 0, 0, 2012, 0x243babd5 -0, 0, 0, 0, 2012, 0x8d6db83c -0, 0, 0, 0, 2012, 0x3923b829 -0, 0, 0, 0, 2012, 0x69b6b587 -0, 0, 0, 0, 2012, 0xdda8d018 -0, 0, 0, 0, 2012, 0x54b1b2a4 -0, 0, 0, 0, 2012, 0x380eb1af -0, 0, 0, 0, 2012, 0xec3cbdb4 -0, 0, 0, 0, 2012, 0x7ce9b4cf -0, 0, 0, 0, 2012, 0xcf6cb99b -0, 0, 0, 0, 2012, 0x7383ab97 -0, 0, 0, 0, 2012, 0xaa4cc068 -0, 0, 0, 0, 2012, 0x96d4c3db -0, 0, 0, 0, 2012, 0xab8cb84f -0, 0, 0, 0, 2012, 0x73dcacf9 -0, 0, 0, 0, 2012, 0xf61ca122 -0, 0, 0, 0, 2012, 0x9f1cbd5b -0, 0, 0, 0, 2012, 0x1f84aa3f -0, 0, 0, 0, 2012, 0xa003ad43 -0, 0, 0, 0, 2012, 0x6cffa4ef -0, 0, 0, 0, 2012, 0x29559e1e -0, 0, 0, 0, 2012, 0x7a79b059 -0, 0, 0, 0, 2012, 0xa1929c42 -0, 0, 0, 0, 2012, 0x52dead1c -0, 0, 0, 0, 2012, 0x8f31b9f5 -0, 0, 0, 0, 2012, 0xb8a899ec -0, 0, 0, 0, 2012, 0x7ca4b02d -0, 0, 0, 0, 2012, 0x2c92ae1b -0, 0, 0, 0, 2012, 0xe683a92f -0, 0, 0, 0, 2012, 0xe9d5abcf -0, 0, 0, 0, 2012, 0x757db377 -0, 0, 0, 0, 2012, 0xd4a8bbae -0, 0, 0, 0, 2012, 0xeea5c4ee -0, 0, 0, 0, 2012, 0xc37ca9a9 -0, 0, 0, 0, 2012, 0x8871bb51 -0, 0, 0, 0, 2012, 0x5dd8b3a2 -0, 0, 0, 0, 2012, 0xef0fae7f -0, 0, 0, 0, 2012, 0xe7ecb23e -0, 0, 0, 0, 2012, 0xc4f6d437 -0, 0, 0, 0, 2012, 0x0c74b81d -0, 0, 0, 0, 2012, 0xee68b1ee -0, 0, 0, 0, 2012, 0x46b4b4a8 -0, 0, 0, 0, 2012, 0x0526abca -0, 0, 0, 0, 2012, 0x7695ba55 -0, 0, 0, 0, 2012, 0xc7f5ad90 -0, 0, 0, 0, 2012, 0x0522b9bc -0, 0, 0, 0, 2012, 0x0eefc6ad -0, 0, 0, 0, 2012, 0x340dae16 -0, 0, 0, 0, 2012, 0xea42bdc0 -0, 0, 0, 0, 2012, 0xe047abb6 -0, 0, 0, 0, 2012, 0x6da5c14f -0, 0, 0, 0, 2012, 0x46d8c11d -0, 0, 0, 0, 2012, 0x8f4d9f2f -0, 0, 0, 0, 2012, 0x6d00d26c -0, 0, 0, 0, 2012, 0x87fc9d1b -0, 0, 0, 0, 2012, 0xbba5b763 -0, 0, 0, 0, 2012, 0xab58b853 -0, 0, 0, 0, 2012, 0x8180b863 -0, 0, 0, 0, 2012, 0x3684b3ba -0, 0, 0, 0, 2012, 0xf1a4a806 -0, 0, 0, 0, 2012, 0x2826b48c -0, 0, 0, 0, 2012, 0x1883af7f -0, 0, 0, 0, 2012, 0x44c5c37a -0, 0, 0, 0, 2012, 0xec33c3f1 -0, 0, 0, 0, 2012, 0xd67fb767 -0, 0, 0, 0, 2012, 0x03c2c219 -0, 0, 0, 0, 2012, 0x75a9b389 -0, 0, 0, 0, 2012, 0xe041ad88 -0, 0, 0, 0, 2012, 0x6bccb005 -0, 0, 0, 0, 2012, 0xd881c24a -0, 0, 0, 0, 2012, 0x7dd0c302 -0, 0, 0, 0, 2012, 0x2ba8a649 -0, 0, 0, 0, 2012, 0x63e19eab -0, 0, 0, 0, 2012, 0x1c0dafce -0, 0, 0, 0, 2012, 0xf266bf47 -0, 0, 0, 0, 2012, 0x11beb4b1 -0, 0, 0, 0, 2012, 0xc6f6b2b5 -0, 0, 0, 0, 2012, 0x15d4b4d0 -0, 0, 0, 0, 2012, 0x08bfa1e7 -0, 0, 0, 0, 2012, 0x18dbb7b5 -0, 0, 0, 0, 2012, 0xc279cc67 -0, 0, 0, 0, 2012, 0xd236bf28 -0, 0, 0, 0, 2012, 0xc9d1b196 -0, 0, 0, 0, 2012, 0xb605983e -0, 0, 0, 0, 2012, 0x8132c566 -0, 0, 0, 0, 2012, 0x6be4cd39 -0, 0, 0, 0, 2012, 0xce53c1f9 -0, 0, 0, 0, 2012, 0xe1efac0f -0, 0, 0, 0, 2012, 0x3d60a57a -0, 0, 0, 0, 2012, 0x1beda4b7 -0, 0, 0, 0, 2012, 0x34a4ac81 -0, 0, 0, 0, 2012, 0x30b0be4b -0, 0, 0, 0, 2012, 0xc7ceaf45 -0, 0, 0, 0, 2012, 0xade0b6ec -0, 0, 0, 0, 2012, 0xe00daf06 -0, 0, 0, 0, 2012, 0x04f79fe4 -0, 0, 0, 0, 2012, 0x8c59b7d9 -0, 0, 0, 0, 2012, 0x6f66b92a -0, 0, 0, 0, 2012, 0x9b08b2c0 -0, 0, 0, 0, 2012, 0xa8c1b5c1 -0, 0, 0, 0, 2012, 0xe3aac0b0 -0, 0, 0, 0, 2012, 0x1622bdaf -0, 0, 0, 0, 2012, 0x25e1a9ff -0, 0, 0, 0, 2012, 0x5577ad82 -0, 0, 0, 0, 2012, 0xfe16a49b -0, 0, 0, 0, 2012, 0xef7fc32a -0, 0, 0, 0, 2012, 0xfe30c35d -0, 0, 0, 0, 2012, 0x3adc9610 -0, 0, 0, 0, 2012, 0x36eeabdc -0, 0, 0, 0, 2012, 0xde3fb56c -0, 0, 0, 0, 2012, 0x5629bd82 -0, 0, 0, 0, 2012, 0xb099a61d -0, 0, 0, 0, 2012, 0x3013b106 -0, 0, 0, 0, 2012, 0xc359aef3 -0, 0, 0, 0, 2012, 0xec01b3e1 -0, 0, 0, 0, 2012, 0x6e8ac0b1 -0, 0, 0, 0, 2012, 0x41e8b82d -0, 0, 0, 0, 2012, 0x3a2fb38b -0, 0, 0, 0, 2012, 0x7025aac9 -0, 0, 0, 0, 2012, 0xbb0eb094 -0, 0, 0, 0, 2012, 0xdc06c156 -0, 0, 0, 0, 2012, 0x4007cea4 -0, 0, 0, 0, 2012, 0x102ebe03 -0, 0, 0, 0, 2012, 0x6e8faae7 -0, 0, 0, 0, 2012, 0xa357aa0c -0, 0, 0, 0, 2012, 0x07d2bf4d -0, 0, 0, 0, 2012, 0xfb71b338 -0, 0, 0, 0, 2012, 0xd5f1be84 -0, 0, 0, 0, 2012, 0x2a7cb554 -0, 0, 0, 0, 2012, 0xfb03b8c3 -0, 0, 0, 0, 2012, 0x2ff1ca87 -0, 0, 0, 0, 2012, 0xeef2b7f3 -0, 0, 0, 0, 2012, 0x9377b15f -0, 0, 0, 0, 2012, 0x370cb0c2 -0, 0, 0, 0, 2012, 0x5f78b118 -0, 0, 0, 0, 2012, 0x19afa87a -0, 0, 0, 0, 2012, 0xc717ab0d -0, 0, 0, 0, 2012, 0x3ca499f4 -0, 0, 0, 0, 2012, 0x9612b8e4 -0, 0, 0, 0, 2012, 0x32c0bb29 -0, 0, 0, 0, 2012, 0x7727beba -0, 0, 0, 0, 2012, 0x8b60a4cb -0, 0, 0, 0, 2012, 0xe899a9c8 -0, 0, 0, 0, 2012, 0x60f4b7fe -0, 0, 0, 0, 2012, 0x544f9ecb -0, 0, 0, 0, 2012, 0x34afcd71 -0, 0, 0, 0, 2012, 0x470eab55 -0, 0, 0, 0, 2012, 0xe4959f93 -0, 0, 0, 0, 2012, 0x69eeaf97 -0, 0, 0, 0, 2012, 0x0ec9aca3 -0, 0, 0, 0, 2012, 0x51e4b7f6 -0, 0, 0, 0, 2012, 0xf6c0a837 -0, 0, 0, 0, 2012, 0x3bdca59b -0, 0, 0, 0, 2012, 0x14c59dfc -0, 0, 0, 0, 2012, 0xa50ab23a -0, 0, 0, 0, 2012, 0x8832b6e2 -0, 0, 0, 0, 2012, 0x3d699d1b -0, 0, 0, 0, 2012, 0x751aa4b8 -0, 0, 0, 0, 2012, 0x59a9b98c -0, 0, 0, 0, 2012, 0xb67c98cb -0, 0, 0, 0, 2012, 0x0fd39ccd -0, 0, 0, 0, 2012, 0x9980d1e1 -0, 0, 0, 0, 2012, 0xffd9a716 -0, 0, 0, 0, 2012, 0x7d2fbed1 -0, 0, 0, 0, 2012, 0x76e6b042 -0, 0, 0, 0, 2012, 0xe027a232 -0, 0, 0, 0, 2012, 0x7c6ca5ce -0, 0, 0, 0, 2012, 0x5cf6bda4 -0, 0, 0, 0, 2012, 0x6075bd0d -0, 0, 0, 0, 2012, 0xedc4abe9 -0, 0, 0, 0, 2012, 0xb8f7cc26 -0, 0, 0, 0, 2012, 0x2cbbb500 -0, 0, 0, 0, 2012, 0x1c34b04d -0, 0, 0, 0, 2012, 0x5f18bea2 -0, 0, 0, 0, 2012, 0x94d0bb2b -0, 0, 0, 0, 2012, 0x6899b78e -0, 0, 0, 0, 2012, 0xc9aaa7a2 -0, 0, 0, 0, 2012, 0x298cbafa -0, 0, 0, 0, 2012, 0x89d9ac80 -0, 0, 0, 0, 2012, 0xc6ffa7e6 -0, 0, 0, 0, 2012, 0xdcf7caf9 -0, 0, 0, 0, 2012, 0x26cfb4ee -0, 0, 0, 0, 2012, 0xec70b09d -0, 0, 0, 0, 2012, 0x65dca50f -0, 0, 0, 0, 2012, 0xcdebc0b6 -0, 0, 0, 0, 2012, 0x9393a262 -0, 0, 0, 0, 2012, 0x34aab06d -0, 0, 0, 0, 2012, 0x4800a550 -0, 0, 0, 0, 2012, 0x4d9aadec -0, 0, 0, 0, 2012, 0x2cddabb6 -0, 0, 0, 0, 2012, 0x91a0c5b2 -0, 0, 0, 0, 2012, 0xd326bee1 -0, 0, 0, 0, 2012, 0xf76ab2d5 -0, 0, 0, 0, 2012, 0xcef99ade -0, 0, 0, 0, 2012, 0x950dc76f -0, 0, 0, 0, 2012, 0xb6aca7ad -0, 0, 0, 0, 2012, 0x1aacb71c -0, 0, 0, 0, 2012, 0x32389da0 -0, 0, 0, 0, 2012, 0x030cbcce -0, 0, 0, 0, 2012, 0x0ec4b0cb -0, 0, 0, 0, 2012, 0x6c0bb62e -0, 0, 0, 0, 2012, 0xfadbb20d -0, 0, 0, 0, 2012, 0x99c9c848 -0, 0, 0, 0, 2012, 0xe3e3b21a -0, 0, 0, 0, 2012, 0x88d9a50b -0, 0, 0, 0, 2012, 0xf4bbaf17 -0, 0, 0, 0, 2012, 0x49fea706 -0, 0, 0, 0, 2012, 0xafd0babf -0, 0, 0, 0, 2012, 0x8970a8f3 -0, 0, 0, 0, 2012, 0x9223a553 -0, 0, 0, 0, 2012, 0x6ec2b2f9 -0, 0, 0, 0, 2012, 0x7960b759 -0, 0, 0, 0, 2012, 0x852891bf -0, 0, 0, 0, 2012, 0x094ebbeb -0, 0, 0, 0, 2012, 0xf9bab418 -0, 0, 0, 0, 2012, 0x010eae8c -0, 0, 0, 0, 2012, 0x10baab3d -0, 0, 0, 0, 2012, 0x2564b13f -0, 0, 0, 0, 2012, 0xaec8ac22 -0, 0, 0, 0, 2012, 0xda0cbd4f -0, 0, 0, 0, 2012, 0x97e1c075 -0, 0, 0, 0, 2012, 0x6731aca5 -0, 0, 0, 0, 2012, 0x2c1db696 -0, 0, 0, 0, 2012, 0x8ff7abbf -0, 0, 0, 0, 2012, 0xf75ab3a2 -0, 0, 0, 0, 2012, 0x8683b824 -0, 0, 0, 0, 2012, 0x9668b354 -0, 0, 0, 0, 2012, 0x6e9aae04 -0, 0, 0, 0, 2012, 0xd8e9acd7 -0, 0, 0, 0, 2012, 0xa326c298 -0, 0, 0, 0, 2012, 0x6abcb409 -0, 0, 0, 0, 2012, 0x7eb3b549 -0, 0, 0, 0, 2012, 0xfc72ba6a -0, 0, 0, 0, 2012, 0xed73b2e6 -0, 0, 0, 0, 2012, 0x07a6b0a9 -0, 0, 0, 0, 2012, 0x10a4aec4 -0, 0, 0, 0, 2012, 0xaac9a650 -0, 0, 0, 0, 2012, 0x848b9869 -0, 0, 0, 0, 2012, 0x1ddaafd6 -0, 0, 0, 0, 2012, 0xe291aaec -0, 0, 0, 0, 2012, 0x8aa1aa4d -0, 0, 0, 0, 2012, 0x9b69b94c -0, 0, 0, 0, 2012, 0xe784bec0 -0, 0, 0, 0, 2012, 0x9305ba2d -0, 0, 0, 0, 2012, 0x5616bb81 -0, 0, 0, 0, 2012, 0xea0facca -0, 0, 0, 0, 2012, 0xe1b9991e -0, 0, 0, 0, 2012, 0xded8bd59 -0, 0, 0, 0, 2012, 0xe79fb0ee -0, 0, 0, 0, 2012, 0x1b8595a6 -0, 0, 0, 0, 2012, 0xb55ba336 -0, 0, 0, 0, 2012, 0xc552bc98 -0, 0, 0, 0, 2012, 0x2fe2c5ba -0, 0, 0, 0, 2012, 0xe18aa5a6 -0, 0, 0, 0, 2012, 0xaa9bae1c -0, 0, 0, 0, 2012, 0xd1ddb68d -0, 0, 0, 0, 2012, 0x95bfb203 -0, 0, 0, 0, 2012, 0xeacab8b9 -0, 0, 0, 0, 2012, 0x5bfcb117 -0, 0, 0, 0, 2012, 0x1a9fa91c -0, 0, 0, 0, 2012, 0xa285b180 -0, 0, 0, 0, 2012, 0xfd58a6e2 -0, 0, 0, 0, 2012, 0x394fc325 -0, 0, 0, 0, 2012, 0x0415a6aa -0, 0, 0, 0, 2012, 0xf75fa5e0 -0, 0, 0, 0, 2012, 0x115cd11b -0, 0, 0, 0, 2012, 0x6587b9e3 -0, 0, 0, 0, 2012, 0xce6bb7e6 -0, 0, 0, 0, 2012, 0xbaa2b409 -0, 0, 0, 0, 2012, 0x271bbb14 -0, 0, 0, 0, 2012, 0x4516c223 -0, 0, 0, 0, 2012, 0x4f6ab266 -0, 0, 0, 0, 2012, 0x244ba6fc -0, 0, 0, 0, 2012, 0x60e0ae4e -0, 0, 0, 0, 2012, 0xfc3cac80 -0, 0, 0, 0, 2012, 0x8465b287 -0, 0, 0, 0, 2012, 0xc683b070 -0, 0, 0, 0, 2012, 0x2901c8e7 -0, 0, 0, 0, 2012, 0x0622b1a1 -0, 0, 0, 0, 2012, 0xe002b34c -0, 0, 0, 0, 2012, 0xf4969e79 -0, 0, 0, 0, 2012, 0x871cc453 -0, 0, 0, 0, 2012, 0x9a7daaf3 -0, 0, 0, 0, 2012, 0xba92a60a -0, 0, 0, 0, 2012, 0xf464a0c4 -0, 0, 0, 0, 2012, 0x53bbb6cd -0, 0, 0, 0, 2012, 0xb58a9d2a -0, 0, 0, 0, 2012, 0x1e1fb830 -0, 0, 0, 0, 2012, 0xdc7eb93e -0, 0, 0, 0, 2012, 0xe6ceaaf9 -0, 0, 0, 0, 2012, 0x8c7ea35d -0, 0, 0, 0, 2012, 0x0b87ba04 -0, 0, 0, 0, 2012, 0xf516a700 -0, 0, 0, 0, 2012, 0xfaf19e13 -0, 0, 0, 0, 2012, 0x53cf9ed0 -0, 0, 0, 0, 2012, 0x2e25c2f9 -0, 0, 0, 0, 2012, 0x959aa1b8 -0, 0, 0, 0, 2012, 0x2a49a572 -0, 0, 0, 0, 2012, 0xf7a9b809 -0, 0, 0, 0, 2012, 0x44a9b879 -0, 0, 0, 0, 2012, 0xe428c0d4 -0, 0, 0, 0, 2012, 0xc258c2c6 -0, 0, 0, 0, 2012, 0xf7f3b794 -0, 0, 0, 0, 2012, 0xa8adbad9 -0, 0, 0, 0, 2012, 0xc2508e79 -0, 0, 0, 0, 2012, 0x1418ac76 -0, 0, 0, 0, 2012, 0xb28aadef -0, 0, 0, 0, 2012, 0xda17bd03 -0, 0, 0, 0, 2012, 0xa92ab852 -0, 0, 0, 0, 2012, 0xc3cbcfa4 -0, 0, 0, 0, 2012, 0xf716bb5e -0, 0, 0, 0, 2012, 0x6009a8af -0, 0, 0, 0, 2012, 0x9e69bc81 -0, 0, 0, 0, 2012, 0x3aafc8cf -0, 0, 0, 0, 2012, 0x03bccdab -0, 0, 0, 0, 2012, 0xfdceb2d9 -0, 0, 0, 0, 2012, 0x68f7afb8 -0, 0, 0, 0, 2012, 0xb7bab330 -0, 0, 0, 0, 2012, 0x4976b125 -0, 0, 0, 0, 2012, 0x7c86ae12 -0, 0, 0, 0, 2012, 0x4ce4ca54 -0, 0, 0, 0, 2012, 0xf1f7b892 -0, 0, 0, 0, 2012, 0xf958abb1 -0, 0, 0, 0, 2012, 0x047accd0 -0, 0, 0, 0, 2012, 0x34a1c49c -0, 0, 0, 0, 2012, 0x4b24a4ed -0, 0, 0, 0, 2012, 0xea31b1bc -0, 0, 0, 0, 2012, 0x8beaa3e3 -0, 0, 0, 0, 2012, 0x064caaf9 -0, 0, 0, 0, 2012, 0x56babf15 -0, 0, 0, 0, 2012, 0xd16fc6f4 -0, 0, 0, 0, 2012, 0x4ac2b78a -0, 0, 0, 0, 2012, 0xba3aa509 -0, 0, 0, 0, 2012, 0xc103b074 -0, 0, 0, 0, 2012, 0x464aba98 -0, 0, 0, 0, 2012, 0xaacac5a3 -0, 0, 0, 0, 2012, 0x9cecbcfa -0, 0, 0, 0, 2012, 0x8da0ab79 -0, 0, 0, 0, 2012, 0x85b2b023 -0, 0, 0, 0, 2012, 0x598abc91 -0, 0, 0, 0, 2012, 0x08c0a35c -0, 0, 0, 0, 2012, 0x30e4a7cf -0, 0, 0, 0, 2012, 0xf1e4a931 -0, 0, 0, 0, 2012, 0x8a4fb6c1 -0, 0, 0, 0, 2012, 0x126aac08 -0, 0, 0, 0, 2012, 0x537fa51b -0, 0, 0, 0, 2012, 0x1e54ac5a -0, 0, 0, 0, 2012, 0x7274bbd0 -0, 0, 0, 0, 2012, 0xd16bc2c2 -0, 0, 0, 0, 2012, 0x9236c1e3 -0, 0, 0, 0, 2012, 0x348aa7af -0, 0, 0, 0, 2012, 0xa020be5e -0, 0, 0, 0, 2012, 0x3cc5a4b8 -0, 0, 0, 0, 2012, 0x8b19b649 -0, 0, 0, 0, 2012, 0x554aa5ab -0, 0, 0, 0, 2012, 0x35d6ac35 -0, 0, 0, 0, 2012, 0x64dba435 -0, 0, 0, 0, 2012, 0x6001bae2 -0, 0, 0, 0, 2012, 0x9220b599 -0, 0, 0, 0, 2012, 0xa3fdb899 -0, 0, 0, 0, 2012, 0x19a5abf4 -0, 0, 0, 0, 2012, 0xd857b8cf -0, 0, 0, 0, 2012, 0x38d1b234 -0, 0, 0, 0, 2012, 0x69f4bfb8 -0, 0, 0, 0, 2012, 0xcc87a375 -0, 0, 0, 0, 2012, 0xc1cdd0c5 -0, 0, 0, 0, 2012, 0xba0ca3ee -0, 0, 0, 0, 2012, 0x4d20c397 -0, 0, 0, 0, 2012, 0x825c9636 -0, 0, 0, 0, 2012, 0x7aa4ae53 -0, 0, 0, 0, 2012, 0xe970ae78 -0, 0, 0, 0, 2012, 0x5fb2ba59 -0, 0, 0, 0, 2012, 0xcd90a953 -0, 0, 0, 0, 2012, 0xf573ac40 -0, 0, 0, 0, 2012, 0x324cbd77 -0, 0, 0, 0, 2012, 0xece0a73d -0, 0, 0, 0, 2012, 0x0dd1aefa -0, 0, 0, 0, 2012, 0xe338c866 -0, 0, 0, 0, 2012, 0xfe71bffc -0, 0, 0, 0, 2012, 0x61a5a810 -0, 0, 0, 0, 2012, 0x7c3ba074 -0, 0, 0, 0, 2012, 0x492f9d91 -0, 0, 0, 0, 2012, 0xa126a7b9 -0, 0, 0, 0, 2012, 0x7cf19a40 -0, 0, 0, 0, 2012, 0x1c2fbae6 -0, 0, 0, 0, 2012, 0x540accdf -0, 0, 0, 0, 2012, 0x5908a938 -0, 0, 0, 0, 2012, 0xe7f8b501 -0, 0, 0, 0, 2012, 0x03a8b53e -0, 0, 0, 0, 2012, 0xb4e3bdda -0, 0, 0, 0, 2012, 0x9e86abe1 -0, 0, 0, 0, 2012, 0x3234b98d -0, 0, 0, 0, 2012, 0x5caec781 -0, 0, 0, 0, 2012, 0x5c21a32e -0, 0, 0, 0, 2012, 0x8b72c112 -0, 0, 0, 0, 2012, 0x2ec2bac3 -0, 0, 0, 0, 2012, 0xd9c4adaa -0, 0, 0, 0, 2012, 0x2da1b496 -0, 0, 0, 0, 2012, 0x0a51b21e -0, 0, 0, 0, 2012, 0x6414ab0d -0, 0, 0, 0, 2012, 0x95c4b203 -0, 0, 0, 0, 2012, 0x98e0b4a2 -0, 0, 0, 0, 2012, 0x34369f5f -0, 0, 0, 0, 2012, 0x9dffa40c -0, 0, 0, 0, 2012, 0xf345b0e5 -0, 0, 0, 0, 2012, 0x6714bdbf -0, 0, 0, 0, 2012, 0xc276c3d1 -0, 0, 0, 0, 2012, 0xf199b475 -0, 0, 0, 0, 2012, 0x3395cf3b -0, 0, 0, 0, 2012, 0x4b52afb0 -0, 0, 0, 0, 2012, 0x3f74b217 -0, 0, 0, 0, 2012, 0xa25cad38 -0, 0, 0, 0, 2012, 0x3290a5b4 -0, 0, 0, 0, 2012, 0x2917b750 -0, 0, 0, 0, 2012, 0xeb3ec739 -0, 0, 0, 0, 2012, 0xbf9ea51d -0, 0, 0, 0, 2012, 0x98e2a0c1 -0, 0, 0, 0, 2012, 0xa39ba7f2 -0, 0, 0, 0, 2012, 0x6df7a05c -0, 0, 0, 0, 2012, 0x2c1bba28 -0, 0, 0, 0, 2012, 0x6099b1cd -0, 0, 0, 0, 2012, 0x9366b9f2 -0, 0, 0, 0, 2012, 0x95899570 -0, 0, 0, 0, 2012, 0x6234a0c8 -0, 0, 0, 0, 2012, 0xec2cbcfc -0, 0, 0, 0, 2012, 0x3ff7a9db -0, 0, 0, 0, 2012, 0x4e44bad7 -0, 0, 0, 0, 2012, 0x1dbbbc39 -0, 0, 0, 0, 2012, 0xf9df99be -0, 0, 0, 0, 2012, 0xa713b313 -0, 0, 0, 0, 2012, 0x8bbdbe51 -0, 0, 0, 0, 2012, 0x0d5bc786 -0, 0, 0, 0, 2012, 0x75d293f2 -0, 0, 0, 0, 2012, 0x4832b688 -0, 0, 0, 0, 2012, 0x71aba74c -0, 0, 0, 0, 2012, 0x04d5abf2 -0, 0, 0, 0, 2012, 0xaa8fbd98 -0, 0, 0, 0, 2012, 0xd93eb6d4 -0, 0, 0, 0, 2012, 0x8fb6b5a8 -0, 0, 0, 0, 2012, 0x779a92f5 -0, 0, 0, 0, 2012, 0x35c8ab3d -0, 0, 0, 0, 2012, 0x0017aaa5 -0, 0, 0, 0, 2012, 0xd6e7bafe -0, 0, 0, 0, 2012, 0xe358b423 -0, 0, 0, 0, 2012, 0x3f74bfba -0, 0, 0, 0, 2012, 0x0a5eb707 -0, 0, 0, 0, 2012, 0xedbfb0df -0, 0, 0, 0, 2012, 0x2e71a26f -0, 0, 0, 0, 2012, 0x214db1a8 -0, 0, 0, 0, 2012, 0xb632c275 -0, 0, 0, 0, 2012, 0xb597cf92 -0, 0, 0, 0, 2012, 0x18a8b508 -0, 0, 0, 0, 2012, 0x8267b4ff -0, 0, 0, 0, 2012, 0x5a9ab8d6 -0, 0, 0, 0, 2012, 0x2037a2b6 +0, 0, 0, 960, 2012, 0x671dc73a +0, 960, 960, 960, 2012, 0x7fd5b1d2 +0, 1920, 1920, 960, 2012, 0xbe7b9e5e +0, 2880, 2880, 960, 2012, 0x671dc73a +0, 3840, 3840, 960, 2012, 0x7fd5b1d2 +0, 4800, 4800, 960, 2012, 0xbe7b9e5e +0, 5760, 5760, 960, 2012, 0x671dc73a +0, 6720, 6720, 960, 2012, 0x7fd5b1d2 +0, 7680, 7680, 960, 2012, 0xbe7b9e5e +0, 8640, 8640, 960, 2012, 0x671dc73a +0, 9600, 9600, 960, 2012, 0x7fd5b1d2 +0, 10560, 10560, 960, 2012, 0xbe7b9e5e +0, 11520, 11520, 960, 2012, 0x671dc73a +0, 12480, 12480, 960, 2012, 0x7fd5b1d2 +0, 13440, 13440, 960, 2012, 0xbe7b9e5e +0, 14400, 14400, 960, 2012, 0x671dc73a +0, 15360, 15360, 960, 2012, 0x7fd5b1d2 +0, 16320, 16320, 960, 2012, 0xbe7b9e5e +0, 17280, 17280, 960, 2012, 0x671dc73a +0, 18240, 18240, 960, 2012, 0x7fd5b1d2 +0, 19200, 19200, 960, 2012, 0xbe7b9e5e +0, 20160, 20160, 960, 2012, 0x671dc73a +0, 21120, 21120, 960, 2012, 0x7fd5b1d2 +0, 22080, 22080, 960, 2012, 0xbe7b9e5e +0, 23040, 23040, 960, 2012, 0x671dc73a +0, 24000, 24000, 960, 2012, 0x7fd5b1d2 +0, 24960, 24960, 960, 2012, 0xbe7b9e5e +0, 25920, 25920, 960, 2012, 0x671dc73a +0, 26880, 26880, 960, 2012, 0x7fd5b1d2 +0, 27840, 27840, 960, 2012, 0xbe7b9e5e +0, 28800, 28800, 960, 2012, 0x671dc73a +0, 29760, 29760, 960, 2012, 0x7fd5b1d2 +0, 30720, 30720, 960, 2012, 0xbe7b9e5e +0, 31680, 31680, 960, 2012, 0x671dc73a +0, 32640, 32640, 960, 2012, 0x7fd5b1d2 +0, 33600, 33600, 960, 2012, 0xbe7b9e5e +0, 34560, 34560, 960, 2012, 0x671dc73a +0, 35520, 35520, 960, 2012, 0x7fd5b1d2 +0, 36480, 36480, 960, 2012, 0xbe7b9e5e +0, 37440, 37440, 960, 2012, 0x671dc73a +0, 38400, 38400, 960, 2012, 0x7fd5b1d2 +0, 39360, 39360, 960, 2012, 0xbe7b9e5e +0, 40320, 40320, 960, 2012, 0x671dc73a +0, 41280, 41280, 960, 2012, 0x7fd5b1d2 +0, 42240, 42240, 960, 2012, 0xbe7b9e5e +0, 43200, 43200, 960, 2012, 0x671dc73a +0, 44160, 44160, 960, 2012, 0x7fd5b1d2 +0, 45120, 45120, 960, 2012, 0xbe7b9e5e +0, 46080, 46080, 960, 2012, 0x671dc73a +0, 47040, 47040, 960, 2012, 0x7fd5b1d2 +0, 48000, 48000, 960, 2012, 0xbe7b9e5e +0, 48960, 48960, 960, 2012, 0x671dc73a +0, 49920, 49920, 960, 2012, 0x7fd5b1d2 +0, 50880, 50880, 960, 2012, 0xbe7b9e5e +0, 51840, 51840, 960, 2012, 0x671dc73a +0, 52800, 52800, 960, 2012, 0x7fd5b1d2 +0, 53760, 53760, 960, 2012, 0xbe7b9e5e +0, 54720, 54720, 960, 2012, 0x671dc73a +0, 55680, 55680, 960, 2012, 0x7fd5b1d2 +0, 56640, 56640, 960, 2012, 0xbe7b9e5e +0, 57600, 57600, 960, 2012, 0x671dc73a +0, 58560, 58560, 960, 2012, 0x7fd5b1d2 +0, 59520, 59520, 960, 2012, 0xbe7b9e5e +0, 60480, 60480, 960, 2012, 0x671dc73a +0, 61440, 61440, 960, 2012, 0x7fd5b1d2 +0, 62400, 62400, 960, 2012, 0xbe7b9e5e +0, 63360, 63360, 960, 2012, 0x671dc73a +0, 64320, 64320, 960, 2012, 0x7fd5b1d2 +0, 65280, 65280, 960, 2012, 0xbe7b9e5e +0, 66240, 66240, 960, 2012, 0x671dc73a +0, 67200, 67200, 960, 2012, 0x7fd5b1d2 +0, 68160, 68160, 960, 2012, 0xbe7b9e5e +0, 69120, 69120, 960, 2012, 0x671dc73a +0, 70080, 70080, 960, 2012, 0x7fd5b1d2 +0, 71040, 71040, 960, 2012, 0xbe7b9e5e +0, 72000, 72000, 960, 2012, 0x671dc73a +0, 72960, 72960, 960, 2012, 0x7fd5b1d2 +0, 73920, 73920, 960, 2012, 0xbe7b9e5e +0, 74880, 74880, 960, 2012, 0x671dc73a +0, 75840, 75840, 960, 2012, 0x7fd5b1d2 +0, 76800, 76800, 960, 2012, 0xbe7b9e5e +0, 77760, 77760, 960, 2012, 0x671dc73a +0, 78720, 78720, 960, 2012, 0x7fd5b1d2 +0, 79680, 79680, 960, 2012, 0xbe7b9e5e +0, 80640, 80640, 960, 2012, 0x671dc73a +0, 81600, 81600, 960, 2012, 0x7fd5b1d2 +0, 82560, 82560, 960, 2012, 0xbe7b9e5e +0, 83520, 83520, 960, 2012, 0x671dc73a +0, 84480, 84480, 960, 2012, 0x7fd5b1d2 +0, 85440, 85440, 960, 2012, 0xbe7b9e5e +0, 86400, 86400, 960, 2012, 0x671dc73a +0, 87360, 87360, 960, 2012, 0x7fd5b1d2 +0, 88320, 88320, 960, 2012, 0xbe7b9e5e +0, 89280, 89280, 960, 2012, 0x671dc73a +0, 90240, 90240, 960, 2012, 0x7fd5b1d2 +0, 91200, 91200, 960, 2012, 0xa9259df1 +0, 92160, 92160, 960, 2012, 0x3e8c2b92 +0, 93120, 93120, 960, 2012, 0x4876a9ff +0, 94080, 94080, 960, 2012, 0x7e469182 +0, 95040, 95040, 960, 2012, 0x10eba401 +0, 96000, 96000, 960, 2012, 0x51c68ed3 +0, 96960, 96960, 960, 2012, 0x3f52901b +0, 97920, 97920, 960, 2012, 0x7bebacce +0, 98880, 98880, 960, 2012, 0xcb94898d +0, 99840, 99840, 960, 2012, 0x14e3ae70 +0, 100800, 100800, 960, 2012, 0x016893cb +0, 101760, 101760, 960, 2012, 0x00739f0a +0, 102720, 102720, 960, 2012, 0x834aba41 +0, 103680, 103680, 960, 2012, 0x6a92ac08 +0, 104640, 104640, 960, 2012, 0x09eda257 +0, 105600, 105600, 960, 2012, 0x81449e3f +0, 106560, 106560, 960, 2012, 0xe6eb91d4 +0, 107520, 107520, 960, 2012, 0x51158c0e +0, 108480, 108480, 960, 2012, 0x84e4a013 +0, 109440, 109440, 960, 2012, 0x4c48a0e6 +0, 110400, 110400, 960, 2012, 0xf54c9811 +0, 111360, 111360, 960, 2012, 0x62778edb +0, 112320, 112320, 960, 2012, 0x7226a51b +0, 113280, 113280, 960, 2012, 0x44b9aad8 +0, 114240, 114240, 960, 2012, 0x8aa6b380 +0, 115200, 115200, 960, 2012, 0xc88c99e6 +0, 116160, 116160, 960, 2012, 0xed5e93e2 +0, 117120, 117120, 960, 2012, 0xeb0b9755 +0, 118080, 118080, 960, 2012, 0xe5ba8ca9 +0, 119040, 119040, 960, 2012, 0x2fef9bcf +0, 120000, 120000, 960, 2012, 0xf19c8749 +0, 120960, 120960, 960, 2012, 0x0feb94d0 +0, 121920, 121920, 960, 2012, 0x1f9194d1 +0, 122880, 122880, 960, 2012, 0x0cad9822 +0, 123840, 123840, 960, 2012, 0xe6f79152 +0, 124800, 124800, 960, 2012, 0x69e78955 +0, 125760, 125760, 960, 2012, 0x91dd8a1b +0, 126720, 126720, 960, 2012, 0x63fe8eea +0, 127680, 127680, 960, 2012, 0x8f6d90a2 +0, 128640, 128640, 960, 2012, 0xe3bf8626 +0, 129600, 129600, 960, 2012, 0xd08599db +0, 130560, 130560, 960, 2012, 0xf556a282 +0, 131520, 131520, 960, 2012, 0x7f8c8f90 +0, 132480, 132480, 960, 2012, 0xa04493b9 +0, 133440, 133440, 960, 2012, 0x21a19b3a +0, 134400, 134400, 960, 2012, 0x6ead9244 +0, 135360, 135360, 960, 2012, 0xe65290d7 +0, 136320, 136320, 960, 2012, 0x8ff58a8e +0, 137280, 137280, 960, 2012, 0x24ada603 +0, 138240, 138240, 960, 2012, 0x79cb85c7 +0, 139200, 139200, 960, 2012, 0x63c0ac54 +0, 140160, 140160, 960, 2012, 0x7f719f83 +0, 141120, 141120, 960, 2012, 0x2eb69654 +0, 142080, 142080, 960, 2012, 0xf5149bc0 +0, 143040, 143040, 960, 2012, 0xd0d6a414 +0, 144000, 144000, 960, 2012, 0x4f4a8ed3 +0, 144960, 144960, 960, 2012, 0x20888cb5 +0, 145920, 145920, 960, 2012, 0x13439c86 +0, 146880, 146880, 960, 2012, 0xc8fc98e1 +0, 147840, 147840, 960, 2012, 0x14689766 +0, 148800, 148800, 960, 2012, 0x830293e4 +0, 149760, 149760, 960, 2012, 0xdd5bb8ce +0, 150720, 150720, 960, 2012, 0x005ea280 +0, 151680, 151680, 960, 2012, 0x9b0581e2 +0, 152640, 152640, 960, 2012, 0x210f89b8 +0, 153600, 153600, 960, 2012, 0xb7c180bd +0, 154560, 154560, 960, 2012, 0xe53c85e4 +0, 155520, 155520, 960, 2012, 0x1f689207 +0, 156480, 156480, 960, 2012, 0x5653813b +0, 157440, 157440, 960, 2012, 0x1d278d66 +0, 158400, 158400, 960, 2012, 0xd94c9a83 +0, 159360, 159360, 960, 2012, 0x7af48548 +0, 160320, 160320, 960, 2012, 0x86209c99 +0, 161280, 161280, 960, 2012, 0x6e3b7fc9 +0, 162240, 162240, 960, 2012, 0x41c289e7 +0, 163200, 163200, 960, 2012, 0x8bea85db +0, 164160, 164160, 960, 2012, 0x45c98c39 +0, 165120, 165120, 960, 2012, 0xee098755 +0, 166080, 166080, 960, 2012, 0x485d9ec1 +0, 167040, 167040, 960, 2012, 0x78819023 +0, 168000, 168000, 960, 2012, 0xf43377bd +0, 168960, 168960, 960, 2012, 0x43fc9439 +0, 169920, 169920, 960, 2012, 0x045e9bf3 +0, 170880, 170880, 960, 2012, 0x0fc09f0c +0, 171840, 171840, 960, 2012, 0x7ba69bf5 +0, 172800, 172800, 960, 2012, 0x4aa7aaf0 +0, 173760, 173760, 960, 2012, 0x620c85bf +0, 174720, 174720, 960, 2012, 0xa6bb8a30 +0, 175680, 175680, 960, 2012, 0xfd10883c +0, 176640, 176640, 960, 2012, 0x32037e17 +0, 177600, 177600, 960, 2012, 0xb18c9e01 +0, 178560, 178560, 960, 2012, 0xd8206ee5 +0, 179520, 179520, 960, 2012, 0xdbc49136 +0, 180480, 180480, 960, 2012, 0x650a785d +0, 181440, 181440, 960, 2012, 0x9e107d61 +0, 182400, 182400, 960, 2012, 0xbf4eac50 +0, 183360, 183360, 960, 2012, 0x9d8f79b2 +0, 184320, 184320, 960, 2012, 0x252d8e8a +0, 185280, 185280, 960, 2012, 0x00af8fd6 +0, 186240, 186240, 960, 2012, 0x9e388d3b +0, 187200, 187200, 960, 2012, 0x75de7f56 +0, 188160, 188160, 960, 2012, 0xd502839c +0, 189120, 189120, 960, 2012, 0x66709e03 +0, 190080, 190080, 960, 2012, 0x3e0a96ba +0, 191040, 191040, 960, 2012, 0x0813ad4e +0, 192000, 192000, 960, 2012, 0x799c90c5 +0, 192960, 192960, 960, 2012, 0x98a18bed +0, 193920, 193920, 960, 2012, 0x8cd197d7 +0, 194880, 194880, 960, 2012, 0xf9ea8b22 +0, 195840, 195840, 960, 2012, 0x674f7cd2 +0, 196800, 196800, 960, 2012, 0xa5c39136 +0, 197760, 197760, 960, 2012, 0xe064ac30 +0, 198720, 198720, 960, 2012, 0x2af78c75 +0, 199680, 199680, 960, 2012, 0x43df9b19 +0, 200640, 200640, 960, 2012, 0x8d1a87d5 +0, 201600, 201600, 960, 2012, 0xd5be8d29 +0, 202560, 202560, 960, 2012, 0x43448bd4 +0, 203520, 203520, 960, 2012, 0xa128a30b +0, 204480, 204480, 960, 2012, 0x6fc29902 +0, 205440, 205440, 960, 2012, 0x5854a24b +0, 206400, 206400, 960, 2012, 0xb222958a +0, 207360, 207360, 960, 2012, 0xfca39cce +0, 208320, 208320, 960, 2012, 0xee0087f0 +0, 209280, 209280, 960, 2012, 0xd2d69b8c +0, 210240, 210240, 960, 2012, 0xe2308f8d +0, 211200, 211200, 960, 2012, 0x8dc4b09a +0, 212160, 212160, 960, 2012, 0x14489aef +0, 213120, 213120, 960, 2012, 0x900f9835 +0, 214080, 214080, 960, 2012, 0x0092a95f +0, 215040, 215040, 960, 2012, 0xfd90b1bf +0, 216000, 216000, 960, 2012, 0xb11ab5d5 +0, 216960, 216960, 960, 2012, 0xc802b908 +0, 217920, 217920, 960, 2012, 0xb12aa91e +0, 218880, 218880, 960, 2012, 0xd173c2a9 +0, 219840, 219840, 960, 2012, 0xaeafb887 +0, 220800, 220800, 960, 2012, 0xeb7eb0d7 +0, 221760, 221760, 960, 2012, 0x9afbc56a +0, 222720, 222720, 960, 2012, 0x2d78bc34 +0, 223680, 223680, 960, 2012, 0x6550aed1 +0, 224640, 224640, 960, 2012, 0xd514a55d +0, 225600, 225600, 960, 2012, 0x9058c263 +0, 226560, 226560, 960, 2012, 0xf819b66a +0, 227520, 227520, 960, 2012, 0x16a5c902 +0, 228480, 228480, 960, 2012, 0x602fc11b +0, 229440, 229440, 960, 2012, 0xe3c6b177 +0, 230400, 230400, 960, 2012, 0xacc4cd06 +0, 231360, 231360, 960, 2012, 0xeb96addb +0, 232320, 232320, 960, 2012, 0x1195cad3 +0, 233280, 233280, 960, 2012, 0x8e96ad7f +0, 234240, 234240, 960, 2012, 0x31e592b7 +0, 235200, 235200, 960, 2012, 0xa0c5ccf0 +0, 236160, 236160, 960, 2012, 0x6e77c92b +0, 237120, 237120, 960, 2012, 0xe87fa928 +0, 238080, 238080, 960, 2012, 0x4923bcdb +0, 239040, 239040, 960, 2012, 0x3260b452 +0, 240000, 240000, 960, 2012, 0x62beafa0 +0, 240960, 240960, 960, 2012, 0x5a6fc18a +0, 241920, 241920, 960, 2012, 0x9d05ae87 +0, 242880, 242880, 960, 2012, 0xb577a54e +0, 243840, 243840, 960, 2012, 0xd66bc5ef +0, 244800, 244800, 960, 2012, 0x40bec7bb +0, 245760, 245760, 960, 2012, 0xedd3a1b9 +0, 246720, 246720, 960, 2012, 0xf6f49f83 +0, 247680, 247680, 960, 2012, 0x316fb06d +0, 248640, 248640, 960, 2012, 0xc3f3a874 +0, 249600, 249600, 960, 2012, 0x3a96b3bd +0, 250560, 250560, 960, 2012, 0x825aba30 +0, 251520, 251520, 960, 2012, 0x5b58ce66 +0, 252480, 252480, 960, 2012, 0x412dc092 +0, 253440, 253440, 960, 2012, 0xcb47bfa3 +0, 254400, 254400, 960, 2012, 0xe025bb79 +0, 255360, 255360, 960, 2012, 0x0042ba53 +0, 256320, 256320, 960, 2012, 0x7e9bba1d +0, 257280, 257280, 960, 2012, 0x0058c99d +0, 258240, 258240, 960, 2012, 0x47d2b590 +0, 259200, 259200, 960, 2012, 0xdf4ba9c6 +0, 260160, 260160, 960, 2012, 0xe671987c +0, 261120, 261120, 960, 2012, 0x90dccc89 +0, 262080, 262080, 960, 2012, 0x012ccae9 +0, 263040, 263040, 960, 2012, 0x2eb5b83e +0, 264000, 264000, 960, 2012, 0x3fecb7f4 +0, 264960, 264960, 960, 2012, 0x7955a464 +0, 265920, 265920, 960, 2012, 0xfe9eb3c3 +0, 266880, 266880, 960, 2012, 0x7457c904 +0, 267840, 267840, 960, 2012, 0xd23ea69d +0, 268800, 268800, 960, 2012, 0xc497bf82 +0, 269760, 269760, 960, 2012, 0x15e5c241 +0, 270720, 270720, 960, 2012, 0x3dfea71f +0, 271680, 271680, 960, 2012, 0x1e59c9c0 +0, 272640, 272640, 960, 2012, 0x1a34b927 +0, 273600, 273600, 960, 2012, 0xbf42b430 +0, 274560, 274560, 960, 2012, 0xf084c29f +0, 275520, 275520, 960, 2012, 0x6443c44a +0, 276480, 276480, 960, 2012, 0x7985a4a5 +0, 277440, 277440, 960, 2012, 0x27add059 +0, 278400, 278400, 960, 2012, 0x7f1faea4 +0, 279360, 279360, 960, 2012, 0x8d9dc732 +0, 280320, 280320, 960, 2012, 0xf272c32e +0, 281280, 281280, 960, 2012, 0x4fa3ab11 +0, 282240, 282240, 960, 2012, 0x512e9887 +0, 283200, 283200, 960, 2012, 0xd478d55b +0, 284160, 284160, 960, 2012, 0xa94a9d93 +0, 285120, 285120, 960, 2012, 0xff73d812 +0, 286080, 286080, 960, 2012, 0xd3a6b9ef +0, 287040, 287040, 960, 2012, 0x7b4ebc1e +0, 288000, 288000, 960, 2012, 0xcc7bba1a +0, 288960, 288960, 960, 2012, 0x1aa7cd1a +0, 289920, 289920, 960, 2012, 0xd707c202 +0, 290880, 290880, 960, 2012, 0xcb6ac18b +0, 291840, 291840, 960, 2012, 0x1ccdcbd6 +0, 292800, 292800, 960, 2012, 0x700cb51e +0, 293760, 293760, 960, 2012, 0x27b6a3e7 +0, 294720, 294720, 960, 2012, 0x8570b8cd +0, 295680, 295680, 960, 2012, 0x22f2b2ed +0, 296640, 296640, 960, 2012, 0x75edb63e +0, 297600, 297600, 960, 2012, 0x8145b53f +0, 298560, 298560, 960, 2012, 0x15efb8bc +0, 299520, 299520, 960, 2012, 0x200bb5e6 +0, 300480, 300480, 960, 2012, 0xfa79b178 +0, 301440, 301440, 960, 2012, 0xbd39cdf4 +0, 302400, 302400, 960, 2012, 0x0970b0b2 +0, 303360, 303360, 960, 2012, 0x1acebe72 +0, 304320, 304320, 960, 2012, 0x1a26aa71 +0, 305280, 305280, 960, 2012, 0x8f71aa54 +0, 306240, 306240, 960, 2012, 0x0265c523 +0, 307200, 307200, 960, 2012, 0x2df0a53b +0, 308160, 308160, 960, 2012, 0x59a7a37a +0, 309120, 309120, 960, 2012, 0x9ad9acda +0, 310080, 310080, 960, 2012, 0x738cbc6f +0, 311040, 311040, 960, 2012, 0xc646a7ad +0, 312000, 312000, 960, 2012, 0x7f25c19b +0, 312960, 312960, 960, 2012, 0x1439bdb0 +0, 313920, 313920, 960, 2012, 0xa40cbef0 +0, 314880, 314880, 960, 2012, 0x9b09b99a +0, 315840, 315840, 960, 2012, 0x5ff0bbde +0, 316800, 316800, 960, 2012, 0x3981c2d6 +0, 317760, 317760, 960, 2012, 0xfa89b40d +0, 318720, 318720, 960, 2012, 0x12e9a7b9 +0, 319680, 319680, 960, 2012, 0xc5faaac3 +0, 320640, 320640, 960, 2012, 0xe12bc3a9 +0, 321600, 321600, 960, 2012, 0x9c57b8f3 +0, 322560, 322560, 960, 2012, 0x4fd4b6c0 +0, 323520, 323520, 960, 2012, 0xb72cca50 +0, 324480, 324480, 960, 2012, 0xb4d4cbbb +0, 325440, 325440, 960, 2012, 0x9399bfa1 +0, 326400, 326400, 960, 2012, 0x0abfb708 +0, 327360, 327360, 960, 2012, 0xd1d9acc0 +0, 328320, 328320, 960, 2012, 0x079ab5b2 +0, 329280, 329280, 960, 2012, 0x05a0be32 +0, 330240, 330240, 960, 2012, 0x445cc8db +0, 331200, 331200, 960, 2012, 0xf9a3aa71 +0, 332160, 332160, 960, 2012, 0xd2e29eac +0, 333120, 333120, 960, 2012, 0x391a9f20 +0, 334080, 334080, 960, 2012, 0x571eab4e +0, 335040, 335040, 960, 2012, 0x6962bc96 +0, 336000, 336000, 960, 2012, 0x2f04b495 +0, 336960, 336960, 960, 2012, 0x7b66bab7 +0, 337920, 337920, 960, 2012, 0xa718b8c9 +0, 338880, 338880, 960, 2012, 0xb069a54e +0, 339840, 339840, 960, 2012, 0xc052a1d2 +0, 340800, 340800, 960, 2012, 0x661ac62e +0, 341760, 341760, 960, 2012, 0xc4ebb529 +0, 342720, 342720, 960, 2012, 0xf998b251 +0, 343680, 343680, 960, 2012, 0x0ee8bffa +0, 344640, 344640, 960, 2012, 0x6e3fd984 +0, 345600, 345600, 960, 2012, 0x5825b63f +0, 346560, 346560, 960, 2012, 0x9c79c561 +0, 347520, 347520, 960, 2012, 0x3470beb7 +0, 348480, 348480, 960, 2012, 0x9135bd9d +0, 349440, 349440, 960, 2012, 0xd8e8bb7f +0, 350400, 350400, 960, 2012, 0x322ea448 +0, 351360, 351360, 960, 2012, 0xe974b3ab +0, 352320, 352320, 960, 2012, 0x4151c32d +0, 353280, 353280, 960, 2012, 0x2b05bf7d +0, 354240, 354240, 960, 2012, 0x4111c0d8 +0, 355200, 355200, 960, 2012, 0xff9ad574 +0, 356160, 356160, 960, 2012, 0xa55dced2 +0, 357120, 357120, 960, 2012, 0x11e6c0cb +0, 358080, 358080, 960, 2012, 0x2478b998 +0, 359040, 359040, 960, 2012, 0xdc8abb54 +0, 360000, 360000, 960, 2012, 0xe16da510 +0, 360960, 360960, 960, 2012, 0xfc18b3db +0, 361920, 361920, 960, 2012, 0x1426cd42 +0, 362880, 362880, 960, 2012, 0xb560a661 +0, 363840, 363840, 960, 2012, 0xc200aa4b +0, 364800, 364800, 960, 2012, 0xea00af2a +0, 365760, 365760, 960, 2012, 0x32bcbf84 +0, 366720, 366720, 960, 2012, 0x4c29cb2a +0, 367680, 367680, 960, 2012, 0xe8a2aabc +0, 368640, 368640, 960, 2012, 0x64bdb6cd +0, 369600, 369600, 960, 2012, 0x3a80adbc +0, 370560, 370560, 960, 2012, 0xa012b2c4 +0, 371520, 371520, 960, 2012, 0xac3ebce7 +0, 372480, 372480, 960, 2012, 0xfae1b2a7 +0, 373440, 373440, 960, 2012, 0x37b4ddae +0, 374400, 374400, 960, 2012, 0x8ff9bd55 +0, 375360, 375360, 960, 2012, 0x16f6abeb +0, 376320, 376320, 960, 2012, 0x5820badf +0, 377280, 377280, 960, 2012, 0x7183b45e +0, 378240, 378240, 960, 2012, 0xc0a6c826 +0, 379200, 379200, 960, 2012, 0x4c36bb02 +0, 380160, 380160, 960, 2012, 0xda46b854 +0, 381120, 381120, 960, 2012, 0xcc8accb6 +0, 382080, 382080, 960, 2012, 0xa6b2c3a2 +0, 383040, 383040, 960, 2012, 0x1c91cc00 +0, 384000, 384000, 960, 2012, 0xf33cd721 +0, 384960, 384960, 960, 2012, 0x7f86d2ed +0, 385920, 385920, 960, 2012, 0x9fdabb1d +0, 386880, 386880, 960, 2012, 0x33ebbbc4 +0, 387840, 387840, 960, 2012, 0x2741ba4f +0, 388800, 388800, 960, 2012, 0x0d0dd107 +0, 389760, 389760, 960, 2012, 0xf1d5b551 +0, 390720, 390720, 960, 2012, 0xf47dbebc +0, 391680, 391680, 960, 2012, 0xa955cea3 +0, 392640, 392640, 960, 2012, 0x51d6b407 +0, 393600, 393600, 960, 2012, 0xb7d3c2c0 +0, 394560, 394560, 960, 2012, 0xce3cc6ae +0, 395520, 395520, 960, 2012, 0x782cc184 +0, 396480, 396480, 960, 2012, 0xf4cec2af +0, 397440, 397440, 960, 2012, 0xa43eb295 +0, 398400, 398400, 960, 2012, 0xc74aa62d +0, 399360, 399360, 960, 2012, 0xf9dfc11f +0, 400320, 400320, 960, 2012, 0x3da1a319 +0, 401280, 401280, 960, 2012, 0xf613bd75 +0, 402240, 402240, 960, 2012, 0x10d9cda4 +0, 403200, 403200, 960, 2012, 0x08c9bcb3 +0, 404160, 404160, 960, 2012, 0x43b9d170 +0, 405120, 405120, 960, 2012, 0x1f0db940 +0, 406080, 406080, 960, 2012, 0x3c4ec614 +0, 407040, 407040, 960, 2012, 0xa94abaaa +0, 408000, 408000, 960, 2012, 0x2557a922 +0, 408960, 408960, 960, 2012, 0x4245c4b4 +0, 409920, 409920, 960, 2012, 0x0cb1b06f +0, 410880, 410880, 960, 2012, 0x778bbeab +0, 411840, 411840, 960, 2012, 0x5ce4ca3b +0, 412800, 412800, 960, 2012, 0xe70e9fd3 +0, 413760, 413760, 960, 2012, 0x28afbcbf +0, 414720, 414720, 960, 2012, 0xc41fb9b2 +0, 415680, 415680, 960, 2012, 0xd60cbfae +0, 416640, 416640, 960, 2012, 0x1087cb26 +0, 417600, 417600, 960, 2012, 0xc9face3b +0, 418560, 418560, 960, 2012, 0x7403b314 +0, 419520, 419520, 960, 2012, 0xe034ba97 +0, 420480, 420480, 960, 2012, 0x15dcbc67 +0, 421440, 421440, 960, 2012, 0x20d3bcff +0, 422400, 422400, 960, 2012, 0xc136a2ce +0, 423360, 423360, 960, 2012, 0x038bb025 +0, 424320, 424320, 960, 2012, 0xd655cf84 +0, 425280, 425280, 960, 2012, 0xcf54c656 +0, 426240, 426240, 960, 2012, 0x3c77bb0d +0, 427200, 427200, 960, 2012, 0xd765d7a7 +0, 428160, 428160, 960, 2012, 0x1a60b020 +0, 429120, 429120, 960, 2012, 0x83c8c2e9 +0, 430080, 430080, 960, 2012, 0x9b97c6e7 +0, 431040, 431040, 960, 2012, 0x3870ad63 +0, 432000, 432000, 960, 2012, 0x0e3ac67d +0, 432960, 432960, 960, 2012, 0xeb53c935 +0, 433920, 433920, 960, 2012, 0xeeb0c3e1 +0, 434880, 434880, 960, 2012, 0x9cb5bdb9 +0, 435840, 435840, 960, 2012, 0x64b1afec +0, 436800, 436800, 960, 2012, 0x57dcadbc +0, 437760, 437760, 960, 2012, 0xed76c5fd +0, 438720, 438720, 960, 2012, 0x0cb4cac5 +0, 439680, 439680, 960, 2012, 0xd30bbd06 +0, 440640, 440640, 960, 2012, 0xaee9c6c3 +0, 441600, 441600, 960, 2012, 0xe845c9b3 +0, 442560, 442560, 960, 2012, 0xc09cc7fc +0, 443520, 443520, 960, 2012, 0xfdebaacb +0, 444480, 444480, 960, 2012, 0x6f2db89f +0, 445440, 445440, 960, 2012, 0x7d89bee7 +0, 446400, 446400, 960, 2012, 0x8699b8be +0, 447360, 447360, 960, 2012, 0x57d6cc8a +0, 448320, 448320, 960, 2012, 0xcdbcd246 +0, 449280, 449280, 960, 2012, 0x9057b285 +0, 450240, 450240, 960, 2012, 0x2ac9cc87 +0, 451200, 451200, 960, 2012, 0xeb20c421 +0, 452160, 452160, 960, 2012, 0x4789d11f +0, 453120, 453120, 960, 2012, 0x55e7c9fe +0, 454080, 454080, 960, 2012, 0xd81cb4c6 +0, 455040, 455040, 960, 2012, 0x2af0a88e +0, 456000, 456000, 960, 2012, 0x7d96a4ee +0, 456960, 456960, 960, 2012, 0xff7cc3ea +0, 457920, 457920, 960, 2012, 0x2514d2a8 +0, 458880, 458880, 960, 2012, 0x7d2cccc3 +0, 459840, 459840, 960, 2012, 0x98dccbbf +0, 460800, 460800, 960, 2012, 0x55f2bd3e +0, 461760, 461760, 960, 2012, 0x0e58bbd7 +0, 462720, 462720, 960, 2012, 0x1520c45d +0, 463680, 463680, 960, 2012, 0x3c60cede +0, 464640, 464640, 960, 2012, 0xbfb2be6b +0, 465600, 465600, 960, 2012, 0xa839c2d5 +0, 466560, 466560, 960, 2012, 0x7713bdba +0, 467520, 467520, 960, 2012, 0xf16c9e95 +0, 468480, 468480, 960, 2012, 0x8e94caf1 +0, 469440, 469440, 960, 2012, 0x3915c673 +0, 470400, 470400, 960, 2012, 0x69afc76f +0, 471360, 471360, 960, 2012, 0x3ebec514 +0, 472320, 472320, 960, 2012, 0x70c5dd9b +0, 473280, 473280, 960, 2012, 0x6868b7d9 +0, 474240, 474240, 960, 2012, 0x9a31c801 +0, 475200, 475200, 960, 2012, 0x93c4b6ac +0, 476160, 476160, 960, 2012, 0xb1aaca39 +0, 477120, 477120, 960, 2012, 0x8f67b9ed +0, 478080, 478080, 960, 2012, 0x09adcf1f +0, 479040, 479040, 960, 2012, 0xe172cb3c +0, 480000, 480000, 960, 2012, 0x044bbdc5 +0, 480960, 480960, 960, 2012, 0x391cb3d9 +0, 481920, 481920, 960, 2012, 0x3bd1bc29 +0, 482880, 482880, 960, 2012, 0x8a78c5d2 +0, 483840, 483840, 960, 2012, 0xa46fce11 +0, 484800, 484800, 960, 2012, 0x4c13d9bc +0, 485760, 485760, 960, 2012, 0x7f47ce4f +0, 486720, 486720, 960, 2012, 0xa03ebcae +0, 487680, 487680, 960, 2012, 0xf6f2b2c8 +0, 488640, 488640, 960, 2012, 0x7995be2a +0, 489600, 489600, 960, 2012, 0x22d7b94a +0, 490560, 490560, 960, 2012, 0x07bcc06a +0, 491520, 491520, 960, 2012, 0x04adcb6d +0, 492480, 492480, 960, 2012, 0x4aecc135 +0, 493440, 493440, 960, 2012, 0x8442dc6a +0, 494400, 494400, 960, 2012, 0x9e67b826 +0, 495360, 495360, 960, 2012, 0xb1c4b235 +0, 496320, 496320, 960, 2012, 0x565ecaae +0, 497280, 497280, 960, 2012, 0x34a2c877 +0, 498240, 498240, 960, 2012, 0x815eb148 +0, 499200, 499200, 960, 2012, 0x354eb4ce +0, 500160, 500160, 960, 2012, 0xf74db8b1 +0, 501120, 501120, 960, 2012, 0x56f3b430 +0, 502080, 502080, 960, 2012, 0x39f9c72f +0, 503040, 503040, 960, 2012, 0x83d1bfde +0, 504000, 504000, 960, 2012, 0x2da1bf57 +0, 504960, 504960, 960, 2012, 0xd97fc933 +0, 505920, 505920, 960, 2012, 0x4b3edbfe +0, 506880, 506880, 960, 2012, 0xb975d346 +0, 507840, 507840, 960, 2012, 0x856ac304 +0, 508800, 508800, 960, 2012, 0xb38dba2e +0, 509760, 509760, 960, 2012, 0xbe14c822 +0, 510720, 510720, 960, 2012, 0xb848c927 +0, 511680, 511680, 960, 2012, 0x0a89c0e6 +0, 512640, 512640, 960, 2012, 0x44a3c3d5 +0, 513600, 513600, 960, 2012, 0x7af1c30c +0, 514560, 514560, 960, 2012, 0xe928b619 +0, 515520, 515520, 960, 2012, 0xc9aeb012 +0, 516480, 516480, 960, 2012, 0xae02cfde +0, 517440, 517440, 960, 2012, 0x0b42c3d9 +0, 518400, 518400, 960, 2012, 0xa5b7c1ed +0, 519360, 519360, 960, 2012, 0xd2dcbcdc +0, 520320, 520320, 960, 2012, 0x18cfbf55 +0, 521280, 521280, 960, 2012, 0x34f0c800 +0, 522240, 522240, 960, 2012, 0x2a80bdba +0, 523200, 523200, 960, 2012, 0x5ef2b3a7 +0, 524160, 524160, 960, 2012, 0x35a6ba33 +0, 525120, 525120, 960, 2012, 0x1088bbf5 +0, 526080, 526080, 960, 2012, 0xaec0bedf +0, 527040, 527040, 960, 2012, 0x769fb535 +0, 528000, 528000, 960, 2012, 0xfe11b979 +0, 528960, 528960, 960, 2012, 0xe856b37e +0, 529920, 529920, 960, 2012, 0x36c3cffd +0, 530880, 530880, 960, 2012, 0x4771db58 +0, 531840, 531840, 960, 2012, 0x5467d13e +0, 532800, 532800, 960, 2012, 0xb405c1b5 +0, 533760, 533760, 960, 2012, 0x3cbdc145 +0, 534720, 534720, 960, 2012, 0xbb9ccdd7 +0, 535680, 535680, 960, 2012, 0xac25ce9e +0, 536640, 536640, 960, 2012, 0x6d2ac82a +0, 537600, 537600, 960, 2012, 0x1661ba50 +0, 538560, 538560, 960, 2012, 0xbc7ac82a +0, 539520, 539520, 960, 2012, 0x020bb4de +0, 540480, 540480, 960, 2012, 0x4e10cb93 +0, 541440, 541440, 960, 2012, 0x3dabc15f +0, 542400, 542400, 960, 2012, 0x12acc64b +0, 543360, 543360, 960, 2012, 0x9cecb51a +0, 544320, 544320, 960, 2012, 0x959acb39 +0, 545280, 545280, 960, 2012, 0x3ee7c0e8 +0, 546240, 546240, 960, 2012, 0xde18c1df +0, 547200, 547200, 960, 2012, 0x3c72c3cd +0, 548160, 548160, 960, 2012, 0x1ac4bb5d +0, 549120, 549120, 960, 2012, 0xb155c741 +0, 550080, 550080, 960, 2012, 0x5069c8aa +0, 551040, 551040, 960, 2012, 0x610db0bc +0, 552000, 552000, 960, 2012, 0xb82bc329 +0, 552960, 552960, 960, 2012, 0x8bd4c522 +0, 553920, 553920, 960, 2012, 0xd44bb865 +0, 554880, 554880, 960, 2012, 0xb51ac7dc +0, 555840, 555840, 960, 2012, 0xfe2bc799 +0, 556800, 556800, 960, 2012, 0x8cd1bb53 +0, 557760, 557760, 960, 2012, 0xba13ca97 +0, 558720, 558720, 960, 2012, 0xf107bd51 +0, 559680, 559680, 960, 2012, 0xa04ece95 +0, 560640, 560640, 960, 2012, 0x4f4faa54 +0, 561600, 561600, 960, 2012, 0x5a74bfe1 +0, 562560, 562560, 960, 2012, 0xdafade5b +0, 563520, 563520, 960, 2012, 0x738fba51 +0, 564480, 564480, 960, 2012, 0xe7b2b78e +0, 565440, 565440, 960, 2012, 0x7685b6ce +0, 566400, 566400, 960, 2012, 0xae45bd8a +0, 567360, 567360, 960, 2012, 0xd52cc84e +0, 568320, 568320, 960, 2012, 0x04abd773 +0, 569280, 569280, 960, 2012, 0x2badb0ff +0, 570240, 570240, 960, 2012, 0x0eaec6b2 +0, 571200, 571200, 960, 2012, 0x7c1ec33f +0, 572160, 572160, 960, 2012, 0x8773b925 +0, 573120, 573120, 960, 2012, 0x40bbc36d +0, 574080, 574080, 960, 2012, 0x330bc288 +0, 575040, 575040, 960, 2012, 0x1659b6f5 +0, 576000, 576000, 960, 2012, 0x66eac162 +0, 576960, 576960, 960, 2012, 0xf3acdb3d +0, 577920, 577920, 960, 2012, 0x465abb87 +0, 578880, 578880, 960, 2012, 0xe8e9bc16 +0, 579840, 579840, 960, 2012, 0x71eebbd9 +0, 580800, 580800, 960, 2012, 0x1f59cb2a +0, 581760, 581760, 960, 2012, 0x53e3c9e7 +0, 582720, 582720, 960, 2012, 0xf410b939 +0, 583680, 583680, 960, 2012, 0xdb13d1b3 +0, 584640, 584640, 960, 2012, 0xcd26bf27 +0, 585600, 585600, 960, 2012, 0x707ecc9c +0, 586560, 586560, 960, 2012, 0x3483b6bf +0, 587520, 587520, 960, 2012, 0x4184d451 +0, 588480, 588480, 960, 2012, 0xcf6abfae +0, 589440, 589440, 960, 2012, 0x5c9eb4ca +0, 590400, 590400, 960, 2012, 0xf396be01 +0, 591360, 591360, 960, 2012, 0x06bfda38 +0, 592320, 592320, 960, 2012, 0x0e92bcf4 +0, 593280, 593280, 960, 2012, 0xaaa2b99d +0, 594240, 594240, 960, 2012, 0xf112a9a9 +0, 595200, 595200, 960, 2012, 0x2844bdf1 +0, 596160, 596160, 960, 2012, 0xb96baf39 +0, 597120, 597120, 960, 2012, 0xd4f2d157 +0, 598080, 598080, 960, 2012, 0x7c74b149 +0, 599040, 599040, 960, 2012, 0xbd43d5f2 +0, 600000, 600000, 960, 2012, 0xaa10b2ba +0, 600960, 600960, 960, 2012, 0x66e9b95f +0, 601920, 601920, 960, 2012, 0x6f01abef +0, 602880, 602880, 960, 2012, 0x1cb5c664 +0, 603840, 603840, 960, 2012, 0x5ee2afc5 +0, 604800, 604800, 960, 2012, 0xeb39d213 +0, 605760, 605760, 960, 2012, 0x1ffeaafc +0, 606720, 606720, 960, 2012, 0x6bb4d548 +0, 607680, 607680, 960, 2012, 0xa045b23a +0, 608640, 608640, 960, 2012, 0x17c3aa49 +0, 609600, 609600, 960, 2012, 0x2d47db7c +0, 610560, 610560, 960, 2012, 0x07ddc9ac +0, 611520, 611520, 960, 2012, 0xa386c99e +0, 612480, 612480, 960, 2012, 0x0e0bae8a +0, 613440, 613440, 960, 2012, 0x7d6fc419 +0, 614400, 614400, 960, 2012, 0x34a3c5a2 +0, 615360, 615360, 960, 2012, 0xda81c8e9 +0, 616320, 616320, 960, 2012, 0xde53bcd8 +0, 617280, 617280, 960, 2012, 0x372ac065 +0, 618240, 618240, 960, 2012, 0x6d07a95c +0, 619200, 619200, 960, 2012, 0x296eb47f +0, 620160, 620160, 960, 2012, 0x0f47be2a +0, 621120, 621120, 960, 2012, 0x389ebaf6 +0, 622080, 622080, 960, 2012, 0x9746ba3b +0, 623040, 623040, 960, 2012, 0x070e9aed +0, 624000, 624000, 960, 2012, 0xa4abc798 +0, 624960, 624960, 960, 2012, 0xe55cac7b +0, 625920, 625920, 960, 2012, 0x0c71ba45 +0, 626880, 626880, 960, 2012, 0x70fbb3c5 +0, 627840, 627840, 960, 2012, 0xa35ec30a +0, 628800, 628800, 960, 2012, 0xf30ab935 +0, 629760, 629760, 960, 2012, 0x2cbb9b99 +0, 630720, 630720, 960, 2012, 0x6606c1bf +0, 631680, 631680, 960, 2012, 0x41ccad5c +0, 632640, 632640, 960, 2012, 0x352fc002 +0, 633600, 633600, 960, 2012, 0x1763bd10 +0, 634560, 634560, 960, 2012, 0xb54bcae6 +0, 635520, 635520, 960, 2012, 0x7374ab92 +0, 636480, 636480, 960, 2012, 0x2895a99a +0, 637440, 637440, 960, 2012, 0x9f68b02f +0, 638400, 638400, 960, 2012, 0xdfabbb76 +0, 639360, 639360, 960, 2012, 0x764ea6c5 +0, 640320, 640320, 960, 2012, 0x4e83c5a5 +0, 641280, 641280, 960, 2012, 0xf0e8c76a +0, 642240, 642240, 960, 2012, 0xdc80b4ea +0, 643200, 643200, 960, 2012, 0xcc53b0a5 +0, 644160, 644160, 960, 2012, 0x7893bc7f +0, 645120, 645120, 960, 2012, 0x6965b355 +0, 646080, 646080, 960, 2012, 0x7f8fac00 +0, 647040, 647040, 960, 2012, 0x6c71c7b8 +0, 648000, 648000, 960, 2012, 0xa00ec367 +0, 648960, 648960, 960, 2012, 0x5f0fc50e +0, 649920, 649920, 960, 2012, 0x1bd2ad87 +0, 650880, 650880, 960, 2012, 0xd054ba2d +0, 651840, 651840, 960, 2012, 0xaf80a0d5 +0, 652800, 652800, 960, 2012, 0x2acac873 +0, 653760, 653760, 960, 2012, 0x260ca584 +0, 654720, 654720, 960, 2012, 0x4f98aa7c +0, 655680, 655680, 960, 2012, 0x0254aa36 +0, 656640, 656640, 960, 2012, 0xe3c7c33a +0, 657600, 657600, 960, 2012, 0x3b9ea70f +0, 658560, 658560, 960, 2012, 0xe829b7e6 +0, 659520, 659520, 960, 2012, 0x9317a8d1 +0, 660480, 660480, 960, 2012, 0x88b3a98f +0, 661440, 661440, 960, 2012, 0xa4a8c3bc +0, 662400, 662400, 960, 2012, 0x95c9a869 +0, 663360, 663360, 960, 2012, 0x7f889fed +0, 664320, 664320, 960, 2012, 0x5438c408 +0, 665280, 665280, 960, 2012, 0x3455a366 +0, 666240, 666240, 960, 2012, 0x5319b33d +0, 667200, 667200, 960, 2012, 0xb19dc4f0 +0, 668160, 668160, 960, 2012, 0xf080b109 +0, 669120, 669120, 960, 2012, 0xef83d8e7 +0, 670080, 670080, 960, 2012, 0x237ac69c +0, 671040, 671040, 960, 2012, 0xbb30b714 +0, 672000, 672000, 960, 2012, 0x8745ba54 +0, 672960, 672960, 960, 2012, 0x8588bd6c +0, 673920, 673920, 960, 2012, 0xc580bdde +0, 674880, 674880, 960, 2012, 0xb062baf1 +0, 675840, 675840, 960, 2012, 0xe014b082 +0, 676800, 676800, 960, 2012, 0x148bcb87 +0, 677760, 677760, 960, 2012, 0x554bc13d +0, 678720, 678720, 960, 2012, 0xc410c270 +0, 679680, 679680, 960, 2012, 0xb2c8b65b +0, 680640, 680640, 960, 2012, 0xa412b3f4 +0, 681600, 681600, 960, 2012, 0xbb52aa9a +0, 682560, 682560, 960, 2012, 0x4005b527 +0, 683520, 683520, 960, 2012, 0x8c5eb055 +0, 684480, 684480, 960, 2012, 0x8622c142 +0, 685440, 685440, 960, 2012, 0x05a3b861 +0, 686400, 686400, 960, 2012, 0x9f6dbb4d +0, 687360, 687360, 960, 2012, 0x033fb867 +0, 688320, 688320, 960, 2012, 0x243babd5 +0, 689280, 689280, 960, 2012, 0x8d6db83c +0, 690240, 690240, 960, 2012, 0x3923b829 +0, 691200, 691200, 960, 2012, 0x69b6b587 +0, 692160, 692160, 960, 2012, 0xdda8d018 +0, 693120, 693120, 960, 2012, 0x54b1b2a4 +0, 694080, 694080, 960, 2012, 0x380eb1af +0, 695040, 695040, 960, 2012, 0xec3cbdb4 +0, 696000, 696000, 960, 2012, 0x7ce9b4cf +0, 696960, 696960, 960, 2012, 0xcf6cb99b +0, 697920, 697920, 960, 2012, 0x7383ab97 +0, 698880, 698880, 960, 2012, 0xaa4cc068 +0, 699840, 699840, 960, 2012, 0x96d4c3db +0, 700800, 700800, 960, 2012, 0xab8cb84f +0, 701760, 701760, 960, 2012, 0x73dcacf9 +0, 702720, 702720, 960, 2012, 0xf61ca122 +0, 703680, 703680, 960, 2012, 0x9f1cbd5b +0, 704640, 704640, 960, 2012, 0x1f84aa3f +0, 705600, 705600, 960, 2012, 0xa003ad43 +0, 706560, 706560, 960, 2012, 0x6cffa4ef +0, 707520, 707520, 960, 2012, 0x29559e1e +0, 708480, 708480, 960, 2012, 0x7a79b059 +0, 709440, 709440, 960, 2012, 0xa1929c42 +0, 710400, 710400, 960, 2012, 0x52dead1c +0, 711360, 711360, 960, 2012, 0x8f31b9f5 +0, 712320, 712320, 960, 2012, 0xb8a899ec +0, 713280, 713280, 960, 2012, 0x7ca4b02d +0, 714240, 714240, 960, 2012, 0x2c92ae1b +0, 715200, 715200, 960, 2012, 0xe683a92f +0, 716160, 716160, 960, 2012, 0xe9d5abcf +0, 717120, 717120, 960, 2012, 0x757db377 +0, 718080, 718080, 960, 2012, 0xd4a8bbae +0, 719040, 719040, 960, 2012, 0xeea5c4ee +0, 720000, 720000, 960, 2012, 0xc37ca9a9 +0, 720960, 720960, 960, 2012, 0x8871bb51 +0, 721920, 721920, 960, 2012, 0x5dd8b3a2 +0, 722880, 722880, 960, 2012, 0xef0fae7f +0, 723840, 723840, 960, 2012, 0xe7ecb23e +0, 724800, 724800, 960, 2012, 0xc4f6d437 +0, 725760, 725760, 960, 2012, 0x0c74b81d +0, 726720, 726720, 960, 2012, 0xee68b1ee +0, 727680, 727680, 960, 2012, 0x46b4b4a8 +0, 728640, 728640, 960, 2012, 0x0526abca +0, 729600, 729600, 960, 2012, 0x7695ba55 +0, 730560, 730560, 960, 2012, 0xc7f5ad90 +0, 731520, 731520, 960, 2012, 0x0522b9bc +0, 732480, 732480, 960, 2012, 0x0eefc6ad +0, 733440, 733440, 960, 2012, 0x340dae16 +0, 734400, 734400, 960, 2012, 0xea42bdc0 +0, 735360, 735360, 960, 2012, 0xe047abb6 +0, 736320, 736320, 960, 2012, 0x6da5c14f +0, 737280, 737280, 960, 2012, 0x46d8c11d +0, 738240, 738240, 960, 2012, 0x8f4d9f2f +0, 739200, 739200, 960, 2012, 0x6d00d26c +0, 740160, 740160, 960, 2012, 0x87fc9d1b +0, 741120, 741120, 960, 2012, 0xbba5b763 +0, 742080, 742080, 960, 2012, 0xab58b853 +0, 743040, 743040, 960, 2012, 0x8180b863 +0, 744000, 744000, 960, 2012, 0x3684b3ba +0, 744960, 744960, 960, 2012, 0xf1a4a806 +0, 745920, 745920, 960, 2012, 0x2826b48c +0, 746880, 746880, 960, 2012, 0x1883af7f +0, 747840, 747840, 960, 2012, 0x44c5c37a +0, 748800, 748800, 960, 2012, 0xec33c3f1 +0, 749760, 749760, 960, 2012, 0xd67fb767 +0, 750720, 750720, 960, 2012, 0x03c2c219 +0, 751680, 751680, 960, 2012, 0x75a9b389 +0, 752640, 752640, 960, 2012, 0xe041ad88 +0, 753600, 753600, 960, 2012, 0x6bccb005 +0, 754560, 754560, 960, 2012, 0xd881c24a +0, 755520, 755520, 960, 2012, 0x7dd0c302 +0, 756480, 756480, 960, 2012, 0x2ba8a649 +0, 757440, 757440, 960, 2012, 0x63e19eab +0, 758400, 758400, 960, 2012, 0x1c0dafce +0, 759360, 759360, 960, 2012, 0xf266bf47 +0, 760320, 760320, 960, 2012, 0x11beb4b1 +0, 761280, 761280, 960, 2012, 0xc6f6b2b5 +0, 762240, 762240, 960, 2012, 0x15d4b4d0 +0, 763200, 763200, 960, 2012, 0x08bfa1e7 +0, 764160, 764160, 960, 2012, 0x18dbb7b5 +0, 765120, 765120, 960, 2012, 0xc279cc67 +0, 766080, 766080, 960, 2012, 0xd236bf28 +0, 767040, 767040, 960, 2012, 0xc9d1b196 +0, 768000, 768000, 960, 2012, 0xb605983e +0, 768960, 768960, 960, 2012, 0x8132c566 +0, 769920, 769920, 960, 2012, 0x6be4cd39 +0, 770880, 770880, 960, 2012, 0xce53c1f9 +0, 771840, 771840, 960, 2012, 0xe1efac0f +0, 772800, 772800, 960, 2012, 0x3d60a57a +0, 773760, 773760, 960, 2012, 0x1beda4b7 +0, 774720, 774720, 960, 2012, 0x34a4ac81 +0, 775680, 775680, 960, 2012, 0x30b0be4b +0, 776640, 776640, 960, 2012, 0xc7ceaf45 +0, 777600, 777600, 960, 2012, 0xade0b6ec +0, 778560, 778560, 960, 2012, 0xe00daf06 +0, 779520, 779520, 960, 2012, 0x04f79fe4 +0, 780480, 780480, 960, 2012, 0x8c59b7d9 +0, 781440, 781440, 960, 2012, 0x6f66b92a +0, 782400, 782400, 960, 2012, 0x9b08b2c0 +0, 783360, 783360, 960, 2012, 0xa8c1b5c1 +0, 784320, 784320, 960, 2012, 0xe3aac0b0 +0, 785280, 785280, 960, 2012, 0x1622bdaf +0, 786240, 786240, 960, 2012, 0x25e1a9ff +0, 787200, 787200, 960, 2012, 0x5577ad82 +0, 788160, 788160, 960, 2012, 0xfe16a49b +0, 789120, 789120, 960, 2012, 0xef7fc32a +0, 790080, 790080, 960, 2012, 0xfe30c35d +0, 791040, 791040, 960, 2012, 0x3adc9610 +0, 792000, 792000, 960, 2012, 0x36eeabdc +0, 792960, 792960, 960, 2012, 0xde3fb56c +0, 793920, 793920, 960, 2012, 0x5629bd82 +0, 794880, 794880, 960, 2012, 0xb099a61d +0, 795840, 795840, 960, 2012, 0x3013b106 +0, 796800, 796800, 960, 2012, 0xc359aef3 +0, 797760, 797760, 960, 2012, 0xec01b3e1 +0, 798720, 798720, 960, 2012, 0x6e8ac0b1 +0, 799680, 799680, 960, 2012, 0x41e8b82d +0, 800640, 800640, 960, 2012, 0x3a2fb38b +0, 801600, 801600, 960, 2012, 0x7025aac9 +0, 802560, 802560, 960, 2012, 0xbb0eb094 +0, 803520, 803520, 960, 2012, 0xdc06c156 +0, 804480, 804480, 960, 2012, 0x4007cea4 +0, 805440, 805440, 960, 2012, 0x102ebe03 +0, 806400, 806400, 960, 2012, 0x6e8faae7 +0, 807360, 807360, 960, 2012, 0xa357aa0c +0, 808320, 808320, 960, 2012, 0x07d2bf4d +0, 809280, 809280, 960, 2012, 0xfb71b338 +0, 810240, 810240, 960, 2012, 0xd5f1be84 +0, 811200, 811200, 960, 2012, 0x2a7cb554 +0, 812160, 812160, 960, 2012, 0xfb03b8c3 +0, 813120, 813120, 960, 2012, 0x2ff1ca87 +0, 814080, 814080, 960, 2012, 0xeef2b7f3 +0, 815040, 815040, 960, 2012, 0x9377b15f +0, 816000, 816000, 960, 2012, 0x370cb0c2 +0, 816960, 816960, 960, 2012, 0x5f78b118 +0, 817920, 817920, 960, 2012, 0x19afa87a +0, 818880, 818880, 960, 2012, 0xc717ab0d +0, 819840, 819840, 960, 2012, 0x3ca499f4 +0, 820800, 820800, 960, 2012, 0x9612b8e4 +0, 821760, 821760, 960, 2012, 0x32c0bb29 +0, 822720, 822720, 960, 2012, 0x7727beba +0, 823680, 823680, 960, 2012, 0x8b60a4cb +0, 824640, 824640, 960, 2012, 0xe899a9c8 +0, 825600, 825600, 960, 2012, 0x60f4b7fe +0, 826560, 826560, 960, 2012, 0x544f9ecb +0, 827520, 827520, 960, 2012, 0x34afcd71 +0, 828480, 828480, 960, 2012, 0x470eab55 +0, 829440, 829440, 960, 2012, 0xe4959f93 +0, 830400, 830400, 960, 2012, 0x69eeaf97 +0, 831360, 831360, 960, 2012, 0x0ec9aca3 +0, 832320, 832320, 960, 2012, 0x51e4b7f6 +0, 833280, 833280, 960, 2012, 0xf6c0a837 +0, 834240, 834240, 960, 2012, 0x3bdca59b +0, 835200, 835200, 960, 2012, 0x14c59dfc +0, 836160, 836160, 960, 2012, 0xa50ab23a +0, 837120, 837120, 960, 2012, 0x8832b6e2 +0, 838080, 838080, 960, 2012, 0x3d699d1b +0, 839040, 839040, 960, 2012, 0x751aa4b8 +0, 840000, 840000, 960, 2012, 0x59a9b98c +0, 840960, 840960, 960, 2012, 0xb67c98cb +0, 841920, 841920, 960, 2012, 0x0fd39ccd +0, 842880, 842880, 960, 2012, 0x9980d1e1 +0, 843840, 843840, 960, 2012, 0xffd9a716 +0, 844800, 844800, 960, 2012, 0x7d2fbed1 +0, 845760, 845760, 960, 2012, 0x76e6b042 +0, 846720, 846720, 960, 2012, 0xe027a232 +0, 847680, 847680, 960, 2012, 0x7c6ca5ce +0, 848640, 848640, 960, 2012, 0x5cf6bda4 +0, 849600, 849600, 960, 2012, 0x6075bd0d +0, 850560, 850560, 960, 2012, 0xedc4abe9 +0, 851520, 851520, 960, 2012, 0xb8f7cc26 +0, 852480, 852480, 960, 2012, 0x2cbbb500 +0, 853440, 853440, 960, 2012, 0x1c34b04d +0, 854400, 854400, 960, 2012, 0x5f18bea2 +0, 855360, 855360, 960, 2012, 0x94d0bb2b +0, 856320, 856320, 960, 2012, 0x6899b78e +0, 857280, 857280, 960, 2012, 0xc9aaa7a2 +0, 858240, 858240, 960, 2012, 0x298cbafa +0, 859200, 859200, 960, 2012, 0x89d9ac80 +0, 860160, 860160, 960, 2012, 0xc6ffa7e6 +0, 861120, 861120, 960, 2012, 0xdcf7caf9 +0, 862080, 862080, 960, 2012, 0x26cfb4ee +0, 863040, 863040, 960, 2012, 0xec70b09d +0, 864000, 864000, 960, 2012, 0x65dca50f +0, 864960, 864960, 960, 2012, 0xcdebc0b6 +0, 865920, 865920, 960, 2012, 0x9393a262 +0, 866880, 866880, 960, 2012, 0x34aab06d +0, 867840, 867840, 960, 2012, 0x4800a550 +0, 868800, 868800, 960, 2012, 0x4d9aadec +0, 869760, 869760, 960, 2012, 0x2cddabb6 +0, 870720, 870720, 960, 2012, 0x91a0c5b2 +0, 871680, 871680, 960, 2012, 0xd326bee1 +0, 872640, 872640, 960, 2012, 0xf76ab2d5 +0, 873600, 873600, 960, 2012, 0xcef99ade +0, 874560, 874560, 960, 2012, 0x950dc76f +0, 875520, 875520, 960, 2012, 0xb6aca7ad +0, 876480, 876480, 960, 2012, 0x1aacb71c +0, 877440, 877440, 960, 2012, 0x32389da0 +0, 878400, 878400, 960, 2012, 0x030cbcce +0, 879360, 879360, 960, 2012, 0x0ec4b0cb +0, 880320, 880320, 960, 2012, 0x6c0bb62e +0, 881280, 881280, 960, 2012, 0xfadbb20d +0, 882240, 882240, 960, 2012, 0x99c9c848 +0, 883200, 883200, 960, 2012, 0xe3e3b21a +0, 884160, 884160, 960, 2012, 0x88d9a50b +0, 885120, 885120, 960, 2012, 0xf4bbaf17 +0, 886080, 886080, 960, 2012, 0x49fea706 +0, 887040, 887040, 960, 2012, 0xafd0babf +0, 888000, 888000, 960, 2012, 0x8970a8f3 +0, 888960, 888960, 960, 2012, 0x9223a553 +0, 889920, 889920, 960, 2012, 0x6ec2b2f9 +0, 890880, 890880, 960, 2012, 0x7960b759 +0, 891840, 891840, 960, 2012, 0x852891bf +0, 892800, 892800, 960, 2012, 0x094ebbeb +0, 893760, 893760, 960, 2012, 0xf9bab418 +0, 894720, 894720, 960, 2012, 0x010eae8c +0, 895680, 895680, 960, 2012, 0x10baab3d +0, 896640, 896640, 960, 2012, 0x2564b13f +0, 897600, 897600, 960, 2012, 0xaec8ac22 +0, 898560, 898560, 960, 2012, 0xda0cbd4f +0, 899520, 899520, 960, 2012, 0x97e1c075 +0, 900480, 900480, 960, 2012, 0x6731aca5 +0, 901440, 901440, 960, 2012, 0x2c1db696 +0, 902400, 902400, 960, 2012, 0x8ff7abbf +0, 903360, 903360, 960, 2012, 0xf75ab3a2 +0, 904320, 904320, 960, 2012, 0x8683b824 +0, 905280, 905280, 960, 2012, 0x9668b354 +0, 906240, 906240, 960, 2012, 0x6e9aae04 +0, 907200, 907200, 960, 2012, 0xd8e9acd7 +0, 908160, 908160, 960, 2012, 0xa326c298 +0, 909120, 909120, 960, 2012, 0x6abcb409 +0, 910080, 910080, 960, 2012, 0x7eb3b549 +0, 911040, 911040, 960, 2012, 0xfc72ba6a +0, 912000, 912000, 960, 2012, 0xed73b2e6 +0, 912960, 912960, 960, 2012, 0x07a6b0a9 +0, 913920, 913920, 960, 2012, 0x10a4aec4 +0, 914880, 914880, 960, 2012, 0xaac9a650 +0, 915840, 915840, 960, 2012, 0x848b9869 +0, 916800, 916800, 960, 2012, 0x1ddaafd6 +0, 917760, 917760, 960, 2012, 0xe291aaec +0, 918720, 918720, 960, 2012, 0x8aa1aa4d +0, 919680, 919680, 960, 2012, 0x9b69b94c +0, 920640, 920640, 960, 2012, 0xe784bec0 +0, 921600, 921600, 960, 2012, 0x9305ba2d +0, 922560, 922560, 960, 2012, 0x5616bb81 +0, 923520, 923520, 960, 2012, 0xea0facca +0, 924480, 924480, 960, 2012, 0xe1b9991e +0, 925440, 925440, 960, 2012, 0xded8bd59 +0, 926400, 926400, 960, 2012, 0xe79fb0ee +0, 927360, 927360, 960, 2012, 0x1b8595a6 +0, 928320, 928320, 960, 2012, 0xb55ba336 +0, 929280, 929280, 960, 2012, 0xc552bc98 +0, 930240, 930240, 960, 2012, 0x2fe2c5ba +0, 931200, 931200, 960, 2012, 0xe18aa5a6 +0, 932160, 932160, 960, 2012, 0xaa9bae1c +0, 933120, 933120, 960, 2012, 0xd1ddb68d +0, 934080, 934080, 960, 2012, 0x95bfb203 +0, 935040, 935040, 960, 2012, 0xeacab8b9 +0, 936000, 936000, 960, 2012, 0x5bfcb117 +0, 936960, 936960, 960, 2012, 0x1a9fa91c +0, 937920, 937920, 960, 2012, 0xa285b180 +0, 938880, 938880, 960, 2012, 0xfd58a6e2 +0, 939840, 939840, 960, 2012, 0x394fc325 +0, 940800, 940800, 960, 2012, 0x0415a6aa +0, 941760, 941760, 960, 2012, 0xf75fa5e0 +0, 942720, 942720, 960, 2012, 0x115cd11b +0, 943680, 943680, 960, 2012, 0x6587b9e3 +0, 944640, 944640, 960, 2012, 0xce6bb7e6 +0, 945600, 945600, 960, 2012, 0xbaa2b409 +0, 946560, 946560, 960, 2012, 0x271bbb14 +0, 947520, 947520, 960, 2012, 0x4516c223 +0, 948480, 948480, 960, 2012, 0x4f6ab266 +0, 949440, 949440, 960, 2012, 0x244ba6fc +0, 950400, 950400, 960, 2012, 0x60e0ae4e +0, 951360, 951360, 960, 2012, 0xfc3cac80 +0, 952320, 952320, 960, 2012, 0x8465b287 +0, 953280, 953280, 960, 2012, 0xc683b070 +0, 954240, 954240, 960, 2012, 0x2901c8e7 +0, 955200, 955200, 960, 2012, 0x0622b1a1 +0, 956160, 956160, 960, 2012, 0xe002b34c +0, 957120, 957120, 960, 2012, 0xf4969e79 +0, 958080, 958080, 960, 2012, 0x871cc453 +0, 959040, 959040, 960, 2012, 0x9a7daaf3 +0, 960000, 960000, 960, 2012, 0xba92a60a +0, 960960, 960960, 960, 2012, 0xf464a0c4 +0, 961920, 961920, 960, 2012, 0x53bbb6cd +0, 962880, 962880, 960, 2012, 0xb58a9d2a +0, 963840, 963840, 960, 2012, 0x1e1fb830 +0, 964800, 964800, 960, 2012, 0xdc7eb93e +0, 965760, 965760, 960, 2012, 0xe6ceaaf9 +0, 966720, 966720, 960, 2012, 0x8c7ea35d +0, 967680, 967680, 960, 2012, 0x0b87ba04 +0, 968640, 968640, 960, 2012, 0xf516a700 +0, 969600, 969600, 960, 2012, 0xfaf19e13 +0, 970560, 970560, 960, 2012, 0x53cf9ed0 +0, 971520, 971520, 960, 2012, 0x2e25c2f9 +0, 972480, 972480, 960, 2012, 0x959aa1b8 +0, 973440, 973440, 960, 2012, 0x2a49a572 +0, 974400, 974400, 960, 2012, 0xf7a9b809 +0, 975360, 975360, 960, 2012, 0x44a9b879 +0, 976320, 976320, 960, 2012, 0xe428c0d4 +0, 977280, 977280, 960, 2012, 0xc258c2c6 +0, 978240, 978240, 960, 2012, 0xf7f3b794 +0, 979200, 979200, 960, 2012, 0xa8adbad9 +0, 980160, 980160, 960, 2012, 0xc2508e79 +0, 981120, 981120, 960, 2012, 0x1418ac76 +0, 982080, 982080, 960, 2012, 0xb28aadef +0, 983040, 983040, 960, 2012, 0xda17bd03 +0, 984000, 984000, 960, 2012, 0xa92ab852 +0, 984960, 984960, 960, 2012, 0xc3cbcfa4 +0, 985920, 985920, 960, 2012, 0xf716bb5e +0, 986880, 986880, 960, 2012, 0x6009a8af +0, 987840, 987840, 960, 2012, 0x9e69bc81 +0, 988800, 988800, 960, 2012, 0x3aafc8cf +0, 989760, 989760, 960, 2012, 0x03bccdab +0, 990720, 990720, 960, 2012, 0xfdceb2d9 +0, 991680, 991680, 960, 2012, 0x68f7afb8 +0, 992640, 992640, 960, 2012, 0xb7bab330 +0, 993600, 993600, 960, 2012, 0x4976b125 +0, 994560, 994560, 960, 2012, 0x7c86ae12 +0, 995520, 995520, 960, 2012, 0x4ce4ca54 +0, 996480, 996480, 960, 2012, 0xf1f7b892 +0, 997440, 997440, 960, 2012, 0xf958abb1 +0, 998400, 998400, 960, 2012, 0x047accd0 +0, 999360, 999360, 960, 2012, 0x34a1c49c +0, 1000320, 1000320, 960, 2012, 0x4b24a4ed +0, 1001280, 1001280, 960, 2012, 0xea31b1bc +0, 1002240, 1002240, 960, 2012, 0x8beaa3e3 +0, 1003200, 1003200, 960, 2012, 0x064caaf9 +0, 1004160, 1004160, 960, 2012, 0x56babf15 +0, 1005120, 1005120, 960, 2012, 0xd16fc6f4 +0, 1006080, 1006080, 960, 2012, 0x4ac2b78a +0, 1007040, 1007040, 960, 2012, 0xba3aa509 +0, 1008000, 1008000, 960, 2012, 0xc103b074 +0, 1008960, 1008960, 960, 2012, 0x464aba98 +0, 1009920, 1009920, 960, 2012, 0xaacac5a3 +0, 1010880, 1010880, 960, 2012, 0x9cecbcfa +0, 1011840, 1011840, 960, 2012, 0x8da0ab79 +0, 1012800, 1012800, 960, 2012, 0x85b2b023 +0, 1013760, 1013760, 960, 2012, 0x598abc91 +0, 1014720, 1014720, 960, 2012, 0x08c0a35c +0, 1015680, 1015680, 960, 2012, 0x30e4a7cf +0, 1016640, 1016640, 960, 2012, 0xf1e4a931 +0, 1017600, 1017600, 960, 2012, 0x8a4fb6c1 +0, 1018560, 1018560, 960, 2012, 0x126aac08 +0, 1019520, 1019520, 960, 2012, 0x537fa51b +0, 1020480, 1020480, 960, 2012, 0x1e54ac5a +0, 1021440, 1021440, 960, 2012, 0x7274bbd0 +0, 1022400, 1022400, 960, 2012, 0xd16bc2c2 +0, 1023360, 1023360, 960, 2012, 0x9236c1e3 +0, 1024320, 1024320, 960, 2012, 0x348aa7af +0, 1025280, 1025280, 960, 2012, 0xa020be5e +0, 1026240, 1026240, 960, 2012, 0x3cc5a4b8 +0, 1027200, 1027200, 960, 2012, 0x8b19b649 +0, 1028160, 1028160, 960, 2012, 0x554aa5ab +0, 1029120, 1029120, 960, 2012, 0x35d6ac35 +0, 1030080, 1030080, 960, 2012, 0x64dba435 +0, 1031040, 1031040, 960, 2012, 0x6001bae2 +0, 1032000, 1032000, 960, 2012, 0x9220b599 +0, 1032960, 1032960, 960, 2012, 0xa3fdb899 +0, 1033920, 1033920, 960, 2012, 0x19a5abf4 +0, 1034880, 1034880, 960, 2012, 0xd857b8cf +0, 1035840, 1035840, 960, 2012, 0x38d1b234 +0, 1036800, 1036800, 960, 2012, 0x69f4bfb8 +0, 1037760, 1037760, 960, 2012, 0xcc87a375 +0, 1038720, 1038720, 960, 2012, 0xc1cdd0c5 +0, 1039680, 1039680, 960, 2012, 0xba0ca3ee +0, 1040640, 1040640, 960, 2012, 0x4d20c397 +0, 1041600, 1041600, 960, 2012, 0x825c9636 +0, 1042560, 1042560, 960, 2012, 0x7aa4ae53 +0, 1043520, 1043520, 960, 2012, 0xe970ae78 +0, 1044480, 1044480, 960, 2012, 0x5fb2ba59 +0, 1045440, 1045440, 960, 2012, 0xcd90a953 +0, 1046400, 1046400, 960, 2012, 0xf573ac40 +0, 1047360, 1047360, 960, 2012, 0x324cbd77 +0, 1048320, 1048320, 960, 2012, 0xece0a73d +0, 1049280, 1049280, 960, 2012, 0x0dd1aefa +0, 1050240, 1050240, 960, 2012, 0xe338c866 +0, 1051200, 1051200, 960, 2012, 0xfe71bffc +0, 1052160, 1052160, 960, 2012, 0x61a5a810 +0, 1053120, 1053120, 960, 2012, 0x7c3ba074 +0, 1054080, 1054080, 960, 2012, 0x492f9d91 +0, 1055040, 1055040, 960, 2012, 0xa126a7b9 +0, 1056000, 1056000, 960, 2012, 0x7cf19a40 +0, 1056960, 1056960, 960, 2012, 0x1c2fbae6 +0, 1057920, 1057920, 960, 2012, 0x540accdf +0, 1058880, 1058880, 960, 2012, 0x5908a938 +0, 1059840, 1059840, 960, 2012, 0xe7f8b501 +0, 1060800, 1060800, 960, 2012, 0x03a8b53e +0, 1061760, 1061760, 960, 2012, 0xb4e3bdda +0, 1062720, 1062720, 960, 2012, 0x9e86abe1 +0, 1063680, 1063680, 960, 2012, 0x3234b98d +0, 1064640, 1064640, 960, 2012, 0x5caec781 +0, 1065600, 1065600, 960, 2012, 0x5c21a32e +0, 1066560, 1066560, 960, 2012, 0x8b72c112 +0, 1067520, 1067520, 960, 2012, 0x2ec2bac3 +0, 1068480, 1068480, 960, 2012, 0xd9c4adaa +0, 1069440, 1069440, 960, 2012, 0x2da1b496 +0, 1070400, 1070400, 960, 2012, 0x0a51b21e +0, 1071360, 1071360, 960, 2012, 0x6414ab0d +0, 1072320, 1072320, 960, 2012, 0x95c4b203 +0, 1073280, 1073280, 960, 2012, 0x98e0b4a2 +0, 1074240, 1074240, 960, 2012, 0x34369f5f +0, 1075200, 1075200, 960, 2012, 0x9dffa40c +0, 1076160, 1076160, 960, 2012, 0xf345b0e5 +0, 1077120, 1077120, 960, 2012, 0x6714bdbf +0, 1078080, 1078080, 960, 2012, 0xc276c3d1 +0, 1079040, 1079040, 960, 2012, 0xf199b475 +0, 1080000, 1080000, 960, 2012, 0x3395cf3b +0, 1080960, 1080960, 960, 2012, 0x4b52afb0 +0, 1081920, 1081920, 960, 2012, 0x3f74b217 +0, 1082880, 1082880, 960, 2012, 0xa25cad38 +0, 1083840, 1083840, 960, 2012, 0x3290a5b4 +0, 1084800, 1084800, 960, 2012, 0x2917b750 +0, 1085760, 1085760, 960, 2012, 0xeb3ec739 +0, 1086720, 1086720, 960, 2012, 0xbf9ea51d +0, 1087680, 1087680, 960, 2012, 0x98e2a0c1 +0, 1088640, 1088640, 960, 2012, 0xa39ba7f2 +0, 1089600, 1089600, 960, 2012, 0x6df7a05c +0, 1090560, 1090560, 960, 2012, 0x2c1bba28 +0, 1091520, 1091520, 960, 2012, 0x6099b1cd +0, 1092480, 1092480, 960, 2012, 0x9366b9f2 +0, 1093440, 1093440, 960, 2012, 0x95899570 +0, 1094400, 1094400, 960, 2012, 0x6234a0c8 +0, 1095360, 1095360, 960, 2012, 0xec2cbcfc +0, 1096320, 1096320, 960, 2012, 0x3ff7a9db +0, 1097280, 1097280, 960, 2012, 0x4e44bad7 +0, 1098240, 1098240, 960, 2012, 0x1dbbbc39 +0, 1099200, 1099200, 960, 2012, 0xf9df99be +0, 1100160, 1100160, 960, 2012, 0xa713b313 +0, 1101120, 1101120, 960, 2012, 0x8bbdbe51 +0, 1102080, 1102080, 960, 2012, 0x0d5bc786 +0, 1103040, 1103040, 960, 2012, 0x75d293f2 +0, 1104000, 1104000, 960, 2012, 0x4832b688 +0, 1104960, 1104960, 960, 2012, 0x71aba74c +0, 1105920, 1105920, 960, 2012, 0x04d5abf2 +0, 1106880, 1106880, 960, 2012, 0xaa8fbd98 +0, 1107840, 1107840, 960, 2012, 0xd93eb6d4 +0, 1108800, 1108800, 960, 2012, 0x8fb6b5a8 +0, 1109760, 1109760, 960, 2012, 0x779a92f5 +0, 1110720, 1110720, 960, 2012, 0x35c8ab3d +0, 1111680, 1111680, 960, 2012, 0x0017aaa5 +0, 1112640, 1112640, 960, 2012, 0xd6e7bafe +0, 1113600, 1113600, 960, 2012, 0xe358b423 +0, 1114560, 1114560, 960, 2012, 0x3f74bfba +0, 1115520, 1115520, 960, 2012, 0x0a5eb707 +0, 1116480, 1116480, 960, 2012, 0xedbfb0df +0, 1117440, 1117440, 960, 2012, 0x2e71a26f +0, 1118400, 1118400, 960, 2012, 0x214db1a8 +0, 1119360, 1119360, 960, 2012, 0xb632c275 +0, 1120320, 1120320, 960, 2012, 0xb597cf92 +0, 1121280, 1121280, 960, 2012, 0x18a8b508 +0, 1122240, 1122240, 960, 2012, 0x8267b4ff +0, 1123200, 1123200, 960, 2012, 0x5a9ab8d6 +0, 1124160, 1124160, 960, 2012, 0x2037a2b6 diff --git a/tests/ref/fate/sub-webvtt b/tests/ref/fate/sub-webvtt index ea587b327..fae50607f 100644 --- a/tests/ref/fate/sub-webvtt +++ b/tests/ref/fate/sub-webvtt @@ -21,7 +21,7 @@ Dialogue: 0,0:00:22.00,0:00:24.00,Default,,0,0,0,,at the AMNH. Dialogue: 0,0:00:24.00,0:00:26.00,Default,,0,0,0,,Thank you for walking down here. Dialogue: 0,0:00:27.00,0:00:30.00,Default,,0,0,0,,And I want to do a follow-up on the last conversation we did.\Nmultiple lines\Nagain Dialogue: 0,0:00:30.00,0:00:31.50,Default,,0,0,0,,When we e-mailed— -Dialogue: 0,0:00:30.50,0:00:32.50,Default,,0,0,0,,Didn't we {\b1}talk {\i1}about\N{\i0} enough{\b0} in that conversation? \{I'm not an ASS comment\} +Dialogue: 0,0:00:30.50,0:00:32.50,Default,,0,0,0,,Didn't we {\b1}talk {\i1}about\N{\i0} enough{\b0} in that conversation? \{{}I'm not an ASS comment} Dialogue: 0,0:00:32.00,0:00:35.50,Default,,0,0,0,,No! No no no no; 'cos 'cos obviously 'cos Dialogue: 0,0:00:32.50,0:00:33.50,Default,,0,0,0,,{\i1}Laughs{\i0} Dialogue: 0,0:00:35.50,0:00:38.00,Default,,0,0,0,,You know I'm so excited my glasses are falling off here. diff --git a/tests/ref/fate/sub-webvtt2 b/tests/ref/fate/sub-webvtt2 index 90f78d904..2925d892a 100644 --- a/tests/ref/fate/sub-webvtt2 +++ b/tests/ref/fate/sub-webvtt2 @@ -21,6 +21,6 @@ Dialogue: 0,0:00:12.50,0:00:32.50,Default,,0,0,0,,OK, let’s go. Dialogue: 0,0:00:38.00,0:00:43.00,Default,,0,0,0,,I want to 愛あい love you\NThat's not proper English! Dialogue: 0,0:00:43.00,0:00:46.00,Default,,0,0,0,,{\i1}キツネ{\i0}じゃない キツネじゃない\N乙女おとめは Dialogue: 0,0:00:50.00,0:00:55.00,Default,,0,0,0,,Some time ago in a rather distant place.... -Dialogue: 0,0:00:55.00,0:01:00.00,Default,,0,0,0,,Descending: 123456\NAscending: 123456 +Dialogue: 0,0:00:55.00,0:01:00.00,Default,,0,0,0,,Descending: ‏123456‎\NAscending: 123456 Dialogue: 0,0:01:00.00,0:01:05.00,Default,,0,0,0,,>> Never gonna give you up Never gonna let you down\NNever\hgonna\hrun\haround & desert\hyou Dialogue: 0,0:55:00.00,1:00:00.00,Default,,0,0,0,,Transcrit par Célestes™ diff --git a/tests/ref/fate/time_base b/tests/ref/fate/time_base index fd6cac53f..ae96232e6 100644 --- a/tests/ref/fate/time_base +++ b/tests/ref/fate/time_base @@ -1 +1 @@ -d408aba82d62a90ed7f46a1999b014f1 +69ffc45e19ab070bc3e964d7b718fe53 diff --git a/tests/ref/fate/ts-demux b/tests/ref/fate/ts-demux index ec4aeb203..45522c2bf 100644 --- a/tests/ref/fate/ts-demux +++ b/tests/ref/fate/ts-demux @@ -23,7 +23,7 @@ packet|codec_type=audio|stream_index=2|pts=3912642700|pts_time=43473.807778|dts= packet|codec_type=video|stream_index=0|pts=3912686363|pts_time=43474.292922|dts=3912686363|dts_time=43474.292922|duration=1501|duration_time=0.016678|size=4944|pos=506660|flags=___|data_hash=CRC32:54a86cbb packet|codec_type=audio|stream_index=1|pts=3912644825|pts_time=43473.831389|dts=3912644825|dts_time=43473.831389|duration=2880|duration_time=0.032000|size=906|pos=474888|flags=K__|data_hash=CRC32:0893d398 packet|codec_type=audio|stream_index=2|pts=3912645580|pts_time=43473.839778|dts=3912645580|dts_time=43473.839778|duration=2880|duration_time=0.032000|size=354|pos=491808|flags=K__|data_hash=CRC32:f5963fa6 -stream|index=0|codec_name=mpeg2video|profile=4|codec_type=video|codec_tag_string=[2][0][0][0]|codec_tag=0x0002|width=1280|height=720|coded_width=0|coded_height=0|closed_captions=0|film_grain=0|has_b_frames=1|sample_aspect_ratio=1:1|display_aspect_ratio=16:9|pix_fmt=yuv420p|level=4|color_range=tv|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|ts_id=32776|ts_packetsize=188|id=0x31|r_frame_rate=60000/1001|avg_frame_rate=60000/1001|time_base=1/90000|start_pts=3912669846|start_time=43474.109400|duration_ts=19519|duration=0.216878|bit_rate=15000000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=15|extradata_size=150|extradata_hash=CRC32:53134fa8|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|side_datum/cpb_properties:side_data_type=CPB properties|side_datum/cpb_properties:max_bitrate=15000000|side_datum/cpb_properties:min_bitrate=0|side_datum/cpb_properties:avg_bitrate=0|side_datum/cpb_properties:buffer_size=9781248|side_datum/cpb_properties:vbv_delay=-1 -stream|index=1|codec_name=ac3|profile=unknown|codec_type=audio|codec_tag_string=[4][0][0][0]|codec_tag=0x0004|sample_fmt=fltp|sample_rate=48000|channels=6|channel_layout=5.1(side)|bits_per_sample=0|initial_padding=0|ts_id=32776|ts_packetsize=188|id=0x34|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=3912633305|start_time=43473.703389|duration_ts=14400|duration=0.160000|bit_rate=384000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=5|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|tag:language=eng -stream|index=2|codec_name=ac3|profile=unknown|codec_type=audio|codec_tag_string=[4][0][0][0]|codec_tag=0x0004|sample_fmt=fltp|sample_rate=48000|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=0|ts_id=32776|ts_packetsize=188|id=0x35|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=3912634060|start_time=43473.711778|duration_ts=14400|duration=0.160000|bit_rate=192000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=5|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|tag:language=es +stream|index=0|codec_name=mpeg2video|profile=4|codec_type=video|codec_tag_string=[2][0][0][0]|codec_tag=0x0002|width=1280|height=720|coded_width=0|coded_height=0|closed_captions=0|film_grain=0|has_b_frames=1|sample_aspect_ratio=1:1|display_aspect_ratio=16:9|pix_fmt=yuv420p|level=4|color_range=tv|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|ts_id=32776|ts_packetsize=188|id=0x31|r_frame_rate=60000/1001|avg_frame_rate=60000/1001|time_base=1/90000|start_pts=3912669846|start_time=43474.109400|duration_ts=19519|duration=0.216878|bit_rate=15000000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=15|extradata_size=150|extradata_hash=CRC32:53134fa8|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|side_datum/cpb_properties:side_data_type=CPB properties|side_datum/cpb_properties:max_bitrate=15000000|side_datum/cpb_properties:min_bitrate=0|side_datum/cpb_properties:avg_bitrate=0|side_datum/cpb_properties:buffer_size=9781248|side_datum/cpb_properties:vbv_delay=-1 +stream|index=1|codec_name=ac3|profile=unknown|codec_type=audio|codec_tag_string=[4][0][0][0]|codec_tag=0x0004|sample_fmt=fltp|sample_rate=48000|channels=6|channel_layout=5.1(side)|bits_per_sample=0|initial_padding=0|ts_id=32776|ts_packetsize=188|id=0x34|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=3912633305|start_time=43473.703389|duration_ts=14400|duration=0.160000|bit_rate=384000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=5|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:language=eng +stream|index=2|codec_name=ac3|profile=unknown|codec_type=audio|codec_tag_string=[4][0][0][0]|codec_tag=0x0004|sample_fmt=fltp|sample_rate=48000|channels=2|channel_layout=stereo|bits_per_sample=0|initial_padding=0|ts_id=32776|ts_packetsize=188|id=0x35|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=3912634060|start_time=43473.711778|duration_ts=14400|duration=0.160000|bit_rate=192000|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=5|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0|tag:language=es format|filename=mp3ac325-4864-small.ts|nb_streams=3|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=43473.703389|duration=0.622889|size=512000|bit_rate=6575810|probe_score=50 diff --git a/tests/ref/fate/ts-opus-demux b/tests/ref/fate/ts-opus-demux index 961b7f2a9..d13b97aa6 100644 --- a/tests/ref/fate/ts-opus-demux +++ b/tests/ref/fate/ts-opus-demux @@ -510,5 +510,5 @@ packet|codec_type=audio|stream_index=0|pts=914400|pts_time=10.160000|dts=914400| packet|codec_type=audio|stream_index=0|pts=916200|pts_time=10.180000|dts=916200|dts_time=10.180000|duration=1800|duration_time=0.020000|size=760|pos=508728|flags=K__|data_hash=CRC32:fdf0ce4a|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189 packet|codec_type=audio|stream_index=0|pts=918000|pts_time=10.200000|dts=918000|dts_time=10.200000|duration=1800|duration_time=0.020000|size=761|pos=510044|flags=K__|data_hash=CRC32:75113c11|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189 packet|codec_type=audio|stream_index=0|pts=919800|pts_time=10.220000|dts=919800|dts_time=10.220000|duration=1800|duration_time=0.020000|size=759|pos=510984|flags=K__|data_hash=CRC32:59fc266f|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189 -stream|index=0|codec_name=opus|profile=unknown|codec_type=audio|codec_tag_string=Opus|codec_tag=0x7375704f|sample_fmt=fltp|sample_rate=48000|channels=8|channel_layout=7.1|bits_per_sample=0|initial_padding=0|ts_id=51338|ts_packetsize=188|id=0x44|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=919800|duration=10.220000|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=512|extradata_size=29|extradata_hash=CRC32:6d6089a7|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0 +stream|index=0|codec_name=opus|profile=unknown|codec_type=audio|codec_tag_string=Opus|codec_tag=0x7375704f|sample_fmt=fltp|sample_rate=48000|channels=8|channel_layout=7.1|bits_per_sample=0|initial_padding=0|ts_id=51338|ts_packetsize=188|id=0x44|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=919800|duration=10.220000|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=512|extradata_size=29|extradata_hash=CRC32:6d6089a7|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0 format|filename=test-8-7.1.opus-small.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=0.000000|duration=10.220000|size=512000|bit_rate=400782|probe_score=50 diff --git a/tests/ref/fate/ts-small-demux b/tests/ref/fate/ts-small-demux index 233f73393..fad4a0754 100644 --- a/tests/ref/fate/ts-small-demux +++ b/tests/ref/fate/ts-small-demux @@ -72,5 +72,5 @@ packet|codec_type=video|stream_index=0|pts=546000|pts_time=6.066667|dts=546000|d packet|codec_type=video|stream_index=0|pts=552000|pts_time=6.133333|dts=552000|dts_time=6.133333|duration=6000|duration_time=0.066667|size=16|pos=15604|flags=___|data_hash=CRC32:cca62b67|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224 packet|codec_type=video|stream_index=0|pts=558000|pts_time=6.200000|dts=558000|dts_time=6.200000|duration=6000|duration_time=0.066667|size=16|pos=15792|flags=___|data_hash=CRC32:27b943ef|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=224 packet|codec_type=video|stream_index=0|pts=564000|pts_time=6.266667|dts=564000|dts_time=6.266667|duration=6000|duration_time=0.066667|size=16|pos=16356|flags=___|data_hash=CRC32:f7116111 -stream|index=0|codec_name=h264|profile=578|codec_type=video|codec_tag_string=[27][0][0][0]|codec_tag=0x001b|width=82|height=144|coded_width=82|coded_height=144|closed_captions=0|film_grain=0|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=41:72|pix_fmt=yuv420p|level=10|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|is_avc=false|nal_length_size=0|ts_id=1|ts_packetsize=188|id=0x100|r_frame_rate=15/1|avg_frame_rate=15/1|time_base=1/90000|start_pts=126000|start_time=1.400000|duration_ts=444000|duration=4.933333|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=74|extradata_size=35|extradata_hash=CRC32:e62cae27|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0 +stream|index=0|codec_name=h264|profile=578|codec_type=video|codec_tag_string=[27][0][0][0]|codec_tag=0x001b|width=82|height=144|coded_width=82|coded_height=144|closed_captions=0|film_grain=0|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=41:72|pix_fmt=yuv420p|level=10|color_range=unknown|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=left|field_order=progressive|refs=1|is_avc=false|nal_length_size=0|ts_id=1|ts_packetsize=188|id=0x100|r_frame_rate=15/1|avg_frame_rate=15/1|time_base=1/90000|start_pts=126000|start_time=1.400000|duration_ts=444000|duration=4.933333|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=74|extradata_size=35|extradata_hash=CRC32:e62cae27|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0 format|filename=h264small.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=1.400000|duration=4.933333|size=16544|bit_rate=26828|probe_score=50 diff --git a/tests/ref/fate/ts-timed-id3-demux b/tests/ref/fate/ts-timed-id3-demux index 938b5326e..3de1ca299 100644 --- a/tests/ref/fate/ts-timed-id3-demux +++ b/tests/ref/fate/ts-timed-id3-demux @@ -1,4 +1,4 @@ packet|codec_type=data|stream_index=0|pts=126000|pts_time=1.400000|dts=126000|dts_time=1.400000|duration=N/A|duration_time=N/A|size=26|pos=564|flags=K__|data_hash=CRC32:469f474b|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189 packet|codec_type=data|stream_index=0|pts=577350|pts_time=6.415000|dts=577350|dts_time=6.415000|duration=N/A|duration_time=N/A|size=26|pos=1316|flags=K__|data_hash=CRC32:469f474b|side_datum/mpegts_stream_id:side_data_type=MPEGTS Stream ID|side_datum/mpegts_stream_id:id=189 -stream|index=0|codec_name=timed_id3|profile=unknown|codec_type=data|codec_tag_string=ID3 |codec_tag=0x20334449|ts_id=1|ts_packetsize=188|id=0x100|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=126000|start_time=1.400000|duration_ts=451350|duration=5.015000|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=2|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0 +stream|index=0|codec_name=timed_id3|profile=unknown|codec_type=data|codec_tag_string=ID3 |codec_tag=0x20334449|ts_id=1|ts_packetsize=188|id=0x100|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/90000|start_pts=126000|start_time=1.400000|duration_ts=451350|duration=5.015000|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=2|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:non_diegetic=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0|disposition:multilayer=0 format|filename=id3.ts|nb_streams=1|nb_programs=1|nb_stream_groups=0|format_name=mpegts|start_time=1.400000|duration=5.015000|size=1504|bit_rate=2399|probe_score=2 diff --git a/tests/ref/fate/vvc-conformance-IBC_B_Tencent_2 b/tests/ref/fate/vvc-conformance-IBC_B_Tencent_2 new file mode 100644 index 000000000..1f03a91a3 --- /dev/null +++ b/tests/ref/fate/vvc-conformance-IBC_B_Tencent_2 @@ -0,0 +1,22 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 416x240 +#sar 0: 0/1 +0, 0, 0, 1, 299520, 0xd40a4b32 +0, 1, 1, 1, 299520, 0x9d573409 +0, 2, 2, 1, 299520, 0x03e18a25 +0, 3, 3, 1, 299520, 0x896d2e32 +0, 4, 4, 1, 299520, 0x7692e0ac +0, 5, 5, 1, 299520, 0xc17c9612 +0, 6, 6, 1, 299520, 0x8d6566e7 +0, 7, 7, 1, 299520, 0x5720f80f +0, 8, 8, 1, 299520, 0x6907eb6c +0, 9, 9, 1, 299520, 0x03e91979 +0, 10, 10, 1, 299520, 0xa31e721b +0, 11, 11, 1, 299520, 0xf6f82463 +0, 12, 12, 1, 299520, 0x602ffac7 +0, 13, 13, 1, 299520, 0x8fbd4cfb +0, 14, 14, 1, 299520, 0x7fd5ebdb +0, 15, 15, 1, 299520, 0x45c6a0b8 +0, 16, 16, 1, 299520, 0x0f644248 diff --git a/tests/ref/fate/vvc-conformance-RPR_A_4 b/tests/ref/fate/vvc-conformance-RPR_A_4 new file mode 100644 index 000000000..58ae0f386 --- /dev/null +++ b/tests/ref/fate/vvc-conformance-RPR_A_4 @@ -0,0 +1,9 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 832x480 +#sar 0: 0/1 +0, 0, 0, 1, 1198080, 0x2c12c2be +0, 1, 1, 1, 1198080, 0x47275378 +0, 2, 2, 1, 1198080, 0x5d7b0327 +0, 3, 3, 1, 1198080, 0x0b15318a diff --git a/tests/ref/fate/vvc-conformance-SUBPIC_C_ERICSSON_1 b/tests/ref/fate/vvc-conformance-SUBPIC_C_ERICSSON_1 new file mode 100644 index 000000000..6fc781285 --- /dev/null +++ b/tests/ref/fate/vvc-conformance-SUBPIC_C_ERICSSON_1 @@ -0,0 +1,37 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 416x240 +#sar 0: 0/1 +0, 0, 0, 1, 299520, 0x011fa852 +0, 1, 1, 1, 299520, 0x25977488 +0, 2, 2, 1, 299520, 0x1334cb3b +0, 3, 3, 1, 299520, 0xc1b6c3fb +0, 4, 4, 1, 299520, 0x1e6cc08d +0, 5, 5, 1, 299520, 0x4a814f09 +0, 6, 6, 1, 299520, 0xb75f364c +0, 7, 7, 1, 299520, 0xaa7229c6 +0, 8, 8, 1, 299520, 0x996e9d73 +0, 9, 9, 1, 299520, 0xbbcf264e +0, 10, 10, 1, 299520, 0x177a5af3 +0, 11, 11, 1, 299520, 0x22d7cc8b +0, 12, 12, 1, 299520, 0xc18a5d10 +0, 13, 13, 1, 299520, 0xa6909d6e +0, 14, 14, 1, 299520, 0x14540bfd +0, 15, 15, 1, 299520, 0x5c850051 +0, 16, 16, 1, 299520, 0x918e9b48 +0, 17, 17, 1, 299520, 0x08036b6b +0, 18, 18, 1, 299520, 0x3da628b2 +0, 19, 19, 1, 299520, 0x6f9705d8 +0, 20, 20, 1, 299520, 0x0ec331b1 +0, 21, 21, 1, 299520, 0x2e33b85b +0, 22, 22, 1, 299520, 0x294bff6f +0, 23, 23, 1, 299520, 0x5d3ae6d2 +0, 24, 24, 1, 299520, 0xf9e78243 +0, 25, 25, 1, 299520, 0x391019f8 +0, 26, 26, 1, 299520, 0xb5d622c2 +0, 27, 27, 1, 299520, 0xeb0980d7 +0, 28, 28, 1, 299520, 0x6c070ba3 +0, 29, 29, 1, 299520, 0x5463d9ed +0, 30, 30, 1, 299520, 0x8cb7d074 +0, 31, 31, 1, 299520, 0x36ce96ae diff --git a/tests/ref/fate/vvc-conformance-WRAP_A_4 b/tests/ref/fate/vvc-conformance-WRAP_A_4 index 7273880c2..7f69d5e02 100644 --- a/tests/ref/fate/vvc-conformance-WRAP_A_4 +++ b/tests/ref/fate/vvc-conformance-WRAP_A_4 @@ -4,11 +4,11 @@ #dimensions 0: 1680x832 #sar 0: 0/1 0, 0, 0, 1, 4193280, 0xbd70f1b3 -0, 1, 1, 1, 4193280, 0x64e160d5 -0, 2, 2, 1, 4193280, 0xd20722ea -0, 3, 3, 1, 4193280, 0xa1d00055 -0, 4, 4, 1, 4193280, 0xe3dcb9cd -0, 5, 5, 1, 4193280, 0xcf97b6cf -0, 6, 6, 1, 4193280, 0xd87b73d0 -0, 7, 7, 1, 4193280, 0x0f8ee2bc -0, 8, 8, 1, 4193280, 0x76607ca4 +0, 1, 1, 1, 4193280, 0x491104c9 +0, 2, 2, 1, 4193280, 0xf600c2c1 +0, 3, 3, 1, 4193280, 0x1e3c8e2b +0, 4, 4, 1, 4193280, 0xad275e45 +0, 5, 5, 1, 4193280, 0xcd6103d7 +0, 6, 6, 1, 4193280, 0x0ec8cfbd +0, 7, 7, 1, 4193280, 0x2f664486 +0, 8, 8, 1, 4193280, 0x543eb3fc diff --git a/tests/ref/fate/wavpack-lossless-dsd b/tests/ref/fate/wavpack-lossless-dsd new file mode 100644 index 000000000..eba76df51 --- /dev/null +++ b/tests/ref/fate/wavpack-lossless-dsd @@ -0,0 +1 @@ +0b33207f1ec7e47333878cb8420c21ce diff --git a/tests/ref/fate/webm-webvtt-remux b/tests/ref/fate/webm-webvtt-remux index 377592690..baf4c296a 100644 --- a/tests/ref/fate/webm-webvtt-remux +++ b/tests/ref/fate/webm-webvtt-remux @@ -393,6 +393,7 @@ DISPOSITION:descriptions=1 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=1 @@ -415,6 +416,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=1 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=2 @@ -437,6 +439,7 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] [STREAM] index=3 @@ -459,4 +462,5 @@ DISPOSITION:descriptions=0 DISPOSITION:metadata=0 DISPOSITION:dependent=0 DISPOSITION:still_image=0 +DISPOSITION:multilayer=0 [/STREAM] diff --git a/tests/ref/lavf-fate/evc.mp4 b/tests/ref/lavf-fate/evc.mp4 index 4b410b84f..6ef7af4dd 100644 --- a/tests/ref/lavf-fate/evc.mp4 +++ b/tests/ref/lavf-fate/evc.mp4 @@ -1,3 +1,3 @@ -885fb330b20632b88ef9d7fb03dfa2e9 *tests/data/lavf-fate/lavf.evc.mp4 +bebb66fc3e13ece081d1aa96802e3c1f *tests/data/lavf-fate/lavf.evc.mp4 37386 tests/data/lavf-fate/lavf.evc.mp4 tests/data/lavf-fate/lavf.evc.mp4 CRC=0x48063f85 diff --git a/tests/ref/lavf-fate/hevc.flv b/tests/ref/lavf-fate/hevc.flv index 1105d8edd..e3962e093 100644 --- a/tests/ref/lavf-fate/hevc.flv +++ b/tests/ref/lavf-fate/hevc.flv @@ -1,3 +1,3 @@ -39cf3df5fc3a9c50ab71a294f45663fe *tests/data/lavf-fate/lavf.hevc.flv +c9e8b5df15135d21bd2781558f32f269 *tests/data/lavf-fate/lavf.hevc.flv 11819 tests/data/lavf-fate/lavf.hevc.flv tests/data/lavf-fate/lavf.hevc.flv CRC=0xd29da885 diff --git a/tests/ref/lavf-fate/hevc.mp4 b/tests/ref/lavf-fate/hevc.mp4 new file mode 100644 index 000000000..aea5ae897 --- /dev/null +++ b/tests/ref/lavf-fate/hevc.mp4 @@ -0,0 +1,3 @@ +37b3a3e84df2350380b05b2af4dc97f5 *tests/data/lavf-fate/lavf.hevc.mp4 +151340 tests/data/lavf-fate/lavf.hevc.mp4 +tests/data/lavf-fate/lavf.hevc.mp4 CRC=0xc0a771de diff --git a/tests/ref/lavf-fate/mv_hevc.mov b/tests/ref/lavf-fate/mv_hevc.mov new file mode 100644 index 000000000..9918c4cdc --- /dev/null +++ b/tests/ref/lavf-fate/mv_hevc.mov @@ -0,0 +1,3 @@ +60baf7bdf2b0d8a4ceccfb0f8c6b4875 *tests/data/lavf-fate/lavf.mv_hevc.mov +145383 tests/data/lavf-fate/lavf.mv_hevc.mov +tests/data/lavf-fate/lavf.mv_hevc.mov CRC=0xb71b4938 diff --git a/tests/ref/lavf-fate/vvc.mp4 b/tests/ref/lavf-fate/vvc.mp4 new file mode 100644 index 000000000..b237fe18c --- /dev/null +++ b/tests/ref/lavf-fate/vvc.mp4 @@ -0,0 +1,3 @@ +b5d5939890d3246475f990e5ebd58dc8 *tests/data/lavf-fate/lavf.vvc.mp4 +16625 tests/data/lavf-fate/lavf.vvc.mp4 +tests/data/lavf-fate/lavf.vvc.mp4 CRC=0x895790b1 diff --git a/tests/ref/lavf/mov_hybrid_frag b/tests/ref/lavf/mov_hybrid_frag new file mode 100644 index 000000000..cd449712b --- /dev/null +++ b/tests/ref/lavf/mov_hybrid_frag @@ -0,0 +1,3 @@ +4871796f41234350f1b050317d0288a3 *tests/data/lavf/lavf.mov_hybrid_frag +358508 tests/data/lavf/lavf.mov_hybrid_frag +tests/data/lavf/lavf.mov_hybrid_frag CRC=0xbb2b949b diff --git a/tests/ref/vsynth/vsynth1-ffv1-v2 b/tests/ref/vsynth/vsynth1-ffv1-v2 new file mode 100644 index 000000000..69536fb39 --- /dev/null +++ b/tests/ref/vsynth/vsynth1-ffv1-v2 @@ -0,0 +1,4 @@ +0f9298229cf53ce257648ccec70c893f *tests/data/fate/vsynth1-ffv1-v2.avi +2689724 tests/data/fate/vsynth1-ffv1-v2.avi +c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ffv1-v2.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-h261-trellis b/tests/ref/vsynth/vsynth1-h261-trellis index 87b078b0d..0cbb9b0e1 100644 --- a/tests/ref/vsynth/vsynth1-h261-trellis +++ b/tests/ref/vsynth/vsynth1-h261-trellis @@ -1,4 +1,4 @@ -02b4109ce5343b7ef24fb11c2635498a *tests/data/fate/vsynth1-h261-trellis.avi -655416 tests/data/fate/vsynth1-h261-trellis.avi -70ceba944548ba680b1101c91707ea25 *tests/data/fate/vsynth1-h261-trellis.out.rawvideo -stddev: 8.75 PSNR: 29.28 MAXDIFF: 90 bytes: 7603200/ 7603200 +9980463214cb744a7780737a16408540 *tests/data/fate/vsynth1-h261-trellis.avi +590384 tests/data/fate/vsynth1-h261-trellis.avi +7bbb0520a5ca26cdcea148f9997eae27 *tests/data/fate/vsynth1-h261-trellis.out.rawvideo +stddev: 9.09 PSNR: 28.96 MAXDIFF: 93 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-mpeg4-thread b/tests/ref/vsynth/vsynth1-mpeg4-thread index 6b69fb4c1..6b110c49f 100644 --- a/tests/ref/vsynth/vsynth1-mpeg4-thread +++ b/tests/ref/vsynth/vsynth1-mpeg4-thread @@ -1,4 +1,4 @@ -369ace2f9613261af869efd9fbb3c149 *tests/data/fate/vsynth1-mpeg4-thread.avi -774754 tests/data/fate/vsynth1-mpeg4-thread.avi -9aa327a244d5179acf7fe64dc1459bff *tests/data/fate/vsynth1-mpeg4-thread.out.rawvideo +7761391e354266976a9e0155eff983dd *tests/data/fate/vsynth1-mpeg4-thread.avi +774752 tests/data/fate/vsynth1-mpeg4-thread.avi +bbdbe9af4f5b106b847595bf3040699f *tests/data/fate/vsynth1-mpeg4-thread.out.rawvideo stddev: 10.13 PSNR: 28.02 MAXDIFF: 183 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-prores_444_int b/tests/ref/vsynth/vsynth1-prores_444_int index 76db62d4e..3d4c616c7 100644 --- a/tests/ref/vsynth/vsynth1-prores_444_int +++ b/tests/ref/vsynth/vsynth1-prores_444_int @@ -1,4 +1,4 @@ -fd2a2f49c61817c2338f39d5736d5fd2 *tests/data/fate/vsynth1-prores_444_int.mov +bd1502671ce7144c106a6a460b2af404 *tests/data/fate/vsynth1-prores_444_int.mov 9940947 tests/data/fate/vsynth1-prores_444_int.mov 732ceeb6887524e0aee98762fe50578b *tests/data/fate/vsynth1-prores_444_int.out.rawvideo stddev: 2.83 PSNR: 39.08 MAXDIFF: 45 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-prores_int b/tests/ref/vsynth/vsynth1-prores_int index 3e2bbeff2..c3b57631c 100644 --- a/tests/ref/vsynth/vsynth1-prores_int +++ b/tests/ref/vsynth/vsynth1-prores_int @@ -1,4 +1,4 @@ -1f1b246dfabe028f04c78887e5da51ed *tests/data/fate/vsynth1-prores_int.mov +842f92426e56cf6208cc94360d29fc69 *tests/data/fate/vsynth1-prores_int.mov 6308688 tests/data/fate/vsynth1-prores_int.mov 164a4ca890695cf594293d1acec9463c *tests/data/fate/vsynth1-prores_int.out.rawvideo stddev: 2.66 PSNR: 39.62 MAXDIFF: 34 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-ffv1-v2 b/tests/ref/vsynth/vsynth2-ffv1-v2 new file mode 100644 index 000000000..0b3f288f8 --- /dev/null +++ b/tests/ref/vsynth/vsynth2-ffv1-v2 @@ -0,0 +1,4 @@ +3144d06b9af1af98d072ccf05ff116ba *tests/data/fate/vsynth2-ffv1-v2.avi +3716500 tests/data/fate/vsynth2-ffv1-v2.avi +36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ffv1-v2.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-h261-trellis b/tests/ref/vsynth/vsynth2-h261-trellis index b9c694f01..03d17e194 100644 --- a/tests/ref/vsynth/vsynth2-h261-trellis +++ b/tests/ref/vsynth/vsynth2-h261-trellis @@ -1,4 +1,4 @@ -f5e0cfc70bbe4f4048c15be88dea4378 *tests/data/fate/vsynth2-h261-trellis.avi -249856 tests/data/fate/vsynth2-h261-trellis.avi -15452237f6c333690d3e05f354f63196 *tests/data/fate/vsynth2-h261-trellis.out.rawvideo -stddev: 7.10 PSNR: 31.10 MAXDIFF: 96 bytes: 7603200/ 7603200 +cdf6013013b8de3fe56476178b5adc89 *tests/data/fate/vsynth2-h261-trellis.avi +227156 tests/data/fate/vsynth2-h261-trellis.avi +d1107f161a7d923e0ffb6aeb9c713633 *tests/data/fate/vsynth2-h261-trellis.out.rawvideo +stddev: 7.24 PSNR: 30.93 MAXDIFF: 87 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd b/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd index 16de39edf..f5bbecfcb 100644 --- a/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd +++ b/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd @@ -1,4 +1,4 @@ -907a30295ed8323780eee08e606af0ab *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video -269722 tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video -d2d9793bf8f3427b5cc17a1be78ddd64 *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.out.rawvideo +f612ea89aa79a7f7b93a8acf332705c4 *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video +269723 tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video +88e17886e6383755829d7da519fd5e79 *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.out.rawvideo stddev: 5.54 PSNR: 33.25 MAXDIFF: 94 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-mpeg4-adap b/tests/ref/vsynth/vsynth2-mpeg4-adap index 35b2b6aac..e058cd1ce 100644 --- a/tests/ref/vsynth/vsynth2-mpeg4-adap +++ b/tests/ref/vsynth/vsynth2-mpeg4-adap @@ -1,4 +1,4 @@ -06a397fe43dab7b6cf56870410fbbbaf *tests/data/fate/vsynth2-mpeg4-adap.avi -203000 tests/data/fate/vsynth2-mpeg4-adap.avi -686565d42d8ba5aea790824b04fa0a18 *tests/data/fate/vsynth2-mpeg4-adap.out.rawvideo -stddev: 4.55 PSNR: 34.95 MAXDIFF: 84 bytes: 7603200/ 7603200 +9465ef120d560537d8fcfb5564782e01 *tests/data/fate/vsynth2-mpeg4-adap.avi +203004 tests/data/fate/vsynth2-mpeg4-adap.avi +d7851ab1ca9744f8e618a24193e5ef76 *tests/data/fate/vsynth2-mpeg4-adap.out.rawvideo +stddev: 4.56 PSNR: 34.95 MAXDIFF: 84 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-mpeg4-qprd b/tests/ref/vsynth/vsynth2-mpeg4-qprd index 0a8786b89..3face947c 100644 --- a/tests/ref/vsynth/vsynth2-mpeg4-qprd +++ b/tests/ref/vsynth/vsynth2-mpeg4-qprd @@ -1,4 +1,4 @@ -4ddd2fef35854d9b387bbcbda03dc7f0 *tests/data/fate/vsynth2-mpeg4-qprd.avi -248706 tests/data/fate/vsynth2-mpeg4-qprd.avi -baa8d0d57a7fb5e393642cb20efed2c2 *tests/data/fate/vsynth2-mpeg4-qprd.out.rawvideo +33fc3d5507cc8d2c8b63b8f811e62e4c *tests/data/fate/vsynth2-mpeg4-qprd.avi +248734 tests/data/fate/vsynth2-mpeg4-qprd.avi +61f8006e8903915056493fb1f05d1b2f *tests/data/fate/vsynth2-mpeg4-qprd.out.rawvideo stddev: 4.85 PSNR: 34.40 MAXDIFF: 85 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-mpeg4-thread b/tests/ref/vsynth/vsynth2-mpeg4-thread index 49c0ce024..a1791c49e 100644 --- a/tests/ref/vsynth/vsynth2-mpeg4-thread +++ b/tests/ref/vsynth/vsynth2-mpeg4-thread @@ -1,4 +1,4 @@ -92128f8adc4ac70a66fdddf58e46b923 *tests/data/fate/vsynth2-mpeg4-thread.avi -268396 tests/data/fate/vsynth2-mpeg4-thread.avi -f432bd8d897c7c8e286e385b77cedcfa *tests/data/fate/vsynth2-mpeg4-thread.out.rawvideo +44df605055498a01afb53eaaabdb94b4 *tests/data/fate/vsynth2-mpeg4-thread.avi +268394 tests/data/fate/vsynth2-mpeg4-thread.avi +13240eaccc345bf4b45f24d44cfc5ca2 *tests/data/fate/vsynth2-mpeg4-thread.out.rawvideo stddev: 4.89 PSNR: 34.34 MAXDIFF: 86 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-prores_444_int b/tests/ref/vsynth/vsynth2-prores_444_int index a2ee569c4..8d2a13b91 100644 --- a/tests/ref/vsynth/vsynth2-prores_444_int +++ b/tests/ref/vsynth/vsynth2-prores_444_int @@ -1,4 +1,4 @@ -5ac517fc2380a6cf11b7d86d2fafee0a *tests/data/fate/vsynth2-prores_444_int.mov +6f5fa77609698fbed3a7eef1c91bb9ea *tests/data/fate/vsynth2-prores_444_int.mov 6420787 tests/data/fate/vsynth2-prores_444_int.mov 33a5db4f0423168d4ae4f1db3610928e *tests/data/fate/vsynth2-prores_444_int.out.rawvideo stddev: 0.93 PSNR: 48.73 MAXDIFF: 14 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-prores_int b/tests/ref/vsynth/vsynth2-prores_int index 72139ee6c..f80ff3460 100644 --- a/tests/ref/vsynth/vsynth2-prores_int +++ b/tests/ref/vsynth/vsynth2-prores_int @@ -1,4 +1,4 @@ -4062c74196d95a64e642bd917377ed93 *tests/data/fate/vsynth2-prores_int.mov +a9a9812dd8944a58c2c2b3b0ce41247d *tests/data/fate/vsynth2-prores_int.mov 4070996 tests/data/fate/vsynth2-prores_int.mov bef9e38387a1fbb1ce2e4401b6d41674 *tests/data/fate/vsynth2-prores_int.out.rawvideo stddev: 1.54 PSNR: 44.37 MAXDIFF: 13 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth3-ffv1-v2 b/tests/ref/vsynth/vsynth3-ffv1-v2 new file mode 100644 index 000000000..3b0397ec0 --- /dev/null +++ b/tests/ref/vsynth/vsynth3-ffv1-v2 @@ -0,0 +1,4 @@ +72f1126e9e270f019d90f74959bcf0cb *tests/data/fate/vsynth3-ffv1-v2.avi +60648 tests/data/fate/vsynth3-ffv1-v2.avi +a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ffv1-v2.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-prores_444_int b/tests/ref/vsynth/vsynth3-prores_444_int index ac3069114..ca30db538 100644 --- a/tests/ref/vsynth/vsynth3-prores_444_int +++ b/tests/ref/vsynth/vsynth3-prores_444_int @@ -1,4 +1,4 @@ -50db4bbc4674de3dfdd41f306af1cb17 *tests/data/fate/vsynth3-prores_444_int.mov +b61864cafb35ad8e592b4f899bdd84b6 *tests/data/fate/vsynth3-prores_444_int.mov 184397 tests/data/fate/vsynth3-prores_444_int.mov a8852aa2841c2ce5f2aa86176ceda4ef *tests/data/fate/vsynth3-prores_444_int.out.rawvideo stddev: 3.24 PSNR: 37.91 MAXDIFF: 41 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-prores_int b/tests/ref/vsynth/vsynth3-prores_int index 86fc2266b..0feee26de 100644 --- a/tests/ref/vsynth/vsynth3-prores_int +++ b/tests/ref/vsynth/vsynth3-prores_int @@ -1,4 +1,4 @@ -24b765064b4aec754fdd0cc3658bba19 *tests/data/fate/vsynth3-prores_int.mov +2e89dfb5e2b5146337c1d65ccc4fe196 *tests/data/fate/vsynth3-prores_int.mov 120484 tests/data/fate/vsynth3-prores_int.mov e5859ba47a99f9e53c1ddcaa68a8f8f8 *tests/data/fate/vsynth3-prores_int.out.rawvideo stddev: 2.92 PSNR: 38.81 MAXDIFF: 29 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth_lena-ffv1-v2 b/tests/ref/vsynth/vsynth_lena-ffv1-v2 new file mode 100644 index 000000000..5f180462b --- /dev/null +++ b/tests/ref/vsynth/vsynth_lena-ffv1-v2 @@ -0,0 +1,4 @@ +4a0dbd5b50fa68fc7d5a8d6d64bd695a *tests/data/fate/vsynth_lena-ffv1-v2.avi +3546264 tests/data/fate/vsynth_lena-ffv1-v2.avi +dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ffv1-v2.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-h261-trellis b/tests/ref/vsynth/vsynth_lena-h261-trellis index a30650803..75558679e 100644 --- a/tests/ref/vsynth/vsynth_lena-h261-trellis +++ b/tests/ref/vsynth/vsynth_lena-h261-trellis @@ -1,4 +1,4 @@ -41522be50f14b7fff6b1fb8d10b1ff00 *tests/data/fate/vsynth_lena-h261-trellis.avi -184586 tests/data/fate/vsynth_lena-h261-trellis.avi -f9df8cd110a2f3d9706dd2f29a1d0a89 *tests/data/fate/vsynth_lena-h261-trellis.out.rawvideo -stddev: 6.32 PSNR: 32.11 MAXDIFF: 89 bytes: 7603200/ 7603200 +aa3e00ffeb48a23452bb1c5b0dde9e77 *tests/data/fate/vsynth_lena-h261-trellis.avi +167808 tests/data/fate/vsynth_lena-h261-trellis.avi +055f8805df2bb21ef6752dc944e7828d *tests/data/fate/vsynth_lena-h261-trellis.out.rawvideo +stddev: 6.43 PSNR: 31.96 MAXDIFF: 87 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-rc b/tests/ref/vsynth/vsynth_lena-mpeg4-rc index fd6a99804..a21ddc87e 100644 --- a/tests/ref/vsynth/vsynth_lena-mpeg4-rc +++ b/tests/ref/vsynth/vsynth_lena-mpeg4-rc @@ -1,4 +1,4 @@ -396a76466dee56e2714dfa42cebe3d2d *tests/data/fate/vsynth_lena-mpeg4-rc.avi +3ae5a2590bdd0e80a95bf374b06c553f *tests/data/fate/vsynth_lena-mpeg4-rc.avi 226314 tests/data/fate/vsynth_lena-mpeg4-rc.avi -6e8b62e8c3bcbfdcc58afb69a0b1c4e3 *tests/data/fate/vsynth_lena-mpeg4-rc.out.rawvideo +27c8771df4154f2be317465a3d3cbd56 *tests/data/fate/vsynth_lena-mpeg4-rc.out.rawvideo stddev: 4.23 PSNR: 35.60 MAXDIFF: 85 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-prores_444_int b/tests/ref/vsynth/vsynth_lena-prores_444_int index f05f1fe77..b13a7a126 100644 --- a/tests/ref/vsynth/vsynth_lena-prores_444_int +++ b/tests/ref/vsynth/vsynth_lena-prores_444_int @@ -1,4 +1,4 @@ -09b5dffd1a484e2152a3b5a0bcceed32 *tests/data/fate/vsynth_lena-prores_444_int.mov +e76d98c772c65c7ac75f7d43484883d3 *tests/data/fate/vsynth_lena-prores_444_int.mov 5696258 tests/data/fate/vsynth_lena-prores_444_int.mov 466380156e4d2b811f4ffb9c5a8bca72 *tests/data/fate/vsynth_lena-prores_444_int.out.rawvideo stddev: 0.88 PSNR: 49.23 MAXDIFF: 9 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-prores_int b/tests/ref/vsynth/vsynth_lena-prores_int index ea0808974..cec45a59b 100644 --- a/tests/ref/vsynth/vsynth_lena-prores_int +++ b/tests/ref/vsynth/vsynth_lena-prores_int @@ -1,4 +1,4 @@ -c7e9a61054f44fe372a3bce619b68ce9 *tests/data/fate/vsynth_lena-prores_int.mov +21d328216b194500a3c87c45afa5e927 *tests/data/fate/vsynth_lena-prores_int.mov 3532698 tests/data/fate/vsynth_lena-prores_int.mov eb5caa9824ca294f403cd13f33c40f23 *tests/data/fate/vsynth_lena-prores_int.out.rawvideo stddev: 1.47 PSNR: 44.78 MAXDIFF: 12 bytes: 7603200/ 7603200 diff --git a/tests/streamgroups/audio_element-7_1_4-2 b/tests/streamgroups/audio_element-7_1_4-2 new file mode 100644 index 000000000..324ab5562 --- /dev/null +++ b/tests/streamgroups/audio_element-7_1_4-2 @@ -0,0 +1,6 @@ +type=iamf_audio_element:id=1:st=1:st=2:st=3:st=4:st=5:st=6:st=7:default_w=10, +demixing=dmixp_mode=1:parameter_id=998,recon_gain=parameter_id=101, +layer=ch_layout=stereo, +layer=ch_layout=3.1.2, +layer=ch_layout=7.1.2, +layer=ch_layout=7.1.4, diff --git a/tools/Makefile b/tools/Makefile index 72e8e709a..7ae6e3cb7 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -5,6 +5,9 @@ TOOLS-$(CONFIG_ZLIB) += cws2fws tools/target_dec_%_fuzzer.o: tools/target_dec_fuzzer.c $(COMPILE_C) -DFFMPEG_DECODER=$* +tools/target_enc_%_fuzzer.o: tools/target_enc_fuzzer.c + $(COMPILE_C) -DFFMPEG_ENCODER=$* + tools/target_bsf_%_fuzzer.o: tools/target_bsf_fuzzer.c $(COMPILE_C) -DFFMPEG_BSF=$* @@ -20,6 +23,9 @@ tools/target_io_dem_fuzzer.o: tools/target_dem_fuzzer.c tools/target_sws_fuzzer.o: tools/target_sws_fuzzer.c $(COMPILE_C) +tools/target_swr_fuzzer.o: tools/target_swr_fuzzer.c + $(COMPILE_C) + tools/enc_recon_frame_test$(EXESUF): tools/decode_simple.o tools/venc_data_dump$(EXESUF): tools/decode_simple.o tools/scale_slice_test$(EXESUF): tools/decode_simple.o diff --git a/tools/crypto_bench.c b/tools/crypto_bench.c index 0aff4ea78..45046a0a9 100644 --- a/tools/crypto_bench.c +++ b/tools/crypto_bench.c @@ -32,6 +32,7 @@ #include "libavutil/avstring.h" #include "libavutil/crc.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/timer.h" #ifndef AV_READ_TIME diff --git a/tools/enc_recon_frame_test.c b/tools/enc_recon_frame_test.c index 798fb772e..c6da6750f 100644 --- a/tools/enc_recon_frame_test.c +++ b/tools/enc_recon_frame_test.c @@ -33,6 +33,7 @@ #include "libavutil/error.h" #include "libavutil/frame.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavformat/avformat.h" diff --git a/tools/ismindex.c b/tools/ismindex.c index 39b537819..6fe68d8a7 100644 --- a/tools/ismindex.c +++ b/tools/ismindex.c @@ -52,6 +52,7 @@ #include "libavformat/os_support.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" static int usage(const char *argv0, int ret) { diff --git a/tools/probetest.c b/tools/probetest.c index e742d598b..a8ce40479 100644 --- a/tools/probetest.c +++ b/tools/probetest.c @@ -24,6 +24,7 @@ #include "libavformat/demux.h" #include "libavcodec/put_bits.h" #include "libavutil/lfg.h" +#include "libavutil/mem.h" #include "libavutil/timer.h" #define MAX_FORMATS 1000 //this must be larger than the number of formats diff --git a/tools/sidxindex.c b/tools/sidxindex.c index 88aea6bcb..3e43d95e0 100644 --- a/tools/sidxindex.c +++ b/tools/sidxindex.c @@ -25,6 +25,7 @@ #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" +#include "libavutil/mem.h" static int usage(const char *argv0, int ret) { diff --git a/tools/target_bsf_fuzzer.c b/tools/target_bsf_fuzzer.c index 76e3b89cf..44a4d1467 100644 --- a/tools/target_bsf_fuzzer.c +++ b/tools/target_bsf_fuzzer.c @@ -18,6 +18,7 @@ #include "config.h" #include "libavutil/imgutils.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/avcodec.h" diff --git a/tools/target_dec_fuzzer.c b/tools/target_dec_fuzzer.c index 8adbc0809..6e6b10e13 100644 --- a/tools/target_dec_fuzzer.c +++ b/tools/target_dec_fuzzer.c @@ -51,6 +51,7 @@ #include "libavutil/cpu.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavcodec/avcodec.h" #include "libavcodec/bytestream.h" @@ -128,7 +129,14 @@ static int fuzz_video_get_buffer(AVCodecContext *ctx, AVFrame *frame) frame->extended_data = frame->data; for (i = 0; i < 4 && size[i]; i++) { - frame->buf[i] = av_buffer_alloc(size[i]); + switch(ctx->codec_id) { + case AV_CODEC_ID_FFV1: + frame->buf[i] = av_buffer_alloc(size[i]); + break; + default: + frame->buf[i] = av_buffer_allocz(size[i]); + } + if (!frame->buf[i]) goto fail; frame->data[i] = frame->buf[i]->data; @@ -229,6 +237,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { case AV_CODEC_ID_DVB_SUBTITLE: av_dict_set_int(&opts, "compute_clut", -2, 0); break; case AV_CODEC_ID_DXA: maxpixels /= 32; break; case AV_CODEC_ID_DXV: maxpixels /= 32; break; + case AV_CODEC_ID_CMV: maxpixels /= 256; break; case AV_CODEC_ID_EXR: maxpixels /= 1024; break; case AV_CODEC_ID_FFV1: maxpixels /= 32; break; case AV_CODEC_ID_FFWAVESYNTH: maxsamples /= 16384; break; @@ -247,6 +256,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { case AV_CODEC_ID_HQ_HQA: maxpixels /= 128; break; case AV_CODEC_ID_IFF_ILBM: maxpixels /= 4096; break; case AV_CODEC_ID_INDEO4: maxpixels /= 128; break; + case AV_CODEC_ID_INDEO5: maxpixels /= 1024; break; case AV_CODEC_ID_INTERPLAY_ACM: maxsamples /= 16384; break; case AV_CODEC_ID_JPEG2000: maxpixels /= 16384; break; case AV_CODEC_ID_LAGARITH: maxpixels /= 1024; break; @@ -262,6 +272,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { case AV_CODEC_ID_MSZH: maxpixels /= 128; break; case AV_CODEC_ID_MTS2: maxpixels /= 4096; break; case AV_CODEC_ID_MV30: maxpixels /= 128; break; + case AV_CODEC_ID_MVC1: maxpixels /= 1024; break; case AV_CODEC_ID_MVC2: maxpixels /= 128; break; case AV_CODEC_ID_MVHA: maxpixels /= 16384; break; case AV_CODEC_ID_MVDV: maxpixels /= 1024; break; @@ -277,8 +288,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { case AV_CODEC_ID_QPEG: maxpixels /= 256; break; case AV_CODEC_ID_RKA: maxsamples /= 1<<20; break; case AV_CODEC_ID_RSCC: maxpixels /= 256; break; - case AV_CODEC_ID_RASC: maxpixels /= 16; break; + case AV_CODEC_ID_RASC: maxpixels /= 256; break; case AV_CODEC_ID_RTV1: maxpixels /= 16; break; + case AV_CODEC_ID_RV30: maxpixels /= 256; break; case AV_CODEC_ID_SANM: maxpixels /= 16; break; case AV_CODEC_ID_SCPR: maxpixels /= 32; break; case AV_CODEC_ID_SCREENPRESSO:maxpixels /= 64; break; @@ -287,6 +299,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { case AV_CODEC_ID_SMACKAUDIO: maxsamples /= 4096; break; case AV_CODEC_ID_SMACKVIDEO: maxpixels /= 64; break; case AV_CODEC_ID_SNOW: maxpixels /= 128; break; + case AV_CODEC_ID_SRGC: maxpixels /= 128; break; case AV_CODEC_ID_TARGA: maxpixels /= 128; break; case AV_CODEC_ID_TAK: maxsamples /= 1024; break; case AV_CODEC_ID_TGV: maxpixels /= 32; break; diff --git a/tools/target_dem_fuzzer.c b/tools/target_dem_fuzzer.c index fe69eb9be..8e96fad7f 100644 --- a/tools/target_dem_fuzzer.c +++ b/tools/target_dem_fuzzer.c @@ -19,6 +19,7 @@ #include "config.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/mem.h" #include "libavcodec/avcodec.h" #include "libavcodec/bytestream.h" diff --git a/tools/target_enc_fuzzer.c b/tools/target_enc_fuzzer.c new file mode 100644 index 000000000..059d78307 --- /dev/null +++ b/tools/target_enc_fuzzer.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2024 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 + * + * Based on target_dec_fuzzer + */ + +#include "config.h" +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/cpu.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" + +#include "libavcodec/avcodec.h" +#include "libavcodec/bytestream.h" +#include "libavcodec/codec_internal.h" +#include "libavformat/avformat.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +extern const FFCodec * codec_list[]; + +static void error(const char *err) +{ + fprintf(stderr, "%s", err); + exit(1); +} + +static const FFCodec *c = NULL; + +// Ensure we don't loop forever +const uint32_t maxiteration = 8096; + + +static int encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt) +{ + int ret; + + ret = avcodec_send_frame(enc_ctx, frame); + if (ret < 0) + return ret; + + while (ret >= 0) { + ret = avcodec_receive_packet(enc_ctx, pkt); + if (ret == AVERROR(EAGAIN)) { + return 0; + } else if (ret < 0) { + return ret; + } + + av_packet_unref(pkt); + } + av_assert0(0); +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + uint64_t maxpixels_per_frame = 512 * 512; + uint64_t maxpixels; + + const uint8_t *end = data + size; + uint32_t it = 0; + uint64_t nb_samples = 0; + AVDictionary *opts = NULL; + uint64_t ec_pixels = 0; + + if (!c) { +#define ENCODER_SYMBOL0(CODEC) ff_##CODEC##_encoder +#define ENCODER_SYMBOL(CODEC) ENCODER_SYMBOL0(CODEC) + extern FFCodec ENCODER_SYMBOL(FFMPEG_ENCODER); + codec_list[0] = &ENCODER_SYMBOL(FFMPEG_ENCODER); + + c = &ENCODER_SYMBOL(FFMPEG_ENCODER); + av_log_set_level(AV_LOG_PANIC); + } + + if (c->p.type != AVMEDIA_TYPE_VIDEO) + return 0; + + maxpixels = maxpixels_per_frame * maxiteration; + switch (c->p.id) { + case AV_CODEC_ID_A64_MULTI: maxpixels /= 65536; break; + case AV_CODEC_ID_A64_MULTI5: maxpixels /= 65536; break; + } + + maxpixels_per_frame = FFMIN(maxpixels_per_frame , maxpixels); + + AVCodecContext* ctx = avcodec_alloc_context3(&c->p); + if (!ctx) + error("Failed memory allocation"); + + if (ctx->max_pixels == 0 || ctx->max_pixels > maxpixels_per_frame) + ctx->max_pixels = maxpixels_per_frame; //To reduce false positive OOM and hangs + + ctx->pix_fmt = AV_PIX_FMT_YUV420P; + if (size > 1024) { + GetByteContext gbc; + int flags; + int64_t flags64; + + size -= 1024; + bytestream2_init(&gbc, data + size, 1024); + ctx->width = bytestream2_get_le32(&gbc) & 0xFFFF; + ctx->height = bytestream2_get_le32(&gbc) & 0xFFFF; + ctx->bit_rate = bytestream2_get_le64(&gbc); + ctx->gop_size = bytestream2_get_le32(&gbc) & 0x7FFFFFFF; + ctx->max_b_frames = bytestream2_get_le32(&gbc) & 0x7FFFFFFF; + ctx->time_base.num = bytestream2_get_le32(&gbc) & 0x7FFFFFFF; + ctx->time_base.den = bytestream2_get_le32(&gbc) & 0x7FFFFFFF; + ctx->framerate.num = bytestream2_get_le32(&gbc) & 0x7FFFFFFF; + ctx->framerate.den = bytestream2_get_le32(&gbc) & 0x7FFFFFFF; + + flags = bytestream2_get_byte(&gbc); + if (flags & 2) + ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; + + if (flags & 0x40) + av_force_cpu_flags(0); + + flags64 = bytestream2_get_le64(&gbc); + + if (c->p.pix_fmts) { + int npixfmts = 0; + while (c->p.pix_fmts[npixfmts++] != AV_PIX_FMT_NONE) + ; + ctx->pix_fmt = c->p.pix_fmts[bytestream2_get_byte(&gbc) % npixfmts]; + } + + switch (c->p.id) { + case AV_CODEC_ID_FFV1:{ + int coder = bytestream2_get_byte(&gbc)&3; + if (coder == 3) coder = -2; + av_dict_set_int(&opts, "coder", coder, 0); + av_dict_set_int(&opts, "context", bytestream2_get_byte(&gbc)&1, 0); + av_dict_set_int(&opts, "slicecrc", bytestream2_get_byte(&gbc)&1, 0); + break;} + } + } + if (ctx->width == 0 || av_image_check_size(ctx->width, ctx->height, 0, ctx)) + ctx->width = ctx->height = 64; + + int res = avcodec_open2(ctx, &c->p, &opts); + if (res < 0) { + avcodec_free_context(&ctx); + av_dict_free(&opts); + return 0; // Failure of avcodec_open2() does not imply that a issue was found + } + + + AVFrame *frame = av_frame_alloc(); + AVPacket *avpkt = av_packet_alloc(); + if (!frame || !avpkt) + error("Failed memory allocation"); + + frame->format = ctx->pix_fmt; + frame->width = ctx->width; + frame->height = ctx->height; + + while (data < end && it < maxiteration) { + ec_pixels += (ctx->width + 32LL) * (ctx->height + 32LL); + if (ec_pixels > maxpixels) + goto maximums_reached; + + res = av_frame_get_buffer(frame, 0); + if (res < 0) + error("Failed av_frame_get_buffer"); + + for (int i=0; ibuf); i++) { + if (frame->buf[i]) { + int buf_size = FFMIN(end-data, frame->buf[i]->size); + memcpy(frame->buf[i]->data, data, buf_size); + memset(frame->buf[i]->data + buf_size, 0, frame->buf[i]->size - buf_size); + data += buf_size; + } + } + + frame->pts = nb_samples; + + res = encode(ctx, frame, avpkt); + if (res < 0) + break; + it++; + for (int i=0; ibuf); i++) + av_buffer_unref(&frame->buf[i]); + + av_packet_unref(avpkt); + } +maximums_reached: + encode(ctx, NULL, avpkt); + av_packet_unref(avpkt); + +// fprintf(stderr, "frames encoded: %"PRId64", iterations: %d\n", nb_samples , it); + + av_frame_free(&frame); + avcodec_free_context(&ctx); + av_packet_free(&avpkt); + av_dict_free(&opts); + return 0; +} diff --git a/tools/target_swr_fuzzer.c b/tools/target_swr_fuzzer.c new file mode 100644 index 000000000..9192d4bed --- /dev/null +++ b/tools/target_swr_fuzzer.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2024 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 "config.h" +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/cpu.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" + +#include "libavcodec/bytestream.h" + +#include "libswresample/swresample.h" + +#define SWR_CH_MAX 32 + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +static const enum AVSampleFormat formats[] = { + 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_FLT, + AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBL, + AV_SAMPLE_FMT_DBLP, +}; + +static const AVChannelLayout layouts[]={ + AV_CHANNEL_LAYOUT_MONO , + AV_CHANNEL_LAYOUT_STEREO , + AV_CHANNEL_LAYOUT_2_1 , + AV_CHANNEL_LAYOUT_SURROUND , + AV_CHANNEL_LAYOUT_4POINT0 , + AV_CHANNEL_LAYOUT_2_2 , + AV_CHANNEL_LAYOUT_QUAD , + AV_CHANNEL_LAYOUT_5POINT0 , + AV_CHANNEL_LAYOUT_5POINT1 , + AV_CHANNEL_LAYOUT_5POINT0_BACK , + AV_CHANNEL_LAYOUT_5POINT1_BACK , + AV_CHANNEL_LAYOUT_7POINT0 , + AV_CHANNEL_LAYOUT_7POINT1 , + AV_CHANNEL_LAYOUT_7POINT1_WIDE , + AV_CHANNEL_LAYOUT_22POINT2 , + AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK , +}; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + struct SwrContext * swr= NULL; + AVChannelLayout in_ch_layout = AV_CHANNEL_LAYOUT_MONO, out_ch_layout = AV_CHANNEL_LAYOUT_MONO; + enum AVSampleFormat in_sample_fmt = AV_SAMPLE_FMT_S16P; + enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16P; + int in_sample_rate = 44100; + int out_sample_rate = 44100; + int in_ch_count, out_ch_count; + char in_layout_string[256]; + char out_layout_string[256]; + uint8_t * ain[SWR_CH_MAX]; + uint8_t *aout[SWR_CH_MAX]; + uint8_t *out_data; + int in_sample_nb; + int out_sample_nb = size; + int count; + int ret; + + if (size > 128) { + GetByteContext gbc; + int64_t flags64; + + size -= 128; + bytestream2_init(&gbc, data + size, 128); + in_sample_rate = bytestream2_get_le16(&gbc) + 1; + out_sample_rate = bytestream2_get_le16(&gbc) + 1; + in_sample_fmt = formats[bytestream2_get_byte(&gbc) % FF_ARRAY_ELEMS(formats)]; + out_sample_fmt = formats[bytestream2_get_byte(&gbc) % FF_ARRAY_ELEMS(formats)]; + av_channel_layout_copy(& in_ch_layout, &layouts[bytestream2_get_byte(&gbc) % FF_ARRAY_ELEMS(layouts)]); + av_channel_layout_copy(&out_ch_layout, &layouts[bytestream2_get_byte(&gbc) % FF_ARRAY_ELEMS(layouts)]); + + out_sample_nb = bytestream2_get_le32(&gbc); + + flags64 = bytestream2_get_le64(&gbc); + if (flags64 & 0x10) + av_force_cpu_flags(0); + } + + in_ch_count= in_ch_layout.nb_channels; + out_ch_count= out_ch_layout.nb_channels; + av_channel_layout_describe(& in_ch_layout, in_layout_string, sizeof( in_layout_string)); + av_channel_layout_describe(&out_ch_layout, out_layout_string, sizeof(out_layout_string)); + + fprintf(stderr, "%s %d %s -> %s %d %s\n", + av_get_sample_fmt_name( in_sample_fmt), in_sample_rate, in_layout_string, + av_get_sample_fmt_name(out_sample_fmt), out_sample_rate, out_layout_string); + + if (swr_alloc_set_opts2(&swr, &out_ch_layout, out_sample_fmt, out_sample_rate, + &in_ch_layout, in_sample_fmt, in_sample_rate, + 0, 0) < 0) { + fprintf(stderr, "Failed swr_alloc_set_opts2()\n"); + goto end; + } + + if (swr_init(swr) < 0) { + fprintf(stderr, "Failed swr_init()\n"); + goto end; + } + + in_sample_nb = size / (in_ch_count * av_get_bytes_per_sample(in_sample_fmt)); + out_sample_nb = out_sample_nb % (av_rescale(in_sample_nb, 2*out_sample_rate, in_sample_rate) + 1); + + if (in_sample_nb > 1000*1000 || out_sample_nb > 1000*1000) + goto end; + + out_data = av_malloc(out_sample_nb * out_ch_count * av_get_bytes_per_sample(out_sample_fmt)); + if (!out_data) + goto end; + + ret = av_samples_fill_arrays(ain , NULL, data, in_ch_count, in_sample_nb, in_sample_fmt, 1); + if (ret < 0) + goto end; + ret = av_samples_fill_arrays(aout, NULL, out_data, out_ch_count, out_sample_nb, out_sample_fmt, 1); + if (ret < 0) + goto end; + + count = swr_convert(swr, aout, out_sample_nb, (const uint8_t **)ain, in_sample_nb); + + av_freep(&out_data); + +end: + swr_free(&swr); + + return 0; +} diff --git a/tools/target_sws_fuzzer.c b/tools/target_sws_fuzzer.c index 6d9d15da2..fd8314cae 100644 --- a/tools/target_sws_fuzzer.c +++ b/tools/target_sws_fuzzer.c @@ -24,6 +24,7 @@ #include "libavutil/cpu.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavcodec/bytestream.h" diff --git a/tools/uncoded_frame.c b/tools/uncoded_frame.c index edea2367c..447bfc8b0 100644 --- a/tools/uncoded_frame.c +++ b/tools/uncoded_frame.c @@ -2,6 +2,7 @@ #include #include #include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavdevice/avdevice.h" #include "libavfilter/avfilter.h" #include "libavfilter/buffersink.h"